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.
SDL_Init(SDL_INIT_AUDIO);
SDL_INIT_AUDIO
– bit‑flag enabling the audio subsystem. Combine multiple flags with |
if you need other subsystems (e.g. SDL_INIT_VIDEO
).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 */
);
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".SDL_AudioSpec
Fieldsfreq
– 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).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);
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.
/* push audio data */
SDL_QueueAudio(audio_dev, wav_buffer, wav_length);
/* start playback */
SDL_PauseAudioDevice(audio_dev, 0); /* 0 = unpause */
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_on
– 1
= pause, 0
= start/unpause.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);
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.
/* 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 */
);
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%.if (audio_dev == 0) {
fprintf(stderr, "Failed to open audio: %s\n", SDL_GetError());
}
SDL_GetError
– returns a human‑readable string describing the last SDL error. Thread‑safe.SDL_CloseAudioDevice(audio_dev);
SDL_FreeWAV(wav_buffer);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
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).SDL_Quit()
when all subsystems are done.