DirectSound is Object Oriented

DirectSound in an object-oriented API. What does that mean? Casey starts this episode with a discussion of "method" dispatch through vtables, and why c++ virtual calls are costly.

Reviewing DirectSound Inititalization

The basic process for initializing DirectSound is as follows:

  1. Load the Library - LoadLibrary("dsound.dll")
  2. Create a DirectSound object - DirectSoundCreate()
  3. Set the Cooperative Level - IDirectSound8::SetCooperativeLevel()
  4. "Create" a primary buffer - IDirectSound8::CreateSoundBuffer()
  5. Create a secondary buffer
  6. Tell DirectSound to start playing the secondary buffer - IDirectSoundBuffer8::Play()

Playing sounds

Audio is a complicated topic, and we start with a discussion of audio "waveforms" and how PCM audio data is encoded in memory.

The procedure for writing sound data into a buffer is as follows

  1. Figure out where in the buffer you want to start writing, and how much data you want to write
  2. Acquire a lock on the buffer - IDirectSoundBuffer8::Lock()
    • Because we are working with a circular buffer, this call will return 1 or 2 writable regions
  3. Write the samples to the buffer
  4. Unlock the regions - IDirectSoundBuffer8::Unlock()

A note on audio latency

Audio latency is determined not by the size of the buffer, but by how far ahead of the PlayCursor you write. The optimal amount of latency is the amount that will cause this frame's audio to coincide with the display of this frame's image. On most platforms, it is very difficult to ascertain the proper amount of latency. It's an unsolved problem, and games with need precise AV sync (like Guitar Hero) go to some lengths to achieve it.