Filling and Playing Static Buffers

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.

Loading data into a static buffer is a three-step process:

  1. Lock the entire buffer by using IDirectSoundBuffer8::Lock. You specify the offset within the buffer where you intend to begin writing (normally 0), and get back the memory address of that point.
  2. Write the audio data to the returned address by using a standard memory-copy routine.
  3. Unlock the buffer using IDirectSoundBuffer8::Unlock.

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.