Playing Sounds
Last Updated 3/24/14
Playing sound is another key concept of game programming. SDL's native sound functions can be quite confusing. So you're going to learn to play sound effects and music using the extension library SDL_mixer. SDL_mixer is an extension library that makes using sound braindead easy.You can get SDL_mixer from here.
To install SDL_mixer just follow the extension library tutorial. Installing SDL_mixer is done pretty much the way SDL_image is, so just replace where you see SDL_image with SDL_mixer.
This tutorial covers the basics playing music and sound effects using SDL_mixer to play sound effects and "music" I made by tapping on my monitor.
A Sound Effects and Music tutorial with SDL 2 is now available.
//The music that will be played
Mix_Music *music = NULL;
//The sound effects that will be used
Mix_Chunk *scratch = NULL;
Mix_Chunk *high = NULL;
Mix_Chunk *med = NULL;
Mix_Chunk *low = NULL;
Here's the new data types we are going to be working with.
Mix_Music is the data type we use for music, and Mix_Chunk is the data type used for sound effects.
Mix_Music is the data type we use for music, and Mix_Chunk is the data type used for sound effects.
bool init()
{
//Initialize all SDL subsystems
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return false;
}
//Set up the screen
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
//If there was an error in setting up the screen
if( screen == NULL )
{
return false;
}
//Initialize SDL_ttf
if( TTF_Init() == -1 )
{
return false;
}
//Initialize SDL_mixer
if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 )
{
return false;
}
//Set the window caption
SDL_WM_SetCaption( "Monitor Music", NULL );
//If everything initialized fine
return true;
}
In the initialization function, we call Mix_OpenAudio() to initialize SDL_mixer's audio functions.
Mix_OpenAudio()'s first argument is the sound frequency we use, and in this case it's 22050 which is what's recommended. The second argument is the sound format used which we set to the default. The third argument is how many channels we plan to use. We set it to 2 so we have stereo sound, if it was set to one we'd have mono sound. The last argument is the sample size, which is set to 4096.
For those of you using OGG, MOD, or other sound formats other than WAV, look into using Mix_Init() to initialize decoders and Mix_Quit() to close the decoders. We're only using WAV files here so let's not add more code for something we're not going to use.
Mix_OpenAudio()'s first argument is the sound frequency we use, and in this case it's 22050 which is what's recommended. The second argument is the sound format used which we set to the default. The third argument is how many channels we plan to use. We set it to 2 so we have stereo sound, if it was set to one we'd have mono sound. The last argument is the sample size, which is set to 4096.
For those of you using OGG, MOD, or other sound formats other than WAV, look into using Mix_Init() to initialize decoders and Mix_Quit() to close the decoders. We're only using WAV files here so let's not add more code for something we're not going to use.
bool load_files()
{
//Load the background image
background = load_image( "background.png" );
//Open the font
font = TTF_OpenFont( "lazy.ttf", 30 );
//If there was a problem in loading the background
if( background == NULL )
{
return false;
}
//If there was an error in loading the font
if( font == NULL )
{
return false;
}
//Load the music
music = Mix_LoadMUS( "beat.wav" );
//If there was a problem loading the music
if( music == NULL )
{
return false;
}
//Load the sound effects
scratch = Mix_LoadWAV( "scratch.wav" );
high = Mix_LoadWAV( "high.wav" );
med = Mix_LoadWAV( "medium.wav" );
low = Mix_LoadWAV( "low.wav" );
//If there was a problem loading the sound effects
if( ( scratch == NULL ) || ( high == NULL ) || ( med == NULL ) || ( low == NULL ) )
{
return false;
}
//If everything loaded fine
return true;
}
Here we have the file loading function.
To load the music, we use Mix_LoadMUS(). Mix_LoadMUS() takes in the filename of the music file and returns the music data. It return NULL if there's an error.
To load sound effects, we use Mix_LoadWAV(). It loads the sound file of the given file name, and returns a Mix_Chunk or NULL if there was an error.
To load the music, we use Mix_LoadMUS(). Mix_LoadMUS() takes in the filename of the music file and returns the music data. It return NULL if there's an error.
To load sound effects, we use Mix_LoadWAV(). It loads the sound file of the given file name, and returns a Mix_Chunk or NULL if there was an error.
void clean_up()
{
//Free the surfaces
SDL_FreeSurface( background );
//Free the sound effects
Mix_FreeChunk( scratch );
Mix_FreeChunk( high );
Mix_FreeChunk( med );
Mix_FreeChunk( low );
//Free the music
Mix_FreeMusic( music );
//Close the font
TTF_CloseFont( font );
//Quit SDL_mixer
Mix_CloseAudio();
//Quit SDL_ttf
TTF_Quit();
//Quit SDL
SDL_Quit();
}
In the clean up function, we call Mix_FreeChunk() to get rid of the sound effects and Mix_FreeMusic() to free the music.
Then after we're done using SDL_mixer, Mix_CloseAudio() is called.
Then after we're done using SDL_mixer, Mix_CloseAudio() is called.
//While the user hasn't quit
while( quit == false )
{
//While there's events to handle
while( SDL_PollEvent( &event ) )
{
//If a key was pressed
if( event.type == SDL_KEYDOWN )
{
In our main function after the initialization, file loading and background and messages have been blitted, we enter
our main loop. Then we start handling events, starting with key presses.
//If 1 was pressed
if( event.key.keysym.sym == SDLK_1 )
{
//Play the scratch effect
if( Mix_PlayChannel( -1, scratch, 0 ) == -1 )
{
return 1;
}
}
//If 2 was pressed
else if( event.key.keysym.sym == SDLK_2 )
{
//Play the high hit effect
if( Mix_PlayChannel( -1, high, 0 ) == -1 )
{
return 1;
}
}
//If 3 was pressed
else if( event.key.keysym.sym == SDLK_3 )
{
//Play the medium hit effect
if( Mix_PlayChannel( -1, med, 0 ) == -1 )
{
return 1;
}
}
//If 4 was pressed
else if( event.key.keysym.sym == SDLK_4 )
{
//Play the low hit effect
if( Mix_PlayChannel( -1, low, 0 ) == -1 )
{
return 1;
}
}
When checking the key presses, first we check if 1, 2, 3, or 4 have been pressed.
These are the keys that play the sound effects.
If one of the these keys have been pressed, we call Mix_PlayChannel() to play the key's associated sound effect.
Mix_PlayChannel()'s first argument is which mixing channel we're going to play the sound in. Since it's set to -1, Mix_PlayChannel() just looks for the first channel that's available and plays the sound.
The second argument in the Mix_Chunk that's going to be played. The third is how many times the sound effect is going to loop. Since it's set to 0, it will only play once.
When there's a problem playing the sound, Mix_PlayChannel() will return -1.
If one of the these keys have been pressed, we call Mix_PlayChannel() to play the key's associated sound effect.
Mix_PlayChannel()'s first argument is which mixing channel we're going to play the sound in. Since it's set to -1, Mix_PlayChannel() just looks for the first channel that's available and plays the sound.
The second argument in the Mix_Chunk that's going to be played. The third is how many times the sound effect is going to loop. Since it's set to 0, it will only play once.
When there's a problem playing the sound, Mix_PlayChannel() will return -1.
//If 9 was pressed
else if( event.key.keysym.sym == SDLK_9 )
{
//If there is no music playing
if( Mix_PlayingMusic() == 0 )
{
//Play the music
if( Mix_PlayMusic( music, -1 ) == -1 )
{
return 1;
}
}
Next we handle when 9 is pressed, which is supposed to play/pause the music.
First we check if the music is playing with Mix_PlayingMusic(). If no music is playing we call Mix_PlayMusic() to play the music.
The first argument of Mix_PlayMusic() is the music we're going to play. The second argument is how many times it will loop the music. Since it's set to -1, it will loop until it is manually stopped.
If there's a problem in playing the music Mix_PlayMusic() will return -1.
First we check if the music is playing with Mix_PlayingMusic(). If no music is playing we call Mix_PlayMusic() to play the music.
The first argument of Mix_PlayMusic() is the music we're going to play. The second argument is how many times it will loop the music. Since it's set to -1, it will loop until it is manually stopped.
If there's a problem in playing the music Mix_PlayMusic() will return -1.
//If music is being played
else
{
//If the music is paused
if( Mix_PausedMusic() == 1 )
{
//Resume the music
Mix_ResumeMusic();
}
//If the music is playing
else
{
//Pause the music
Mix_PauseMusic();
}
}
}
Now if music was playing when the user pressed 9, we either pause or unpause the music.
First we check if the music is playing using Mix_PausedMusic(). If it is, we unpause the music using Mix_ResumeMusic(). If the music is not paused, we pause it using Mix_PauseMusic()
First we check if the music is playing using Mix_PausedMusic(). If it is, we unpause the music using Mix_ResumeMusic(). If the music is not paused, we pause it using Mix_PauseMusic()
//If 0 was pressed
else if( event.key.keysym.sym == SDLK_0 )
{
//Stop the music
Mix_HaltMusic();
}
}
Lastly, We check if the user presses 0.
If the user presses 0, the music is stopped using Mix_HaltMusic().
If the user presses 0, the music is stopped using Mix_HaltMusic().