1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3 
4 This file is part of Aquaria.
5 
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */
21 
22 #include "Core.h"
23 #include "SoundManager.h"
24 #include "Base.h"
25 #include "PackRead.h"
26 
27 #if defined(BBGE_BUILD_FMODEX)
28     #ifdef BBGE_BUILD_FMOD_OPENAL_BRIDGE
29 	#include "FmodOpenALBridge.h"
30 	#else
31 	#include <fmod.h>
32 	#include <fmod.hpp>
33 	#ifdef BBGE_BUILD_WINDOWS
34 		#pragma comment(lib, "fmodex_vc.lib")
35 	#endif
36 	#endif
37 #endif
38 
39 #ifdef BBGE_BUILD_FMODEX
40 #endif
41 
42 SoundManager *sound = 0;
43 
44 std::string soundPath = "sfx/cache/";
45 std::string localSoundPath = "sfx/local/";
46 std::string musicPath = "mus/";
47 std::string voicePath = "vox/";
48 std::string fileType = ".ogg";
49 
50 namespace SoundCore
51 {
52 #ifdef BBGE_BUILD_FMODEX
53 
54 	typedef std::map<std::string, FMOD::Sound*> SoundMap;
55 	SoundMap soundMap;
56 
57 	FMOD_RESULT result;
58 	FMOD::System *system=0;
59 
60 	FMOD::Sound *musicStream=0, *voiceStream=0, *musicStream2=0;
61 
62 	FMOD::Channel *musicChannel=0, *musicChannel2=0;
63 	FMOD::Channel *voiceChannel=0;
64 
65 	FMOD::ChannelGroup *group_vox = 0;
66 	FMOD::ChannelGroup *group_sfx = 0;
67 	FMOD::ChannelGroup *group_mus = 0;
68 
69 	FMOD::Sound *modSound = 0;
70 	FMOD::Channel *modChannel = 0;
71 
72 	FMOD::ChannelGroup *masterChannelGroup = 0;
73 
74 	FMOD::DSP *dspReverb=0, *dspFlange=0;
75 
76 	float musicFader2Time = 0, musicFader2Timer = 0, musicFader2Volume = 0;
77 
78 	struct FadeCh
79 	{
80 	public:
FadeChSoundCore::FadeCh81 		FadeCh() : v(1), s(1), c(0), d(-1), to(0) {}
82 		FMOD::Channel *c;
83 		float v,s,to;
84 		int d;
85 	};
86 
87 	float faderV=1;
88 	FMOD::Channel *faderCh = 0;
89 
90 
91 	bool stopMusicOnFadeOut=false;
92 	bool wasPlayingVoice=false;
93 	bool playingMusicOnce=false;
94 
95 	typedef std::list<FadeCh> FadeChs;
96 	FadeChs fadeChs;
97 
addFadeCh(const FadeCh & fadeCh)98 	void addFadeCh(const FadeCh &fadeCh)
99 	{
100 		FadeChs::iterator i = fadeChs.begin();
101 		for (; i != fadeChs.end();)
102 		{
103 			if ((*i).c == fadeCh.c)
104 			{
105 				i = fadeChs.erase(i);
106 			}
107 			else
108 			{
109 				i++;
110 			}
111 		}
112 		fadeChs.push_back(fadeCh);
113 	}
114 #endif
115 }
116 
117 using namespace SoundCore;
118 
119 
120 /*
121     TIPS:
122 
123     1. use F_CALLBACK.  Do NOT force cast your own function to fmod's callback type.
124     2. return FMOD_ERR_FILE_NOTFOUND in open as required.
125     3. return number of bytes read in read callback.  Do not get the size and count
126        around the wrong way in fread for example, this would return 1 instead of the number of bytes read.
127 
128     QUESTIONS:
129 
130     1. Why does fmod seek to the end and read?  Because it is looking for ID3V1 tags.
131        Use FMOD_IGNORETAGS in System::createSound / System::createStream if you don't like this behaviour.
132 
133 */
134 
myopen(const char * name,int unicode,unsigned int * filesize,void ** handle,void ** userdata)135 FMOD_RESULT F_CALLBACK myopen(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata)
136 {
137 	if (name)
138 	{
139 		VFILE *fp = vfopen(name, "rb");
140 		if (!fp)
141 			return FMOD_ERR_FILE_NOTFOUND;
142 		size_t sz = 0;
143 		if(vfsize(fp, &sz) < 0)
144 		{
145 			vfclose(fp);
146 			return FMOD_ERR_FILE_NOTFOUND;
147 		}
148 
149 		*filesize = (unsigned int)sz;
150 		*userdata = (void *)0x12345678;
151 		*handle = fp;
152 	}
153 
154 	return FMOD_OK;
155 }
156 
myclose(void * handle,void * userdata)157 FMOD_RESULT F_CALLBACK myclose(void *handle, void *userdata)
158 {
159 	if (!handle)
160 	{
161 		return FMOD_ERR_INVALID_PARAM;
162 	}
163 
164 	vfclose((VFILE *)handle);
165 
166 	return FMOD_OK;
167 }
168 
myread(void * handle,void * buffer,unsigned int sizebytes,unsigned int * bytesread,void * userdata)169 FMOD_RESULT F_CALLBACK myread(void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata)
170 {
171 	if (!handle)
172 	{
173 		return FMOD_ERR_INVALID_PARAM;
174 	}
175 
176 	if (bytesread)
177 	{
178 		*bytesread = (int)vfread(buffer, 1, sizebytes, (VFILE *)handle);
179 
180 		if (*bytesread < sizebytes)
181 		{
182 			return FMOD_ERR_FILE_EOF;
183 		}
184 	}
185 
186 	return FMOD_OK;
187 }
188 
myseek(void * handle,unsigned int pos,void * userdata)189 FMOD_RESULT F_CALLBACK myseek(void *handle, unsigned int pos, void *userdata)
190 {
191 	if (!handle)
192 	{
193 		return FMOD_ERR_INVALID_PARAM;
194 	}
195 
196 	vfseek((VFILE *)handle, pos, SEEK_SET);
197 
198 	return FMOD_OK;
199 }
200 
201 
pause()202 void SoundManager::pause()
203 {
204 #ifdef BBGE_BUILD_FMODEX
205 	debugLog("SoundManager::pause");
206 
207 	debugLog("mus");
208 	result = group_mus->setPaused(true);
209 	checkError();
210 
211 	debugLog("vox");
212 	result = group_vox->setPaused(true);
213 	checkError();
214 
215 	debugLog("sfx");
216 	result = group_sfx->setPaused(true);
217 	checkError();
218 
219 	debugLog("master channel");
220 	result = SoundCore::masterChannelGroup->setPaused(true);
221 	checkError();
222 
223 	debugLog("update");
224 	result = SoundCore::system->update();
225 	checkError();
226 
227 	debugLog("done");
228 #endif
229 }
230 
resume()231 void SoundManager::resume()
232 {
233 #ifdef BBGE_BUILD_FMODEX
234 	debugLog("SoundManager::resume");
235 
236 	debugLog("mus");
237 	result = group_mus->setPaused(false);
238 	checkError();
239 
240 	debugLog("vox");
241 	result = group_vox->setPaused(false);
242 	checkError();
243 
244 	debugLog("sfx");
245 	result = group_sfx->setPaused(false);
246 	checkError();
247 
248 	debugLog("master channel");
249 	result = SoundCore::masterChannelGroup->setPaused(false);
250 	checkError();
251 
252 	debugLog("update");
253 	result = SoundCore::system->update();
254 	checkError();
255 
256 	debugLog("done");
257 #endif
258 }
259 
getBuffer(const std::string & name)260 Buffer SoundManager::getBuffer(const std::string &name)
261 {
262 	std::string n = name;
263 	stringToLower(n);
264 	return soundMap[n];
265 }
266 
getStats(int * curAlloc,int * maxAlloc)267 void SoundManager::getStats(int *curAlloc, int *maxAlloc)
268 {
269 	FMOD::Memory_GetStats(curAlloc, maxAlloc);
270 }
271 
SoundManager(const std::string & defaultDevice)272 SoundManager::SoundManager(const std::string &defaultDevice)
273 {
274 	overrideVoiceFader = -1;
275 
276 	sound = this;
277 
278 	enabled = false;
279 
280 	sfxFader = 1;
281 
282 	voxVol = Vector(1,1,1);
283 	musVol = Vector(1,1,1);
284 	sfxVol = 1;
285 	voiceFader = 1;
286 
287 	loadProgressCallback = NULL;
288 
289 #ifdef BBGE_BUILD_FMODEX
290 
291 	int channels	= 128;
292 
293     unsigned int     version;
294     FMOD_SPEAKERMODE speakermode;
295     FMOD_CAPS        caps;
296 
297 	debugLog("system::create");
298 	result = FMOD::System_Create(&SoundCore::system);
299     if (checkError()) goto get_out;
300 
301 	debugLog("getVersion");
302     result = SoundCore::system->getVersion(&version);
303     if (checkError()) goto get_out;
304 
305     if (version < FMOD_VERSION)
306     {
307 		char str[256];
308         sprintf(str, "Error!  You are using an old version of FMOD %08x.  This program requires %08x\n", version, FMOD_VERSION);
309 		debugLog(str);
310 		goto get_out;
311     }
312 
313 	debugLog("driver caps");
314     result = SoundCore::system->getDriverCaps(0, &caps, 0, 0, &speakermode);
315     if (checkError()) goto get_out;
316 
317 	debugLog("set speaker mode");
318     result = SoundCore::system->setSpeakerMode(speakermode);       /* Set the user selected speaker mode. */
319 	if (checkError()) goto get_out;
320 
321 	debugLog("check caps");
322     if (caps & FMOD_CAPS_HARDWARE_EMULATED)             /* The user has the 'Acceleration' slider set to off!  This is really bad for latency!. */
323     {                                                   /* You might want to warn the user about this. */
324 		debugLog("acceleration slider is off");
325         result = SoundCore::system->setDSPBufferSize(1024, 10);    /* At 48khz, the latency between issuing an fmod command and hearing it will now be about 213ms. */
326         if (checkError()) goto get_out;
327     }
328 
329 	debugLog("init");
330     result = SoundCore::system->init(channels, FMOD_INIT_NORMAL, 0);    /* Replace with whatever channel count and flags you use! */
331     if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)         /* Ok, the speaker mode selected isn't supported by this soundcard.  Switch it back to stereo... */
332     {
333 		debugLog("err_output_createbuffer, speaker mode");
334 		result = SoundCore::system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
335         if (checkError()) goto get_out;
336 
337 		debugLog("init 2");
338         result = SoundCore::system->init(channels, FMOD_INIT_NORMAL, 0); /* Replace with whatever channel count and flags you use! */
339 		if (checkError()) goto get_out;
340     }
341 
342 #ifdef BBGE_BUILD_FMOD_OPENAL_BRIDGE
343 	SoundCore::system->getNumChannels(&channels);
344 #endif
345 
346 	//FMOD::Debug_SetLevel(FMOD_DEBUG_LEVEL_ALL);
347 
348 	/*
349 	result = FMOD::System_Create(&SoundCore::system);		// Create the main system object.
350 	if (checkError())
351 	{
352 		exit(-1);
353 	}
354 
355 	result = SoundCore::system->init(64, FMOD_INIT_NORMAL, 0);	// Initialize FMOD.
356 	if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
357 	{
358 		debugLog("FMOD_ERR_OUTPUT_CREATEBUFFER, setting stereo speaker mode");
359 		SoundCore::system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
360 		result = SoundCore::system->init(64, FMOD_INIT_NORMAL, 0);
361 		if (checkError())
362 			exit(-1);
363 	}
364 	else
365 	{
366 		if (checkError())
367 			exit(-1);
368 	}
369 	*/
370 
371 	debugLog("set file system");
372 	result = SoundCore::system->setFileSystem(myopen, myclose, myread, myseek, 2048);
373     if (checkError()) goto get_out;
374 
375 	debugLog("create channel group vox");
376 	result = SoundCore::system->createChannelGroup("vox", &group_vox);
377 	if (checkError()) goto get_out;
378 
379 	debugLog("create channel group sfx");
380 	result = SoundCore::system->createChannelGroup("sfx", &group_sfx);
381 	if (checkError()) goto get_out;
382 
383 	debugLog("create channel group mus");
384 	result = SoundCore::system->createChannelGroup("mus", &group_mus);
385 	if (checkError()) goto get_out;
386 
387 	debugLog("getMasterChannelGroup");
388 	result = SoundCore::system->getMasterChannelGroup(&masterChannelGroup);
389 	if (checkError()) goto get_out;
390 
391 	debugLog("createDSPByType flange");
392 	result = SoundCore::system->createDSPByType(FMOD_DSP_TYPE_FLANGE, &dspFlange);
393 	if (checkError()) { dspFlange = 0; }
394 
395 	debugLog("createDSPByType reverb");
396 	result = SoundCore::system->createDSPByType(FMOD_DSP_TYPE_REVERB, &dspReverb);
397 	if (checkError()) { dspReverb = 0; }
398 
399 
400 	//dspReverb->setParameter(FMOD_DSP_REVERB_ROOMSIZE, 0.5);
401 	//dspReverb->setParameter(FMOD_DSP_REVERB_DAMP, 0.5);
402 	//dspReverb->setParameter(FMOD_DSP_REVERB_WETMIX, 0.33);
403 	//dspReverb->setParameter(FMOD_DSP_REVERB_DRYMIX, 0.66);
404 	//dspReverb->setParameter(FMOD_DSP_REVERB_WIDTH, 1.0);
405 	//dspReverb->setParameter(FMOD_DSP_REVERB_MODE, 0); // 0 or 1
406 
407 	if (dspReverb)
408 	{
409 		dspReverb->setParameter(FMOD_DSP_REVERB_ROOMSIZE, 0.8);
410 		dspReverb->setParameter(FMOD_DSP_REVERB_DAMP, 0.7);
411 		dspReverb->setParameter(FMOD_DSP_REVERB_WETMIX, 0.11);
412 		dspReverb->setParameter(FMOD_DSP_REVERB_DRYMIX, 0.88);
413 		dspReverb->setParameter(FMOD_DSP_REVERB_WIDTH, 1.0);
414 		dspReverb->setParameter(FMOD_DSP_REVERB_MODE, 0); // 0 or 1
415 	}
416 
417 
418 #endif
419 
420 	enabled = true;
421 
422 	return;
423 
424 get_out:
425 
426 	debugLog("get_out");
427 
428 	enabled = false;
429 
430 	if (SoundCore::system)
431 	{
432 		// clean up?
433 		SoundCore::system = 0;
434 		//SoundCore::system
435 	}
436 }
437 
toggleEffectMusic(SoundEffectType effect,bool on)438 void SoundManager::toggleEffectMusic(SoundEffectType effect, bool on)
439 {
440 	if (!enabled) return;
441 
442 #ifdef BBGE_BUILD_FMODEX
443 
444 	bool active = false;
445 
446 	switch(effect){
447 	case SFX_FLANGE:
448 		if (dspFlange){
449 			dspFlange->getActive(&active);
450 			if (on && !active)
451 				group_mus->addDSP(dspFlange, 0);
452 			else if (!on && active)
453 				dspFlange->remove();
454 		}
455 	break;
456 	}
457 
458 #endif
459 }
460 
461 
getVolumeString()462 std::string SoundManager::getVolumeString()
463 {
464 	std::ostringstream os;
465 	os << "sfxFader: " << this->sfxFader << " sfxVol: " << this->sfxVol << " [" << lastMusic << "]" << std::endl;
466 	os << "musVol: " << musVol.y << " voxVol: " << voxVol.y << std::endl;
467 
468 	float musicChannelVol = -1;
469 	if (musicChannel)
470 		musicChannel->getVolume(&musicChannelVol);
471 
472 	float musicGroupVol = -1;
473 	if (group_mus)
474 		group_mus->getVolume(&musicGroupVol);
475 
476 	float musicChannel2Vol = -1;
477 	if (musicChannel2)
478 		musicChannel2->getVolume(&musicChannel2Vol);
479 
480 	os << "curMusVol (c1/c2/g): " << musicChannelVol << " " << musicChannel2Vol << " " << musicGroupVol << std::endl;
481 	return os.str();
482 }
483 
getMusicFader()484 float SoundManager::getMusicFader()
485 {
486 	return musVol.y;
487 }
488 
getVoxFader()489 float SoundManager::getVoxFader()
490 {
491 	return voxVol.y;
492 }
493 
setChannelVolume(void * chan,float v)494 void SoundManager::setChannelVolume(void *chan, float v)
495 {
496 	// is this now unused?
497 }
498 
setOverrideVoiceFader(float v)499 void SoundManager::setOverrideVoiceFader(float v)
500 {
501 	overrideVoiceFader = v;
502 }
503 
setMusicFader(float v,float t)504 void SoundManager::setMusicFader(float v, float t)
505 {
506 	// ignore fades if the music is already on its way to fading out to 0
507 	if (v != 0 && musVol.data && musVol.data->target.y == 0 && musVol.y > 0)
508 	{
509 		return;
510 	}
511 
512 	/*
513 	std::ostringstream os;
514 	os << "musicFader " << v << " over " << t;
515 	debugLog(os.str());
516 	*/
517 
518 	musVol.interpolateTo(Vector(musVol.x, v, musVol.z), t);
519 
520 #ifdef BBGE_BUILD_FMODEX
521 	/*
522 	result = group_mus->setVolume(musVol.x*musVol.y*v);
523 	checkError();
524 	*/
525 #endif
526 }
527 
error(const std::string & errMsg)528 void SoundManager::error(const std::string &errMsg)
529 {
530 	//std::cout << errMsg << std::endl;
531 	errorLog(errMsg);
532 }
533 
~SoundManager()534 SoundManager::~SoundManager()
535 {
536 	// release
537 	if (!enabled) return;
538 
539 	for (SoundMap::iterator i = soundMap.begin(); i != soundMap.end(); i++)
540 	{
541 		std::string snd = (*i).first;
542 		debugLog("unloading sound [" + snd + "]");
543 #ifndef BBGE_DISABLE_SOUND_CACHE
544 		FMOD::Sound *samp = (FMOD::Sound*)((*i).second);
545 		samp->release();
546 #else
547 		SoundInfo *info = (SoundInfo*)((*i).second);
548 		delete info;
549 #endif
550 	}
551 	soundMap.clear();
552 
553 #ifdef BBGE_BUILD_FMODEX
554 	SoundCore::system->release();
555 #endif
556 }
557 
stopAllSfx()558 void SoundManager::stopAllSfx()
559 {
560 #ifdef BBGE_BUILD_FMODEX
561 	if (group_sfx)
562 		group_sfx->stop();
563 #endif
564 }
565 
stopAll()566 void SoundManager::stopAll()
567 {
568 }
569 
onVoiceEnded()570 void SoundManager::onVoiceEnded()
571 {
572 	//debugLog("Voice Ended!");
573 	event_stopVoice.call();
574 	//debugLog("checking vox queue");
575 
576 	if (dspReverb)
577 		dspReverb->remove();
578 
579 	if (!voxQueue.empty())
580 	{
581 		//debugLog("calling playVoice");
582 
583 		std::string vox = voxQueue.front();
584 
585 		//debugLog("popping voxQueue");
586 		if (!voxQueue.empty())
587 			voxQueue.pop();
588 
589 		//debugLog("calling playVoice");
590 		playVoice(vox, SVT_INTERRUPT);
591 	}
592 	else
593 	{
594 		//debugLog("setting music fader");
595 		setMusicFader(1, 1);
596 		sfxFader = 1;
597 	}
598 
599 
600 
601 	//debugLog("done onVoiceEnded");
602 }
603 
604 
isPaused()605 bool SoundManager::isPaused()
606 {
607 	bool paused = false;
608 
609 	if (!enabled) return paused;
610 
611 #ifdef BBGE_BUILD_FMODEX
612 
613 	result = masterChannelGroup->getPaused(&paused);
614 	checkError();
615 
616 #endif
617 
618 	return paused;
619 }
620 
clearFadingSfx()621 void SoundManager::clearFadingSfx()
622 {
623 #ifdef BBGE_BUILD_FMODEX
624 
625 	SoundCore::FadeChs::iterator i = fadeChs.begin();
626 	for (; i != fadeChs.end(); i++)
627 	{
628 		//haha:
629 		FadeCh *f = &(*i);
630 		if (f->c)
631 		{
632 			f->c->stop();
633 		}
634 	}
635 	SoundCore::fadeChs.clear();
636 
637 #endif
638 
639 }
640 
update(float dt)641 void SoundManager::update(float dt)
642 {
643 	if (isPaused()) return;
644 
645 	dt = core->get_old_dt();
646 
647 	voxVol.update(dt);
648 	musVol.update(dt);
649 
650 
651 #ifdef BBGE_BUILD_FMODEX
652 
653 	if (musicChannel)
654 	{
655 		if (!isPlayingMusic())
656 		{
657 			if(!playingMusicOnce && lastMusic.size())
658 			{
659 				debugLog("music not playing, but it should be - force restart");
660 				playMusic(lastMusic, SLT_LOOP, SFT_IN, 1, SCT_NORMAL); // FIXME: make sure this works with playMusicOnce()
661 			}
662 			else
663 			{
664 				stopMusic();
665 			}
666 		}
667 	}
668 
669 	if (musicChannel)
670 	{
671 		// fader value
672 
673 		result = musicChannel->setVolume(musVol.y*1.0f);
674 		checkError();
675 
676 
677 		if (musVol.y <= 0 && stopMusicOnFadeOut)
678 		{
679 			stopMusic();
680 			stopMusicOnFadeOut = false;
681 		}
682 	}
683 
684 	if (group_sfx)
685 	{
686 		group_sfx->setVolume(sfxFader*sfxVol);
687 	}
688 
689 
690 	// for cross fading
691 	if (musicChannel2)
692 	{
693 		musicFader2Timer -= dt;
694 		if (musicFader2Timer < 0) musicFader2Timer = 0;
695 
696 		musicChannel2->setVolume((musicFader2Timer/musicFader2Time)*musicFader2Volume);
697 
698 		if (musicFader2Timer <= 0)
699 		{
700 			result = musicChannel2->stop();
701 			checkError();
702 
703 			result = musicStream2->release();
704 			checkError();
705 
706 			musicChannel2 = 0;
707 			musicStream2 = 0;
708 		}
709 	}
710 
711 	if (!fadeChs.empty())
712 	{
713 		int itr=0;
714 		for (FadeChs::iterator i = fadeChs.begin(); i != fadeChs.end();)
715 		{
716 			itr++;
717 			FadeCh *f = &(*i);
718 
719 			f->v += dt*f->s * f->d;
720 
721 
722 			if (f->d > 0)
723 			{
724 				if (f->v >= f->to)
725 				{
726 					f->v = f->to;
727 					i = fadeChs.erase(i);
728 					continue;
729 				}
730 			}
731 			else
732 			{
733 				if (f->v <= f->to)
734 				{
735 					f->v = f->to;
736 
737 					result = f->c->stop();
738 					checkError();
739 					f->c = 0;
740 					i = fadeChs.erase(i);
741 					continue;
742 				}
743 			}
744 
745 			if (f->c)
746 			{
747 				f->c->setVolume(f->v);
748 				checkError();
749 			}
750 
751 			i++;
752 		}
753 	}
754 
755 	SoundCore::system->update();
756 
757 #endif
758 
759 #if defined(BBGE_BUILD_BASS20) || defined(BBGE_BUILD_FMODEX) || defined(BBGE_BUILD_SDLMIXER)
760 	if (wasPlayingVoice && !isPlayingVoice())
761 	{
762 		wasPlayingVoice = false;
763 		onVoiceEnded();
764 	}
765 #endif
766 }
767 
fadeMusic(SoundFadeType sft,float t)768 void SoundManager::fadeMusic(SoundFadeType sft, float t)
769 {
770 	switch(sft)
771 	{
772 	case SFT_CROSS:
773 	{
774 #ifdef BBGE_BUILD_FMODEX
775 		if (musicChannel2)
776 		{
777 			musicChannel2->stop();
778 			if (musicStream2)
779 			{
780 				musicStream2->release();
781 				musicStream2 = 0;
782 			}
783 			musicChannel2 = 0;
784 		}
785 
786 		musicChannel2 = musicChannel;
787 		musicStream2 = musicStream;
788 		musicStream = 0;
789 		musicChannel = 0;
790 		musicFader2Volume = musVol.y;
791 		musicFader2Time = musicFader2Timer = t;
792 
793 #endif
794 
795 	}
796 	break;
797 	case SFT_OUT:
798 		setMusicFader(0, t);
799 
800 #ifdef BBGE_BUILD_FMODEX
801 		stopMusicOnFadeOut = true;
802 #endif
803 	break;
804 	default:
805 		//setMusMul(0, t);
806 	break;
807 	}
808 }
809 
isPlayingMusic()810 bool SoundManager::isPlayingMusic()
811 {
812 #ifdef BBGE_BUILD_FMODEX
813 
814 	if (musicChannel)
815 	{
816 		bool b=false;
817 		musicChannel->isPlaying(&b);
818 		return b;
819 	}
820 
821 #endif
822 
823 #ifdef BBGE_BUILD_BASS20
824 
825 	return musicStream != 0;
826 
827 #endif
828 
829 	return false;
830 }
831 
setMusicVolume(float v)832 void SoundManager::setMusicVolume(float v)
833 {
834 	musVol.x = v;
835 
836 #ifdef BBGE_BUILD_FMODEX
837 
838 	result = group_mus->setVolume(v);
839 	checkError();
840 
841 #endif
842 }
843 
setSfxVolume(float v)844 void SoundManager::setSfxVolume(float v)
845 {
846 	sfxVol = v;
847 }
848 
getSfxVol()849 float SoundManager::getSfxVol()
850 {
851 	return sfxVol;
852 }
853 
setVoiceVolume(float v)854 void SoundManager::setVoiceVolume(float v)
855 {
856 	voxVol.x = v;
857 
858 #ifdef BBGE_BUILD_FMODEX
859 	result = group_vox->setVolume(v);
860 	checkError();
861 #endif
862 }
863 
isPlayingVoice()864 bool SoundManager::isPlayingVoice()
865 {
866 #ifdef BBGE_BUILD_FMODEX
867 
868 	if (voiceChannel)
869 	{
870 		bool b=false;
871 		result = voiceChannel->isPlaying(&b);
872 		if (result == FMOD_ERR_CHANNEL_STOLEN)
873 		{
874 			b = false;
875 			debugLog("voice channel 'stolen'");
876 		}
877 		else
878 		{
879 			checkError();
880 		}
881 		if (!b)
882 			voiceChannel = 0;
883 		return b;
884 	}
885 
886 #endif
887 
888 	return false;
889 }
890 
setSfxChannelsVolume(float v)891 void SoundManager::setSfxChannelsVolume(float v)
892 {
893 }
894 
playVoice(const std::string & name,SoundVoiceType svt,float vmod)895 bool SoundManager::playVoice(const std::string &name, SoundVoiceType svt, float vmod)
896 {
897 	if (!enabled) return false;
898 
899 	bool checkOther = true;
900 	std::string fn, n;
901 
902 	n = name;
903 	stringToLower(n);
904 
905 	if (!voicePath2.empty())
906 	{
907 		fn = voicePath2 + name + fileType;
908 		fn = localisePathInternalModpath(fn);
909 		fn = core->adjustFilenameCase(fn);
910 		if (exists(fn))	checkOther = false;
911 	}
912 
913 	if (checkOther)
914 	{
915 		fn = voicePath + name + fileType;
916 		fn = localisePath(fn);
917 		fn = core->adjustFilenameCase(fn);
918 		if (!exists(fn))
919 		{
920 			debugLog("Could not find voice file [" + fn + "]");
921 		}
922 	}
923 
924 	bool playNow=false;
925 
926 	debugLog("checking is playing now...");
927 
928 	switch(svt)
929 	{
930 	case SVT_QUEUE:
931 	{
932 		if (isPlayingVoice())
933 		{
934 			if (voxQueue.empty() || voxQueue.front() != n)
935 				voxQueue.push(n);
936 		}
937 		else
938 		{
939 			playNow = true;
940 		}
941 	}
942 	break;
943 	case SVT_INTERRUPT:
944 	{
945 		stopAllVoice();
946 		playNow = true;
947 	}
948 	break;
949 	default:
950 	break;
951 	}
952 
953 	if (playNow)
954 	{
955 #ifdef BBGE_BUILD_FMODEX
956 		if (voiceStream)
957 		{
958 			stopVoice();
959 		}
960 #endif
961 
962 		debugLog("play now");
963 
964 		if (overrideVoiceFader != -1)
965 		{
966 			if (overrideVoiceFader < 1)
967 			{
968 				setMusicFader(overrideVoiceFader, 0.5);
969 				sfxFader = overrideVoiceFader;
970 			}
971 		}
972 		else
973 		{
974 			if (voiceFader < 1 )
975 			{
976 				setMusicFader(voiceFader, 0.5);
977 				sfxFader = voiceFader;
978 			}
979 		}
980 
981 #ifdef BBGE_BUILD_FMODEX
982 
983 
984 		// FMOD_DEFAULT uses the defaults.  These are the same as FMOD_LOOP_OFF | FMOD_2D | FMOD_HARDWARE.
985 
986 		FMOD_MODE mode=0;
987 		mode = FMOD_2D | FMOD_SOFTWARE | FMOD_CREATESTREAM;
988 
989 		result = SoundCore::system->createStream(fn.c_str(), mode, 0, &voiceStream);
990 		if (checkError())
991 		{
992 			voiceStream = 0;
993 		}
994 
995 		if (voiceStream)
996 		{
997 
998 			if (!reverbKeyword.empty())
999 			{
1000 				bool useReverb = (n.find(reverbKeyword) != std::string::npos);
1001 
1002 				if (dspReverb)
1003 				{
1004 					bool active = false;
1005 
1006 					result = dspReverb->getActive(&active);
1007 					checkError();
1008 
1009 					if (!active && useReverb)
1010 					{
1011 						result = group_vox->addDSP(dspReverb, 0);
1012 						checkError();
1013 					}
1014 					else if (active && !useReverb)
1015 					{
1016 						result = dspReverb->remove();
1017 						checkError();
1018 					}
1019 
1020 					// defaults:
1021 					//dspReverb->setParameter(FMOD_DSP_REVERB_ROOMSIZE, 0.5);
1022 					//dspReverb->setParameter(FMOD_DSP_REVERB_DAMP, 0.5);
1023 					//dspReverb->setParameter(FMOD_DSP_REVERB_WETMIX, 0.33);
1024 					//dspReverb->setParameter(FMOD_DSP_REVERB_DRYMIX, 0.66);
1025 					//dspReverb->setParameter(FMOD_DSP_REVERB_WIDTH, 1.0);
1026 					//dspReverb->setParameter(FMOD_DSP_REVERB_MODE, 0); // 0 or 1
1027 				}
1028 			}
1029 
1030 			result = SoundCore::system->playSound(FMOD_CHANNEL_FREE, voiceStream, true, &voiceChannel);
1031 			checkError();
1032 
1033 			result = voiceChannel->setChannelGroup(group_vox);
1034 			checkError();
1035 
1036 			if (vmod != -1)
1037 			{
1038 				result = voiceChannel->setVolume(vmod);
1039 				checkError();
1040 			}
1041 
1042 			result = voiceChannel->setPriority(1);
1043 			checkError();
1044 
1045 			/*
1046 			result = dspReverb->remove();
1047 			checkError();
1048 			*/
1049 
1050 			voiceChannel->setFrequency(1);
1051 			voiceChannel->setCallback(NULL);
1052 			voiceChannel->setUserData(NULL);
1053 			voiceChannel->set3DMinMaxDistance(0.0f, 0.0f);
1054 			setSoundRelative(voiceChannel, true);
1055 			setSoundPos(voiceChannel, 0, 0);
1056 
1057 			result = voiceChannel->setPaused(false);
1058 			checkError();
1059 
1060 			wasPlayingVoice = true;
1061 		}
1062 
1063 #endif
1064 
1065 		lastVoice = n;
1066 		event_playVoice.call();
1067 		core->onPlayedVoice(n);
1068 	}
1069 
1070 	return true;
1071 }
1072 
updateChannelVolume(void * ch,float v)1073 void SoundManager::updateChannelVolume(void *ch, float v)
1074 {
1075 }
1076 
getVoiceTime()1077 float SoundManager::getVoiceTime()
1078 {
1079 #ifdef BBGE_BUILD_FMODEX
1080 
1081 	if (isPlayingVoice())
1082 	{
1083 		unsigned int position;
1084 		voiceChannel->getPosition(&position, FMOD_TIMEUNIT_MS);
1085 		return float(position) * 0.001f;
1086 	}
1087 
1088 #endif
1089 
1090 	return 0;
1091 }
1092 
playSfx(const PlaySfx & play)1093 void *SoundManager::playSfx(const PlaySfx &play)
1094 {
1095 	if (!enabled) return 0;
1096 
1097 #ifdef BBGE_BUILD_FMODEX
1098 
1099 	FMOD::Channel *channel = 0;
1100 	FMOD::Sound *sound = 0;
1101 
1102 
1103 	if (play.handle)
1104 		sound = (FMOD::Sound*)play.handle;
1105 	else if (!play.name.empty())
1106 		sound = (FMOD::Sound*)getBuffer(play.name);
1107 
1108 	if (!sound) return 0;
1109 
1110 	result = SoundCore::system->playSound(FMOD_CHANNEL_FREE, sound, true, &channel);
1111 	checkError();
1112 
1113 	if (channel == NULL)  // the OpenAL bridge code might return NULL here.
1114 		return 0;
1115 
1116 	result = channel->setChannelGroup(group_sfx);
1117 	checkError();
1118 
1119 	result = channel->setPriority((int) ((1-play.priority)*255));
1120 	checkError();
1121 
1122 	if (play.fade == SFT_IN)
1123 	{
1124 		result = channel->setVolume(0);
1125 		checkError();
1126 
1127 		FadeCh fade;
1128 		fade.c = channel;
1129 		fade.v = 0;
1130 		fade.s = 1.0f/play.time;
1131 		fade.d = 1;
1132 		fade.to = play.vol;
1133 
1134 		SoundCore::addFadeCh(fade);
1135 	}
1136 	else
1137 	{
1138 		result = channel->setVolume(play.vol);
1139 		checkError();
1140 	}
1141 
1142 	float freq = play.freq;
1143 	if (freq <= 0)
1144 		freq = 1;
1145 	channel->setFrequency(freq);
1146 
1147 	channel->setCallback(NULL);
1148 	channel->setUserData(NULL);
1149 
1150 	// distance gain attenuation: stereo separation + silence at further away than maxdist
1151 	float maxdist = play.maxdist;
1152 	if (!maxdist)
1153 		maxdist = 1800;
1154 
1155 	if(maxdist > 0 && play.positional)
1156 		channel->set3DMinMaxDistance(maxdist * 0.3, maxdist); // HACK: this works reasonably well
1157 	else
1158 		channel->set3DMinMaxDistance(0, 0); // no attenuation
1159 
1160 	// position in space
1161 	setSoundRelative(channel, play.relative);
1162 	setSoundPos(channel, play.x, play.y); // must be set after everything else (See hack in OpenALChannel::set3DAttributes())
1163 
1164 
1165 
1166 	result = channel->setPaused(false);
1167 	checkError();
1168 
1169 	return channel;
1170 #endif
1171 
1172 
1173 	return 0;
1174 }
1175 
playSfx(const std::string & name,float vol)1176 void *SoundManager::playSfx(const std::string &name, float vol)
1177 {
1178 	PlaySfx play;
1179 	play.name = name;
1180 	play.vol = vol;
1181 	return playSfx(play);
1182 }
1183 
setVoiceFader(float v)1184 void SoundManager::setVoiceFader(float v)
1185 {
1186 	voiceFader = v;
1187 }
1188 
isPlayingMusic(const std::string & name)1189 bool SoundManager::isPlayingMusic(const std::string &name)
1190 {
1191 	if (isPlayingMusic())
1192 	{
1193 		std::string test = name;
1194 		stringToLower(test);
1195 
1196 		/*
1197 		std::ostringstream os;
1198 		os << "checking lastMusic: " << lastMusic << " test: " << test;
1199 		debugLog(os.str());
1200 		*/
1201 
1202 		if (test == lastMusic)
1203 			return true;
1204 	}
1205 
1206 	return false;
1207 }
1208 
playMusic(const std::string & name,SoundLoopType slt,SoundFadeType sft,float trans,SoundConditionType sct)1209 bool SoundManager::playMusic(const std::string &name, SoundLoopType slt, SoundFadeType sft, float trans, SoundConditionType sct)
1210 {
1211 	debugLog("playMusic: " + name);
1212 
1213 	if (!enabled) return false;
1214 
1215 
1216 	if (sct == SCT_ISNOTPLAYING && isPlayingMusic())
1217 	{
1218 		if (isPlayingMusic(name))
1219 		{
1220 			return false;
1221 		}
1222 	}
1223 
1224 	std::string fn = "";
1225 	if (!name.empty() && name[0] == '.')
1226 	{
1227 		fn = name;
1228 	}
1229 	else
1230 	{
1231 		if (!audioPath2.empty())
1232 		{
1233 			fn = audioPath2 + name + fileType;
1234 			if (!exists(fn))
1235 			{
1236 				fn = musicPath + name + fileType;
1237 			}
1238 		}
1239 		else
1240 		{
1241 			fn = musicPath + name + fileType;
1242 		}
1243 	}
1244 
1245 	fn = core->adjustFilenameCase(fn);
1246 
1247 	lastMusic = name;
1248 	stringToLower(lastMusic);
1249 
1250 #ifdef BBGE_BUILD_FMODEX
1251 
1252 	if (sft == SFT_CROSS)
1253 	{
1254 		fadeMusic(SFT_CROSS, trans);
1255 	}
1256 
1257 	if (musicStream)
1258 	{
1259 		musicStream->release();
1260 		musicStream = 0;
1261 	}
1262 
1263 	if (musicChannel)
1264 	{
1265 		if (sft == SFT_IN)
1266 		{
1267 			musicChannel->stop();  // we're fading in music but didn't stop the old one?
1268 		}
1269 		musicChannel = 0;
1270 	}
1271 
1272 	// FMOD_DEFAULT uses the defaults.  These are the same as FMOD_LOOP_OFF | FMOD_2D | FMOD_HARDWARE.
1273 
1274 	FMOD_MODE mode=0;
1275 
1276 	///FMOD_DEFAULT;////mode = FMOD_2D | FMOD_SOFTWARE;
1277 
1278 	mode = FMOD_2D | FMOD_SOFTWARE | FMOD_CREATESTREAM;
1279 
1280 
1281 	switch(slt)
1282 	{
1283 	case SLT_OFF:
1284 	case SLT_NONE:
1285 		mode |= FMOD_LOOP_OFF;
1286 		playingMusicOnce = true;
1287 	break;
1288 	default:
1289 		mode |= FMOD_LOOP_NORMAL;
1290 		playingMusicOnce = false;
1291 	break;
1292 	}
1293 
1294 	stopMusicOnFadeOut = false;
1295 	musVol.stop();
1296 
1297 	result = SoundCore::system->createStream(fn.c_str(), mode, 0, &musicStream);
1298 	if (checkError()) musicStream = 0;
1299 
1300 	if (musicStream)
1301 	{
1302 
1303 
1304 		result = SoundCore::system->playSound(FMOD_CHANNEL_FREE, musicStream, true, &musicChannel);
1305 		checkError();
1306 
1307 		result = musicChannel->setChannelGroup(group_mus);
1308 		checkError();
1309 
1310 		result = musicChannel->setPriority(0); // should be highest priority (according to the docs)
1311 		checkError();
1312 
1313 		if (sft == SFT_IN || sft == SFT_CROSS)
1314 		{
1315 			setMusicFader(0);
1316 			setMusicFader(1,trans);
1317 
1318 			result = musicChannel->setVolume(0);
1319 			checkError();
1320 		}
1321 		else
1322 		{
1323 			setMusicFader(1,0);
1324 
1325 			result = musicChannel->setVolume(musVol.y);
1326 			checkError();
1327 		}
1328 
1329 		musicChannel->setFrequency(1); // in case the channel was used by a pitch-shifted sound before
1330 		musicChannel->setCallback(NULL);
1331 		musicChannel->setUserData(NULL);
1332 		musicChannel->set3DMinMaxDistance(0.0f, 0.0f); // disable attenuation
1333 		setSoundRelative(musicChannel, true);
1334 		setSoundPos(musicChannel, 0, 0);
1335 
1336 		result = musicChannel->setPaused(false);		// This is where the sound really starts.
1337 		checkError();
1338 		debugLog("music play: " + fn);
1339 	}
1340 	else
1341 	{
1342 		debugLog("Failed to create music stream: " + fn);
1343 	}
1344 #endif
1345 
1346 	return true;
1347 }
1348 
1349 
stopMusic()1350 void SoundManager::stopMusic()
1351 {
1352 #ifdef BBGE_BUILD_FMODEX
1353 	if (musicChannel)
1354 	{
1355 		musicChannel->stop();
1356 		checkError();
1357 		if (musicStream)
1358 		{
1359 			musicStream->release();
1360 			checkError();
1361 		}
1362 		musicStream = 0;
1363 		musicChannel = 0;
1364 	}
1365 #endif
1366 	playingMusicOnce = false;
1367 	lastMusic = "";
1368 }
1369 
stopSfx(void * channel)1370 void SoundManager::stopSfx(void *channel)
1371 {
1372 #ifdef BBGE_BUILD_FMODEX
1373 	if (!channel) return;
1374 	FMOD::Channel *ch = (FMOD::Channel*)channel;
1375 	if (ch)
1376 	{
1377 		ch->stop();
1378 		checkError();
1379 		ch = 0;
1380 	}
1381 #endif
1382 }
1383 
fadeSfx(void * channel,SoundFadeType sft,float t)1384 void SoundManager::fadeSfx(void *channel, SoundFadeType sft, float t)
1385 {
1386 #ifdef BBGE_BUILD_FMODEX
1387 	if (!channel) return;
1388 	if (sft == SFT_OUT)
1389 	{
1390 		FMOD::Channel *ch = (FMOD::Channel*)channel;
1391 		if (ch)
1392 		{
1393 			FadeCh f;
1394 			f.s = 1.0f/t;
1395 			result = ch->getVolume(&f.v);
1396 			checkError();
1397 
1398 			f.c = ch;
1399 			SoundCore::addFadeCh(f);
1400 		}
1401 	}
1402 #endif
1403 }
1404 
stopVoice()1405 void SoundManager::stopVoice()
1406 {
1407 
1408 #ifdef BBGE_BUILD_FMODEX
1409 	if (voiceChannel)
1410 	{
1411 		bool playing = false;
1412 		result = voiceChannel->isPlaying(&playing);
1413 		checkError();
1414 
1415 		if (playing)
1416 		{
1417 			result = voiceChannel->stop();
1418 			checkError();
1419 			voiceChannel = 0;
1420 		}
1421 	}
1422 	if (voiceStream)
1423 	{
1424 		result = voiceStream->release();
1425 		checkError();
1426 		voiceStream = 0;
1427 	}
1428 	onVoiceEnded();
1429 #endif
1430 
1431 }
1432 
stopAllVoice()1433 void SoundManager::stopAllVoice()
1434 {
1435 	while (!voxQueue.empty()) voxQueue.pop();
1436 	stopVoice();
1437 }
1438 
loadCacheSoundsCallback(const std::string & filename,intptr_t param)1439 void loadCacheSoundsCallback (const std::string &filename, intptr_t param)
1440 {
1441 	SoundManager *sm;
1442 	sm = (SoundManager*)param;
1443 	if (!sm->enabled)
1444 	{
1445 		//sm->erorr();
1446 		debugLog("Disabled: Won't Load Sample ["+filename+"]");
1447 		return;
1448 	}
1449 	if (fileType==".ogg")
1450 	{
1451 		debugLog("trying to load sound " + filename);
1452 		sm->loadSoundIntoBank(filename, "", "");
1453 	}
1454 }
1455 
loadSoundCache(const std::string & path,const std::string & ftype,void progressCallback ())1456 void SoundManager::loadSoundCache(const std::string &path, const std::string &ftype, void progressCallback())
1457 {
1458 	loadProgressCallback = progressCallback;
1459 	forEachFile(path, ftype, loadCacheSoundsCallback, (intptr_t)this);
1460 	loadProgressCallback = NULL;
1461 }
1462 
loadSoundIntoBank(const std::string & filename,const std::string & path,const std::string & format,SoundLoadType slt)1463 Buffer SoundManager::loadSoundIntoBank(const std::string &filename, const std::string &path, const std::string &format, SoundLoadType slt)
1464 {
1465 	if (loadProgressCallback)
1466 		loadProgressCallback();
1467 
1468 	std::string f = filename, name;
1469 
1470 	// HACK: proper sound looping
1471 	bool loop = false;
1472 	stringToLower(f);
1473 	if (f.find("loop")!=std::string::npos)
1474 		loop = true;
1475 
1476 	// WARNING: local sounds should go here!
1477 
1478 	debugLog(filename);
1479 	if (slt == SFXLOAD_LOCAL && !audioPath2.empty())
1480 	{
1481 		f = audioPath2 + filename + format;
1482 		f = localisePathInternalModpath(f);
1483 		f = core->adjustFilenameCase(f);
1484 		if (!exists(f))
1485 		{
1486 			f = path + filename + format;
1487 			f = localisePath(f);
1488 			f = core->adjustFilenameCase(f);
1489 		}
1490 	}
1491 	else
1492 	{
1493 		f = path + filename + format;
1494 		f = localisePath(f);
1495 		f = core->adjustFilenameCase(f);
1496 	}
1497 
1498 	int loc = f.find_last_of('/');
1499 	int loc2 = f.rfind('.');
1500 	if (loc != std::string::npos && loc2 != std::string::npos)
1501 	{
1502 		name = f.substr(loc+1, loc2-(loc+1));
1503 	}
1504 	else
1505 	{
1506 		debugLog("returning 0");
1507 		return Buffer();
1508 	}
1509 
1510 	stringToLower(name);
1511 
1512 #ifdef BBGE_BUILD_FMODEX
1513 
1514 	FMOD::Sound * sound = SoundCore::soundMap[name];
1515 
1516 	if (sound)
1517 		return sound;
1518 
1519 	FMOD_MODE mode = FMOD_DEFAULT | FMOD_LOWMEM | FMOD_3D | FMOD_3D_LINEARROLLOFF;
1520 	if (loop)
1521 		mode |= FMOD_LOOP_NORMAL;
1522 
1523 	result = SoundCore::system->createSound(f.c_str(), mode, 0, &sound);
1524 	if (checkError())
1525 	{
1526 		debugLog("createSound failed");
1527 		return Buffer();
1528 	}
1529 
1530 	SoundCore::soundMap[name] = sound;
1531 
1532 
1533 	if (slt == SFXLOAD_LOCAL)
1534 	{
1535 		localSounds.push_back(name);
1536 	}
1537 
1538 	return sound;
1539 #endif
1540 
1541 #ifdef BBGE_BUILD_FMODEX
1542 
1543 #endif
1544 
1545 	return Buffer();
1546 }
1547 
loadLocalSound(const std::string & filename)1548 Buffer SoundManager::loadLocalSound(const std::string &filename)
1549 {
1550 	return loadSoundIntoBank(filename, localSoundPath, fileType, SFXLOAD_LOCAL);
1551 }
1552 
setMusicSpeed(float speed)1553 void SoundManager::setMusicSpeed(float speed)
1554 {
1555 	musicChannel->setFrequency(speed);
1556 }
1557 
setModSpeed(float speed)1558 void SoundManager::setModSpeed(float speed)
1559 {
1560 	if (modChannel)
1561 		modChannel->setFrequency(speed);
1562 }
1563 
clearLocalSounds()1564 void SoundManager::clearLocalSounds()
1565 {
1566 #ifdef BBGE_BUILD_FMODEX
1567 	for (LocalSounds::iterator i = localSounds.begin(); i != localSounds.end(); i++)
1568 	{
1569 		std::string snd = (*i);
1570 		debugLog("unloading sound [" + snd + "]");
1571 		FMOD::Sound *samp = (FMOD::Sound*)soundMap[snd];
1572 		samp->release();
1573 		soundMap[snd] = 0;
1574 	}
1575 	localSounds.clear();
1576 #endif
1577 }
1578 
checkError()1579 bool SoundManager::checkError()
1580 {
1581 #ifdef BBGE_BUILD_FMODEX
1582 	if (result != FMOD_OK)
1583 	{
1584 		std::ostringstream os;
1585 		os << "FMODEX error: " << result << ": ";
1586 
1587 		switch(result)
1588 		{
1589 		case FMOD_ERR_ALREADYLOCKED:
1590 			os << "FMOD_ERR_ALREADYLOCKED Tried to call lock a second time before unlock was called.";
1591 		break;
1592 		case FMOD_ERR_BADCOMMAND:
1593 			os << "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound).";
1594 		break;
1595 		case FMOD_ERR_CHANNEL_ALLOC:
1596 			os << "FMOD_ERR_CHANNEL_ALLOC: Error trying to allocate a channel.";
1597 		break;
1598 		case FMOD_ERR_CHANNEL_STOLEN:
1599 			os << "FMOD_ERR_CHANNEL_STOLEN: The specified channel has been reused to play another sound.";
1600 		break;
1601 		case FMOD_ERR_COM:
1602 			os << "FMOD_ERR_COM: A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly.";
1603 		break;
1604 		case FMOD_ERR_DMA:
1605 			os << "FMOD_ERR_DMA: DMA Failure. See debug output for more information.";
1606 		break;
1607 		case FMOD_ERR_DSP_CONNECTION:
1608 			os << "FMOD_ERR_DSP_CONNECTION: DSP connection error. Connection possibly caused a cyclic dependancy.";
1609 		break;
1610 		case FMOD_ERR_DSP_FORMAT:
1611 			os << "FMOD_ERR_DSP_FORMAT: DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format.";
1612 		break;
1613 		case FMOD_ERR_DSP_NOTFOUND:
1614 			os << "FMOD_ERR_DSP_NOTFOUND: DSP connection error. Couldn't find the DSP unit specified.";
1615 		break;
1616 		default:
1617 			os << "Unknown error code";
1618 		break;
1619 		}
1620 		debugLog(os.str());
1621 		return true;
1622 	}
1623 #endif
1624 	return false;
1625 }
1626 
setListenerPos(float x,float y)1627 void SoundManager::setListenerPos(float x, float y)
1628 {
1629 	FMOD_VECTOR pos;
1630 	pos.x = x;
1631 	pos.y = y;
1632 	pos.z = 0.0f;
1633 
1634 	FMOD_VECTOR forward;
1635 	forward.x = 0.0f;
1636 	forward.y = 0.0f;
1637 	forward.z = -1.0f;
1638 
1639 	FMOD_VECTOR up;
1640 	up.x = 0.0f;
1641 	up.y = 1.0f;
1642 	up.z = 0.0f;
1643 
1644 	SoundCore::system->set3DListenerAttributes(0, &pos, NULL, &forward, &up);
1645 }
1646 
setSoundPos(void * channel,float x,float y)1647 void SoundManager::setSoundPos(void *channel, float x, float y)
1648 {
1649 	if (!channel)
1650 		return;
1651 
1652 	FMOD::Channel *pChannel = (FMOD::Channel*)channel;
1653 	FMOD_VECTOR pos;
1654 	pos.x = x;
1655 	pos.y = y;
1656 	pos.z = 0.0f;
1657 
1658 	pChannel->set3DAttributes(&pos, NULL);
1659 }
1660 
setSoundRelative(void * channel,bool relative)1661 void SoundManager::setSoundRelative(void *channel, bool relative)
1662 {
1663 	if (!channel)
1664 		return;
1665 
1666 	FMOD::Channel *pChannel = (FMOD::Channel*)channel;
1667 
1668 	FMOD_MODE mode = 0;
1669 	pChannel->getMode(&mode);
1670 	FMOD_MODE newmode = mode & ~(FMOD_3D_WORLDRELATIVE | FMOD_3D_HEADRELATIVE);
1671 	if(relative)
1672 		newmode |= (FMOD_3D_HEADRELATIVE | FMOD_3D);
1673 	else
1674 		newmode |= (FMOD_3D_WORLDRELATIVE | FMOD_3D);
1675 
1676 	if (mode != newmode)
1677 		pChannel->setMode(newmode);
1678 }
1679 
s_soundHolderCallback(void * channel,FMOD_CHANNEL_CALLBACKTYPE type,void * commanddata1,void * commanddata2)1680 static FMOD_RESULT s_soundHolderCallback(void *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2)
1681 {
1682 	if (!channel)
1683 		return FMOD_ERR_INVALID_PARAM;
1684 
1685 	SoundHolder *holder = NULL;
1686 	FMOD::Channel *pChannel = (FMOD::Channel*)channel;
1687 	pChannel->getUserData((void**)&holder);
1688 
1689 	switch(type)
1690 	{
1691 		case FMOD_CHANNEL_CALLBACKTYPE_END:
1692 			holder->unlinkSound(channel);
1693 			break;
1694 		default:
1695 			return FMOD_ERR_INVALID_PARAM;
1696 	}
1697 
1698 	return FMOD_OK;
1699 }
1700 
1701 
~SoundHolder()1702 SoundHolder::~SoundHolder()
1703 {
1704 	unlinkAllSounds();
1705 }
1706 
updateSoundPosition(float x,float y)1707 void SoundHolder::updateSoundPosition(float x, float y)
1708 {
1709 	if (activeSounds.size())
1710 		for(std::set<void*>::iterator it = activeSounds.begin(); it != activeSounds.end(); ++it)
1711 			sound->setSoundPos(*it, x, y);
1712 }
1713 
stopAllSounds()1714 void SoundHolder::stopAllSounds()
1715 {
1716 	// activeSounds is modified by SoundManager::stopSfx(), which calls unkinkSound(), can't use iterator here
1717 	while(activeSounds.size())
1718 		sound->stopSfx(*activeSounds.begin());
1719 }
1720 
unlinkSound(void * channel)1721 void SoundHolder::unlinkSound(void *channel)
1722 {
1723 	FMOD::Channel *pChannel = (FMOD::Channel*)channel;
1724 	pChannel->setUserData(NULL);
1725 	pChannel->setCallback(NULL);
1726 	activeSounds.erase(channel);
1727 }
1728 
linkSound(void * channel)1729 void SoundHolder::linkSound(void *channel)
1730 {
1731 	if (!channel)
1732 		return;
1733 	FMOD::Channel *pChannel = (FMOD::Channel*)channel;
1734 	pChannel->setUserData(this);
1735 	pChannel->setCallback(s_soundHolderCallback);
1736 	activeSounds.insert(channel);
1737 }
1738 
unlinkAllSounds()1739 void SoundHolder::unlinkAllSounds()
1740 {
1741 	while(activeSounds.size())
1742 		unlinkSound(*activeSounds.begin());
1743 }
1744 
1745