-
-
Save armornick/3447121 to your computer and use it in GitHub Desktop.
#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; | |
} |
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);
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?
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.
great
how i can make it repeat for many times?
This doesn't work for me. Instead of playing the sound once, it fails to play it on first call, then plays it about 5 times when I call this again.
Works great, but I think it would be better to have line 72 commented instead of line 71, since I thought everything was broken :-)
The code doesn't work for me. It's keep repeating the first few seconds over and over . Can anyone help me ? (I'm using SDL 2.0.12 with Code::Blocks 17.12)
Same thing happend to me @NguyenMVo
oh god thats a lot of code xD
Thanks!!
Works great, but I think it would be better to have line 72 commented instead of line 71, since I thought everything was broken :-)
Agree!!!, Commenting line 72 makes a lot noise for me.
Since SDL 2.0.4 you can use SDL_QueueAudio
to not use callbacks
SDL_AudioSpec spec;
Uint8 *data;
Uint32 len;
SDL_LoadWAV("sound.wav", &spec, &data, &len);
SDL_OpenAudio(&spec, NULL);
SDL_QueueAudio(1, data, len);
SDL_PauseAudio(0);
Good and clean sample. Will be using SDL2 to output sound in my Gameboy Advance emulator.