Filling and Playing Static Buffers
[The feature associated with this page, DirectSound, is a legacy feature. It has been superseded by WASAPI and Audio Graphs. Media Casting have been optimized for Windows 10 and Windows 11. Microsoft strongly recommends that new code use Media Casting instead of DirectSound, when possible. Microsoft suggests that existing code that uses the legacy APIs be rewritten to use the new APIs if possible.]
A secondary buffer that contains an entire self-contained sound is called a static buffer. Although it is possible to reuse the same buffer for different sounds, typically data is written to a static buffer only once.
Static buffers are created and managed just like streaming buffers. The only difference is in the way they are used: static buffers are filled once and then played, but streaming buffers are constantly refreshed with data as they are playing.
Note
A static buffer is not necessarily one created by setting the DSBCAPS_STATIC flag in the buffer description. This flag requests allocation of memory on the sound card, which is not available on most modern hardware. A static buffer can exist in system memory and can be created with either the DSBCAPS_LOCHARDWARE or DSBCAPS_LOCSOFTWARE flag.
To load data into a static buffer
Use IDirectSoundBuffer8::Lock to lock the entire buffer.
You need to specify the offset within the buffer where you intend to begin writing (normally 0), and get back the memory address of that point.
Use a standard memory-copy routine to write the audio data to the returned address.
Use IDirectSoundBuffer8::Unlock to unlock the buffer.
These steps are shown in the following example, where lpdsbStatic is an IDirectSoundBuffer8 interface pointer and pbData is the address of the data source:
LPVOID lpvWrite; DWORD dwLength; if (DS_OK == lpdsbStatic->Lock( 0, // Offset at which to start lock. 0, // Size of lock; ignored because of flag. &lpvWrite, // Gets address of first part of lock. &dwLength, // Gets size of first part of lock. NULL, // Address of wraparound not needed. NULL, // Size of wraparound not needed. DSBLOCK_ENTIREBUFFER)) // Flag. { memcpy(lpvWrite, pbData, dwLength); lpdsbStatic->Unlock( lpvWrite, // Address of lock start. dwLength, // Size of lock. NULL, // No wraparound portion. 0); // No wraparound size. } else { ErrorHandler(); // Add error-handling here. }
To play the buffer, call IDirectSoundBuffer8::Play, as in the following example:
lpdsbStatic->SetCurrentPosition(0); HRESULT hr = lpdsbStatic->Play( 0, // Unused. 0, // Priority for voice management. 0); // Flags. if (FAILED(hr)) { ErrorHandler(); // Add error-handling here. }
Because the DSBPLAY_LOOPING flag is not set in the example, the buffer automatically stops when it reaches the end. You can also stop it prematurely by using IDirectSoundBuffer8::Stop. When you stop a buffer prematurely, the play cursor position remains where it is. Hence the call to IDirectSoundBuffer8::SetCurrentPosition in the example, which ensures that the buffer starts from the beginning.