Previously we saw how to get sound to work on the Raspberry Pi with SDL2 and the SDL2_mixer library. Although this works for simple situations, you’d like your game to have a more sophisticated sound system as we often have many different sound effects playing at once, as well as background music. We could load and play these every time we need them, but when things get busy on the screen this might lead to quite the performace drop.

So we’ll design a class which handles all sound in our application, and we want it to have the following features:

1. Handle sound initialization with separate initialization of sound modules to ease cross-platform development
2. Handle background music and switching it
3. Handling sound effects and repeated sound effects
4. Clean everything up (duh…)

So, we’ll implement the SoundHandler class, with the following interface:

Note that I’m not using Mix_Music for the sound effects, but Mix_Chunk. This is because SDL mixer treats sound effects differently from music. You can only have one music file playing at a time, while you can have multiple sound effects playing at once.

In the last post on programming with SDL2 mixer we saw how to initialize the system, and this is quite straightforward. Initializing Ogg Vorbis is put in a different file as I like to have all my platform-specific code in 1 file:

Note that if your sound files use a different bitrate, you have to change the 44100 in the code

# Handling background music

We also saw how play music in the last post, however we didn’t yet loop it. In order to do this, we need to look at the second parameter to Mix_PlayMusic, which represents the number of times the music should be looped, so a value of 0 would play the music once, 1 plays it twice etc. A value of -1 will loop it infinitely, which is what we want.

Before loading a new music file, we need to check whether a file is already loaded. This is pretty easy, as when no music is loaded, the music variable will be equal to NULL.

# Handing sound effects

Any game will probably have quite a number of sound effects. Some will be used everywhere, some may be specific to a certain level. As we probably have a lot of sound effects, we don’t want all of those in our memory at the same time, but we also don’t want to load every sound effect everytime we go to a new level. To avoid these problems, we’ll use a sound effects pool, and everytime we go to a different level or screen, we’ll pass the entire list of sound effects we want loaded for that screen to AudioHandler. AudioHandler will then free redundant sound effects, and load the effects that weren’t loaded yet. This minimizes the number of disk reads and the amount of memory used at the same time:

Note that you’ll need to include the algorithm header in order to use std::find.

Playing a sound is almost just as straightforward as playing music, except its function Mix_PlayChannel requires 1 more parameter, which is the channel we want to play the effect on (as the function name suggests). We don’t really have to care about this however, as we can just pass -1 to it, and SDL mixer will find a free channel to play the effect on. The resulting function then is:

# Looping sound effects

Sometimes you want to loop a sound effects, for example when you have a driving car, an elevator or a flamethrower. We can do this using the loop parameter of Mix_PlayChannel, however in order to stop the sound effect from playing we need to know what channel it is playing on. Luckily, Mix_PlayChannel returns the channel the sound is played on, and we can later call Mix_HaltChannel to stop a sound effect playing on a specific channel.

And there you have it, a nice, compact class for handling all sound in a game using SDL. Later on, I’ll probably add support for volume and fading in and out. The entire class can be found on this GitHub gist