/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "common/system.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/textconsole.h"
#include "hopkins/sound.h"
#include "hopkins/globals.h"
#include "hopkins/hopkins.h"

namespace Hopkins {

SoundManager::SoundManager() {
	SPECIAL_SOUND = 0;
	SOUNDVOL = 0;
	VOICEVOL = 0;
	MUSICVOL = 0;
	OLD_SOUNDVOL = 0;
	OLD_MUSICVOL = 0;
	OLD_VOICEVOL = 0;
	SOUNDOFF = true;
	MUSICOFF = true;
	VOICEOFF = true;
	TEXTOFF = false;
	SOUND_FLAG = false;
	VBL_MERDE = false;
	SOUND_NUM = 0;
	old_music = 0;
	MOD_FLAG = false;

	CARD_SB = true;

	for (int i = 0; i < VOICE_COUNT; ++i)
		Common::fill((byte *)&Voice[i], (byte *)&Voice[i] + sizeof(VoiceItem), 0);
	for (int i = 0; i < SWAV_COUNT; ++i)
		Common::fill((byte *)&Swav[i], (byte *)&Swav[i] + sizeof(SwavItem), 0);
	for (int i = 0; i < MWAV_COUNT; ++i)
		Common::fill((byte *)&Mwav[i], (byte *)&Mwav[i] + sizeof(MwavItem), 0);
	for (int i = 0; i < SOUND_COUNT; ++i)
		Common::fill((byte *)&SOUND[i], (byte *)&SOUND[i] + sizeof(SoundItem), 0);
	Common::fill((byte *)&Music, (byte *)&Music + sizeof(MusicItem), 0);
}

void SoundManager::setParent(HopkinsEngine *vm) {
	_vm = vm;
	SPECIAL_SOUND = 0;
}

void SoundManager::WSOUND_INIT() {
	warning("TODO: WSOUND_INIT");
}

void SoundManager::VERIF_SOUND() {
	if (CARD_SB && !SOUNDOFF && SOUND_FLAG) {
		if (!VOICE_STAT(1)) {
			STOP_VOICE(1);
			DEL_NWAV(SOUND_NUM);
		}
	}
}

void SoundManager::LOAD_ANM_SOUND() {
	if (SPECIAL_SOUND == 200)
		VOICE_MIX(682, 1);
	if (SPECIAL_SOUND == 199)
		LOAD_WAV("SOUND22.WAV", 1);
	if (SPECIAL_SOUND == 198)
		LOAD_WAV("SOUND3.WAV", 1);
	if (SPECIAL_SOUND == 16)
		LOAD_WAV("SOUND16.WAV", 1);
	if (SPECIAL_SOUND == 14)
		LOAD_WAV("SOUND14.WAV", 1);
	if (SPECIAL_SOUND == 208)
		LOAD_WAV("SOUND77.WAV", 1);
	if (SPECIAL_SOUND == 210)
		LOAD_WAV("SOUND78.WAV", 1);
	if (SPECIAL_SOUND == 211)
		LOAD_WAV("SOUND78.WAV", 1);
	if (SPECIAL_SOUND == 5)
		LOAD_WAV("CRIE.WAV", 1);
	if (SPECIAL_SOUND == 2) {
		CHARGE_SAMPLE(5, "mitra1.wav");
		CHARGE_SAMPLE(1, "tir2.wav");
		CHARGE_SAMPLE(2, "sound6.wav");
		CHARGE_SAMPLE(3, "sound5.WAV");
		CHARGE_SAMPLE(4, "sound4.WAV");
	}
	if (SPECIAL_SOUND == 229) {
		LOAD_WAV("SOUND80.WAV", 1);
		LOAD_WAV("SOUND82.WAV", 2);
	}
}

void SoundManager::PLAY_ANM_SOUND(int soundNumber) {
	if (!_vm->_globals.CENSURE && SPECIAL_SOUND == 2) {
		if (soundNumber == 20)
			PLAY_SAMPLE2(5);
		if (soundNumber == 57)
			PLAY_SAMPLE2(1);
		if (soundNumber == 63)
			PLAY_SAMPLE2(1);
		if (soundNumber == 69)
			PLAY_SAMPLE2(1);
		if (soundNumber == 75)
			PLAY_SAMPLE2(2);
		if (soundNumber == 109)
			PLAY_SAMPLE2(3);
		if (soundNumber == 122)
			PLAY_SAMPLE2(4);
	}
	if (SPECIAL_SOUND == 1 && soundNumber == 17)
		PLAY_SOUND("SOUND42.WAV");
	if (SPECIAL_SOUND == 199 && soundNumber == 72)
		PLAY_WAV(1);
	if (SPECIAL_SOUND == 198 && soundNumber == 15)
		PLAY_WAV(1);
	if (SPECIAL_SOUND == 16 && soundNumber == 25)
		PLAY_WAV(1);
	if (SPECIAL_SOUND == 14 && soundNumber == 625)
		PLAY_WAV(1);
	if (SPECIAL_SOUND == 208 && soundNumber == 40)
		PLAY_WAV(1);
	if (SPECIAL_SOUND == 210 && soundNumber == 2)
		PLAY_WAV(1);
	if (SPECIAL_SOUND == 211 && soundNumber == 22)
		PLAY_WAV(1);
	if (SPECIAL_SOUND == 5 && soundNumber == 19)
		PLAY_WAV(1);
	if (SPECIAL_SOUND == 17) {
		if (soundNumber == 6)
			PLAY_SAMPLE2(1);
		if (soundNumber == 14)
			PLAY_SAMPLE2(2);
		if (soundNumber == 67)
			PLAY_SAMPLE2(3);
	}
	if (SPECIAL_SOUND == 229) {
		if (soundNumber == 15)
			PLAY_WAV(1);
		if (soundNumber == 91)
			PLAY_WAV(2);
	}
}

void SoundManager::WSOUND(int soundNumber) {
	if (CARD_SB && (old_music != soundNumber || !MOD_FLAG)) {
		if (MOD_FLAG == 1)
			WSOUND_OFF();
		if (soundNumber == 1)
			PLAY_MOD("appar");
		if (soundNumber == 2)
			PLAY_MOD("ville");
		if (soundNumber == 3)
			PLAY_MOD("Rock");
		if (soundNumber == 4)
			PLAY_MOD("polic");
		if (soundNumber == 5)
			PLAY_MOD("deep");
		if (soundNumber == 6)
			PLAY_MOD("purga");
		if (soundNumber == 12)
			PLAY_MOD("purg2");
		if (soundNumber == 7)
			PLAY_MOD("rivie");
		if (soundNumber == 8)
			PLAY_MOD("SUSPE");
		if (soundNumber == 9)
			PLAY_MOD("labo");
		if (soundNumber == 10)
			PLAY_MOD("cadav");
		if (soundNumber == 11)
			PLAY_MOD("caban");
		if (soundNumber == 13)
			PLAY_MOD("foret");
		if (soundNumber == 14)
			PLAY_MOD("ile");
		if (soundNumber == 15)
			PLAY_MOD("ile2");
		if (soundNumber == 16)
			PLAY_MOD("hopki");
		if (soundNumber == 17)
			PLAY_MOD("peur");
		if (soundNumber == 18)
			PLAY_MOD("peur");
		if (soundNumber == 19)
			PLAY_MOD("BASE");
		if (soundNumber == 20)
			PLAY_MOD("cada2");
		if (soundNumber == 21)
			PLAY_MOD("usine");
		if (soundNumber == 22)
			PLAY_MOD("chien");
		if (soundNumber == 23)
			PLAY_MOD("coeur");
		if (soundNumber == 24)
			PLAY_MOD("stand");
		if (soundNumber == 25)
			PLAY_MOD("ocean");
		if (soundNumber == 26)
			PLAY_MOD("base3");
		if (soundNumber == 27)
			PLAY_MOD("gloop");
		if (soundNumber == 28)
			PLAY_MOD("cant");
		if (soundNumber == 29)
			PLAY_MOD("feel");
		if (soundNumber == 30)
			PLAY_MOD("lost");
		if (soundNumber == 31)
			PLAY_MOD("tobac");
		old_music = soundNumber;
	}
}

void SoundManager::WSOUND_OFF() {
	if (CARD_SB) {
		STOP_VOICE(0);
		STOP_VOICE(1);
		STOP_VOICE(2);
		if (_vm->_soundManager.SOUND_FLAG)
			DEL_NWAV(SOUND_NUM);

		for (int i = 1; i <= 48; ++i)
			DEL_SAMPLE_SDL(i);
		
		if (MOD_FLAG) {
			STOP_MUSIC();
			DEL_MUSIC();
			MOD_FLAG = false;
		}
	}
}

void SoundManager::PLAY_MOD(const Common::String &file) {
	if (CARD_SB && !MUSICOFF) {
		_vm->_fileManager.CONSTRUIT_FICHIER(_vm->_globals.HOPMUSIC, file);
		if (MOD_FLAG) {
			STOP_MUSIC();
			DEL_MUSIC();
			MOD_FLAG = false;
		}

		LOAD_MUSIC(_vm->_globals.NFICHIER);
		PLAY_MUSIC();
		MOD_FLAG = true;
	}
}

void SoundManager::LOAD_MUSIC(const Common::String &file) {
	if (Music._active)
		DEL_MUSIC();

	Common::File f;
	Common::String filename = Common::String::format("%s.TWA", file.c_str());

	if (!f.open(filename))
		error("Error opening file %s", filename.c_str());

	char s[8];
	int destIndex = 0;
	int mwavIndex;

	bool breakFlag = false;
	do {
		f.read(&s[0], 3);

		if (s[0] == 'x') {
			// End of list reached
			Music._mwavIndexes[destIndex] = -1;
			breakFlag = true;
		} else {
			// Convert two digits to a number
			s[2] = '\0';
			mwavIndex = atol(&s[0]);

			filename = Common::String::format("%s_%s.WAV", file.c_str(), &s[0]);
			LOAD_MSAMPLE(mwavIndex, filename);

			assert(destIndex < MUSIC_WAVE_COUNT);
			Music._mwavIndexes[destIndex++] = mwavIndex;
		}
	} while (!breakFlag);

	f.close();

	Music._active = true;
	Music._isPlaying = false;
	Music._currentIndex = -1;
}

void SoundManager::PLAY_MUSIC() {
	if (Music._active)
		Music._isPlaying = true;
}

void SoundManager::STOP_MUSIC() {
	if (Music._active)
		Music._isPlaying = false;
}

void SoundManager::DEL_MUSIC() {
	if (Music._active) {
		for (int i = 0; i < 50; ++i) {
			DEL_MSAMPLE(i);
		}
	}

	Music._active = false;
	Music._isPlaying = false;
	Music._string = "     ";
	Music._currentIndex = -1;
}

void SoundManager::checkSounds() {
	checkMusic();
	checkVoices();
}

void SoundManager::checkMusic() {
	if (Music._active && Music._isPlaying) {
		int mwavIndex = Music._mwavIndexes[Music._currentIndex];
		if (mwavIndex == -1)
			return;

		if (Music._currentIndex >= 0 && Music._currentIndex < MWAV_COUNT) {
			if (mwavIndex != -1 && !Mwav[mwavIndex]._audioStream->endOfStream())
				// Currently playing wav has not finished, so exit
				return;

			_vm->_mixer->stopHandle(Mwav[mwavIndex]._soundHandle);
		}

		// Time to move to the next index
		if (++Music._currentIndex >= MWAV_COUNT)
			return;

		mwavIndex = Music._mwavIndexes[Music._currentIndex];
		if (mwavIndex == -1) {
			Music._currentIndex = 0;
			mwavIndex = Music._mwavIndexes[Music._currentIndex];
		}			

		int volume = MUSICVOL * 255 / 16;

		Mwav[mwavIndex]._audioStream->rewind();
		_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &Mwav[mwavIndex]._soundHandle, 
			Mwav[mwavIndex]._audioStream, -1, volume, 0, DisposeAfterUse::NO);
	}
}

void SoundManager::checkVoices() {
	// Check the status of each voice.
	bool hasActiveVoice = false;
	for (int i = 0; i < VOICE_COUNT; ++i) {
		VOICE_STAT(i);
		hasActiveVoice |= Voice[i]._status != 0;
	}

	if (!hasActiveVoice && SOUND_FLAG) {
		SOUND_FLAG = false;
		SOUND_NUM = 0;
	}
}

void SoundManager::LOAD_MSAMPLE(int mwavIndex, const Common::String &file) {
	if (!Mwav[mwavIndex]._active) {
		Common::File f;
		if (!f.open(file))
			error("Could not open %s for reading", file.c_str());

		Mwav[mwavIndex]._audioStream = Audio::makeWAVStream(f.readStream(f.size()), DisposeAfterUse::YES);
		Mwav[mwavIndex]._active = true;

		f.close();
	}
}

void SoundManager::DEL_MSAMPLE(int mwavIndex) {
	if (Mwav[mwavIndex]._active) {
		Mwav[mwavIndex]._active = false;
		_vm->_mixer->stopHandle(Mwav[mwavIndex]._soundHandle);

		delete Mwav[mwavIndex]._audioStream;
		Mwav[mwavIndex]._audioStream = NULL;
	}
}

bool SoundManager::VOICE_MIX(int voiceId, int voiceMode) {
	int fileNumber; 
	int oldMusicVol; 
	bool breakFlag; 
	Common::String prefix;
	Common::String filename;
	Common::File f;
	size_t catPos, catLen;

	fileNumber = voiceId;
	if (!CARD_SB || VOICEOFF == 1)
		return false;

	if ((unsigned int)(voiceMode - 1) <= 1
	        && (voiceId == 4
	            || voiceId == 16
	            || voiceId == 121
	            || voiceId == 142
	            || voiceId == 182
	            || voiceId == 191
	            || voiceId == 212
	            || voiceId == 225
	            || voiceId == 239
	            || voiceId == 245
	            || voiceId == 297
	            || voiceId == 308
	            || voiceId == 333
	            || voiceId == 348
	            || voiceId == 352
	            || voiceId == 358
	            || voiceId == 364
	            || voiceId == 371
	            || voiceId == 394
	            || voiceId == 414
	            || voiceId == 429
	            || voiceId == 442
	            || voiceId == 446
	            || voiceId == 461
	            || voiceId == 468
	            || voiceId == 476
	            || voiceId == 484
	            || voiceId == 491
	            || voiceId == 497
	            || voiceId == 501
	            || voiceId == 511
	            || voiceId == 520
	            || voiceId == 536
	            || voiceId == 554
	            || voiceId == 566
	            || voiceId == 573
	            || voiceId == 632
	            || voiceId == 645))
		fileNumber = 684;
	
	if ((unsigned int)(voiceMode - 1) <= 1) {
		prefix = "DF";
	}
	if (voiceMode == 3) {
		prefix = "IF";
	}
	if (voiceMode == 4) {
		prefix = "TF";
	}
	if (voiceMode == 5) {
		prefix = "OF";
	}

	filename = Common::String::format("%s%d.WAV", prefix.c_str(), fileNumber);
	
	if (!_vm->_fileManager.RECHERCHE_CAT(filename, 9)) {
		if (_vm->_globals.FR == 1)
			_vm->_fileManager.CONSTRUIT_FICHIER(_vm->_globals.HOPVOICE, "RES_VFR.RES");
		if (!_vm->_globals.FR)
			_vm->_fileManager.CONSTRUIT_FICHIER(_vm->_globals.HOPVOICE, "RES_VAN.RES");
		if (_vm->_globals.FR == 2)
			_vm->_fileManager.CONSTRUIT_FICHIER(_vm->_globals.HOPVOICE, "RES_VES.RES");

		catPos = _vm->_globals.CAT_POSI;
		catLen = _vm->_globals.CAT_TAILLE;
	} else {
		_vm->_fileManager.CONSTRUIT_FICHIER(_vm->_globals.HOPVOICE, filename);
	
		if (!f.exists(_vm->_globals.NFICHIER))
			return false;

		catPos = 0;
		catLen = 0;
	}

	SDL_LVOICE(catPos, catLen);
	oldMusicVol = MUSICVOL;
	if (!MUSICOFF && MUSICVOL > 2)
		MUSICVOL = (signed int)((long double)MUSICVOL - (long double)MUSICVOL / 100.0 * 45.0);

	PLAY_VOICE_SDL();

	// Loop for playing voice
	breakFlag = 0;
	do {
		if (SPECIAL_SOUND != 4 && !VBL_MERDE)
			_vm->_eventsManager.VBL();
		if (_vm->_eventsManager.BMOUSE())
			break;
		_vm->_eventsManager.CONTROLE_MES();
		if (_vm->_eventsManager.ESC_KEY)
			break;
		if (!VOICE_STAT(2))
			breakFlag = true;
	} while (!_vm->shouldQuit() && !breakFlag);


	STOP_VOICE(2);
	DEL_SAMPLE_SDL(20);
	MUSICVOL = oldMusicVol;
	_vm->_eventsManager.ESC_KEY = false;
	VBL_MERDE = 0;
	return true;
}

void SoundManager::DEL_SAMPLE(int soundIndex) {
	if (CARD_SB) {
		if (VOICE_STAT(1) == 1)
			STOP_VOICE(1);
		if (VOICE_STAT(2) == 2)
			STOP_VOICE(2);
		if (VOICE_STAT(3) == 3)
			STOP_VOICE(3);
		DEL_SAMPLE_SDL(soundIndex);
		SOUND[soundIndex]._active = false;
	}
}

void SoundManager::PLAY_SOUND(const Common::String &file) {
	if (CARD_SB && !SOUNDOFF) {
		if (SOUND_FLAG)
			DEL_NWAV(SOUND_NUM);
		LOAD_NWAV(file, 1);
		PLAY_NWAV(1);
	}
}

void SoundManager::PLAY_SOUND2(const Common::String &file) {
	if (CARD_SB) {
		if (!SOUNDOFF) {
			LOAD_NWAV(file, 1);
			PLAY_NWAV(1);
		}
	}
}

void SoundManager::MODSetSampleVolume() {
	// No implementatoin needed
}

void SoundManager::MODSetVoiceVolume() {
	// No implementatoin needed
}

void SoundManager::MODSetMusicVolume(int volume) {
	// No implementatoin needed
}

void SoundManager::CHARGE_SAMPLE(int wavIndex, const Common::String &file) {
	if (CARD_SB) {
		_vm->_fileManager.CONSTRUIT_FICHIER(_vm->_globals.HOPSOUND, file);
		LOAD_SAMPLE2_SDL(wavIndex, _vm->_globals.NFICHIER, 0);
		SOUND[wavIndex]._active = true;
	}
}

void SoundManager::PLAY_SAMPLE(int wavIndex, int voiceMode) {
	if (CARD_SB && !SOUNDOFF && SOUND[wavIndex]._active) {
		if (SOUND_FLAG)
			DEL_NWAV(SOUND_NUM);
		if (voiceMode == 5) {
			if (VOICE_STAT(1) == 1)
				STOP_VOICE(1);
			PLAY_SAMPLE_SDL(1, wavIndex);
		}
		if (voiceMode == 6) {
			if (VOICE_STAT(2) == 1)
				STOP_VOICE(1);
			PLAY_SAMPLE_SDL(2, wavIndex);
		}
		if (voiceMode == 7) {
			if (VOICE_STAT(3) == 1)
				STOP_VOICE(1);
			PLAY_SAMPLE_SDL(3, wavIndex);
		}
		if (voiceMode == 8) {
			if (VOICE_STAT(1) == 1)
				STOP_VOICE(1);
			PLAY_SAMPLE_SDL(1, wavIndex);
		}
	}
}

void SoundManager::PLAY_SAMPLE2(int idx) {
	if (CARD_SB && !SOUNDOFF && SOUND[idx]._active) {
		if (SOUND_FLAG)
			DEL_NWAV(SOUND_NUM);
		if (VOICE_STAT(1) == 1)
			STOP_VOICE(1);
		PLAY_SAMPLE_SDL(1, idx);
	}
}

void SoundManager::LOAD_WAV(const Common::String &file, int wavIndex) {
	if (CARD_SB)
		LOAD_NWAV(file, wavIndex);
}

void SoundManager::PLAY_WAV(int wavIndex) {
	if (CARD_SB)
		PLAY_NWAV(wavIndex);
}

int SoundManager::VOICE_STAT(int voiceIndex) {
	if (Voice[voiceIndex]._status) {
		int wavIndex = Voice[voiceIndex]._wavIndex;
		if (Swav[wavIndex]._audioStream != NULL && Swav[wavIndex]._audioStream->endOfStream())
			STOP_VOICE(voiceIndex);
	}

	return Voice[voiceIndex]._status;
}

void SoundManager::STOP_VOICE(int voiceIndex) {
	if (Voice[voiceIndex]._status) {
		Voice[voiceIndex]._status = 0;
		int wavIndex = Voice[voiceIndex]._wavIndex;
		if (Swav[wavIndex]._active) {
			if (Swav[wavIndex].freeSample)
				DEL_SAMPLE_SDL(wavIndex);
		}
	}
	Voice[voiceIndex].fieldC = 0;
	Voice[voiceIndex]._status = 0;
	Voice[voiceIndex].field14 = 0;
}

void SoundManager::SDL_LVOICE(size_t filePosition, size_t entryLength) {
	if (!SDL_LoadVoice(_vm->_globals.NFICHIER, filePosition, entryLength, Swav[20]))
		error("Couldn't load the sample %s", _vm->_globals.NFICHIER.c_str());

	Swav[20]._active = true;
}
	
void SoundManager::PLAY_VOICE_SDL() {
	if (!Swav[20]._active)
		error("Bad handle");

	if (!Voice[2]._status) {
		int wavIndex = Voice[2]._wavIndex;
		if (Swav[wavIndex]._active && Swav[wavIndex].freeSample)
			DEL_SAMPLE_SDL(wavIndex);
	}

	PLAY_SAMPLE_SDL(2, 20);
}

bool SoundManager::DEL_SAMPLE_SDL(int wavIndex) {
	if (Swav[wavIndex]._active) {
		_vm->_mixer->stopHandle(Swav[wavIndex]._soundHandle);
		delete Swav[wavIndex]._audioStream;
		Swav[wavIndex]._audioStream = NULL;
		Swav[wavIndex]._active = false;

		return true;
	} else {
		return false;
	}
}

bool SoundManager::SDL_LoadVoice(const Common::String &filename, size_t fileOffset, size_t entryLength, SwavItem &item) {
	Common::File f;
	if (!f.open(filename))
		error("Could not open %s for reading", filename.c_str());

	f.seek(fileOffset);
	item._audioStream = Audio::makeWAVStream(f.readStream((entryLength == 0) ? f.size() : entryLength),
		DisposeAfterUse::YES);
	f.close();

	return true;
}

void SoundManager::LOAD_SAMPLE2_SDL(int wavIndex, const Common::String &filename, bool freeSample) {
	if (Swav[wavIndex]._active)
		DEL_SAMPLE_SDL(wavIndex);

	SDL_LoadVoice(filename, 0, 0, Swav[wavIndex]);
	Swav[wavIndex]._active = true;
	Swav[wavIndex].freeSample = freeSample;
}

void SoundManager::LOAD_NWAV(const Common::String &file, int wavIndex) {
	if (CARD_SB) {
		_vm->_fileManager.CONSTRUIT_FICHIER(_vm->_globals.HOPSOUND, file);
		LOAD_SAMPLE2_SDL(wavIndex, _vm->_globals.NFICHIER, 1);
	}
}

void SoundManager::PLAY_NWAV(int wavIndex) {
	if (CARD_SB && !SOUND_FLAG && !SOUNDOFF) {
		SOUND_FLAG = true;
		SOUND_NUM = wavIndex;
		PLAY_SAMPLE_SDL(1, wavIndex);
	}
}

void SoundManager::DEL_NWAV(int wavIndex) {
	if (CARD_SB) {
		if (DEL_SAMPLE_SDL(wavIndex)) {
			if (VOICE_STAT(1) == 1)
				STOP_VOICE(1);

			SOUND_NUM = 0;
			SOUND_FLAG = false;
		}
	}
}

void SoundManager::PLAY_SAMPLE_SDL(int voiceIndex, int wavIndex) {
	if (!Swav[wavIndex]._active)
		warning("Bad handle");

	if (Voice[voiceIndex]._status == 1 && Swav[wavIndex]._active && Swav[wavIndex].freeSample)
		DEL_SAMPLE_SDL(wavIndex);

	Voice[voiceIndex].fieldC = 0;
	Voice[voiceIndex]._status = 1;
	Voice[voiceIndex].field14 = 4;
	Voice[voiceIndex]._wavIndex = wavIndex;
	
	int volume = (voiceIndex == 2) ? VOICEVOL * 255 / 16 : SOUNDVOL * 255 / 16;

	// Start the voice playing
	_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &Swav[wavIndex]._soundHandle, 
		Swav[wavIndex]._audioStream, -1, volume, 0, DisposeAfterUse::NO);
}

void SoundManager::syncSoundSettings() {
	bool muteAll = false;
	if (ConfMan.hasKey("mute"))
		muteAll = ConfMan.getBool("mute");

	// Update the mute settings
	MUSICOFF = muteAll || (ConfMan.hasKey("music_mute") && ConfMan.getBool("music_mute"));
	SOUNDOFF = muteAll || (ConfMan.hasKey("sfx_mute") && ConfMan.getBool("sfx_mute"));
	VOICEOFF = muteAll || (ConfMan.hasKey("speech_mute") && ConfMan.getBool("speech_mute"));

	// Update the volume levels
	MUSICVOL = MIN(255, ConfMan.getInt("music_volume")) * 16 / 255;
	SOUNDVOL = MIN(255, ConfMan.getInt("sfx_volume")) * 16 / 255;
	VOICEVOL = MIN(255, ConfMan.getInt("speech_volume")) * 16 / 255;

	// Update any active sounds
	for (int idx = 0; idx < SWAV_COUNT; ++idx) {
		if (Swav[idx]._active) {
			int volume = (idx == 20) ? (VOICEVOL * 255 / 16) : (SOUNDVOL * 255 / 16);
			_vm->_mixer->setChannelVolume(Swav[idx]._soundHandle, volume);
		}
	}
	for (int idx = 0; idx < MWAV_COUNT; ++idx) {
		if (Mwav[idx]._active) {
			_vm->_mixer->setChannelVolume(Mwav[idx]._soundHandle, MUSICVOL * 255 / 16);
		}
	}
}

void SoundManager::updateScummVMSoundSettings() {
	ConfMan.setBool("mute", MUSICOFF && SOUNDOFF && VOICEOFF);
	ConfMan.setBool("music_mute", MUSICOFF);
	ConfMan.setBool("sfx_mute", SOUNDOFF);
	ConfMan.setBool("speech_mute", VOICEOFF);

	ConfMan.setInt("music_volume", MUSICVOL * 255 / 16);
	ConfMan.setInt("sfx_volume", SOUNDVOL * 255 / 16);
	ConfMan.setInt("speech_volume", VOICEVOL * 255 / 16);

	ConfMan.flushToDisk();
}

} // End of namespace Hopkins