Files
itgmania212121/stepmania/src/RageSoundManager.cpp
T

221 lines
6.7 KiB
C++
Raw Normal View History

/*
* This manager has several distinct purposes:
*
2005-12-30 19:12:10 +00:00
* Load the sound driver, and handle most communication between it and RageSound.
* Factory and reference count RageSoundReader objects for RageSound.
* User-level:
* - global volume management
* - sound detaching ("play and delete when done playing")
*/
2002-12-13 07:44:34 +00:00
2004-05-06 02:40:33 +00:00
#include "global.h"
2002-12-13 07:44:34 +00:00
#include "RageSoundManager.h"
#include "RageUtil.h"
#include "RageSound.h"
#include "RageLog.h"
#include "RageTimer.h"
2005-07-18 19:08:28 +00:00
#include "RageSoundReader_Preload.h"
#include "Foreach.h"
2005-12-22 03:10:04 +00:00
#include "LocalizedString.h"
2005-12-31 02:35:49 +00:00
#include "Preference.h"
2002-12-13 07:44:34 +00:00
#include "arch/Sound/RageSoundDriver.h"
2005-12-31 02:35:49 +00:00
#include "arch/arch_default.h"
/*
* The lock ordering requirements are:
* RageSound::Lock before g_SoundManMutex
* RageSound::Lock must not be locked when calling driver calls (since the driver
* may lock a mutex and then make RageSound calls back)
*
* Do not make RageSound calls that might lock while holding g_SoundManMutex.
*/
static RageMutex g_SoundManMutex("SoundMan");
2006-01-22 01:00:06 +00:00
static Preference<RString> g_sSoundDrivers( "SoundDrivers", "" ); // "" == DEFAULT_SOUND_DRIVER_LIST
2003-02-14 06:40:08 +00:00
RageSoundManager *SOUNDMAN = NULL;
RageSoundManager::RageSoundManager()
2002-12-13 07:44:34 +00:00
{
2005-07-03 04:03:46 +00:00
m_fMixVolume = 1.0f;
m_bPlayOnlyCriticalSounds = false;
}
2005-12-20 08:35:47 +00:00
static LocalizedString COULDNT_FIND_SOUND_DRIVER( "RageSoundManager", "Couldn't find a sound driver that works" );
2005-12-31 02:35:49 +00:00
void RageSoundManager::Init()
{
2006-01-22 01:00:06 +00:00
RString sDrivers = g_sSoundDrivers;
2005-12-31 02:35:49 +00:00
if( sDrivers.empty() )
sDrivers = DEFAULT_SOUND_DRIVER_LIST;
m_pDriver = RageSoundDriver::Create( sDrivers );
2005-07-03 04:03:46 +00:00
if( m_pDriver == NULL )
RageException::Throw( "%s", COULDNT_FIND_SOUND_DRIVER.GetValue().c_str() );
2002-12-13 07:44:34 +00:00
}
RageSoundManager::~RageSoundManager()
{
2004-01-22 23:21:07 +00:00
/* Don't lock while deleting the driver (the decoder thread might deadlock). */
2005-07-03 04:03:46 +00:00
delete m_pDriver;
2002-12-13 07:44:34 +00:00
}
/*
* Previously, we went to some lengths to shut down sounds before exiting threads.
* The only other thread that actually starts sounds is SOUND. Doing this was ugly;
* instead, let's shut down the driver early, stopping all sounds. We don't want
* to delete SOUNDMAN early, since those threads are still using it; just shut down
* the driver.
*/
void RageSoundManager::Shutdown()
{
2005-07-03 04:03:46 +00:00
SAFE_DELETE( m_pDriver );
}
2005-07-03 04:03:46 +00:00
void RageSoundManager::StartMixing( RageSoundBase *pSound )
2002-12-13 07:44:34 +00:00
{
2005-07-03 04:03:46 +00:00
if( m_pDriver != NULL )
m_pDriver->StartMixing( pSound );
2002-12-13 07:44:34 +00:00
}
2005-07-03 04:03:46 +00:00
void RageSoundManager::StopMixing( RageSoundBase *pSound )
2002-12-13 07:44:34 +00:00
{
2005-07-03 04:03:46 +00:00
if( m_pDriver != NULL )
m_pDriver->StopMixing( pSound );
2002-12-13 07:44:34 +00:00
}
2005-07-03 04:03:46 +00:00
bool RageSoundManager::Pause( RageSoundBase *pSound, bool bPause )
{
2005-07-03 04:03:46 +00:00
if( m_pDriver == NULL )
return false;
else
2005-07-03 04:03:46 +00:00
return m_pDriver->PauseMixing( pSound, bPause );
}
int64_t RageSoundManager::GetPosition( RageTimer *pTimer ) const
2002-12-13 07:44:34 +00:00
{
2005-07-03 04:03:46 +00:00
if( m_pDriver == NULL )
return 0;
return m_pDriver->GetHardwareFrame( pTimer );
2002-12-13 07:44:34 +00:00
}
2006-08-21 00:20:14 +00:00
void RageSoundManager::Update()
2002-12-13 07:44:34 +00:00
{
2005-07-18 19:08:28 +00:00
/* Scan m_mapPreloadedSounds for sounds that are no longer loaded, and delete them. */
g_SoundManMutex.Lock(); /* lock for access to m_mapPreloadedSounds, owned_sounds */
{
2006-01-22 01:00:06 +00:00
map<RString, RageSoundReader_Preload *>::iterator it, next;
2005-07-18 19:08:28 +00:00
it = m_mapPreloadedSounds.begin();
while( it != m_mapPreloadedSounds.end() )
{
next = it; ++next;
if( it->second->GetReferenceCount() == 1 )
{
LOG->Trace( "Deleted old sound \"%s\"", it->first.c_str() );
delete it->second;
m_mapPreloadedSounds.erase( it );
}
it = next;
}
}
2007-01-18 08:20:36 +00:00
g_SoundManMutex.Unlock(); /* finished with m_mapPreloadedSounds */
2002-12-13 07:44:34 +00:00
2005-07-03 04:03:46 +00:00
if( m_pDriver != NULL )
2006-08-21 00:20:13 +00:00
m_pDriver->Update();
2002-12-13 07:44:34 +00:00
}
float RageSoundManager::GetPlayLatency() const
{
2005-07-03 04:03:46 +00:00
if( m_pDriver == NULL )
return 0;
2005-07-03 04:03:46 +00:00
return m_pDriver->GetPlayLatency();
2002-12-13 07:44:34 +00:00
}
2006-12-13 09:15:29 +00:00
int RageSoundManager::GetDriverSampleRate() const
2003-04-23 19:31:32 +00:00
{
2005-07-03 04:03:46 +00:00
if( m_pDriver == NULL )
return 44100;
return m_pDriver->GetSampleRate();
2003-04-23 19:31:32 +00:00
}
2005-07-18 19:08:28 +00:00
/* If the given path is loaded, return a copy; otherwise return NULL.
* It's the caller's responsibility to delete the result. */
2006-11-29 02:20:10 +00:00
RageSoundReader *RageSoundManager::GetLoadedSound( const RString &sPath_ )
2005-07-18 19:08:28 +00:00
{
LockMut(g_SoundManMutex); /* lock for access to m_mapPreloadedSounds */
2006-01-22 01:00:06 +00:00
RString sPath(sPath_);
2005-07-18 19:08:28 +00:00
sPath.MakeLower();
2006-01-22 01:00:06 +00:00
map<RString, RageSoundReader_Preload *>::const_iterator it;
2005-07-18 19:08:28 +00:00
it = m_mapPreloadedSounds.find( sPath );
if( it == m_mapPreloadedSounds.end() )
return NULL;
return it->second->Copy();
}
/* Add the sound to the set of loaded sounds that can be copied for reuse.
* The sound will be kept in memory as long as there are any other references
* to it; once we hold the last one, we'll release it. */
2006-01-22 01:00:06 +00:00
void RageSoundManager::AddLoadedSound( const RString &sPath_, RageSoundReader_Preload *pSound )
2005-07-18 19:08:28 +00:00
{
LockMut(g_SoundManMutex); /* lock for access to m_mapPreloadedSounds */
/* Don't AddLoadedSound a sound that's already registered. It should have been
* used in GetLoadedSound. */
2006-01-22 01:00:06 +00:00
RString sPath(sPath_);
2005-07-18 19:08:28 +00:00
sPath.MakeLower();
2006-01-22 01:00:06 +00:00
map<RString, RageSoundReader_Preload *>::const_iterator it;
2005-07-18 19:08:28 +00:00
it = m_mapPreloadedSounds.find( sPath );
ASSERT_M( it == m_mapPreloadedSounds.end(), sPath );
2006-10-20 09:35:38 +00:00
m_mapPreloadedSounds[sPath] = pSound->Copy();
2005-07-18 19:08:28 +00:00
}
void RageSoundManager::SetMixVolume( float fMixVol )
{
2005-10-07 07:12:35 +00:00
ASSERT_M( fMixVol >= 0 && fMixVol <= 1, ssprintf("%f",fMixVol) );
2005-10-07 05:29:33 +00:00
2005-07-03 04:03:46 +00:00
g_SoundManMutex.Lock(); /* lock for access to m_fMixVolume */
m_fMixVolume = fMixVol;
g_SoundManMutex.Unlock(); /* finished with m_fMixVolume */
}
void RageSoundManager::SetPlayOnlyCriticalSounds( bool bPlayOnlyCriticalSounds )
{
g_SoundManMutex.Lock(); /* lock for access to m_bPlayOnlyCriticalSounds */
m_bPlayOnlyCriticalSounds = bPlayOnlyCriticalSounds;
g_SoundManMutex.Unlock(); /* finished with m_bPlayOnlyCriticalSounds */
}
2004-05-06 02:40:33 +00:00
/*
* Copyright (c) 2002-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/