For applications that require specialized mixing or other effects not supported by secondary buffers, DirectSound allows direct access to the primary buffer.
When you obtain write access to a primary sound buffer, other DirectSound features become unavailable. Secondary buffers are not mixed and, consequently, hardware-accelerated mixing is unavailable.
Most applications should use secondary buffers instead of directly accessing the primary buffer. Applications can write to a secondary buffer easily because the larger buffer size provides more time to write the next block of data, thereby minimizing the risk of gaps in the audio. Even if an application has simple audio requirements, such as using one stream of audio data that does not require mixing, it will achieve better performance by using a secondary buffer to play its audio data.
You cannot specify the size of the primary buffer, and you must accept the returned size after the buffer is created. A primary buffer is typically very small, so if your application writes directly to this kind of buffer, it must write blocks of data at short intervals to prevent the previously written data from being replayed.
You create an accessible primary buffer by specifying the DSBCAPS_PRIMARYBUFFER flag in the DSBUFFERDESC structure passed to the IDirectSound::CreateSoundBuffer method. If you want to write to the buffer, the cooperative level must be DSSCL_WRITEPRIMARY.
You cannot obtain write access to a primary buffer unless it exists in hardware. To determine whether this is the case, call the IDirectSoundBuffer::GetCaps method and check for the DSBCAPS_LOCHARDWARE flag in the dwFlags member of the DSBCAPS structure that is returned. If you attempt to lock a primary buffer that is emulated in software, the call will fail.
Primary sound buffers must be played 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;
WAVEFORMATEX wf;
// Set up wave format structure.
memset(&wf, 0, sizeof(WAVEFORMATEX));
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = 2;
wf.nSamplesPerSec = 22050;
wf.nBlockAlign = 4;
wf.nAvgBytesPerSec =
wf.nSamplesPerSec * wf.nBlockAlign;
wf.wBitsPerSample = 16;
// Set up DSBUFFERDESC structure.
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
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 SUCCEEDED(hr)
{
// Try to create buffer.
hr = lpDirectSound->lpVtbl->CreateSoundBuffer(lpDirectSound,
&dsbdesc, lplpDsb, NULL);
if SUCCEEDED(hr)
{
// Set primary buffer to desired format.
hr = (*lplpDsb)->lpVtbl->SetFormat(*lplpDsb, &wf);
if SUCCEEDED(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;
}
}
}
// Failure.
*lplpDsb = NULL;
*lpdwBufferSize = 0;
return FALSE;
}
You may also create a primary buffer object without write access, by specifying a cooperative level other than DSSCL_WRITEPRIMARY. One reason for doing this would be to call the IDirectSoundBuffer::Play method for the primary buffer, in order to eliminate problems associated with frequent short periods of silence. For more information, see Playing the Primary Buffer Continuously.
See also Custom Mixers.