1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ultima/nuvie/core/nuvie_defs.h"
24 #include "ultima/nuvie/misc/u6_misc.h"
25 #include "ultima/nuvie/core/u6_objects.h"
26 #include "ultima/nuvie/sound/sound_manager.h"
27 #include "ultima/nuvie/sound/adplug/emu_opl.h"
28 #include "ultima/nuvie/sound/song_adplug.h"
29 #include "ultima/nuvie/core/game.h"
30 #include "ultima/nuvie/core/player.h"
31 #include "ultima/nuvie/gui/widgets/map_window.h"
32 #include "ultima/nuvie/core/effect.h"
33 #include "ultima/nuvie/sound/adplug/emu_opl.h"
34 #include "ultima/nuvie/sound/adlib_sfx_manager.h"
35 #include "ultima/nuvie/sound/pc_speaker_sfx_manager.h"
36 #include "ultima/nuvie/sound/towns_sfx_manager.h"
37 #include "ultima/nuvie/sound/custom_sfx_manager.h"
38 #include "audio/mixer.h"
39 #include "common/algorithm.h"
40 
41 namespace Ultima {
42 namespace Nuvie {
43 
44 struct ObjSfxLookup { // obj sfx lookup
45 	uint16 obj_n;
46 	SfxIdType sfx_id;
47 };
48 
49 #define SOUNDMANANGER_OBJSFX_TBL_SIZE 5
50 
51 static const ObjSfxLookup u6_obj_lookup_tbl[] = {
52 	{OBJ_U6_FOUNTAIN, NUVIE_SFX_FOUNTAIN},
53 	{OBJ_U6_FIREPLACE, NUVIE_SFX_FIRE},
54 	{OBJ_U6_CLOCK, NUVIE_SFX_CLOCK},
55 	{OBJ_U6_PROTECTION_FIELD, NUVIE_SFX_PROTECTION_FIELD},
56 	{OBJ_U6_WATER_WHEEL, NUVIE_SFX_WATER_WHEEL}
57 };
58 
59 
60 
61 bool SoundManager::g_MusicFinished;
62 
musicFinished()63 void musicFinished() {
64 	SoundManager::g_MusicFinished = true;
65 }
66 
SoundManager(Audio::Mixer * mixer)67 SoundManager::SoundManager(Audio::Mixer *mixer) : _mixer(mixer) {
68 	m_pCurrentSong = NULL;
69 	m_CurrentGroup = "";
70 	g_MusicFinished = true;
71 
72 	audio_enabled = false;
73 	music_enabled = false;
74 	sfx_enabled = false;
75 
76 	m_Config = NULL;
77 	m_SfxManager = NULL;
78 
79 	opl = NULL;
80 }
81 
~SoundManager()82 SoundManager::~SoundManager() {
83 	// Stop all mixing
84 	_mixer->stopAll();
85 
86 	//thanks to wjp for this one
87 	while (!m_Songs.empty()) {
88 		delete *(m_Songs.begin());
89 		m_Songs.erase(m_Songs.begin());
90 	}
91 	while (!m_Samples.empty()) {
92 		delete *(m_Samples.begin());
93 		m_Samples.erase(m_Samples.begin());
94 	}
95 
96 	delete opl;
97 
98 	for (IntCollectionMap::iterator it = m_ObjectSampleMap.begin(); it != m_ObjectSampleMap.end(); ++it)
99 		delete it->_value;
100 	for (IntCollectionMap::iterator it = m_TileSampleMap.begin(); it != m_TileSampleMap.end(); ++it)
101 		delete it->_value;
102 	for (StringCollectionMap::iterator it = m_MusicMap.begin(); it != m_MusicMap.end(); ++it)
103 		delete it->_value;
104 
105 	delete m_SfxManager;
106 }
107 
nuvieStartup(Configuration * config)108 bool SoundManager::nuvieStartup(Configuration *config) {
109 	Std::string config_key;
110 	Std::string music_style;
111 	Std::string music_cfg_file; //full path and filename to music.cfg
112 	Std::string sound_dir;
113 	Std::string sfx_style;
114 	bool val;
115 
116 	m_Config = config;
117 
118 	m_Config->value("config/mute", val, false);
119 	audio_enabled = !val;
120 	m_Config->value("config/GameType", game_type);
121 	m_Config->value("config/audio/stop_music_on_group_change", stop_music_on_group_change, true);
122 
123 	/*  if(audio_enabled == false) // commented out to allow toggling
124 	     {
125 	      music_enabled = false;
126 	      sfx_enabled = false;
127 	      music_volume = 0;
128 	      sfx_volume = 0;
129 	      mixer = NULL;
130 	      return false;
131 	     }*/
132 
133 	m_Config->value("config/music_mute", val, false);
134 	music_enabled = !val;
135 	m_Config->value("config/sfx_mute", val, false);
136 	sfx_enabled = !val;
137 
138 	int volume;
139 
140 	m_Config->value("config/music_volume", volume, Audio::Mixer::kMaxChannelVolume);
141 	music_volume = clamp(volume, 0, 255);
142 
143 	m_Config->value("config/sfx_volume", volume, Audio::Mixer::kMaxChannelVolume);
144 	sfx_volume = clamp(volume, 0, 255);
145 
146 	config_key = config_get_game_key(config);
147 	config_key.append("/music");
148 	config->value(config_key, music_style, "native");
149 
150 	config_key = config_get_game_key(config);
151 	config_key.append("/sfx");
152 	config->value(config_key, sfx_style, "native");
153 
154 	config_key = config_get_game_key(config);
155 	config_key.append("/sounddir");
156 	config->value(config_key, sound_dir, "");
157 
158 	if (game_type == NUVIE_GAME_U6) { // FM-Towns speech
159 		config->value("config/speech_mute", val, false);
160 		speech_enabled = !val;
161 	} else {
162 		speech_enabled = false;
163 	}
164 
165 	if (!initAudio()) {
166 		return false;
167 	}
168 
169 //  if(music_enabled)  // commented out to allow toggling
170 	{
171 		if (music_style == "native") {
172 			if (game_type == NUVIE_GAME_U6)
173 				LoadNativeU6Songs(); //FIX need to handle MD & SE music too.
174 		} else if (music_style == "custom")
175 			LoadCustomSongs(sound_dir);
176 		else
177 			DEBUG(0, LEVEL_WARNING, "Unknown music style '%s'\n", music_style.c_str());
178 
179 		musicPlayFrom("random");
180 	}
181 
182 //  if(sfx_enabled)  // commented out to allow toggling
183 	{
184 		//LoadObjectSamples(sound_dir);
185 		//LoadTileSamples(sound_dir);
186 		LoadSfxManager(sfx_style);
187 	}
188 
189 	return true;
190 }
191 
initAudio()192 bool SoundManager::initAudio() {
193 	opl = new CEmuopl(_mixer->getOutputRate(), true, true);
194 	return true;
195 }
196 
LoadNativeU6Songs()197 bool SoundManager::LoadNativeU6Songs() {
198 	Song *song;
199 
200 	string filename;
201 
202 	config_get_path(m_Config, "brit.m", filename);
203 	song = new SongAdPlug(_mixer, opl);
204 // loadSong(song, filename.c_str());
205 	loadSong(song, filename.c_str(), "Rule Britannia");
206 	groupAddSong("random", song);
207 
208 	config_get_path(m_Config, "forest.m", filename);
209 	song = new SongAdPlug(_mixer, opl);
210 	loadSong(song, filename.c_str(), "Wanderer (Forest)");
211 	groupAddSong("random", song);
212 
213 	config_get_path(m_Config, "stones.m", filename);
214 	song = new SongAdPlug(_mixer, opl);
215 	loadSong(song, filename.c_str(), "Stones");
216 	groupAddSong("random", song);
217 
218 	config_get_path(m_Config, "ultima.m", filename);
219 	song = new SongAdPlug(_mixer, opl);
220 	loadSong(song, filename.c_str(), "Ultima VI Theme");
221 	groupAddSong("random", song);
222 
223 	config_get_path(m_Config, "engage.m", filename);
224 	song = new SongAdPlug(_mixer, opl);
225 	loadSong(song, filename.c_str(), "Engagement and Melee");
226 	groupAddSong("combat", song);
227 
228 	config_get_path(m_Config, "hornpipe.m", filename);
229 	song = new SongAdPlug(_mixer, opl);
230 	loadSong(song, filename.c_str(), "Captain Johne's Hornpipe");
231 	groupAddSong("boat", song);
232 
233 	config_get_path(m_Config, "gargoyle.m", filename);
234 	song = new SongAdPlug(_mixer, opl);
235 	loadSong(song, filename.c_str(), "Audchar Gargl Zenmur");
236 	groupAddSong("gargoyle", song);
237 
238 	config_get_path(m_Config, "dungeon.m", filename);
239 	song = new SongAdPlug(_mixer, opl);
240 	loadSong(song, filename.c_str(), "Dungeon");
241 	groupAddSong("dungeon", song);
242 
243 	return true;
244 }
245 
LoadCustomSongs(string sound_dir)246 bool SoundManager::LoadCustomSongs(string sound_dir) {
247 	char seps[] = ";\r\n";
248 	char *token1;
249 	char *token2;
250 	char *sz;
251 	NuvieIOFileRead niof;
252 	Song *song;
253 	Std::string scriptname;
254 	Std::string filename;
255 
256 	build_path(sound_dir, "music.cfg", scriptname);
257 
258 	if (niof.open(scriptname) == false)
259 		return false;
260 
261 	sz = (char *)niof.readAll();
262 
263 	if (sz == NULL)
264 		return false;
265 
266 	token1 = strtok(sz, seps);
267 	for (; (token1 != NULL) && ((token2 = strtok(NULL, seps)) != NULL) ; token1 = strtok(NULL, seps)) {
268 		build_path(sound_dir, token2, filename);
269 
270 		song = (Song *)SongExists(token2);
271 		if (song == NULL) {
272 			song = new Song;
273 			if (!loadSong(song, filename.c_str()))
274 				continue; //error loading song
275 		}
276 
277 		if (groupAddSong(token1, song))
278 			DEBUG(0, LEVEL_DEBUGGING, "%s : %s\n", token1, token2);
279 	}
280 
281 	free(sz);
282 
283 	return true;
284 }
285 
loadSong(Song * song,const char * filename)286 bool SoundManager::loadSong(Song *song, const char *filename) {
287 	if (song->Init(filename)) {
288 		m_Songs.push_back(song);       //add it to our global list
289 		return true;
290 	} else {
291 		DEBUG(0, LEVEL_ERROR, "could not load %s\n", filename);
292 	}
293 
294 	return false;
295 }
296 
297 // (SB-X)
loadSong(Song * song,const char * filename,const char * title)298 bool SoundManager::loadSong(Song *song, const char *filename, const char *title) {
299 	if (loadSong(song, filename) == true) {
300 		song->SetName(title);
301 		return true;
302 	}
303 	return false;
304 }
305 
groupAddSong(const char * group,Song * song)306 bool SoundManager::groupAddSong(const char *group, Song *song) {
307 	if (song != NULL) {
308 		//we have a valid song
309 		SoundCollection *psc;
310 		Std::map <Common::String, SoundCollection * >::iterator it;
311 		it = m_MusicMap.find(group);
312 		if (it == m_MusicMap.end()) {
313 			//is there already a collection for this entry?
314 			psc = new SoundCollection();	// no, create a new sound collection
315 			psc->m_Sounds.push_back(song);	// add this sound to the collection
316 			m_MusicMap[group] = psc;		// insert this pair into the map
317 		} else {
318 			psc = (*it)._value;				// yes, get the existing
319 			psc->m_Sounds.push_back(song);	// add this sound to the collection
320 		}
321 	}
322 
323 	return true;
324 }
325 
326 /*
327 bool SoundManager::LoadObjectSamples (string sound_dir)
328 {
329   char seps[] = ";\r\n";
330   char *token1;
331   char *token2;
332   NuvieIOFileRead niof;
333   char *sz;
334   string samplename;
335   string scriptname;
336 
337   build_path(sound_dir, "obj_samples.cfg", scriptname);
338 
339   if(niof.open (scriptname) == false)
340 	return false;
341 
342   sz = (char *) niof.readAll ();
343 
344   token1 = strtok (sz, seps);
345 
346   while ((token1 != NULL) && ((token2 = strtok (NULL, seps)) != NULL))
347 	{
348 	  int id = atoi (token1);
349 	  DEBUG(0,LEVEL_DEBUGGING,"%d : %s\n", id, token2);
350 	  Sound *ps;
351 	  ps = SampleExists (token2);
352 	  if (ps == NULL)
353 		{
354 		  Sample *s;
355 		  s = new Sample;
356 		  build_path(sound_dir, token2, samplename);
357 		  if (!s->Init (samplename.c_str ()))
358 			{
359 			  DEBUG(0,LEVEL_ERROR,"could not load %s\n", samplename.c_str ());
360 			}
361 		  ps = s;
362 		  m_Samples.push_back (ps);     //add it to our global list
363 		}
364 	  if (ps != NULL)
365 		{                       //we have a valid sound
366 		  SoundCollection *psc;
367 		  Std::map < int, SoundCollection * >::iterator it;
368 		  it = m_ObjectSampleMap.find (id);
369 		  if (it == m_ObjectSampleMap.end ())
370 			{                   //is there already a collection for this entry?
371 			  psc = new SoundCollection;        //no, create a new sound collection
372 			  psc->m_Sounds.push_back (ps);     //add this sound to the collection
373 			  m_ObjectSampleMap.insert (Std::make_pair (id, psc));      //insert this pair into the map
374 			}
375 		  else
376 			{
377 			  psc = (*it).second;       //yes, get the existing
378 			  psc->m_Sounds.push_back (ps);     //add this sound to the collection
379 			}
380 		}
381 	  token1 = strtok (NULL, seps);
382 	}
383   return true;
384 };
385 
386 bool SoundManager::LoadTileSamples (string sound_dir)
387 {
388   char seps[] = ";\r\n";
389   char *token1;
390   char *token2;
391   NuvieIOFileRead niof;
392   char *sz;
393   string samplename;
394   string scriptname;
395 
396   build_path(sound_dir, "tile_samples.cfg", scriptname);
397 
398   if(niof.open (scriptname) == false)
399 	{
400 	 DEBUG(0,LEVEL_ERROR,"opening %s\n",scriptname.c_str());
401 	 return false;
402 	}
403 
404   sz = (char *) niof.readAll ();
405 
406   token1 = strtok (sz, seps);
407 
408   while ((token1 != NULL) && ((token2 = strtok (NULL, seps)) != NULL))
409 	{
410 	  int id = atoi (token1);
411 	  DEBUG(0,LEVEL_DEBUGGING,"%d : %s\n", id, token2);
412 	  Sound *ps;
413 	  ps = SampleExists (token2);
414 	  if (ps == NULL)
415 		{
416 		  Sample *s;
417 		  s = new Sample;
418 		  build_path(sound_dir, token2, samplename);
419 		  if (!s->Init (samplename.c_str ()))
420 			{
421 			  DEBUG(0,LEVEL_ERROR,"could not load %s\n", samplename.c_str ());
422 			}
423 		  ps = s;
424 		  m_Samples.push_back (ps);     //add it to our global list
425 		}
426 	  if (ps != NULL)
427 		{                       //we have a valid sound
428 		  SoundCollection *psc;
429 		  Std::map < int, SoundCollection * >::iterator it;
430 		  it = m_TileSampleMap.find (id);
431 		  if (it == m_TileSampleMap.end ())
432 			{                   //is there already a collection for this entry?
433 			  psc = new SoundCollection;        //no, create a new sound collection
434 			  psc->m_Sounds.push_back (ps);     //add this sound to the collection
435 			  m_TileSampleMap.insert (Std::make_pair (id, psc));        //insert this pair into the map
436 			}
437 		  else
438 			{
439 			  psc = (*it).second;       //yes, get the existing
440 			  psc->m_Sounds.push_back (ps);     //add this sound to the collection
441 			}
442 		}
443 	  token1 = strtok (NULL, seps);
444 	}
445   return true;
446 };
447 */
LoadSfxManager(string sfx_style)448 bool SoundManager::LoadSfxManager(string sfx_style) {
449 	if (m_SfxManager != NULL) {
450 		return false;
451 	}
452 
453 	if (sfx_style == "native") {
454 		switch (game_type) {
455 		case NUVIE_GAME_U6 :
456 			if (has_fmtowns_support(m_Config)) {
457 				sfx_style = "towns";
458 			} else {
459 				sfx_style = "pcspeaker";
460 			}
461 			break;
462 		case NUVIE_GAME_MD :
463 		case NUVIE_GAME_SE :
464 			sfx_style = "adlib";
465 			break;
466 		}
467 	}
468 
469 	if (sfx_style == "pcspeaker") {
470 		m_SfxManager = new PCSpeakerSfxManager(m_Config, _mixer);
471 	}
472 	if (sfx_style == "adlib") {
473 		m_SfxManager = new AdLibSfxManager(m_Config, _mixer);
474 	} else if (sfx_style == "towns") {
475 		m_SfxManager = new TownsSfxManager(m_Config, _mixer);
476 	} else if (sfx_style == "custom") {
477 		m_SfxManager = new CustomSfxManager(m_Config, _mixer);
478 	}
479 //FIXME what to do if unknown sfx_style is entered in config file.
480 	return true;
481 }
482 
musicPlayFrom(string group)483 void SoundManager::musicPlayFrom(string group) {
484 	if (!music_enabled || !audio_enabled)
485 		return;
486 	if (m_CurrentGroup != group) {
487 		if (stop_music_on_group_change)
488 			g_MusicFinished = true;
489 		m_CurrentGroup = group;
490 	}
491 }
492 
musicPause()493 void SoundManager::musicPause() {
494 //Mix_PauseMusic();
495 	if (m_pCurrentSong != NULL) {
496 		m_pCurrentSong->Stop();
497 	}
498 }
499 
500 /* don't call if audio or music is disabled */
musicPlay()501 void SoundManager::musicPlay() {
502 // Mix_ResumeMusic();
503 
504 // (SB-X) Get a new song if stopped.
505 	if (m_pCurrentSong == NULL)
506 		m_pCurrentSong = RequestSong(m_CurrentGroup);
507 
508 	if (m_pCurrentSong != NULL) {
509 		m_pCurrentSong->Play();
510 		m_pCurrentSong->SetVolume(music_volume);
511 	}
512 
513 }
514 
musicPlay(const char * filename,uint16 song_num)515 void SoundManager::musicPlay(const char *filename, uint16 song_num) {
516 	string path;
517 
518 	if (!music_enabled || !audio_enabled)
519 		return;
520 
521 	config_get_path(m_Config, filename, path);
522 	SongAdPlug *song = new SongAdPlug(_mixer, opl);
523 	song->Init(path.c_str(), song_num);
524 
525 	musicStop();
526 	m_pCurrentSong = song;
527 	m_CurrentGroup = "";
528 	musicPlay();
529 }
530 
531 // (SB-X) Stop the current song so a new song will play when resumed.
musicStop()532 void SoundManager::musicStop() {
533 	musicPause();
534 	m_pCurrentSong = NULL;
535 }
536 
SoundManagerSfx_find(Std::list<SoundManagerSfx>::iterator first,Std::list<SoundManagerSfx>::iterator last,const SfxIdType & value)537 Std::list < SoundManagerSfx >::iterator SoundManagerSfx_find(Std::list < SoundManagerSfx >::iterator first, Std::list < SoundManagerSfx >::iterator last, const SfxIdType &value) {
538 	for (; first != last; first++) {
539 		if ((*first).sfx_id == value)
540 			break;
541 	}
542 	return first;
543 }
544 
update_map_sfx()545 void SoundManager::update_map_sfx() {
546 	unsigned int i;
547 	uint16 x, y;
548 	uint8 l;
549 
550 	if (sfx_enabled == false)
551 		return;
552 
553 	string next_group = "";
554 	Player *p = Game::get_game()->get_player();
555 	MapWindow *mw = Game::get_game()->get_map_window();
556 
557 	vector < SfxIdType >currentlyActiveSounds;
558 	map < SfxIdType, float >volumeLevels;
559 
560 	p->get_location(&x, &y, &l);
561 
562 	//m_ViewableTiles
563 
564 	//get a list of all the sounds
565 	for (i = 0; i < mw->m_ViewableObjects.size(); i++) {
566 		//DEBUG(0,LEVEL_DEBUGGING,"%d %s",mw->m_ViewableObjects[i]->obj_n,Game::get_game()->get_obj_manager()->get_obj_name(mw->m_ViewableObjects[i]));
567 		SfxIdType sfx_id = RequestObjectSfxId(mw->m_ViewableObjects[i]->obj_n); //does this object have an associated sound?
568 		if (sfx_id != NUVIE_SFX_NONE) {
569 			//calculate the volume
570 			uint16 ox = mw->m_ViewableObjects[i]->x;
571 			uint16 oy = mw->m_ViewableObjects[i]->y;
572 			float dist = sqrtf((float)(x - ox) * (x - ox) + (float)(y - oy) * (y - oy));
573 			float vol = (8.0f - dist) / 8.0f;
574 			if (vol < 0)
575 				vol = 0;
576 			//sp->SetVolume(vol);
577 			//need the map to adjust volume according to number of active elements
578 			Std::map < SfxIdType, float >::iterator it;
579 			it = volumeLevels.find(sfx_id);
580 			if (it != volumeLevels.end()) {
581 				if (volumeLevels[sfx_id] < vol)
582 					volumeLevels[sfx_id] = vol;
583 			} else {
584 				volumeLevels[sfx_id] = vol;
585 			}
586 			//add to currently active list
587 			currentlyActiveSounds.push_back(sfx_id);
588 		}
589 	}
590 	/*
591 	for (i = 0; i < mw->m_ViewableTiles.size(); i++)
592 	  {
593 	    Sound *sp = RequestTileSound (mw->m_ViewableTiles[i].t->tile_num);        //does this object have an associated sound?
594 	    if (sp != NULL)
595 	      {
596 	        //calculate the volume
597 	        short ox = mw->m_ViewableTiles[i].x - 5;
598 	        short oy = mw->m_ViewableTiles[i].y - 5;
599 	//                      DEBUG(0,LEVEL_DEBUGGING,"%d %d\n",ox,oy);
600 	        float dist = sqrtf ((float) (ox) * (ox) + (float) (oy) * (oy));
601 	//                      DEBUG(0,LEVEL_DEBUGGING,"%s %f\n",sp->GetName().c_str(),dist);
602 	        float vol = (7.0f - (dist - 1)) / 7.0f;
603 	        if (vol < 0)
604 	          vol = 0;
605 	        //sp->SetVolume(vol);
606 	        //need the map to adjust volume according to number of active elements
607 	        Std::map < Sound *, float >::iterator it;
608 	        it = volumeLevels.find (sp);
609 	        if (it != volumeLevels.end ())
610 	          {
611 	            float old = volumeLevels[sp];
612 	//                              DEBUG(0,LEVEL_DEBUGGING,"old:%f new:%f\n",old,vol);
613 	            if (old < vol)
614 	              {
615 	                volumeLevels[sp] = vol;
616 	              }
617 	          }
618 	        else
619 	          {
620 	            volumeLevels.insert (Std::make_pair (sp, vol));
621 	          }
622 	        //add to currently active list
623 	        currentlyActiveSounds.push_back (sp);
624 	      }
625 	  }
626 	  */
627 	//DEBUG(1,LEVEL_DEBUGGING,"\n");
628 	//is this sound new? - activate it.
629 	for (i = 0; i < currentlyActiveSounds.size(); i++) {
630 		Std::list < SoundManagerSfx >::iterator it;
631 		it = SoundManagerSfx_find(m_ActiveSounds.begin(), m_ActiveSounds.end(), currentlyActiveSounds[i]);          //is the sound already active?
632 		if (it == m_ActiveSounds.end()) {
633 			//this is a new sound, add it to the active list
634 			//currentlyActiveSounds[i]->Play (true);
635 			//currentlyActiveSounds[i]->SetVolume (0);
636 			SoundManagerSfx sfx;
637 			sfx.sfx_id = currentlyActiveSounds[i];
638 			if (m_SfxManager->playSfxLooping(sfx.sfx_id, &sfx.handle, 0)) {
639 				m_ActiveSounds.push_back(sfx);//currentlyActiveSounds[i]);
640 			}
641 		}
642 	}
643 	//is this sound old? - deactivate it
644 	Std::list < SoundManagerSfx >::iterator it;
645 	it = m_ActiveSounds.begin();
646 	while (it != m_ActiveSounds.end()) {
647 		Std::vector<SfxIdType>::iterator fit;
648 		SoundManagerSfx sfx = (*it);
649 		fit = Common::find(currentlyActiveSounds.begin(), currentlyActiveSounds.end(), sfx.sfx_id);          //is the sound in the new active list?
650 		if (fit == currentlyActiveSounds.end()) {
651 			//its not, stop this sound from playing.
652 			//sfx_id->Stop ();
653 			_mixer->stopHandle(sfx.handle);
654 			it = m_ActiveSounds.erase(it);
655 		} else {
656 			_mixer->setChannelVolume(sfx.handle, (uint8)(volumeLevels[sfx.sfx_id] * (sfx_volume / 255.0f) * 255.0f));
657 			it++;
658 		}
659 	}
660 }
661 
update()662 void SoundManager::update() {
663 	if (music_enabled && audio_enabled && g_MusicFinished) {
664 		g_MusicFinished = false;
665 		if (m_pCurrentSong != NULL) {
666 			m_pCurrentSong->Stop();
667 		}
668 
669 		if (m_CurrentGroup.length() > 0)
670 			m_pCurrentSong = SoundManager::RequestSong(m_CurrentGroup);
671 
672 		if (m_pCurrentSong) {
673 			DEBUG(0, LEVEL_INFORMATIONAL, "assigning new song! '%s'\n", m_pCurrentSong->GetName().c_str());
674 			if (!m_pCurrentSong->Play(false)) {
675 				DEBUG(0, LEVEL_ERROR, "play failed!\n");
676 			}
677 			m_pCurrentSong->SetVolume(music_volume);
678 		}
679 	}
680 
681 }
682 
683 
SongExists(string name)684 Sound *SoundManager::SongExists(string name) {
685 	Std::list < Sound * >::iterator it;
686 	for (it = m_Songs.begin(); it != m_Songs.end(); ++it) {
687 		if ((*it)->GetName() == name)
688 			return *it;
689 	}
690 
691 	return NULL;
692 }
693 
SampleExists(string name)694 Sound *SoundManager::SampleExists(string name) {
695 	Std::list < Sound * >::iterator it;
696 	for (it = m_Samples.begin(); it != m_Samples.end(); ++it) {
697 		if ((*it)->GetName() == name)
698 			return *it;
699 	}
700 
701 	return NULL;
702 }
703 
RequestTileSound(int id)704 Sound *SoundManager::RequestTileSound(int id) {
705 	Std::map < int, SoundCollection * >::iterator it;
706 	it = m_TileSampleMap.find(id);
707 	if (it != m_TileSampleMap.end()) {
708 		SoundCollection *psc;
709 		psc = (*it)._value;
710 		return psc->Select();
711 	}
712 	return NULL;
713 }
714 
RequestObjectSound(int id)715 Sound *SoundManager::RequestObjectSound(int id) {
716 	Std::map < int, SoundCollection * >::iterator it;
717 	it = m_ObjectSampleMap.find(id);
718 	if (it != m_ObjectSampleMap.end()) {
719 		SoundCollection *psc;
720 		psc = (*it)._value;
721 		return psc->Select();
722 	}
723 	return NULL;
724 }
725 
RequestObjectSfxId(uint16 obj_n)726 uint16 SoundManager::RequestObjectSfxId(uint16 obj_n) {
727 	uint16 i = 0;
728 	for (i = 0; i < SOUNDMANANGER_OBJSFX_TBL_SIZE; i++) {
729 		if (u6_obj_lookup_tbl[i].obj_n == obj_n) {
730 			return u6_obj_lookup_tbl[i].sfx_id;
731 		}
732 	}
733 
734 	return NUVIE_SFX_NONE;
735 }
736 
RequestSong(string group)737 Sound *SoundManager::RequestSong(string group) {
738 	Std::map<Common::String, SoundCollection * >::iterator it;
739 	it = m_MusicMap.find(group);
740 	if (it != m_MusicMap.end()) {
741 		SoundCollection *psc;
742 		psc = (*it)._value;
743 		return psc->Select();
744 	}
745 	return NULL;
746 }
747 
playTownsSound(Std::string filename,uint16 sample_num)748 Audio::SoundHandle SoundManager::playTownsSound(Std::string filename, uint16 sample_num) {
749 	FMtownsDecoderStream *stream = new FMtownsDecoderStream(filename, sample_num);
750 	Audio::SoundHandle handle;
751 	_mixer->playStream(Audio::Mixer::kSpeechSoundType, &handle, stream, -1);
752 
753 	return handle;
754 }
755 
isSoundPLaying(Audio::SoundHandle handle)756 bool SoundManager::isSoundPLaying(Audio::SoundHandle handle) {
757 	return _mixer->isSoundHandleActive(handle);
758 }
759 
playSfx(uint16 sfx_id,bool async)760 bool SoundManager::playSfx(uint16 sfx_id, bool async) {
761 	if (m_SfxManager == NULL || audio_enabled == false || sfx_enabled == false)
762 		return false;
763 
764 	if (async) {
765 		if (m_SfxManager->playSfx(sfx_id, sfx_volume)) {
766 			uint32 duration = m_SfxManager->getLastSfxDuration();
767 
768 			TimedEffect *timer = new TimedEffect();
769 
770 			AsyncEffect *e = new AsyncEffect(timer);
771 			timer->start_timer(duration);
772 			e->run();
773 
774 			return true;
775 		}
776 	} else {
777 		return m_SfxManager->playSfx(sfx_id, sfx_volume);
778 	}
779 
780 	return false;
781 }
782 
set_audio_enabled(bool val)783 void SoundManager::set_audio_enabled(bool val) {
784 	audio_enabled = val;
785 	if (audio_enabled && music_enabled)
786 		musicPlay();
787 	else
788 		musicStop();
789 }
790 
set_music_enabled(bool val)791 void SoundManager::set_music_enabled(bool val) {
792 	music_enabled = val;
793 	if (audio_enabled && music_enabled)
794 		musicPlay();
795 	else
796 		musicStop();
797 }
798 
set_speech_enabled(bool val)799 void SoundManager::set_speech_enabled(bool val) {
800 	speech_enabled = val;
801 	// FIXME - stop speech
802 }
803 
804 } // End of namespace Nuvie
805 } // End of namespace Ultima
806