From 29464ea18558f166dda591f944b634e03fb9cf7c Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Tue, 6 Apr 2004 04:10:41 +0000 Subject: [PATCH] simplify RageSounds using a qeue (this was actually in Windows a15, just forgot to commit it) allow disabling beat alignment --- stepmania/src/RageSounds.cpp | 249 ++++++++++++++-------------- stepmania/src/RageSounds.h | 4 +- stepmania/src/ScreenSelectMusic.cpp | 4 +- 3 files changed, 126 insertions(+), 131 deletions(-) diff --git a/stepmania/src/RageSounds.cpp b/stepmania/src/RageSounds.cpp index 8019c5b2ce..02b32413d4 100644 --- a/stepmania/src/RageSounds.cpp +++ b/stepmania/src/RageSounds.cpp @@ -24,7 +24,7 @@ RageSounds *SOUND = NULL; * on the same fractional beat when we loop. (XXX: should we increase fade_len, too? * That would cause the extra pad time to be silence.) */ -/* Lock this before touching any of these globals. */ +/* Lock this before touching g_UpdatingTimer or g_Playing. */ static RageMutex *g_Mutex; static bool g_UpdatingTimer; static bool g_ThreadedMusicStart = true; @@ -56,101 +56,32 @@ struct MusicPlaying } }; +static MusicPlaying *g_Playing; + +static RageThread MusicThread; + +/* These buffers can be accessed without locking. */ +#include "RageUtil_CircularBuffer.h" +CircBuf g_SoundsToPlayOnce; +CircBuf g_SoundsToPlayOnceFromDir; + struct MusicToPlay { CString file, timing_file; bool HasTiming; bool force_loop; float start_sec, length_sec, fade_len; - bool pending; - MusicToPlay() { pending=false; } + bool align_beat; }; +CircBuf g_MusicsToPlay; -static MusicToPlay g_MusicToPlay; -static MusicPlaying *g_Playing; -static RageThread MusicThread; - -static vector g_SoundsToPlayOnce, g_SoundsToPlayOnceFromDir; -void StartQueuedSounds() -{ - /* Don't hold the mutex if we don't have to. */ - while( 1 ) - { - CString sPath; - - g_Mutex->Lock(); - if( g_SoundsToPlayOnce.size() ) - { - sPath = g_SoundsToPlayOnce.back(); - g_SoundsToPlayOnce.erase( g_SoundsToPlayOnce.begin()+g_SoundsToPlayOnce.size()-1, g_SoundsToPlayOnce.end() ); - } - g_Mutex->Unlock(); - - if( sPath != "" ) - SOUNDMAN->PlayOnce( sPath ); - else - break; - } - - while( 1 ) - { - CString sPath; - - g_Mutex->Lock(); - if( g_SoundsToPlayOnceFromDir.size() ) - { - sPath = g_SoundsToPlayOnceFromDir.back(); - g_SoundsToPlayOnceFromDir.erase( g_SoundsToPlayOnceFromDir.begin()+g_SoundsToPlayOnceFromDir.size()-1, g_SoundsToPlayOnceFromDir.end() ); - } - g_Mutex->Unlock(); - - if( sPath != "" ) - { - // make sure there's a slash at the end of this path - if( sPath.Right(1) != "/" ) - sPath += "/"; - - CStringArray arraySoundFiles; - GetDirListing( sPath + "*.mp3", arraySoundFiles ); - GetDirListing( sPath + "*.wav", arraySoundFiles ); - GetDirListing( sPath + "*.ogg", arraySoundFiles ); - - if( arraySoundFiles.empty() ) - return; - - int index = rand() % arraySoundFiles.size(); - SOUNDMAN->PlayOnce( sPath + arraySoundFiles[index] ); - } - else - break; - } - -} - -void StartPlayingMusic( const RageTimer &when, const MusicToPlay &ToPlay, MusicPlaying &Playing ) -{ - Playing.m_HasTiming = ToPlay.HasTiming; - Playing.m_TimingDelayed = true; - - Playing.m_Music->Load( ToPlay.file, false ); - - RageSoundParams p; - p.m_StartSecond = ToPlay.start_sec; - p.m_LengthSeconds = ToPlay.length_sec; - p.m_FadeLength = ToPlay.fade_len; - p.StartTime = when; - if( ToPlay.force_loop ) - p.StopMode = RageSoundParams::M_LOOP; - Playing.m_Music->SetParams( p ); - - Playing.m_Music->SetPositionSeconds( p.m_StartSecond ); - Playing.m_Music->StartPlaying(); -} - -void StartMusic( MusicToPlay &ToPlay ) +static void StartMusic( MusicToPlay &ToPlay ) { LockMutex L( *g_Mutex ); + if( g_Playing->m_Music->IsPlaying() && !g_Playing->m_Music->GetLoadedFilePath().CompareNoCase(ToPlay.file) ) + return; + if( ToPlay.file.empty() ) { if( g_Playing->m_Music->IsPlaying() ) @@ -172,7 +103,7 @@ void StartMusic( MusicToPlay &ToPlay ) ToPlay.HasTiming = true; } - if( ToPlay.HasTiming && ToPlay.force_loop && ToPlay.length_sec != -1 ) + if( ToPlay.align_beat && ToPlay.HasTiming && ToPlay.force_loop && ToPlay.length_sec != -1 ) { /* Extend the loop period so it always starts and ends on the same fractional * beat. That is, if it starts on beat 1.5, and ends on beat 10.2, extend it @@ -215,6 +146,8 @@ void StartMusic( MusicToPlay &ToPlay ) * start now. */ if( !g_Playing->m_HasTiming && !g_UpdatingTimer ) StartImmediately = true; + if( !ToPlay.align_beat ) + StartImmediately = true; RageTimer when; /* zero */ if( !StartImmediately ) @@ -241,16 +174,75 @@ void StartMusic( MusicToPlay &ToPlay ) when = GAMESTATE->m_LastBeatUpdate + PresumedLatency + fDistance; } - /* Important: don't hold the mutex while we load the actual sound. */ + /* Important: don't hold the mutex while we load and seek the actual sound. */ L.Unlock(); + { + NewMusic->m_HasTiming = ToPlay.HasTiming; + NewMusic->m_TimingDelayed = true; + NewMusic->m_Music->Load( ToPlay.file, false ); - StartPlayingMusic( when, ToPlay, *NewMusic ); + RageSoundParams p; + p.m_StartSecond = ToPlay.start_sec; + p.m_LengthSeconds = ToPlay.length_sec; + p.m_FadeLength = ToPlay.fade_len; + p.StartTime = when; + if( ToPlay.force_loop ) + p.StopMode = RageSoundParams::M_LOOP; + NewMusic->m_Music->SetParams( p ); + + NewMusic->m_Music->SetPositionSeconds( p.m_StartSecond ); + NewMusic->m_Music->StartPlaying(); + } LockMut( *g_Mutex ); delete g_Playing; g_Playing = NewMusic; } +static void StartQueuedSounds() +{ + CString *p; + while( g_SoundsToPlayOnce.read( &p, 1 ) ) + { + if( *p != "" ) + SOUNDMAN->PlayOnce( *p ); + delete p; + } + + while( g_SoundsToPlayOnceFromDir.read( &p, 1 ) ) + { + CString sPath( *p ); + if( sPath != "" ) + { + // make sure there's a slash at the end of this path + if( sPath.Right(1) != "/" ) + sPath += "/"; + + CStringArray arraySoundFiles; + GetDirListing( sPath + "*.mp3", arraySoundFiles ); + GetDirListing( sPath + "*.wav", arraySoundFiles ); + GetDirListing( sPath + "*.ogg", arraySoundFiles ); + + if( arraySoundFiles.empty() ) + return; + + int index = rand() % arraySoundFiles.size(); + SOUNDMAN->PlayOnce( sPath + arraySoundFiles[index] ); + } + + delete p; + } + + MusicToPlay *pMusic; + while( g_MusicsToPlay.read( &pMusic, 1 ) ) + { + /* Don't bother starting this music if there's another one in the queue after it. */ + if( !g_MusicsToPlay.num_readable() ) + StartMusic( *pMusic ); + delete pMusic; + } +} + int MusicThread_start( void *p ) { while( !g_Shutdown ) @@ -258,19 +250,6 @@ int MusicThread_start( void *p ) SDL_Delay( 10 ); StartQueuedSounds(); - - LockMutex L( *g_Mutex ); - if( !g_MusicToPlay.pending ) - continue; - - /* We have a sound to start. Don't keep the lock while we do this; if another - * music tries to start in the meantime, it'll cause a skip. */ - MusicToPlay ToPlay = g_MusicToPlay; - g_MusicToPlay.pending = false; - - L.Unlock(); - - StartMusic( ToPlay ); } return 0; @@ -281,6 +260,10 @@ RageSounds::RageSounds() /* Init RageSoundMan first: */ ASSERT( SOUNDMAN ); + g_SoundsToPlayOnce.reserve( 16 ); + g_SoundsToPlayOnceFromDir.reserve( 16 ); + g_MusicsToPlay.reserve( 16 ); + g_Mutex = new RageMutex("RageSounds"); g_Playing = new MusicPlaying( new RageSound ); @@ -307,6 +290,17 @@ RageSounds::~RageSounds() delete g_Playing; delete g_Mutex; + + CString *p; + while( g_SoundsToPlayOnce.read( &p, 1 ) ) + delete p; + + while( g_SoundsToPlayOnceFromDir.read( &p, 1 ) ) + delete p; + + MusicToPlay *pMusic; + while( g_MusicsToPlay.read( &pMusic, 1 ) ) + delete pMusic; } static float GetFrameTimingAdjustment( float fDeltaTime ) @@ -414,34 +408,31 @@ CString RageSounds::GetMusicPath() const return g_Playing->m_Music->GetLoadedFilePath(); } -/* This function should not touch the disk at all. */ -void RageSounds::PlayMusic( const CString &file, const CString &timing_file, bool force_loop, float start_sec, float length_sec, float fade_len ) +/* If g_ThreadedMusicStart, this function should not touch the disk at all. */ +void RageSounds::PlayMusic( const CString &file, const CString &timing_file, bool force_loop, float start_sec, float length_sec, float fade_len, bool align_beat ) { - LockMut( *g_Mutex ); // LOG->Trace("play '%s' (current '%s')", file.c_str(), g_Playing->m_Music->GetLoadedFilePath().c_str()); - if( g_Playing->m_Music->IsPlaying() && !g_Playing->m_Music->GetLoadedFilePath().CompareNoCase(file) ) - return; // do nothing - MusicToPlay ToPlay; + MusicToPlay *ToPlay = new MusicToPlay; - ToPlay.file = file; - ToPlay.force_loop = force_loop; - ToPlay.start_sec = start_sec; - ToPlay.length_sec = length_sec; - ToPlay.fade_len = fade_len; - ToPlay.timing_file = timing_file; - ToPlay.pending = true; + ToPlay->file = file; + ToPlay->force_loop = force_loop; + ToPlay->start_sec = start_sec; + ToPlay->length_sec = length_sec; + ToPlay->fade_len = fade_len; + ToPlay->timing_file = timing_file; + ToPlay->align_beat = align_beat; /* If no timing file was specified, look for one in the same place as the music file. */ - if( ToPlay.timing_file == "" ) - ToPlay.timing_file = SetExtension( file, "sm" ); + if( ToPlay->timing_file == "" ) + ToPlay->timing_file = SetExtension( file, "sm" ); - if( g_ThreadedMusicStart ) - { - g_MusicToPlay = ToPlay; - } - else - StartMusic( ToPlay ); + /* Add the MusicToPlay to the g_MusicsToPlay queue. */ + if( !g_MusicsToPlay.write( &ToPlay, 1 ) ) + delete ToPlay; + + if( !g_ThreadedMusicStart ) + StartQueuedSounds(); } void RageSounds::HandleSongTimer( bool on ) @@ -452,9 +443,10 @@ void RageSounds::HandleSongTimer( bool on ) void RageSounds::PlayOnce( CString sPath ) { - g_Mutex->Lock(); - g_SoundsToPlayOnce.push_back( sPath ); - g_Mutex->Unlock(); + /* Add the sound to the g_SoundsToPlayOnce queue. */ + CString *p = new CString( sPath ); + if( !g_SoundsToPlayOnce.write( &p, 1 ) ) + delete p; if( !g_ThreadedMusicStart ) StartQueuedSounds(); @@ -462,9 +454,10 @@ void RageSounds::PlayOnce( CString sPath ) void RageSounds::PlayOnceFromDir( CString PlayOnceFromDir ) { - g_Mutex->Lock(); - g_SoundsToPlayOnceFromDir.push_back( PlayOnceFromDir ); - g_Mutex->Unlock(); + /* Add the path to the g_SoundsToPlayOnceFromDir queue. */ + CString *p = new CString( PlayOnceFromDir ); + if( !g_SoundsToPlayOnceFromDir.write( &p, 1 ) ) + delete p; if( !g_ThreadedMusicStart ) StartQueuedSounds(); diff --git a/stepmania/src/RageSounds.h b/stepmania/src/RageSounds.h index ba5e7df339..2a27d28861 100644 --- a/stepmania/src/RageSounds.h +++ b/stepmania/src/RageSounds.h @@ -13,8 +13,8 @@ public: ~RageSounds(); void Update( float fDeltaTime ); - void PlayMusic( const CString &file, bool force_loop = false, float start_sec = 0, float length_sec = -1, float fade_len = 0 ) { PlayMusic( file, "", force_loop, start_sec, length_sec, fade_len ); } - void PlayMusic( const CString &file, const CString &timing_file, bool force_loop = false, float start_sec = 0, float length_sec = -1, float fade_len = 0 ); + void PlayMusic( const CString &file, bool force_loop = false, float start_sec = 0, float length_sec = -1, float fade_len = 0, bool align_beat = true ) { PlayMusic( file, "", force_loop, start_sec, length_sec, fade_len, align_beat ); } + void PlayMusic( const CString &file, const CString &timing_file, bool force_loop = false, float start_sec = 0, float length_sec = -1, float fade_len = 0, bool align_beat = true ); void StopMusic() { PlayMusic(""); } CString GetMusicPath() const; diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index c934c57bb9..48ccf8ce21 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -58,6 +58,7 @@ const int NUM_SCORE_DIGITS = 9; #define SCORE_SORT_CHANGE_COMMAND(i) THEME->GetMetric ("ScreenSelectMusic",ssprintf("ScoreP%iSortChangeCommand", i+1)) #define SCORE_FRAME_SORT_CHANGE_COMMAND(i) THEME->GetMetric ("ScreenSelectMusic",ssprintf("ScoreFrameP%iSortChangeCommand", i+1)) #define DO_ROULETTE_ON_MENU_TIMER THEME->GetMetricB("ScreenSelectMusic","DoRouletteOnMenuTimer") +#define ALIGN_MUSIC_BEATS THEME->GetMetricB("ScreenSelectMusic","AlignMusicBeat") static const ScreenMessage SM_AllowOptionsMenuRepeat = ScreenMessage(SM_User+1); CString g_sFallbackCDTitlePath; @@ -676,7 +677,8 @@ void ScreenSelectMusic::Update( float fDeltaTime ) true, m_fSampleStartSeconds, m_fSampleLengthSeconds, - 1.5f); /* fade out for 1.5 seconds */ + 1.5f, /* fade out for 1.5 seconds */ + ALIGN_MUSIC_BEATS ); } } }