Primary and Secondary Sound Buffers

Primary sound buffers represent the actual audio samples that the listener will hear. Secondary buffers each represent a single sound or stream of audio. Your application can create a primary buffer by specifying the DSBCAPS_PRIMARYBUFFER flag in the DSBUFFERDESC structure. If this flag is not specified, a secondary buffer will be created.

Usually you should create secondary sound buffers for each sound in a given application. Note that sound buffers can be reused by overwriting the old sound data with new data. DirectSound takes care of the hardware resource allocation and the mixing together of all buffers that are playing.

If your application uses secondary buffers, you may choose to create a primary sound buffer to perform certain controls. For example, you can control the hardware output format by calling the IDirectSoundBuffer::SetFormat method on the primary buffer. However, any methods that access the actual buffer memory, such as IDirectSoundBuffer::Lock and IDirectSoundBuffer::GetCurrentPosition, will fail.

If your application performs its own mixing, DirectSound provides write access to the primary buffer. You should write data into this buffer in a timely manner; if you do not update the data, the previous buffer will repeat itself, causing gaps in the audio. Write access to the primary buffer is only available if your application has the DSSCL_WRITEPRIMARY cooperative level. At this cooperative level, no secondary buffers can be played.

Note that primary sound buffers must be played with looping. Be sure that the DSBPLAY_LOOPING flag is set.

The following example shows how to obtain write access to the primary buffer:

BOOL AppCreateWritePrimaryBuffer(

LPDIRECTSOUND lpDirectSound,

LPDIRECTSOUNDBUFFER *lplpDsb,

LPDWORD lpdwBufferSize,

HWND hwnd)

{

DSBUFFERDESC dsbdesc;

DSBCAPS dsbcaps;

HRESULT hr;

// Set up wave format structure.

memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT));

pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;

pcmwf.wf.nChannels = 2;

pcmwf.wf.nSamplesPerSec = 22050;

pcmwf.wf.nBlockAlign = 4;

pcmwf.wf.nAvgBytesPerSec =

pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;

pcmwf.wBitsPerSample = 16;

// Set up DSBUFFERDESC structure.

memset(&lplpDsb, 0, sizeof(DSBUFFERDESC)); // Zero it out.

dsbdesc.dwSize = sizeof(DSBUFFERDESC);

dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;

dsbdesc.dwBufferBytes = 0; // Buffer size is determined

// by sound hardware.

dsbdesc.lpwfxFormat = NULL; // Must be NULL for primary buffers.

// Obtain write-primary cooperative level.

hr = lpDirectSound->lpVtbl->SetCooperativeLevel(lpDirectSound,

hwnd, DSSCL_WRITEPRIMARY);

if(DS_OK == hr) {

// Succeeded! Try to create buffer.

hr = lpDirectSound->lpVtbl->CreateSoundBuffer(lpDirectSound,

&dsbdesc, lplpDsb, NULL);

if(DS_OK == hr) {

// Succeeded! Set primary buffer to desired format.

hr = (*lplpDsb)->lpVtbl->SetFormat(*lplpDsb, &pcmwf);

if(DS_OK == hr) {

// If you want to know the buffer size, call GetCaps.

dsbcaps.dwSize = sizeof(DSBCAPS);

(*lplpDsb)->lpVtbl->GetCaps(*lplpDsb, &dsbcaps);

*lpdwBufferSize = dsbcaps.dwBufferBytes;

return TRUE;

}

}

}

// If we got here, then we failed SetCooperativeLevel.

// CreateSoundBuffer, or SetFormat.

*lplpDsb = NULL;

*lpdwBufferSize = 0;

return FALSE;

}