Implementing sound in C and C Plus Plus

From RogueBasin
Revision as of 09:19, 18 March 2009 by Dominikmarczuk (talk | contribs) (added a missing sentence in the introduction)
Jump to navigation Jump to search

Introduction

Sound, in the meaning of one shot sound effects, background ambience and background music, is an essential element of modern games. A good sound can build up the atmosphere far better than a thousand words.

The implementation of sound, however, is considered a difficult task, especially for an inexperienced programmer such as myself. Fortunately, there exists a library that allows to introduce sound to any C or C++ program. It's called FMOD Ex, by Firelight Technologies Pty, Ltd.

The first thing you need to do is to download the library from FMOD site. The library is available free of charge for anyone, provided you use it only for noncommercial productions. The installation file includes an extense programmer's API reference, so you can browse it to learn to use FMOD. After that, you just link your project with the appropriate library and you're ready to go.

There is one thing you should be aware of: if you use the C++ interface of FMOD, it won't compile with MinGW. It is a known problem and it can be avoided by either using the C interface or writing your own C++ code that uses FMOD's C interface internally.

Below you can find example code that should make FMOD reproduce looped background music in any C++ project, copied directly from Umbra Engine.

Code: sound.hpp

#include "fmod.h" //FMOD Ex

/******** CLASS DEFINITION ********/

class Sound {
private:
    static bool on; //is sound on?
    static bool possible; //is it possible to play sound?
    static char * currentSound; //currently played sound
    //FMOD-specific stuff
	static FMOD_RESULT result;
	static FMOD_SYSTEM * fmodsystem;
	static FMOD_SOUND * sound;
	static FMOD_CHANNEL * channel;

public:
	static void initialise (void); //initialises sound

	//sound control
	static void setVolume (float v); //sets the actual playing sound's volume
	static void load (const char * filename); //loads a soundfile
	static void unload (void); //frees the sound object
	static void play (bool pause = false); //plays a sound (may be started paused; no argument for unpaused)

    //getters
    static bool getSound (void); //checks whether the sound is on

    //setters
    static void setPause (bool pause); //pause or unpause the sound
    static void setSound (bool sound); //set the sound on or off

    //toggles
    static void toggleSound (void); //toggles sound on and off
    static void togglePause (void); //toggle pause on/off
};

Code: sound.cpp

#include "sound.hpp"

/******** CLASS VARIABLE DECLARATIONS ********/

bool Sound::on = true; //is sound on?
bool Sound::possible = true; //is it possible to play sound?
char * Sound::currentSound; //currently played sound
//FMOD-specific stuff
FMOD_RESULT Sound::result;
FMOD_SYSTEM * Sound::fmodsystem;
FMOD_SOUND * Sound::sound;
FMOD_CHANNEL * Sound::channel;

/******** METHODS' IMPLEMENTATIONS ********/

//initialises sound
void Sound::initialise (void) {
    //create the sound system. If fails, sound is set to impossible
    result = FMOD_System_Create(&fmodsystem);
    if (result != FMOD_OK) possible = false;
    //if initialise the sound system. If fails, sound is set to impossible
    if (possible) result = FMOD_System_Init(fmodsystem,2, FMOD_INIT_NORMAL, 0);
    if (result != FMOD_OK) possible = false;
    //sets initial sound volume (mute)
    if (possible) FMOD_Channel_SetVolume(channel,0.0f);
}

//sets the actual playing sound's volume
void Sound::setVolume (float v) {
	if (possible && on && v >= 0.0f && v <= 1.0f) {
		FMOD_Channel_SetVolume(channel,v);
	}
}

//loads a soundfile
void Sound::load (const char * filename) {
	currentSound = (char *)filename;
	if (possible && on) {
		result = FMOD_Sound_Release(sound);
		result = FMOD_System_CreateStream(fmodsystem,currentSound, FMOD_SOFTWARE, 0, &sound);
		if (result != FMOD_OK) possible = false;
	}
}

//frees the sound object
void Sound::unload (void) {
	if (possible) {
		result = FMOD_Sound_Release(sound);
	}
}

//plays a sound (no argument to leave pause as dafault)
void Sound::play (bool pause) {
	if (possible && on) {
		result = FMOD_System_PlaySound(fmodsystem,FMOD_CHANNEL_FREE, sound, pause, &channel);
		FMOD_Channel_SetMode(channel,FMOD_LOOP_NORMAL);
	}
}

//toggles sound on and off
void Sound::toggleSound (void) {
    on = !on;
    if (on == true) { load(currentSound); play(); }
    if (on == false) { unload(); }
}

//pause or unpause the sound
void Sound::setPause (bool pause) {
    FMOD_Channel_SetPaused (channel, pause);
}

//turn sound on or off
void Sound::setSound (bool s) {
    on = s;
}

//toggle pause on and off
void Sound::togglePause (void) {
    FMOD_BOOL p;
    FMOD_Channel_GetPaused(channel,&p);
    FMOD_Channel_SetPaused (channel,!p);
}

//tells whether the sound is on or off
bool Sound::getSound (void) {
    return on;
}

Conclusion

With this code, adding a looped background track is as easy as adding these lines to your main.cpp file:

Sound::initialise();
Sound::load("yoursound.mp3");
Sound::play();

There! You have sound playing in the background while the rest of the program continues!

For details about the example implementation, please refer to Umbra Engine documentation. For details about the used FMOD functions, as well as others, please refer to FMOD API documentation.

by Dominik "Mingos" Marczuk