Step 1: Setting Up DirectSound

The tutorial requires the following definitions and global variables:

#define NUMEVENTS 2
 
LPDIRECTSOUND               lpds;
DSBUFFERDESC                dsbdesc;
LPDIRECTSOUNDBUFFER         lpdsb;
LPDIRECTSOUNDBUFFER         lpdsbPrimary;
LPDIRECTSOUNDNOTIFY         lpdsNotify;
WAVEFORMATEX                *pwfx;
HMMIO                       hmmio;
MMCKINFO                    mmckinfoData, mmckinfoParent;
DSBPOSITIONNOTIFY           rgdsbpn[NUMEVENTS];
HANDLE                      rghEvent[NUMEVENTS];
 

The first step is to create the DirectSound object, establish a cooperative level, and set the primary buffer format. All this is done in the InitDSound function shown in the following code.

The function takes two parameters: the main window handle and a pointer to the GUID of the sound device. In most cases you will pass NULL as the second parameter, indicating the default device, but you may obtain a GUID by device enumeration.

BOOL InitDSound(HWND hwnd, GUID *pguid)
{
   // Create DirectSound
 
    if FAILED(DirectSoundCreate(pguid, &lpds, NULL)) 
        return FALSE;
 
    // Set co-op level
 
    if FAILED(IDirectSound_SetCooperativeLevel(
            lpds, hwnd, DSSCL_PRIORITY))
        return FALSE;
 

You have set the priority cooperative level in order to be able to set the format of the primary buffer. If you don't change the default format, output will be in the 8-bit, 22 kHz format regardless of the format of the input. Setting the primary buffer to a higher format can do no harm, because even if the secondary buffers are in a lower format, the samples will be converted automatically by DirectSound. Note also that there's no danger of the call to IDirectSoundBuffer::SetFormat failing because the hardware doesn't support the higher format. DirectSound will simply set the closest available format.

To set the format of the primary buffer, you first describe it in the global DSBUFFERDESC structure, then pass this description to the IDirectSound::CreateSoundBuffer method.

    // Obtain primary buffer
 
    ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
    if FAILED(lpds->CreateSoundBuffer(&dsbdesc, &lpdsbPrimary, NULL))
        return FALSE;
 

Once you have a primary buffer object, you describe the desired wave format and pass the description to the IDirectSoundBuffer::SetFormat method:

    // Set primary buffer format
 
    WAVEFORMATEX wfx;
    memset(&wfx, 0, sizeof(WAVEFORMATEX)); 
    wfx.wFormatTag = WAVE_FORMAT_PCM; 
    wfx.nChannels = 2; 
    wfx.nSamplesPerSec = 44100; 
    wfx.wBitsPerSample = 16; 
    wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
 
    hr = lpdsbPrimary->SetFormat(&wfx); 
 
    return TRUE;
}  // InitDSound()