Primary and Secondary Sound Buffers
Primary sound buffers represent the audio samples that the listener will hear. Secondary sound 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 is created.
Usually you should create a secondary sound buffer for every sound in an application. Note that your application can reuse sound buffers by overwriting the old sound data with new data. DirectSound takes care of the hardware resource allocation and the mixing of all buffers that are playing.
If your application uses secondary buffers, you can 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 buffer memory, such as IDirectSoundBuffer::Lock and IDirectSoundBuffer::GetCurrentPosition, fail.
If your application performs its own mixing, DirectSound provides write access to the primary buffer. You should write data to 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 available only if your application sets the DSSCL_WRITEPRIMARY cooperative level. At this cooperative level, no secondary buffers can be played.
Note that your application must play primary sound buffers with looping. Ensure 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;
// Buffer size is determined by sound hardware.
dsbdesc.dwBufferBytes = 0;
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;
}
}
}
// SetCooperativeLevel failed.
// CreateSoundBuffer, or SetFormat.
*lplpDsb = NULL;
*lpdwBufferSize = 0;
return FALSE;
}