Legend of Bob: Playing Sound with FMOD

fmod_logo_border_medresA few month ago I gave up on the idea on using OpenAL for playing sound effect since trying to get MP3s to play with it was getting annoying. A friend recommended whilst in the Student Union to use FMOD, so I switched over and found it did everything I needed, plus there was plenty of documentation and examples.

So here is some basic code for getting audio playing using FMOD, as well as a few additional functions. I’ve only allocated blocks for playing 10 sounds (if more than 10 sounds are attempted to be loaded, LoadSoundByFile() returns -1).

Here is the header for my sound manager.

#ifndef SOUNDMANAGER_H_INCLUDED
#define SOUNDMANAGER_H_INCLUDED
 
// --- [ libraries ] ------------------------------------------
#pragma comment(lib, "fmodex_vc.lib")
 
// --- [ includes ] -------------------------------------------
#include <fmod.hpp>
 
// --- [ definitions ] ----------------------------------------
#define SOUND_LOOP_INFINITE -1
#define MAX_NUM_SOUNDS 10
 
// --- [ class ] ----------------------------------------------
class SoundManager
{
// Attributes
private
	FMOD::System * m_pSystem;
	FMOD::Sound * m_pSound[MAX_NUM_SOUNDS];
 
// Functions
public:
	// Constructor
	SoundManager();
 
	// Destructor
	~SoundManager();
 
	// Load Sound from File
	int LoadSoundFromFile( const char * inFilename );
 
	// Free Sound
	void FreeSound( const int inSoundId );
 
	// Play Sound
	void PlaySound( const int inSoundId );
 
	// Set Position
	void SetSoundPosition( const int inSoundId, const int inPositionInMilliseconds );
 
	// Set Loop Count
	void SetSoundLoopCount( const int inSoundId, const int inCount );
 
	// Set Loop Points
	void SetSoundLoopPoints( const int inSoundId, const int inStartInMilliseconds, const int inEndInMilliseconds );
};
 
#endif

 

For background music, I’ve also included code so that the sound can be looped forever, and since not all sounds will be looping from the beginning, I’ve added a function to set where the loop repeats from and begins again. When a sound is not being used anymore, FreeSound() should be called for the id returned by LoadSoundFromFile().

// --- [ includes ] -------------------------------------------
#include "SoundManager.h"
 
// --- [ constructor / destructor ] ---------------------------
SoundManager::SoundManager()
{
	for( unsigned int i = 0; i < MAX_NUM_EFFECTS; ++i )
	{
	m_pSound[i] = 0;
	}
 
	// Create FMOD SoundSystem
	FMOD::System_Create( &m_pSystem );
 
	// Check FMOD Version
	unsigned int fmodVersion;
	m_pSystem->getVersion( &fmodVersion );
	assert( fmodVersion >= FMOD_VERSION )
 
	// Initialize FMOD SoundSystem
	m_pSystem->init(32, FMOD_INIT_NORMAL, 0);
}
 
SoundManager::~SoundManager()
{
	// Free FMOD Sounds
	for( unsigned int i = 0; i < MAX_NUM_SOUNDS; ++i )
	{
		if( m_pSound[i] )
		{
			m_pSound[i]->release();
		}
	}
 
	// Free FMOD SoundSystem
	if( m_pSystem )
	{
		m_pSystem->close();
		m_pSystem->release();
		m_pSystem = 0;
	}
}
 
// --- [ functions ] ------------------------------------------
int SoundManager::LoadSoundFromFile( const char * inFilename )
{
	for( int i = 0; i < MAX_NUM_SOUNDS; ++i )
	{
		if( !m_pSound[i] )
		{
			m_pSystem->createSound( inFilename, FMOD_SOFTWARE, 0, &m_pSound[i] );
			return i;
		}
	}
 
	return -1;
}
 
void SoundManager::FreeSound( const int inSoundId )
{
	assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
 
	if( m_pSound[inSoundId] )
	{
		m_pSound[inSoundId]->release();
		m_pSound[inSoundId] = 0;
	}
}
 
void SoundManager::PlaySound( const int inSoundId )
{
	assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
 
	if( m_pSound[inSoundId] )
	{
		FMOD::Channel * channel;
		m_pSystem->playSound( FMOD_CHANNEL_FREE, m_pSound[inSoundId], false, &channel );
	}
}
 
void SetSoundPosition( const int inSoundId, const int inPositionInMilliseconds )
{
	assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
 
	if( m_pSound[inSoundId] )
	{
		m_pSound[inSoundId]->setPosition( inPositionInMilliseconds, FMOD_TIMEUNIT_MS );
	}
}
 
void SoundManager::SetSoundLoopCount( const int inSoundId, const int inCount )
{
	assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
 
	if( m_pSound[inSoundId] )
	{
		m_pSound[inSoundId]->setLoopCount( inCount );
	}
}
 
void SoundManager::SetSoundLoopPoints( const int inSoundId, const int inStartInMilliseconds, const int inEndInMilliseconds )
{
	assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
 
	if( m_pSound[inSoundId] )
	{
		m_pSound[inSoundId]->setLoopPoints( inStartInMilliseconds, FMOD_TIMEUNIT_MS, inEndInMilliseconds, FMOD_TIMEUNIT_MS );
	}
}

 

All timing in my code is in milliseconds, but it can be changed to another supported FMOD time unit.