Преглед на файлове

Split audioh into soundh and musich. Derive both from a new CAudioBase class. Fixed crash when there is no sound card present.

Frank Zago преди 16 години
родител
ревизия
8e2a6466e2
променени са 9 файла, в които са добавени 172 реда и са изтрити 158 реда
  1. 16 16
      client/CBattleInterface.cpp
  2. 1 1
      client/CCastleInterface.cpp
  3. 4 2
      client/CGameInfo.h
  4. 11 8
      client/CMT.cpp
  5. 14 14
      client/CPlayerInterface.cpp
  6. 3 3
      client/CPreGame.cpp
  7. 4 4
      client/GUIClasses.cpp
  8. 94 84
      hch/CMusicHandler.cpp
  9. 25 26
      hch/CMusicHandler.h

+ 16 - 16
client/CBattleInterface.cpp

@@ -1097,12 +1097,12 @@ void CBattleInterface::stackMoved(int number, int destHex, bool endMoving, int d
 	if(startMoving) //animation of starting move; some units don't have this animation (ie. halberdier)
 	{
 		if (movedStack->creature->sounds.startMoving)
-			CGI->audioh->playSound(movedStack->creature->sounds.startMoving);
+			CGI->soundh->playSound(movedStack->creature->sounds.startMoving);
 		handleStartMoving(number);
 	}
 	if(moveStarted)
 	{
-		moveSh = CGI->audioh->playSound(movedStack->creature->sounds.move, -1);
+		moveSh = CGI->soundh->playSound(movedStack->creature->sounds.move, -1);
 		CGI->curh->hide();
 		creAnims[number]->setType(0);
 		moveStarted = false;
@@ -1198,7 +1198,7 @@ void CBattleInterface::stackMoved(int number, int destHex, bool endMoving, int d
 		if(creAnims[number]->framesInGroup(21)!=0) // some units don't have this animation (ie. halberdier)
 		{
 			if (movedStack->creature->sounds.endMoving) {
-				CGI->audioh->playSound(movedStack->creature->sounds.endMoving);
+				CGI->soundh->playSound(movedStack->creature->sounds.endMoving);
 			}
 
 			creAnims[number]->setType(21);
@@ -1213,7 +1213,7 @@ void CBattleInterface::stackMoved(int number, int destHex, bool endMoving, int d
 		}
 		creAnims[number]->setType(2); //resetting to default
 		CGI->curh->show();
-		CGI->audioh->stopSound(moveSh);
+		CGI->soundh->stopSound(moveSh);
 	}
 
 	CStack curs = *LOCPLINT->cb->battleGetStackByID(number);
@@ -1287,13 +1287,13 @@ void CBattleInterface::stacksAreAttacked(std::vector<CBattleInterface::SStackAtt
 			
 		if(attackedInfos[g].killed)
 		{
-			CGI->audioh->playSound(attacked.creature->sounds.killed);
+			CGI->soundh->playSound(attacked.creature->sounds.killed);
 			creAnims[attackedInfos[g].ID]->setType(5); //death
 		}
 		else
 		{
 			// TODO: this block doesn't seems correct if the unit is defending.
-			CGI->audioh->playSound(attacked.creature->sounds.wince);
+			CGI->soundh->playSound(attacked.creature->sounds.wince);
 			creAnims[attackedInfos[g].ID]->setType(3); //getting hit
 		}
 	}
@@ -1786,7 +1786,7 @@ void CBattleInterface::battleFinished(const BattleResult& br)
 	CGI->curh->changeGraphic(0,0);
 	
 	SDL_Rect temp_rect = genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
-	CGI->audioh->stopMusic();
+	CGI->musich->stopMusic();
 	resWindow = new CBattleReslutWindow(br, temp_rect, this);
 	LOCPLINT->pushInt(resWindow);
 }
@@ -1801,7 +1801,7 @@ void CBattleInterface::spellCast(SpellCast * sc)
 	std::vector< std::string > anims; //for magic arrow and ice bolt
 
 	if (spell.soundID != soundBase::invalid)
-		CGI->audioh->playSound(spell.soundID);
+		CGI->soundh->playSound(spell.soundID);
 
 	switch(sc->id)
 	{
@@ -2052,14 +2052,14 @@ void CBattleInterface::attackingShowHelper()
 				// that is fixed. Once done, we can get rid of
 				// attackingInfo->sh
 				if (attackingInfo->sh == -1)
-					attackingInfo->sh = CGI->audioh->playSound(aStack.creature->sounds.shoot);
+					attackingInfo->sh = CGI->soundh->playSound(aStack.creature->sounds.shoot);
 				creAnims[attackingInfo->ID]->setType(attackingInfo->shootingGroup);
 			}
 			else
 			{
 				// TODO: see comment above
 				if (attackingInfo->sh == -1)
-					attackingInfo->sh = CGI->audioh->playSound(aStack.creature->sounds.attack);
+					attackingInfo->sh = CGI->soundh->playSound(aStack.creature->sounds.attack);
 				if(aStack.creature->isDoubleWide())
 				{
 					switch(BattleInfo::mutualPosition(aStack.position+attackingInfo->posShiftDueToDist, attackingInfo->dest)) //attack direction
@@ -2792,36 +2792,36 @@ CBattleReslutWindow::CBattleReslutWindow(const BattleResult &br, const SDL_Rect
 	case 0: //normal victory
 		if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won
 		{
-			CGI->audioh->playMusic(musicBase::winBattle);
+			CGI->musich->playMusic(musicBase::winBattle);
 			CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[304], 235, 235, GEOR13, zwykly, background);
 		}
 		else
 		{
-			CGI->audioh->playMusic(musicBase::loseCombat);
+			CGI->musich->playMusic(musicBase::loseCombat);
 			CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[311], 235, 235, GEOR13, zwykly, background);
 		}
 		break;
 	case 1: //flee
 		if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won
 		{
-			CGI->audioh->playMusic(musicBase::winBattle);
+			CGI->musich->playMusic(musicBase::winBattle);
 			CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[303], 235, 235, GEOR13, zwykly, background);
 		}
 		else
 		{
-			CGI->audioh->playMusic(musicBase::retreatBattle);
+			CGI->musich->playMusic(musicBase::retreatBattle);
 			CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[310], 235, 235, GEOR13, zwykly, background);
 		}
 		break;
 	case 2: //surrender
 		if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won
 		{
-			CGI->audioh->playMusic(musicBase::winBattle);
+			CGI->musich->playMusic(musicBase::winBattle);
 			CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[302], 235, 235, GEOR13, zwykly, background);
 		}
 		else
 		{
-			CGI->audioh->playMusic(musicBase::surrenderBattle);
+			CGI->musich->playMusic(musicBase::surrenderBattle);
 			CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[309], 235, 235, GEOR13, zwykly, background);
 		}
 		break;

+ 1 - 1
client/CCastleInterface.cpp

@@ -504,7 +504,7 @@ void CCastleInterface::close()
 		LOCPLINT->adventureInt->select(town->visitingHero);
 	LOCPLINT->castleInt = NULL;
 	LOCPLINT->popIntTotally(this);
-	CGI->audioh->stopMusic(5000);
+	CGI->musich->stopMusic(5000);
 }
 
 void CCastleInterface::splitF()

+ 4 - 2
client/CGameInfo.h

@@ -25,7 +25,8 @@ class CAmbarCendamo;
 class CPreGameTextHandler;
 class CBuildingHandler;
 class CObjectHandler;
-class CAudioHandler;
+class CSoundHandler;
+class CMusicHandler;
 class CSemiLodHandler;
 class CDefObjInfoHandler;
 class CTownHandler;
@@ -55,7 +56,8 @@ public:
 	CMapHandler * mh;
 	CBuildingHandler * buildh;
 	CObjectHandler * objh;
-	CAudioHandler * audioh;
+	CSoundHandler * soundh;
+	CMusicHandler * musich;
 	CSemiLodHandler * sspriteh;
 	CDefObjInfoHandler * dobjinfo;
 	CTownHandler * townh;

+ 11 - 8
client/CMT.cpp

@@ -119,18 +119,21 @@ int main(int argc, char** argv)
 		THC tlog0<<"\tInitializing fonts: "<<pomtime.getDif()<<std::endl;
 
 		//initializing audio
-		CAudioHandler * audioh = new CAudioHandler;
 		// Note: because of interface button range, volume can only be a
 		// multiple of 11, from 0 to 99.
-		audioh->initAudio(88);
-		cgi->audioh = audioh;
+		cgi->soundh = new CSoundHandler;
+		cgi->soundh->init();
+		cgi->soundh->setVolume(88);
+		cgi->musich = new CMusicHandler;
+		cgi->musich->init();
+		cgi->musich->setVolume(88);
 		tlog0<<"\tInitializing sound: "<<pomtime.getDif()<<std::endl;
 
 		tlog0<<"Initializing screen, fonts and sound handling: "<<tmh.getDif()<<std::endl;
 		initDLL(::console,logfile);
 		CGI->setFromLib();
-		cgi->audioh->initCreaturesSounds(CGI->creh->creatures);
-		cgi->audioh->initSpellsSounds(CGI->spellh->spells);
+		cgi->soundh->initCreaturesSounds(CGI->creh->creatures);
+		cgi->soundh->initSpellsSounds(CGI->spellh->spells);
 		tlog0<<"Initializing VCMI_Lib: "<<tmh.getDif()<<std::endl;
 		pomtime.getDif();
 		cgi->curh = new CCursorHandler;
@@ -148,7 +151,7 @@ int main(int argc, char** argv)
 		tlog0<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
 		tlog0<<"Initialization of VCMI (together): "<<total.getDif()<<std::endl;
 
-		audioh->playMusic(musicBase::mainMenu, -1);
+		cgi->musich->playMusic(musicBase::mainMenu, -1);
 		StartInfo *options = new StartInfo(cpg->runLoop());
 
 		if(screen->w != conf.cc.resx   ||   screen->h != conf.cc.resy)
@@ -187,7 +190,7 @@ int main(int argc, char** argv)
 			THC tlog0<<"\tConnecting to the server: "<<tmh.getDif()<<std::endl;
 			cl.newGame(c,options);
 			client = &cl;
-			audioh->stopMusic();
+			cgi->musich->stopMusic();
 			boost::thread t(boost::bind(&CClient::run,&cl));
 		}
 		else //load game
@@ -196,7 +199,7 @@ int main(int argc, char** argv)
 			boost::algorithm::erase_last(fname,".vlgm1");
 			cl.load(fname);
 			client = &cl;
-			audioh->stopMusic();
+			cgi->musich->stopMusic();
 			boost::thread t(boost::bind(&CClient::run,&cl));
 		}
 

+ 14 - 14
client/CPlayerInterface.cpp

@@ -150,9 +150,9 @@ void CPlayerInterface::yourTurn()
 		 * NEWDAY. And we don't play NEWMONTH. */
 		int day = cb->getDate(1);
 		if (day != 1)
-			CGI->audioh->playSound(soundBase::newDay);
+			CGI->soundh->playSound(soundBase::newDay);
 		else
-			CGI->audioh->playSound(soundBase::newWeek);
+			CGI->soundh->playSound(soundBase::newWeek);
 
 		adventureInt->infoBar.newDay(day);
 
@@ -820,7 +820,7 @@ void CPlayerInterface::heroCreated(const CGHeroInstance * hero)
 void CPlayerInterface::openTownWindow(const CGTownInstance * town)
 {
 	castleInt = new CCastleInterface(town);
-	CGI->audioh->playMusic(castleInt->musicID, -1);
+	CGI->musich->playMusic(castleInt->musicID, -1);
 	LOCPLINT->pushInt(castleInt);
 }
 
@@ -1064,7 +1064,7 @@ void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std:
 			showingDialog->cond.wait(un);
 	}
 
-	CGI->audioh->playSound(soundBase::heroNewLevel);
+	CGI->soundh->playSound(soundBase::heroNewLevel);
 
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	CLevelWindow *lw = new CLevelWindow(hero,pskill,skills,callback);
@@ -1165,7 +1165,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID,
 	switch(what)
 	{
 	case 1:
-		CGI->audioh->playSound(soundBase::newBuilding);
+		CGI->soundh->playSound(soundBase::newBuilding);
 		castleInt->addBuilding(buildingID);
 		break;
 	case 2:
@@ -1181,7 +1181,7 @@ void CPlayerInterface::battleStart(CCreatureSet *army1, CCreatureSet *army2, int
 
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	battleInt = new CBattleInterface(army1, army2, hero1, hero2, genRect(600, 800, (conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2));
-	CGI->audioh->playMusicFromSet(CGI->audioh->battleMusics, -1);
+	CGI->musich->playMusicFromSet(CGI->musich->battleMusics, -1);
 	pushInt(battleInt);
 }
 
@@ -1389,7 +1389,7 @@ void CPlayerInterface::showComp(SComponent comp)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 
-	CGI->audioh->playSoundFromSet(CGI->audioh->pickupSounds);
+	CGI->soundh->playSoundFromSet(CGI->soundh->pickupSounds);
 
 	adventureInt->infoBar.showComp(&comp,4000);
 }
@@ -1421,7 +1421,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 
 	if(makingTurn && listInt.size())
 	{
-		CGI->audioh->playSound(static_cast<soundBase::soundID>(soundID));
+		CGI->soundh->playSound(static_cast<soundBase::soundID>(soundID));
 		showingDialog->set(true);
 		pushInt(temp);
 	}
@@ -1452,7 +1452,7 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 
-	CGI->audioh->playSound(static_cast<soundBase::soundID>(soundID));
+	CGI->soundh->playSound(static_cast<soundBase::soundID>(soundID));
 
 	if(!selection && cancel) //simple yes/no dialog
 	{
@@ -1588,18 +1588,18 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath path )
 #if 0
 		// TODO
 		if (hero is flying && sh == -1)
-			sh = CGI->audioh->playSound(soundBase::horseFlying, -1);
+			sh = CGI->soundh->playSound(soundBase::horseFlying, -1);
 		} 
 		else if (hero is in a boat && sh = -1) {
-			sh = CGI->audioh->playSound(soundBase::sound_todo, -1);
+			sh = CGI->soundh->playSound(soundBase::sound_todo, -1);
 		} else
 #endif
 		{
 			newTerrain = cb->getTileInfo(path.nodes[i].coord)->tertype;
 
 			if (newTerrain != currentTerrain) {
-				CGI->audioh->stopSound(sh);
-				sh = CGI->audioh->playSound(CGI->audioh->horseSounds[newTerrain], -1);
+				CGI->soundh->stopSound(sh);
+				sh = CGI->soundh->playSound(CGI->soundh->horseSounds[newTerrain], -1);
 				currentTerrain = newTerrain;
 			}
 		}
@@ -1612,7 +1612,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath path )
 			stillMoveHero.cond.wait(un);
 	}
 
-	CGI->audioh->stopSound(sh);
+	CGI->soundh->stopSound(sh);
 
 	//stillMoveHero = false;
 	return result;

+ 3 - 3
client/CPreGame.cpp

@@ -2000,7 +2000,7 @@ void CPreGame::scenHandleEv(SDL_Event& sEvent)
 		{
 			if (isItIn(&btns[i]->pos,sEvent.motion.x,sEvent.motion.y))
 			{
-				CGI->audioh->playSound(soundBase::button);
+				CGI->soundh->playSound(soundBase::button);
 				btns[i]->press(true);
 				ourScenSel->pressed=(Button*)btns[i];
 			}
@@ -2009,7 +2009,7 @@ void CPreGame::scenHandleEv(SDL_Event& sEvent)
 									&& (sEvent.button.x>55) && (sEvent.button.x<372))
 		{
 			int py = ((sEvent.button.y-121)/25)+ourScenSel->mapsel.slid->whereAreWe;
-			CGI->audioh->playSound(soundBase::button);
+			CGI->soundh->playSound(soundBase::button);
 			ourScenSel->mapsel.select(ourScenSel->mapsel.whichWL(py));
 		}
 
@@ -2266,7 +2266,7 @@ StartInfo CPreGame::runLoop()
 						current->highlighted=5;
 					}
 					if (current->highlighted)
-						CGI->audioh->playSound(soundBase::button);
+						CGI->soundh->playSound(soundBase::button);
 				}
 				else if ((sEvent.type==SDL_MOUSEBUTTONUP) && (sEvent.button.button == SDL_BUTTON_LEFT))
 				{

+ 4 - 4
client/GUIClasses.cpp

@@ -2674,16 +2674,16 @@ CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface
 	{
 		musicVolume->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[326+i].first),CGI->generaltexth->zelp[326+i].second, "syslb.def", 188 + 19*i, 416, i*11);
 	}
-	musicVolume->select(CGI->audioh->getMusicVolume(), 1);
-	musicVolume->onChange = boost::bind(&CAudioHandler::setMusicVolume, CGI->audioh, _1);
+	musicVolume->select(CGI->musich->getVolume(), 1);
+	musicVolume->onChange = boost::bind(&CMusicHandler::setVolume, CGI->musich, _1);
 
 	effectsVolume = new CHighlightableButtonsGroup(0, true);
 	for(int i=0; i<10; ++i)
 	{
 		effectsVolume->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[336+i].first),CGI->generaltexth->zelp[336+i].second, "syslb.def", 188 + 19*i, 482, i*11);
 	}
-	effectsVolume->select(CGI->audioh->getSoundVolume(), 1);
-	effectsVolume->onChange = boost::bind(&CAudioHandler::setSoundVolume, CGI->audioh, _1);
+	effectsVolume->select(CGI->soundh->getVolume(), 1);
+	effectsVolume->onChange = boost::bind(&CSoundHandler::setVolume, CGI->soundh, _1);
 }
 
 CSystemOptionsWindow::~CSystemOptionsWindow()

+ 94 - 84
hch/CMusicHandler.cpp

@@ -29,10 +29,40 @@ static boost::bimap<soundBase::soundID, std::string> sounds;
 
 // Not pretty, but there's only one music handler object in the game.
 static void musicFinishedCallbackC(void) {
-	CGI->audioh->musicFinishedCallback();
+	CGI->musich->musicFinishedCallback();
 }
 
-void CSoundHandler::initSounds()
+void CAudioBase::init()
+{
+	if (initialized)
+		return;
+
+	if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)==-1)
+	{
+		tlog1 << "Mix_OpenAudio error: %s!!!" << Mix_GetError() << std::endl;
+		return;
+	}
+
+	initialized = true;
+}
+
+void CAudioBase::release()
+{
+	if (initialized) {
+		Mix_CloseAudio();
+		initialized = false;
+	}
+}
+
+void CAudioBase::setVolume(unsigned int percent)
+{
+	if (percent > 100)
+		percent = 100;
+	
+	volume = percent;
+}
+
+CSoundHandler::CSoundHandler(): sndh(NULL)
 {
 	// Map sound names
 #define VCMI_SOUND_NAME(x) ( soundBase::x,
@@ -50,21 +80,31 @@ void CSoundHandler::initSounds()
 		soundBase::horseSnow, soundBase::horseSwamp, soundBase::horseRough,
 		soundBase::horseSubterranean, soundBase::horseLava,
 		soundBase::horseWater, soundBase::horseRock;
+};
 
-	// Load sounds
-	sndh = new CSndHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "Heroes3.snd"));
+void CSoundHandler::init()
+{
+	CAudioBase::init();
+
+	if (initialized)
+		// Load sounds
+		sndh = new CSndHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "Heroes3.snd"));
 }
 
-void CSoundHandler::freeSounds()
+void CSoundHandler::release()
 {
-	Mix_HaltChannel(-1);
-	delete sndh;
-
-	std::map<soundBase::soundID, Mix_Chunk *>::iterator it;
-	for (it=soundChunks.begin(); it != soundChunks.end(); it++) {
-		if (it->second)
-			Mix_FreeChunk(it->second);
+	if (initialized) {
+		Mix_HaltChannel(-1);
+		delete sndh;
+
+		std::map<soundBase::soundID, Mix_Chunk *>::iterator it;
+		for (it=soundChunks.begin(); it != soundChunks.end(); it++) {
+			if (it->second)
+				Mix_FreeChunk(it->second);
+		}
 	}
+
+	CAudioBase::release();
 }
 
 // Allocate an SDL chunk and cache it.
@@ -201,13 +241,11 @@ void CSoundHandler::initSpellsSounds(std::vector<CSpell> &spells)
 // Plays a sound, and return its channel so we can fade it out later
 int CSoundHandler::playSound(soundBase::soundID soundID, int repeats)
 {
-	int channel;
-	Mix_Chunk *chunk;
-
-	if (!sndh)
+	if (!initialized)
 		return -1;
 
-	chunk = GetSoundChunk(soundID);
+	int channel;
+	Mix_Chunk *chunk = GetSoundChunk(soundID);
 
 	if (chunk)
 	{
@@ -230,27 +268,20 @@ int CSoundHandler::playSoundFromSet(std::vector<soundBase::soundID> &sound_vec)
 
 void CSoundHandler::stopSound( int handler )
 {
-	if (handler != -1)
+	if (initialized && handler != -1)
 		Mix_HaltChannel(handler);
 }
 
 // Sets the sound volume, from 0 (mute) to 100
-void CSoundHandler::setSoundVolume(unsigned int percent)
+void CSoundHandler::setVolume(unsigned int percent)
 {
-	if (percent > 100)
-		percent = 100;
+	CAudioBase::setVolume(percent);
 
-	volume = percent;
-	Mix_Volume(-1, (MIX_MAX_VOLUME * percent)/100);
-}
-
-// Returns the current sound volume, from 0 (mute) to 100
-unsigned int CSoundHandler::getSoundVolume()
-{
-	return volume;
+	if (initialized)
+		Mix_Volume(-1, (MIX_MAX_VOLUME * volume)/100);
 }
 
-void CMusicHandler::initMusics()
+CMusicHandler::CMusicHandler(): currentMusic(NULL), nextMusic(NULL)
 {
 	// Map music IDs
 #define VCMI_MUSIC_ID(x) ( musicBase::x ,
@@ -260,35 +291,48 @@ void CMusicHandler::initMusics()
 #undef VCMI_MUSIC_NAME
 #undef VCMI_MUSIC_FILE
 
-	Mix_HookMusicFinished(musicFinishedCallbackC);
-
 	// Vector for helper
 	battleMusics += musicBase::combat1, musicBase::combat2, 
 		musicBase::combat3, musicBase::combat4;
 }
 
-void CMusicHandler::freeMusics()
+void CMusicHandler::init()
 {
-	Mix_HookMusicFinished(NULL);
+	CAudioBase::init();
 
-	musicMutex.lock();
+	if (initialized)
+		Mix_HookMusicFinished(musicFinishedCallbackC);
+}
 
-	if (currentMusic)
-	{
-		Mix_HaltMusic();
-		Mix_FreeMusic(currentMusic);
-	}
+void CMusicHandler::release()
+{
+	if (initialized) {
+		Mix_HookMusicFinished(NULL);
 
-	if (nextMusic)
-		Mix_FreeMusic(nextMusic);
+		musicMutex.lock();
 
-	musicMutex.unlock();
+		if (currentMusic)
+		{
+			Mix_HaltMusic();
+			Mix_FreeMusic(currentMusic);
+		}
+
+		if (nextMusic)
+			Mix_FreeMusic(nextMusic);
+
+		musicMutex.unlock();
+	}
+
+	CAudioBase::release();
 }
 
 // Plays a music
 // loop: -1 always repeats, 0=do not play, 1+=number of loops
 void CMusicHandler::playMusic(musicBase::musicID musicID, int loop)
 {
+	if (!initialized)
+		return;
+
 	std::string filename = DATA_DIR "Mp3" PATHSEPARATOR;
 	filename += musics[musicID];
 
@@ -328,6 +372,9 @@ void CMusicHandler::playMusicFromSet(std::vector<musicBase::musicID> &music_vec,
 // Stop and free the current music
 void CMusicHandler::stopMusic(int fade_ms)
 {
+	if (!initialized)
+		return;
+
 	musicMutex.lock();
 
 	if (currentMusic)
@@ -339,19 +386,12 @@ void CMusicHandler::stopMusic(int fade_ms)
 }
 
 // Sets the music volume, from 0 (mute) to 100
-void CMusicHandler::setMusicVolume(unsigned int percent)
+void CMusicHandler::setVolume(unsigned int percent)
 {
-	if (percent > 100)
-		percent = 100;
-
-	volume = percent;
-	Mix_VolumeMusic((MIX_MAX_VOLUME * percent)/100);
-}
+	CAudioBase::setVolume(percent);
 
-// Returns the current music volume, from 0 (mute) to 100
-unsigned int CMusicHandler::getMusicVolume()
-{
-	return volume;
+	if (initialized)
+		Mix_VolumeMusic((MIX_MAX_VOLUME * volume)/100);
 }
 
 // Called by SDL when a music finished.
@@ -375,33 +415,3 @@ void CMusicHandler::musicFinishedCallback(void)
 
 	musicMutex.unlock();
 }
-
-void CAudioHandler::initAudio(unsigned int volume)
-{
-	if (audioInitialized)
-		return;
-
-	if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)==-1)
-	{
-		tlog1 << "Mix_OpenAudio error: %s!!!" << Mix_GetError() << std::endl;
-		return;
-	}
-
-	audioInitialized = true;
-
-	initSounds();
-	setSoundVolume(volume);
-	initMusics();
-	setMusicVolume(volume);
-}
-
-CAudioHandler::~CAudioHandler()
-{
-	if (!audioInitialized)
-		return;
-
-	freeSounds();
-	freeMusics();
-
-	Mix_CloseAudio();
-}

+ 25 - 26
hch/CMusicHandler.h

@@ -23,7 +23,21 @@ struct _Mix_Music;
 typedef struct _Mix_Music Mix_Music;
 struct Mix_Chunk;
 
-class CSoundHandler
+class CAudioBase {
+protected:
+	bool initialized;
+	int volume;					// from 0 (mute) to 100
+
+public:
+	CAudioBase(): initialized(false), volume(0) {};
+	virtual void init() = 0;
+	virtual void release() = 0;
+
+	virtual void setVolume(unsigned int percent);
+	unsigned int getVolume() { return volume; };
+};
+
+class CSoundHandler: public CAudioBase
 {
 private:
 	CSndHandler *sndh;
@@ -32,29 +46,28 @@ private:
 	std::map<soundBase::soundID, Mix_Chunk *> soundChunks;
 
 	Mix_Chunk *GetSoundChunk(soundBase::soundID soundID);
-	int volume;					// from 0 (mute) to 100
 
 public:
-	CSoundHandler(): sndh(NULL), volume(0) {};
+	CSoundHandler();
+
+	void init();
+	void release();
 
-	void initSounds();
-	void freeSounds();
 	void initCreaturesSounds(std::vector<CCreature> &creatures);
 	void initSpellsSounds(std::vector<CSpell> &spells);
+	void setVolume(unsigned int percent);
 
 	// Sounds
 	int playSound(soundBase::soundID soundID, int repeats=0);
 	int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
 	void stopSound(int handler);
-	void setSoundVolume(unsigned int percent);
-	unsigned int getSoundVolume();
 
 	// Sets
 	std::vector<soundBase::soundID> pickupSounds;
 	std::vector<soundBase::soundID> horseSounds;
 };
 
-class CMusicHandler
+class CMusicHandler: public CAudioBase
 {
 private:
 	// Because we use the SDL music callback, our music variables must
@@ -63,13 +76,13 @@ private:
 	Mix_Music *currentMusic;
 	Mix_Music *nextMusic;
 	int nextMusicLoop;
-	int volume;					// from 0 (mute) to 100
 
 public:
-	CMusicHandler(): currentMusic(NULL), nextMusic(NULL), volume(0) {};
+	CMusicHandler();
 
-	void initMusics();
-	void freeMusics();
+	void init();
+	void release();
+	void setVolume(unsigned int percent);
 
 	// Musics
 	std::map<musicBase::musicID, std::string> musics;
@@ -78,21 +91,7 @@ public:
 	void playMusic(musicBase::musicID musicID, int loop=1);
 	void playMusicFromSet(std::vector<musicBase::musicID> &music_vec, int loop=1);
 	void stopMusic(int fade_ms=1000);
-	void setMusicVolume(unsigned int percent);
-	unsigned int getMusicVolume();
 	void musicFinishedCallback(void);
 };
 
-class CAudioHandler: public CSoundHandler, public CMusicHandler
-{
-private:
-	bool audioInitialized;
-
-public:
-	CAudioHandler(): audioInitialized(false) {};
-	~CAudioHandler();
-
-	void initAudio(unsigned int volume = 90);
-};
-
 #endif // __CMUSICHANDLER_H__