Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Play a sound with SDL2 (no SDL_Mixer)
#include <SDL2/SDL.h>
#define MUS_PATH "Roland-GR-1-Trumpet-C5.wav"
// prototype for our audio callback
// see the implementation for more information
void my_audio_callback(void *userdata, Uint8 *stream, int len);
// variable declarations
static Uint8 *audio_pos; // global pointer to the audio buffer to be played
static Uint32 audio_len; // remaining length of the sample we have to play
/*
** PLAYING A SOUND IS MUCH MORE COMPLICATED THAN IT SHOULD BE
*/
int main(int argc, char* argv[]){
// Initialize SDL.
if (SDL_Init(SDL_INIT_AUDIO) < 0)
return 1;
// local variables
static Uint32 wav_length; // length of our sample
static Uint8 *wav_buffer; // buffer containing our audio file
static SDL_AudioSpec wav_spec; // the specs of our piece of music
/* Load the WAV */
// the specs, length and buffer of our wav are filled
if( SDL_LoadWAV(MUS_PATH, &wav_spec, &wav_buffer, &wav_length) == NULL ){
return 1;
}
// set the callback function
wav_spec.callback = my_audio_callback;
wav_spec.userdata = NULL;
// set our global static variables
audio_pos = wav_buffer; // copy sound buffer
audio_len = wav_length; // copy file length
/* Open the audio device */
if ( SDL_OpenAudio(&wav_spec, NULL) < 0 ){
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
exit(-1);
}
/* Start playing */
SDL_PauseAudio(0);
// wait until we're don't playing
while ( audio_len > 0 ) {
SDL_Delay(100);
}
// shut everything down
SDL_CloseAudio();
SDL_FreeWAV(wav_buffer);
}
// audio callback function
// here you have to copy the data of your audio buffer into the
// requesting audio buffer (stream)
// you should only copy as much as the requested length (len)
void my_audio_callback(void *userdata, Uint8 *stream, int len) {
if (audio_len ==0)
return;
len = ( len > audio_len ? audio_len : len );
//SDL_memcpy (stream, audio_pos, len); // simply copy from one buffer into the other
SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);// mix from one buffer into another
audio_pos += len;
audio_len -= len;
}

aneury1 commented Nov 9, 2015

very good sample.

Quark66 commented Nov 18, 2015

Great example. Clear, functional and running! It is much better than wiki description of separate functions without glue.

bkeys commented Jun 8, 2016

This does not work for me, the load_WAV function returns 1 despite the fact the file is indeed there

I've created a modern version of this (this version isn't scalable and uses deprecated functions), but also with mixing multiple sounds, and playing music vs sounds here: https://github.com/jakebesworth/Simple-SDL2-Audio feel free to try it out!

Good and clean sample. Will be using SDL2 to output sound in my Gameboy Advance emulator.

tinnnysu commented Dec 8, 2016

Good example! But before mix audio, I think that it's better make destination buffer silence, or it may make new programmer like me confused.
SDL_memset(stream, 0, len);

frranck commented Jan 11, 2017

Is there a simple example on how to change the tone ?

Why does this play the sample for every call of my_audio_callback for me?

jordanhalase commented May 13, 2017

There is a race condition on line 75 and line 51 where the main thread checks audio_len as the audio thread writes to it.

It (probably) doesn't matter in this tiny example, but audio_len should be atomic. SDL already provides this as SDL_atomic_t.

@jordanhalase A race condition can usually have adverse effects. In this case, the worst thing that can happen is that the waiting thread reads an older value, so it waits a bit longer than it should. Given that the waiting is achieved with 100ms delays (i.e. the program doesn't guarantee to terminate as soon as the sound finished playing), this is really fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment