Another FMOD SoundManager        

This manager attempts to effectively use FMODs channel groups and sound groups. The idea behind it is to hide FMOD specific implementation from the user.

It does not use OGREs' resource loader. Sound loading is handled via input files (sample input files are after code). Each input file specifies a soundgroup to contain the sounds. Unloading the sounds is handled by the same input file. Playlists are implemented but not thoroughly tested. There are few comments, but most of the code is easily distinguishable via the method name.

Playing a sound creates a channel (may specify channel group). Sounds may be modified via the individual sound, the channel, the soundgroup or the channelgroup.

Only a single listener is supported for 3D sound.



The interface

#pragma once

class ISoundManager{
public:
	virtual void Load2DSoundsFromFile(const Ogre::String &fileName)=0;
	virtual void Load3DSoundsFromFile(const Ogre::String &fileName)=0;
	virtual void UnloadSoundsFromFile(const Ogre::String &fileName)=0;
	virtual void Load2DPlaylistFromFile(const Ogre::String &fileName)=0;
	
	virtual void System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity)=0;
	virtual void System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, 
            const Ogre::Vector3 &forward)=0;
	virtual void System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, 
            const Ogre::Vector3 &forward, const Ogre::Vector3 &up)=0;
	virtual void System3DSettings(const Ogre::Real &dopplerScale, const Ogre::Real &distanceFactor, 
            const Ogre::Real rolloffScale)=0;

	virtual void SoundGroupMaxAudible(const Ogre::String &name, const int  &maxAudible)=0;
	virtual void SoundGroupMuteFadeSpeed(const Ogre::String &name, const Ogre::Real &speed)=0;
	virtual void SoundGroupStop(const Ogre::String &name)=0;
	virtual void SoundGroupStopAll()=0;
	virtual void SoundGroupEmpty(const Ogre::String &name)=0;
	virtual void SoundGroupEmptyAll()=0;
	virtual void SoundGroupDestroy(const Ogre::String &name)=0;
	virtual void SoundGroupDestroyAll()=0;
	virtual void SoundGroupVolume(const Ogre::String &name, const Ogre::Real &volume)=0;
	virtual Ogre::Real GetSoundGroupVolume(const Ogre::String &name)=0;

	virtual void Sound2DLoopCount(const Ogre::String &name, const int &loopCount)=0;
	virtual void Sound3DLoopCount(const Ogre::String &name, const int &loopCount)=0;
	virtual void Sound3DConeSettings(const Ogre::String &name, const Ogre::Real &insideAngle, 
            const Ogre::Real &outsideAngle, const Ogre::Real &outsideVolume)=0;
	virtual void Sound3DMinMaxDistance(const Ogre::String &name, const Ogre::Real &minDistance, 
            const Ogre::Real &maxDistance)=0;

	virtual void ChannelGroupCreate(const Ogre::String &name)=0;
	virtual void ChannelGroupPause(const Ogre::String &name, const bool &isPaused)=0;
	virtual void ChannelGroupPauseAll(const bool &isPaused)=0;
	virtual void ChannelGroupMute(const Ogre::String &name, const bool &isMuted)=0;
	virtual void ChannelGroupMuteAll(const bool &isMuted)=0;
	virtual void ChannelGroupVolume(const Ogre::String &name, const Ogre::Real &volume)=0;
	virtual void ChannelGroupVolumeAll(const Ogre::Real &volume)=0;
	virtual void ChannelGroupStop(const Ogre::String &name)=0;
	virtual void ChannelGroupStopAll()=0;
	virtual void ChannelGroupDestroy(const Ogre::String &name)=0;
	virtual void ChannelGroupDestroyAll()=0;

	virtual void ChannelPause(const int &index, const bool &isPaused)=0;
	virtual void ChannelMute(const int &index, const bool &isMuted)=0;
	virtual void ChannelVolume(const int &index, const Ogre::Real &volume)=0;
	virtual void ChannelLoop(const int &index, const int &loopCount)=0;
	virtual void ChannelStop(const int &index)=0;

	virtual void Channel3DAttributes(const int &index, const Ogre::Vector3 &position, 
            const Ogre::Vector3 &velocity)=0;
	virtual void Channel3DConeOrientation(const int &index, const Ogre::Vector3 &orientation)=0;
	virtual void Channel3DConeSettings(const int &index, const Ogre::Real &insideAngle, 
            const Ogre::Real &outsideAngle, const Ogre::Real &outsideVolume)=0;
	virtual void Channel3DDopplerLevel(const int &index, const Ogre::Real &level)=0;
	virtual void Channel3DMinMaxDistance(const int &index, const Ogre::Real &minDistance, 
            const Ogre::Real &maxDistance)=0;
	
	virtual void PlaylistPlay(const Ogre::String &playlistName)=0;
	virtual void PlaylistPlayAll()=0;
	virtual void PlaylistSkip(const Ogre::String &playlistName)=0;
	virtual void PlaylistPause(const Ogre::String &playlistName)=0;
	virtual void PlaylistPauseAll()=0;
	virtual void PlaylistResume(const Ogre::String &playlistName)=0;
	virtual void PlaylistResumeAll()=0;
	virtual void PlaylistStop(const Ogre::String &playlistName)=0;
	virtual void PlatlistStopAll()=0;
	virtual void PlaylistDestroy(const Ogre::String &playlistName)=0;
	virtual void PlaylistDestroyAll()=0;

	virtual int Play2DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName)=0;
	virtual int Play2DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const int &loopCount)=0;

	virtual int Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const Ogre::Vector3 &position)=0;
	virtual int Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const Ogre::Vector3 &position, const int &loopCount)=0;
	virtual int Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, const Ogre::Vector3 &forward)=0;
	virtual int Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, const Ogre::Vector3 &forward, 
            const int &loopCount)=0;
};



The header

#pragma once

#include "ISoundManager.h"
#include <fmod.hpp>
#include "FMOD\fmod_errors.h"
#include <hash_map>
#include <fstream>

#define SOUND_LOG_NAME				"SoundManager.log"
#define SOUND_LOG(x)				Ogre::LogManager::getSingleton().getLog(SOUND_LOG_NAME)->logMessage(x)

#define MAX_CHAR_ARRAY_SIZE			255
#define MAX_SOUND_CHANNELS			200
#define SONG_PRIORITY				0
#define SOUND_PRIORITY_2D			1
#define SOUND_PATH				"..\\..\\res\\Audio\\"

class SoundInstance{
public:
	SoundInstance(Ogre::String soundName, FMOD::Sound* sound):
		_soundName(soundName), _sound(sound)
	{}

	~SoundInstance(){
		_sound->release();
	}

	Ogre::String _soundName;
	FMOD::Sound* _sound;
};

class SoundManager : public ISoundManager{
public:
	void Load2DSoundsFromFile(const Ogre::String &fileName);
	void Load3DSoundsFromFile(const Ogre::String &fileName);
	void UnloadSoundsFromFile(const Ogre::String &fileName);
	void Load2DPlaylistFromFile(const Ogre::String &fileName);

	void System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity);
	void System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, 
            const Ogre::Vector3 &forward);
	void System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, 
            const Ogre::Vector3 &forward, const Ogre::Vector3 &up);
	void System3DSettings(const Ogre::Real &dopplerScale, const Ogre::Real &distanceFactor, 
            const Ogre::Real rolloffScale);

	void SoundGroupCreate(const Ogre::String &name);
	void SoundGroupMaxAudible(const Ogre::String &name, const int  &maxAudible);
	void SoundGroupMuteFadeSpeed(const Ogre::String &name, const Ogre::Real &speed);
	void SoundGroupStop(const Ogre::String &name);
	void SoundGroupStopAll();
	void SoundGroupEmpty(const Ogre::String &name);
	void SoundGroupEmptyAll();
	void SoundGroupDestroy(const Ogre::String &name);
	void SoundGroupDestroyAll();
	void SoundGroupVolume(const Ogre::String &name, const Ogre::Real &volume);
	Ogre::Real GetSoundGroupVolume(const Ogre::String &name);
	
	void Sound2DLoopCount(const Ogre::String &name, const int &loopCount);
	void Sound3DLoopCount(const Ogre::String &name, const int &loopCount);
	void Sound3DConeSettings(const Ogre::String &name, const Ogre::Real &insideAngle, 
            const Ogre::Real &outsideAngle, const Ogre::Real &outsideVolume);
	void Sound3DMinMaxDistance(const Ogre::String &name, const Ogre::Real &minDistance, 
            const Ogre::Real &maxDistance);
	
	void ChannelGroupCreate(const Ogre::String &name);
	void ChannelGroupPause(const Ogre::String &name, const bool &isPaused);
	void ChannelGroupPauseAll(const bool &isPaused);
	void ChannelGroupMute(const Ogre::String &name, const bool &isMuted);
	void ChannelGroupMuteAll(const bool &isMuted);
	void ChannelGroupVolume(const Ogre::String &name, const Ogre::Real &volume);
	void ChannelGroupVolumeAll(const Ogre::Real &volume);
	void ChannelGroupStop(const Ogre::String &name);
	void ChannelGroupStopAll();
	void ChannelGroupDestroy(const Ogre::String &name);
	void ChannelGroupDestroyAll();

	void ChannelPause(const int &index, const bool &isPaused);
	void ChannelMute(const int &index, const bool &isMuted);
	void ChannelVolume(const int &index, const Ogre::Real &volume);
	void ChannelLoop(const int &index, const int &loopCount);
	void ChannelStop(const int &index);

	void Channel3DAttributes(const int &index, const Ogre::Vector3 &position, 
            const Ogre::Vector3 &velocity);
	void Channel3DConeOrientation(const int &index, const Ogre::Vector3 &orientation);
	void Channel3DConeSettings(const int &index, const Ogre::Real &insideAngle, const Ogre::Real &outsideAngle, 
            const Ogre::Real &outsideVolume);
	void Channel3DDopplerLevel(const int &index, const Ogre::Real &level);
	void Channel3DMinMaxDistance(const int &index, const Ogre::Real &minDistance, const Ogre::Real &maxDistance);

	void PlaylistPlay(const Ogre::String &playlistName);
	void PlaylistPlayAll();
	void PlaylistSkip(const Ogre::String &playlistName);
	void PlaylistPause(const Ogre::String &playlistName);
	void PlaylistPauseAll();
	void PlaylistResume(const Ogre::String &playlistName);
	void PlaylistResumeAll();
	void PlaylistStop(const Ogre::String &playlistName);
	void PlatlistStopAll();
	void PlaylistDestroy(const Ogre::String &playlistName);
	void PlaylistDestroyAll();

	int Play2DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName="MASTER");
	int Play2DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName="MASTER", 
            const int &loopCount=0);

	int Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const Ogre::Vector3 &position);
	int Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const Ogre::Vector3 &position, const int &loopCount);
	int Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, const Ogre::Vector3 &forward);
	int Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
            const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, const Ogre::Vector3 &forward, 
            const int &loopCount);
        
        static SoundManager* getSingleton(){
		if(!_soundManager)
			_soundManager = new SoundManager();
		return _soundManager;
	}

	
private:
        static SoundManager* _soundManager;
	static int SOUND_2D;          //memory addresses of these these values are used to distinguish 
	static int SOUND_3D;          //between 2d and 3d sounds. passed around as void pointers in fmod
	
	SoundManager();
	virtual ~SoundManager();

	void Initialize();
	void UpdateStarted(const Ogre::FrameEvent &gameTime);
	void UpdateEnded(const Ogre::FrameEvent &gameTime);
	void Cleanup();

	void UnloadSound(const Ogre::String &name, const void *type);

	static void OpenFile(const Ogre::String fileName, std::ifstream &infile);
	static const FMOD_VECTOR OgreToFmodVec(const Ogre::Vector3 &vector);
	static const Ogre::Vector3 FmodToOgreVec(const FMOD_VECTOR &vector);

	FMOD::System* _system;
	Ogre::Real _timeSinceLastFrame;
	FMOD_VECTOR _listenerPosition;
	FMOD_VECTOR _velocityVector;
	FMOD_VECTOR _forwardVector;
	FMOD_VECTOR _upVector;
	stdext::hash_map<const Ogre::String, SoundInstance*>* _2DsoundMap;
	stdext::hash_map<const Ogre::String, SoundInstance*>* _3DsoundMap;
	stdext::hash_map<const Ogre::String, FMOD::SoundGroup*>* _soundGroupMap;
	stdext::hash_map<const Ogre::String, FMOD::SoundGroup*>::iterator _SGMitr;
	stdext::hash_map<const Ogre::String, FMOD::ChannelGroup*>* _channelGroupMap;
	stdext::hash_map<const Ogre::String, FMOD::ChannelGroup*>::iterator _CGMitr;

	class Sound2DPlaylist;
	stdext::hash_map<const Ogre::String, Sound2DPlaylist*>* _playlistMap;
	stdext::hash_map<const Ogre::String, Sound2DPlaylist*>::iterator _playlistItr;

	class Sound2DPlaylist{
	public:
		Sound2DPlaylist(const Ogre::String &name) : _name(name)		{}
		~Sound2DPlaylist()						{ _soundQueue.clear();}

		void Update(FMOD::System *system){
			FMOD::Channel *channel;
			if(system->getChannel(_channel, &channel) == FMOD_OK)
				return;
			Skip();
		}

		void AddSound(const Ogre::String soundName)	{ _soundQueue.push_back(soundName); }
		void Play(){ Stop(); _channel = SoundManager::getSingleton()->Play2DSound(_soundQueue.front(), _name);}
		void Pause() { SoundManager::getSingleton()->ChannelPause(_channel, true); }
		void Resume(){ SoundManager::getSingleton()->ChannelPause(_channel, false); }
		void Stop(){ SoundManager::getSingleton()->ChannelStop(_channel); _channel = -1; }
		void Skip(){ _soundQueue.push_back(_soundQueue.front()); _soundQueue.pop_front(); Stop(); Play(); }

		Ogre::String _name;
		FMOD::ChannelGroup* _channelGroup;
		std::deque<const Ogre::String> _soundQueue;
		std::deque<const Ogre::String>::iterator _itr;
		int _channel;
	};
};



The implementation

#include "SoundManager.h"

//static variable instances
int SoundManager::SOUND_2D;
int SoundManager::SOUND_3D;
SoundManager* SoundManager::_soundManager;

SoundManager::SoundManager() :
	_system(nullptr),
	_2DsoundMap(new stdext::hash_map<const Ogre::String, SoundInstance*>()),
	_3DsoundMap(new stdext::hash_map<const Ogre::String, SoundInstance*>()),
	_soundGroupMap(new stdext::hash_map<const Ogre::String, FMOD::SoundGroup*>()),
	_channelGroupMap(new stdext::hash_map<const Ogre::String, FMOD::ChannelGroup*>()),
	_playlistMap(new stdext::hash_map<const Ogre::String, Sound2DPlaylist*>())
{ 
	Ogre::LogManager::getSingleton().createLog(SOUND_LOG_NAME);
	SOUND_LOG("SoundManager created");
}

SoundManager::~SoundManager(){
	_system = nullptr;

	delete _2DsoundMap; _2DsoundMap = nullptr;
	delete _3DsoundMap; _3DsoundMap = nullptr;
	delete _soundGroupMap; _soundGroupMap = nullptr;
	delete _channelGroupMap; _channelGroupMap = nullptr;

	SOUND_LOG("SoundManager destroyed");
}

void SoundManager::Initialize(){
	FMOD::System_Create(&_system);
	_system->init(MAX_SOUND_CHANNELS, FMOD_INIT_NORMAL,0);

	FMOD::SoundGroup* soundGroup;
	_system->getMasterSoundGroup(&soundGroup);
	_soundGroupMap->insert(std::pair<const Ogre::String, FMOD::SoundGroup*>("MASTER", soundGroup));

	FMOD::ChannelGroup* channelGroup;
	_system->getMasterChannelGroup(&channelGroup);
	_channelGroupMap->insert(std::pair<const Ogre::String, FMOD::ChannelGroup*>("MASTER", channelGroup));

	_system->set3DNumListeners(1);

	SOUND_LOG("SoundManager initialized");
}

void SoundManager::UpdateStarted(const Ogre::FrameEvent &gameTime){
	_timeSinceLastFrame = gameTime.timeSinceLastFrame;
	_system->update();
}

void SoundManager::UpdateEnded(const Ogre::FrameEvent &gameTime){
}

void SoundManager::Cleanup(){
	this->PlaylistDestroyAll();
	this->ChannelGroupDestroyAll();
	this->SoundGroupDestroyAll();
	this->PlaylistDestroyAll();
	
	_system->close();
	_system->release();
}

void SoundManager::UnloadSound(const Ogre::String &name, const void *type){
	SoundInstance* tempSound;
	if(int(type) == int(&SoundManager::SOUND_2D)){
		if(!_2DsoundMap->count(name))
			return;
		tempSound = _2DsoundMap->at(name);
		_2DsoundMap->erase(name);
	}else if(int(type) == int(&SoundManager::SOUND_3D)){
		if(!_3DsoundMap->count(name))
			return;

		tempSound = _3DsoundMap->at(name);
		_3DsoundMap->erase(name);
	}
	delete tempSound;
}

#pragma region static functions

/**open the file specified starting from the BASE_PATH directory\n
opens the file using the ifstream passed in
*/
void SoundManager::OpenFile(const Ogre::String fileName, std::ifstream &infile){
	Ogre::String listPath;
	listPath.append(SOUND_PATH + fileName);
	infile.open(listPath);
	if(infile.fail()){
		SOUND_LOG("SoundManager::OpenFile() - cannot open file: " + listPath);
		return;
	}
}

/** returns an FMOD_VECTOR equivalent to the Ogre::Vector3 passed in
*/
const FMOD_VECTOR SoundManager::OgreToFmodVec(const Ogre::Vector3 &vector){
	FMOD_VECTOR tempVec;
	tempVec.x = vector.x;
	tempVec.y = vector.y;
	tempVec.z = vector.z;
	return tempVec;
}

/** returns an Ogre::Vector3 equivalent to the FMOD_VECTOR passed in
*/
const Ogre::Vector3 SoundManager::FmodToOgreVec(const FMOD_VECTOR &vector){
	return Ogre::Vector3(vector.x, vector.y, vector.z);
}

#pragma endregion 

#pragma region loading/unloading sound

void SoundManager::Load2DSoundsFromFile(const Ogre::String &fileName){
	std::ifstream infile;
	SoundManager::OpenFile(fileName, infile);
	if(infile.fail()){
		infile.close();
		return;
	}
	
	FMOD::Sound* soundResult;				//dont delete this pointer, it just holds results
	
	const Ogre::String soundPathString(SOUND_PATH);
	Ogre::String soundFileString;
	Ogre::String soundNameString;
	Ogre::String soundGroupName;
	Ogre::String soundPriorityString;
	char* tempChar = new char[MAX_CHAR_ARRAY_SIZE];
	
	infile>>tempChar;
	soundGroupName.append(tempChar);
	if(!_soundGroupMap->count(soundGroupName)){	//make the soundgroup if it doesn't exist
		this->SoundGroupCreate(soundGroupName);
		_soundGroupMap->at(soundGroupName)->setUserData(&SoundManager::SOUND_2D);
	}

	while(!infile.eof()){
		soundNameString.clear();
		soundFileString.clear();
		infile>>tempChar;
		soundFileString.append(soundPathString + tempChar);
		infile>>tempChar;
		soundPriorityString.append(tempChar);
		infile.getline(tempChar, MAX_CHAR_ARRAY_SIZE);
		soundNameString.append(tempChar);
		Ogre::StringUtil::trim(soundNameString);
		if(_2DsoundMap->count(soundNameString))
			continue;	//sound already loaded

		if(_system->createSound(soundFileString.c_str(), FMOD_2D | FMOD_HARDWARE, nullptr, &soundResult)
                   != FMOD_OK)
			continue;
		
		int priority;
		Ogre::Real frequency, volume, pan;
		soundResult->getDefaults(&frequency, &volume, &pan, &priority);
		soundResult->setDefaults(frequency, volume, pan, Ogre::StringConverter::parseInt(soundPriorityString));

		soundResult->setSoundGroup(_soundGroupMap->at(soundGroupName));
		_2DsoundMap->insert(std::pair<const Ogre::String, SoundInstance*>(
                    soundNameString, new SoundInstance(soundNameString, soundResult)));
		soundResult->setUserData(&(_2DsoundMap->at(soundNameString)->_soundName));
	}
	infile.close();	
	delete tempChar;
}

void SoundManager::Load3DSoundsFromFile(const Ogre::String &fileName){
	std::ifstream infile;
	SoundManager::OpenFile(fileName, infile);
	if(infile.fail()){
		infile.close();
		return;
	}
	
	FMOD::Sound* soundResult;				//dont delete this pointer, it just holds results
	
	const Ogre::String soundPathString(SOUND_PATH);
	Ogre::String soundFileString;
	Ogre::String soundNameString;
	Ogre::String soundGroupName;
	Ogre::String soundPriorityString;
	char* tempChar = new char[MAX_CHAR_ARRAY_SIZE];
	
	infile>>tempChar;
	soundGroupName.append(tempChar);
	if(!_soundGroupMap->count(soundGroupName)){	//make the soundgroup if it doesn't exist
		this->SoundGroupCreate(soundGroupName);
		_soundGroupMap->at(soundGroupName)->setUserData(&SoundManager::SOUND_3D);
	}

	while(!infile.eof()){
		soundNameString.clear();
		soundFileString.clear();
		infile>>tempChar;
		soundFileString.append(soundPathString + tempChar);
		infile>>tempChar;
		soundPriorityString.append(tempChar);
		infile.getline(tempChar, MAX_CHAR_ARRAY_SIZE);
		soundNameString.append(tempChar);
		Ogre::StringUtil::trim(soundNameString);
		if(_3DsoundMap->count(soundNameString))
			continue;	//sound already loaded

		if(_system->createSound(soundFileString.c_str(), FMOD_3D | FMOD_HARDWARE, nullptr, &soundResult) 
                   != FMOD_OK)
			continue;

		int priority;
		Ogre::Real frequency, volume, pan;
		soundResult->getDefaults(&frequency, &volume, &pan, &priority);
		soundResult->setDefaults(frequency, volume, pan, Ogre::StringConverter::parseInt(soundPriorityString));

		soundResult->setSoundGroup(_soundGroupMap->at(soundGroupName));
		_3DsoundMap->insert(std::pair<const Ogre::String, SoundInstance*>(
                    soundNameString, new SoundInstance(soundNameString, soundResult)));
		soundResult->setUserData(&(_3DsoundMap->at(soundNameString)->_soundName));
	}
	infile.close();	
	delete tempChar;
}

void SoundManager::UnloadSoundsFromFile(const Ogre::String &fileName){
	std::ifstream infile;
	SoundManager::OpenFile(fileName, infile);
	if(infile.bad()){
		infile.close();
		return;
	}
	Ogre::String soundGroupName;
	char* tempChar = new char[MAX_CHAR_ARRAY_SIZE];
	infile>>tempChar;
	soundGroupName.append(tempChar);
	this->SoundGroupDestroy(soundGroupName);
	infile.close();
	delete tempChar;
}

void SoundManager::Load2DPlaylistFromFile(const Ogre::String &fileName){
	this->Load2DSoundsFromFile(fileName);

	std::ifstream infile;
	SoundManager::OpenFile(fileName, infile);
	if(infile.bad()){
		infile.close();
		return;
	}
	Ogre::String playlistNameString, nameString;
	char* tempChar = new char[MAX_CHAR_ARRAY_SIZE];
	infile>>tempChar>>tempChar;
	infile.getline(tempChar, MAX_CHAR_ARRAY_SIZE);
	playlistNameString.append(tempChar);
	Sound2DPlaylist* playlist = new Sound2DPlaylist(playlistNameString);

	while(!infile.eof()){
		nameString.clear();
		infile.getline(tempChar, MAX_CHAR_ARRAY_SIZE);
		nameString.append(tempChar);
		if(!_2DsoundMap->count(nameString))
			continue;

		playlist->AddSound(nameString);
	}

	_playlistMap->insert(std::pair<const Ogre::String, Sound2DPlaylist*>(playlistNameString, playlist));
	
	infile.close();
	delete tempChar;
}

#pragma endregion

#pragma region system

void SoundManager::System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity){
	const FMOD_VECTOR posVec = {position.x, position.y, position.z},
		velVec = {velocity.x * _timeSinceLastFrame, 
                          velocity.y * _timeSinceLastFrame, 
                          velocity.z * _timeSinceLastFrame};

	_listenerPosition = posVec;
	_velocityVector = velVec;
	_system->set3DListenerAttributes(0, &posVec, &velVec, &_forwardVector, &_upVector);
}

void SoundManager::System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, 
    const Ogre::Vector3 &forward){
	const FMOD_VECTOR posVec = {position.x, position.y, position.z},
		velVec = {velocity.x * _timeSinceLastFrame,
                          velocity.y * _timeSinceLastFrame, 
                          velocity.z * _timeSinceLastFrame},
		forVec = {forward.normalisedCopy().x, forward.normalisedCopy().y, forward.normalisedCopy().z};

	_listenerPosition = posVec;
	_velocityVector = velVec;
	_forwardVector = forVec;
	_system->set3DListenerAttributes(0, &posVec, &velVec, &forVec, &_upVector);
}

void SoundManager::System3DAttributes(const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, 
    const Ogre::Vector3 &forward, const Ogre::Vector3 &up){
	const FMOD_VECTOR posVec = {position.x, position.y, position.z},
		velVec = {velocity.x * _timeSinceLastFrame,
                          velocity.y * _timeSinceLastFrame,
                          velocity.z * _timeSinceLastFrame},
		forVec = {forward.normalisedCopy().x, forward.normalisedCopy().y, forward.normalisedCopy().z},
		upVec = {up.normalisedCopy().x, up.normalisedCopy().y, up.normalisedCopy().z};
	
	_listenerPosition = posVec;
	_velocityVector = velVec;
	_forwardVector = forVec;
	_upVector = upVec;

	_system->set3DListenerAttributes(0, &posVec, &velVec, &forVec, &upVec);
}

void SoundManager::System3DSettings(const Ogre::Real &dopplerScale, const Ogre::Real &distanceFactor, 
    const Ogre::Real rolloffScale){
	_system->set3DSettings(dopplerScale, distanceFactor, rolloffScale);
}

#pragma endregion

#pragma region sound group

void SoundManager::SoundGroupCreate(const Ogre::String &name){
	if(_soundGroupMap->count(name))
		return;

	FMOD::SoundGroup* soundGroup;
	if(_system->createSoundGroup(name.c_str(), &soundGroup) != FMOD_OK)
		return;
	_soundGroupMap->insert(std::pair<const Ogre::String, FMOD::SoundGroup*>(name.c_str(), soundGroup));
}

void SoundManager::SoundGroupMuteFadeSpeed(const Ogre::String &name, const Ogre::Real &speed){
	if(_soundGroupMap->count(name))
		return;

	_soundGroupMap->at(name)->setMuteFadeSpeed(speed);
}

void SoundManager::SoundGroupMaxAudible(const Ogre::String &name, const int &maxAudible){
	if(!_soundGroupMap->count(name))
		return;

	_soundGroupMap->at(name)->setMaxAudible(maxAudible);
	_soundGroupMap->at(name)->setMaxAudibleBehavior(FMOD_SOUNDGROUP_BEHAVIOR_MUTE);
}


void SoundManager::SoundGroupStop(const Ogre::String &name){
	if(!_soundGroupMap->count(name))
		return;

	_soundGroupMap->at(name)->stop();
}

void SoundManager::SoundGroupStopAll(){
	for(_SGMitr = _soundGroupMap->begin(); _SGMitr != _soundGroupMap->end(); ++_SGMitr)
		_SGMitr->second->stop();
}

void SoundManager::SoundGroupEmpty(const Ogre::String &name){
	if(!_soundGroupMap->count(name))
		return;

	this->SoundGroupStop(name);

	FMOD::Sound* sound;
	FMOD::SoundGroup* soundGroup = _soundGroupMap->at(name);
	Ogre::String* soundName;
	void* userData;
	int soundCount;
	soundGroup->getNumSounds(&soundCount);
	while(soundCount-- > 0){
		soundGroup->getSound(0, &sound);
		sound->getUserData(&userData);
		soundName = (Ogre::String*)userData;
		soundGroup->getUserData(&userData);
		this->UnloadSound(*soundName, userData);
	}
}

void SoundManager::SoundGroupEmptyAll(){
	for(_SGMitr = _soundGroupMap->begin(); _SGMitr != _soundGroupMap->end(); ++_SGMitr)
		this->SoundGroupEmpty(_SGMitr->first);
}

void SoundManager::SoundGroupDestroy(const Ogre::String &name){
	if(!_soundGroupMap->count(name) || !name.compare("MASTER"))
		return;

	this->SoundGroupEmpty(name);
	_soundGroupMap->at(name)->release();
	_soundGroupMap->erase(name);
}

void SoundManager::SoundGroupDestroyAll(){
	this->SoundGroupEmptyAll();
	for(_SGMitr = _soundGroupMap->begin(); _SGMitr != _soundGroupMap->end(); ++_SGMitr){
		if(!_SGMitr->first.compare("MASTER"))
			continue;
		_SGMitr->second->release();
	}
	_soundGroupMap->clear();
	FMOD::SoundGroup* soundGroup;
	_system->getMasterSoundGroup(&soundGroup);
	_soundGroupMap->insert(std::pair<const Ogre::String, FMOD::SoundGroup*>("MASTER", soundGroup));

}

void SoundManager::SoundGroupVolume(const Ogre::String &name, const Ogre::Real &volume){
	if(!_soundGroupMap->count(name))
		return;

	_soundGroupMap->at(name)->setVolume(volume);
}

Ogre::Real SoundManager::GetSoundGroupVolume(const Ogre::String &name){
	if(!_soundGroupMap->count(name))
		return -1.0f;

	Ogre::Real volume;
	_soundGroupMap->at(name)->getVolume(&volume);
	return volume;
}

#pragma endregion

#pragma region sound

void SoundManager::Sound2DLoopCount(const Ogre::String &name, const int &loopCount){
	if(!_2DsoundMap->count(name))
		return;

	_2DsoundMap->at(name)->_sound->setLoopCount(loopCount);
}

void SoundManager::Sound3DLoopCount(const Ogre::String &name, const int &loopCount){
	if(!_3DsoundMap->count(name))
		return;

	_3DsoundMap->at(name)->_sound->setLoopCount(loopCount);
}

void SoundManager::Sound3DConeSettings(const Ogre::String &name, const Ogre::Real &insideAngle, 
    const Ogre::Real &outsideAngle, const Ogre::Real &outsideVolume){
	if(!_3DsoundMap->count(name))
		return;

	_3DsoundMap->at(name)->_sound->set3DConeSettings(insideAngle, outsideAngle, outsideVolume);
}

void SoundManager::Sound3DMinMaxDistance(const Ogre::String &name, const Ogre::Real &minDistance, 
    const Ogre::Real &maxDistance){
	if(!_3DsoundMap->count(name))
		return;

	_3DsoundMap->at(name)->_sound->set3DMinMaxDistance(minDistance, maxDistance);
}

#pragma endregion

#pragma region channel group
	
void SoundManager::ChannelGroupCreate(const Ogre::String &name){
	if(_channelGroupMap->count(name))
		return;

	FMOD::ChannelGroup* channelGroup;
	if(_system->createChannelGroup(name.c_str(), &channelGroup) == FMOD_OK)
	        _channelGroupMap->insert(std::pair<const Ogre::String, FMOD::ChannelGroup*>(name.c_str(), channelGroup));
}

void SoundManager::ChannelGroupPause(const Ogre::String &name, const bool &isPaused){
	if(_channelGroupMap->count(name))
		return;

	_channelGroupMap->at(name)->setPaused(isPaused);
}

void SoundManager::ChannelGroupPauseAll(const bool &isPaused){
	for(_CGMitr = _channelGroupMap->begin(); _CGMitr != _channelGroupMap->end(); ++_CGMitr)
		_CGMitr->second->setPaused(isPaused);
}

void SoundManager::ChannelGroupMute(const Ogre::String &name, const bool &isMuted){
	if(_channelGroupMap->count(name))
		return;

	_channelGroupMap->at(name)->setMute(isMuted);
}

void SoundManager::ChannelGroupMuteAll(const bool &isMuted){
	for(_CGMitr = _channelGroupMap->begin(); _CGMitr != _channelGroupMap->end(); ++_CGMitr)
		_CGMitr->second->setMute(isMuted);
}

void SoundManager::ChannelGroupVolume(const Ogre::String &name, const Ogre::Real &volume){
	if(_channelGroupMap->count(name))
		return;

	_channelGroupMap->at(name)->setVolume(volume);
}

void SoundManager::ChannelGroupVolumeAll(const Ogre::Real &volume){
	for(_CGMitr = _channelGroupMap->begin(); _CGMitr != _channelGroupMap->end(); ++_CGMitr)
		_CGMitr->second->setVolume(volume);
}

void SoundManager::ChannelGroupStop(const Ogre::String &name){
	if(!_channelGroupMap->count(name))
		return;
	
	_channelGroupMap->at(name)->stop();
}

void SoundManager::ChannelGroupStopAll(){
	for(_CGMitr = _channelGroupMap->begin(); _CGMitr != _channelGroupMap->end(); ++_CGMitr)
		_CGMitr->second->stop();
}

void SoundManager::ChannelGroupDestroy(const Ogre::String &name){
	if(!_channelGroupMap->count(name) || !name.compare("MASTER"))
		return;

	this->ChannelGroupStop(name);
	_channelGroupMap->at(name)->release();
	_channelGroupMap->erase(name);
}

void SoundManager::ChannelGroupDestroyAll(){
	this->ChannelGroupStopAll();
	for(_CGMitr = _channelGroupMap->begin(); _CGMitr != _channelGroupMap->end(); ++_CGMitr){
		if(!_CGMitr->first.compare("MASTER"))
			continue;
		_CGMitr->second->release();
	}
	_channelGroupMap->clear();

	FMOD::ChannelGroup* channelGroup;
	_system->getMasterChannelGroup(&channelGroup);
	_channelGroupMap->insert(std::pair<const Ogre::String, FMOD::ChannelGroup*>("MASTER", channelGroup));
}

#pragma endregion

#pragma region channel

void SoundManager::ChannelPause(const int &index, const bool &isPaused){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;
	channel->setPaused(isPaused);
}

void SoundManager::ChannelMute(const int &index, const bool &isMuted){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;
	channel->setMute(isMuted);
}

void SoundManager::ChannelVolume(const int &index, const Ogre::Real &volume){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;
	channel->setVolume(volume);
}

void SoundManager::ChannelLoop(const int &index, const int &loopCount){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;
	channel->setLoopCount(loopCount);
}

void SoundManager::ChannelStop(const int &index){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;
	channel->stop();
}

#pragma endregion

#pragma region channel3D

void SoundManager::Channel3DAttributes(const int &index, const Ogre::Vector3 &position, const Ogre::Vector3 &velocity){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;

	const FMOD_VECTOR posVec = {position.x, position.y, position.z},
		velVec = {velocity.x * _timeSinceLastFrame, 
                          velocity.y * _timeSinceLastFrame, 
                          velocity.z * _timeSinceLastFrame};
	channel->set3DAttributes(&posVec, &velVec);
}

void SoundManager::Channel3DConeOrientation(const int &index, const Ogre::Vector3 &orientation){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;
	
	FMOD_VECTOR orient = {orientation.normalisedCopy().x, 
                              orientation.normalisedCopy().y, 
                              orientation.normalisedCopy().z};
	channel->set3DConeOrientation(&orient);
}

void SoundManager::Channel3DConeSettings(const int &index, const Ogre::Real &insideAngle, const Ogre::Real &outsideAngle,
    const Ogre::Real &outsideVolume){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;

	channel->set3DConeSettings(insideAngle, outsideAngle, outsideVolume);
}

void SoundManager::Channel3DDopplerLevel(const int &index, const Ogre::Real &level){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;
	
	channel->set3DDopplerLevel(level);
}

void SoundManager::Channel3DMinMaxDistance(const int &index, const Ogre::Real &minDistance, 
    const Ogre::Real &maxDistance){
	FMOD::Channel* channel;
	if(_system->getChannel(index, &channel) != FMOD_OK)
		return;

	channel->set3DMinMaxDistance(minDistance, maxDistance);
}

#pragma endregion

#pragma region playlist

void SoundManager::PlaylistPlay(const Ogre::String &playlistName){
	if(!_playlistMap->count(playlistName))
		return;
	_playlistMap->at(playlistName)->Play();
}

void SoundManager::PlaylistPlayAll(){
	for(_playlistItr = _playlistMap->begin(); _playlistItr != _playlistMap->end(); ++_playlistItr)
		_playlistItr->second->Play();
}

void SoundManager::PlaylistSkip(const Ogre::String &playlistName){
	if(!_playlistMap->count(playlistName))
		return;
	_playlistMap->at(playlistName)->Skip();
}

void SoundManager::PlaylistPause(const Ogre::String &playlistName){
	if(!_playlistMap->count(playlistName))
		return;
	_playlistMap->at(playlistName)->Pause();
}

void SoundManager::PlaylistPauseAll(){
	for(_playlistItr = _playlistMap->begin(); _playlistItr != _playlistMap->end(); ++_playlistItr)
		_playlistItr->second->Pause();
}

void SoundManager::PlaylistResume(const Ogre::String &playlistName){
	if(!_playlistMap->count(playlistName))
		return;
	_playlistMap->at(playlistName)->Resume();
}

void SoundManager::PlaylistResumeAll(){
	for(_playlistItr = _playlistMap->begin(); _playlistItr != _playlistMap->end(); ++_playlistItr)
		_playlistItr->second->Resume();
}

void SoundManager::PlaylistStop(const Ogre::String &playlistName){
	if(!_playlistMap->count(playlistName))
		return;
	_playlistMap->at(playlistName)->Stop();
	
}

void SoundManager::PlatlistStopAll(){
	for(_playlistItr = _playlistMap->begin(); _playlistItr != _playlistMap->end(); ++_playlistItr)
		_playlistItr->second->Stop();
}

void SoundManager::PlaylistDestroy(const Ogre::String &playlistName){
	if(!_playlistMap->count(playlistName))
		return;

	Sound2DPlaylist *playlist = _playlistMap->at(playlistName);
	_playlistMap->erase(playlistName);
	delete playlist;
}

void SoundManager::PlaylistDestroyAll(){
	Sound2DPlaylist *playlist;

	while(_playlistMap->begin() != _playlistMap->end()){
		playlist = _playlistMap->begin()->second;
		_playlistMap->erase(_playlistMap->begin()->first);
		delete playlist;
	}
}

#pragma endregion

#pragma region play

int SoundManager::Play2DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName){
	if(!_2DsoundMap->count(soundName))
		return -1;

	int channelIndex;
	FMOD::Channel* channel;

	if(_system->playSound(FMOD_CHANNEL_FREE, _2DsoundMap->at(soundName)->_sound, false, &channel) != FMOD_OK)
		return -1;

	if(!_channelGroupMap->count(channelGroupName))
		this->ChannelGroupCreate(channelGroupName);
	
	channel->setChannelGroup(_channelGroupMap->at(channelGroupName));
	channel->getIndex(&channelIndex);
	return channelIndex;
}

int SoundManager::Play2DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, const int &loopCount){
	if(!_2DsoundMap->count(soundName))
		return -1;

	int channelIndex;
	FMOD::Channel* channel;

	if(_system->playSound(FMOD_CHANNEL_FREE, _2DsoundMap->at(soundName)->_sound, false, &channel) != FMOD_OK)
		return -1;
	
	if(!_channelGroupMap->count(channelGroupName))
		this->ChannelGroupCreate(channelGroupName);

	channel->setChannelGroup(_channelGroupMap->at(channelGroupName));
	channel->setLoopCount(loopCount);
	channel->getIndex(&channelIndex);
	return channelIndex;
}

int SoundManager::Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
    const Ogre::Vector3 &position){
	if(!_3DsoundMap->count(soundName))
		return -1;

	int channelIndex;
	FMOD::Channel* channel;

	if(_system->playSound(FMOD_CHANNEL_FREE, _3DsoundMap->at(soundName)->_sound, false, &channel) != FMOD_OK)
		return -1;

	if(!_channelGroupMap->count(channelGroupName))
		this->ChannelGroupCreate(channelGroupName);
	
	channel->setChannelGroup(_channelGroupMap->at(channelGroupName));
	channel->getIndex(&channelIndex);
	
	this->Channel3DAttributes(channelIndex, position, Ogre::Vector3(0.0f));

	return channelIndex;
}

int SoundManager::Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
    const Ogre::Vector3 &position, const int &loopCount){
	if(!_3DsoundMap->count(soundName))
		return -1;
	
	int channelIndex;
	FMOD::Channel* channel;

	if(_system->playSound(FMOD_CHANNEL_FREE, _3DsoundMap->at(soundName)->_sound, false, &channel) != FMOD_OK)
		return -1;
	
	if(!_channelGroupMap->count(channelGroupName))
		this->ChannelGroupCreate(channelGroupName);
	
	channel->setChannelGroup(_channelGroupMap->at(channelGroupName));
	channel->setLoopCount(loopCount);
	channel->getIndex(&channelIndex);

	this->Channel3DAttributes(channelIndex, position, Ogre::Vector3(0.0f));

	return channelIndex;
}

int SoundManager::Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
    const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, const Ogre::Vector3 &forward){
	if(!_3DsoundMap->count(soundName))
		return -1;

	int channelIndex;
	FMOD::Channel* channel;

	if(_system->playSound(FMOD_CHANNEL_FREE, _3DsoundMap->at(soundName)->_sound, false, &channel) != FMOD_OK)
		return -1;
	
	if(!_channelGroupMap->count(channelGroupName))
		this->ChannelGroupCreate(channelGroupName);

	channel->setChannelGroup(_channelGroupMap->at(channelGroupName));
	channel->getIndex(&channelIndex);

	this->Channel3DAttributes(channelIndex, position, velocity);
	this->Channel3DConeOrientation(channelIndex, forward);

	return channelIndex;
}

int SoundManager::Play3DSound(const Ogre::String &soundName, const Ogre::String &channelGroupName, 
    const Ogre::Vector3 &position, const Ogre::Vector3 &velocity, const Ogre::Vector3 &forward, const int &loopCount){
	if(!_3DsoundMap->count(soundName))
		return -1;

		if(!_3DsoundMap->count(soundName))
		return -1;

	int channelIndex;
	FMOD::Channel* channel;

	if(_system->playSound(FMOD_CHANNEL_FREE, _3DsoundMap->at(soundName)->_sound, false, &channel) != FMOD_OK)
		return -1;
	
	if(!_channelGroupMap->count(channelGroupName))
		this->ChannelGroupCreate(channelGroupName);

	channel->setChannelGroup(_channelGroupMap->at(channelGroupName));
	channel->setLoopCount(loopCount);
	channel->getIndex(&channelIndex);

	this->Channel3DAttributes(channelIndex, position, velocity);
	this->Channel3DConeOrientation(channelIndex, forward);

	return channelIndex;
}

#pragma endregion



sample sound input file

first line is the sound group name
first param is the relative path from the directory
second param is the default priority of the sound
third param is the string used to identify the sound

songTest
ambient_one_four.ogg		0	Ambient One Four
ambient_one_loop.ogg  		0	Ambient Loop
ambient_three.ogg 		0	Ambient Three
ambient_two.ogg 		0	Ambient Two
excited.ogg 			0	Excited
relaxed.ogg 			0	Relaxed



sample playlist file

first line is the playlist name
each additional entry is the identification string. (sounds must already be loaded)

playlistTest
Ambient Loop
Ambient Three
Ambient Two