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