DirectX SDK

Playing Sounds

[C++]

Playing a sound consists of the following steps:

  1. Lock a portion of the secondary buffer using IDirectSoundBuffer::Lock. This method returns a pointer to the address where writing will begin, based on the offset from the beginning of the buffer that you pass in to the method.
  2. Write the audio data to the buffer.
  3. Unlock the buffer using IDirectSoundBuffer::Unlock.
  4. Send the sound to the primary buffer and from there to the output device using IDirectSoundBuffer::Play. If the buffer is a streaming buffer, it will continue playing in a loop as steps 1 to 3 are repeated.

Because streaming sound buffers usually play continually and are conceptually circular, DirectSound returns two write pointers when locking a sound buffer. For example, if you tried to lock 3,000 bytes beginning at the midpoint of a 4,000-byte buffer, the Lock method would return one pointer to the last 2,000 bytes of the buffer, and a second pointer to the first 1,000 bytes. The second pointer is NULL if the locked portion of the buffer does not wrap around.

[Visual Basic]

Playing a sound consists of the following steps:

  1. Create an array to hold the buffer data.
  2. Reallocate the storage buffer to match the buffer size. The formula is: dscursors.lWrite * dsbufferdesc.fxformat.nBlockAlign + 1.
  3. Read a portion of the secondary buffer using DirectSoundBuffer.ReadBuffer. This method sets the address where writing will begin, based on the offset from the beginning of the buffer that you pass in to the method. Keep in mind you have to pass the first element of the array to hold the buffer data.
  4. Write the audio data to the buffer by calling DirectSoundBuffer.WriteBuffer.
  5. Send the sound to the primary buffer and from there to the output device using DirectSoundBuffer.Play. If the buffer is a streaming buffer, it will continue playing in a loop as steps 3 and 4 are repeated.

Because streaming sound buffers usually play continually and are conceptually circular, DirectSound returns two write pointers when locking a sound buffer. For example, if you tried to lock 3,000 bytes beginning at the midpoint of a 4,000-byte buffer, the ReadBuffer method would return one pointer to the last 2,000 bytes of the buffer, and a second pointer to the first 1,000 bytes.

[C++]

Normally the buffer stops playing automatically when the end is reached. However, if the DSBPLAY_LOOPING flag was set in the dwFlags parameter to the Play method, the buffer plays repeatedly until the application calls the IDirectSoundBuffer::Stop method.

[Visual Basic]

Normally the buffer stops playing automatically when the end is reached. However, if the DSBPLAY_LOOPING flag was set in the dwFlags parameter to the Play method, the buffer plays repeatedly until the application calls the DirectSoundBuffer.Stop method.

For streaming sound buffers, your application is responsible for ensuring that each block of data is written to the buffer ahead of the current play position. (For more on the play position, see Current Play and Write Positions.) Applications should write at least 1 second ahead of the current play position to minimize the possibility of gaps in the audio output during playback.

[C++]

The following C example writes data to a sound buffer, starting at the offset into the buffer passed in dwOffset:

BOOL AppWriteDataToBuffer( 
    LPDIRECTSOUNDBUFFER lpDsb,  // the DirectSound buffer
    DWORD dwOffset,             // our own write cursor
    LPBYTE lpbSoundData,        // start of our data
    DWORD dwSoundBytes)         // size of block to copy
{ 
    LPVOID  lpvPtr1; 
    DWORD   dwBytes1; 
    LPVOID  lpvPtr2; 
    DWORD   dwBytes2; 
    HRESULT hr; 
 
    // Obtain memory address of write block. This will be in two parts
    // if the block wraps around.
    hr = lpDsb->lpVtbl->Lock(lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 
        &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
 
    // If DSERR_BUFFERLOST is returned, restore and retry lock. 
    if (DSERR_BUFFERLOST == hr) 
    { 
        lpDsb->lpVtbl->Restore(lpDsb); 
        hr = lpDsb->lpVtbl->Lock(lpDsb, dwOffset, dwSoundBytes, 
            &lpvPtr1, &dwAudio1, &lpvPtr2, &dwAudio2, 0); 
    } 
    if SUCCEEDED(hr) 
    { 
        // Write to pointers. 
        CopyMemory(lpvPtr1, lpbSoundData, dwBytes1); 
        if (NULL != lpvPtr2) 
        { 
            CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2); 
        } 
        // Release the data back to DirectSound. 
        hr = lpDsb->lpVtbl->Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, 
            dwBytes2); 
        if SUCCEEDED(hr) 
        { 
            // Success. 
            return TRUE; 
        } 
    } 
    // Lock, Unlock, or Restore failed. 
    return FALSE; 
}