1 /* Copyright (C) 2018 Wildfire Games.
2 * This file is part of 0 A.D.
3 *
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "precompiled.h"
19
20 #include "ISoundManager.h"
21 #include "SoundManager.h"
22 #include "data/SoundData.h"
23 #include "items/CBufferItem.h"
24 #include "items/CSoundItem.h"
25 #include "items/CStreamItem.h"
26
27 #include "lib/external_libraries/libsdl.h"
28 #include "ps/CLogger.h"
29 #include "ps/CStr.h"
30 #include "ps/ConfigDB.h"
31 #include "ps/Filesystem.h"
32 #include "ps/Profiler2.h"
33 #include "ps/XML/Xeromyces.h"
34
35 ISoundManager* g_SoundManager = NULL;
36
37 #define SOURCE_NUM 64
38
39 #if CONFIG2_AUDIO
40
41 class CSoundManagerWorker
42 {
43 NONCOPYABLE(CSoundManagerWorker);
44
45 public:
CSoundManagerWorker()46 CSoundManagerWorker()
47 {
48 m_Items = new ItemsList;
49 m_DeadItems = new ItemsList;
50 m_Shutdown = false;
51
52 int ret = pthread_create(&m_WorkerThread, NULL, &RunThread, this);
53 ENSURE(ret == 0);
54 }
55
~CSoundManagerWorker()56 ~CSoundManagerWorker()
57 {
58 delete m_Items;
59 CleanupItems();
60 delete m_DeadItems;
61 }
62
Shutdown()63 bool Shutdown()
64 {
65 {
66 CScopeLock lock(m_WorkerMutex);
67
68 m_Shutdown = true;
69
70 ItemsList::iterator lstr = m_Items->begin();
71 while (lstr != m_Items->end())
72 {
73 delete *lstr;
74 ++lstr;
75 }
76
77 }
78
79 pthread_join(m_WorkerThread, NULL);
80
81 return true;
82 }
83
addItem(ISoundItem * anItem)84 void addItem(ISoundItem* anItem)
85 {
86 CScopeLock lock(m_WorkerMutex);
87 m_Items->push_back(anItem);
88 }
89
CleanupItems()90 void CleanupItems()
91 {
92 CScopeLock lock(m_DeadItemsMutex);
93 AL_CHECK;
94 ItemsList::iterator deadItems = m_DeadItems->begin();
95 while (deadItems != m_DeadItems->end())
96 {
97 delete *deadItems;
98 ++deadItems;
99
100 AL_CHECK;
101 }
102 m_DeadItems->clear();
103 }
104
105 private:
RunThread(void * data)106 static void* RunThread(void* data)
107 {
108 debug_SetThreadName("CSoundManagerWorker");
109 g_Profiler2.RegisterCurrentThread("soundmanager");
110
111 static_cast<CSoundManagerWorker*>(data)->Run();
112
113 return NULL;
114 }
115
Run()116 void Run()
117 {
118 while (true)
119 {
120 // Handle shutdown requests as soon as possible
121 if (GetShutdown())
122 return;
123
124 int pauseTime = 500;
125 if (g_SoundManager->InDistress())
126 pauseTime = 50;
127
128 {
129 CScopeLock workerLock(m_WorkerMutex);
130
131 ItemsList::iterator lstr = m_Items->begin();
132 ItemsList* nextItemList = new ItemsList;
133
134 while (lstr != m_Items->end())
135 {
136 AL_CHECK;
137 if ((*lstr)->IdleTask())
138 {
139 if ((pauseTime == 500) && (*lstr)->IsFading())
140 pauseTime = 100;
141
142 nextItemList->push_back(*lstr);
143 }
144 else
145 {
146 CScopeLock deadItemsLock(m_DeadItemsMutex);
147 m_DeadItems->push_back(*lstr);
148 }
149 ++lstr;
150
151 AL_CHECK;
152 }
153
154 delete m_Items;
155 m_Items = nextItemList;
156
157 AL_CHECK;
158 }
159 SDL_Delay(pauseTime);
160 }
161 }
162
GetShutdown()163 bool GetShutdown()
164 {
165 CScopeLock lock(m_WorkerMutex);
166 return m_Shutdown;
167 }
168
169 private:
170 // Thread-related members:
171 pthread_t m_WorkerThread;
172 CMutex m_WorkerMutex;
173 CMutex m_DeadItemsMutex;
174
175 // Shared by main thread and worker thread:
176 // These variables are all protected by a mutexes
177 ItemsList* m_Items;
178 ItemsList* m_DeadItems;
179
180 bool m_Shutdown;
181
CSoundManagerWorker(ISoundManager * UNUSED (other))182 CSoundManagerWorker(ISoundManager* UNUSED(other)){};
183 };
184
CreateSoundManager()185 void ISoundManager::CreateSoundManager()
186 {
187 if (!g_SoundManager)
188 {
189 g_SoundManager = new CSoundManager();
190 g_SoundManager->StartWorker();
191 }
192 }
193
SetEnabled(bool doEnable)194 void ISoundManager::SetEnabled(bool doEnable)
195 {
196 if (g_SoundManager && !doEnable)
197 SAFE_DELETE(g_SoundManager);
198 else if (!g_SoundManager && doEnable)
199 ISoundManager::CreateSoundManager();
200 }
CloseGame()201 void ISoundManager::CloseGame()
202 {
203 if (CSoundManager* aSndMgr = (CSoundManager*)g_SoundManager)
204 aSndMgr->SetAmbientItem(NULL);
205 }
206
al_ReportError(ALenum err,const char * caller,int line)207 void CSoundManager::al_ReportError(ALenum err, const char* caller, int line)
208 {
209 LOGERROR("OpenAL error: %s; called from %s (line %d)\n", alGetString(err), caller, line);
210 }
211
al_check(const char * caller,int line)212 void CSoundManager::al_check(const char* caller, int line)
213 {
214 ALenum err = alGetError();
215 if (err != AL_NO_ERROR)
216 al_ReportError(err, caller, line);
217 }
218
ReloadChangedFiles(const VfsPath & UNUSED (path))219 Status CSoundManager::ReloadChangedFiles(const VfsPath& UNUSED(path))
220 {
221 // TODO implement sound file hotloading
222 return INFO::OK;
223 }
224
ReloadChangedFileCB(void * param,const VfsPath & path)225 /*static*/ Status CSoundManager::ReloadChangedFileCB(void* param, const VfsPath& path)
226 {
227 return static_cast<CSoundManager*>(param)->ReloadChangedFiles(path);
228 }
229
CSoundManager()230 CSoundManager::CSoundManager()
231 : m_Context(nullptr), m_Device(nullptr), m_ALSourceBuffer(nullptr),
232 m_CurrentTune(nullptr), m_CurrentEnvirons(nullptr),
233 m_Worker(nullptr), m_DistressMutex(), m_PlayListItems(nullptr), m_SoundGroups(),
234 m_Gain(.5f), m_MusicGain(.5f), m_AmbientGain(.5f), m_ActionGain(.5f), m_UIGain(.5f),
235 m_Enabled(false), m_BufferSize(98304), m_BufferCount(50),
236 m_SoundEnabled(true), m_MusicEnabled(true), m_MusicPaused(false),
237 m_AmbientPaused(false), m_ActionPaused(false),
238 m_RunningPlaylist(false), m_PlayingPlaylist(false), m_LoopingPlaylist(false),
239 m_PlaylistGap(0), m_DistressErrCount(0), m_DistressTime(0)
240 {
241 CFG_GET_VAL("sound.mastergain", m_Gain);
242 CFG_GET_VAL("sound.musicgain", m_MusicGain);
243 CFG_GET_VAL("sound.ambientgain", m_AmbientGain);
244 CFG_GET_VAL("sound.actiongain", m_ActionGain);
245 CFG_GET_VAL("sound.uigain", m_UIGain);
246
247 AlcInit();
248
249 if (m_Enabled)
250 {
251 SetMasterGain(m_Gain);
252 InitListener();
253
254 m_PlayListItems = new PlayList;
255 }
256
257 if (!CXeromyces::AddValidator(g_VFS, "sound_group", "audio/sound_group.rng"))
258 LOGERROR("CSoundManager: failed to load grammar file 'audio/sound_group.rng'");
259
260 RegisterFileReloadFunc(ReloadChangedFileCB, this);
261 }
262
~CSoundManager()263 CSoundManager::~CSoundManager()
264 {
265 UnregisterFileReloadFunc(ReloadChangedFileCB, this);
266
267 if (m_Worker)
268 {
269 AL_CHECK;
270 m_Worker->Shutdown();
271 AL_CHECK;
272 m_Worker->CleanupItems();
273 AL_CHECK;
274
275 delete m_Worker;
276 }
277 AL_CHECK;
278
279 for (const std::pair<std::wstring, CSoundGroup*>& p : m_SoundGroups)
280 delete p.second;
281 m_SoundGroups.clear();
282
283 if (m_PlayListItems)
284 delete m_PlayListItems;
285
286 if (m_ALSourceBuffer != NULL)
287 delete[] m_ALSourceBuffer;
288
289 if (m_Context)
290 alcDestroyContext(m_Context);
291
292 if (m_Device)
293 alcCloseDevice(m_Device);
294 }
295
StartWorker()296 void CSoundManager::StartWorker()
297 {
298 if (m_Enabled)
299 m_Worker = new CSoundManagerWorker();
300 }
301
AlcInit()302 Status CSoundManager::AlcInit()
303 {
304 Status ret = INFO::OK;
305
306 m_Device = alcOpenDevice(NULL);
307 if (m_Device)
308 {
309 ALCint attribs[] = {ALC_STEREO_SOURCES, 16, 0};
310 m_Context = alcCreateContext(m_Device, &attribs[0]);
311
312 if (m_Context)
313 {
314 alcMakeContextCurrent(m_Context);
315 m_ALSourceBuffer = new ALSourceHolder[SOURCE_NUM];
316 ALuint* sourceList = new ALuint[SOURCE_NUM];
317
318 alGenSources(SOURCE_NUM, sourceList);
319 ALCenum err = alcGetError(m_Device);
320
321 if (err == ALC_NO_ERROR)
322 {
323 for (int x = 0; x < SOURCE_NUM; x++)
324 {
325 m_ALSourceBuffer[x].ALSource = sourceList[x];
326 m_ALSourceBuffer[x].SourceItem = NULL;
327 }
328 m_Enabled = true;
329 }
330 else
331 {
332 LOGERROR("error in gensource = %d", err);
333 }
334 delete[] sourceList;
335 }
336 }
337
338 // check if init succeeded.
339 // some OpenAL implementations don't indicate failure here correctly;
340 // we need to check if the device and context pointers are actually valid.
341 ALCenum err = alcGetError(m_Device);
342 const char* dev_name = (const char*)alcGetString(m_Device, ALC_DEVICE_SPECIFIER);
343
344 if (err == ALC_NO_ERROR && m_Device && m_Context)
345 debug_printf("Sound: AlcInit success, using %s\n", dev_name);
346 else
347 {
348 LOGERROR("Sound: AlcInit failed, m_Device=%p m_Context=%p dev_name=%s err=%x\n", (void *)m_Device, (void *)m_Context, dev_name, err);
349
350 // FIXME Hack to get around exclusive access to the sound device
351 #if OS_UNIX
352 ret = INFO::OK;
353 #else
354 ret = ERR::FAIL;
355 #endif // !OS_UNIX
356 }
357
358 return ret;
359 }
360
InDistress()361 bool CSoundManager::InDistress()
362 {
363 CScopeLock lock(m_DistressMutex);
364
365 if (m_DistressTime == 0)
366 return false;
367 else if ((timer_Time() - m_DistressTime) > 10)
368 {
369 m_DistressTime = 0;
370 // Coming out of distress mode
371 m_DistressErrCount = 0;
372 return false;
373 }
374
375 return true;
376 }
377
SetDistressThroughShortage()378 void CSoundManager::SetDistressThroughShortage()
379 {
380 CScopeLock lock(m_DistressMutex);
381
382 // Going into distress for normal reasons
383
384 m_DistressTime = timer_Time();
385 }
386
SetDistressThroughError()387 void CSoundManager::SetDistressThroughError()
388 {
389 CScopeLock lock(m_DistressMutex);
390
391 // Going into distress due to unknown error
392
393 m_DistressTime = timer_Time();
394 m_DistressErrCount++;
395 }
396
397
398
GetALSource(ISoundItem * anItem)399 ALuint CSoundManager::GetALSource(ISoundItem* anItem)
400 {
401 for (int x = 0; x < SOURCE_NUM; x++)
402 {
403 if (!m_ALSourceBuffer[x].SourceItem)
404 {
405 m_ALSourceBuffer[x].SourceItem = anItem;
406 return m_ALSourceBuffer[x].ALSource;
407 }
408 }
409 SetDistressThroughShortage();
410 return 0;
411 }
412
ReleaseALSource(ALuint theSource)413 void CSoundManager::ReleaseALSource(ALuint theSource)
414 {
415 for (int x = 0; x < SOURCE_NUM; x++)
416 {
417 if (m_ALSourceBuffer[x].ALSource == theSource)
418 {
419 m_ALSourceBuffer[x].SourceItem = NULL;
420 return;
421 }
422 }
423 }
424
GetBufferCount()425 long CSoundManager::GetBufferCount()
426 {
427 return m_BufferCount;
428 }
GetBufferSize()429 long CSoundManager::GetBufferSize()
430 {
431 return m_BufferSize;
432 }
433
AddPlayListItem(const VfsPath & itemPath)434 void CSoundManager::AddPlayListItem(const VfsPath& itemPath)
435 {
436 if (m_Enabled)
437 m_PlayListItems->push_back(itemPath);
438 }
439
ClearPlayListItems()440 void CSoundManager::ClearPlayListItems()
441 {
442 if (m_Enabled)
443 {
444 if (m_PlayingPlaylist)
445 SetMusicItem(NULL);
446
447 m_PlayingPlaylist = false;
448 m_LoopingPlaylist = false;
449 m_RunningPlaylist = false;
450
451 m_PlayListItems->clear();
452 }
453 }
454
StartPlayList(bool doLoop)455 void CSoundManager::StartPlayList(bool doLoop)
456 {
457 if (m_Enabled && m_MusicEnabled)
458 {
459 if (m_PlayListItems->size() > 0)
460 {
461 m_PlayingPlaylist = true;
462 m_LoopingPlaylist = doLoop;
463 m_RunningPlaylist = false;
464
465 ISoundItem* aSnd = LoadItem((m_PlayListItems->at(0)));
466 if (aSnd)
467 SetMusicItem(aSnd);
468 else
469 SetMusicItem(NULL);
470 }
471 }
472 }
473
SetMasterGain(float gain)474 void CSoundManager::SetMasterGain(float gain)
475 {
476 if (m_Enabled)
477 {
478 m_Gain = gain;
479 alListenerf(AL_GAIN, m_Gain);
480 AL_CHECK;
481 }
482 }
483
SetMusicGain(float gain)484 void CSoundManager::SetMusicGain(float gain)
485 {
486 m_MusicGain = gain;
487
488 if (m_CurrentTune)
489 m_CurrentTune->SetGain(m_MusicGain);
490 }
SetAmbientGain(float gain)491 void CSoundManager::SetAmbientGain(float gain)
492 {
493 m_AmbientGain = gain;
494 }
SetActionGain(float gain)495 void CSoundManager::SetActionGain(float gain)
496 {
497 m_ActionGain = gain;
498 }
SetUIGain(float gain)499 void CSoundManager::SetUIGain(float gain)
500 {
501 m_UIGain = gain;
502 }
503
504
LoadItem(const VfsPath & itemPath)505 ISoundItem* CSoundManager::LoadItem(const VfsPath& itemPath)
506 {
507 AL_CHECK;
508
509 if (m_Enabled)
510 {
511 CSoundData* itemData = CSoundData::SoundDataFromFile(itemPath);
512
513 AL_CHECK;
514 if (itemData)
515 return CSoundManager::ItemForData(itemData);
516 }
517
518 return NULL;
519 }
520
ItemForData(CSoundData * itemData)521 ISoundItem* CSoundManager::ItemForData(CSoundData* itemData)
522 {
523 AL_CHECK;
524 ISoundItem* answer = NULL;
525
526 AL_CHECK;
527
528 if (m_Enabled && (itemData != NULL))
529 {
530 if (itemData->IsOneShot())
531 {
532 if (itemData->GetBufferCount() == 1)
533 answer = new CSoundItem(itemData);
534 else
535 answer = new CBufferItem(itemData);
536 }
537 else
538 {
539 answer = new CStreamItem(itemData);
540 }
541
542 if (answer && m_Worker)
543 m_Worker->addItem(answer);
544 }
545
546 return answer;
547 }
548
IdleTask()549 void CSoundManager::IdleTask()
550 {
551 if (m_Enabled)
552 {
553 if (m_CurrentTune)
554 {
555 m_CurrentTune->EnsurePlay();
556 if (m_PlayingPlaylist && m_RunningPlaylist)
557 {
558 if (m_CurrentTune->Finished())
559 {
560 if (m_PlaylistGap == 0)
561 {
562 m_PlaylistGap = timer_Time() + 15;
563 }
564 else if (m_PlaylistGap < timer_Time())
565 {
566 m_PlaylistGap = 0;
567 PlayList::iterator it = find(m_PlayListItems->begin(), m_PlayListItems->end(), m_CurrentTune->GetName());
568 if (it != m_PlayListItems->end())
569 {
570 ++it;
571
572 Path nextPath;
573 if (it == m_PlayListItems->end())
574 nextPath = m_PlayListItems->at(0);
575 else
576 nextPath = *it;
577
578 ISoundItem* aSnd = LoadItem(nextPath);
579 if (aSnd)
580 SetMusicItem(aSnd);
581 }
582 }
583 }
584 }
585 }
586
587 if (m_CurrentEnvirons)
588 m_CurrentEnvirons->EnsurePlay();
589
590 if (m_Worker)
591 m_Worker->CleanupItems();
592 }
593 }
594
ItemForEntity(entity_id_t UNUSED (source),CSoundData * sndData)595 ISoundItem* CSoundManager::ItemForEntity(entity_id_t UNUSED(source), CSoundData* sndData)
596 {
597 ISoundItem* currentItem = NULL;
598
599 if (m_Enabled)
600 currentItem = ItemForData(sndData);
601
602 return currentItem;
603 }
604
605
InitListener()606 void CSoundManager::InitListener()
607 {
608 ALfloat listenerPos[] = {0.0, 0.0, 0.0};
609 ALfloat listenerVel[] = {0.0, 0.0, 0.0};
610 ALfloat listenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0};
611
612 alListenerfv(AL_POSITION, listenerPos);
613 alListenerfv(AL_VELOCITY, listenerVel);
614 alListenerfv(AL_ORIENTATION, listenerOri);
615
616 alDistanceModel(AL_LINEAR_DISTANCE);
617 }
618
PlayGroupItem(ISoundItem * anItem,ALfloat groupGain)619 void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain)
620 {
621 if (anItem)
622 {
623 if (m_Enabled && (m_ActionGain > 0))
624 {
625 anItem->SetGain(m_ActionGain * groupGain);
626 anItem->PlayAndDelete();
627 AL_CHECK;
628 }
629 }
630 }
631
SetMusicEnabled(bool isEnabled)632 void CSoundManager::SetMusicEnabled(bool isEnabled)
633 {
634 if (m_CurrentTune && !isEnabled)
635 {
636 m_CurrentTune->FadeAndDelete(1.00);
637 m_CurrentTune = NULL;
638 }
639 m_MusicEnabled = isEnabled;
640 }
641
PlayAsGroup(const VfsPath & groupPath,const CVector3D & sourcePos,entity_id_t source,bool ownedSound)642 void CSoundManager::PlayAsGroup(const VfsPath& groupPath, const CVector3D& sourcePos, entity_id_t source, bool ownedSound)
643 {
644 // Make sure the sound group is loaded
645 CSoundGroup* group;
646 if (m_SoundGroups.find(groupPath.string()) == m_SoundGroups.end())
647 {
648 group = new CSoundGroup();
649 if (!group->LoadSoundGroup(L"audio/" + groupPath.string()))
650 {
651 LOGERROR("Failed to load sound group '%s'", groupPath.string8());
652 delete group;
653 group = NULL;
654 }
655 // Cache the sound group (or the null, if it failed)
656 m_SoundGroups[groupPath.string()] = group;
657 }
658 else
659 {
660 group = m_SoundGroups[groupPath.string()];
661 }
662
663 // Failed to load group -> do nothing
664 if (group && (ownedSound || !group->TestFlag(eOwnerOnly)))
665 group->PlayNext(sourcePos, source);
666 }
667
PlayAsMusic(const VfsPath & itemPath,bool looping)668 void CSoundManager::PlayAsMusic(const VfsPath& itemPath, bool looping)
669 {
670 if (m_Enabled)
671 {
672 UNUSED2(looping);
673
674 ISoundItem* aSnd = LoadItem(itemPath);
675 if (aSnd != NULL)
676 SetMusicItem(aSnd);
677 }
678 }
679
PlayAsAmbient(const VfsPath & itemPath,bool looping)680 void CSoundManager::PlayAsAmbient(const VfsPath& itemPath, bool looping)
681 {
682 if (m_Enabled)
683 {
684 UNUSED2(looping);
685 ISoundItem* aSnd = LoadItem(itemPath);
686 if (aSnd != NULL)
687 SetAmbientItem(aSnd);
688 }
689 }
690
691
PlayAsUI(const VfsPath & itemPath,bool looping)692 void CSoundManager::PlayAsUI(const VfsPath& itemPath, bool looping)
693 {
694 if (m_Enabled)
695 {
696 IdleTask();
697
698 if (ISoundItem* anItem = LoadItem(itemPath))
699 {
700 if (m_UIGain > 0)
701 {
702 anItem->SetGain(m_UIGain);
703 anItem->SetLooping(looping);
704 anItem->PlayAndDelete();
705 }
706 }
707 AL_CHECK;
708 }
709 }
710
Pause(bool pauseIt)711 void CSoundManager::Pause(bool pauseIt)
712 {
713 PauseMusic(pauseIt);
714 PauseAmbient(pauseIt);
715 PauseAction(pauseIt);
716 }
717
PauseMusic(bool pauseIt)718 void CSoundManager::PauseMusic(bool pauseIt)
719 {
720 if (m_CurrentTune && pauseIt && !m_MusicPaused)
721 {
722 m_CurrentTune->FadeAndPause(1.0);
723 }
724 else if (m_CurrentTune && m_MusicPaused && !pauseIt && m_MusicEnabled)
725 {
726 m_CurrentTune->SetGain(0);
727 m_CurrentTune->Resume();
728 m_CurrentTune->FadeToIn(m_MusicGain, 1.0);
729 }
730 m_MusicPaused = pauseIt;
731 }
732
PauseAmbient(bool pauseIt)733 void CSoundManager::PauseAmbient(bool pauseIt)
734 {
735 if (m_CurrentEnvirons && pauseIt)
736 m_CurrentEnvirons->Pause();
737 else if (m_CurrentEnvirons)
738 m_CurrentEnvirons->Resume();
739
740 m_AmbientPaused = pauseIt;
741 }
742
PauseAction(bool pauseIt)743 void CSoundManager::PauseAction(bool pauseIt)
744 {
745 m_ActionPaused = pauseIt;
746 }
747
SetMusicItem(ISoundItem * anItem)748 void CSoundManager::SetMusicItem(ISoundItem* anItem)
749 {
750 if (m_Enabled)
751 {
752 AL_CHECK;
753 if (m_CurrentTune)
754 {
755 m_CurrentTune->FadeAndDelete(2.00);
756 m_CurrentTune = NULL;
757 }
758
759 IdleTask();
760
761 if (anItem)
762 {
763 if (m_MusicEnabled)
764 {
765 m_CurrentTune = anItem;
766 m_CurrentTune->SetGain(0);
767
768 if (m_PlayingPlaylist)
769 {
770 m_RunningPlaylist = true;
771 m_CurrentTune->Play();
772 }
773 else
774 m_CurrentTune->PlayLoop();
775
776 m_MusicPaused = false;
777 m_CurrentTune->FadeToIn(m_MusicGain, 1.00);
778 }
779 else
780 {
781 anItem->StopAndDelete();
782 }
783 }
784 AL_CHECK;
785 }
786 }
787
SetAmbientItem(ISoundItem * anItem)788 void CSoundManager::SetAmbientItem(ISoundItem* anItem)
789 {
790 if (m_Enabled)
791 {
792 if (m_CurrentEnvirons)
793 {
794 m_CurrentEnvirons->FadeAndDelete(3.00);
795 m_CurrentEnvirons = NULL;
796 }
797 IdleTask();
798
799 if (anItem)
800 {
801 if (m_AmbientGain > 0)
802 {
803 m_CurrentEnvirons = anItem;
804 m_CurrentEnvirons->SetGain(0);
805 m_CurrentEnvirons->PlayLoop();
806 m_CurrentEnvirons->FadeToIn(m_AmbientGain, 2.00);
807 }
808 }
809 AL_CHECK;
810 }
811 }
812 #else // CONFIG2_AUDIO
813
CreateSoundManager()814 void ISoundManager::CreateSoundManager(){}
SetEnabled(bool UNUSED (doEnable))815 void ISoundManager::SetEnabled(bool UNUSED(doEnable)){}
CloseGame()816 void ISoundManager::CloseGame(){}
817
818 #endif // CONFIG2_AUDIO
819
820