Support background loading. The principle is simple: when the song
changes, request all of its assets that we need be loaded. Once each piece finishes, load it from cache. We still take a skip to decode graphics (banners in particular), but not from disk seeks, which is an issue on hard drives and fatal on CDs. This also handles fading banners much more precisely: we fade to the high res banner once the music wheel has settled. Before, it was approximate; we'd often load the banner before we settled. It still skips, but it's much less prominent to skip when the music wheel is completely settled, than to skip just before it settles. Some more work is necessary to resolve lock contention; currently, you'll still see frequent skips off a CD (but not constant as before). I'm working on that, but I'm not sure if I want to put that in before the release, since it's caused some crashes that I havn't tracked down. The actual background work is disabled, and may not be enabled for the release. I'm committing this to get the basic API work ironed out. It still gives perceptual skip improvements even without the background thread.
This commit is contained in:
@@ -50,6 +50,14 @@ const int NUM_SCORE_DIGITS = 9;
|
||||
static const ScreenMessage SM_AllowOptionsMenuRepeat = ScreenMessage(SM_User+1);
|
||||
CString g_sFallbackCDTitlePath;
|
||||
|
||||
static CString g_sCDTitlePath;
|
||||
static bool g_bWantFallbackCdTitle;
|
||||
static bool g_bCDTitleWaiting = false;
|
||||
static CString g_sBannerPath;
|
||||
static bool g_bBannerWaiting = false;
|
||||
static bool g_bSampleMusicWaiting = false;
|
||||
static RageTimer g_StartedLoadingAt(RageZeroTimer);
|
||||
|
||||
ScreenSelectMusic::ScreenSelectMusic( CString sClassName ) : ScreenWithMenuElements( sClassName )
|
||||
{
|
||||
LOG->Trace( "ScreenSelectMusic::ScreenSelectMusic()" );
|
||||
@@ -312,7 +320,6 @@ ScreenSelectMusic::ScreenSelectMusic( CString sClassName ) : ScreenWithMenuEleme
|
||||
|
||||
m_bMadeChoice = false;
|
||||
m_bGoToOptions = false;
|
||||
m_fPlaySampleCountdown = 0;
|
||||
m_bAllowOptionsMenu = m_bAllowOptionsMenuRepeat = false;
|
||||
|
||||
UpdateOptionsDisplays();
|
||||
@@ -635,6 +642,75 @@ void ScreenSelectMusic::TweenScoreOnAndOffAfterChangeSort()
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSelectMusic::CheckBackgroundRequests()
|
||||
{
|
||||
if( g_bCDTitleWaiting )
|
||||
{
|
||||
/* The CDTitle is normally very small, so we don't bother waiting to display it. */
|
||||
CString sPath;
|
||||
if( m_BackgroundLoader.IsCacheFileFinished(g_sCDTitlePath, sPath) )
|
||||
{
|
||||
g_bCDTitleWaiting = false;
|
||||
|
||||
CString sCDTitlePath = sPath;
|
||||
|
||||
if( sCDTitlePath.empty() || !IsAFile(sCDTitlePath) )
|
||||
sCDTitlePath = g_bWantFallbackCdTitle? g_sFallbackCDTitlePath:"";
|
||||
|
||||
if( !sCDTitlePath.empty() )
|
||||
{
|
||||
TEXTUREMAN->DisableOddDimensionWarning();
|
||||
m_sprCDTitleFront.Load( sCDTitlePath );
|
||||
m_sprCDTitleBack.Load( sCDTitlePath );
|
||||
TEXTUREMAN->EnableOddDimensionWarning();
|
||||
}
|
||||
|
||||
m_BackgroundLoader.FinishedWithCachedFile( g_sCDTitlePath );
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
/* Loading the rest can cause small skips, so don't do it until the wheel settles. */
|
||||
if( !m_MusicWheel.IsSettled() )
|
||||
return;
|
||||
|
||||
if( g_bBannerWaiting )
|
||||
{
|
||||
float HighQualTime = THEME->GetMetricF("FadingBanner","FadeSeconds");
|
||||
|
||||
CString sPath;
|
||||
if( g_StartedLoadingAt.Ago() >= HighQualTime && m_BackgroundLoader.IsCacheFileFinished(g_sBannerPath, sPath) )
|
||||
{
|
||||
g_bBannerWaiting = false;
|
||||
RageTimer foo;
|
||||
m_Banner.Load( sPath );
|
||||
|
||||
m_BackgroundLoader.FinishedWithCachedFile( g_sBannerPath );
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
/* Nothing else is going. Start the music, if we havn't yet. */
|
||||
if( g_bSampleMusicWaiting )
|
||||
{
|
||||
/* Don't start the music sample when moving fast. */
|
||||
if( g_StartedLoadingAt.Ago() >= SAMPLE_MUSIC_DELAY )
|
||||
{
|
||||
g_bSampleMusicWaiting = false;
|
||||
|
||||
SOUND->PlayMusic(
|
||||
m_sSampleMusicToPlay, m_pSampleMusicTimingData,
|
||||
true, m_fSampleStartSeconds, m_fSampleLengthSeconds,
|
||||
1.5f, /* fade out for 1.5 seconds */
|
||||
ALIGN_MUSIC_BEATS );
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSelectMusic::Update( float fDeltaTime )
|
||||
{
|
||||
Screen::Update( fDeltaTime );
|
||||
@@ -642,24 +718,7 @@ void ScreenSelectMusic::Update( float fDeltaTime )
|
||||
m_bgNoOptionsOut.Update( fDeltaTime );
|
||||
m_sprOptionsMessage.Update( fDeltaTime );
|
||||
|
||||
|
||||
if( m_fPlaySampleCountdown > 0 )
|
||||
{
|
||||
m_fPlaySampleCountdown -= fDeltaTime;
|
||||
/* Make sure we don't start the sample when rouletting is
|
||||
* spinning down. */
|
||||
if( m_fPlaySampleCountdown <= 0 && !m_MusicWheel.IsRouletting() )
|
||||
{
|
||||
if( !m_sSampleMusicToPlay.empty() )
|
||||
{
|
||||
SOUND->PlayMusic(
|
||||
m_sSampleMusicToPlay, m_pSampleMusicTimingData,
|
||||
true, m_fSampleStartSeconds, m_fSampleLengthSeconds,
|
||||
1.5f, /* fade out for 1.5 seconds */
|
||||
ALIGN_MUSIC_BEATS );
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckBackgroundRequests();
|
||||
}
|
||||
|
||||
void ScreenSelectMusic::Input( const DeviceInput& DeviceI, InputEventType type, const GameInput &GameI, const MenuInput &MenuI, const StyleInput &StyleI )
|
||||
@@ -1353,6 +1412,11 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
|
||||
m_sSampleMusicToPlay = "";
|
||||
m_pSampleMusicTimingData = NULL;
|
||||
g_sCDTitlePath = "";
|
||||
g_sBannerPath = "";
|
||||
g_bWantFallbackCdTitle = false;
|
||||
bool bWantBanner = true;
|
||||
|
||||
switch( m_MusicWheel.GetSelectedType() )
|
||||
{
|
||||
case TYPE_SECTION:
|
||||
@@ -1363,8 +1427,7 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
m_iSelection[p] = -1;
|
||||
|
||||
m_BPMDisplay.NoBPM();
|
||||
m_sprCDTitleFront.UnloadTexture();
|
||||
m_sprCDTitleBack.UnloadTexture();
|
||||
g_sCDTitlePath = ""; // none
|
||||
m_DifficultyDisplay.UnsetDifficulties();
|
||||
|
||||
m_fSampleStartSeconds = 0;
|
||||
@@ -1376,10 +1439,11 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
switch( m_MusicWheel.GetSelectedType() )
|
||||
{
|
||||
case TYPE_SECTION:
|
||||
m_Banner.LoadFromGroup( sGroup ); // if this isn't a group, it'll default to the fallback banner
|
||||
g_sBannerPath = SONGMAN->GetGroupBannerPath( sGroup );
|
||||
m_sSampleMusicToPlay = THEME->GetPathS(m_sName,"section music");
|
||||
break;
|
||||
case TYPE_SORT:
|
||||
bWantBanner = false; /* we load it ourself */
|
||||
switch( GAMESTATE->m_SortOrder )
|
||||
{
|
||||
case SORT_SORT_MENU:
|
||||
@@ -1417,9 +1481,7 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
StepsUtil::SortNotesArrayByDifficulty( m_vpSteps );
|
||||
|
||||
if ( PREFSMAN->m_bShowBanners )
|
||||
m_Banner.LoadFromSong( pSong );
|
||||
else
|
||||
m_Banner.LoadFallback() ;
|
||||
g_sBannerPath = pSong->GetBannerPath();
|
||||
|
||||
if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() )
|
||||
{
|
||||
@@ -1430,11 +1492,8 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
m_BPMDisplay.SetBPM( pSong );
|
||||
}
|
||||
|
||||
const CString CDTitlePath = pSong->HasCDTitle()? pSong->GetCDTitlePath():g_sFallbackCDTitlePath;
|
||||
TEXTUREMAN->DisableOddDimensionWarning();
|
||||
m_sprCDTitleFront.Load( CDTitlePath );
|
||||
m_sprCDTitleBack.Load( CDTitlePath );
|
||||
TEXTUREMAN->EnableOddDimensionWarning();
|
||||
g_sCDTitlePath = pSong->GetCDTitlePath();
|
||||
g_bWantFallbackCdTitle = true;
|
||||
|
||||
const vector<Song*> best = SONGMAN->GetBestSongs( PROFILE_SLOT_MACHINE );
|
||||
const int index = FindIndex( best.begin(), best.end(), pSong );
|
||||
@@ -1478,16 +1537,15 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
break;
|
||||
case TYPE_ROULETTE:
|
||||
case TYPE_RANDOM:
|
||||
bWantBanner = false; /* we load it ourself */
|
||||
switch(m_MusicWheel.GetSelectedType())
|
||||
{
|
||||
case TYPE_ROULETTE: m_Banner.LoadRoulette(); break;
|
||||
case TYPE_RANDOM: m_Banner.LoadRandom(); break;
|
||||
default: ASSERT(0);
|
||||
}
|
||||
|
||||
m_BPMDisplay.NoBPM();
|
||||
m_sprCDTitleFront.UnloadTexture();
|
||||
m_sprCDTitleBack.UnloadTexture();
|
||||
g_sCDTitlePath = ""; // none
|
||||
m_DifficultyDisplay.UnsetDifficulties();
|
||||
|
||||
m_fSampleStartSeconds = 0;
|
||||
@@ -1535,7 +1593,10 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
else
|
||||
m_textTotalTime.SetText( "xx:xx.xx" ); // The numbers format doesn't have a '?'. Is there a better solution?
|
||||
|
||||
m_Banner.LoadFromCourse( pCourse );
|
||||
g_sBannerPath = pCourse->m_sBannerPath;
|
||||
if( g_sBannerPath.empty() )
|
||||
m_Banner.LoadFallback();
|
||||
|
||||
m_BPMDisplay.SetBPM( pCourse );
|
||||
|
||||
m_DifficultyDisplay.UnsetDifficulties();
|
||||
@@ -1581,16 +1642,45 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
// update stage counter display (long versions/marathons)
|
||||
m_sprStage.Load( THEME->GetPathG(m_sName,"stage "+GAMESTATE->GetStageText()) );
|
||||
m_sprCDTitleFront.UnloadTexture();
|
||||
m_sprCDTitleBack.UnloadTexture();
|
||||
|
||||
if( m_MusicWheel.GetSelectedType() == TYPE_ROULETTE || m_MusicWheel.GetSelectedType() == TYPE_RANDOM )
|
||||
m_BackgroundLoader.Abort();
|
||||
|
||||
g_bCDTitleWaiting = false;
|
||||
if( !g_sCDTitlePath.empty() || g_bWantFallbackCdTitle )
|
||||
{
|
||||
LOG->Trace( "cache \"%s\"", g_sCDTitlePath.c_str());
|
||||
m_BackgroundLoader.CacheFile( g_sCDTitlePath ); // empty OK
|
||||
g_bCDTitleWaiting = true;
|
||||
}
|
||||
|
||||
g_bBannerWaiting = false;
|
||||
if( bWantBanner )
|
||||
{
|
||||
LOG->Trace("LoadFromCachedBanner(%s)",g_sBannerPath .c_str());
|
||||
if( m_Banner.LoadFromCachedBanner( g_sBannerPath ) )
|
||||
{
|
||||
m_BackgroundLoader.CacheFile( g_sBannerPath );
|
||||
g_bBannerWaiting = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't stop music if it's already playing the right file.
|
||||
if( SOUND->GetMusicPath() != m_sSampleMusicToPlay )
|
||||
g_bSampleMusicWaiting = false;
|
||||
if( !m_MusicWheel.IsRouletting() && SOUND->GetMusicPath() != m_sSampleMusicToPlay )
|
||||
{
|
||||
SOUND->StopMusic();
|
||||
m_fPlaySampleCountdown = SAMPLE_MUSIC_DELAY;
|
||||
if( !m_sSampleMusicToPlay.empty() )
|
||||
g_bSampleMusicWaiting = true;
|
||||
}
|
||||
|
||||
g_StartedLoadingAt.Touch();
|
||||
|
||||
// update stage counter display (long versions/marathons)
|
||||
m_sprStage.Load( THEME->GetPathG(m_sName,"stage "+GAMESTATE->GetStageText()) );
|
||||
|
||||
m_Artist.SetTips( m_Artists, m_AltArtists );
|
||||
|
||||
FOREACH_HumanPlayer( p )
|
||||
@@ -1607,10 +1697,6 @@ void ScreenSelectMusic::AfterMusicChange()
|
||||
m_CourseContentsFrame.TweenInAfterChangedCourse();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make sure we never start the sample when moving fast. */
|
||||
if(m_MusicWheel.IsMoving())
|
||||
m_fPlaySampleCountdown = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user