add reference counting for preloaded sounds

This doesn't give full refcounting: loading a sound that isn't preloaded
will still go through a full load (eg. initting Vorbis, etc).  This handles the
most expensive case, where the whole sound is loaded.  This case is
easy because we can make free copies, and track the number of copies
remaining to handle cleanup.
This commit is contained in:
Glenn Maynard
2005-07-18 19:08:28 +00:00
parent c3ff27796a
commit 2493236cea
2 changed files with 68 additions and 2 deletions
+60 -1
View File
@@ -8,6 +8,8 @@
#include "RageSound.h"
#include "RageLog.h"
#include "RageTimer.h"
#include "RageSoundReader_Preload.h"
#include "Foreach.h"
#include "arch/Sound/RageSoundDriver.h"
@@ -97,8 +99,30 @@ void RageSoundManager::Update( float fDeltaTime )
{
FlushPosMapQueue();
/* Scan m_mapPreloadedSounds for sounds that are no longer loaded, and delete them. */
g_SoundManMutex.Lock(); /* lock for access to m_mapPreloadedSounds, owned_sounds */
{
map<CString, RageSoundReader_Preload *>::iterator it, next;
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 );
}
else
LOG->Trace( "Kept sound \"%s\" (%i)", it->first.c_str(),
it->second->GetReferenceCount() );
it = next;
}
}
/* Scan the owned_sounds list for sounds that are no longer playing, and delete them. */
g_SoundManMutex.Lock(); /* lock for access to owned_sounds */
set<RageSound *> ToDelete;
for( set<RageSound *>::iterator it = owned_sounds.begin(); it != owned_sounds.end(); ++it )
{
@@ -256,6 +280,41 @@ void RageSoundManager::DeleteSoundWhenFinished( RageSound *pSound )
g_SoundManMutex.Unlock(); /* finished with owned_sounds */
}
/* If the given path is loaded, return a copy; otherwise return NULL.
* It's the caller's responsibility to delete the result. */
SoundReader *RageSoundManager::GetLoadedSound( const CString &sPath_ )
{
LockMut(g_SoundManMutex); /* lock for access to m_mapPreloadedSounds */
CString sPath(sPath_);
sPath.MakeLower();
map<CString, RageSoundReader_Preload *>::const_iterator it;
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. */
void RageSoundManager::AddLoadedSound( const CString &sPath_, RageSoundReader_Preload *pSound )
{
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. */
CString sPath(sPath_);
sPath.MakeLower();
map<CString, RageSoundReader_Preload *>::const_iterator it;
it = m_mapPreloadedSounds.find( sPath );
ASSERT_M( it == m_mapPreloadedSounds.end(), sPath );
m_mapPreloadedSounds[sPath] = (RageSoundReader_Preload *) pSound->Copy();
}
/* Don't hold the lock when we don't have to. We call this function from other
* threads, to avoid stalling the gameplay thread. */
void RageSoundManager::PlayOnce( CString sPath )
+8 -1
View File
@@ -11,6 +11,8 @@ class RageSound;
class RageSoundBase;
class RageSoundDriver;
struct RageSoundParams;
class SoundReader;
class RageSoundReader_Preload;
class RageSoundManager
{
@@ -46,6 +48,9 @@ public:
void DeleteSound( RageSound *pSound );
void DeleteSoundWhenFinished( RageSound *pSound );
SoundReader *GetLoadedSound( const CString &sPath );
void AddLoadedSound( const CString &sPath, RageSoundReader_Preload *pSound );
void PlayOnce( CString sPath );
RageSound *PlaySound( RageSound &snd, const RageSoundParams *params = NULL );
@@ -60,7 +65,9 @@ private:
/* A list of all sounds that currently exist, by ID. */
map<int,RageSound *> all_sounds;
map<CString, RageSoundReader_Preload *> m_mapPreloadedSounds;
RageSoundDriver *m_pDriver;
/* Prefs: */