# HG changeset patch
# User Sven Eberhardt
# Date 1349381764 -7200
# Node ID d1e97b07b2b79b421995f4d43649119b24d85351
# Parent  cb043bd906782579ca110ae00e6195df422ce2ab
Change sound and music code to use fmodex_4 instead of fmod3

diff -r cb043bd90678 -r d1e97b07b2b7 cmake/FindFMod.cmake
--- a/cmake/FindFMod.cmake	Wed Oct 03 00:54:56 2012 +0200
+++ b/cmake/FindFMod.cmake	Thu Oct 04 22:16:04 2012 +0200
@@ -23,15 +23,15 @@
 
 if(CMAKE_CL_64)
 	if(MSVC)
-		set(FMOD_NAMES ${FMOD_NAMES} fmod64vc)
+		set(FMOD_NAMES ${FMOD_NAMES} fmodex64_vc)
 	else()
-		set(FMOD_NAMES ${FMOD_NAMES} fmod64)
+		set(FMOD_NAMES ${FMOD_NAMES} fmodex64_lcc)
 	endif()
 else()
 	if(MSVC)
-		set(FMOD_NAMES ${FMOD_NAMES} fmodvc)
+		set(FMOD_NAMES ${FMOD_NAMES} fmodex_vc)
 	else()
-		set(FMOD_NAMES ${FMOD_NAMES} fmod)
+		set(FMOD_NAMES ${FMOD_NAMES} fmodex_lcc)
 	endif()
 endif()
 find_library(FMOD_LIBRARY NAMES ${FMOD_NAMES})
diff -r cb043bd90678 -r d1e97b07b2b7 src/game/C4Application.cpp
--- a/src/game/C4Application.cpp	Wed Oct 03 00:54:56 2012 +0200
+++ b/src/game/C4Application.cpp	Thu Oct 04 22:16:04 2012 +0200
@@ -553,8 +553,8 @@
 	// gamepad clear
 	if (pGamePadControl) { delete pGamePadControl; pGamePadControl=NULL; }
 	// music system clear
+	SoundSystem.Clear();
 	MusicSystem.Clear();
-	SoundSystem.Clear();
 	RestoreVideoMode();
 	// Clear direct draw (late, because it's needed for e.g. Log)
 	if (pDraw) { delete pDraw; pDraw=NULL; }
@@ -624,6 +624,7 @@
 		break;
 	case C4AS_Startup:
 		// wait for the user to start a game
+		SoundSystem.Execute();
 		break;
 	case C4AS_StartGame:
 		// immediate progress to next state; OpenGame will enter HandleMessage-loops in startup and lobby!
diff -r cb043bd90678 -r d1e97b07b2b7 src/platform/C4MusicFile.cpp
--- a/src/platform/C4MusicFile.cpp	Wed Oct 03 00:54:56 2012 +0200
+++ b/src/platform/C4MusicFile.cpp	Thu Oct 04 22:16:04 2012 +0200
@@ -60,7 +60,16 @@
 }
 
 #if defined HAVE_FMOD
-bool C4MusicFileMID::Play(bool loop)
+C4MusicFileFMOD::C4MusicFileFMOD() : mod(NULL), channel(NULL), Playing(false), Data(NULL)
+{
+}
+
+C4MusicFileFMOD::~C4MusicFileFMOD()
+{
+	Stop();
+}
+
+bool C4MusicFileFMOD::Play(bool loop)
 {
 	// check existance
 	if (!FileExists(FileName))
@@ -70,233 +79,82 @@
 			return false;
 
 	// init fmusic
-	mod = FMUSIC_LoadSong(SongExtracted ? Config.AtTempPath(C4CFN_TempMusic2) : FileName);
+	FMOD_RESULT result = fmod_system->createSound(SongExtracted ? Config.AtTempPath(C4CFN_TempMusic2) : FileName, FMOD_DEFAULT | FMOD_CREATESTREAM | FMOD_CREATESTREAM, NULL, &mod);
 
 	if (!mod)
 	{
-		LogF("FMod: %s", FMOD_ErrorString(FSOUND_GetError()));
+		LogF("FMod load MIDI: %s", FMOD_ErrorString(result));
 		return false;
 	}
 
 	// Play Song
-	FMUSIC_PlaySong(mod);
+	result = fmod_system->playSound(FMOD_CHANNEL_FREE, mod, true, &channel);
+	if (result != FMOD_OK)
+	{
+		LogF("FMod play MIDI: %s", FMOD_ErrorString(result));
+		return false;
+	}
+	// Set highest priority
+	if (channel->setPriority(255) != FMOD_OK)
+		return false;
+
+	Playing = true;
+
+	// Actually start playing
+	channel->setPaused(false);
+	
+
 
 	return true;
 }
 
-void C4MusicFileMID::Stop(int fadeout_ms)
+void C4MusicFileFMOD::Stop(int fadeout_ms)
 {
 	if (mod)
 	{
-		FMUSIC_StopSong(mod);
-		FMUSIC_FreeSong(mod);
+		mod->release();
 		mod = NULL;
+		channel = NULL;
 	}
+	if (Data) { delete[] Data; Data = NULL; }
 	RemTempFile();
+	Playing = false;
 }
 
-void C4MusicFileMID::CheckIfPlaying()
+void C4MusicFileFMOD::CheckIfPlaying()
 {
-	if (FMUSIC_IsFinished(mod))
+	// Check if still playing
+	if (mod && channel && Playing)
+	{
+		Playing = false;
+		// Sound must still be in channel...
+		FMOD::Sound *chan_sound;
+		if (channel->getCurrentSound(&chan_sound) == FMOD_OK)
+		{
+			if (chan_sound == mod)
+			{
+				// ...and not done yet
+				unsigned int chan_pos, song_len;
+				if (   channel->getPosition(&chan_pos, FMOD_TIMEUNIT_PCM) == FMOD_OK
+					&& mod->getLength(&song_len, FMOD_TIMEUNIT_PCM) == FMOD_OK)
+				{
+					if (chan_pos < song_len)
+						Playing = true;
+				}
+				
+			}
+		}
+	}
+	if (!Playing)
 		Application.MusicSystem.NotifySuccess();
 }
 
-void C4MusicFileMID::SetVolume(int iLevel)
+void C4MusicFileFMOD::SetVolume(int iLevel)
 {
-	FMUSIC_SetMasterVolume(mod, BoundBy((iLevel * 256) / 100, 0, 255));
+	if (channel)
+		channel->setVolume(BoundBy(float(iLevel)/100.0f, 0.0f, 1.0f));
 }
 
-/* MOD */
-
-C4MusicFileMOD::C4MusicFileMOD()
-		: mod(NULL), Data(NULL)
-{
-
-}
-
-C4MusicFileMOD::~C4MusicFileMOD()
-{
-	Stop();
-}
-
-bool C4MusicFileMOD::Play(bool loop)
-{
-	// Load Song
-	size_t iFileSize;
-	if (!C4Group_ReadFile(FileName, &Data, &iFileSize))
-		return false;
-
-	// init fmusic
-	mod = FMUSIC_LoadSongEx(Data, 0, iFileSize, FSOUND_LOADMEMORY, 0, 0);
-
-	if (!mod)
-	{
-		LogF("FMod: %s", FMOD_ErrorString(FSOUND_GetError()));
-		return false;
-	}
-
-	// Play Song
-	FMUSIC_PlaySong(mod);
-
-	return true;
-}
-
-void C4MusicFileMOD::Stop(int fadeout_ms)
-{
-	if (mod)
-	{
-		FMUSIC_StopSong(mod);
-		FMUSIC_FreeSong(mod);
-		mod = NULL;
-	}
-	if (Data) { delete[] Data; Data = NULL; }
-}
-
-void C4MusicFileMOD::CheckIfPlaying()
-{
-	if (FMUSIC_IsFinished(mod))
-		Application.MusicSystem.NotifySuccess();
-}
-
-void C4MusicFileMOD::SetVolume(int iLevel)
-{
-	FMUSIC_SetMasterVolume(mod, (int) ((iLevel * 255) / 100));
-}
-
-/* MP3 */
-
-C4MusicFileMP3::C4MusicFileMP3()
-		: stream(NULL), Data(NULL), Channel(-1)
-{
-
-}
-
-C4MusicFileMP3::~C4MusicFileMP3()
-{
-	Stop();
-}
-
-bool C4MusicFileMP3::Play(bool loop)
-{
-#ifndef USE_MP3
-	return false;
-#endif
-
-	// Load Song
-	size_t iFileSize;
-	if (!C4Group_ReadFile(FileName, &Data, &iFileSize))
-		return false;
-
-	// init fsound
-	int loop_flag = loop ? FSOUND_LOOP_NORMAL : 0;
-	stream = FSOUND_Stream_Open(Data, FSOUND_LOADMEMORY | FSOUND_NORMAL | FSOUND_2D | loop_flag, 0, iFileSize);
-
-	if (!stream) return false;
-
-	// Play Song
-	Channel = FSOUND_Stream_Play(FSOUND_FREE, stream);
-	if (Channel == -1) return false;
-
-	// Set highest priority
-	if (!FSOUND_SetPriority(Channel, 255))
-		return false;
-
-	return true;
-}
-
-void C4MusicFileMP3::Stop(int fadeout_ms)
-{
-	if (stream)
-	{
-		FSOUND_Stream_Close(stream);
-		stream = NULL;
-	}
-	if (Data) { delete[] Data; Data = NULL; }
-}
-
-void C4MusicFileMP3::CheckIfPlaying()
-{
-	if (FSOUND_Stream_GetPosition(stream) >= (unsigned) FSOUND_Stream_GetLength(stream))
-		Application.MusicSystem.NotifySuccess();
-}
-
-void C4MusicFileMP3::SetVolume(int iLevel)
-{
-	FSOUND_SetVolume(Channel, (int) ((iLevel * 255) / 100));
-}
-
-/* Ogg Vobis */
-
-C4MusicFileOgg::C4MusicFileOgg()
-		: stream(NULL), Data(NULL), Channel(-1), Playing(false)
-{
-
-}
-
-C4MusicFileOgg::~C4MusicFileOgg()
-{
-	Stop();
-}
-
-bool C4MusicFileOgg::Play(bool loop)
-{
-	// Load Song
-	size_t iFileSize;
-	if (!C4Group_ReadFile(FileName, &Data, &iFileSize))
-		return false;
-
-	// init fsound
-	int loop_flag = loop ? FSOUND_LOOP_NORMAL : 0;
-	stream = FSOUND_Stream_Open(Data, FSOUND_LOADMEMORY | FSOUND_NORMAL | FSOUND_2D | loop_flag, 0, iFileSize);
-
-	if (!stream) return false;
-
-	// Play Song
-	Channel = FSOUND_Stream_Play(FSOUND_FREE, stream);
-	if (Channel == -1) return false;
-
-	// Set highest priority
-	if (!FSOUND_SetPriority(Channel, 255))
-		return false;
-
-	Playing = true;
-
-	FSOUND_Stream_SetEndCallback(stream, &C4MusicFileOgg::OnEnd, this);
-
-	return true;
-}
-
-// End Callback
-signed char __stdcall C4MusicFileOgg::OnEnd(FSOUND_STREAM* stream, void* buff, int length, void *param)
-{
-	C4MusicFileOgg* pFile = static_cast<C4MusicFileOgg*>(param);
-	pFile->Playing = false;
-	return 0;
-}
-
-void C4MusicFileOgg::Stop(int fadeout_ms)
-{
-	if (stream)
-	{
-		FSOUND_Stream_Close(stream);
-		stream = NULL;
-	}
-	if (Data) { delete[] Data; Data = NULL; }
-	Playing = false;
-}
-
-void C4MusicFileOgg::CheckIfPlaying()
-{
-
-	if (!Playing)
-		//if(FSOUND_Stream_GetPosition(stream) >= (unsigned) FSOUND_Stream_GetLength(stream))
-		Application.MusicSystem.NotifySuccess();
-}
-
-void C4MusicFileOgg::SetVolume(int iLevel)
-{
-	FSOUND_SetVolume(Channel, (int) ((iLevel * 255) / 100));
-}
 
 #elif defined HAVE_LIBSDL_MIXER
 C4MusicFileSDL::C4MusicFileSDL():
diff -r cb043bd90678 -r d1e97b07b2b7 src/platform/C4MusicFile.h
--- a/src/platform/C4MusicFile.h	Wed Oct 03 00:54:56 2012 +0200
+++ b/src/platform/C4MusicFile.h	Thu Oct 04 22:16:04 2012 +0200
@@ -24,7 +24,7 @@
 #define INC_C4MusicFile
 
 #if defined HAVE_FMOD
-#include <fmod.h>
+#include <fmod.hpp>
 #elif defined HAVE_LIBSDL_MIXER
 #define USE_RWOPS
 #include <SDL_mixer.h>
@@ -61,69 +61,22 @@
 
 };
 #if defined HAVE_FMOD
-class C4MusicFileMID : public C4MusicFile
+
+class C4MusicFileFMOD : public C4MusicFile
 {
 public:
-	bool Play(bool loop = false);
-	bool Extract();
-	void Stop(int fadeout_ms = 0);
-	void CheckIfPlaying();
-	//C4MusicFileMID();
-	void SetVolume(int);
-protected:
-	FMUSIC_MODULE *mod;
-};
-
-/* MOD class */
-
-class C4MusicFileMOD : public C4MusicFile
-{
-public:
-	C4MusicFileMOD();
-	~C4MusicFileMOD();
-	bool Play(bool loop = false);
-	void Stop(int fadeout_ms = 0);
-	void CheckIfPlaying();
-	void SetVolume(int);
-protected:
-	FMUSIC_MODULE *mod;
-	char *Data;
-};
-
-/* MP3 class */
-
-class C4MusicFileMP3 : public C4MusicFile
-{
-public:
-	C4MusicFileMP3();
-	~C4MusicFileMP3();
-	bool Play(bool loop = false);
-	void Stop(int fadeout_ms = 0);
-	void CheckIfPlaying();
-	void SetVolume(int);
-protected:
-	FSOUND_STREAM *stream;
-	char *Data;
-	int Channel;
-};
-
-/* Ogg class */
-
-class C4MusicFileOgg : public C4MusicFile
-{
-public:
-	C4MusicFileOgg();
-	~C4MusicFileOgg();
+	C4MusicFileFMOD();
+	~C4MusicFileFMOD();
 	bool Play(bool loop = false);
 	void Stop(int fadeout_ms = 0);
 	void CheckIfPlaying();
 	void SetVolume(int);
 
-	static signed char __stdcall OnEnd(FSOUND_STREAM* stream, void* buff, int length, void* param);
+	static signed char __stdcall OnEnd(FMOD::Sound* stream, void* buff, int length, void* param);
 protected:
-	FSOUND_STREAM *stream;
+	FMOD::Sound *mod;
+	FMOD::Channel *channel;
 	char *Data;
-	int Channel;
 
 	bool Playing;
 };
diff -r cb043bd90678 -r d1e97b07b2b7 src/platform/C4MusicSystem.cpp
--- a/src/platform/C4MusicSystem.cpp	Wed Oct 03 00:54:56 2012 +0200
+++ b/src/platform/C4MusicSystem.cpp	Thu Oct 04 22:16:04 2012 +0200
@@ -68,34 +68,82 @@
 bool C4MusicSystem::InitializeMOD()
 {
 #if defined HAVE_FMOD
-#ifdef _WIN32
+	// init sequence according to docs
+	unsigned int version;
+	int numdrivers;
+	FMOD_SPEAKERMODE speakermode;
+	FMOD_CAPS caps;
+	char name[256];
+	/*
+	Create a System object and initialize.
+	*/
+	if (FMOD::System_Create(&fmod_system) != FMOD_OK) { LogF("FMOD init error"); return false; }
+	if (fmod_system->getVersion(&version) != FMOD_OK) { LogF("FMOD version error"); DeinitializeMOD(); return false; }
+	if (version < FMOD_VERSION)
+	{
+		LogF("Error! You are using an old version of FMOD %08x. This program requires %08x\n", version, FMOD_VERSION);
+		DeinitializeMOD(); return false;
+	}
+#ifdef _WIN32
 	// Debug code
+	void *init_data = NULL;
 	switch (Config.Sound.FMMode)
 	{
 	case 0:
-		FSOUND_SetOutput(FSOUND_OUTPUT_WINMM);
+		fmod_system->setOutput(FMOD_OUTPUTTYPE_WINMM);
 		break;
 	case 1:
-		FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND);
-		FSOUND_SetHWND(Application.pWindow->hWindow);
+		fmod_system->setOutput(FMOD_OUTPUTTYPE_DSOUND);
+		init_data = (void *)(Application.pWindow->hWindow);
 		break;
 	case 2:
-		FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND);
-		FSOUND_SetDriver(0);
+		fmod_system->setOutput(FMOD_OUTPUTTYPE_DSOUND);
 		break;
-	}
-	FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT);
-#endif
-	if (FSOUND_GetVersion() < FMOD_VERSION)
-	{
-		LogF("FMod: You are using the wrong DLL version!  You should be using %.02f", FMOD_VERSION);
-		return false;
-	}
-	if (!FSOUND_Init(44100, 32, 0))
-	{
-		LogF("FMod: %s", FMOD_ErrorString(FSOUND_GetError()));
-		return false;
-	}
+	}
+	//
+	if (fmod_system->getNumDrivers(&numdrivers) != FMOD_OK) { LogF("FMOD driver error"); DeinitializeMOD(); return false; }
+	if (numdrivers == 0) { LogF("FMOD: 0 drivers."); DeinitializeMOD(); return false; }
+	if (fmod_system->getDriverCaps(0, &caps, 0, &speakermode) != FMOD_OK) { LogF("FMOD driver caps error"); DeinitializeMOD(); return false; }
+	/*
+	Set the user selected speaker mode.
+	*/
+	if (fmod_system->setSpeakerMode(speakermode) != FMOD_OK) { LogF("FMOD setSpeakerMode error"); DeinitializeMOD(); return false; }
+	if (caps & FMOD_CAPS_HARDWARE_EMULATED)
+	{
+		/*
+		The user has the 'Acceleration' slider set to off! This is really bad
+		for latency! You might want to warn the user about this.
+		*/
+		if (fmod_system->setDSPBufferSize(1024, 10) != FMOD_OK) { LogF("FMOD setDSPBufferSize error"); DeinitializeMOD(); return false; }
+	}
+	if (fmod_system->getDriverInfo(0, name, 256, 0) != FMOD_OK) { LogF("FMOD getDriverInfo error"); DeinitializeMOD(); return false; }
+	if (strstr(name, "SigmaTel"))
+	{
+		/*
+		Sigmatel sound devices crackle for some reason if the format is PCM 16bit.
+		PCM floating point output seems to solve it.
+		*/
+		if (fmod_system->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0,FMOD_DSP_RESAMPLER_LINEAR) != FMOD_OK) { LogF("FMOD getDriverInfo error"); DeinitializeMOD(); return false; }
+	}
+#endif
+	FMOD_RESULT result = fmod_system->init(100, FMOD_INIT_NORMAL, init_data);
+#ifdef _WIN32
+	if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
+	{
+		/*
+		Ok, the speaker mode selected isn't supported by this soundcard. Switch it
+		back to stereo...
+		*/
+		if (fmod_system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO) != FMOD_OK)
+			 { LogF("FMOD setSpeakerMode error"); DeinitializeMOD(); return false; }
+		/*
+		... and re-init.
+		*/
+		result = fmod_system->init(100, FMOD_INIT_NORMAL, init_data);
+	}
+#endif
+	if (result != FMOD_OK)
+		{ LogF("FMod: %s", FMOD_ErrorString(result)); DeinitializeMOD(); return false; }
 	// ok
 	MODInitialized = true;
 	return true;
@@ -135,11 +183,10 @@
 void C4MusicSystem::DeinitializeMOD()
 {
 #if defined HAVE_FMOD
-	FSOUND_StopSound(FSOUND_ALL); /* to prevent some hangs in FMOD */
-#ifdef DEBUG
-	Sleep(0);
-#endif
-	FSOUND_Close();
+	if (fmod_system)
+	{
+		fmod_system->release(); fmod_system = NULL;
+	}
 #elif defined HAVE_LIBSDL_MIXER
 	Mix_CloseAudio();
 	SDL_Quit();
@@ -228,18 +275,20 @@
 	switch (GetMusicFileTypeByExtension(GetExtension(szFile)))
 	{
 	case MUSICTYPE_MOD:
-		if (MODInitialized) NewSong = new C4MusicFileMOD;
+		if (MODInitialized) NewSong = new C4MusicFileFMOD;
 		break;
 	case MUSICTYPE_MP3:
-		if (MODInitialized) NewSong = new C4MusicFileMP3;
+#ifdef USE_MP3
+		if (MODInitialized) NewSong = new C4MusicFileFMOD;
+#endif
 		break;
 	case MUSICTYPE_OGG:
-		if (MODInitialized) NewSong = new C4MusicFileOgg;
+		if (MODInitialized) NewSong = new C4MusicFileFMOD;
 		break;
 
 	case MUSICTYPE_MID:
 		if (MODInitialized)
-			NewSong = new C4MusicFileMID;
+			NewSong = new C4MusicFileFMOD;
 		break;
 	default: return; // safety
 	}
diff -r cb043bd90678 -r d1e97b07b2b7 src/platform/C4SoundLoaders.cpp
--- a/src/platform/C4SoundLoaders.cpp	Wed Oct 03 00:54:56 2012 +0200
+++ b/src/platform/C4SoundLoaders.cpp	Thu Oct 04 22:16:04 2012 +0200
@@ -244,24 +244,29 @@
 #ifdef HAVE_FMOD
 bool FMODSoundLoader::ReadInfo(SoundInfo* result, BYTE* data, size_t data_length, uint32_t options)
 {
-	int32_t iOptions = FSOUND_NORMAL | FSOUND_2D | FSOUND_LOADMEMORY;
+	FMOD_CREATESOUNDEXINFO load_info;
+	ZeroMemory(&load_info, sizeof load_info);
+	load_info.cbsize = sizeof load_info;
+	load_info.length = data_length;
+	int32_t iOptions = FMOD_2D | FMOD_OPENMEMORY | FMOD_CREATESAMPLE;
 	if (options & OPTION_Raw)
-		iOptions |= FSOUND_LOADRAW;
+		iOptions |= FMOD_OPENRAW;
 	C4SoundHandle pSample;
-	if (!(pSample = FSOUND_Sample_Load(FSOUND_UNMANAGED, (const char *)data, iOptions, 0, data_length)))
-		{ return false; }
+	if (fmod_system->createSound((const char *)(data), iOptions, &load_info, &pSample) != FMOD_OK)
+		return false;
 	// get length
-	int32_t iSamples = FSOUND_Sample_GetLength(pSample);
-	int iSampleRate = 0;
-	if (!iSamples || !FSOUND_Sample_GetDefaults(pSample, &iSampleRate, 0, 0, 0))
+	unsigned int sample_length;
+	float sample_rate;
+	if (pSample->getLength(&sample_length, FMOD_TIMEUNIT_PCM) != FMOD_OK) sample_length = 0;
+	if (pSample->getDefaults(&sample_rate, NULL, NULL, NULL) != FMOD_OK) sample_rate = 0;
+	if (!sample_length || !sample_rate)
 	{
-		FSOUND_Sample_Free(pSample);
+		pSample->release();
 		return false;
 	}
-	result->sample_rate = iSampleRate;
-	result->sample_length = static_cast<double>(iSamples) / iSampleRate;
+	result->sample_rate = sample_rate;
+	result->sample_length = static_cast<double>(sample_length) / sample_rate;
 	result->final_handle = pSample;
-	assert(result->sample_length > 0);
 	return true;
 }
 
diff -r cb043bd90678 -r d1e97b07b2b7 src/platform/C4SoundSystem.cpp
--- a/src/platform/C4SoundSystem.cpp	Wed Oct 03 00:54:56 2012 +0200
+++ b/src/platform/C4SoundSystem.cpp	Thu Oct 04 22:16:04 2012 +0200
@@ -40,6 +40,10 @@
 #include <SDL_mixer.h>
 #endif
 
+#ifdef HAVE_FMOD
+FMOD::System *fmod_system;
+#endif
+
 using namespace C4SoundLoaders;
 
 C4SoundEffect::C4SoundEffect():
@@ -60,7 +64,7 @@
 {
 	while (FirstInst) RemoveInst(FirstInst);
 #ifdef HAVE_FMOD
-	if (pSample) FSOUND_Sample_Free(pSample);
+	if (pSample) { pSample->release(); pSample=NULL; }
 #endif
 #ifdef HAVE_LIBSDL_MIXER
 	if (pSample) Mix_FreeChunk(pSample);
@@ -206,7 +210,7 @@
 C4SoundInstance::C4SoundInstance():
 		pEffect (NULL),
 		iVolume (0), iPan (0),
-		iChannel (-1),
+		iChannel (C4SoundChannel_None),
 		pNext (NULL)
 {
 }
@@ -219,7 +223,7 @@
 void C4SoundInstance::Clear()
 {
 	Stop();
-	iChannel = -1;
+	iChannel = C4SoundChannel_None;
 }
 
 bool C4SoundInstance::Create(C4SoundEffect *pnEffect, bool fLoop, int32_t inVolume, C4Object *pnObj, int32_t inNearInstanceMax, int32_t iFalloffDistance)
@@ -232,7 +236,7 @@
 	pEffect = pnEffect;
 	// Set
 	iStarted = GetTime();
-	iVolume = inVolume; iPan = 0; iChannel = -1;
+	iVolume = inVolume; iPan = 0; iChannel = C4SoundChannel_None;
 	iNearInstanceMax = inNearInstanceMax;
 	this->iFalloffDistance = iFalloffDistance;
 	pObj = pnObj;
@@ -262,16 +266,18 @@
 {
 #ifdef HAVE_FMOD
 	// Start
-	if ((iChannel = FSOUND_PlaySound(FSOUND_FREE, pEffect->pSample)) == -1)
+	if (fmod_system->playSound(FMOD_CHANNEL_FREE, pEffect->pSample, true, &iChannel) != FMOD_OK)
 		return false;
-	if (!FSOUND_SetLoopMode(iChannel, fLooping ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF))
+	if (iChannel->setLoopCount(fLooping ? -1 : 0) != FMOD_OK)
+		{ Stop(); return false; }
+	if (iChannel->setPaused(false) != FMOD_OK)
 		{ Stop(); return false; }
 	// set position
 	if (GetTime() > iStarted + 20)
 	{
 		assert(pEffect->Length > 0);
 		int32_t iTime = (GetTime() - iStarted) % pEffect->Length;
-		FSOUND_SetCurrentPosition(iChannel, iTime / 10 * pEffect->SampleRate / 100);
+		iChannel->setPosition(iTime, FMOD_TIMEUNIT_MS);
 	}
 #elif defined HAVE_LIBSDL_MIXER
 	// Be paranoid about SDL_Mixer initialisation
@@ -298,7 +304,7 @@
 	bool fRet = true;
 #ifdef HAVE_FMOD
 	if (Playing())
-		fRet = !! FSOUND_StopSound(iChannel);
+		fRet = (iChannel->stop() == FMOD_OK);
 #endif
 #ifdef HAVE_LIBSDL_MIXER
 	// iChannel == -1 will halt all channels. Is that right?
@@ -309,7 +315,7 @@
 	if (Playing())
 		alSourceStop(iChannel);
 #endif
-	iChannel = -1;
+	iChannel = C4SoundChannel_None;
 	iStarted = 0;
 	fLooping = false;
 	return fRet;
@@ -320,8 +326,21 @@
 	if (!pEffect) return false;
 #ifdef HAVE_FMOD
 	if (fLooping) return true;
-	return isStarted() ? FSOUND_GetCurrentSample(iChannel) == pEffect->pSample
-	       : GetTime() < iStarted + pEffect->Length;
+	if( isStarted())
+	{
+		FMOD::Sound *sound;
+		if (iChannel->getCurrentSound(&sound) != FMOD_OK) return false;
+		if (sound == pEffect->pSample)
+		{
+			bool is_playing = false;
+			if (iChannel->isPlaying(&is_playing) == FMOD_OK)
+				return is_playing;
+		}
+	}
+	else
+	{
+		return GetTime() < iStarted + pEffect->Length;
+	}
 #endif
 #ifdef HAVE_LIBSDL_MIXER
 	return Application.MusicSystem.MODInitialized && (iChannel != -1) && Mix_Playing(iChannel);
@@ -364,7 +383,7 @@
 		if (isStarted())
 		{
 #ifdef HAVE_FMOD
-			FSOUND_StopSound(iChannel);
+			iChannel->stop();
 #endif
 #ifdef HAVE_LIBSDL_MIXER
 			Mix_HaltChannel(iChannel);
@@ -372,7 +391,7 @@
 #ifdef USE_OPEN_AL
 			alDeleteSources(1, (ALuint*)&iChannel);
 #endif
-			iChannel = -1;
+			iChannel = C4SoundChannel_None;
 		}
 	}
 	else
@@ -383,8 +402,8 @@
 				return;
 		// set volume & panning
 #ifdef HAVE_FMOD
-		FSOUND_SetVolume(iChannel, BoundBy(iVol / 100, 0, 255));
-		FSOUND_SetPan(iChannel, BoundBy(256*(iPan+100)/200,0,255));
+		iChannel->setVolume(BoundBy<float>(float(iVol) / 25600.0f, 0.0f, 1.0f));
+		iChannel->setPan(BoundBy<float>(float(iPan) / 100.0f, -1.0f, +1.0f));
 #endif
 #ifdef HAVE_LIBSDL_MIXER
 		Mix_Volume(iChannel, (iVol * MIX_MAX_VOLUME) / (100 * 256));
diff -r cb043bd90678 -r d1e97b07b2b7 src/platform/C4SoundSystem.h
--- a/src/platform/C4SoundSystem.h	Wed Oct 03 00:54:56 2012 +0200
+++ b/src/platform/C4SoundSystem.h	Thu Oct 04 22:16:04 2012 +0200
@@ -37,10 +37,15 @@
 class C4SoundInstance;
 
 #if defined(HAVE_FMOD)
-#include <fmod.h>
-typedef FSOUND_SAMPLE* C4SoundHandle;
+#include <fmod.hpp>
+typedef FMOD::Sound* C4SoundHandle;
+typedef FMOD::Channel* C4SoundChannel;
+#define C4SoundChannel_None NULL
+extern FMOD::System *fmod_system;
 #elif defined(HAVE_LIBSDL_MIXER)
 typedef struct Mix_Chunk* C4SoundHandle;
+typedef int32_t C4SoundChannel;
+#define C4SoundChannel_None -1
 #elif defined(USE_OPEN_AL)
 #ifdef __APPLE__
 #import <OpenAL/al.h>
@@ -48,8 +53,12 @@
 #include <AL/al.h>
 #endif
 typedef ALuint C4SoundHandle;
+typedef int32_t C4SoundChannel;
+#define C4SoundChannel_None -1
 #else
 typedef void* C4SoundHandle;
+typedef void *C4SoundChannel;
+#define C4SoundChannel_None -1
 #endif
 
 class C4SoundEffect
@@ -89,7 +98,8 @@
 	~C4SoundInstance();
 protected:
 	C4SoundEffect *pEffect;
-	int32_t iVolume, iPan, iChannel;
+	C4SoundChannel iChannel;
+	int32_t iVolume, iPan;
 	unsigned long iStarted;
 	int32_t iNearInstanceMax;
 	bool fLooping;
@@ -98,7 +108,8 @@
 	C4SoundInstance *pNext;
 public:
 	C4Object *getObj() const { return pObj; }
-	bool isStarted() const { return iChannel != -1; }
+	bool isStarted() const { return iChannel != C4SoundChannel_None; }
+
 	void Clear();
 	bool Create(C4SoundEffect *pEffect, bool fLoop = false, int32_t iVolume = 100, C4Object *pObj = NULL, int32_t iNearInstanceMax = 0, int32_t iFalloffDistance = 0);
 	bool CheckStart();
