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