Introduction to SDL2 Audio

SDL2 provides a powerful, cross‑platform audio API for playback and capture. This guide covers initialization, loading audio data, playback methods, mixing, error handling, and cleanup with detailed parameter explanations.

Note: ensure SDL2 is installed and linked properly before using audio features.

Initializing SDL Audio Subsystem

SDL_Init(SDL_INIT_AUDIO);

Parameters

  • SDL_INIT_AUDIO – bit‑flag enabling the audio subsystem. Combine multiple flags with | if you need other subsystems (e.g. SDL_INIT_VIDEO).

Opening an Audio Device

SDL_AudioSpec desired{}, obtained{};

desired.freq     = 48000;          /* 48 kHz sample rate           */
desired.format   = AUDIO_F32SYS;   /* 32‑bit float, native endian  */
desired.channels = 2;              /* stereo                       */
desired.samples  = 4096;           /* buffer (power of two)        */
desired.callback = NULL;           /* use queue API                */

audio_dev = SDL_OpenAudioDevice(
    NULL,            /* nullptr = default output device        */
    0,               /* 0 = playback, 1 = capture              */
    &desired,        /* desired spec (filled above)            */
    &obtained,       /* filled with actual values              */
    0                /* allowed changes flags → 0 = strict     */
);

Parameters

  • device (const char*) – name of the device or NULL for the system default.
  • iscapture (int) – 0 for playback, 1 for audio capture.
  • desired – pointer to SDL_AudioSpec describing the format you want.
  • obtained – pointer to SDL_AudioSpec where SDL writes the format you'll actually get (may differ).
  • allowed_changes – bit‑mask (SDL_AUDIO_ALLOW_*) permitting SDL to change freq, format, or channels if needed; 0 means "exact format or fail".

Common SDL_AudioSpec Fields

  • freq – sample rate in Hz (e.g. 44100 or 48000).
  • format – sample format constant (e.g. AUDIO_S16SYS, AUDIO_F32SYS). Suffix SYS picks host endianness.
  • channels – number of interleaved channels: 1 = mono, 2 = stereo, etc.
  • samples – size of the audio buffer (per channel). Must be power of two for most backends.
  • callback – function pointer for pull‑based audio (set NULL to use queue API).
  • userdata – pointer passed untouched to your callback (can be void* struct).

Loading WAV Audio Data

SDL_AudioSpec wav_spec;
Uint32        wav_length;  /* bytes */
Uint8*        wav_buffer;  /* malloc'd by SDL */

SDL_LoadWAV("sound.wav", &wav_spec, &wav_buffer, &wav_length);

Parameters

  • file – path to a RIFF/WAVE file.
  • wav_spec – filled with the audio format stored in the file.
  • wav_buffer – pointer to newly allocated raw sample buffer.
  • wav_length – size of that buffer in bytes, not samples.

Free the buffer with SDL_FreeWAV once finished.

Playing Audio via Queue API

/* push audio data */
SDL_QueueAudio(audio_dev, wav_buffer, wav_length);

/* start playback */
SDL_PauseAudioDevice(audio_dev, 0);  /* 0 = unpause */

Parameters

  • SDL_QueueAudio
    • dev – the device ID returned by SDL_OpenAudioDevice.
    • data – pointer to your sample buffer.
    • len – size in bytes.
  • SDL_PauseAudioDevice
    • dev – same device ID.
    • pause_on1 = pause, 0 = start/unpause.

Using Audio Callbacks

void audio_callback(void* userdata, Uint8* stream, int len) {
    /* fill  with  bytes of audio */
}

desired.callback = audio_callback;

/* (re)open device with callback */
audio_dev = SDL_OpenAudioDevice(NULL,0,&desired,&obtained,0);
SDL_PauseAudioDevice(audio_dev,0);

Callback Parameters

  • userdata – pointer you supplied in desired.userdata (carries state).
  • stream – byte buffer to be filled; initially contains silence.
  • len – size in bytes to fill each invocation.

The callback runs on a dedicated audio thread – avoid heavy work or SDL API calls that might block.

Mixing Multiple Audio Streams


/* mix pcm2 into mix_buffer (same format) */
SDL_MixAudioFormat(
    mix_buffer,     /* destination                       */
    pcm2_buffer,    /* source                            */
    obtained.format,/* audio format constant             */
    pcm2_length,    /* byte count                        */
    SDL_MIX_MAXVOLUME/* volume 0‑128                      */
);

Parameters

  • dst – destination buffer to mix into in place.
  • src – second buffer you wish to add.
  • format – the shared sample format. Must match both buffers.
  • len – number of bytes to mix.
  • volume – 0 (silent) to 128 (full volume). Use SDL_MIX_MAXVOLUME for 100%.

Error Handling

if (audio_dev == 0) {
    fprintf(stderr, "Failed to open audio: %s\n", SDL_GetError());
}

Function

  • SDL_GetError – returns a human‑readable string describing the last SDL error. Thread‑safe.

Cleanup and Shutdown

SDL_CloseAudioDevice(audio_dev);
SDL_FreeWAV(wav_buffer);
SDL_QuitSubSystem(SDL_INIT_AUDIO);

Steps

  • SDL_CloseAudioDevice – stops device and releases backend resources.
  • SDL_FreeWAV – deallocates buffer allocated by SDL_LoadWAV.
  • SDL_QuitSubSystem – matches your SDL_Init call (audio only).
  • Finally (optional but common) SDL_Quit() when all subsystems are done.