Introduction to C++ with Game Development: Part 20, Sound

00000000000000000000000000000000
0
Anonymous Dec 05, 2011 at 11:44

Introduction

In this tutorial, you will learn how to add sound to your game, using the FMOD Ex sound library. You will also learn about sound quality, and how to use FMOD for special sound effects, such as echo, reverb, low-pass filters and so on.

Digital Sound

Sound is stored on computers as a series of numbers. Each of these numbers represents an amplitude (or signal strength) of the recorded sound at a point in time.

When recording sounds, two things determine the quality:

  • The samplerate. This determines how many samples, or amplitudes, or sample points, were recorded per second. The higher this number, the more the recorded sound will sound like the original. Typical samplerates are 44.1Khz (CD's, modern games) or 22Khz (older games or less important sounds).
  • The bitrate. This determines how many bits are used to store each amplitude. Common bitrates are 8 or 16 bits. 8 bits is old and not much used anymore because it really is too limited and results in bad quality.

Playing Sounds: FMOD

An easy way to play sound in games is by using FMOD. This is a sound playing library that is cross platform, with implementations for most current and older game hardware, and it's easier to use than other, Windows-only libraries. And best of all, it's free for non-commercial use!

First, you need to download the latest version of FMOD. Go to http://www.fmod.org, and find the download link for Fmod Ex. At the time of writing, the latest stable version was 4.28.03. If your version is newer, be aware that minor things (class names, function names) could have changed since then! Once you have downloaded the installer, run it.

FMOD supplies a library that you can use in your project, just like in tutorial 16 ("Research"). The only difference is that FMOD uses a Dynamic Link Library (or DLL). This is just a kind of library that has all the compiled code in a separate file, rather than inside your executable. In order to use it, you setup your project and settings to get the correct .lib file just as you would for a normal library. The difference is that when you try to run your application, it will complain about not finding fmodex.dll. You need to copy this DLL from the correct fmod folder (see below) to the folder where the executables for your game are (the root folder of the project in case of the template).

You should be able to do all of this yourself, using the skills you learned in tutorial 16, but to help you out, here are some quick hints:

  • The include files (.h files) can be found here:
    C:\Program Files\FMOD SoundSystem\FMOD Programmers API Win32\api\inc
  • The library file you need is this one:
    C:\Program Files\FMOD SoundSystem\FMOD Programmers API Win32\api\lib\fmodex_vc.lib
  • Don't forget to copy the fmodex.dll file from
    C:\Program Files\FMOD SoundSystem\FMOD Programmers API Win32\api to the root folder of your project!

Assuming you did all this correctly, we are now ready to start coding.

Initializing FMOD

Before we can play sound, we need to initialize FMOD.

First, make sure you include the correct header files like this:

#include "fmod.h"
#include "fmod_errors.h"

Try compiling this. If it causes a compilation error, you have not correctly setup your include paths. Go back 3 squares and skip a turn! And fix your paths!

Now, we can initialize FMOD. Add the following code to the template:

FMOD::System* fmodSystem;	// the global variable for talking to FMOD

void FmodErrorCheck(FMOD_RESULT result)	// this is an error handling function
{						// for FMOD errors
	if (result != FMOD_OK)
	{
		printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
		exit(-1);
	}
}

void Game::Init()
{
	FMOD_RESULT result;
	result = FMOD::System_Create(&fmodSystem);
	FmodErrorCheck(result);

	result = fmodSystem->init(32, FMOD_INIT_NORMAL, 0);
	FmodErrorCheck(result);
}

In the Game::Init method, this creates the FMOD sound system and initializes it. The parameters of the fmodSystem->init call tell it never to mix more than 32 sounds at the same time, and that you don't require any special setup. FMOD will use all the default values which is good enough for now.

Make sure FMOD gets updated every tick by adding the following line to the Game::Tick method:

    fmodSystem->update();

Playing background music

Let's play some music for our game. Copy your favourite MP3 file to the assets folder in the project, and add the following variables:

FMOD::Sound *music;
FMOD::Channel* musicChannel;

Then, at the end of the Game::Init function, add this code to load and start the sound:

result = fmodSystem->createStream("assets/YOUR SONG.mp3", 
				  FMOD_SOFTWARE | FMOD_LOOP_NORMAL, 0, &music);
FmodErrorCheck(result);

result = fmodSystem->playSound(FMOD_CHANNEL_FREE, music, false, &musicChannel);
FmodErrorCheck(result);

The first line takes care of creating the streaming sound, and preparing it for playback, telling FMOD to mix it using the software mixer (FMOD can use hardware mixing, but for the best cross platform compatibility and widest range of supported effects, use software mixing), and with the added flag that tells it to loop this sound when it is played. Creating it as a stream will tell FMOD not to load it all at once, but instead load it in little chunks as needed, and to decode it on the fly. This uses a lot less memory than if you were to load and decode the file once and keep it memory for playback, but it costs a bit more CPU and hard disk time.

The second line starts playing the sound. Once FMOD plays a sound, it creates a 'Channel' for it. If you want to change how it's playing, you can do this through the Channel's method. By using this design, it is possible to load a sound once, yet play it multiple times, by having just one Sound variable and multiple Channel variables.

You can change the playing sound's volume by using the following code, anytime after having started it:

    musicChannel->setVolume( 0.1f );

Where you can pass in a volume between 0 and 1.

Action Sound

Now go on the internet and find a good action sound, like a sword hit or a gun or something, because we are going to play a sound based on a keypress.

Once you have the sound you want, save it in the assets folder again. Add a Sound type variable called actionSound for it right after declaring the one for the music. Don't worry about the channel for now.

Add the following code to load it in the Game::Init function:

result = fmodSystem->createSound("assets/YOUR_SOUND_FILENAME", FMOD_SOFTWARE, 0, 
						&actionSound);
FmodErrorCheck(result);

This is very similar to the createStream call we did for the music, but it loads the sound into memory in one go. This is better for all your normal event/action sounds, because it takes less CPU time to play later, and does not need the hard disk during play.

Then, in the Game::KeyDown method, add the following code to play it:

if( code == SDL_SCANCODE_SPACE )
{
  FMOD_RESULT result;
  result = fmodSystem->playSound(FMOD_CHANNEL_FREE, actionSound, false,NULL );
  FmodErrorCheck(result);
}

It's just like playing the music, except that we didn't pass in a Channel variable at the end. Instead, we just said NULL. This tells FMOD we are not interested in which channel it uses to play this sound, so it will handle all of that by itself. It also means we can't change modify how this sound is playing anymore (volume, effects, stop etc.).

Effects

Last but not least, we're going to learn how we can apply special effects to sounds.

Special effects could be things like Echo, Reverb (lots of echoes at the same time), Low pass (remove all the frequencies above a certain value; this makes the sound sound muffled) and more. FMOD supports quite a lot of effects out of the box, and they are easy to apply.

Let's try putting an echo effect on our background music. We start by adding a variable to hold our DSP effect. (DSP = Digital Signal Processing, the common name given to any algorithm that works on a digital signal). Add the following line after your other variables:

    FMOD::DSP* dspecho;

Then, in the Game::Init function, we have to ask FMOD to give us the desired effect, so we can use it on a sound later on:

result = fmodSystem->createDSPByType(FMOD_DSP_TYPE_ECHO, &dspecho);
FmodErrorCheck(result);

And finally, after telling FMOD to play the sound in the Init function, add the following lines:

result = musicChannel->addDSP( dspecho, 0 );
FmodErrorCheck(result);
result = dspecho->setParameter(FMOD_DSP_ECHO_DELAY, 150.0f);
FmodErrorCheck(result);

The first line is for adding the effect to the channel. The second line is error checking.

The third line is for changing one of the default parameters of the Echo effect. We are changing how fast the echoes die down, by changing the time between each echo. The default is 500 (half a second), but that's pretty long. I changed it to 150 for this example.

You can create different effects in exactly the same way, and add more than one by calling addDSP multiple times, with different effects. For a list of other supported effects, find and open the fmod_dsp.h file and look for FMOD_DSP_TYPE.

Assignment

Take one of the games you made during fasttrack so far, and add proper sound to it:

  1. Play background music, at a nice volume so it doesn't drown out the game sounds
  2. Make sure all events have a corresponding sound
  3. Find a heartbeat sound, and play it looping. Dynamically change the volume based on how low the energy or life bar is, so it's silent at first, but the player can start to hear it when things are getting bad. If you don't have a life or energy bar, be creative and think of something else to which you can couple this sound.
  4. Add a highpass filter (a filter that removes frequencies below a certain threshold, makes the sound 'thinner' sounding) to the hearbeat sound and change its cutoff frequency so that, as it gets louder and more intense, it adds more and more bass (low frequencies) to the sound. You will have to figure out which parameter you need to set using the DSP::setParameter function to change the cutoff frequency for the highpass effect.

0 Replies

Please log in or register to post a reply.

No replies have been made yet.