simplify RageSounds using a qeue (this was actually in Windows a15, just
forgot to commit it) allow disabling beat alignment
This commit is contained in:
+121
-128
@@ -24,7 +24,7 @@ RageSounds *SOUND = NULL;
|
|||||||
* on the same fractional beat when we loop. (XXX: should we increase fade_len, too?
|
* 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.)
|
* 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 RageMutex *g_Mutex;
|
||||||
static bool g_UpdatingTimer;
|
static bool g_UpdatingTimer;
|
||||||
static bool g_ThreadedMusicStart = true;
|
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<CString *> g_SoundsToPlayOnce;
|
||||||
|
CircBuf<CString *> g_SoundsToPlayOnceFromDir;
|
||||||
|
|
||||||
struct MusicToPlay
|
struct MusicToPlay
|
||||||
{
|
{
|
||||||
CString file, timing_file;
|
CString file, timing_file;
|
||||||
bool HasTiming;
|
bool HasTiming;
|
||||||
bool force_loop;
|
bool force_loop;
|
||||||
float start_sec, length_sec, fade_len;
|
float start_sec, length_sec, fade_len;
|
||||||
bool pending;
|
bool align_beat;
|
||||||
MusicToPlay() { pending=false; }
|
|
||||||
};
|
};
|
||||||
|
CircBuf<MusicToPlay *> g_MusicsToPlay;
|
||||||
|
|
||||||
static MusicToPlay g_MusicToPlay;
|
static void StartMusic( MusicToPlay &ToPlay )
|
||||||
static MusicPlaying *g_Playing;
|
|
||||||
static RageThread MusicThread;
|
|
||||||
|
|
||||||
static vector<CString> 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 )
|
|
||||||
{
|
{
|
||||||
LockMutex L( *g_Mutex );
|
LockMutex L( *g_Mutex );
|
||||||
|
|
||||||
|
if( g_Playing->m_Music->IsPlaying() && !g_Playing->m_Music->GetLoadedFilePath().CompareNoCase(ToPlay.file) )
|
||||||
|
return;
|
||||||
|
|
||||||
if( ToPlay.file.empty() )
|
if( ToPlay.file.empty() )
|
||||||
{
|
{
|
||||||
if( g_Playing->m_Music->IsPlaying() )
|
if( g_Playing->m_Music->IsPlaying() )
|
||||||
@@ -172,7 +103,7 @@ void StartMusic( MusicToPlay &ToPlay )
|
|||||||
ToPlay.HasTiming = true;
|
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
|
/* 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
|
* 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. */
|
* start now. */
|
||||||
if( !g_Playing->m_HasTiming && !g_UpdatingTimer )
|
if( !g_Playing->m_HasTiming && !g_UpdatingTimer )
|
||||||
StartImmediately = true;
|
StartImmediately = true;
|
||||||
|
if( !ToPlay.align_beat )
|
||||||
|
StartImmediately = true;
|
||||||
|
|
||||||
RageTimer when; /* zero */
|
RageTimer when; /* zero */
|
||||||
if( !StartImmediately )
|
if( !StartImmediately )
|
||||||
@@ -241,16 +174,75 @@ void StartMusic( MusicToPlay &ToPlay )
|
|||||||
when = GAMESTATE->m_LastBeatUpdate + PresumedLatency + fDistance;
|
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();
|
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 );
|
LockMut( *g_Mutex );
|
||||||
delete g_Playing;
|
delete g_Playing;
|
||||||
g_Playing = NewMusic;
|
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 )
|
int MusicThread_start( void *p )
|
||||||
{
|
{
|
||||||
while( !g_Shutdown )
|
while( !g_Shutdown )
|
||||||
@@ -258,19 +250,6 @@ int MusicThread_start( void *p )
|
|||||||
SDL_Delay( 10 );
|
SDL_Delay( 10 );
|
||||||
|
|
||||||
StartQueuedSounds();
|
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;
|
return 0;
|
||||||
@@ -281,6 +260,10 @@ RageSounds::RageSounds()
|
|||||||
/* Init RageSoundMan first: */
|
/* Init RageSoundMan first: */
|
||||||
ASSERT( SOUNDMAN );
|
ASSERT( SOUNDMAN );
|
||||||
|
|
||||||
|
g_SoundsToPlayOnce.reserve( 16 );
|
||||||
|
g_SoundsToPlayOnceFromDir.reserve( 16 );
|
||||||
|
g_MusicsToPlay.reserve( 16 );
|
||||||
|
|
||||||
g_Mutex = new RageMutex("RageSounds");
|
g_Mutex = new RageMutex("RageSounds");
|
||||||
g_Playing = new MusicPlaying( new RageSound );
|
g_Playing = new MusicPlaying( new RageSound );
|
||||||
|
|
||||||
@@ -307,6 +290,17 @@ RageSounds::~RageSounds()
|
|||||||
|
|
||||||
delete g_Playing;
|
delete g_Playing;
|
||||||
delete g_Mutex;
|
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 )
|
static float GetFrameTimingAdjustment( float fDeltaTime )
|
||||||
@@ -414,34 +408,31 @@ CString RageSounds::GetMusicPath() const
|
|||||||
return g_Playing->m_Music->GetLoadedFilePath();
|
return g_Playing->m_Music->GetLoadedFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function should not touch the disk at all. */
|
/* 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 )
|
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());
|
// 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->file = file;
|
||||||
ToPlay.force_loop = force_loop;
|
ToPlay->force_loop = force_loop;
|
||||||
ToPlay.start_sec = start_sec;
|
ToPlay->start_sec = start_sec;
|
||||||
ToPlay.length_sec = length_sec;
|
ToPlay->length_sec = length_sec;
|
||||||
ToPlay.fade_len = fade_len;
|
ToPlay->fade_len = fade_len;
|
||||||
ToPlay.timing_file = timing_file;
|
ToPlay->timing_file = timing_file;
|
||||||
ToPlay.pending = true;
|
ToPlay->align_beat = align_beat;
|
||||||
|
|
||||||
/* If no timing file was specified, look for one in the same place as the music file. */
|
/* If no timing file was specified, look for one in the same place as the music file. */
|
||||||
if( ToPlay.timing_file == "" )
|
if( ToPlay->timing_file == "" )
|
||||||
ToPlay.timing_file = SetExtension( file, "sm" );
|
ToPlay->timing_file = SetExtension( file, "sm" );
|
||||||
|
|
||||||
if( g_ThreadedMusicStart )
|
/* Add the MusicToPlay to the g_MusicsToPlay queue. */
|
||||||
{
|
if( !g_MusicsToPlay.write( &ToPlay, 1 ) )
|
||||||
g_MusicToPlay = ToPlay;
|
delete ToPlay;
|
||||||
}
|
|
||||||
else
|
if( !g_ThreadedMusicStart )
|
||||||
StartMusic( ToPlay );
|
StartQueuedSounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RageSounds::HandleSongTimer( bool on )
|
void RageSounds::HandleSongTimer( bool on )
|
||||||
@@ -452,9 +443,10 @@ void RageSounds::HandleSongTimer( bool on )
|
|||||||
|
|
||||||
void RageSounds::PlayOnce( CString sPath )
|
void RageSounds::PlayOnce( CString sPath )
|
||||||
{
|
{
|
||||||
g_Mutex->Lock();
|
/* Add the sound to the g_SoundsToPlayOnce queue. */
|
||||||
g_SoundsToPlayOnce.push_back( sPath );
|
CString *p = new CString( sPath );
|
||||||
g_Mutex->Unlock();
|
if( !g_SoundsToPlayOnce.write( &p, 1 ) )
|
||||||
|
delete p;
|
||||||
|
|
||||||
if( !g_ThreadedMusicStart )
|
if( !g_ThreadedMusicStart )
|
||||||
StartQueuedSounds();
|
StartQueuedSounds();
|
||||||
@@ -462,9 +454,10 @@ void RageSounds::PlayOnce( CString sPath )
|
|||||||
|
|
||||||
void RageSounds::PlayOnceFromDir( CString PlayOnceFromDir )
|
void RageSounds::PlayOnceFromDir( CString PlayOnceFromDir )
|
||||||
{
|
{
|
||||||
g_Mutex->Lock();
|
/* Add the path to the g_SoundsToPlayOnceFromDir queue. */
|
||||||
g_SoundsToPlayOnceFromDir.push_back( PlayOnceFromDir );
|
CString *p = new CString( PlayOnceFromDir );
|
||||||
g_Mutex->Unlock();
|
if( !g_SoundsToPlayOnceFromDir.write( &p, 1 ) )
|
||||||
|
delete p;
|
||||||
|
|
||||||
if( !g_ThreadedMusicStart )
|
if( !g_ThreadedMusicStart )
|
||||||
StartQueuedSounds();
|
StartQueuedSounds();
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ public:
|
|||||||
~RageSounds();
|
~RageSounds();
|
||||||
void Update( float fDeltaTime );
|
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, 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 );
|
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(""); }
|
void StopMusic() { PlayMusic(""); }
|
||||||
CString GetMusicPath() const;
|
CString GetMusicPath() const;
|
||||||
|
|
||||||
|
|||||||
@@ -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_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 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 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);
|
static const ScreenMessage SM_AllowOptionsMenuRepeat = ScreenMessage(SM_User+1);
|
||||||
CString g_sFallbackCDTitlePath;
|
CString g_sFallbackCDTitlePath;
|
||||||
@@ -676,7 +677,8 @@ void ScreenSelectMusic::Update( float fDeltaTime )
|
|||||||
true,
|
true,
|
||||||
m_fSampleStartSeconds,
|
m_fSampleStartSeconds,
|
||||||
m_fSampleLengthSeconds,
|
m_fSampleLengthSeconds,
|
||||||
1.5f); /* fade out for 1.5 seconds */
|
1.5f, /* fade out for 1.5 seconds */
|
||||||
|
ALIGN_MUSIC_BEATS );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user