Playing a WAV File Using SDL2

Sound effects and music are fundamental in giving life to a game. In this article, we’re going to see how we can play a simple WAV file using just the native SDL2 Audio APIs. Unfortunately these APIs are very tricky to use, and the documentation is littered with incoherent examples and legacy function calls. For this reason, most people prefer to use the SDL_mixer extension library to handle sound and music.

The source code for this article is available at the Gigi Labs BitBucket repository. It includes a sample WAV file generated with Bfxr. You will need to copy the WAV file into the output directly (along with SDL2.dll) before running the program.

While error handling has been omitted in this article for conciseness, checking the output of each SDL2 function call and showing something in case of error (e.g. using SDL_ShowSimpleMessageBox()) will save you a lot of hair-ripping experiences.

In order to use audio in SDL2, the first thing we need to do is initialise the audio subsystem when we initialise SDL2 itself:

SDL_Init(SDL_INIT_AUDIO);

We can play simple sound effects in SDL2 by loading and playing a WAV file. We can load a WAV file by calling SDL_LoadWAV(), passing in arguments which it will populate with data read from the WAV file:

	// load WAV file

	SDL_AudioSpec wavSpec;
	Uint32 wavLength;
	Uint8 *wavBuffer;

	SDL_LoadWAV("Powerup5.wav", &wavSpec, &wavBuffer, &wavLength);

The next thing we need to do is get a handle on our audio device, which is a fancy way of saying speakers (or headphones, or whatever).

	// open audio device

	SDL_AudioDeviceID deviceId = SDL_OpenAudioDevice(NULL, 0, &wavSpec, NULL, 0);

You’ll notice we have a bunch of arguments, and for most of them we aren’t really caring about the details and passing in NULL or 0 to get reasonable defaults. Below is a summary of what each argument does; feel free to skip it if you just want to get something up and running quickly.

  • The first argument is the name of the audio device you want to open. While you might have several, passing in NULL will give you a reasonable default audio device. You can, however, use this to explicitly name a device you want to use – see SDL_OpenAudioDevice() documentation for more detail.
  • The second argument is relevant to recording devices, and we don’t care about it for playback.
  • The third argument represents the desired audio output format. We already got this information when we read the WAV file.
  • If provided, the fourth argument will be populated with the actual output format of the audio device. In our case, we don’t care, and can pass NULL.
  • The fifth argument is for advanced scenarios and we don’t need it either.

Now that we have a handle on the audio device, we can actually play something:

	// play audio

	int success = SDL_QueueAudio(deviceId, wavBuffer, wavLength);
	SDL_PauseAudioDevice(deviceId, 0);

SDL_QueueAudio is a handy function available since SDL 2.0.4 (at the time of writing this article, the current stable version is 2.0.5) that lets you send WAV (audio) data to the audio device without having to register callback functions (which is what you’d otherwise have to do).

SDL_PauseAudioDevice() is used to pause/unpause audio playback on the audio device (depending on the value of the second parameter). By passing 0 as the second parameter, we are enabling playback (i.e. unpausing the audio device), and this allows the sound to be played.

Let’s add a small delay so that we can hear the sound before the application exits:

	// keep application running long enough to hear the sound

	SDL_Delay(3000);

Finally, let’s remember to clean up after ourselves before exiting the application:

	// clean up

	SDL_CloseAudioDevice(deviceId);
	SDL_FreeWAV(wavBuffer);
	SDL_Quit();

	return 0;

We can now run the application, and should hear the sound play if everything is set up correctly. If not, then:

  • Remember to have both SDL2.dll (if running under Windows) and the WAV file in the output directory.
  • Make sure the path to the WAV file is set correctly. If running under Visual Studio, you may also need to change the Working Directory project setting. See the last part of “Setting up SDL2 with Visual Studio 2015” for instructions on how to do this.
  • Add error handling logic, as suggested at the beginning of this article.