Introduction
Microsoft DirectX is a heavy stone that cannot be broken without any tools. Each part of DirectX is worth separate attention by a developer. Looking deep inside of those components is too difficult. But to use them properly one must know what he is doing or wants to do...
But nowadays technologies are so developed that they free developers from having to cover much of the 'technical' aspects of their job and let them concentrate on the core issues they have. One of such helpers is the core concept of object-oriented languages, and C++ too, which of course is - the class.
Classes are the very basement on which object-oriented programming is built. The wiser you use them, the more you will sleep at nights. Not going into the depth of C++ notions, I want to introduce a few classes of mine to you that may help you with using MS DirectSound components in your applications. Particularly, I will speak about how to play .wav (wave) files by DirectSound.
What's New in This Update
The major new feature in this article is that CDSoundPlay
now supports notification mechanism; it uses IDirectSoundNotify
interface to handle that. CWave class's source is available in the source download. Also there are some corrections in the code from previous article.
Background
First, let me say that .wav files may be played not only by DirectSound, but also by MMIO, MCI and so on. The problem is that those machines don't provide immediate attention to a user; the latency to start playing is much. This may be crucial in some situations, for example, in games, where the bomber-man wants his gun to sound (and shoot) as soon as possible. Here DirectSound may help.
DirectSound provides low-latency playback and immediate attention from users.
To minimize the job necessary for using DirectSound at a maximum, I've created four classes: one may say wrapper classes. Two of them are helper classes and are not supposed to be used directly, but you still can use them. Here are the classes:
CWave
(helper)
CDSBuffer
(helper)
CDSound
CDSoundPlay
CWave
helps us with opening .wav files. This class is used by CDSBuffer
. I have put CWave
in a DLL to hide the unnecessary stuff from you (believe in me, there are lots of ugly things). Though the source code of CWave
you can find in the download package of this article.
CDSound
is the main entity in your system. It represents the DirectSound object. Within a given application there must be only one instance of this class. This class is used by CDSBuffer
.
CDSBuffer
is a low-level class that represents DirectSound buffers. This class is used by CDSoundPlay
.
CDSoundPlay
is a high-level class that represents the interface for playing, stopping, ... of Waves.
These classes use MFC and cannot live without it. For example, I've put CWave
in a MFC extension DLL; it means that the client application also must be MFC based.
Using The Code
Now let's see how to use them. You can declare the objects of these classes in a view class, dialog class or main frame class; in other words, any window that has HWND
(really I haven't seen any window without a HWND
). I'll choose a dialog.
Declarations:
#include "DirectSound.h"
using namespace DirectSound;
class CMyDialog : public CDialog
{
CDSound m_dsound;
CDsoundPlayer m_player;
};
Next construct the corresponding DirectSound object in OnInitDialog
:
BOOL CMyDialog::OnInitDialog()
{
m_dsound.Create();
m_dsound.SetCooperativeLevel(GetSafeHwnd());
return FALSE;
}
Now you may load files. Assume you have a Load method to do it:
BOOL CMyDialog::Load(LPCTSTR lpszFileName)
{
m_player.Destroy();
BOOL fOk = m_player.Create(&m_dsound, lpszFileName);
return fOk;
}
Let's play and stop Wave files. Assume you have OnPlay
and OnStop
handlers to do it:
void CMyDialog::OnPlay()
{
Load(TEXT("flowers.wav"));
m_player.Play();
}
void CMyDialog::OnStop()
{
m_player.Stop();
}
A couple of new functions has been added to CDSoundPlay
which are for handling notifications; CDSounfPlay::SetNotifyFuction
and CDSoundPlay::SetNotificationPositions
. The former takes a parameter of type PNOTIFYFUNC
which is a typedef for callback functions:
typedef LONG (*PNOTIFYFUNC) (LONG );
This means that a callback should take a LONG
parameter and return a LONG
value. This type was defined by me and you may change it for your convention if needed.
The second function looks like so:
BOOL SetNotificationPositions(DWORD dwOffsets[], SIZE_T nSize);
It takes an array of integer values showing positions to be considered, and an integer value showing how many positions are there in the first parameter.
For example, the demo application calls these functions to be notified when a wave starts and when it ends:
m_player.SetNotifyFunction(CSounderDlg::NotifyCallback);
DWORD dwOffset[] = { 0, DSBPN_OFFSETSTOP };
m_player.SetNotificationPositions(dwOffset, 2);
CSounderDlg::NotifyCallback
is a static function which has the type of PNOTIFYFUNC
:
LONG CSounderDlg::NotifyCallback(LONG f)
{
return 0;
}
That's all for playing Wave files. But CDSoundPlay
has also other features; amongst them: looping, volume setting/getting, panorama setting/getting, frequency setting/getting. I've created a demo application that shows most of these features. It is a simple application and I'll not describe it thoroughly. Just see its interface and you'll understand it yourself.