Setting Up Direct Sound

By: Kevin Scardina

Abstract: Document on what DirectSound is and how to set it up.

Setting Up Direct Sound

Table Of Contents
Objective
What is Direct Sound?
How Direct Sound Works
Getting a GUID for the Audio Device
Creating a DirectSound Object
Setting the Cooperative Level
Setting the Primary Format
Conclusion
Appendix A: An Example
Appendix B: Creating a dsound import library
References

Objective TOC

        The objective of this document is to introduce DirectSound to the Borland Developer and demonstrate how to set up DirectSound in Borland's C++ Builder environment. This article assumes that the reader has the following knowledge:
  • Borland C++ Builder
  • Win32 multi-media API
  • Microsoft's Common Object Modal (COM)

What Is Direct Sound? TOC

        DirectSound is a component of the DirectX library that gives today's audio developer added speed and control of the audio devices. Usually the Win32 multi-media API will suffice, but if you want to develop a game in which guns are blazing, engines are roaring, music is blaring, and grunts of pain are all around you, DirectSound is what you need. Besides just speed and control, DirectSound also has the following advantages over the Win32 multi-media API:
  • Automatic use of hardware acceleration where available
  • Mixing unlimited number of sounds
  • Low-latency playback
  • 3d positional sound effects
  • Automatic conversion of input wave format
  • Support for property sets, giving access to new hardware features without hanging the API

How Direct Sound Works TOC

        DirectSound works off sound buffers. The secondary sound buffer object is were it all starts. It represents a single sound, whether it be a short sound that fits into the block of memory or a long sound that has to be streamed into the buffer. The buffer stores the sound sample in the form of pulse code modulation (PCM) data. You can have as many secondary sound buffer's as you like, and when you play them DirectSound will "mix" them on to the primary sound buffer, performing any conversions like -- converting the sample rate and adding 3D special effects. From the primary buffer the PCM data is sent to the output device.

        Like all of the DirectX components DirectSound tries to use as much hardware acceleration as possible. Whenever possible it places as many buffers as it can in hardware memory and uses hardware mixing if available. If this is not possible then DirectSound will use hardware emulation to get the task done. The figure below illustrates this process.

Getting a GUID for the Audio Device TOC

        The first step in setting up DirectSound is getting a GUID for the audio output device. This step is optional and in most cases you will not have to do this. The DirectSound object is initialized for the preferred audio device. This is the audio device selected by using the Multi-media applet in the Control Panel. In the rare case that you choose to select the audio device, DirectSound provides a nice call back enumeration function called DirectSoundEnumerate. The function looks as follows:


HRESULT WINAPI DirectSoundEnumerate(
  LPDSENUMCALLBACK lpDSEnumCallback,  
  LPVOID lpContext                    
);
 

Parameters:

	lpDSEnumCallback

		Address of the DSEnumCallback function that will be called for each DirectSound object installed in
		the	system.

	lpContext

		Address of the user-defined context passed to the enumeration callback function every time that
		function is called.

Return Values:

	If the function succeeds, the return value is DS_OK.
	If the function fails, the return value may be DSERR_INVALIDPARAM.

-----------------------------------------------------------------------------------------------------------	
	
BOOL CALLBACK DSEnumCallback(
  LPGUID lpGuid,            
  LPCSTR lpcstrDescription,  
  LPCSTR lpcstrModule,       
  LPVOID lpContext          
);
 

Parameters:

	lpGuid

		Address of the GUID that identifies the DirectSound driver being enumerated. This value can be
		passed to the DirectSoundCreate function to create a DirectSound object for that driver.

	lpcstrDescription

		Address of a null-terminated string that provides a textual description of the DirectSound device.

	lpcstrModule

		Address of a null-terminated string that specifies the module name of the DirectSound driver
		corresponding to this device.

	lpContext

		Address of application-defined data that is passed to each callback function.

Return Values:

	Returns TRUE to continue enumerating drivers, or FALSE to stop.


        By using this callback a list of audio devices to choose from can be generated. The first device enumerated is always the primary sound driver, for this device there is no GUID. It is the application's responsibility to create an Object for the default device if the user chooses this device. For all the others a GUID will be passed into the callback function. This GUID can be used to create the Object for that device. The following example code will enumerate all the devices and put them all in a list for future use.


#define DIRECTSOUND_VERSION 5
#include <dsound.h>
#include<vector>
#include<string>
#include<iostream>
#pragma hdrstop

using namespace std;

struct AudioDevice
{
  LPGUID guid;
  string description;
  string module;
  AudioDevice (){
    guid = NULL;
  }
  ~AudioDevice (){
    delete guid;
  }
};

typedef vector<AudioDevice*> AudioDevices;

BOOL CALLBACK EnumCallBack (LPGUID guid, LPCSTR desc,
  LPCSTR mod, LPVOID list)
{
  AudioDevice *ad = new AudioDevice;
  if (guid == NULL)
    ad->guid = NULL;
  else{
    ad->guid = new GUID;
    memcpy (ad->guid, guid, sizeof (GUID));
  }
  ad->description = desc;
  ad->module = mod;
  (static_cast<AudioDevices*>(list))->push_back (ad);
  return true;
}
const char* app_title = "Direct Sound CP player";
LPDIRECTSOUND pds;
#pragma argsused
int main(int argc, char* argv[])
{
  AudioDevices ads;
  unsigned int i;
  string filename;

  if (argc != 2){
    cout << "Usage: dsenumprj.exe <wave file>" << endl;
    return 2;
  }

  filename = argv[1];
  SetConsoleTitle (app_title);

  if (FAILED (DirectSoundEnumerate (EnumCallBack, &ads))){
    cout << "Couldn't enumerate the audio devices" << endl;
    return 1;
  }
  for (i = 0; i < ads.size (); i++)
  {
    cout << i << ":t" << ads[i]->description << "t" << ads[i]->module << endl;
  }
  return 0;
}

Creating a DirectSound Object TOC

        To create a DirectSound Object simply use the DirectSoundCreate function.


HRESULT WINAPI DirectSoundCreate(
  LPGUID lpGuid,         
  LPDIRECTSOUND * ppDS,  
  LPUNKNOWN * pUnkOuter  
);
 
Parameters:

	lpGuid

		Address of the GUID that identifies the sound device. The value of this parameter must be one of
		the GUIDs returned by DirectSoundEnumerate, or NULL for the default device.

	ppDS

		Address of a pointer to a DirectSound object created in response to this function.

	pUnkOuter

		Controlling unknown of the aggregate. Its value must be NULL.

Return Values:

	If the function succeeds, the return value is DS_OK.
	If the function fails, the return value may be one of the following error values:
		DSERR_ALLOCATED 
		DSERR_INVALIDPARAM 
		DSERR_NOAGGREGATION 
		DSERR_NODRIVER 
		DSERR_OUTOFMEMORY 

        Since most of the time we just use the primary sound driver, this function is often set with both the lpGuid and pUnkOuter set to null. The following example shows how one would create a DirectSound Object with its sound device set to the primary sound driver.


LPDIRECTSOUND pds;
if (FAILED (DirectSoundCreate (NULL, pds, NULL))) return false;

Setting the Cooperative Level TOC

        Immediately after creating a DirectSound Object you should call SetCooperativeLevel. This will bind the Object to a window and determine how the sound device will be shared with other applications. It must be set before the buffers are able to be played. SetCooperativeLevel looks as follows:


HRESULT SetCooperativeLevel(
  HWND hwnd,     
  DWORD dwLevel  
);
 
Parameters:

	hwnd

		Window handle to the application.

	dwLevel

		Requested priority level. Specify one of the following values: 

		DSSCL_EXCLUSIVE 

			Sets the application to the exclusive level. When it has the input focus, the application will
			be the only one audible (sounds from applications with the DSBCAPS_GLOBALFOCUS flag set will be
			muted). With this level, it also has all the privileges of the DSSCL_PRIORITY level.
			DirectSound will restore the hardware format, as specified by the most recent call to the
			IDirectSoundBuffer::SetFormat method, once the application gains the input focus. (Note that
			DirectSound will always restore the wave format no matter what priority level is set.) 

		DSSCL_NORMAL 

			Sets the application to a fully cooperative status. Most applications should use this level,
			because it has the smoothest multitasking and resource-sharing behavior. 

		DSSCL_PRIORITY 

			Sets the application to the priority level. Applications with this cooperative level can call
			the IDirectSoundBuffer::SetFormat and IDirectSound::Compact methods. 
			
		DSSCL_WRITEPRIMARY 

			This is the highest priority level. The application has write access to the primary sound
			buffers. No secondary sound buffers can be played. This level cannot be set if the DirectSound
			driver is being emulated for the device; that is, if the IDirectSound::GetCaps method returns
			the DSCAPS_EMULDRIVER flag in the DSCAPS structure.

Return Values:

	If the method succeeds, the return value is DS_OK.
	If the method fails, the return value may be one of the following error values: 
		DSERR_ALLOCATED 
		DSERR_INVALIDPARAM 
		DSERR_UNINITIALIZED 
		DSERR_UNSUPPORTED

  • TIP -- If using DirectSound with DirectDraw, make sure that the hwnd passed into SetCooperativeLevel for the DirectSound Object is the same as the hwnd passed into the DirectDraw's SetCooperativeLevel, otherwise you will get a DDERR_HWNDALREADYSET error.

        The recommended level is DSSCL_NORMAL, most of the time this is what a program uses as its level. DSSCL_PRIORITY can be used, but only when you have to. DSSCL_WRITEPRIMARY should only be used for highly specialized applications that need to do there own mixing. Here is an example of how to call SetCooperativeLevel.


LPDIRECTSOUND pds;
if (FAILED (DirectSoundCreate (NULL, pds, NULL))) return false;
if (FAILED (pds->SetCooperativeLevel (hwnd, DSSCL_NORMAL))) return false;

Setting the Primary Format TOC

        After we have created our DirectSound Object and set its cooperative level, we now need to set up it's primary buffer format. To do this we first need to declare and initialize DSBUFFERDESC sturcture. The DSBUFFERDESC struct looks as follows:


typedef struct { 
    DWORD           dwSize; 
    DWORD           dwFlags; 
    DWORD           dwBufferBytes; 
    DWORD           dwReserved; 
    LPWAVEFORMATEX  lpwfxFormat; 
} DSBUFFERDESC, *LPDSBUFFERDESC; 
 
typedef const DSBUFFERDESC *LPCDSBUFFERDESC;
 
Members:

	dwSize

		Size of the structure, in bytes. This member must be initialized before the structure is used.

	dwFlags

		Identifies the capabilities to include when creating a new DirectSoundBuffer object. Specify 
		one or more of the following: 
		
			DSBCAPS_CTRL3D 

				The buffer is either a primary buffer or a secondary buffer that uses 3-D control. 

			DSBCAPS_CTRLALL 

				The buffer must have all control capabilities. 

			DSBCAPS_CTRLDEFAULT 

				The buffer should have default control options. This is the same as specifying the
				DSBCAPS_CTRLPAN, DSBCAPS_CTRLVOLUME, and DSBCAPS_CTRLFREQUENCY flags. 

			DSBCAPS_CTRLFREQUENCY 

				The buffer must have frequency control capability. 

			DSBCAPS_CTRLPAN 

				The buffer must have pan control capability. 

			DSBCAPS_CTRLPOSITIONNOTIFY 

				The buffer must have position notification capability. 

			DSBCAPS_CTRLVOLUME 

				The buffer must have volume control capability. 

			DSBCAPS_GETCURRENTPOSITION2 

				Indicates that IDirectSoundBuffer::GetCurrentPosition should use the new behavior
				of the play cursor. In DirectSound in DirectX 1, the play cursor was significantly 
				ahead of the actual playing sound on emulated sound cards; it was directly behind 
				the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the
				application can get a moreaccurate play position. If this flag is not specified, 
				the old behavior is preserved for compatibility. Note that this flag affects only 
				emulated sound cards; if a DirectSound driver is present, the play cursor is 
				accurate for DirectSound in all versions of DirectX. 

			DSBCAPS_GLOBALFOCUS 

				The buffer is a global sound buffer. With this flag set, an application using 
				DirectSound can continue to play its buffers if the user switches focus to another
				application, even if the new application uses DirectSound. The one exception is if 
				you switch focus to a DirectSound application that uses the DSSCL_EXCLUSIVE or
				DSSCL_WRITEPRIMARY flag for its	cooperative level. In this case, the global sounds
				from other applications will not be	audible. 

			DSBCAPS_LOCHARDWARE 

				Forces the buffer to use hardware mixing, even if DSBCAPS_STATIC is not specified. 
				If the device does not support hardware mixing or if the required hardware memory 
				is not available, the call to the IDirectSound::CreateSoundBuffer method will fail.
				The application must ensure that a mixing channel will be available for this buffer;
				this condition is not guaranteed. 

			DSBCAPS_LOCSOFTWARE 

				Forces the buffer to be stored in software memory and use software mixing, even if
				DSBCAPS_STATIC is specified and hardware resources are available. 

			DSBCAPS_MUTE3DATMAXDISTANCE 

				The sound is to be reduced to silence at the maximum distance. The buffer will stop
				playing	when the maximum distance is exceeded, so that processor time is not wasted.

			DSBCAPS_PRIMARYBUFFER 

				Indicates that the buffer is a primary sound buffer. If this value is not specified, a
				secondary sound buffer will be created. 

			DSBCAPS_STATIC 

				Indicates that the buffer will be used for static sound data. Typically, these buffers 
				are loaded once and played many times. These buffers are candidates for hardware memory.

			DSBCAPS_STICKYFOCUS 

				Changes the focus behavior of the sound buffer. This flag can be specified in an
				IDirectSound::CreateSoundBuffer call. With this flag set, an application using 
				DirectSound can continue to play its sticky focus buffers if the user switches to 
				another application	not using DirectSound. In this situation, the application's 
				normal buffers are muted, but the sticky focus buffers are still audible. This is 
				useful for nongame applications, such as movie playback (DirectShow), when the user 
				wants to hear the soundtrack while typing in Microsoft Word or Microsoft Excel, for
				example. However, if the user switches to another DirectSound application, all sound
				buffers, both normal and sticky focus, in the previous application are muted. 

		dwBufferBytes

			Size of the new buffer, in bytes. This value must be 0 when creating primary buffers. For
			secondary buffers, the minimum and maximum sizes allowed are specified by DSBSIZE_MIN and
			DSBSIZE_MAX, defined in Dsound.h.

		dwReserved

			This value is reserved. Do not use.

		lpwfxFormat

			Address of a structure specifying the waveform format for the buffer. This value must 
			be NULL for primary buffers. The application can use IDirectSoundBuffer::SetFormat to 
			set the format of the primary buffer.

        Once we have the DSBUFFERDESC structure set up the way we want our primary buffer to look, we then call the CreateSoundBuffer and create the primary buffer.
  • NOTE -- Unless specified the primary buffer is created with the default settings. The default has a frequency of 22,050 Hz, 2 channels, and 8 bits per sample. This might not be what you want. You can change it by setting the DSBUFFERDESC structure to the format that you want, but you need to have the cooperative level set to at least DSSCL_PRIORITY to change the primary buffer from the default settings.
CreateSoundBuffer looks as follows:


HRESULT CreateSoundBuffer(
  LPCDSBUFFERDESC lpcDSBufferDesc,              
  LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer,  
  IUnknown FAR * pUnkOuter                      
);
 

Parameters:

	lpcDSBufferDesc

		Address of a DSBUFFERDESC structure that contains the description of the sound buffer to be
		created.

	lplpDirectSoundBuffer

		Address of a pointer to the new DirectSoundBuffer object, or NULL if the buffer cannot be created.

	pUnkOuter

		Controlling unknown of the aggregate. Its value must be NULL.

Return Values:

	If the method succeeds, the return value is DS_OK.
	If the method fails, the return value may be one of the following error values:
		DSERR_ALLOCATED 
		DSERR_BADFORMAT 
		DSERR_INVALIDPARAM 
		DSERR_NOAGGREGATION 
		DSERR_OUTOFMEMORY 
		DSERR_UNINITIALIZED 
		DSERR_UNSUPPORTED 

        After CreateSoundBuffer for the primary buffer has been called if we want to set the format we need to set up a WAVEFORMATEX structure. This structure is not part of DirectSound, it is a part of the Multi-media API. None-the-less DirectSound uses this structure to specify the format of a buffer. The WAVEFORMATEX structure looks as follows:


typedef struct {  
    WORD  wFormatTag; 
    WORD  nChannels; 
    DWORD nSamplesPerSec; 
    DWORD nAvgBytesPerSec; 
    WORD  nBlockAlign; 
    WORD  wBitsPerSample; 
    WORD  cbSize; 
} WAVEFORMATEX; 
 
Members:

	wFormatTag

		Waveform-audio format type. Format tags are registered with Microsoft Corporation for many
		compression algorithms. A complete list of format tags can be found in the MMREG.H header file.

	nChannels

		Number of channels in the waveform-audio data. Monaural data uses one channel and stereo data uses
		two channels.

	nSamplesPerSec

		Sample rate, in samples per second (hertz), that each channel should be played or recorded. If
		wFormatTag is WAVE_FORMAT_PCM, then common values for nSamplesPerSec are 8.0 kHz, 11.025 kHz, 22.05
		kHz, and 44.1 kHz. For non-PCM formats, this member must be computed according to the
		manufacturer's specification of the format tag.

	nAvgBytesPerSec

		Required average data-transfer rate, in bytes per second, for the format tag. If wFormatTag is
		WAVE_FORMAT_PCM, nAvgBytesPerSec should be equal to the product of nSamplesPerSec and nBlockAlign.
		For non-PCM formats, this member must be computed according to the manufacturer's specification of
		the format tag.  Playback and record software can estimate buffer sizes by using the 	
		nAvgBytesPerSec member.

	nBlockAlign

		Block alignment, in bytes. The block alignment is the minimum atomic unit of data for the
		wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, nBlockAlign should be equal to the
		product of nChannels and wBitsPerSample divided by 8 (bits per byte). For non-PCM formats, this
		member must be computed according to the manufacturer's specification of the format tag.  Playback
		and record software must process a multiple of nBlockAlign bytes of data at a time. Data written
		and read from a device must always start at the beginning of a block. For example, it is illegal to
		start playback of PCM data in the middle of a sample (that is, on a non-block-aligned boundary).

	wBitsPerSample

		Bits per sample for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, then 
		wBitsPerSample should be equal to 8 or 16. For non-PCM formats, this member must be set according
		to the manufacturer's specification of the format tag. Note that some compression schemes cannot
		define a value for wBitsPerSample, so this member can be zero.

	cbSize

		Size, in bytes, of extra format information appended to the end of the WAVEFORMATEX structure. This
		information can be used by non-PCM formats to store extra attributes for the wFormatTag. If no
		extra information is required by the wFormatTag, this member must be set to zero. Note that for
		WAVE_FORMAT_PCM formats (and only WAVE_FORMAT_PCM formats), this member is ignored.

        To set the WAVEFORMATEX structure to the desired sound buffer we will use the SetFormat function. The SetFormat function looks as follows:


HRESULT SetFormat(
  LPCWAVEFORMATEX lpcfxFormat  
);
 
Parameters:

	lpcfxFormat

		Address of a WAVEFORMATEX structure that describes the new format for the primary sound buffer.

Return Values:

	If the method succeeds, the return value is DS_OK.
	If the method fails, the return value may be one of the following error values:
		DSERR_BADFORMAT 
		DSERR_INVALIDCALL 
		DSERR_INVALIDPARAM 
		DSERR_OUTOFMEMORY 
		DSERR_PRIOLEVELNEEDED 
		DSERR_UNSUPPORTED 

        The following is an example of using the DSBUFFERDESC and the WAVEFORMATEX structure along with CreateSoundBuffer and SetFormat to create our primary buffer with a specified format.


LPDIRECTSOUND pds;
DSBUFFERDESC bd;
LPDIRECTSOUNDBUFFER pdsb;
WAVEFORMATEX wf;

if (FAILED (DirectSoundCreate (NULL, pds, NULL))) return false;
if (FAILED (pds->SetCooperativeLevel (hwnd, DSSCL_NORMAL))) return false;

memset (&bd, 0, sizeof (DSBUFFERDESC));
bd.dwSize = sizeof (DSBUFFERDESC);
bd.dwFlags = DSBCAPS_PRIMARYBUFFER;
bd.dwBufferBytes = 0;     //must be 0 for primary buffer
bd.lpwfxFormat = NULL;    //must be null for primary buffer

memset (&wf, 0, sizeof (WAVEFORMATEX));
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = 2;
wf.nSamplesPerSec = 44100;
wf.wBitsPerSample = 16;
wf.nBlockAlign = 4;
wf.nAvgBytesPerSec = 176400;

if (SUCCEEDED (pds->CreateSoundBuffer (&bd, &pdsb, NULL))) 
	//if primary buffer was created successfully then set its format,
	//otherwaise we will just use the default.
	pdsb->SetFormat (&wf);


Conclusion TOC

        With the primary buffer set up and the Object created, DirectSound is all set up. To sum it up here are the key points:
  • DirectSound works by using sound buffers. You create secondary buffers load PCM data into them and then mix them down to the primary buffer that sends the mix off to the audio device.
  • You can use, but don't have to, DirectSoundEnumerate to generate a list of audio devices and locate a GUID for the disired audio device.
  • You create a DirectSound Object using DirectSoundCreate.
  • After creating the DirectSound Object you must call SetCooperativeLevel to bind the Object ot a window and determine how the audio device is shared with other applications.
  • You can use the DSBUFFERDESC and WAVEFORMATEX structures with the CreateSoundBuffer and SetFormat functions to specify a format for the primary buffer.
You are now ready to create some secondary buffers and make some noise!

Appendix A: An Example TOC

The following code is an example of how to do what was talked about in this example.

#define DIRECTSOUND_VERSION 5

#include <dsound.h>
#include<vector>
#include<string>
#include<iostream>
#pragma hdrstop

using namespace std;

struct AudioDevice
{
  LPGUID guid;
  string description;
  string module;
  AudioDevice (){
    guid = NULL;
  }
  ~AudioDevice (){
    delete guid;
  }
};

typedef vector<AudioDevice*> AudioDevices;

BOOL CALLBACK EnumCallBack (LPGUID guid, LPCSTR desc,
  LPCSTR mod, LPVOID list)
{
  AudioDevice *ad = new AudioDevice;
  if (guid == NULL)
    ad->guid = NULL;
  else{
    ad->guid = new GUID;
    memcpy (ad->guid, guid, sizeof (GUID));
  }
  ad->description = desc;
  ad->module = mod;
  (static_cast<AudioDevices*>(list))->push_back (ad);
  return true;
}
const char* app_title = "Direct Sound CP player";
LPDIRECTSOUND pds;
#pragma argsused
int main(int argc, char* argv[])
{
  AudioDevices ads;
  unsigned int i;
  string filename;

  if (argc != 2){
    cout << "Usage: dsenumprj.exe <wave file>" << endl;
    return 2;
  }

  filename = argv[1];
  SetConsoleTitle (app_title);

  if (FAILED (DirectSoundEnumerate (EnumCallBack, &ads))){
    cout << "Couldn't enumerate the audio devices" << endl;
    return 1;
  }
  for (i = 0; i < ads.size (); i++)
  {
    cout << i << ":t" << ads[i]->description << "t" << ads[i]->module << endl;
  }
  cout << endl << "Which drive shall we use?: ";
  cin >> i;
  if (i > ads.size () - 1){
    cout << "Not a valid choice, using default" << endl;
    i = 0;
  }
  if (FAILED (DirectSoundCreate (ads[i]->guid, &pds, NULL))){
    cout << "Unable to create the DirectSound Object!!!" << endl;
    return 3;
  }
  if (FAILED (pds->SetCooperativeLevel (FindWindow (NULL, app_title),
    DSSCL_PRIORITY))){
      cout << "Unable to set the cooperative level!!!" << endl;
      return 4;
  }
  DSBUFFERDESC bd;
  LPDIRECTSOUNDBUFFER ppdsb, psdsb;
  WAVEFORMATEX wf;

  memset (&bd, 0, sizeof (DSBUFFERDESC));
  bd.dwSize = sizeof (DSBUFFERDESC);
  bd.dwFlags = DSBCAPS_PRIMARYBUFFER;
  bd.dwBufferBytes = 0;     //must be 0 for primary buffer
  bd.lpwfxFormat = NULL;    //must be null for primary buffer

  memset (&wf, 0, sizeof (WAVEFORMATEX));
  wf.wFormatTag = WAVE_FORMAT_PCM;
  wf.nChannels = 2;
  wf.nSamplesPerSec = 44100;
  wf.wBitsPerSample = 16;
  wf.nBlockAlign = 4;
  wf.nAvgBytesPerSec = 176400;

  if (SUCCEEDED (pds->CreateSoundBuffer (&bd, &ppdsb, NULL))){
    ppdsb->SetFormat (&wf);
  }

  return 0;
}

Appendix B: Creating a dsound import library TOC

        Chances are that you are going to have to create a import library for the dsound.dll. If you have DirectX installed on your machine, this DLL will live in the windows/system directory. If you don't have DirectX installed, go to Microsoft's site and download the SDK. Here are the steps for creating the import library:
  1. open a command prompt
  2. change directories to the c:/window/system directory (cd c:windowssystem)
  3. type the following: implib <path to bcb>libdsound.lib dsound.dll
This will create a dsound.lib file in you bcb/lib directory. To use this in your application link dsound.lib to your project.
  • NOTE -- If you get unresolved external linker errors on the DirectSound functions this is more then likely your problem. Make the import library and link it in and your linker errors will go away.

References TOC

Inside DirectX, Bradley Bargen and Peter Donnelly, "Microsoft Press", 1998.


Server Response from: ETNASC03