2013-06-06 13:13:57 +02:00
|
|
|
/* Copyright (C) 2013 Wildfire Games.
|
2012-08-15 02:10:44 +02:00
|
|
|
* This file is part of 0 A.D.
|
|
|
|
*
|
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 0 A.D. is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "precompiled.h"
|
|
|
|
|
2013-06-06 13:13:57 +02:00
|
|
|
#include "ISoundManager.h"
|
2012-08-15 02:10:44 +02:00
|
|
|
#include "SoundManager.h"
|
|
|
|
|
2013-09-10 16:17:04 +02:00
|
|
|
#include "ps/Filesystem.h"
|
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
#include "soundmanager/data/SoundData.h"
|
|
|
|
#include "soundmanager/items/CSoundItem.h"
|
|
|
|
#include "soundmanager/items/CBufferItem.h"
|
|
|
|
#include "soundmanager/items/CStreamItem.h"
|
2013-01-07 22:02:22 +01:00
|
|
|
#include "lib/external_libraries/libsdl.h"
|
2012-08-31 21:08:41 +02:00
|
|
|
#include "ps/CLogger.h"
|
2012-11-24 18:15:07 +01:00
|
|
|
#include "ps/CStr.h"
|
2012-09-27 04:42:03 +02:00
|
|
|
#include "ps/Profiler2.h"
|
2012-08-31 21:08:41 +02:00
|
|
|
|
2013-06-06 13:13:57 +02:00
|
|
|
ISoundManager* g_SoundManager = NULL;
|
2012-08-15 02:10:44 +02:00
|
|
|
|
2013-03-01 15:22:28 +01:00
|
|
|
#define SOURCE_NUM 64
|
|
|
|
|
|
|
|
#if CONFIG2_AUDIO
|
2012-08-15 02:10:44 +02:00
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
class CSoundManagerWorker
|
|
|
|
{
|
2013-05-22 23:40:56 +02:00
|
|
|
NONCOPYABLE(CSoundManagerWorker);
|
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
public:
|
|
|
|
CSoundManagerWorker()
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
~CSoundManagerWorker()
|
|
|
|
{
|
2013-03-14 03:59:31 +01:00
|
|
|
delete m_Items;
|
|
|
|
CleanupItems();
|
|
|
|
delete m_DeadItems;
|
2012-09-27 04:42:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SetEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
CScopeLock lock(m_WorkerMutex);
|
|
|
|
if (enabled != m_Enabled)
|
|
|
|
{
|
|
|
|
m_Enabled = enabled;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Shutdown()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
CScopeLock lock(m_WorkerMutex);
|
2013-04-18 05:24:20 +02:00
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
m_Shutdown = true;
|
|
|
|
m_Enabled = false;
|
|
|
|
|
|
|
|
ItemsList::iterator lstr = m_Items->begin();
|
|
|
|
while (lstr != m_Items->end())
|
|
|
|
{
|
|
|
|
delete *lstr;
|
2013-04-12 05:10:54 +02:00
|
|
|
++lstr;
|
2012-09-27 04:42:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_join(m_WorkerThread, NULL);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2013-04-18 05:24:20 +02:00
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
void addItem( ISoundItem* anItem )
|
|
|
|
{
|
|
|
|
CScopeLock lock(m_WorkerMutex);
|
|
|
|
m_Items->push_back( anItem );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CleanupItems()
|
|
|
|
{
|
2013-01-07 22:02:22 +01:00
|
|
|
CScopeLock lock(m_DeadItemsMutex);
|
2012-09-27 04:42:03 +02:00
|
|
|
AL_CHECK
|
|
|
|
ItemsList::iterator deadItems = m_DeadItems->begin();
|
|
|
|
while (deadItems != m_DeadItems->end())
|
|
|
|
{
|
|
|
|
delete *deadItems;
|
2013-04-12 05:10:54 +02:00
|
|
|
++deadItems;
|
2012-09-27 04:42:03 +02:00
|
|
|
|
|
|
|
AL_CHECK
|
|
|
|
}
|
|
|
|
m_DeadItems->clear();
|
|
|
|
}
|
2013-01-07 22:02:22 +01:00
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
private:
|
|
|
|
static void* RunThread(void* data)
|
|
|
|
{
|
|
|
|
debug_SetThreadName("CSoundManagerWorker");
|
|
|
|
g_Profiler2.RegisterCurrentThread("soundmanager");
|
|
|
|
|
|
|
|
static_cast<CSoundManagerWorker*>(data)->Run();
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Run()
|
|
|
|
{
|
|
|
|
while ( true )
|
|
|
|
{
|
2013-03-01 15:22:28 +01:00
|
|
|
g_Profiler2.RecordRegionLeave("semaphore wait");
|
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
// Handle shutdown requests as soon as possible
|
|
|
|
if (GetShutdown())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If we're not enabled, ignore this wakeup
|
|
|
|
if (!GetEnabled())
|
|
|
|
continue;
|
|
|
|
|
2013-04-10 13:51:42 +02:00
|
|
|
int pauseTime = 500;
|
2013-03-01 15:22:28 +01:00
|
|
|
if ( g_SoundManager->InDistress() )
|
|
|
|
pauseTime = 50;
|
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
{
|
|
|
|
CScopeLock lock(m_WorkerMutex);
|
|
|
|
|
|
|
|
ItemsList::iterator lstr = m_Items->begin();
|
|
|
|
ItemsList* nextItemList = new ItemsList;
|
|
|
|
|
|
|
|
|
|
|
|
while (lstr != m_Items->end()) {
|
|
|
|
|
2013-03-01 15:22:28 +01:00
|
|
|
AL_CHECK
|
2012-09-27 04:42:03 +02:00
|
|
|
if ((*lstr)->IdleTask())
|
2013-01-07 22:02:22 +01:00
|
|
|
{
|
2013-03-01 15:22:28 +01:00
|
|
|
if ( (pauseTime == 1000) && (*lstr)->IsFading() )
|
2013-01-07 22:02:22 +01:00
|
|
|
pauseTime = 100;
|
2013-03-01 15:22:28 +01:00
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
nextItemList->push_back(*lstr);
|
2013-01-07 22:02:22 +01:00
|
|
|
}
|
2012-09-27 04:42:03 +02:00
|
|
|
else
|
2013-01-07 22:02:22 +01:00
|
|
|
{
|
|
|
|
CScopeLock lock(m_DeadItemsMutex);
|
2012-09-27 04:42:03 +02:00
|
|
|
m_DeadItems->push_back(*lstr);
|
2013-01-07 22:02:22 +01:00
|
|
|
}
|
2013-04-12 05:10:54 +02:00
|
|
|
++lstr;
|
2012-09-27 04:42:03 +02:00
|
|
|
|
|
|
|
AL_CHECK
|
|
|
|
}
|
|
|
|
|
|
|
|
delete m_Items;
|
|
|
|
m_Items = nextItemList;
|
|
|
|
|
|
|
|
AL_CHECK
|
|
|
|
}
|
2013-01-07 22:02:22 +01:00
|
|
|
SDL_Delay( pauseTime );
|
2012-09-27 04:42:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
CMutex m_WorkerMutex;
|
2013-01-07 22:02:22 +01:00
|
|
|
CMutex m_DeadItemsMutex;
|
2012-09-27 04:42:03 +02:00
|
|
|
|
|
|
|
// Shared by main thread and worker thread:
|
2013-04-18 05:24:20 +02:00
|
|
|
// These variables are all protected by a mutexes
|
2012-09-27 04:42:03 +02:00
|
|
|
ItemsList* m_Items;
|
|
|
|
ItemsList* m_DeadItems;
|
|
|
|
|
|
|
|
bool m_Enabled;
|
|
|
|
bool m_Shutdown;
|
2013-04-12 05:10:54 +02:00
|
|
|
|
2013-06-06 13:13:57 +02:00
|
|
|
CSoundManagerWorker(ISoundManager* UNUSED(other)){};
|
2012-09-27 04:42:03 +02:00
|
|
|
};
|
|
|
|
|
2013-06-06 13:13:57 +02:00
|
|
|
void ISoundManager::CreateSoundManager()
|
2012-08-31 21:08:41 +02:00
|
|
|
{
|
2013-09-10 16:17:04 +02:00
|
|
|
if ( !g_SoundManager )
|
|
|
|
g_SoundManager = new CSoundManager();
|
2012-08-31 21:08:41 +02:00
|
|
|
}
|
|
|
|
|
2013-06-06 13:13:57 +02:00
|
|
|
void ISoundManager::SetEnabled(bool doEnable)
|
2012-08-31 21:08:41 +02:00
|
|
|
{
|
|
|
|
if ( g_SoundManager && !doEnable )
|
|
|
|
{
|
2012-12-12 23:43:57 +01:00
|
|
|
SAFE_DELETE(g_SoundManager);
|
2012-08-31 21:08:41 +02:00
|
|
|
}
|
2013-09-10 16:17:04 +02:00
|
|
|
else if ( !g_SoundManager && doEnable )
|
2012-08-31 21:08:41 +02:00
|
|
|
{
|
2013-06-06 13:13:57 +02:00
|
|
|
ISoundManager::CreateSoundManager();
|
2012-08-31 21:08:41 +02:00
|
|
|
}
|
|
|
|
}
|
2013-08-29 15:20:55 +02:00
|
|
|
void ISoundManager::CloseGame()
|
|
|
|
{
|
|
|
|
if ( CSoundManager* aSndMgr = (CSoundManager*)g_SoundManager )
|
|
|
|
aSndMgr->SetAmbientItem( NULL );
|
|
|
|
}
|
2012-08-31 21:08:41 +02:00
|
|
|
|
|
|
|
void CSoundManager::al_ReportError(ALenum err, const char* caller, int line)
|
|
|
|
{
|
|
|
|
LOGERROR(L"OpenAL error: %hs; called from %hs (line %d)\n", alGetString(err), caller, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::al_check(const char* caller, int line)
|
|
|
|
{
|
|
|
|
ALenum err = alGetError();
|
|
|
|
if (err != AL_NO_ERROR)
|
|
|
|
al_ReportError(err, caller, line);
|
|
|
|
}
|
|
|
|
|
2013-09-10 16:17:04 +02:00
|
|
|
Status CSoundManager::ReloadChangedFiles(const VfsPath& UNUSED(path))
|
|
|
|
{
|
|
|
|
// LOGERROR(L"GUI file '%ls' changed - reloading page", path.string().c_str());
|
|
|
|
|
|
|
|
return INFO::OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ Status CSoundManager::ReloadChangedFileCB(void* param, const VfsPath& path)
|
|
|
|
{
|
|
|
|
return static_cast<CSoundManager*>(param)->ReloadChangedFiles(path);
|
|
|
|
}
|
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
CSoundManager::CSoundManager()
|
|
|
|
{
|
2013-03-01 15:22:28 +01:00
|
|
|
m_CurrentEnvirons = 0;
|
|
|
|
m_ALSourceBuffer = NULL;
|
2013-04-18 05:24:20 +02:00
|
|
|
m_Device = NULL;
|
|
|
|
m_Context = NULL;
|
|
|
|
m_Worker = NULL;
|
2013-04-24 14:03:42 +02:00
|
|
|
m_PlayListItems = NULL;
|
2013-03-01 15:22:28 +01:00
|
|
|
m_CurrentTune = 0;
|
2012-08-15 02:10:44 +02:00
|
|
|
m_Gain = 1;
|
|
|
|
m_MusicGain = 1;
|
|
|
|
m_AmbientGain = 1;
|
|
|
|
m_ActionGain = 1;
|
2013-06-10 15:58:43 +02:00
|
|
|
m_UIGain = 1;
|
2012-08-15 02:10:44 +02:00
|
|
|
m_BufferCount = 50;
|
2013-06-10 15:58:43 +02:00
|
|
|
m_BufferSize = 98304;
|
2013-04-12 05:10:54 +02:00
|
|
|
m_SoundEnabled = true;
|
2012-08-15 02:10:44 +02:00
|
|
|
m_MusicEnabled = true;
|
2013-04-07 06:13:15 +02:00
|
|
|
m_MusicPaused = false;
|
|
|
|
m_AmbientPaused = false;
|
|
|
|
m_ActionPaused = false;
|
|
|
|
|
2013-03-01 15:22:28 +01:00
|
|
|
m_DistressTime = 0;
|
|
|
|
m_DistressErrCount = 0;
|
|
|
|
|
2013-04-24 14:03:42 +02:00
|
|
|
m_PlayingPlaylist = false;
|
|
|
|
m_LoopingPlaylist = false;
|
|
|
|
m_RunningPlaylist = false;
|
|
|
|
m_PlaylistGap = 0;
|
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
m_Enabled = false;
|
|
|
|
AlcInit();
|
2012-09-27 04:42:03 +02:00
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
if ( m_Enabled )
|
|
|
|
{
|
|
|
|
InitListener();
|
|
|
|
|
2013-04-24 14:03:42 +02:00
|
|
|
m_PlayListItems = new PlayList;
|
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
m_Worker = new CSoundManagerWorker();
|
|
|
|
m_Worker->SetEnabled( true );
|
|
|
|
}
|
2013-09-10 16:17:04 +02:00
|
|
|
|
|
|
|
RegisterFileReloadFunc(ReloadChangedFileCB, this);
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CSoundManager::~CSoundManager()
|
2013-04-18 05:24:20 +02:00
|
|
|
{
|
2013-09-10 16:17:04 +02:00
|
|
|
UnregisterFileReloadFunc(ReloadChangedFileCB, this);
|
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
if (m_Worker )
|
|
|
|
{
|
|
|
|
AL_CHECK
|
|
|
|
m_Worker->Shutdown();
|
|
|
|
AL_CHECK
|
|
|
|
m_Worker->CleanupItems();
|
|
|
|
AL_CHECK
|
|
|
|
|
2012-12-12 23:43:57 +01:00
|
|
|
delete m_Worker;
|
2013-04-18 05:24:20 +02:00
|
|
|
}
|
|
|
|
AL_CHECK
|
2012-08-15 02:10:44 +02:00
|
|
|
|
2013-06-13 14:12:44 +02:00
|
|
|
for (std::map<std::wstring, CSoundGroup*>::iterator it = m_SoundGroups.begin(); it != m_SoundGroups.end(); ++it)
|
|
|
|
delete it->second;
|
|
|
|
m_SoundGroups.clear();
|
|
|
|
|
2013-04-24 14:03:42 +02:00
|
|
|
if ( m_PlayListItems )
|
|
|
|
delete m_PlayListItems;
|
|
|
|
|
2013-03-14 03:59:31 +01:00
|
|
|
if ( m_ALSourceBuffer != NULL )
|
|
|
|
delete[] m_ALSourceBuffer;
|
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
if ( m_Context )
|
|
|
|
alcDestroyContext(m_Context);
|
|
|
|
|
|
|
|
if ( m_Device )
|
|
|
|
alcCloseDevice(m_Device);
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-01 15:22:28 +01:00
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
Status CSoundManager::AlcInit()
|
|
|
|
{
|
|
|
|
Status ret = INFO::OK;
|
|
|
|
|
|
|
|
m_Device = alcOpenDevice(NULL);
|
2013-04-18 05:24:20 +02:00
|
|
|
if (m_Device)
|
2012-08-15 02:10:44 +02:00
|
|
|
{
|
2012-11-18 23:39:20 +01:00
|
|
|
ALCint attribs[] = {ALC_STEREO_SOURCES, 16, 0};
|
|
|
|
m_Context = alcCreateContext(m_Device, &attribs[0]);
|
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
if (m_Context)
|
2013-03-01 15:22:28 +01:00
|
|
|
{
|
2012-08-15 02:10:44 +02:00
|
|
|
alcMakeContextCurrent(m_Context);
|
2013-03-01 15:22:28 +01:00
|
|
|
m_ALSourceBuffer = new ALSourceHolder[SOURCE_NUM];
|
|
|
|
ALuint* sourceList = new ALuint[SOURCE_NUM];
|
|
|
|
|
|
|
|
alGenSources( SOURCE_NUM, sourceList);
|
|
|
|
ALCenum err = alcGetError(m_Device);
|
|
|
|
|
|
|
|
|
|
|
|
if ( err == ALC_NO_ERROR )
|
|
|
|
{
|
|
|
|
for ( int x=0; x<SOURCE_NUM;x++)
|
|
|
|
{
|
|
|
|
m_ALSourceBuffer[x].ALSource = sourceList[x];
|
|
|
|
m_ALSourceBuffer[x].SourceItem = NULL;
|
|
|
|
|
|
|
|
}
|
2013-04-18 05:24:20 +02:00
|
|
|
m_Enabled = true;
|
2013-03-01 15:22:28 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOGERROR(L"error in gensource = %d", err);
|
|
|
|
}
|
|
|
|
delete[] sourceList;
|
|
|
|
}
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// check if init succeeded.
|
|
|
|
// some OpenAL implementations don't indicate failure here correctly;
|
|
|
|
// we need to check if the device and context pointers are actually valid.
|
|
|
|
ALCenum err = alcGetError(m_Device);
|
2012-08-16 20:52:39 +02:00
|
|
|
const char* dev_name = (const char*)alcGetString(m_Device, ALC_DEVICE_SPECIFIER);
|
|
|
|
|
2012-08-16 19:01:15 +02:00
|
|
|
if(err == ALC_NO_ERROR && m_Device && m_Context)
|
|
|
|
debug_printf(L"Sound: AlcInit success, using %hs\n", dev_name);
|
|
|
|
else
|
2012-08-15 02:10:44 +02:00
|
|
|
{
|
2012-08-31 21:08:41 +02:00
|
|
|
LOGERROR(L"Sound: AlcInit failed, m_Device=%p m_Context=%p dev_name=%hs err=%d\n", m_Device, m_Context, dev_name, err);
|
2013-03-01 15:22:28 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2012-08-16 19:01:15 +02:00
|
|
|
// FIXME Hack to get around exclusive access to the sound device
|
2012-08-15 02:10:44 +02:00
|
|
|
#if OS_UNIX
|
|
|
|
ret = INFO::OK;
|
|
|
|
#else
|
|
|
|
ret = ERR::FAIL;
|
2012-08-31 21:08:41 +02:00
|
|
|
#endif // !OS_UNIX
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2013-03-01 15:22:28 +01:00
|
|
|
|
|
|
|
bool CSoundManager::InDistress()
|
|
|
|
{
|
|
|
|
CScopeLock lock(m_DistressMutex);
|
|
|
|
|
|
|
|
if ( m_DistressTime == 0 )
|
|
|
|
return false;
|
|
|
|
else if ( (timer_Time() - m_DistressTime) > 10 )
|
|
|
|
{
|
|
|
|
m_DistressTime = 0;
|
2013-03-13 04:55:36 +01:00
|
|
|
// Coming out of distress mode
|
2013-03-01 15:22:28 +01:00
|
|
|
m_DistressErrCount = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::SetDistressThroughShortage()
|
|
|
|
{
|
|
|
|
CScopeLock lock(m_DistressMutex);
|
|
|
|
|
2013-03-13 04:55:36 +01:00
|
|
|
// Going into distress for normal reasons
|
2013-03-01 15:22:28 +01:00
|
|
|
|
|
|
|
m_DistressTime = timer_Time();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::SetDistressThroughError()
|
|
|
|
{
|
|
|
|
CScopeLock lock(m_DistressMutex);
|
|
|
|
|
2013-03-13 04:55:36 +01:00
|
|
|
// Going into distress due to unknown error
|
2013-03-01 15:22:28 +01:00
|
|
|
|
|
|
|
m_DistressTime = timer_Time();
|
|
|
|
m_DistressErrCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ALuint CSoundManager::GetALSource( ISoundItem* anItem)
|
|
|
|
{
|
|
|
|
for ( int x=0; x<SOURCE_NUM;x++)
|
|
|
|
{
|
|
|
|
if ( ! m_ALSourceBuffer[x].SourceItem )
|
|
|
|
{
|
|
|
|
m_ALSourceBuffer[x].SourceItem = anItem;
|
|
|
|
return m_ALSourceBuffer[x].ALSource;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetDistressThroughShortage();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::ReleaseALSource(ALuint theSource)
|
|
|
|
{
|
|
|
|
for ( int x=0; x<SOURCE_NUM;x++)
|
|
|
|
{
|
|
|
|
if ( m_ALSourceBuffer[x].ALSource == theSource )
|
|
|
|
{
|
|
|
|
m_ALSourceBuffer[x].SourceItem = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
long CSoundManager::GetBufferCount()
|
|
|
|
{
|
|
|
|
return m_BufferCount;
|
|
|
|
}
|
|
|
|
long CSoundManager::GetBufferSize()
|
|
|
|
{
|
|
|
|
return m_BufferSize;
|
|
|
|
}
|
|
|
|
|
2013-09-30 03:09:16 +02:00
|
|
|
void CSoundManager::AddPlayListItem(const VfsPath& itemPath)
|
2013-04-24 14:03:42 +02:00
|
|
|
{
|
2013-09-30 03:09:16 +02:00
|
|
|
m_PlayListItems->push_back(itemPath);
|
2013-04-24 14:03:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::ClearPlayListItems()
|
|
|
|
{
|
|
|
|
if ( m_PlayingPlaylist )
|
|
|
|
SetMusicItem( NULL );
|
|
|
|
|
|
|
|
m_PlayingPlaylist = false;
|
|
|
|
m_LoopingPlaylist = false;
|
|
|
|
m_RunningPlaylist = false;
|
|
|
|
|
|
|
|
m_PlayListItems->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::StartPlayList( bool doLoop )
|
|
|
|
{
|
2013-06-06 13:13:57 +02:00
|
|
|
if ( m_MusicEnabled )
|
|
|
|
{
|
|
|
|
if ( m_PlayListItems->size() > 0 )
|
|
|
|
{
|
|
|
|
m_PlayingPlaylist = true;
|
|
|
|
m_LoopingPlaylist = doLoop;
|
|
|
|
m_RunningPlaylist = false;
|
|
|
|
|
|
|
|
ISoundItem* aSnd = LoadItem( (m_PlayListItems->at( 0 )) );
|
|
|
|
if ( aSnd )
|
|
|
|
SetMusicItem( aSnd );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetMusicItem( NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-24 14:03:42 +02:00
|
|
|
}
|
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
void CSoundManager::SetMasterGain(float gain)
|
|
|
|
{
|
2013-04-18 05:24:20 +02:00
|
|
|
if ( m_Enabled )
|
|
|
|
{
|
|
|
|
m_Gain = gain;
|
|
|
|
alListenerf( AL_GAIN, m_Gain);
|
|
|
|
AL_CHECK
|
|
|
|
}
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
2012-09-27 04:42:03 +02:00
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
void CSoundManager::SetMusicGain(float gain)
|
|
|
|
{
|
|
|
|
m_MusicGain = gain;
|
|
|
|
}
|
|
|
|
void CSoundManager::SetAmbientGain(float gain)
|
|
|
|
{
|
|
|
|
m_AmbientGain = gain;
|
|
|
|
}
|
|
|
|
void CSoundManager::SetActionGain(float gain)
|
|
|
|
{
|
|
|
|
m_ActionGain = gain;
|
|
|
|
}
|
2013-06-10 15:58:43 +02:00
|
|
|
void CSoundManager::SetUIGain(float gain)
|
|
|
|
{
|
|
|
|
m_UIGain = gain;
|
|
|
|
}
|
2012-08-15 02:10:44 +02:00
|
|
|
|
|
|
|
|
2012-08-16 03:41:45 +02:00
|
|
|
ISoundItem* CSoundManager::LoadItem(const VfsPath& itemPath)
|
2012-08-15 02:10:44 +02:00
|
|
|
{
|
2012-08-31 21:08:41 +02:00
|
|
|
AL_CHECK
|
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
if ( m_Enabled )
|
|
|
|
{
|
|
|
|
CSoundData* itemData = CSoundData::SoundDataFromFile(itemPath);
|
2013-03-01 15:22:28 +01:00
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
AL_CHECK
|
|
|
|
if ( itemData )
|
|
|
|
return CSoundManager::ItemForData( itemData );
|
|
|
|
}
|
2013-03-01 15:22:28 +01:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ISoundItem* CSoundManager::ItemForData(CSoundData* itemData)
|
|
|
|
{
|
|
|
|
AL_CHECK
|
2012-08-15 02:10:44 +02:00
|
|
|
ISoundItem* answer = NULL;
|
2012-08-31 21:08:41 +02:00
|
|
|
|
|
|
|
AL_CHECK
|
2012-08-15 02:10:44 +02:00
|
|
|
|
2013-04-18 05:24:20 +02:00
|
|
|
if ( m_Enabled && (itemData != NULL) )
|
2012-08-15 02:10:44 +02:00
|
|
|
{
|
|
|
|
if (itemData->IsOneShot())
|
|
|
|
{
|
|
|
|
if (itemData->GetBufferCount() == 1)
|
|
|
|
answer = new CSoundItem(itemData);
|
|
|
|
else
|
|
|
|
answer = new CBufferItem(itemData);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
answer = new CStreamItem(itemData);
|
|
|
|
}
|
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
if ( answer && m_Worker )
|
|
|
|
m_Worker->addItem( answer );
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return answer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::IdleTask()
|
|
|
|
{
|
2013-04-18 05:24:20 +02:00
|
|
|
if ( m_Enabled )
|
|
|
|
{
|
|
|
|
if (m_CurrentTune)
|
2013-04-24 14:03:42 +02:00
|
|
|
{
|
2013-04-18 05:24:20 +02:00
|
|
|
m_CurrentTune->EnsurePlay();
|
2013-04-24 14:03:42 +02:00
|
|
|
if ( m_PlayingPlaylist && m_RunningPlaylist )
|
|
|
|
{
|
|
|
|
if ( m_CurrentTune->Finished() )
|
|
|
|
{
|
|
|
|
if ( m_PlaylistGap == 0 )
|
|
|
|
{
|
|
|
|
m_PlaylistGap = timer_Time() + 15;
|
|
|
|
}
|
|
|
|
else if ( m_PlaylistGap < timer_Time() )
|
|
|
|
{
|
|
|
|
m_PlaylistGap = 0;
|
|
|
|
PlayList::iterator it = find (m_PlayListItems->begin(), m_PlayListItems->end(), *(m_CurrentTune->GetName()) );
|
2013-08-29 15:20:55 +02:00
|
|
|
if ( it != m_PlayListItems->end() )
|
|
|
|
{
|
|
|
|
++it;
|
|
|
|
|
|
|
|
Path nextPath;
|
|
|
|
if ( it == m_PlayListItems->end() )
|
|
|
|
nextPath = m_PlayListItems->at( 0 );
|
|
|
|
else
|
|
|
|
nextPath = *it;
|
|
|
|
|
|
|
|
ISoundItem* aSnd = LoadItem( nextPath );
|
|
|
|
if ( aSnd )
|
|
|
|
SetMusicItem( aSnd );
|
|
|
|
}
|
2013-04-24 14:03:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-18 05:24:20 +02:00
|
|
|
|
|
|
|
if (m_CurrentEnvirons)
|
|
|
|
m_CurrentEnvirons->EnsurePlay();
|
|
|
|
|
|
|
|
if (m_Worker)
|
|
|
|
m_Worker->CleanupItems();
|
|
|
|
|
|
|
|
}
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
2013-04-12 05:10:54 +02:00
|
|
|
ISoundItem* CSoundManager::ItemForEntity( entity_id_t UNUSED(source), CSoundData* sndData)
|
2012-08-15 02:10:44 +02:00
|
|
|
{
|
2013-04-18 05:24:20 +02:00
|
|
|
ISoundItem* currentItem = NULL;
|
|
|
|
|
|
|
|
if ( m_Enabled )
|
|
|
|
currentItem = ItemForData( sndData );
|
2013-03-01 15:22:28 +01:00
|
|
|
|
|
|
|
return currentItem;
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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};
|
|
|
|
|
|
|
|
alListenerfv(AL_POSITION,listenerPos);
|
|
|
|
alListenerfv(AL_VELOCITY,listenerVel);
|
|
|
|
alListenerfv(AL_ORIENTATION,listenerOri);
|
|
|
|
|
2012-09-27 04:42:03 +02:00
|
|
|
alDistanceModel(AL_LINEAR_DISTANCE);
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
2013-03-01 15:22:28 +01:00
|
|
|
void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain )
|
2012-08-15 02:10:44 +02:00
|
|
|
{
|
|
|
|
if (anItem)
|
|
|
|
{
|
|
|
|
if (m_Enabled && (m_ActionGain > 0)) {
|
2012-09-27 04:42:03 +02:00
|
|
|
anItem->SetGain(m_ActionGain * groupGain);
|
2013-03-01 15:22:28 +01:00
|
|
|
anItem->PlayAndDelete();
|
2012-08-31 21:08:41 +02:00
|
|
|
AL_CHECK
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::SetMusicEnabled (bool isEnabled)
|
|
|
|
{
|
|
|
|
if (m_CurrentTune && !isEnabled)
|
|
|
|
{
|
|
|
|
m_CurrentTune->FadeAndDelete(1.00);
|
|
|
|
m_CurrentTune = 0L;
|
|
|
|
}
|
|
|
|
m_MusicEnabled = isEnabled;
|
|
|
|
}
|
|
|
|
|
2013-06-17 04:30:40 +02:00
|
|
|
void CSoundManager::PlayAsGroup(const VfsPath& groupPath, CVector3D sourcePos, entity_id_t source, bool ownedSound)
|
2013-06-13 14:12:44 +02:00
|
|
|
{
|
|
|
|
// Make sure the sound group is loaded
|
|
|
|
CSoundGroup* group;
|
|
|
|
if (m_SoundGroups.find(groupPath.string()) == m_SoundGroups.end())
|
|
|
|
{
|
|
|
|
group = new CSoundGroup();
|
|
|
|
if (!group->LoadSoundGroup(L"audio/" + groupPath.string() ))
|
|
|
|
{
|
|
|
|
LOGERROR(L"Failed to load sound group '%ls'", groupPath.string().c_str());
|
|
|
|
delete group;
|
|
|
|
group = NULL;
|
|
|
|
}
|
|
|
|
// Cache the sound group (or the null, if it failed)
|
|
|
|
m_SoundGroups[groupPath.string()] = group;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
group = m_SoundGroups[groupPath.string()];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Failed to load group -> do nothing
|
2013-06-17 04:30:40 +02:00
|
|
|
if ( group && ( ownedSound || !group->TestFlag( eOwnerOnly ) ) )
|
2013-06-13 14:12:44 +02:00
|
|
|
group->PlayNext(sourcePos, source);
|
|
|
|
}
|
|
|
|
|
2013-06-10 15:58:43 +02:00
|
|
|
void CSoundManager::PlayAsMusic( const VfsPath& itemPath, bool looping )
|
|
|
|
{
|
|
|
|
UNUSED2( looping );
|
|
|
|
|
|
|
|
ISoundItem* aSnd = LoadItem(itemPath);
|
|
|
|
if (aSnd != NULL)
|
|
|
|
SetMusicItem( aSnd );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::PlayAsAmbient( const VfsPath& itemPath, bool looping )
|
|
|
|
{
|
|
|
|
UNUSED2( looping );
|
|
|
|
ISoundItem* aSnd = LoadItem(itemPath);
|
|
|
|
if (aSnd != NULL)
|
|
|
|
SetAmbientItem( aSnd );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CSoundManager::PlayAsUI(const VfsPath& itemPath, bool looping)
|
|
|
|
{
|
|
|
|
IdleTask();
|
|
|
|
|
|
|
|
if ( ISoundItem* anItem = LoadItem(itemPath) )
|
|
|
|
{
|
|
|
|
if (m_Enabled && (m_UIGain > 0))
|
|
|
|
{
|
|
|
|
anItem->SetGain(m_UIGain);
|
|
|
|
anItem->SetLooping( looping );
|
|
|
|
anItem->PlayAndDelete();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AL_CHECK
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CSoundManager::Pause(bool pauseIt)
|
|
|
|
{
|
|
|
|
PauseMusic(pauseIt);
|
|
|
|
PauseAmbient(pauseIt);
|
|
|
|
PauseAction(pauseIt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::PauseMusic (bool pauseIt)
|
|
|
|
{
|
|
|
|
if (m_CurrentTune && pauseIt && !m_MusicPaused )
|
|
|
|
{
|
|
|
|
m_CurrentTune->FadeAndPause( 1.0 );
|
|
|
|
}
|
|
|
|
else if ( m_CurrentTune && m_MusicPaused && !pauseIt && m_MusicEnabled )
|
|
|
|
{
|
|
|
|
m_CurrentTune->SetGain(0);
|
|
|
|
m_CurrentTune->Resume();
|
|
|
|
m_CurrentTune->FadeToIn( m_MusicGain, 1.0);
|
|
|
|
}
|
|
|
|
m_MusicPaused = pauseIt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::PauseAmbient (bool pauseIt)
|
|
|
|
{
|
|
|
|
if (m_CurrentEnvirons && pauseIt)
|
|
|
|
m_CurrentEnvirons->Pause();
|
|
|
|
else if ( m_CurrentEnvirons )
|
|
|
|
m_CurrentEnvirons->Resume();
|
|
|
|
|
|
|
|
m_AmbientPaused = pauseIt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::PauseAction (bool pauseIt)
|
|
|
|
{
|
|
|
|
m_ActionPaused = pauseIt;
|
|
|
|
}
|
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
void CSoundManager::SetMusicItem(ISoundItem* anItem)
|
|
|
|
{
|
2012-08-31 21:08:41 +02:00
|
|
|
AL_CHECK
|
2012-08-15 02:10:44 +02:00
|
|
|
if (m_CurrentTune)
|
|
|
|
{
|
2012-09-27 04:42:03 +02:00
|
|
|
m_CurrentTune->FadeAndDelete(2.00);
|
2012-08-15 02:10:44 +02:00
|
|
|
m_CurrentTune = 0L;
|
|
|
|
}
|
2012-09-27 04:42:03 +02:00
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
IdleTask();
|
2012-09-27 04:42:03 +02:00
|
|
|
|
2012-08-15 02:10:44 +02:00
|
|
|
if (anItem)
|
|
|
|
{
|
|
|
|
if (m_MusicEnabled && m_Enabled)
|
|
|
|
{
|
|
|
|
m_CurrentTune = anItem;
|
|
|
|
m_CurrentTune->SetGain(0);
|
2013-04-24 14:03:42 +02:00
|
|
|
|
|
|
|
if ( m_PlayingPlaylist )
|
|
|
|
{
|
|
|
|
m_RunningPlaylist = true;
|
|
|
|
m_CurrentTune->Play();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_CurrentTune->PlayLoop();
|
|
|
|
|
2013-09-06 04:46:13 +02:00
|
|
|
m_MusicPaused = false;
|
2012-09-27 04:42:03 +02:00
|
|
|
m_CurrentTune->FadeToIn( m_MusicGain, 1.00);
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
anItem->StopAndDelete();
|
|
|
|
}
|
|
|
|
}
|
2012-08-31 21:08:41 +02:00
|
|
|
AL_CHECK
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CSoundManager::SetAmbientItem(ISoundItem* anItem)
|
|
|
|
{
|
|
|
|
if (m_CurrentEnvirons)
|
|
|
|
{
|
|
|
|
m_CurrentEnvirons->FadeAndDelete(3.00);
|
|
|
|
m_CurrentEnvirons = 0L;
|
|
|
|
}
|
|
|
|
IdleTask();
|
|
|
|
|
|
|
|
if (anItem)
|
|
|
|
{
|
|
|
|
if (m_Enabled && (m_AmbientGain > 0))
|
|
|
|
{
|
|
|
|
m_CurrentEnvirons = anItem;
|
|
|
|
m_CurrentEnvirons->SetGain(0);
|
|
|
|
m_CurrentEnvirons->PlayLoop();
|
2012-09-27 04:42:03 +02:00
|
|
|
m_CurrentEnvirons->FadeToIn( m_AmbientGain, 2.00);
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
|
|
|
}
|
2012-08-31 21:08:41 +02:00
|
|
|
AL_CHECK
|
2012-08-15 02:10:44 +02:00
|
|
|
}
|
2013-06-13 14:12:44 +02:00
|
|
|
#else // CONFIG2_AUDIO
|
|
|
|
|
|
|
|
void ISoundManager::CreateSoundManager(){}
|
|
|
|
void ISoundManager::SetEnabled(bool UNUSED(doEnable)){}
|
2013-08-29 15:20:55 +02:00
|
|
|
void ISoundManager::CloseGame(){}
|
2012-08-15 02:10:44 +02:00
|
|
|
|
2012-08-31 21:08:41 +02:00
|
|
|
#endif // CONFIG2_AUDIO
|
|
|
|
|