diff --git a/stepmania/src/RageSoundManager.cpp b/stepmania/src/RageSoundManager.cpp index 1b086e4d86..79724c9fba 100644 --- a/stepmania/src/RageSoundManager.cpp +++ b/stepmania/src/RageSoundManager.cpp @@ -90,16 +90,31 @@ void RageSoundManager::Update(float delta) g_DeletionMutex.Lock(); /* Scan the owned_sounds list for sounds that are no longer playing, and delete them. */ - g_SoundManMutex.Lock(); /* lock for access to owned_sounds */ + g_SoundManMutex.Lock(); /* lock for access to owned_sounds and all_sounds */ set::iterator it; set ToDelete; for( it = owned_sounds.begin(); it != owned_sounds.end(); ++it ) if( !(*it)->IsPlaying() ) + { + LOG->Trace("XXX: deleting '%s'", (*it)->GetLoadedFilePath().c_str()); ToDelete.insert( *it ); + } + + /* Don't delete any sounds that are the parent of another sound. Always delete + * child sounds first. Otherwise, another sound might be allocated that has the + * same pointer as an old, deleted parent, and since we use the pointer to the + * parent to determine which sounds share the same parent, it'll confuse GetCopies(). */ + for( it = all_sounds.begin(); it != all_sounds.end(); ++it ) + if( (*it)->GetOriginal() != (*it) ) // child + { + set::iterator parent = ToDelete.find( (*it)->GetOriginal() ); + if( parent != ToDelete.end() ) + ToDelete.erase( parent ); + } for( it = ToDelete.begin(); it != ToDelete.end(); ++it ) owned_sounds.erase( *it ); - g_SoundManMutex.Unlock(); /* finished with owned_sounds */ + g_SoundManMutex.Unlock(); /* finished with owned_sounds and all_sounds */ /* We can safely delete sounds while holding g_DeletionMutex, but not while * holding g_SoundManMutex (see the mutex ordering at the top of the file). */