From 9fd6768f49d96d3e0e389cf8f9aa6000f48ced49 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 21 Jan 2013 22:52:36 -0500 Subject: [PATCH 01/11] TimingData: fix constness on getters --- src/TimingData.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TimingData.h b/src/TimingData.h index ee644b311c..4478fa6fd1 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -220,11 +220,11 @@ public: void SetLabelAtBeat( float fBeat, const RString sLabel ) { SetLabelAtRow( BeatToNoteRow( fBeat ), sLabel ); } bool DoesLabelExist( const RString& sLabel ) const; - float GetSpeedPercentAtRow( int iNoteRow ) { return GetSpeedSegmentAtRow(iNoteRow)->GetRatio(); } - float GetSpeedPercentAtBeat( float fBeat ) { return GetSpeedPercentAtRow( BeatToNoteRow(fBeat) ); } + float GetSpeedPercentAtRow( int iNoteRow ) const { return GetSpeedSegmentAtRow(iNoteRow)->GetRatio(); } + float GetSpeedPercentAtBeat( float fBeat ) const { return GetSpeedPercentAtRow( BeatToNoteRow(fBeat) ); } - float GetSpeedWaitAtRow( int iNoteRow ) { return GetSpeedSegmentAtRow(iNoteRow)->GetDelay(); } - float GetSpeedWaitAtBeat( float fBeat ) { return GetSpeedWaitAtRow( BeatToNoteRow(fBeat) ); } + float GetSpeedWaitAtRow( int iNoteRow ) const { return GetSpeedSegmentAtRow(iNoteRow)->GetDelay(); } + float GetSpeedWaitAtBeat( float fBeat ) const { return GetSpeedWaitAtRow( BeatToNoteRow(fBeat) ); } // XXX: is there any point to having specific unit types? SpeedSegment::BaseUnit GetSpeedModeAtRow( int iNoteRow ) const { return GetSpeedSegmentAtRow(iNoteRow)->GetUnit(); } From da1ebd50ed22c23167b6358331eff276e8f84e8d Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 23 Jan 2013 14:25:10 -0500 Subject: [PATCH 02/11] remove unused TimingData variable --- src/NotesLoaderSMA.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NotesLoaderSMA.cpp b/src/NotesLoaderSMA.cpp index b8852822a1..bb1bf09c46 100644 --- a/src/NotesLoaderSMA.cpp +++ b/src/NotesLoaderSMA.cpp @@ -163,7 +163,6 @@ bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach int state = SMA_GETTING_SONG_INFO; Steps* pNewNotes = NULL; - TimingData stepsTiming; int iRowsPerBeat = -1; // Start with an invalid value: needed for checking. for( unsigned i=0; i Date: Sun, 20 Jan 2013 18:11:17 -0500 Subject: [PATCH 03/11] Steps: add a pointer to the associated Song. not used yet. --- src/Steps.cpp | 2 +- src/Steps.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Steps.cpp b/src/Steps.cpp index 70c6edc168..9e53aed9a7 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -42,7 +42,7 @@ static const char *DisplayBPMNames[] = XToString( DisplayBPM ); LuaXType( DisplayBPM ); -Steps::Steps(): m_StepsType(StepsType_Invalid), +Steps::Steps(): m_StepsType(StepsType_Invalid), m_pSong(NULL), parent(NULL), m_pNoteData(new NoteData), m_bNoteDataIsFilled(false), m_sNoteDataCompressed(""), m_sFilename(""), m_bSavedToDisk(false), m_LoadedFromProfile(ProfileSlot_Invalid), m_iHash(0), diff --git a/src/Steps.h b/src/Steps.h index e81e754269..6838ed55ed 100644 --- a/src/Steps.h +++ b/src/Steps.h @@ -171,6 +171,8 @@ public: void PushSelf( lua_State *L ); StepsType m_StepsType; + /** @brief The Song these Steps are associated with */ + Song *m_pSong; CachedObject m_CachedObject; From afaa382b8499c5a4c544f16cadf73d93f19ca797 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 20 Jan 2013 19:23:28 -0500 Subject: [PATCH 04/11] Steps: set Song pointer to associated song when constructing --- src/JsonUtil.h | 14 ++++++++++++++ src/NotesLoaderJson.cpp | 2 +- src/NotesLoaderSMA.cpp | 2 +- src/Song.cpp | 6 +++--- src/Steps.cpp | 3 ++- src/Steps.h | 2 +- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/JsonUtil.h b/src/JsonUtil.h index 22c33ae4ec..3cb1bdf673 100644 --- a/src/JsonUtil.h +++ b/src/JsonUtil.h @@ -181,6 +181,20 @@ namespace JsonUtil } } + /* For classes with one-parameter constructors, such as Steps */ + template + static void DeserializeVectorPointersParam(vector &v, void fn(T &, const Json::Value &), const Json::Value &root, const P param) + { + for(unsigned i=0; i static void DeserializeArrayValues(vector &v, const Json::Value &root) { diff --git a/src/NotesLoaderJson.cpp b/src/NotesLoaderJson.cpp index 1195ea413f..b09d564454 100644 --- a/src/NotesLoaderJson.cpp +++ b/src/NotesLoaderJson.cpp @@ -218,7 +218,7 @@ static void Deserialize( Song &out, const Json::Value &root ) { vector vpSteps; - JsonUtil::DeserializeVectorPointers( vpSteps, Deserialize, root["Charts"] ); + JsonUtil::DeserializeVectorPointersParam( vpSteps, Deserialize, root["Charts"], &out ); FOREACH( Steps*, vpSteps, iter ) out.AddSteps( *iter ); } diff --git a/src/NotesLoaderSMA.cpp b/src/NotesLoaderSMA.cpp index bb1bf09c46..43d5d08b50 100644 --- a/src/NotesLoaderSMA.cpp +++ b/src/NotesLoaderSMA.cpp @@ -301,7 +301,7 @@ bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach else { state = SMA_GETTING_STEP_INFO; - pNewNotes = new Steps; + pNewNotes = new Steps(&out); } } diff --git a/src/Song.cpp b/src/Song.cpp index c5da1cb5f0..5404507ad0 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -191,7 +191,7 @@ void Song::AddLyricSegment( LyricSegment seg ) Steps *Song::CreateSteps() { - Steps *pSteps = new Steps; + Steps *pSteps = new Steps(this); InitSteps( pSteps ); return pSteps; } @@ -415,7 +415,7 @@ bool Song::ReloadFromSongDir( RString sDir ) // The leftovers in the map are steps that didn't exist before we reverted for( map::const_iterator it = mNewSteps.begin(); it != mNewSteps.end(); ++it ) { - Steps *NewSteps = new Steps(); + Steps *NewSteps = new Steps(this); *NewSteps = *(it->second); AddSteps( NewSteps ); } @@ -1136,7 +1136,7 @@ void Song::AutoGen( StepsType ntTo, StepsType ntFrom ) const Steps* pOriginalNotes = m_vpSteps[j]; if( pOriginalNotes->m_StepsType == ntFrom ) { - Steps* pNewNotes = new Steps; + Steps* pNewNotes = new Steps(this); pNewNotes->AutogenFrom( pOriginalNotes, ntTo ); this->AddSteps( pNewNotes ); } diff --git a/src/Steps.cpp b/src/Steps.cpp index 9e53aed9a7..e1c0d9d31a 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -42,7 +42,7 @@ static const char *DisplayBPMNames[] = XToString( DisplayBPM ); LuaXType( DisplayBPM ); -Steps::Steps(): m_StepsType(StepsType_Invalid), m_pSong(NULL), +Steps::Steps(Song *song): m_StepsType(StepsType_Invalid), m_pSong(song), parent(NULL), m_pNoteData(new NoteData), m_bNoteDataIsFilled(false), m_sNoteDataCompressed(""), m_sFilename(""), m_bSavedToDisk(false), m_LoadedFromProfile(ProfileSlot_Invalid), m_iHash(0), @@ -465,6 +465,7 @@ void Steps::CopyFrom( Steps* pSource, StepsType ntTo, float fMusicLengthSeconds noteData.SetNumTracks( GAMEMAN->GetStepsTypeInfo(ntTo).iNumTracks ); parent = NULL; m_Timing = pSource->m_Timing; + this->m_pSong = pSource->m_pSong; this->m_Attacks = pSource->m_Attacks; this->m_sAttackString = pSource->m_sAttackString; this->SetNoteData( noteData ); diff --git a/src/Steps.h b/src/Steps.h index 6838ed55ed..95b179bcd1 100644 --- a/src/Steps.h +++ b/src/Steps.h @@ -42,7 +42,7 @@ class Steps { public: /** @brief Set up the Steps with initial values. */ - Steps(); + Steps( Song* song ); /** @brief Destroy the Steps that are no longer needed. */ ~Steps(); From 8815da5f1f32c325536f09d7582ffe76d32485dd Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 20 Jan 2013 19:51:59 -0500 Subject: [PATCH 05/11] replace SongManager::GetSongFromSteps with use of song pointer --- src/NotesLoaderBMS.cpp | 2 +- src/ScreenOptionsManageEditSteps.cpp | 8 ++++---- src/SongManager.cpp | 28 ++++------------------------ src/SongManager.h | 1 - src/SongUtil.cpp | 2 +- 5 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/NotesLoaderBMS.cpp b/src/NotesLoaderBMS.cpp index 4fd1ccc054..b1a2d44836 100644 --- a/src/NotesLoaderBMS.cpp +++ b/src/NotesLoaderBMS.cpp @@ -1243,7 +1243,7 @@ void BMSSongLoader::AddToSong() bool BMSLoader::LoadNoteDataFromSimfile( const RString & cachePath, Steps & out ) { - Song *pSong = SONGMAN->GetSongFromSteps( &out ); + Song *pSong = out.m_pSong; // before doing anything else, load the chart first! BMSChart chart; diff --git a/src/ScreenOptionsManageEditSteps.cpp b/src/ScreenOptionsManageEditSteps.cpp index f009ff6cbb..3a6b646bcb 100644 --- a/src/ScreenOptionsManageEditSteps.cpp +++ b/src/ScreenOptionsManageEditSteps.cpp @@ -87,7 +87,7 @@ void ScreenOptionsManageEditSteps::BeginScreen() vHands.push_back( OptionRowHandlerUtil::MakeNull() ); OptionRowDefinition &def = vHands.back()->m_Def; - Song *pSong = SONGMAN->GetSongFromSteps( *s ); + Song *pSong = (*s)->m_pSong; def.m_sName = pSong->GetTranslitFullTitle() + " - " + (*s)->GetDescription(); def.m_bAllowThemeTitle = false; // not themable @@ -153,7 +153,7 @@ void ScreenOptionsManageEditSteps::HandleScreenMessage( const ScreenMessage SM ) ASSERT( ScreenTextEntry::s_sLastAnswer != "" ); // validate should have assured this Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; - Song *pSong = SONGMAN->GetSongFromSteps( pSteps ); + Song *pSong = pSteps->m_pSong; RString sOldDescription = pSteps->GetDescription(); pSteps->SetDescription( ScreenTextEntry::s_sLastAnswer ); @@ -190,7 +190,7 @@ void ScreenOptionsManageEditSteps::HandleScreenMessage( const ScreenMessage SM ) case StepsEditAction_Edit: { Steps *pSteps = GetStepsWithFocus(); - Song *pSong = SONGMAN->GetSongFromSteps( pSteps ); + Song *pSong = pSteps->m_pSong; GAMESTATE->m_pCurSong.Set( pSong ); GAMESTATE->m_pCurSteps[PLAYER_1].Set( pSteps ); @@ -230,7 +230,7 @@ void ScreenOptionsManageEditSteps::HandleScreenMessage( const ScreenMessage SM ) void ScreenOptionsManageEditSteps::AfterChangeRow( PlayerNumber pn ) { Steps *pSteps = GetStepsWithFocus(); - Song *pSong = pSteps ? SONGMAN->GetSongFromSteps( pSteps ) : NULL; + Song *pSong = pSteps ? pSteps->m_pSong : NULL; GAMESTATE->m_pCurSong.Set( pSong ); GAMESTATE->m_pCurSteps[PLAYER_1].Set( pSteps ); diff --git a/src/SongManager.cpp b/src/SongManager.cpp index 0558824d46..4450f1db85 100644 --- a/src/SongManager.cpp +++ b/src/SongManager.cpp @@ -1127,30 +1127,9 @@ void SongManager::GetStepsLoadedFromProfile( vector &AddTo, ProfileSlot } } -Song *SongManager::GetSongFromSteps( Steps *pSteps ) const -{ - ASSERT( pSteps != NULL ); - const vector &vSongs = GetAllSongs(); - FOREACH_CONST( Song*, vSongs, song ) - { - vector vSteps; - SongUtil::GetSteps( *song, vSteps ); - - FOREACH_CONST( Steps*, vSteps, steps ) - { - if( *steps == pSteps ) - { - return *song; - } - } - } - FAIL_M("No song found for steps"); -} - void SongManager::DeleteSteps( Steps *pSteps ) { - Song *pSong = GetSongFromSteps( pSteps ); - pSong->DeleteSteps( pSteps ); + pSteps->m_pSong->DeleteSteps( pSteps ); } bool SongManager::WasLoadedFromAdditionalSongs( const Song *pSong ) const @@ -1942,11 +1921,12 @@ public: static int GetNumCourses( T* p, lua_State *L ) { lua_pushnumber( L, p->GetNumCourses() ); return 1; } static int GetNumAdditionalCourses( T* p, lua_State *L ){ lua_pushnumber( L, p->GetNumAdditionalCourses() ); return 1; } static int GetNumCourseGroups( T* p, lua_State *L ) { lua_pushnumber( L, p->GetNumCourseGroups() ); return 1; } + /* Note: this could now be implemented as Luna::GetSong */ static int GetSongFromSteps( T* p, lua_State *L ) { Song *pSong = NULL; - if( lua_isnil(L,1) ) { pSong = p->GetSongFromSteps( NULL ); } - else { Steps *pSteps = Luna::check(L,1); pSong = p->GetSongFromSteps( pSteps ); } + if( lua_isnil(L,1) ) { pSong = NULL; } + else { Steps *pSteps = Luna::check(L,1); pSong = pSteps->m_pSong; } if(pSong) pSong->PushSelf(L); else lua_pushnil(L); return 1; diff --git a/src/SongManager.h b/src/SongManager.h index 2ad3ff6ace..0ddb5bd69a 100644 --- a/src/SongManager.h +++ b/src/SongManager.h @@ -144,7 +144,6 @@ public: int GetSongRank(Song* pSong); void GetStepsLoadedFromProfile( vector &AddTo, ProfileSlot slot ) const; - Song *GetSongFromSteps( Steps *pSteps ) const; void DeleteSteps( Steps *pSteps ); // transfers ownership of pSteps bool WasLoadedFromAdditionalSongs( const Song *pSong ) const; bool WasLoadedFromAdditionalCourses( const Course *pCourse ) const; diff --git a/src/SongUtil.cpp b/src/SongUtil.cpp index 8b03b31233..eb57e74288 100644 --- a/src/SongUtil.cpp +++ b/src/SongUtil.cpp @@ -795,7 +795,7 @@ static LocalizedString EDIT_NAME_CANNOT_CONTAIN ( "SongUtil", "The edit name can bool SongUtil::ValidateCurrentEditStepsDescription( const RString &sAnswer, RString &sErrorOut ) { Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; - Song *pSong = SONGMAN->GetSongFromSteps( pSteps ); + Song *pSong = pSteps->m_pSong; ASSERT( pSteps->IsAnEdit() ); From 4385b9242d72d1071b380696b422964adfd61d4c Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 20 Jan 2013 21:12:11 -0500 Subject: [PATCH 06/11] Steps: add GetTimingData function that falls back on Song if necessary --- src/Steps.cpp | 5 +++++ src/Steps.h | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/Steps.cpp b/src/Steps.cpp index e1c0d9d31a..0c1de3112a 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -520,6 +520,11 @@ void Steps::SetMeter( int meter ) m_iMeter = meter; } +const TimingData *Steps::GetTimingData() const +{ + return m_Timing.empty() ? &m_pSong->m_SongTiming : &m_Timing; +} + bool Steps::HasSignificantTimingChanges() const { if( m_Timing.HasStops() || m_Timing.HasDelays() || m_Timing.HasWarps() || diff --git a/src/Steps.h b/src/Steps.h index 95b179bcd1..178a0ab725 100644 --- a/src/Steps.h +++ b/src/Steps.h @@ -157,6 +157,12 @@ public: * This is required to allow Split Timing. */ TimingData m_Timing; + /** + * @brief Retrieves the appropriate timing data for the Steps. Falls + * back on the Song if needed. */ + const TimingData *GetTimingData() const; + TimingData *GetTimingData() { return const_cast( static_cast( this )->GetTimingData() ); }; + /** * @brief Determine if the Steps have any major timing changes during gameplay. * @return true if it does, or false otherwise. */ From 234cbf4281975b41e307cbb34b1c4553caeda491 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 21 Jan 2013 22:53:12 -0500 Subject: [PATCH 07/11] ScreenEdit: add GetAppropriateStepsForUpdate function --- src/ScreenEdit.cpp | 98 ++++++++++++++++++++++++++-------------------- src/ScreenEdit.h | 5 ++- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index fd2993b437..8acd7e2e5d 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -1785,7 +1785,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) // does it mean in this case? return false; } - TimingData &sTiming = GetAppropriateTiming(); + const TimingData &sTiming = GetAppropriateTiming(); float playerBeat = GetAppropriatePosition().m_fSongBeat; int beatsPerMeasure = sTiming.GetTimeSignatureSegmentAtBeat( playerBeat )->GetNum(); @@ -2008,7 +2008,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) case EDIT_BUTTON_SEGMENT_NEXT: { // TODO: Work around Stops and Delays. We MAY have to separate them. - TimingData &timing = GetAppropriateTiming(); + const TimingData &timing = GetAppropriateTiming(); ScrollTo(timing.GetNextSegmentBeatAtBeat(this->currentCycleSegment, GetBeat())); } @@ -2016,7 +2016,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) case EDIT_BUTTON_SEGMENT_PREV: { // TODO: Work around Stops and Delays. We MAY have to separate them. - TimingData &timing = GetAppropriateTiming(); + const TimingData &timing = GetAppropriateTiming(); ScrollTo(timing.GetPreviousSegmentBeatAtBeat(this->currentCycleSegment, GetBeat())); } @@ -2189,7 +2189,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } float fNewBPM = fBPM + fDelta; - GetAppropriateTiming().SetBPMAtBeat( GetBeat(), fNewBPM ); + GetAppropriateTimingForUpdate().SetBPMAtBeat( GetBeat(), fNewBPM ); (fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play(); SetDirty( true ); } @@ -2217,7 +2217,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } // is there a StopSegment on the current row? - TimingData & timing = GetAppropriateTiming(); + TimingData & timing = GetAppropriateTimingForUpdate(); StopSegment *seg = timing.GetStopSegmentAtRow( GetRow() ); int i = timing.GetSegmentIndexAtRow(SEGMENT_STOP, GetRow()); if (i == -1 || seg->GetRow() != GetRow()) // invalid @@ -2263,7 +2263,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } // is there a StopSegment on the current row? - TimingData & timing = GetAppropriateTiming(); + TimingData & timing = GetAppropriateTimingForUpdate(); DelaySegment *seg = timing.GetDelaySegmentAtRow( GetRow() ); int i = timing.GetSegmentIndexAtRow(SEGMENT_DELAY, GetRow()); if (i == -1 || seg->GetRow() != GetRow()) // invalid @@ -2306,7 +2306,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) else fDelta *= 40; } - GetAppropriateTiming().m_fBeat0OffsetInSeconds += fDelta; + GetAppropriateTimingForUpdate().m_fBeat0OffsetInSeconds += fDelta; (fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play(); if (GAMESTATE->m_bIsUsingStepTiming) { @@ -2547,7 +2547,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } else { - TimingData &timing = GetAppropriateTiming(); + const TimingData &timing = GetAppropriateTiming(); start = timing.GetElapsedTimeFromBeat(NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker)); AttackArray &attacks = (GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks); @@ -2928,7 +2928,7 @@ bool ScreenEdit::InputPlay( const InputEventPlus &input, EditButton EditB ) fOffsetDelta *= 40; } - GetAppropriateTiming().m_fBeat0OffsetInSeconds += fOffsetDelta; + GetAppropriateTimingForUpdate().m_fBeat0OffsetInSeconds += fOffsetDelta; if (!GAMESTATE->m_bIsUsingStepTiming) { GAMESTATE->m_pCurSong->m_fMusicSampleStartSeconds += fOffsetDelta; @@ -3317,7 +3317,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) float fBPM = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fBPM > 0 ) - GetAppropriateTiming().AddSegment( BPMSegment(GetRow(), fBPM) ); + GetAppropriateTimingForUpdate().AddSegment( BPMSegment(GetRow(), fBPM) ); SetDirty( true ); } @@ -3326,7 +3326,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) float fStop = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fStop >= 0 ) - GetAppropriateTiming().AddSegment( StopSegment(GetRow(), fStop) ); + GetAppropriateTimingForUpdate().AddSegment( StopSegment(GetRow(), fStop) ); SetDirty( true ); } @@ -3335,7 +3335,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) float fDelay = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fDelay >= 0 ) - GetAppropriateTiming().AddSegment( DelaySegment(GetRow(), fDelay) ); + GetAppropriateTimingForUpdate().AddSegment( DelaySegment(GetRow(), fDelay) ); SetDirty( true ); } @@ -3344,7 +3344,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) int iNum, iDen; if( sscanf( ScreenTextEntry::s_sLastAnswer.c_str(), " %d / %d ", &iNum, &iDen ) == 2 ) - GetAppropriateTiming().AddSegment( TimeSignatureSegment(GetRow(), iNum, iDen) ); + GetAppropriateTimingForUpdate().AddSegment( TimeSignatureSegment(GetRow(), iNum, iDen) ); SetDirty( true ); } @@ -3353,7 +3353,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) int iTick = StringToInt( ScreenTextEntry::s_sLastAnswer ); if ( iTick >= 0 && iTick <= ROWS_PER_BEAT ) - GetAppropriateTiming().AddSegment( TickcountSegment( GetRow(), iTick) ); + GetAppropriateTimingForUpdate().AddSegment( TickcountSegment( GetRow(), iTick) ); SetDirty( true ); } @@ -3362,7 +3362,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) int iCombo, iMiss; if (sscanf(ScreenTextEntry::s_sLastAnswer.c_str(), " %d / %d ", &iCombo, &iMiss) == 2) - GetAppropriateTiming().AddSegment( ComboSegment(GetRow(), iCombo, iMiss) ); + GetAppropriateTimingForUpdate().AddSegment( ComboSegment(GetRow(), iCombo, iMiss) ); SetDirty( true ); } @@ -3375,7 +3375,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) // XXX: these should be in the NotesWriters where they're needed. sLabel.Replace("=", "_"); sLabel.Replace(",", "_"); - GetAppropriateTiming().AddSegment( LabelSegment(GetRow(), sLabel) ); + GetAppropriateTimingForUpdate().AddSegment( LabelSegment(GetRow(), sLabel) ); SetDirty( true ); } } @@ -3384,14 +3384,14 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) float fWarp = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fWarp >= 0 ) // allow 0 to kill a warp. { - GetAppropriateTiming().SetWarpAtBeat( GetBeat(), fWarp ); + GetAppropriateTimingForUpdate().SetWarpAtBeat( GetBeat(), fWarp ); SetDirty( true ); } } else if( SM == SM_BackFromSpeedPercentChange && !ScreenTextEntry::s_bCancelledLast ) { float fNum = StringToFloat( ScreenTextEntry::s_sLastAnswer ); - GetAppropriateTiming().SetSpeedPercentAtBeat( GetBeat(), fNum ); + GetAppropriateTimingForUpdate().SetSpeedPercentAtBeat( GetBeat(), fNum ); SetDirty( true ); } else if ( SM == SM_BackFromSpeedWaitChange && !ScreenTextEntry::s_bCancelledLast ) @@ -3399,7 +3399,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) float fDen = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fDen >= 0) { - GetAppropriateTiming().SetSpeedWaitAtBeat( GetBeat(), fDen ); + GetAppropriateTimingForUpdate().SetSpeedWaitAtBeat( GetBeat(), fDen ); } SetDirty( true ); } @@ -3407,11 +3407,11 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) { if( ScreenTextEntry::s_sLastAnswer.substr(0, 1) == "b" || ScreenTextEntry::s_sLastAnswer.substr(0, 1) == "B" ) { - GetAppropriateTiming().SetSpeedModeAtBeat( GetBeat(), SpeedSegment::UNIT_BEATS ); + GetAppropriateTimingForUpdate().SetSpeedModeAtBeat( GetBeat(), SpeedSegment::UNIT_BEATS ); } else if( ScreenTextEntry::s_sLastAnswer.substr(0, 1) == "s" || ScreenTextEntry::s_sLastAnswer.substr(0, 1) == "S" ) { - GetAppropriateTiming().SetSpeedModeAtBeat( GetBeat(), SpeedSegment::UNIT_SECONDS ); + GetAppropriateTimingForUpdate().SetSpeedModeAtBeat( GetBeat(), SpeedSegment::UNIT_SECONDS ); } else { @@ -3420,14 +3420,14 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) SpeedSegment::BaseUnit unit = (tmp == 0 ) ? SpeedSegment::UNIT_BEATS : SpeedSegment::UNIT_SECONDS; - GetAppropriateTiming().SetSpeedModeAtBeat( GetBeat(), unit ); + GetAppropriateTimingForUpdate().SetSpeedModeAtBeat( GetBeat(), unit ); } SetDirty( true ); } else if( SM == SM_BackFromScrollChange && !ScreenTextEntry::s_bCancelledLast ) { float fNum = StringToFloat( ScreenTextEntry::s_sLastAnswer ); - GetAppropriateTiming().SetScrollAtBeat( GetBeat(), fNum ); + GetAppropriateTimingForUpdate().SetScrollAtBeat( GetBeat(), fNum ); SetDirty( true ); } else if ( SM == SM_BackFromFakeChange && !ScreenTextEntry::s_bCancelledLast ) @@ -3435,7 +3435,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) float fFake = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fFake >= 0 ) // allow 0 to kill a fake. { - GetAppropriateTiming().AddSegment( FakeSegment(GetRow(), fFake) ); + GetAppropriateTimingForUpdate().AddSegment( FakeSegment(GetRow(), fFake) ); SetDirty( true ); } } @@ -3708,7 +3708,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) { int attackChoice = ScreenMiniMenu::s_iLastRowCode; int attackDecision = ScreenMiniMenu::s_viLastAnswers[attackChoice]; - TimingData &timing = GetAppropriateTiming(); + const TimingData &timing = GetAppropriateTiming(); float startTime = timing.GetElapsedTimeFromBeat(GetBeat()); AttackArray &attacks = (GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks); @@ -3784,7 +3784,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) else if (SM == SM_BackFromInsertStepAttack) { int iDurationChoice = ScreenMiniMenu::s_viLastAnswers[0]; - TimingData &timing = GetAppropriateTiming(); + const TimingData &timing = GetAppropriateTiming(); g_fLastInsertAttackPositionSeconds = timing.GetElapsedTimeFromBeat( GetBeat() ); g_fLastInsertAttackDurationSeconds = StringToFloat( g_InsertStepAttack.rows[0].choices[iDurationChoice] ); AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks; @@ -4174,7 +4174,7 @@ static void ChangeStepsMaxBPM(const RString &sNew) step->SetMaxBPM(StringToFloat(sNew)); } -TimingData & ScreenEdit::GetAppropriateTiming() const +const TimingData & ScreenEdit::GetAppropriateTiming() const { if( GAMESTATE->m_bIsUsingStepTiming ) { @@ -4183,6 +4183,18 @@ TimingData & ScreenEdit::GetAppropriateTiming() const return m_pSong->m_SongTiming; } +TimingData & ScreenEdit::GetAppropriateTimingForUpdate() +{ + if( GAMESTATE->m_bIsUsingStepTiming ) + { + // Copy from song if there is no step timing + if( m_pSteps->m_Timing.empty() ) + m_pSteps->m_Timing = m_pSong->m_SongTiming; + return m_pSteps->m_Timing; + } + return m_pSong->m_SongTiming; +} + SongPosition & ScreenEdit::GetAppropriatePosition() const { if (GAMESTATE->m_bIsUsingStepTiming) @@ -4223,7 +4235,7 @@ inline int ScreenEdit::GetRow() void ScreenEdit::DisplayTimingMenu() { int row = GetRow(); - TimingData &pTime = GetAppropriateTiming(); + const TimingData &pTime = GetAppropriateTiming(); bool bHasSpeedOnThisRow = pTime.GetSpeedSegmentAtRow( row )->GetRow() == row; // bool bIsSelecting = ( (m_NoteFieldEdit.m_iEndMarker != -1) && (m_NoteFieldEdit.m_iBeginMarker != -1) ); @@ -4713,7 +4725,7 @@ void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector &iAn NoteDataUtil::ScaleRegion( m_NoteDataEdit, fScale, iStartIndex, iEndIndex ); // scale timing data - GetAppropriateTiming().ScaleRegion(fScale, + GetAppropriateTimingForUpdate().ScaleRegion(fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker, true ); @@ -4755,9 +4767,9 @@ void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector &iAn m_NoteFieldEdit.m_iBeginMarker + 1, m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); - GetAppropriateTiming().DeleteRows( m_NoteFieldEdit.m_iBeginMarker + 1, + GetAppropriateTimingForUpdate().DeleteRows( m_NoteFieldEdit.m_iBeginMarker + 1, m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); - GetAppropriateTiming().SetStopAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); + GetAppropriateTimingForUpdate().SetStopAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); m_NoteFieldEdit.m_iBeginMarker = -1; m_NoteFieldEdit.m_iEndMarker = -1; break; @@ -4775,9 +4787,9 @@ void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector &iAn m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); - GetAppropriateTiming().DeleteRows( m_NoteFieldEdit.m_iBeginMarker, + GetAppropriateTimingForUpdate().DeleteRows( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); - GetAppropriateTiming().SetDelayAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); + GetAppropriateTimingForUpdate().SetDelayAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); m_NoteFieldEdit.m_iBeginMarker = -1; m_NoteFieldEdit.m_iEndMarker = -1; break; @@ -4786,7 +4798,7 @@ void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector &iAn { float startBeat = NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker); float lengthBeat = NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) - startBeat; - GetAppropriateTiming().SetWarpAtBeat(startBeat,lengthBeat); + GetAppropriateTimingForUpdate().SetWarpAtBeat(startBeat,lengthBeat); SetDirty(true); break; } @@ -4794,7 +4806,7 @@ void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector &iAn { float startBeat = NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker); float endBeat = NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker); - TimingData &timing = GetAppropriateTiming(); + const TimingData &timing = GetAppropriateTiming(); float &start = g_fLastInsertAttackPositionSeconds; float &length = g_fLastInsertAttackDurationSeconds; start = timing.GetElapsedTimeFromBeat(startBeat); @@ -4819,7 +4831,7 @@ void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector &iAn { int startRow = m_NoteFieldEdit.m_iBeginMarker; float lengthBeat = NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) - NoteRowToBeat(startRow); - GetAppropriateTiming().AddSegment( FakeSegment(startRow,lengthBeat) ); + GetAppropriateTimingForUpdate().AddSegment( FakeSegment(startRow,lengthBeat) ); SetDirty(true); break; } @@ -4962,12 +4974,12 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns NoteTypeToRow((NoteType)iAnswers[c]) : 48); break; case shift_pauses_forward: - GetAppropriateTiming().InsertRows( GetRow(), + GetAppropriateTimingForUpdate().InsertRows( GetRow(), iAnswers.size() > 0 ? NoteTypeToRow((NoteType)iAnswers[c]) : 48); break; case shift_pauses_backward: - GetAppropriateTiming().DeleteRows( GetRow() + 1, + GetAppropriateTimingForUpdate().DeleteRows( GetRow() + 1, iAnswers.size() > 0 ? NoteTypeToRow((NoteType)iAnswers[c]) : 48); break; @@ -4975,18 +4987,18 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns case convert_pause_to_beat: { float fStopSeconds = GetAppropriateTiming().GetStopAtRow(GetRow()); - GetAppropriateTiming().SetStopAtBeat( GetBeat() , 0 ); + GetAppropriateTimingForUpdate().SetStopAtBeat( GetBeat() , 0 ); float fStopBeats = fStopSeconds * GetAppropriateTiming().GetBPMAtBeat( GetBeat() ) / 60; // don't move the step from where it is, just move everything later NoteDataUtil::InsertRows( m_NoteDataEdit, GetRow() + 1, BeatToNoteRow(fStopBeats) ); - GetAppropriateTiming().InsertRows( GetRow() + 1, BeatToNoteRow(fStopBeats) ); + GetAppropriateTimingForUpdate().InsertRows( GetRow() + 1, BeatToNoteRow(fStopBeats) ); } break; case convert_delay_to_beat: { - TimingData &timing = GetAppropriateTiming(); + TimingData &timing = GetAppropriateTimingForUpdate(); float pause = timing.GetDelayAtRow(GetRow()); timing.SetDelayAtRow(GetRow(), 0); @@ -4998,7 +5010,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns } case last_second_at_beat: { - TimingData &timing = GetAppropriateTiming(); + const TimingData &timing = GetAppropriateTiming(); Song &s = *GAMESTATE->m_pCurSong; s.SetSpecifiedLastSecond(timing.GetElapsedTimeFromBeat(GetBeat())); break; @@ -5778,7 +5790,7 @@ static RString GetDeviceButtonsLocalized( const vector &veb, const M void ScreenEdit::DoStepAttackMenu() { - TimingData &timing = GetAppropriateTiming(); + const TimingData &timing = GetAppropriateTiming(); float startTime = timing.GetElapsedTimeFromBeat(GetBeat()); AttackArray &attacks = (GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks); diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index a7a0b2b01a..f73679fbbd 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -682,7 +682,10 @@ private: /** * @brief Retrieve the appropriate TimingData based on GAMESTATE. * @return the proper TimingData. */ - TimingData & GetAppropriateTiming() const; + const TimingData & GetAppropriateTiming() const; + /** + * @brief Retrieve the appropriate TimingData to use for updating. */ + TimingData & GetAppropriateTimingForUpdate(); /** * @brief Retrieve the appropriate SongPosition data based on GAMESTATE. * @return the proper SongPosition. */ From 3d6f1c522741a8bf584b6c07f5b7c9b3e8336535 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 21 Jan 2013 23:13:38 -0500 Subject: [PATCH 08/11] ScreenEdit: handle beat-0 offset the same as other timing data --- src/ScreenEdit.cpp | 53 +++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 8acd7e2e5d..207f554987 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -86,6 +86,7 @@ AutoScreenMessage( SM_DoRevertToLastSave ); AutoScreenMessage( SM_DoRevertFromDisk ); AutoScreenMessage( SM_BackFromTimingDataInformation ); AutoScreenMessage( SM_BackFromDifficultyMeterChange ); +AutoScreenMessage( SM_BackFromBeat0Change ); AutoScreenMessage( SM_BackFromBPMChange ); AutoScreenMessage( SM_BackFromStopChange ); AutoScreenMessage( SM_BackFromDelayChange ); @@ -3312,6 +3313,27 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) GAMESTATE->m_pCurSteps[PLAYER_1]->SetMeter(i); SetDirty( true ); } + else if( SM == SM_BackFromBeat0Change && !ScreenTextEntry::s_bCancelledLast ) + { + float fBeat0 = StringToFloat( ScreenTextEntry::s_sLastAnswer ); + + TimingData &timing = GetAppropriateTimingForUpdate(); + float old = timing.m_fBeat0OffsetInSeconds; + timing.m_fBeat0OffsetInSeconds = fBeat0; + float delta = timing.m_fBeat0OffsetInSeconds - old; + + if (GAMESTATE->m_bIsUsingStepTiming) + { + GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks.UpdateStartTimes(delta); + } + else + { + GAMESTATE->m_pCurSong->m_Attacks.UpdateStartTimes(delta); + GAMESTATE->m_pCurSong->m_fMusicSampleStartSeconds += delta; + } + + SetDirty( true ); + } else if( SM == SM_BackFromBPMChange && !ScreenTextEntry::s_bCancelledLast ) { float fBPM = StringToFloat( ScreenTextEntry::s_sLastAnswer ); @@ -4116,26 +4138,6 @@ static void ChangeArtistTranslit( const RString &sNew ) pSong->m_sArtistTranslit = sNew; } -static void ChangeBeat0Offset( const RString &sNew ) -{ - TimingData &timing = (GAMESTATE->m_bIsUsingStepTiming ? - GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing : - GAMESTATE->m_pCurSong->m_SongTiming); - float old = timing.m_fBeat0OffsetInSeconds; - timing.m_fBeat0OffsetInSeconds = StringToFloat(sNew); - float delta = timing.m_fBeat0OffsetInSeconds - old; - - if (GAMESTATE->m_bIsUsingStepTiming) - { - GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks.UpdateStartTimes(delta); - } - else - { - GAMESTATE->m_pCurSong->m_Attacks.UpdateStartTimes(delta); - GAMESTATE->m_pCurSong->m_fMusicSampleStartSeconds += delta; - } -} - static void ChangeLastSecondHint( const RString &sNew ) { Song &s = *GAMESTATE->m_pCurSong; @@ -5231,11 +5233,14 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice { DEFAULT_FAIL( c ); case beat_0_offset: - ScreenTextEntry::TextEntry( SM_None, ENTER_BEAT_0_OFFSET, - FloatToString(GetAppropriateTiming().m_fBeat0OffsetInSeconds), 20, - ScreenTextEntry::FloatValidate, ChangeBeat0Offset, NULL ); + ScreenTextEntry::TextEntry( + SM_BackFromBeat0Change, + ENTER_BEAT_0_OFFSET, + FloatToString(GetAppropriateTiming().m_fBeat0OffsetInSeconds), + 20 + ); break; - case bpm: + case bpm: ScreenTextEntry::TextEntry( SM_BackFromBPMChange, ENTER_BPM_VALUE, From 0ae7b0da85e7881437d96108a2cd9490a93f11aa Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 23 Jan 2013 14:38:57 -0500 Subject: [PATCH 09/11] TimingData: add allowEmpty parameter to TidyUpData. always false for now... --- src/NotesLoaderBMS.cpp | 2 +- src/ScreenHowToPlay.cpp | 2 +- src/Song.cpp | 4 ++-- src/TimingData.cpp | 7 ++++++- src/TimingData.h | 4 +++- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/NotesLoaderBMS.cpp b/src/NotesLoaderBMS.cpp index b1a2d44836..ef49a5130c 100644 --- a/src/NotesLoaderBMS.cpp +++ b/src/NotesLoaderBMS.cpp @@ -1002,7 +1002,7 @@ bool BMSChartReader::ReadNoteData() delete holdStart; delete lastNote; - td.TidyUpData(); + td.TidyUpData( false ); out->SetNoteData(nd); out->m_Timing = td; out->TidyUpData(); diff --git a/src/ScreenHowToPlay.cpp b/src/ScreenHowToPlay.cpp index 16d5ae3f62..ef5062c891 100644 --- a/src/ScreenHowToPlay.cpp +++ b/src/ScreenHowToPlay.cpp @@ -151,7 +151,7 @@ void ScreenHowToPlay::Init() Steps *pSteps = SongUtil::GetClosestNotes( &m_Song, pStyle->m_StepsType, Difficulty_Beginner ); ASSERT_M( pSteps != NULL, ssprintf("No playable steps of StepsType '%s' for ScreenHowToPlay", StringConversion::ToString(pStyle->m_StepsType).c_str()) ); - pSteps->m_Timing.TidyUpData(); + pSteps->m_Timing.TidyUpData( false ); NoteData tempNoteData; pSteps->GetNoteData( tempNoteData ); pStyle->GetTransformedNoteDataForStyle( PLAYER_1, tempNoteData, m_NoteData ); diff --git a/src/Song.cpp b/src/Song.cpp index 5404507ad0..f189c7f454 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -537,11 +537,11 @@ void Song::TidyUpData( bool fromCache, bool /* duringCache */ ) m_fMusicLengthSeconds = 0; } - m_SongTiming.TidyUpData(); + m_SongTiming.TidyUpData( false ); FOREACH( Steps *, m_vpSteps, s ) { - (*s)->m_Timing.TidyUpData(); + (*s)->m_Timing.TidyUpData( false ); } /* Generate these before we autogen notes, so the new notes can inherit diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 9fb9668cce..02653f81b8 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -863,8 +863,13 @@ float TimingData::GetDisplayedSpeedPercent( float fSongBeat, float fMusicSeconds } -void TimingData::TidyUpData() +void TimingData::TidyUpData(bool allowEmpty) { + // Empty TimingData is used to implement steps with no timing of their + // own. Don't override this. + if( allowEmpty && empty() ) + return; + // If there are no BPM segments, provide a default. vector *segs = m_avpTimingSegments; if( segs[SEGMENT_BPM].empty() ) diff --git a/src/TimingData.h b/src/TimingData.h index 4478fa6fd1..7fd1acdcd1 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -378,8 +378,10 @@ public: /** * @brief Tidy up the timing data, e.g. provide default BPMs, labels, tickcounts. + * @param allowEmpty true if completely empty TimingData should be left + * alone, false if it should be changed */ - void TidyUpData(); + void TidyUpData(bool allowEmpty); // Lua void PushSelf( lua_State *L ); From ce507b98001629f842e756354f43abd66f8c2dbc Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 23 Jan 2013 14:51:18 -0500 Subject: [PATCH 10/11] use empty TimingData in Steps to signify fallback on Song timing. This required using the new Steps::GetTimingData function and the allowEmpty parameter to TimingData::TidyUpData when appropriate, as well as clearing the TimingData to remove step timing rather than coping the song timing over it. Fixes some odd editor behavior when changing song timing, and is overall a slightly less hacky way of doing things. --- src/AdjustSync.cpp | 4 ++++ src/ArrowEffects.cpp | 4 ++-- src/AutoKeysounds.cpp | 2 +- src/BPMDisplay.cpp | 2 +- src/GameState.cpp | 2 +- src/GameplayAssist.cpp | 2 +- src/NotesWriterSSC.cpp | 5 +++-- src/Player.cpp | 2 +- src/PlayerState.cpp | 7 ++++--- src/ScoreKeeperNormal.cpp | 8 ++++---- src/ScreenEdit.cpp | 33 ++++++++++++++++++--------------- src/ScreenGameplay.cpp | 2 +- src/ScreenHowToPlay.cpp | 3 ++- src/ScreenSelectMusic.cpp | 2 +- src/ScreenSyncOverlay.cpp | 8 ++++++++ src/Song.cpp | 11 ++++++----- src/Steps.cpp | 13 +++++++------ src/Trail.cpp | 2 +- 18 files changed, 66 insertions(+), 46 deletions(-) diff --git a/src/AdjustSync.cpp b/src/AdjustSync.cpp index 7d410dad42..fb88d39475 100644 --- a/src/AdjustSync.cpp +++ b/src/AdjustSync.cpp @@ -216,6 +216,10 @@ void AdjustSync::AutosyncOffset() const vector& vpSteps = GAMESTATE->m_pCurSong->GetAllSteps(); FOREACH( Steps*, const_cast&>(vpSteps), s ) { + // Empty TimingData means it's inherited + // from the song and is already changed. + if( (*s)->m_Timing.empty() ) + continue; (*s)->m_Timing.m_fBeat0OffsetInSeconds += mean; } break; diff --git a/src/ArrowEffects.cpp b/src/ArrowEffects.cpp index ad1ff53648..e0513eb8ba 100644 --- a/src/ArrowEffects.cpp +++ b/src/ArrowEffects.cpp @@ -262,7 +262,7 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float fBeatsUntilStep = GetDisplayedBeat(pPlayerState, fNoteBeat) - GetDisplayedBeat(pPlayerState, fSongBeat); float fYOffsetBeatSpacing = fBeatsUntilStep; float fSpeedMultiplier = bShowEffects ? - pCurSteps->m_Timing.GetDisplayedSpeedPercent( + pCurSteps->GetTimingData()->GetDisplayedSpeedPercent( position.m_fSongBeatVisible, position.m_fMusicSecondsVisible ) : 1.0f; fYOffset += fSpeedMultiplier * fYOffsetBeatSpacing * (1-pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing); @@ -271,7 +271,7 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float if( pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing != 0.0f ) { float fSongSeconds = GAMESTATE->m_Position.m_fMusicSecondsVisible; - float fNoteSeconds = pCurSteps->m_Timing.GetElapsedTimeFromBeat(fNoteBeat); + float fNoteSeconds = pCurSteps->GetTimingData()->GetElapsedTimeFromBeat(fNoteBeat); float fSecondsUntilStep = fNoteSeconds - fSongSeconds; float fBPM = pPlayerState->m_PlayerOptions.GetCurrent().m_fScrollBPM; float fBPS = fBPM/60.f; diff --git a/src/AutoKeysounds.cpp b/src/AutoKeysounds.cpp index 97968228da..e7fcf31f2b 100644 --- a/src/AutoKeysounds.cpp +++ b/src/AutoKeysounds.cpp @@ -103,7 +103,7 @@ void AutoKeysounds::LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain ) if( tn[pn].iKeysoundIndex >= 0 ) { RString sKeysoundFilePath = sSongDir + pSong->m_vsKeysoundFile[tn[pn].iKeysoundIndex]; - float fSeconds = GAMESTATE->m_pCurSteps[pn]->m_Timing.GetElapsedTimeFromBeatNoOffset( NoteRowToBeat(iRow) ) + SOUNDMAN->GetPlayLatency(); + float fSeconds = GAMESTATE->m_pCurSteps[pn]->GetTimingData()->GetElapsedTimeFromBeatNoOffset( NoteRowToBeat(iRow) ) + SOUNDMAN->GetPlayLatency(); float fPan = 0; if( !bSoundIsGlobal ) diff --git a/src/BPMDisplay.cpp b/src/BPMDisplay.cpp index f6e3cae00c..c2e29c99d8 100644 --- a/src/BPMDisplay.cpp +++ b/src/BPMDisplay.cpp @@ -204,7 +204,7 @@ void BPMDisplay::SetBpmFromSteps( const Steps* pSteps ) ASSERT( pSteps != NULL ); DisplayBpms bpms; float fMinBPM, fMaxBPM; - pSteps->m_Timing.GetActualBPM( fMinBPM, fMaxBPM ); + pSteps->GetTimingData()->GetActualBPM( fMinBPM, fMaxBPM ); bpms.Add( fMinBPM ); bpms.Add( fMaxBPM ); m_fCycleTime = 1.0f; diff --git a/src/GameState.cpp b/src/GameState.cpp index 4b966aa990..7da1e2dd0a 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -985,7 +985,7 @@ void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &ti { if( m_pCurSteps[pn] ) { - m_pPlayerState[pn]->m_Position.UpdateSongPosition( fPositionSeconds, m_pCurSteps[pn]->m_Timing, timestamp ); + m_pPlayerState[pn]->m_Position.UpdateSongPosition( fPositionSeconds, *m_pCurSteps[pn]->GetTimingData(), timestamp ); Actor::SetPlayerBGMBeat( pn, m_pPlayerState[pn]->m_Position.m_fSongBeatVisible, m_pPlayerState[pn]->m_Position.m_fSongBeatNoOffset ); } } diff --git a/src/GameplayAssist.cpp b/src/GameplayAssist.cpp index 66fe7398c9..9334470812 100644 --- a/src/GameplayAssist.cpp +++ b/src/GameplayAssist.cpp @@ -34,7 +34,7 @@ void GameplayAssist::PlayTicks( const NoteData &nd, const PlayerState *ps ) //float fPositionSeconds = GAMESTATE->m_Position.m_fMusicSeconds; fPositionSeconds += SOUNDMAN->GetPlayLatency() + (float)CommonMetrics::TICK_EARLY_SECONDS + 0.250f; - const TimingData &timing = GAMESTATE->m_pCurSteps[ps->m_PlayerNumber]->m_Timing; + const TimingData &timing = *GAMESTATE->m_pCurSteps[ps->m_PlayerNumber]->GetTimingData(); const float fSongBeat = timing.GetBeatFromElapsedTimeNoOffset( fPositionSeconds ); const int iSongRow = max( 0, BeatToNoteRowNotRounded( fSongBeat ) ); diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index 17db0285a4..d15a599709 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -369,8 +369,9 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa lines.push_back( ssprintf( "#CREDIT:%s;", SmEscape(in.GetCredit()).c_str() ) ); - // XXX: Is there a better way to write this? - if (const_cast(song.m_SongTiming) != in.m_Timing) + // If the Steps TimingData is not empty, then they have their own + // timing. Write out the corresponding tags. + if( !in.m_Timing.empty() ) { lines.push_back( ssprintf( "#OFFSET:%.f;", in.m_Timing.m_fBeat0OffsetInSeconds ) ); GetTimingTags( lines, in.m_Timing ); diff --git a/src/Player.cpp b/src/Player.cpp index 4d3b7f157f..b158a19ee8 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -659,7 +659,7 @@ void Player::Load() const Song* pSong = GAMESTATE->m_pCurSong; - m_Timing = &GAMESTATE->m_pCurSteps[pn]->m_Timing; + m_Timing = GAMESTATE->m_pCurSteps[pn]->GetTimingData(); // Generate some cache data structure. GenerateCacheDataStructure(m_pPlayerState, m_NoteData); diff --git a/src/PlayerState.cpp b/src/PlayerState.cpp index 68016ebb34..23dee44b62 100644 --- a/src/PlayerState.cpp +++ b/src/PlayerState.cpp @@ -199,9 +199,10 @@ const SongPosition &PlayerState::GetDisplayedPosition() const const TimingData &PlayerState::GetDisplayedTiming() const { - if( GAMESTATE->m_bIsUsingStepTiming && GAMESTATE->m_pCurSteps[m_PlayerNumber] != NULL ) - return GAMESTATE->m_pCurSteps[m_PlayerNumber]->m_Timing; - return GAMESTATE->m_pCurSong->m_SongTiming; + Steps *steps = GAMESTATE->m_pCurSteps[m_PlayerNumber]; + if( steps == NULL ) + return GAMESTATE->m_pCurSong->m_SongTiming; + return *steps->GetTimingData(); } diff --git a/src/ScoreKeeperNormal.cpp b/src/ScoreKeeperNormal.cpp index 62743275db..3fe433e76c 100644 --- a/src/ScoreKeeperNormal.cpp +++ b/src/ScoreKeeperNormal.cpp @@ -122,7 +122,7 @@ void ScoreKeeperNormal::Load( * forced and not chosen by the user. */ NoteDataUtil::TransformNoteData( nd, aa, pSteps->m_StepsType, pSong ); RadarValues rvPre; - GAMESTATE->SetProcessedTimingData(&pSteps->m_Timing); + GAMESTATE->SetProcessedTimingData(pSteps->GetTimingData()); NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPre ); /* Apply user transforms to find out how the notes will really look. @@ -283,7 +283,7 @@ void ScoreKeeperNormal::HandleTapNoteScoreInternal( TapNoteScore tns, TapNoteSco m_pPlayerStageStats->m_iActualDancePoints += TapNoteScoreToDancePoints( tns ); // update judged row totals. Respect Combo segments here. - TimingData &td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; + TimingData &td = *GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->GetTimingData(); ComboSegment *cs = td.GetComboSegmentAtRow(row); if (tns == TNS_CheckpointHit || tns >= m_MinScoreToContinueCombo) { @@ -316,7 +316,7 @@ void ScoreKeeperNormal::HandleComboInternal( int iNumHitContinueCombo, int iNumH { m_pPlayerStageStats->m_iCurMissCombo = 0; } - TimingData &td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; + TimingData &td = *GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->GetTimingData(); if( iNumBreakCombo == 0 ) { int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow )->GetCombo() ); @@ -336,7 +336,7 @@ void ScoreKeeperNormal::HandleRowComboInternal( TapNoteScore tns, int iNumTapsIn { iNumTapsInRow = min( iNumTapsInRow, 1); } - TimingData &td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; + TimingData &td = *GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->GetTimingData(); if ( tns >= m_MinScoreToContinueCombo ) { m_pPlayerStageStats->m_iCurMissCombo = 0; diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 207f554987..8a31f4e610 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -1375,7 +1375,7 @@ void ScreenEdit::Update( float fDeltaTime ) continue; float fStartedHoldingSeconds = m_pSoundMusic->GetPositionSeconds() - fSecsHeld; - float fStartBeat = max( fStartPlayingAtBeat, m_pSteps->m_Timing.GetBeatFromElapsedTime(fStartedHoldingSeconds) ); + float fStartBeat = max( fStartPlayingAtBeat, m_pSteps->GetTimingData()->GetBeatFromElapsedTime(fStartedHoldingSeconds) ); float fEndBeat = max( fStartBeat, GetBeat() ); fEndBeat = min( fEndBeat, fStopPlayingAtBeat ); @@ -1420,11 +1420,11 @@ void ScreenEdit::Update( float fDeltaTime ) float fLastBeat = NoteRowToBeat(m_iStopPlayingAt); if( bButtonIsBeingPressed && m_EditState == STATE_RECORDING ) { - float fSeconds = m_pSteps->m_Timing.GetElapsedTimeFromBeat( fLastBeat ); - fLastBeat = m_pSteps->m_Timing.GetBeatFromElapsedTime( fSeconds + 0.5f ); + float fSeconds = m_pSteps->GetTimingData()->GetElapsedTimeFromBeat( fLastBeat ); + fLastBeat = m_pSteps->GetTimingData()->GetBeatFromElapsedTime( fSeconds + 0.5f ); } - float fStopAtSeconds = m_pSteps->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_iStopPlayingAt) ) + 1; + float fStopAtSeconds = m_pSteps->GetTimingData()->GetElapsedTimeFromBeat( NoteRowToBeat(m_iStopPlayingAt) ) + 1; if( GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fMusicSeconds > fStopAtSeconds ) { TransitionEditState( ( LOOP_ON_CHART_END ? STATE_PLAYING : STATE_EDITING ) ); @@ -1601,7 +1601,7 @@ void ScreenEdit::UpdateTextInfo() sText += ssprintf("Attack here?: %s\n", FindAttackAtTime(attacks, beat) > -1 ? "YES" : "NO"); } - GAMESTATE->SetProcessedTimingData(&m_pSteps->m_Timing); + GAMESTATE->SetProcessedTimingData(m_pSteps->GetTimingData()); const StepsTypeCategory &cat = GAMEMAN->GetStepsTypeInfo(m_pSteps->m_StepsType).m_StepsTypeCategory; if (cat == StepsTypeCategory_Couple || cat == StepsTypeCategory_Routine) { @@ -2512,7 +2512,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) if( pCourse == NULL ) return false; CourseEntry &ce = pCourse->m_vEntries[GAMESTATE->m_iEditCourseEntryIndex]; - float fStartTime = m_pSteps->m_Timing.GetElapsedTimeFromBeat( GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat ); + float fStartTime = m_pSteps->GetTimingData()->GetElapsedTimeFromBeat( GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat ); int iAttack = FindAttackAtTime( ce.attacks, fStartTime ); if( iAttack >= 0 ) @@ -2594,7 +2594,8 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) else { // TODO: Give Song/Step Timing switches/functions here? - fStart = m_pSteps->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); + TimingData *timing = m_pSteps->GetTimingData(); + fStart = timing->GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); int iAttack = FindAttackAtTime( ce.attacks, fStart ); if( iAttack >= 0 ) @@ -2603,7 +2604,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) if( m_NoteFieldEdit.m_iEndMarker == -1 ) fEnd = m_pSong->m_fMusicLengthSeconds; else - fEnd = m_pSteps->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); + fEnd = timing->GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); } g_fLastInsertAttackPositionSeconds = fStart; g_fLastInsertAttackDurationSeconds = fEnd - fStart; @@ -3049,8 +3050,10 @@ void ScreenEdit::TransitionEditState( EditState em ) if (!GAMESTATE->m_bIsUsingStepTiming) { + // Substitute the song timing for the step timing during + // previuw if we're in song mode backupStepTiming = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing; - GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing = GAMESTATE->m_pCurSong->m_SongTiming; + GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing.Clear(); } /* Reset the note skin, in case preferences have changed. */ @@ -3839,7 +3842,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) // TODO: Handle Song/Step Timing functions/switches here? - g_fLastInsertAttackPositionSeconds = m_pSteps->m_Timing.GetElapsedTimeFromBeat( GAMESTATE->m_Position.m_fSongBeat ); + g_fLastInsertAttackPositionSeconds = m_pSteps->GetTimingData()->GetElapsedTimeFromBeat( GAMESTATE->m_Position.m_fSongBeat ); g_fLastInsertAttackDurationSeconds = StringToFloat( g_InsertCourseAttack.rows[0].choices[iDurationChoice] ); iAttack = FindAttackAtTime( ce.attacks, g_fLastInsertAttackPositionSeconds ); @@ -3935,7 +3938,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) if( ScreenPrompt::s_LastAnswer == ANSWER_YES ) { SaveUndo(); - m_pSteps->m_Timing = m_pSong->m_SongTiming; + m_pSteps->m_Timing.Clear(); SetDirty( true ); } } @@ -4180,7 +4183,7 @@ const TimingData & ScreenEdit::GetAppropriateTiming() const { if( GAMESTATE->m_bIsUsingStepTiming ) { - return m_pSteps->m_Timing; + return *m_pSteps->GetTimingData(); } return m_pSong->m_SongTiming; } @@ -4211,12 +4214,12 @@ inline void ScreenEdit::SetBeat(float fBeat) if( !GAMESTATE->m_bIsUsingStepTiming ) { GAMESTATE->m_Position.m_fSongBeat = fBeat; - GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = m_pSteps->m_Timing.GetBeatFromElapsedTime(m_pSong->m_SongTiming.GetElapsedTimeFromBeat(fBeat)); + GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = m_pSteps->GetTimingData()->GetBeatFromElapsedTime(m_pSong->m_SongTiming.GetElapsedTimeFromBeat(fBeat)); } else { GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat = fBeat; - GAMESTATE->m_Position.m_fSongBeat = m_pSong->m_SongTiming.GetBeatFromElapsedTime(m_pSteps->m_Timing.GetElapsedTimeFromBeat(fBeat)); + GAMESTATE->m_Position.m_fSongBeat = m_pSong->m_SongTiming.GetBeatFromElapsedTime(m_pSteps->GetTimingData()->GetElapsedTimeFromBeat(fBeat)); } } @@ -4285,7 +4288,7 @@ static LocalizedString SAVE_CHANGES_BEFORE_EXITING ( "ScreenEdit", "Do you want void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAnswers ) { - GAMESTATE->SetProcessedTimingData(&m_pSteps->m_Timing); + GAMESTATE->SetProcessedTimingData(m_pSteps->GetTimingData()); switch( c ) { DEFAULT_FAIL( c ); diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index 2db7247365..71a7035b32 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -2340,7 +2340,7 @@ void ScreenGameplay::SaveStats() const NoteData &nd = pi->m_pPlayer->GetNoteData(); PlayerNumber pn = pi->m_pn; - GAMESTATE->SetProcessedTimingData(&GAMESTATE->m_pCurSteps[pn]->m_Timing); + GAMESTATE->SetProcessedTimingData(GAMESTATE->m_pCurSteps[pn]->GetTimingData()); NoteDataUtil::CalculateRadarValues( nd, fMusicLen, rv ); pss.m_radarPossible += rv; NoteDataWithScoring::GetActualRadarValues( nd, pss, fMusicLen, rv ); diff --git a/src/ScreenHowToPlay.cpp b/src/ScreenHowToPlay.cpp index ef5062c891..2daf79084e 100644 --- a/src/ScreenHowToPlay.cpp +++ b/src/ScreenHowToPlay.cpp @@ -151,7 +151,8 @@ void ScreenHowToPlay::Init() Steps *pSteps = SongUtil::GetClosestNotes( &m_Song, pStyle->m_StepsType, Difficulty_Beginner ); ASSERT_M( pSteps != NULL, ssprintf("No playable steps of StepsType '%s' for ScreenHowToPlay", StringConversion::ToString(pStyle->m_StepsType).c_str()) ); - pSteps->m_Timing.TidyUpData( false ); + m_Song.m_SongTiming.TidyUpData( false ); + pSteps->m_Timing.TidyUpData( true ); NoteData tempNoteData; pSteps->GetNoteData( tempNoteData ); pStyle->GetTransformedNoteDataForStyle( PLAYER_1, tempNoteData, m_NoteData ); diff --git a/src/ScreenSelectMusic.cpp b/src/ScreenSelectMusic.cpp index c5eaa06bda..c79f889da4 100644 --- a/src/ScreenSelectMusic.cpp +++ b/src/ScreenSelectMusic.cpp @@ -1779,7 +1779,7 @@ void ScreenSelectMusic::AfterMusicChange() if(SAMPLE_MUSIC_PREVIEW_MODE == SampleMusicPreviewMode_LastSong) { m_sSampleMusicToPlay = pSong->GetMusicPath(); - m_pSampleMusicTimingData = &pSong->m_Timing; + m_pSampleMusicTimingData = &pSong->m_SongTiming; m_fSampleStartSeconds = pSong->m_fMusicSampleStartSeconds; m_fSampleLengthSeconds = pSong->m_fMusicSampleLengthSeconds; } diff --git a/src/ScreenSyncOverlay.cpp b/src/ScreenSyncOverlay.cpp index bd556266d0..b0ba604e4b 100644 --- a/src/ScreenSyncOverlay.cpp +++ b/src/ScreenSyncOverlay.cpp @@ -233,6 +233,10 @@ bool ScreenSyncOverlay::Input( const InputEventPlus &input ) FOREACH( Steps*, const_cast&>(vpSteps), s ) { TimingData &pTiming = (*s)->m_Timing; + // Empty means it inherits song timing, + // which has already been updated. + if( pTiming.empty() ) + continue; float second = sTiming.GetElapsedTimeFromBeat(GAMESTATE->m_Position.m_fSongBeat); seg = pTiming.GetBPMSegmentAtBeat(pTiming.GetBeatFromElapsedTime(second)); seg->SetBPS( seg->GetBPS() + fDelta ); @@ -278,6 +282,10 @@ bool ScreenSyncOverlay::Input( const InputEventPlus &input ) const vector& vpSteps = GAMESTATE->m_pCurSong->GetAllSteps(); FOREACH( Steps*, const_cast&>(vpSteps), s ) { + // Empty means it inherits song timing, + // which has already been updated. + if( (*s)->m_Timing.empty() ) + continue; (*s)->m_Timing.m_fBeat0OffsetInSeconds += fDelta; } } diff --git a/src/Song.cpp b/src/Song.cpp index f189c7f454..5d0d16eac9 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -198,7 +198,7 @@ Steps *Song::CreateSteps() void Song::InitSteps(Steps *pSteps) { - pSteps->m_Timing = this->m_SongTiming; + // TimingData is initially empty (i.e. defaults to song timing) pSteps->m_sAttackString = this->m_sAttackString; pSteps->m_Attacks = this->m_Attacks; pSteps->SetDisplayBPM(this->m_DisplayBPMType); @@ -541,7 +541,7 @@ void Song::TidyUpData( bool fromCache, bool /* duringCache */ ) FOREACH( Steps *, m_vpSteps, s ) { - (*s)->m_Timing.TidyUpData( false ); + (*s)->m_Timing.TidyUpData( true ); } /* Generate these before we autogen notes, so the new notes can inherit @@ -889,9 +889,9 @@ void Song::ReCalculateRadarValuesAndLastSecond(bool fromCache, bool duringCache) if( tempNoteData.GetLastRow() != 0 ) { localFirst = min(localFirst, - pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetFirstBeat())); + pSteps->GetTimingData()->GetElapsedTimeFromBeat(tempNoteData.GetFirstBeat())); localLast = max(localLast, - pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetLastBeat())); + pSteps->GetTimingData()->GetElapsedTimeFromBeat(tempNoteData.GetLastBeat())); } wipe_notedata: if (duringCache) @@ -1587,7 +1587,8 @@ bool Song::IsEditAlreadyLoaded( Steps* pSteps ) const bool Song::IsStepsUsingDifferentTiming(Steps *pSteps) const { - return pSteps->m_Timing != this->m_SongTiming; + // XXX This no longer depends on Song at all + return !pSteps->m_Timing.empty(); } bool Song::HasSignificantBpmChangesOrStops() const diff --git a/src/Steps.cpp b/src/Steps.cpp index 0c1de3112a..40c9258665 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -66,7 +66,7 @@ void Steps::GetDisplayBpms( DisplayBpms &AddTo ) const else { float fMinBPM, fMaxBPM; - this->m_Timing.GetActualBPM( fMinBPM, fMaxBPM ); + this->GetTimingData()->GetActualBPM( fMinBPM, fMaxBPM ); AddTo.Add( fMinBPM ); AddTo.Add( fMaxBPM ); } @@ -291,7 +291,7 @@ void Steps::CalculateRadarValues( float fMusicLengthSeconds ) FOREACH_PlayerNumber( pn ) m_CachedRadarValues[pn].Zero(); - GAMESTATE->SetProcessedTimingData(&this->m_Timing); + GAMESTATE->SetProcessedTimingData(this->GetTimingData()); if( tempNoteData.IsComposite() ) { vector vParts; @@ -527,11 +527,12 @@ const TimingData *Steps::GetTimingData() const bool Steps::HasSignificantTimingChanges() const { - if( m_Timing.HasStops() || m_Timing.HasDelays() || m_Timing.HasWarps() || - m_Timing.HasSpeedChanges() || m_Timing.HasScrollChanges() ) + const TimingData *timing = GetTimingData(); + if( timing->HasStops() || timing->HasDelays() || timing->HasWarps() || + timing->HasSpeedChanges() || timing->HasScrollChanges() ) return true; - if( m_Timing.HasBpmChanges() ) + if( timing->HasBpmChanges() ) { // check to see if these changes are significant. if( (GetMaxBPM() - GetMinBPM()) > 3.000f ) @@ -584,7 +585,7 @@ public: } static int GetTimingData( T* p, lua_State *L ) { - p->m_Timing.PushSelf(L); + p->GetTimingData()->PushSelf(L); return 1; } static int GetHash( T* p, lua_State *L ) { lua_pushnumber( L, p->GetHash() ); return 1; } diff --git a/src/Trail.cpp b/src/Trail.cpp index f1e334e686..d2c9d8febe 100644 --- a/src/Trail.cpp +++ b/src/Trail.cpp @@ -115,7 +115,7 @@ const RadarValues &Trail::GetRadarValues() const NoteData nd; pSteps->GetNoteData( nd ); RadarValues rv_orig; - GAMESTATE->SetProcessedTimingData(const_cast(&pSteps->m_Timing)); + GAMESTATE->SetProcessedTimingData(const_cast(pSteps->GetTimingData())); NoteDataUtil::CalculateRadarValues( nd, e->pSong->m_fMusicLengthSeconds, rv_orig ); PlayerOptions po; po.FromString( e->Modifiers ); From 533b0f9eff8d125c5f101767418db4d312e648ed Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 24 Jan 2013 00:20:56 -0500 Subject: [PATCH 11/11] NotesWriterSSC: fix steps offset when saving --- src/NotesWriterSSC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index 17db0285a4..ab6b5d7e84 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -372,7 +372,7 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa // XXX: Is there a better way to write this? if (const_cast(song.m_SongTiming) != in.m_Timing) { - lines.push_back( ssprintf( "#OFFSET:%.f;", in.m_Timing.m_fBeat0OffsetInSeconds ) ); + lines.push_back( ssprintf( "#OFFSET:%.6f;", in.m_Timing.m_fBeat0OffsetInSeconds ) ); GetTimingTags( lines, in.m_Timing ); }