diff --git a/source/soundmanager/ISoundManager.h b/source/soundmanager/ISoundManager.h index 2c033a967b..f0142aca36 100644 --- a/source/soundmanager/ISoundManager.h +++ b/source/soundmanager/ISoundManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,29 +26,30 @@ class CVector3D; class ISoundManager { - public: - virtual ~ISoundManager() {}; + virtual ~ISoundManager() {}; - static void CreateSoundManager(); - static void SetEnabled(bool doEnable); - static void CloseGame(); + static void CreateSoundManager(); + static void SetEnabled(bool doEnable); + static void CloseGame(); - virtual void IdleTask() = 0; - virtual void Pause(bool pauseIt) = 0; + virtual void StartWorker() = 0; - virtual void SetMasterGain(float gain) = 0; - virtual void SetMusicGain(float gain) = 0; - virtual void SetAmbientGain(float gain) = 0; - virtual void SetActionGain(float gain) = 0; - virtual void SetUIGain(float gain) = 0; + virtual void IdleTask() = 0; + virtual void Pause(bool pauseIt) = 0; - virtual void PlayAsUI(const VfsPath& itemPath, bool looping) = 0; - virtual void PlayAsMusic(const VfsPath& itemPath, bool looping) = 0; - virtual void PlayAsAmbient(const VfsPath& itemPath, bool looping) = 0; - virtual void PlayAsGroup(const VfsPath& groupPath, CVector3D sourcePos, entity_id_t source, bool ownedSound) = 0; + virtual void SetMasterGain(float gain) = 0; + virtual void SetMusicGain(float gain) = 0; + virtual void SetAmbientGain(float gain) = 0; + virtual void SetActionGain(float gain) = 0; + virtual void SetUIGain(float gain) = 0; - virtual bool InDistress() = 0; + virtual void PlayAsUI(const VfsPath& itemPath, bool looping) = 0; + virtual void PlayAsMusic(const VfsPath& itemPath, bool looping) = 0; + virtual void PlayAsAmbient(const VfsPath& itemPath, bool looping) = 0; + virtual void PlayAsGroup(const VfsPath& groupPath, CVector3D sourcePos, entity_id_t source, bool ownedSound) = 0; + + virtual bool InDistress() = 0; }; extern ISoundManager* g_SoundManager; diff --git a/source/soundmanager/SoundManager.cpp b/source/soundmanager/SoundManager.cpp index b0f0a233e4..daa6f3eae1 100644 --- a/source/soundmanager/SoundManager.cpp +++ b/source/soundmanager/SoundManager.cpp @@ -19,21 +19,20 @@ #include "ISoundManager.h" #include "SoundManager.h" +#include "data/SoundData.h" +#include "items/CBufferItem.h" +#include "items/CSoundItem.h" +#include "items/CStreamItem.h" -#include "ps/Filesystem.h" - -#include "soundmanager/data/SoundData.h" -#include "soundmanager/items/CSoundItem.h" -#include "soundmanager/items/CBufferItem.h" -#include "soundmanager/items/CStreamItem.h" #include "lib/external_libraries/libsdl.h" #include "ps/CLogger.h" #include "ps/CStr.h" +#include "ps/Filesystem.h" #include "ps/Profiler2.h" ISoundManager* g_SoundManager = NULL; -#define SOURCE_NUM 64 +#define SOURCE_NUM 64 #if CONFIG2_AUDIO @@ -47,7 +46,6 @@ public: m_Items = new ItemsList; m_DeadItems = new ItemsList; m_Shutdown = false; - m_Enabled = false; int ret = pthread_create(&m_WorkerThread, NULL, &RunThread, this); ENSURE(ret == 0); @@ -60,22 +58,12 @@ public: delete m_DeadItems; } - void SetEnabled(bool enabled) - { - CScopeLock lock(m_WorkerMutex); - if (enabled != m_Enabled) - { - m_Enabled = enabled; - } - } - bool Shutdown() { { CScopeLock lock(m_WorkerMutex); m_Shutdown = true; - m_Enabled = false; ItemsList::iterator lstr = m_Items->begin(); while (lstr != m_Items->end()) @@ -91,10 +79,10 @@ public: return true; } - void addItem( ISoundItem* anItem ) + void addItem(ISoundItem* anItem) { CScopeLock lock(m_WorkerMutex); - m_Items->push_back( anItem ); + m_Items->push_back(anItem); } void CleanupItems() @@ -103,7 +91,7 @@ public: AL_CHECK ItemsList::iterator deadItems = m_DeadItems->begin(); while (deadItems != m_DeadItems->end()) - { + { delete *deadItems; ++deadItems; @@ -125,20 +113,14 @@ private: void Run() { - while ( true ) + while (true) { - g_Profiler2.RecordRegionLeave("semaphore wait"); - // Handle shutdown requests as soon as possible if (GetShutdown()) return; - // If we're not enabled, ignore this wakeup - if (!GetEnabled()) - continue; - int pauseTime = 500; - if ( g_SoundManager->InDistress() ) + if (g_SoundManager->InDistress()) pauseTime = 50; { @@ -147,13 +129,12 @@ private: ItemsList::iterator lstr = m_Items->begin(); ItemsList* nextItemList = new ItemsList; - - while (lstr != m_Items->end()) { - + while (lstr != m_Items->end()) + { AL_CHECK if ((*lstr)->IdleTask()) { - if ( (pauseTime == 1000) && (*lstr)->IsFading() ) + if ((pauseTime == 500) && (*lstr)->IsFading()) pauseTime = 100; nextItemList->push_back(*lstr); @@ -173,24 +154,16 @@ private: AL_CHECK } - SDL_Delay( pauseTime ); + SDL_Delay(pauseTime); } } - bool GetEnabled() - { - CScopeLock lock(m_WorkerMutex); - return m_Enabled; - } - bool GetShutdown() { CScopeLock lock(m_WorkerMutex); return m_Shutdown; } - - private: // Thread-related members: pthread_t m_WorkerThread; @@ -202,7 +175,6 @@ private: ItemsList* m_Items; ItemsList* m_DeadItems; - bool m_Enabled; bool m_Shutdown; CSoundManagerWorker(ISoundManager* UNUSED(other)){}; @@ -210,25 +182,24 @@ private: void ISoundManager::CreateSoundManager() { - if ( !g_SoundManager ) + if (!g_SoundManager) + { g_SoundManager = new CSoundManager(); + g_SoundManager->StartWorker(); + } } void ISoundManager::SetEnabled(bool doEnable) { - if ( g_SoundManager && !doEnable ) - { + if (g_SoundManager && !doEnable) SAFE_DELETE(g_SoundManager); - } - else if ( !g_SoundManager && doEnable ) - { + else if (!g_SoundManager && doEnable) ISoundManager::CreateSoundManager(); - } } void ISoundManager::CloseGame() { - if ( CSoundManager* aSndMgr = (CSoundManager*)g_SoundManager ) - aSndMgr->SetAmbientItem( NULL ); + if (CSoundManager* aSndMgr = (CSoundManager*)g_SoundManager) + aSndMgr->SetAmbientItem(NULL); } void CSoundManager::al_ReportError(ALenum err, const char* caller, int line) @@ -257,45 +228,42 @@ Status CSoundManager::ReloadChangedFiles(const VfsPath& UNUSED(path)) CSoundManager::CSoundManager() { - m_CurrentEnvirons = 0; - m_ALSourceBuffer = NULL; - m_Device = NULL; - m_Context = NULL; - m_Worker = NULL; + m_CurrentEnvirons = NULL; + m_ALSourceBuffer = NULL; + m_Device = NULL; + m_Context = NULL; + m_Worker = NULL; m_PlayListItems = NULL; - m_CurrentTune = 0; - m_Gain = 1; - m_MusicGain = 1; - m_AmbientGain = 1; - m_ActionGain = 1; + m_CurrentTune = NULL; + m_Gain = 1; + m_MusicGain = 1; + m_AmbientGain = 1; + m_ActionGain = 1; m_UIGain = 1; - m_BufferCount = 50; - m_BufferSize = 98304; - m_SoundEnabled = true; - m_MusicEnabled = true; - m_MusicPaused = false; - m_AmbientPaused = false; - m_ActionPaused = false; + m_BufferCount = 50; + m_BufferSize = 98304; + m_SoundEnabled = true; + m_MusicEnabled = true; + m_MusicPaused = false; + m_AmbientPaused = false; + m_ActionPaused = false; - m_DistressTime = 0; + m_DistressTime = 0; m_DistressErrCount = 0; m_PlayingPlaylist = false; m_LoopingPlaylist = false; m_RunningPlaylist = false; - m_PlaylistGap = 0; + m_PlaylistGap = 0; m_Enabled = false; AlcInit(); - if ( m_Enabled ) + if (m_Enabled) { InitListener(); m_PlayListItems = new PlayList; - - m_Worker = new CSoundManagerWorker(); - m_Worker->SetEnabled( true ); } RegisterFileReloadFunc(ReloadChangedFileCB, this); @@ -305,7 +273,7 @@ CSoundManager::~CSoundManager() { UnregisterFileReloadFunc(ReloadChangedFileCB, this); - if (m_Worker ) + if (m_Worker) { AL_CHECK m_Worker->Shutdown(); @@ -321,20 +289,24 @@ CSoundManager::~CSoundManager() delete it->second; m_SoundGroups.clear(); - if ( m_PlayListItems ) + if (m_PlayListItems) delete m_PlayListItems; - if ( m_ALSourceBuffer != NULL ) + if (m_ALSourceBuffer != NULL) delete[] m_ALSourceBuffer; - if ( m_Context ) + if (m_Context) alcDestroyContext(m_Context); - if ( m_Device ) + if (m_Device) alcCloseDevice(m_Device); } - +void CSoundManager::StartWorker() +{ + if (m_Enabled) + m_Worker = new CSoundManagerWorker(); +} Status CSoundManager::AlcInit() { @@ -352,17 +324,15 @@ Status CSoundManager::AlcInit() m_ALSourceBuffer = new ALSourceHolder[SOURCE_NUM]; ALuint* sourceList = new ALuint[SOURCE_NUM]; - alGenSources( SOURCE_NUM, sourceList); + alGenSources(SOURCE_NUM, sourceList); ALCenum err = alcGetError(m_Device); - - if ( err == ALC_NO_ERROR ) + if (err == ALC_NO_ERROR) { - for ( int x=0; x 10 ) + else if ((timer_Time() - m_DistressTime) > 10) { m_DistressTime = 0; // Coming out of distress mode @@ -437,11 +405,11 @@ void CSoundManager::SetDistressThroughError() -ALuint CSoundManager::GetALSource( ISoundItem* anItem) +ALuint CSoundManager::GetALSource(ISoundItem* anItem) { - for ( int x=0; xat( 0 )) ); + + ISoundItem* aSnd = LoadItem((m_PlayListItems->at(0))); if (aSnd) SetMusicItem(aSnd); else @@ -514,10 +482,10 @@ void CSoundManager::StartPlayList( bool doLoop ) void CSoundManager::SetMasterGain(float gain) { - if ( m_Enabled ) + if (m_Enabled) { m_Gain = gain; - alListenerf( AL_GAIN, m_Gain); + alListenerf(AL_GAIN, m_Gain); AL_CHECK } } @@ -544,13 +512,13 @@ ISoundItem* CSoundManager::LoadItem(const VfsPath& itemPath) { AL_CHECK - if ( m_Enabled ) + if (m_Enabled) { CSoundData* itemData = CSoundData::SoundDataFromFile(itemPath); AL_CHECK - if ( itemData ) - return CSoundManager::ItemForData( itemData ); + if (itemData) + return CSoundManager::ItemForData(itemData); } return NULL; @@ -563,7 +531,7 @@ ISoundItem* CSoundManager::ItemForData(CSoundData* itemData) AL_CHECK - if ( m_Enabled && (itemData != NULL) ) + if (m_Enabled && (itemData != NULL)) { if (itemData->IsOneShot()) { @@ -577,46 +545,45 @@ ISoundItem* CSoundManager::ItemForData(CSoundData* itemData) answer = new CStreamItem(itemData); } - if ( answer && m_Worker ) - m_Worker->addItem( answer ); + if (answer && m_Worker) + m_Worker->addItem(answer); } - return answer; } void CSoundManager::IdleTask() { - if ( m_Enabled ) + if (m_Enabled) { if (m_CurrentTune) { m_CurrentTune->EnsurePlay(); - if ( m_PlayingPlaylist && m_RunningPlaylist ) + if (m_PlayingPlaylist && m_RunningPlaylist) { - if ( m_CurrentTune->Finished() ) + if (m_CurrentTune->Finished()) { - if ( m_PlaylistGap == 0 ) + if (m_PlaylistGap == 0) { m_PlaylistGap = timer_Time() + 15; } - else if ( m_PlaylistGap < timer_Time() ) + else if (m_PlaylistGap < timer_Time()) { m_PlaylistGap = 0; - PlayList::iterator it = find (m_PlayListItems->begin(), m_PlayListItems->end(), *(m_CurrentTune->GetName()) ); - if ( it != m_PlayListItems->end() ) + PlayList::iterator it = find(m_PlayListItems->begin(), m_PlayListItems->end(), *(m_CurrentTune->GetName())); + if (it != m_PlayListItems->end()) { ++it; Path nextPath; - if ( it == m_PlayListItems->end() ) - nextPath = m_PlayListItems->at( 0 ); + if (it == m_PlayListItems->end()) + nextPath = m_PlayListItems->at(0); else nextPath = *it; - ISoundItem* aSnd = LoadItem( nextPath ); - if ( aSnd ) - SetMusicItem( aSnd ); + ISoundItem* aSnd = LoadItem(nextPath); + if (aSnd) + SetMusicItem(aSnd); } } } @@ -628,16 +595,15 @@ void CSoundManager::IdleTask() if (m_Worker) m_Worker->CleanupItems(); - } } -ISoundItem* CSoundManager::ItemForEntity( entity_id_t UNUSED(source), CSoundData* sndData) +ISoundItem* CSoundManager::ItemForEntity(entity_id_t UNUSED(source), CSoundData* sndData) { ISoundItem* currentItem = NULL; - if ( m_Enabled ) - currentItem = ItemForData( sndData ); + if (m_Enabled) + currentItem = ItemForData(sndData); return currentItem; } @@ -645,22 +611,23 @@ ISoundItem* CSoundManager::ItemForEntity( entity_id_t UNUSED(source), CSoundData void CSoundManager::InitListener() { - ALfloat listenerPos[]={0.0,0.0,0.0}; - ALfloat listenerVel[]={0.0,0.0,0.0}; - ALfloat listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0}; + ALfloat listenerPos[] = {0.0, 0.0, 0.0}; + ALfloat listenerVel[] = {0.0, 0.0, 0.0}; + ALfloat listenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0}; - alListenerfv(AL_POSITION,listenerPos); - alListenerfv(AL_VELOCITY,listenerVel); - alListenerfv(AL_ORIENTATION,listenerOri); + alListenerfv(AL_POSITION, listenerPos); + alListenerfv(AL_VELOCITY, listenerVel); + alListenerfv(AL_ORIENTATION, listenerOri); alDistanceModel(AL_LINEAR_DISTANCE); } -void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain ) +void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain) { if (anItem) { - if (m_Enabled && (m_ActionGain > 0)) { + if (m_Enabled && (m_ActionGain > 0)) + { anItem->SetGain(m_ActionGain * groupGain); anItem->PlayAndDelete(); AL_CHECK @@ -668,12 +635,12 @@ void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain ) } } -void CSoundManager::SetMusicEnabled (bool isEnabled) +void CSoundManager::SetMusicEnabled(bool isEnabled) { if (m_CurrentTune && !isEnabled) { m_CurrentTune->FadeAndDelete(1.00); - m_CurrentTune = 0L; + m_CurrentTune = NULL; } m_MusicEnabled = isEnabled; } @@ -685,7 +652,7 @@ void CSoundManager::PlayAsGroup(const VfsPath& groupPath, CVector3D sourcePos, e if (m_SoundGroups.find(groupPath.string()) == m_SoundGroups.end()) { group = new CSoundGroup(); - if (!group->LoadSoundGroup(L"audio/" + groupPath.string() )) + if (!group->LoadSoundGroup(L"audio/" + groupPath.string())) { LOGERROR(L"Failed to load sound group '%ls'", groupPath.string().c_str()); delete group; @@ -700,11 +667,11 @@ void CSoundManager::PlayAsGroup(const VfsPath& groupPath, CVector3D sourcePos, e } // Failed to load group -> do nothing - if ( group && ( ownedSound || !group->TestFlag( eOwnerOnly ) ) ) + if (group && (ownedSound || !group->TestFlag(eOwnerOnly))) group->PlayNext(sourcePos, source); } -void CSoundManager::PlayAsMusic( const VfsPath& itemPath, bool looping ) +void CSoundManager::PlayAsMusic(const VfsPath& itemPath, bool looping) { if (m_Enabled) { @@ -716,14 +683,14 @@ void CSoundManager::PlayAsMusic( const VfsPath& itemPath, bool looping ) } } -void CSoundManager::PlayAsAmbient( const VfsPath& itemPath, bool looping ) +void CSoundManager::PlayAsAmbient(const VfsPath& itemPath, bool looping) { if (m_Enabled) { - UNUSED2( looping ); + UNUSED2(looping); ISoundItem* aSnd = LoadItem(itemPath); if (aSnd != NULL) - SetAmbientItem( aSnd ); + SetAmbientItem(aSnd); } } @@ -739,7 +706,7 @@ void CSoundManager::PlayAsUI(const VfsPath& itemPath, bool looping) if (m_UIGain > 0) { anItem->SetGain(m_UIGain); - anItem->SetLooping( looping ); + anItem->SetLooping(looping); anItem->PlayAndDelete(); } } @@ -747,42 +714,41 @@ void CSoundManager::PlayAsUI(const VfsPath& itemPath, bool looping) } } - void CSoundManager::Pause(bool pauseIt) { - PauseMusic(pauseIt); - PauseAmbient(pauseIt); - PauseAction(pauseIt); + PauseMusic(pauseIt); + PauseAmbient(pauseIt); + PauseAction(pauseIt); } -void CSoundManager::PauseMusic (bool pauseIt) +void CSoundManager::PauseMusic(bool pauseIt) { - if (m_CurrentTune && pauseIt && !m_MusicPaused ) + if (m_CurrentTune && pauseIt && !m_MusicPaused) { - m_CurrentTune->FadeAndPause( 1.0 ); + m_CurrentTune->FadeAndPause(1.0); } - else if ( m_CurrentTune && m_MusicPaused && !pauseIt && m_MusicEnabled ) + else if (m_CurrentTune && m_MusicPaused && !pauseIt && m_MusicEnabled) { m_CurrentTune->SetGain(0); m_CurrentTune->Resume(); - m_CurrentTune->FadeToIn( m_MusicGain, 1.0); + m_CurrentTune->FadeToIn(m_MusicGain, 1.0); } m_MusicPaused = pauseIt; } -void CSoundManager::PauseAmbient (bool pauseIt) +void CSoundManager::PauseAmbient(bool pauseIt) { - if (m_CurrentEnvirons && pauseIt) - m_CurrentEnvirons->Pause(); - else if ( m_CurrentEnvirons ) - m_CurrentEnvirons->Resume(); + if (m_CurrentEnvirons && pauseIt) + m_CurrentEnvirons->Pause(); + else if (m_CurrentEnvirons) + m_CurrentEnvirons->Resume(); - m_AmbientPaused = pauseIt; + m_AmbientPaused = pauseIt; } -void CSoundManager::PauseAction (bool pauseIt) +void CSoundManager::PauseAction(bool pauseIt) { - m_ActionPaused = pauseIt; + m_ActionPaused = pauseIt; } void CSoundManager::SetMusicItem(ISoundItem* anItem) @@ -793,7 +759,7 @@ void CSoundManager::SetMusicItem(ISoundItem* anItem) if (m_CurrentTune) { m_CurrentTune->FadeAndDelete(2.00); - m_CurrentTune = 0L; + m_CurrentTune = NULL; } IdleTask(); @@ -814,7 +780,7 @@ void CSoundManager::SetMusicItem(ISoundItem* anItem) m_CurrentTune->PlayLoop(); m_MusicPaused = false; - m_CurrentTune->FadeToIn( m_MusicGain, 1.00); + m_CurrentTune->FadeToIn(m_MusicGain, 1.00); } else { @@ -832,7 +798,7 @@ void CSoundManager::SetAmbientItem(ISoundItem* anItem) if (m_CurrentEnvirons) { m_CurrentEnvirons->FadeAndDelete(3.00); - m_CurrentEnvirons = 0L; + m_CurrentEnvirons = NULL; } IdleTask(); @@ -843,7 +809,7 @@ void CSoundManager::SetAmbientItem(ISoundItem* anItem) m_CurrentEnvirons = anItem; m_CurrentEnvirons->SetGain(0); m_CurrentEnvirons->PlayLoop(); - m_CurrentEnvirons->FadeToIn( m_AmbientGain, 2.00); + m_CurrentEnvirons->FadeToIn(m_AmbientGain, 2.00); } } AL_CHECK diff --git a/source/soundmanager/SoundManager.h b/source/soundmanager/SoundManager.h index 423fbe6789..4af88be74d 100644 --- a/source/soundmanager/SoundManager.h +++ b/source/soundmanager/SoundManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,17 +22,15 @@ #if CONFIG2_AUDIO +#include "ISoundManager.h" +#include "data/SoundData.h" +#include "items/ISoundItem.h" +#include "scripting/SoundGroup.h" + #include "lib/external_libraries/openal.h" - - #include "lib/file/vfs/vfs_path.h" -#include "soundmanager/ISoundManager.h" -#include "soundmanager/items/ISoundItem.h" -#include "simulation2/system/Entity.h" -#include "soundmanager/data/SoundData.h" -#include "soundmanager/items/ISoundItem.h" -#include "soundmanager/scripting/SoundGroup.h" #include "ps/Profiler2.h" +#include "simulation2/system/Entity.h" #include #include @@ -98,14 +96,16 @@ public: CSoundManager(); virtual ~CSoundManager(); + void StartWorker(); + ISoundItem* LoadItem(const VfsPath& itemPath); ISoundItem* ItemForData(CSoundData* itemData); - ISoundItem* ItemForEntity( entity_id_t source, CSoundData* sndData); + ISoundItem* ItemForEntity(entity_id_t source, CSoundData* sndData); Status ReloadChangedFiles(const VfsPath& path); void ClearPlayListItems(); - void StartPlayList( bool doLoop ); + void StartPlayList(bool doLoop); void AddPlayListItem(const VfsPath& itemPath); static void CreateSoundManager(); @@ -117,8 +117,8 @@ public: static void al_ReportError(ALenum err, const char* caller, int line); static void al_check(const char* caller, int line); - void SetMusicEnabled (bool isEnabled); - void setSoundEnabled( bool enabled ); + void SetMusicEnabled(bool isEnabled); + void setSoundEnabled(bool enabled); ALuint GetALSource(ISoundItem* anItem); void ReleaseALSource(ALuint theSource); @@ -135,8 +135,8 @@ public: long GetBufferCount(); long GetBufferSize(); - void PlayAsMusic( const VfsPath& itemPath, bool looping); - void PlayAsAmbient( const VfsPath& itemPath, bool looping); + void PlayAsMusic(const VfsPath& itemPath, bool looping); + void PlayAsAmbient(const VfsPath& itemPath, bool looping); void PlayAsUI(const VfsPath& itemPath, bool looping); void PlayAsGroup(const VfsPath& groupPath, CVector3D sourcePos, entity_id_t source, bool ownedSound); @@ -147,9 +147,9 @@ public: void SetDistressThroughError(); void Pause(bool pauseIt); - void PauseMusic (bool pauseIt); - void PauseAmbient (bool pauseIt); - void PauseAction (bool pauseIt); + void PauseMusic(bool pauseIt); + void PauseAmbient(bool pauseIt); + void PauseAction(bool pauseIt); void SetAmbientItem(ISoundItem* anItem); void SetMasterGain(float gain);