diff --git a/Docs/Changelog_SSCformat.txt b/Docs/Changelog_SSCformat.txt index 95b48cf7d7..fb04d68912 100644 --- a/Docs/Changelog_SSCformat.txt +++ b/Docs/Changelog_SSCformat.txt @@ -9,6 +9,9 @@ change to JSON, but it is unsure if this will be done. Implement .ssc at your own risk. ________________________________________________________________________________ +[v0.7] - theDtTvB, Wolfman2000 +* Split Timing officially implemented. + [v0.59] - Wolfman2000 * Typo fix: #RADARVALUES needed a semicolon at the end, not a colon. diff --git a/Themes/_fallback/Scripts/04 Scoring.lua b/Themes/_fallback/Scripts/04 Scoring.lua index c0bf2b9bda..b6d68abb9c 100644 --- a/Themes/_fallback/Scripts/04 Scoring.lua +++ b/Themes/_fallback/Scripts/04 Scoring.lua @@ -11,6 +11,7 @@ function GetTotalItems(radars) return radars:GetValue('RadarCategory_TapsAndHolds') + radars:GetValue('RadarCategory_Holds') + radars:GetValue('RadarCategory_Rolls'); + + radars:GetValue('RadarCategory_Lifts'); end; -- Determine whether marvelous timing is to be considered. diff --git a/src/AdjustSync.cpp b/src/AdjustSync.cpp index e669f9cb74..b375928a25 100644 --- a/src/AdjustSync.cpp +++ b/src/AdjustSync.cpp @@ -58,7 +58,7 @@ void AdjustSync::ResetOriginalSyncData() s_pTimingDataOriginal = new TimingData; if( GAMESTATE->m_pCurSong ) - *s_pTimingDataOriginal = GAMESTATE->m_pCurSong->m_Timing; + *s_pTimingDataOriginal = GAMESTATE->m_pCurSong->m_SongTiming; else *s_pTimingDataOriginal = TimingData(); s_fGlobalOffsetSecondsOriginal = PREFSMAN->m_fGlobalOffsetSeconds; @@ -87,7 +87,7 @@ void AdjustSync::SaveSyncChanges() { if( GAMESTATE->IsCourseMode() ) return; - if( GAMESTATE->m_pCurSong && *s_pTimingDataOriginal != GAMESTATE->m_pCurSong->m_Timing ) + if( GAMESTATE->m_pCurSong && *s_pTimingDataOriginal != GAMESTATE->m_pCurSong->m_SongTiming ) { if( GAMESTATE->IsEditing() ) { @@ -110,7 +110,7 @@ void AdjustSync::RevertSyncChanges() if( GAMESTATE->IsCourseMode() ) return; PREFSMAN->m_fGlobalOffsetSeconds.Set( s_fGlobalOffsetSecondsOriginal ); - GAMESTATE->m_pCurSong->m_Timing = *s_pTimingDataOriginal; + GAMESTATE->m_pCurSong->m_SongTiming = *s_pTimingDataOriginal; ResetOriginalSyncData(); s_fStandardDeviation = 0.0f; s_fAverageError = 0.0f; @@ -186,7 +186,7 @@ void AdjustSync::AutosyncOffset() switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType ) { case SongOptions::AUTOSYNC_SONG: - GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += mean; + GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += mean; break; case SongOptions::AUTOSYNC_MACHINE: PREFSMAN->m_fGlobalOffsetSeconds.Set( PREFSMAN->m_fGlobalOffsetSeconds + mean ); @@ -232,15 +232,15 @@ void AdjustSync::AutosyncTempo() if( !CalcLeastSquares( s_vAutosyncTempoData, fSlope, fIntercept, fFilteredError ) ) return; - GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += fIntercept; + GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += fIntercept; const float fScaleBPM = 1.0f/(1.0f - fSlope); - FOREACH( BPMSegment, GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments, i ) + FOREACH( BPMSegment, GAMESTATE->m_pCurSong->m_SongTiming.m_BPMSegments, i ) i->SetBPM( i->GetBPM() * fScaleBPM ); // We assume that the stops were measured as a number of beats. // Therefore, if we change the bpms, we need to make a similar // change to the stops. - FOREACH( StopSegment, GAMESTATE->m_pCurSong->m_Timing.m_StopSegments, i ) + FOREACH( StopSegment, GAMESTATE->m_pCurSong->m_SongTiming.m_StopSegments, i ) i->m_fStopSeconds *= 1.0f - fSlope; SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_APPLIED.GetValue() ); @@ -296,7 +296,7 @@ void AdjustSync::GetSyncChangeTextSong( vector &vsAddTo ) { float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_fBeat0OffsetInSeconds, 0.001f ); - float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds, 0.001f ); + float fNew = Quantize( GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds, 0.001f ); float fDelta = fNew - fOld; if( fabsf(fDelta) > 0.0001f ) @@ -309,10 +309,10 @@ void AdjustSync::GetSyncChangeTextSong( vector &vsAddTo ) } } - for( unsigned i=0; im_pCurSong->m_Timing.m_BPMSegments.size(); i++ ) + for( unsigned i=0; im_pCurSong->m_SongTiming.m_BPMSegments.size(); i++ ) { float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_BPMSegments[i].GetBPM(), 0.001f ); - float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments[i].GetBPM(), 0.001f ); + float fNew = Quantize( GAMESTATE->m_pCurSong->m_SongTiming.m_BPMSegments[i].GetBPM(), 0.001f ); float fDelta = fNew - fOld; if( fabsf(fDelta) > 0.0001f ) @@ -330,10 +330,10 @@ void AdjustSync::GetSyncChangeTextSong( vector &vsAddTo ) } } - for( unsigned i=0; im_pCurSong->m_Timing.m_StopSegments.size(); i++ ) + for( unsigned i=0; im_pCurSong->m_SongTiming.m_StopSegments.size(); i++ ) { float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_StopSegments[i].m_fStopSeconds, 0.001f ); - float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_StopSegments[i].m_fStopSeconds, 0.001f ); + float fNew = Quantize( GAMESTATE->m_pCurSong->m_SongTiming.m_StopSegments[i].m_fStopSeconds, 0.001f ); float fDelta = fNew - fOld; if( fabsf(fDelta) > 0.0001f ) diff --git a/src/Attack.cpp b/src/Attack.cpp index a896944158..1a67cc3181 100644 --- a/src/Attack.cpp +++ b/src/Attack.cpp @@ -11,9 +11,10 @@ void Attack::GetAttackBeats( const Song *pSong, float &fStartBeat, float &fEndBe { ASSERT( pSong ); ASSERT_M( fStartSecond >= 0, ssprintf("StartSecond: %f",fStartSecond) ); - - fStartBeat = pSong->GetBeatFromElapsedTime( fStartSecond ); - fEndBeat = pSong->GetBeatFromElapsedTime( fStartSecond+fSecsRemaining ); + + const TimingData &timing = pSong->m_SongTiming; + fStartBeat = timing.GetBeatFromElapsedTime( fStartSecond ); + fEndBeat = timing.GetBeatFromElapsedTime( fStartSecond+fSecsRemaining ); } /* Get the range for an attack that's being applied in realtime, eg. during battle @@ -34,9 +35,10 @@ void Attack::GetRealtimeAttackBeats( const Song *pSong, const PlayerState* pPlay fStartBeat = min( GAMESTATE->m_fSongBeat+8, pPlayerState->m_fLastDrawnBeat ); fStartBeat = truncf(fStartBeat)+1; - const float lStartSecond = pSong->GetElapsedTimeFromBeat( fStartBeat ); + const TimingData &timing = pSong->m_SongTiming; + const float lStartSecond = timing.GetElapsedTimeFromBeat( fStartBeat ); const float fEndSecond = lStartSecond + fSecsRemaining; - fEndBeat = pSong->GetBeatFromElapsedTime( fEndSecond ); + fEndBeat = timing.GetBeatFromElapsedTime( fEndSecond ); fEndBeat = truncf(fEndBeat)+1; // loading the course should have caught this. diff --git a/src/AutoKeysounds.cpp b/src/AutoKeysounds.cpp index 5aac67976b..aba066200d 100644 --- a/src/AutoKeysounds.cpp +++ b/src/AutoKeysounds.cpp @@ -99,7 +99,7 @@ void AutoKeysounds::LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain ) if( tn[pn].iKeysoundIndex >= 0 ) { RString sKeysoundFilePath = sSongDir + pSong->m_vsKeysoundFile[tn[pn].iKeysoundIndex]; - float fSeconds = pSong->m_Timing.GetElapsedTimeFromBeatNoOffset( NoteRowToBeat(iRow) ) + SOUNDMAN->GetPlayLatency(); + float fSeconds = pSong->m_SongTiming.GetElapsedTimeFromBeatNoOffset( NoteRowToBeat(iRow) ) + SOUNDMAN->GetPlayLatency(); float fPan = 0; if( !bSoundIsGlobal ) diff --git a/src/Background.cpp b/src/Background.cpp index 34050aedcc..5047e5fc1e 100644 --- a/src/Background.cpp +++ b/src/Background.cpp @@ -419,7 +419,7 @@ void BackgroundImpl::LoadFromRandom( float fFirstBeat, float fEndBeat, const Bac int iStartRow = BeatToNoteRow(fFirstBeat); int iEndRow = BeatToNoteRow(fEndBeat); - const TimingData &timing = m_pSong->m_Timing; + const TimingData &timing = m_pSong->m_SongTiming; // change BG every time signature change or 4 measures FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, iter ) @@ -697,7 +697,7 @@ void BackgroundImpl::Layer::UpdateCurBGChange( const Song *pSong, float fLastMus float fBeat, fBPS, fThrowAway; bool bFreeze; int iThrowAway; - pSong->m_Timing.GetBeatAndBPSFromElapsedTime( fCurrentTime, fBeat, fBPS, bFreeze, bFreeze, iThrowAway, fThrowAway ); + pSong->m_SongTiming.GetBeatAndBPSFromElapsedTime( fCurrentTime, fBeat, fBPS, bFreeze, bFreeze, iThrowAway, fThrowAway ); // Calls to Update() should *not* be scaled by music rate; fCurrentTime is. Undo it. const float fRate = GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate; @@ -762,7 +762,7 @@ void BackgroundImpl::Layer::UpdateCurBGChange( const Song *pSong, float fLastMus m_pCurrentBGA->PlayCommand( "GainFocus" ); /* How much time of this BGA have we skipped? (This happens with SetSeconds.) */ - const float fStartSecond = pSong->m_Timing.GetElapsedTimeFromBeat( change.m_fStartBeat ); + const float fStartSecond = pSong->m_SongTiming.GetElapsedTimeFromBeat( change.m_fStartBeat ); /* This is affected by the music rate. */ fDeltaTime = fCurrentTime - fStartSecond; diff --git a/src/Foreground.cpp b/src/Foreground.cpp index 708fbcb608..54ba873d7e 100644 --- a/src/Foreground.cpp +++ b/src/Foreground.cpp @@ -41,9 +41,9 @@ void Foreground::LoadFromSong( const Song *pSong ) bga.m_fStartBeat = change.m_fStartBeat; bga.m_bFinished = false; - const float fStartSecond = pSong->m_Timing.GetElapsedTimeFromBeat( bga.m_fStartBeat ); + const float fStartSecond = pSong->m_SongTiming.GetElapsedTimeFromBeat( bga.m_fStartBeat ); const float fStopSecond = fStartSecond + bga.m_bga->GetTweenTimeLeft(); - bga.m_fStopBeat = pSong->m_Timing.GetBeatFromElapsedTime( fStopSecond ); + bga.m_fStopBeat = pSong->m_SongTiming.GetBeatFromElapsedTime( fStopSecond ); bga.m_bga->SetVisible( false ); @@ -82,7 +82,7 @@ void Foreground::Update( float fDeltaTime ) bga.m_bga->SetVisible( true ); bga.m_bga->PlayCommand( "On" ); - const float fStartSecond = m_pSong->m_Timing.GetElapsedTimeFromBeat( bga.m_fStartBeat ); + const float fStartSecond = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( bga.m_fStartBeat ); lDeltaTime = GAMESTATE->m_fMusicSeconds - fStartSecond; } else diff --git a/src/GameSoundManager.cpp b/src/GameSoundManager.cpp index 5b3ba858de..6e517249fb 100644 --- a/src/GameSoundManager.cpp +++ b/src/GameSoundManager.cpp @@ -146,7 +146,7 @@ static void StartMusic( MusicToPlay &ToPlay ) SSCLoader::LoadFromSSCFile(ToPlay.m_sTimingFile, song) ) { ToPlay.HasTiming = true; - ToPlay.m_TimingData = song.m_Timing; + ToPlay.m_TimingData = song.m_SongTiming; // get cabinet lights if any Steps *pStepsCabinetLights = SongUtil::GetOneSteps( &song, StepsType_lights_cabinet ); if( pStepsCabinetLights ) @@ -156,7 +156,7 @@ static void StartMusic( MusicToPlay &ToPlay ) SMLoader::LoadFromSMFile(ToPlay.m_sTimingFile, song) ) { ToPlay.HasTiming = true; - ToPlay.m_TimingData = song.m_Timing; + ToPlay.m_TimingData = song.m_SongTiming; // get cabinet lights if any Steps *pStepsCabinetLights = SongUtil::GetOneSteps( &song, StepsType_lights_cabinet ); if( pStepsCabinetLights ) diff --git a/src/GameplayAssist.cpp b/src/GameplayAssist.cpp index 7531c77e43..97a324416d 100644 --- a/src/GameplayAssist.cpp +++ b/src/GameplayAssist.cpp @@ -27,7 +27,7 @@ void GameplayAssist::PlayTicks( const NoteData &nd ) * come out on time; the actual precise timing is handled by SetStartTime. */ float fPositionSeconds = GAMESTATE->m_fMusicSeconds; fPositionSeconds += SOUNDMAN->GetPlayLatency() + (float)CommonMetrics::TICK_EARLY_SECONDS + 0.250f; - const TimingData &timing = GAMESTATE->m_pCurSong->m_Timing; + const TimingData &timing = GAMESTATE->m_pCurSong->m_SongTiming; const float fSongBeat = timing.GetBeatFromElapsedTimeNoOffset( fPositionSeconds ); const int iSongRow = max( 0, BeatToNoteRowNotRounded( fSongBeat ) ); diff --git a/src/LyricDisplay.cpp b/src/LyricDisplay.cpp index 27263d068c..fec9827e34 100644 --- a/src/LyricDisplay.cpp +++ b/src/LyricDisplay.cpp @@ -59,7 +59,7 @@ void LyricDisplay::Update( float fDeltaTime ) if( m_iCurLyricNumber+1 < GAMESTATE->m_pCurSong->m_LyricSegments.size() ) fEndTime = pSong->m_LyricSegments[m_iCurLyricNumber+1].m_fStartTime; else - fEndTime = pSong->GetElapsedTimeFromBeat( pSong->m_fLastBeat ); + fEndTime = pSong->m_SongTiming.GetElapsedTimeFromBeat( pSong->m_fLastBeat ); const float fDistance = fEndTime - pSong->m_LyricSegments[m_iCurLyricNumber].m_fStartTime; const float fTweenBufferTime = IN_LENGTH.GetValue() + OUT_LENGTH.GetValue(); diff --git a/src/MeterDisplay.cpp b/src/MeterDisplay.cpp index 3018125cd1..66c0b19587 100644 --- a/src/MeterDisplay.cpp +++ b/src/MeterDisplay.cpp @@ -73,8 +73,8 @@ void SongMeterDisplay::Update( float fDeltaTime ) { if( GAMESTATE->m_pCurSong ) { - float fSongStartSeconds = GAMESTATE->m_pCurSong->m_Timing.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fFirstBeat ); - float fSongEndSeconds = GAMESTATE->m_pCurSong->m_Timing.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat ); + float fSongStartSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fFirstBeat ); + float fSongEndSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat ); float fPercentPositionSong = SCALE( GAMESTATE->m_fMusicSeconds, fSongStartSeconds, fSongEndSeconds, 0.0f, 1.0f ); CLAMP( fPercentPositionSong, 0, 1 ); diff --git a/src/NoteData.cpp b/src/NoteData.cpp index 88c350b408..eac5bc42b4 100644 --- a/src/NoteData.cpp +++ b/src/NoteData.cpp @@ -466,7 +466,8 @@ int NoteData::GetNumTapNotes( int iStartIndex, int iEndIndex ) const FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, t, r, iStartIndex, iEndIndex ) { const TapNote &tn = GetTapNote(t, r); - if( tn.type != TapNote::empty && tn.type != TapNote::mine && tn.type != TapNote::fake ) + if( tn.type != TapNote::empty && tn.type != TapNote::mine + && tn.type != TapNote::lift && tn.type != TapNote::fake ) iNumNotes++; } } diff --git a/src/NoteDataUtil.cpp b/src/NoteDataUtil.cpp index 6b7f47cba1..413fd3a425 100644 --- a/src/NoteDataUtil.cpp +++ b/src/NoteDataUtil.cpp @@ -2215,7 +2215,7 @@ void NoteDataUtil::AddTapAttacks( NoteData &nd, Song* pSong ) for( float sec=15; secm_fMusicLengthSeconds; sec+=30 ) { - float fBeat = pSong->GetBeatFromElapsedTime( sec ); + float fBeat = pSong->m_SongTiming.GetBeatFromElapsedTime( sec ); int iBeat = (int)fBeat; int iTrack = iBeat % nd.GetNumTracks(); // deterministically calculates track TapNote tn( @@ -2448,7 +2448,7 @@ void NoteDataUtil::SetHopoPossibleFlags( const Song *pSong, NoteData& ndInOut ) FOREACH_NONEMPTY_ROW_ALL_TRACKS( ndInOut, r ) { float fBeat = NoteRowToBeat( r ); - float fSeconds = pSong->GetElapsedTimeFromBeat( fBeat ); + float fSeconds = pSong->m_SongTiming.GetElapsedTimeFromBeat( fBeat ); int iLastTapTrack = ndInOut.GetLastTrackWithTapOrHoldHead( r ); if( iLastTapTrack != -1 && fSeconds <= fLastRowMusicSeconds + g_fTimingWindowHopo ) diff --git a/src/NoteField.cpp b/src/NoteField.cpp index 6895b07234..20e7c08f8b 100644 --- a/src/NoteField.cpp +++ b/src/NoteField.cpp @@ -742,7 +742,7 @@ void NoteField::DrawPrimitives() // Draw beat bars if( GAMESTATE->IsEditing() || SHOW_BEAT_BARS ) { - const vector &vTimeSignatureSegments = GAMESTATE->m_pCurSong->m_Timing.m_vTimeSignatureSegments; + const vector &vTimeSignatureSegments = GAMESTATE->m_pCurSong->m_SongTiming.m_vTimeSignatureSegments; int iMeasureIndex = 0; FOREACH_CONST( TimeSignatureSegment, vTimeSignatureSegments, iter ) { @@ -785,8 +785,10 @@ void NoteField::DrawPrimitives() { ASSERT(GAMESTATE->m_pCurSong); + const TimingData &timing = GAMESTATE->m_pCurSong->m_SongTiming; + // BPM text - FOREACH_CONST( BPMSegment, GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments, seg ) + FOREACH_CONST( BPMSegment, timing.m_BPMSegments, seg ) { if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw ) { @@ -797,7 +799,7 @@ void NoteField::DrawPrimitives() } // Freeze text - FOREACH_CONST( StopSegment, GAMESTATE->m_pCurSong->m_Timing.m_StopSegments, seg ) + FOREACH_CONST( StopSegment, timing.m_StopSegments, seg ) { if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw ) { @@ -808,7 +810,7 @@ void NoteField::DrawPrimitives() } // Warp text - FOREACH_CONST( WarpSegment, GAMESTATE->m_pCurSong->m_Timing.m_WarpSegments, seg ) + FOREACH_CONST( WarpSegment, timing.m_WarpSegments, seg ) { if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw ) { @@ -819,7 +821,7 @@ void NoteField::DrawPrimitives() } // Time Signature text - FOREACH_CONST( TimeSignatureSegment, GAMESTATE->m_pCurSong->m_Timing.m_vTimeSignatureSegments, seg ) + FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, seg ) { if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw ) { @@ -830,7 +832,7 @@ void NoteField::DrawPrimitives() } // Tickcount text - FOREACH_CONST( TickcountSegment, GAMESTATE->m_pCurSong->m_Timing.m_TickcountSegments, seg ) + FOREACH_CONST( TickcountSegment, timing.m_TickcountSegments, seg ) { if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw ) { @@ -841,7 +843,7 @@ void NoteField::DrawPrimitives() } // Combo text - FOREACH_CONST( ComboSegment, GAMESTATE->m_pCurSong->m_Timing.m_ComboSegments, seg ) + FOREACH_CONST( ComboSegment, timing.m_ComboSegments, seg ) { if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw ) { @@ -852,7 +854,7 @@ void NoteField::DrawPrimitives() } // Label text - FOREACH_CONST( LabelSegment, GAMESTATE->m_pCurSong->m_Timing.m_LabelSegments, seg ) + FOREACH_CONST( LabelSegment, timing.m_LabelSegments, seg ) { if( seg->m_iStartRow >= iFirstRowToDraw && seg->m_iStartRow <= iLastRowToDraw ) { @@ -872,7 +874,7 @@ void NoteField::DrawPrimitives() FOREACH_CONST( Attack, ce.attacks, a ) { float fSecond = a->fStartSecond; - float fBeat = GAMESTATE->m_pCurSong->m_Timing.GetBeatFromElapsedTime( fSecond ); + float fBeat = timing.GetBeatFromElapsedTime( fSecond ); if( BeatToNoteRow(fBeat) >= iFirstRowToDraw && BeatToNoteRow(fBeat) <= iLastRowToDraw) diff --git a/src/NotesLoaderBMS.cpp b/src/NotesLoaderBMS.cpp index 4a95e85d57..9eb58168ed 100644 --- a/src/NotesLoaderBMS.cpp +++ b/src/NotesLoaderBMS.cpp @@ -799,7 +799,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( PREFSMAN->m_bQuirksMode ) { BPMSegment newSeg( 0, fBPM ); - out.AddBPMSegment( newSeg ); + out.m_SongTiming.AddBPMSegment( newSeg ); if( fBPM > 0.0f ) LOG->Trace( "Inserting new positive BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM ); else @@ -810,7 +810,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( fBPM > 0.0f ) { BPMSegment newSeg( 0, fBPM ); - out.AddBPMSegment( newSeg ); + out.m_SongTiming.AddBPMSegment( newSeg ); LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM ); } else @@ -901,7 +901,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur case BMS_TRACK_BPM: if( iVal > 0 ) { - out.SetBPMAtBeat( fBeat, (float) iVal ); + out.m_SongTiming.SetBPMAtBeat( fBeat, (float) iVal ); LOG->Trace( "Inserting new BPM change at beat %f, BPM %i", fBeat, iVal ); } else @@ -918,7 +918,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( GetTagFromMap( mapNameToData, sTagToLookFor, sBPM ) ) { float fBPM = StringToFloat( sBPM ); - out.SetBPMAtBeat( fBeat, fBPM ); + out.m_SongTiming.SetBPMAtBeat( fBeat, fBPM ); } else { @@ -937,12 +937,12 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( GetTagFromMap( mapNameToData, sTagToLookFor, sBeats ) ) { // find the BPM at the time of this freeze - float fBPS = out.m_Timing.GetBPMAtBeat(fBeat) / 60.0f; + float fBPS = out.m_SongTiming.GetBPMAtBeat(fBeat) / 60.0f; float fBeats = StringToFloat( sBeats ) / 48.0f; float fFreezeSecs = fBeats / fBPS; StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs ); - out.AddStopSegment( newSeg ); + out.m_SongTiming.AddStopSegment( newSeg ); LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.m_fStopSeconds ); } else diff --git a/src/NotesLoaderKSF.cpp b/src/NotesLoaderKSF.cpp index b1732cdf81..14e6b4bca7 100644 --- a/src/NotesLoaderKSF.cpp +++ b/src/NotesLoaderKSF.cpp @@ -358,7 +358,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant else if( sValueName=="BPM" ) { BPM1 = StringToFloat(sParams[1]); - out.AddBPMSegment( BPMSegment(0, BPM1) ); + out.m_SongTiming.AddBPMSegment( BPMSegment(0, BPM1) ); } else if( sValueName=="BPM2" ) { @@ -383,7 +383,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant else if( sValueName=="STARTTIME" ) { SMGap1 = -StringToFloat( sParams[1] )/100; - out.m_Timing.m_fBeat0OffsetInSeconds = SMGap1; + out.m_SongTiming.m_fBeat0OffsetInSeconds = SMGap1; } // This is currently required for more accurate KIU BPM changes. else if( sValueName=="STARTTIME2" ) @@ -409,7 +409,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant TickcountSegment tcs; tcs.m_iStartRow = BeatToNoteRow(0.0f); tcs.m_iTicks = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount; - out.m_Timing.AddTickcountSegment( tcs ); + out.m_SongTiming.AddTickcountSegment( tcs ); } else if ( sValueName=="STEP" ) { @@ -469,7 +469,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant const float beat = (BPMPos2 + SMGap1) * BeatsPerSecond; LOG->Trace( "BPM %f, BPS %f, BPMPos2 %f, beat %f", BPM1, BeatsPerSecond, BPMPos2, beat ); - out.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), BPM2) ); + out.m_SongTiming.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), BPM2) ); } if( BPM3 > 0 && BPMPos3 > 0 ) @@ -479,7 +479,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant const float beat = (BPMPos3 + SMGap2) * BeatsPerSecond; LOG->Trace( "BPM %f, BPS %f, BPMPos3 %f, beat %f", BPM2, BeatsPerSecond, BPMPos3, beat ); - out.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), BPM3) ); + out.m_SongTiming.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), BPM3) ); } } else @@ -515,7 +515,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant TickcountSegment tcs; tcs.m_iStartRow = BeatToNoteRow(fCurBeat); tcs.m_iTicks = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount; - out.m_Timing.AddTickcountSegment( tcs ); + out.m_SongTiming.AddTickcountSegment( tcs ); continue; } @@ -523,22 +523,22 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant { float fCurBpm = (float)numTemp; //out.m_Timing.AddBPMSegment( BPMSegment( BeatToNoteRow(fCurBeat), (float)numTemp ) ); - out.m_Timing.SetBPMAtBeat( fCurBeat, fCurBpm ); + out.m_SongTiming.SetBPMAtBeat( fCurBeat, fCurBpm ); continue; } else if (BeginsWith(NoteRowString, "|E")) { // Finally! the |E| tag is working as it should. I can die happy now -DaisuMaster - float fCurDelay = 60 / out.m_Timing.GetBPMAtBeat(fCurBeat) * (float)numTemp / iTickCount; - fCurDelay += out.m_Timing.GetStopAtRow(BeatToNoteRow(fCurBeat) ); - out.m_Timing.SetStopAtBeat( fCurBeat, fCurDelay, true ); + float fCurDelay = 60 / out.m_SongTiming.GetBPMAtBeat(fCurBeat) * (float)numTemp / iTickCount; + fCurDelay += out.m_SongTiming.GetStopAtRow(BeatToNoteRow(fCurBeat) ); + out.m_SongTiming.SetStopAtBeat( fCurBeat, fCurDelay, true ); continue; } else if (BeginsWith(NoteRowString, "|D")) { - float fCurDelay = out.m_Timing.GetStopAtRow(BeatToNoteRow(fCurBeat) ); + float fCurDelay = out.m_SongTiming.GetStopAtRow(BeatToNoteRow(fCurBeat) ); fCurDelay += (float)numTemp / 1000; - out.m_Timing.SetStopAtBeat( fCurBeat, fCurDelay, true ); + out.m_SongTiming.SetStopAtBeat( fCurBeat, fCurDelay, true ); continue; } } diff --git a/src/NotesLoaderMidi.cpp b/src/NotesLoaderMidi.cpp index a74b3610a8..ef354d7bfe 100644 --- a/src/NotesLoaderMidi.cpp +++ b/src/NotesLoaderMidi.cpp @@ -682,7 +682,7 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut ) double fSecondsPerBeat = (iter->tickSeconds * GUITAR_MIDI_COUNTS_PER_BEAT); bpmSeg.m_fBPS = float( 1. / fSecondsPerBeat ); - songOut.m_Timing.AddBPMSegment( bpmSeg ); + songOut.m_SongTiming.AddBPMSegment( bpmSeg ); } FOREACH_CONST( MidiFileIn::TimeSignatureChange, midi.timeSignatureEvents_, iter ) @@ -692,7 +692,7 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut ) seg.m_iNumerator = iter->numerator; seg.m_iDenominator = iter->denominator; - songOut.m_Timing.AddTimeSignatureSegment( seg ); + songOut.m_SongTiming.AddTimeSignatureSegment( seg ); } diff --git a/src/NotesLoaderPMS.cpp b/src/NotesLoaderPMS.cpp index b733aa3d9f..44a125e1cb 100644 --- a/src/NotesLoaderPMS.cpp +++ b/src/NotesLoaderPMS.cpp @@ -591,7 +591,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( fBPM > 0.0f ) { BPMSegment newSeg( 0, fBPM ); - out.AddBPMSegment( newSeg ); + out.m_SongTiming.AddBPMSegment( newSeg ); LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM ); } else @@ -673,7 +673,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur case PMS_TRACK_BPM: if( iVal > 0 ) { - out.SetBPMAtBeat( fBeat, (float) iVal ); + out.m_SongTiming.SetBPMAtBeat( fBeat, (float) iVal ); LOG->Trace( "Inserting new BPM change at beat %f, BPM %i", fBeat, iVal ); } else @@ -694,7 +694,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( fBPM > 0.0f ) { BPMSegment newSeg( BeatToNoteRow(fBeat), fBPM ); - out.AddBPMSegment( newSeg ); + out.m_SongTiming.AddBPMSegment( newSeg ); LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", fBeat, newSeg.GetBPM() ); } else @@ -716,12 +716,12 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( GetTagFromMap( mapNameToData, sTagToLookFor, sBeats ) ) { // find the BPM at the time of this freeze - float fBPS = out.m_Timing.GetBPMAtBeat(fBeat) / 60.0f; + float fBPS = out.m_SongTiming.GetBPMAtBeat(fBeat) / 60.0f; float fBeats = StringToFloat( sBeats ) / 48.0f; float fFreezeSecs = fBeats / fBPS; StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs ); - out.AddStopSegment( newSeg ); + out.m_SongTiming.AddStopSegment( newSeg ); LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.m_fStopSeconds ); } else @@ -750,7 +750,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( fBPM > 0.0f ) { BPMSegment newSeg( iStepIndex, fBPM ); - out.AddBPMSegment( newSeg ); + out.m_SongTiming.AddBPMSegment( newSeg ); LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(newSeg.m_iStartRow), newSeg.GetBPM() ); } diff --git a/src/NotesLoaderSM.cpp b/src/NotesLoaderSM.cpp index 3ee9994332..3fa6432713 100644 --- a/src/NotesLoaderSM.cpp +++ b/src/NotesLoaderSM.cpp @@ -103,6 +103,244 @@ bool SMLoader::LoadTimingFromFile( const RString &fn, TimingData &out ) return true; } +void SMLoader::ProcessBPMs( TimingData &out, const RString sParam ) +{ + vector arrayBPMChangeExpressions; + split( sParam, ",", arrayBPMChangeExpressions ); + + // prepare storage variables for negative BPMs -> Warps. + float negBeat = -1; + float negBPM = 1; + float highspeedBeat = -1; + + for( unsigned b=0; b arrayBPMChangeValues; + split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); + // XXX: Hard to tell which file caused this. + if( arrayBPMChangeValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #BPMs value \"%s\" (must have exactly one '='), ignored.", + arrayBPMChangeExpressions[b].c_str() ); + continue; + } + + const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); + const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); + + if( fNewBPM < 0.0f ) + { + out.m_bHasNegativeBpms = true; + negBeat = fBeat; + negBPM = fNewBPM; + } + else if( fNewBPM > 0.0f ) + { + // add in a warp. + if( negBPM < 0 ) + { + float endBeat = fBeat + (fNewBPM / -negBPM) * (fBeat - negBeat); + WarpSegment new_seg(negBeat, endBeat); + out.AddWarpSegment( new_seg ); + + negBeat = -1; + negBPM = 1; + } + // too fast. make it a warp. + if( fNewBPM > FAST_BPM_WARP ) + { + highspeedBeat = fBeat; + } + else + { + // add in a warp. + if( highspeedBeat > 0 ) + { + WarpSegment new_seg(highspeedBeat, fBeat); + out.AddWarpSegment( new_seg ); + highspeedBeat = -1; + } + { + BPMSegment new_seg; + new_seg.m_iStartRow = BeatToNoteRow(fBeat); + new_seg.SetBPM( fNewBPM ); + out.AddBPMSegment( new_seg ); + } + } + } + } +} + +void SMLoader::ProcessStops( TimingData &out, const RString sParam ) +{ + vector arrayFreezeExpressions; + split( sParam, ",", arrayFreezeExpressions ); + + // Prepare variables for negative stop conversion. + float negBeat = -1; + float negPause = 0; + + for( unsigned f=0; f arrayFreezeValues; + split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); + if( arrayFreezeValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #STOPS value \"%s\" (must have exactly one '='), ignored.", + arrayFreezeExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); + + // Process the prior stop. + if( negPause > 0 ) + { + BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); + float fSecondsPerBeat = 60 / oldBPM.GetBPM(); + float fSkipBeats = negPause / fSecondsPerBeat; + + if( negBeat + fSkipBeats > fFreezeBeat ) + fSkipBeats = fFreezeBeat - negBeat; + + WarpSegment ws( negBeat, negBeat + fSkipBeats); + out.AddWarpSegment( ws ); + + negBeat = -1; + negPause = 0; + } + + if( fFreezeSeconds < 0.0f ) + { + negBeat = fFreezeBeat; + negPause = -fFreezeSeconds; + } + else if( fFreezeSeconds > 0.0f ) + { + StopSegment ss( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); + out.AddStopSegment( ss ); + } + + } + + // Process the prior stop if there was one. + if( negPause > 0 ) + { + BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); + float fSecondsPerBeat = 60 / oldBPM.GetBPM(); + float fSkipBeats = negPause / fSecondsPerBeat; + + WarpSegment ws( negBeat, negBeat + fSkipBeats); + out.AddWarpSegment( ws ); + } +} + +void SMLoader::ProcessDelays( TimingData &out, const RString sParam ) +{ + vector arrayDelayExpressions; + split( sParam, ",", arrayDelayExpressions ); + + for( unsigned f=0; f arrayDelayValues; + split( arrayDelayExpressions[f], "=", arrayDelayValues ); + if( arrayDelayValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #DELAYS value \"%s\" (must have exactly one '='), ignored.", + arrayDelayExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); + + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); + // XXX: Remove Negatives Bug? + new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat); + new_seg.m_fStopSeconds = fFreezeSeconds; + + // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + + if(fFreezeSeconds > 0.0f) + out.AddStopSegment( new_seg ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } +} + +void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam ) +{ + vector vs1; + split( sParam, ",", vs1 ); + + FOREACH_CONST( RString, vs1, s1 ) + { + vector vs2; + split( *s1, "=", vs2 ); + + if( vs2.size() < 3 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); + continue; + } + + const float fBeat = StringToFloat( vs2[0] ); + + TimeSignatureSegment seg; + seg.m_iStartRow = BeatToNoteRow(fBeat); + seg.m_iNumerator = atoi( vs2[1] ); + seg.m_iDenominator = atoi( vs2[2] ); + + if( fBeat < 0 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); + continue; + } + + if( seg.m_iNumerator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); + continue; + } + + if( seg.m_iDenominator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); + continue; + } + + out.AddTimeSignatureSegment( seg ); + } +} + +void SMLoader::ProcessTickcounts( TimingData &out, const RString sParam ) +{ + vector arrayTickcountExpressions; + split( sParam, ",", arrayTickcountExpressions ); + + for( unsigned f=0; f arrayTickcountValues; + split( arrayTickcountExpressions[f], "=", arrayTickcountValues ); + if( arrayTickcountValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #TICKCOUNTS value \"%s\" (must have exactly one '='), ignored.", + arrayTickcountExpressions[f].c_str() ); + continue; + } + + const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); + int iTicks = clamp(atoi( arrayTickcountValues[1] ), 0, ROWS_PER_BEAT); + + TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); + out.AddTickcountSegment( new_seg ); + } +} + void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) { out.m_fBeat0OffsetInSeconds = 0; @@ -123,255 +361,27 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) } else if( sValueName=="BPMS" ) { - vector arrayBPMChangeExpressions; - split( sParams[1], ",", arrayBPMChangeExpressions ); - - // prepare storage variables for negative BPMs -> Warps. - float negBeat = -1; - float negBPM = 1; - float highspeedBeat = -1; - - for( unsigned b=0; b arrayBPMChangeValues; - split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); - // XXX: Hard to tell which file caused this. - if( arrayBPMChangeValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); - continue; - } - - const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); - const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - - if( fNewBPM < 0.0f ) - { - out.m_bHasNegativeBpms = true; - negBeat = fBeat; - negBPM = fNewBPM; - } - else if( fNewBPM > 0.0f ) - { - // add in a warp. - if( negBPM < 0 ) - { - float endBeat = fBeat + (fNewBPM / -negBPM) * (fBeat - negBeat); - WarpSegment new_seg(negBeat, endBeat); - out.AddWarpSegment( new_seg ); - - negBeat = -1; - negBPM = 1; - } - // too fast. make it a warp. - if( fNewBPM > FAST_BPM_WARP ) - { - highspeedBeat = fBeat; - } - else - { - // add in a warp. - if( highspeedBeat > 0 ) - { - WarpSegment new_seg(highspeedBeat, fBeat); - out.AddWarpSegment( new_seg ); - highspeedBeat = -1; - } - { - BPMSegment new_seg; - new_seg.m_iStartRow = BeatToNoteRow(fBeat); - new_seg.SetBPM( fNewBPM ); - out.AddBPMSegment( new_seg ); - } - } - } - } + ProcessBPMs(out, sParams[1]); } else if( sValueName=="STOPS" || sValueName=="FREEZES" ) { - vector arrayFreezeExpressions; - split( sParams[1], ",", arrayFreezeExpressions ); - - // Prepare variables for negative stop conversion. - float negBeat = -1; - float negPause = 0; - - for( unsigned f=0; f arrayFreezeValues; - split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); - if( arrayFreezeValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); - - // Process the prior stop. - if( negPause > 0 ) - { - BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); - float fSecondsPerBeat = 60 / oldBPM.GetBPM(); - float fSkipBeats = negPause / fSecondsPerBeat; - - if( negBeat + fSkipBeats > fFreezeBeat ) - fSkipBeats = fFreezeBeat - negBeat; - - WarpSegment ws( negBeat, negBeat + fSkipBeats); - out.AddWarpSegment( ws ); - - negBeat = -1; - negPause = 0; - } - - if( fFreezeSeconds < 0.0f ) - { - negBeat = fFreezeBeat; - negPause = -fFreezeSeconds; - } - else if( fFreezeSeconds > 0.0f ) - { - StopSegment ss( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); - out.AddStopSegment( ss ); - } - - } - - // Process the prior stop if there was one. - if( negPause > 0 ) - { - BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); - float fSecondsPerBeat = 60 / oldBPM.GetBPM(); - float fSkipBeats = negPause / fSecondsPerBeat; - - WarpSegment ws( negBeat, negBeat + fSkipBeats); - out.AddWarpSegment( ws ); - } + ProcessStops(out, sParams[1]); } else if( sValueName=="DELAYS" ) { - vector arrayDelayExpressions; - split( sParams[1], ",", arrayDelayExpressions ); - - for( unsigned f=0; f arrayDelayValues; - split( arrayDelayExpressions[f], "=", arrayDelayValues ); - if( arrayDelayValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayDelayExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); - - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); - // XXX: Remove Negatives Bug? - new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat); - new_seg.m_fStopSeconds = fFreezeSeconds; - - // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - - if(fFreezeSeconds > 0.0f) - out.AddStopSegment( new_seg ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } + ProcessDelays(out, sParams[1]); } else if( sValueName=="TIMESIGNATURES" ) { - vector vs1; - split( sParams[1], ",", vs1 ); - - FOREACH_CONST( RString, vs1, s1 ) - { - vector vs2; - split( *s1, "=", vs2 ); - - if( vs2.size() < 3 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); - continue; - } - - const float fBeat = StringToFloat( vs2[0] ); - - TimeSignatureSegment seg; - seg.m_iStartRow = BeatToNoteRow(fBeat); - seg.m_iNumerator = atoi( vs2[1] ); - seg.m_iDenominator = atoi( vs2[2] ); - - if( fBeat < 0 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); - continue; - } - - if( seg.m_iNumerator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); - continue; - } - - if( seg.m_iDenominator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); - continue; - } - - out.AddTimeSignatureSegment( seg ); - } + ProcessTimeSignatures(out, sParams[1]); } else if( sValueName=="TICKCOUNTS" ) { - vector arrayTickcountExpressions; - split( sParams[1], ",", arrayTickcountExpressions ); - - for( unsigned f=0; f arrayTickcountValues; - split( arrayTickcountExpressions[f], "=", arrayTickcountValues ); - if( arrayTickcountValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); - continue; - } - - const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); - int iTicks = atoi( arrayTickcountValues[1] ); - // you're lazy, let SM do the work for you... -DaisuMaster - if( iTicks < 1) iTicks = 1; - if( iTicks > ROWS_PER_BEAT ) iTicks = ROWS_PER_BEAT; - - TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); - out.AddTickcountSegment( new_seg ); - - if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants - { - // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); - //out.AddTickcountSegment( new_seg ); - } - else - { - //LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); - //LOG->UserLog( "Song file", "(UNKNOWN)", "Clamping tickcount value to %d at beat %f.", iTicks, fTickcountBeat); - //etc - } - } + ProcessTickcounts(out, sParams[1]); } // Ensure all of the warps are handled right. sort(out.m_WarpSegments.begin(), out.m_WarpSegments.end()); diff --git a/src/NotesLoaderSM.h b/src/NotesLoaderSM.h index db1e938528..d61c7b19ff 100644 --- a/src/NotesLoaderSM.h +++ b/src/NotesLoaderSM.h @@ -25,6 +25,13 @@ namespace SMLoader bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ); bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression ); + + + void ProcessBPMs( TimingData &, const RString ); + void ProcessStops( TimingData &, const RString ); + void ProcessDelays( TimingData &, const RString ); + void ProcessTimeSignatures( TimingData &, const RString ); + void ProcessTickcounts( TimingData &, const RString ); } #endif diff --git a/src/NotesLoaderSMA.cpp b/src/NotesLoaderSMA.cpp index 93dcb65095..1fa083136d 100644 --- a/src/NotesLoaderSMA.cpp +++ b/src/NotesLoaderSMA.cpp @@ -113,8 +113,8 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) return false; } - out.m_Timing.m_sFile = sPath; - LoadTimingFromSMAFile( msd, out.m_Timing ); + out.m_SongTiming.m_sFile = sPath; + LoadTimingFromSMAFile( msd, out.m_SongTiming ); for( unsigned i=0; i aBGChangeValues; - split( sBGChangeExpression, "=", aBGChangeValues, false ); - - aBGChangeValues.resize( min((int)aBGChangeValues.size(),11) ); - - switch( aBGChangeValues.size() ) - { - case 11: - change.m_def.m_sColor2 = aBGChangeValues[10]; - change.m_def.m_sColor2.Replace( '^', ',' ); - change.m_def.m_sColor2 = RageColor::NormalizeColorString( change.m_def.m_sColor2 ); - // fall through - case 10: - change.m_def.m_sColor1 = aBGChangeValues[9]; - change.m_def.m_sColor1.Replace( '^', ',' ); - change.m_def.m_sColor1 = RageColor::NormalizeColorString( change.m_def.m_sColor1 ); - // fall through - case 9: - change.m_sTransition = aBGChangeValues[8]; - // fall through - case 8: - change.m_def.m_sFile2 = aBGChangeValues[7]; - // fall through - case 7: - change.m_def.m_sEffect = aBGChangeValues[6]; - // fall through - case 6: - // param 7 overrides this. - // Backward compatibility: - if( change.m_def.m_sEffect.empty() ) - { - bool bLoop = atoi( aBGChangeValues[5] ) != 0; - if( !bLoop ) - change.m_def.m_sEffect = SBE_StretchNoLoop; - } - // fall through - case 5: - // param 7 overrides this. - // Backward compatibility: - if( change.m_def.m_sEffect.empty() ) - { - bool bRewindMovie = atoi( aBGChangeValues[4] ) != 0; - if( bRewindMovie ) - change.m_def.m_sEffect = SBE_StretchRewind; - } - // fall through - case 4: - // param 9 overrides this. - // Backward compatibility: - if( change.m_sTransition.empty() ) - change.m_sTransition = (atoi( aBGChangeValues[3] ) != 0) ? "CrossFade" : ""; - // fall through - case 3: - change.m_fRate = StringToFloat( aBGChangeValues[2] ); - // fall through - case 2: - change.m_def.m_sFile1 = aBGChangeValues[1]; - // fall through - case 1: - change.m_fStartBeat = StringToFloat( aBGChangeValues[0] ); - // fall through - } - - return aBGChangeValues.size() >= 2; + return SMLoader::LoadFromBGChangesString( change, sBGChangeExpression ); } bool SSCLoader::LoadFromDir( const RString &sPath, Song &out ) @@ -112,6 +46,86 @@ bool SSCLoader::LoadFromDir( const RString &sPath, Song &out ) return LoadFromSSCFile( sPath + aFileNames[0], out ); } +void SSCLoader::ProcessWarps( TimingData &out, const RString sParam ) +{ + vector arrayWarpExpressions; + split( sParam, ",", arrayWarpExpressions ); + + for( unsigned b=0; b arrayWarpValues; + split( arrayWarpExpressions[b], "=", arrayWarpValues ); + // XXX: Hard to tell which file caused this. + if( arrayWarpValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #WARPS value \"%s\" (must have exactly one '='), ignored.", + arrayWarpExpressions[b].c_str() ); + continue; + } + + const float fBeat = StringToFloat( arrayWarpValues[0] ); + const float fNewBeat = StringToFloat( arrayWarpValues[1] ); + + if(fNewBeat > fBeat) + out.AddWarpSegment( WarpSegment(fBeat, fNewBeat) ); + else + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Warp at beat %f, BPM %f.", fBeat, fNewBeat ); + } + } +} + +void SSCLoader::ProcessLabels( TimingData &out, const RString sParam ) +{ + vector arrayLabelExpressions; + split( sParam, ",", arrayLabelExpressions ); + + for( unsigned b=0; b arrayLabelValues; + split( arrayLabelExpressions[b], "=", arrayLabelValues ); + if( arrayLabelValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #LABELS value \"%s\" (must have exactly one '='), ignored.", + arrayLabelExpressions[b].c_str() ); + continue; + } + + const float fBeat = StringToFloat( arrayLabelValues[0] ); + RString sLabel = arrayLabelValues[1]; + TrimRight(sLabel); + if( fBeat >= 0.0f ) + out.AddLabelSegment( LabelSegment(fBeat, sLabel) ); + else + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Label at beat %f called %s.", fBeat, sLabel.c_str() ); + } + + } +} + +void SSCLoader::ProcessCombos( TimingData &out, const RString sParam ) +{ + vector arrayComboExpressions; + split( sParam, ",", arrayComboExpressions ); + + for( unsigned f=0; f arrayComboValues; + split( arrayComboExpressions[f], "=", arrayComboValues ); + if( arrayComboValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #COMBOS value \"%s\" (must have exactly one '='), ignored.", + arrayComboExpressions[f].c_str() ); + continue; + } + const float fComboBeat = StringToFloat( arrayComboValues[0] ); + const int iCombos = atoi( arrayComboValues[1] ); + ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); + out.AddComboSegment( new_seg ); + } +} + bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache ) { LOG->Trace( "Song::LoadFromSSCFile(%s)", sPath.c_str() ); @@ -123,7 +137,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach return false; } - out.m_Timing.m_sFile = sPath; // songs still have their fallback timing. + out.m_SongTiming.m_sFile = sPath; // songs still have their fallback timing. int state = GETTING_SONG_INFO; const unsigned values = msd.GetNumValues(); @@ -384,270 +398,47 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach else if( sValueName=="OFFSET" ) { - out.m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + out.m_SongTiming.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); } /* Below are the song based timings that should only be used * if the steps do not have their own timing. */ else if( sValueName=="STOPS" ) { - vector arrayFreezeExpressions; - split( sParams[1], ",", arrayFreezeExpressions ); - - for( unsigned f=0; f arrayFreezeValues; - split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); - if( arrayFreezeValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); - - if(fFreezeSeconds > 0.0f) - { - // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - out.m_Timing.AddStopSegment( new_seg ); - } - else - { - // negative stops (hi JS!) -aj - if( PREFSMAN->m_bQuirksMode ) - { - // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - out.m_Timing.AddStopSegment( new_seg ); - } - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } - } + SMLoader::ProcessStops(out.m_SongTiming, sParams[1]); } else if( sValueName=="DELAYS" ) { - vector arrayDelayExpressions; - split( sParams[1], ",", arrayDelayExpressions ); - - for( unsigned f=0; f arrayDelayValues; - split( arrayDelayExpressions[f], "=", arrayDelayValues ); - if( arrayDelayValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayDelayExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); - - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); - - // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - - if(fFreezeSeconds > 0.0f) - out.m_Timing.AddStopSegment( new_seg ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } + SMLoader::ProcessDelays(out.m_SongTiming, sParams[1]); } else if( sValueName=="BPMS" ) { - vector arrayBPMChangeExpressions; - split( sParams[1], ",", arrayBPMChangeExpressions ); - - for( unsigned b=0; b arrayBPMChangeValues; - split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); - // XXX: Hard to tell which file caused this. - if( arrayBPMChangeValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); - continue; - } - - const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); - const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - - if(fNewBPM > 0.0f) - out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - { - out.m_Timing.m_bHasNegativeBpms = true; - // only add Negative BPMs in quirks mode -aj - if( PREFSMAN->m_bQuirksMode ) - out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); - } - } + SMLoader::ProcessBPMs(out.m_SongTiming, sParams[1]); } else if( sValueName=="WARPS" ) { - vector arrayWarpExpressions; - split( sParams[1], ",", arrayWarpExpressions ); - - for( unsigned b=0; b arrayWarpValues; - split( arrayWarpExpressions[b], "=", arrayWarpValues ); - // XXX: Hard to tell which file caused this. - if( arrayWarpValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayWarpExpressions[b].c_str() ); - continue; - } - - const float fBeat = StringToFloat( arrayWarpValues[0] ); - const float fNewBeat = StringToFloat( arrayWarpValues[1] ); - - if(fNewBeat > fBeat) - out.m_Timing.AddWarpSegment( WarpSegment(fBeat, fNewBeat) ); - else - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Warp at beat %f, BPM %f.", fBeat, fNewBeat ); - } - } + ProcessWarps( out.m_SongTiming, sParams[1] ); } else if( sValueName=="LABELS" ) { - vector arrayLabelExpressions; - split( sParams[1], ",", arrayLabelExpressions ); - - for( unsigned b=0; b arrayLabelValues; - split( arrayLabelExpressions[b], "=", arrayLabelValues ); - if( arrayLabelValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayLabelExpressions[b].c_str() ); - continue; - } - - const float fBeat = StringToFloat( arrayLabelValues[0] ); - RString sLabel = arrayLabelValues[1]; - TrimRight(sLabel); - if( fBeat >= 0.0f ) - out.m_Timing.AddLabelSegment( LabelSegment(fBeat, sLabel) ); - else - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Label at beat %f called %s.", fBeat, sLabel.c_str() ); - } - - } + ProcessLabels( out.m_SongTiming, sParams[1] ); } else if( sValueName=="TIMESIGNATURES" ) { - vector vs1; - split( sParams[1], ",", vs1 ); - - FOREACH_CONST( RString, vs1, s1 ) - { - vector vs2; - split( *s1, "=", vs2 ); - - if( vs2.size() < 3 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); - continue; - } - - const float fBeat = StringToFloat( vs2[0] ); - - TimeSignatureSegment seg; - seg.m_iStartRow = BeatToNoteRow(fBeat); - seg.m_iNumerator = atoi( vs2[1] ); - seg.m_iDenominator = atoi( vs2[2] ); - - if( fBeat < 0 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); - continue; - } - - if( seg.m_iNumerator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); - continue; - } - - if( seg.m_iDenominator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); - continue; - } - - out.m_Timing.AddTimeSignatureSegment( seg ); - } + SMLoader::ProcessTimeSignatures(out.m_SongTiming, sParams[1]); } else if( sValueName=="TICKCOUNTS" ) { - vector arrayTickcountExpressions; - split( sParams[1], ",", arrayTickcountExpressions ); - - for( unsigned f=0; f arrayTickcountValues; - split( arrayTickcountExpressions[f], "=", arrayTickcountValues ); - if( arrayTickcountValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); - continue; - } - - const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); - const int iTicks = atoi( arrayTickcountValues[1] ); - TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); - - if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants - { - // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); - out.m_Timing.AddTickcountSegment( new_seg ); - } - else - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); - } - } + SMLoader::ProcessTickcounts(out.m_SongTiming, sParams[1]); } else if( sValueName=="COMBOS" ) { - vector arrayComboExpressions; - split( sParams[1], ",", arrayComboExpressions ); - - for( unsigned f=0; f arrayComboValues; - split( arrayComboExpressions[f], "=", arrayComboValues ); - if( arrayComboValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayComboExpressions[f].c_str() ); - continue; - } - const float fComboBeat = StringToFloat( arrayComboValues[0] ); - const int iCombos = atoi( arrayComboValues[1] ); - ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); - out.m_Timing.AddComboSegment( new_seg ); - } + ProcessCombos( out.m_SongTiming, sParams[1] ); } /* The following are cache tags. Never fill their values @@ -756,41 +547,14 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach out.AddSteps( pNewNotes ); } - else if( sValueName=="BPMS" ) + else if( sValueName=="BPMS" ) // This must ALWAYS be here in Split Timing. { - /* state = GETTING_STEP_TIMING_INFO; - vector arrayBPMChangeExpressions; - split( sParams[1], ",", arrayBPMChangeExpressions ); - - for( unsigned b=0; b arrayBPMChangeValues; - split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); - // XXX: Hard to tell which file caused this. - if( arrayBPMChangeValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); - continue; - } - - const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); - const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - - if(fNewBPM > 0.0f) - pNewNotes->m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - { - pNewNotes->m_Timing.m_bHasNegativeBpms = true; - // only add Negative BPMs in quirks mode -aj - if( PREFSMAN->m_bQuirksMode ) - pNewNotes->m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); - } - } - */ + /* + pNewNotes->m_Timing = TimingData(out.m_SongTiming.m_fBeat0OffsetInSeconds); + SMLoader::ProcessBPMs(pNewNotes->m_Timing, sParams[1]); + */ + } break; } @@ -798,28 +562,31 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach { if( sValueName=="STOPS" ) { - // copy from above when it's time. + // SMLoader::ProcessStops(pNewNotes->m_Timing, sParams[1]); } else if( sValueName=="DELAYS" ) { - // copy from above when it's time. + // SMLoader::ProcessDelays(pNewNotes->m_Timing, sParams[1]); } else if( sValueName=="TIMESIGNATURES" ) { - // copy from above when it's time. + // SMLoader::ProcessTimeSignatures(pNewNotes->m_Timing, sParams[1]); } - else if( sValueName=="TICKCOUNTS" ) { - // copy from above when it's time. + // SMLoader::ProcessTickcounts(pNewNotes->m_Timing, sParams[1]); } else if( sValueName=="COMBOS" ) { - // copy from above when it's time. + // ProcessCombos(pNewNotes->m_Timing, sParams[1]); } - else if( sValueName=="WARPS" || sValueName=="LABELS" ) + else if( sValueName=="WARPS" ) { - // copy from above when it's time. + // ProcessWarps(pNewNotes->m_Timing, sParams[1]); + } + else if( sValueName=="LABELS" ) + { + // ProcessLabels(pNewNotes->m_Timing, sParams[1]); } else if( sValueName=="ATTACKS" ) { @@ -874,10 +641,9 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach */ } - else if( sValueName=="NOTES" ) + else if( sValueName=="NOTES" || sValueName=="NOTES2" ) { state = GETTING_SONG_INFO; - // pNewNotes->m_Timing.m_fBeat0OffsetInSeconds = out.m_Timing.m_fBeat0OffsetInSeconds; pNewNotes->SetSMNoteData( sParams[1] ); pNewNotes->TidyUpData(); out.AddSteps( pNewNotes ); @@ -1095,55 +861,7 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat void SSCLoader::TidyUpData( Song &song, bool bFromCache ) { - /* - * Hack: if the song has any changes at all (so it won't use a random BGA) - * and doesn't end with "-nosongbg-", add a song background BGC. Remove - * "-nosongbg-" if it exists. - * - * This way, songs that were created earlier, when we added the song BG - * at the end by default, will still behave as expected; all new songs will - * have to add an explicit song BG tag if they want it. This is really a - * formatting hack only; nothing outside of SMLoader ever sees "-nosongbg-". - */ - vector &bg = song.GetBackgroundChanges(BACKGROUND_LAYER_1); - if( !bg.empty() ) - { - /* BGChanges have been sorted. On the odd chance that a BGChange exists - * with a very high beat, search the whole list. */ - bool bHasNoSongBgTag = false; - - for( unsigned i = 0; !bHasNoSongBgTag && i < bg.size(); ++i ) - { - if( !bg[i].m_def.m_sFile1.CompareNoCase(NO_SONG_BG_FILE) ) - { - bg.erase( bg.begin()+i ); - bHasNoSongBgTag = true; - } - } - - // If there's no -nosongbg- tag, add the song BG. - if( !bHasNoSongBgTag ) do - { - /* If we're loading cache, -nosongbg- should always be in there. We - * must not call IsAFile(song.GetBackgroundPath()) when loading cache. */ - if( bFromCache ) - break; - - /* If BGChanges already exist after the last beat, don't add the - * background in the middle. */ - if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= song.m_fLastBeat ) - break; - - // If the last BGA is already the song BGA, don't add a duplicate. - if( !bg.empty() && !bg.back().m_def.m_sFile1.CompareNoCase(song.m_sBackgroundFile) ) - break; - - if( !IsAFile( song.GetBackgroundPath() ) ) - break; - - bg.push_back( BackgroundChange(song.m_fLastBeat,song.m_sBackgroundFile) ); - } while(0); - } + SMLoader::TidyUpData(song, bFromCache); } /* diff --git a/src/NotesLoaderSSC.h b/src/NotesLoaderSSC.h index ff44a23cb5..bf85bdd73c 100644 --- a/src/NotesLoaderSSC.h +++ b/src/NotesLoaderSSC.h @@ -25,6 +25,8 @@ enum SSCLoadingStates const float VERSION_RADAR_FAKE = 0.53f; /** @brief The version where WarpSegments started to be utilized. */ const float VERSION_WARP_SEGMENT = 0.56f; +/** @brief The version that formally introduced Split Timing. */ +const float VERSION_SPLIT_TIMING = 0.7f; /** * @brief The SSCLoader handles all of the parsing needed for .ssc files. @@ -75,6 +77,11 @@ namespace SSCLoader * @param bFromCache a flag to determine if this song is loaded from a cache file. */ void TidyUpData( Song &song, bool bFromCache ); + + + void ProcessWarps( TimingData &, const RString ); + void ProcessLabels( TimingData &, const RString ); + void ProcessCombos( TimingData &, const RString ); } #endif /** diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index 69ca696756..3c4ff71a3b 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -74,7 +74,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) f.PutLine( "#INSTRUMENTTRACK:" + s + ";\n" ); } } - f.PutLine( ssprintf( "#OFFSET:%.6f;", out.m_Timing.m_fBeat0OffsetInSeconds ) ); + f.PutLine( ssprintf( "#OFFSET:%.6f;", out.m_SongTiming.m_fBeat0OffsetInSeconds ) ); f.PutLine( ssprintf( "#SAMPLESTART:%.6f;", out.m_fMusicSampleStartSeconds ) ); f.PutLine( ssprintf( "#SAMPLELENGTH:%.6f;", out.m_fMusicSampleLengthSeconds ) ); if( out.m_fSpecifiedLastBeat > 0 ) @@ -107,39 +107,39 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) } f.Write( "#BPMS:" ); - for( unsigned i=0; im_iStartRow), iter->m_iNumerator, iter->m_iDenominator ) ); vector::const_iterator iter2 = iter; iter2++; - if( iter2 != out.m_Timing.m_vTimeSignatureSegments.end() ) + if( iter2 != out.m_SongTiming.m_vTimeSignatureSegments.end() ) f.Write( "," ); } f.PutLine( ";" ); - ASSERT( !out.m_Timing.m_TickcountSegments.empty() ); + ASSERT( !out.m_SongTiming.m_TickcountSegments.empty() ); f.Write( "#TICKCOUNTS:" ); - for( unsigned i=0; isecond; - if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( begin->first ) ) + if( GAMESTATE->m_pCurSong->m_SongTiming.IsWarpAtRow( begin->first ) ) break; if( tn.type == TapNote::empty ) break; @@ -1579,7 +1579,7 @@ int Player::GetClosestNonEmptyRowDirectional( int iStartRow, int iEndRow, bool b ++iter; continue; } - if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iter.Row() ) ) + if( GAMESTATE->m_pCurSong->m_SongTiming.IsWarpAtRow( iter.Row() ) ) { ++iter; continue; @@ -1873,7 +1873,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b break; } - const float fSongBeat = GAMESTATE->m_pCurSong ? GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds ) : GAMESTATE->m_fSongBeat; + const float fSongBeat = GAMESTATE->m_pCurSong ? GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime( fPositionSeconds ) : GAMESTATE->m_fSongBeat; const int iSongRow = row == -1 ? BeatToNoteRow( fSongBeat ) : row; if( col != -1 && !bRelease ) @@ -2011,8 +2011,8 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b * "jack hammers." Hmm. */ const int iStepSearchRows = max( - BeatToNoteRow( GAMESTATE->m_pCurSong->m_Timing.GetBeatFromElapsedTime( GAMESTATE->m_fMusicSeconds + StepSearchDistance ) ) - iSongRow, - iSongRow - BeatToNoteRow( GAMESTATE->m_pCurSong->m_Timing.GetBeatFromElapsedTime( GAMESTATE->m_fMusicSeconds - StepSearchDistance ) ) + BeatToNoteRow( GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime( GAMESTATE->m_fMusicSeconds + StepSearchDistance ) ) - iSongRow, + iSongRow - BeatToNoteRow( GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime( GAMESTATE->m_fMusicSeconds - StepSearchDistance ) ) ) + ROWS_PER_BEAT; int iRowOfOverlappingNoteOrRow = row; if( row == -1 ) @@ -2039,7 +2039,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b float fNoteOffset = 0.0f; // we need this later if we are autosyncing const float fStepBeat = NoteRowToBeat( iRowOfOverlappingNoteOrRow ); - const float fStepSeconds = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat(fStepBeat); + const float fStepSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat(fStepBeat); if( row == -1 ) { @@ -2089,7 +2089,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b // Stepped too close to mine? if( !bRelease && ( REQUIRE_STEP_ON_MINES == !bHeld ) && fSecondsFromExact <= GetWindowSeconds(TW_Mine) && - !GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow(iSongRow) ) + !GAMESTATE->m_pCurSong->m_SongTiming.IsWarpAtRow(iSongRow) ) score = TNS_HitMine; break; @@ -2564,7 +2564,7 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) float fThrowAway; int iWarpBeginRow; float fWarpLength; - GAMESTATE->m_pCurSong->m_Timing.GetBeatAndBPSFromElapsedTime( fEarliestTime, fMissIfOlderThanThisBeat, fThrowAway, bFreeze, bDelay, iWarpBeginRow, fWarpLength ); + GAMESTATE->m_pCurSong->m_SongTiming.GetBeatAndBPSFromElapsedTime( fEarliestTime, fMissIfOlderThanThisBeat, fThrowAway, bFreeze, bDelay, iWarpBeginRow, fWarpLength ); iMissIfOlderThanThisRow = BeatToNoteRow( fMissIfOlderThanThisBeat ); if( bFreeze || bDelay ) @@ -2587,7 +2587,7 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) continue; // Ignore all notes that are skipped via WARPS. - if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iter.Row() ) ) + if( GAMESTATE->m_pCurSong->m_SongTiming.IsWarpAtRow( iter.Row() ) ) continue; if( tn.type == TapNote::mine ) @@ -2622,7 +2622,7 @@ void Player::UpdateJudgedRows() int iRow = iter.Row(); // If row is within a warp section, ignore it. -aj - if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow(iRow) ) + if( GAMESTATE->m_pCurSong->m_SongTiming.IsWarpAtRow(iRow) ) continue; if( iLastSeenRow != iRow ) @@ -2843,13 +2843,13 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) int iCheckpointFrequencyRows = ROWS_PER_BEAT/2; if( CHECKPOINTS_USE_TICKCOUNTS ) { - int tickCurrent = GAMESTATE->m_pCurSong->m_Timing.GetTickcountAtRow( iLastRowCrossed ); + int tickCurrent = GAMESTATE->m_pCurSong->m_SongTiming.GetTickcountAtRow( iLastRowCrossed ); // There are some charts that don't want tickcounts involved at all. iCheckpointFrequencyRows = (tickCurrent > 0 ? ROWS_PER_BEAT / tickCurrent : 0); } else if( CHECKPOINTS_USE_TIME_SIGNATURES ) { - TimeSignatureSegment tSignature = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iLastRowCrossed ) ); + TimeSignatureSegment tSignature = GAMESTATE->m_pCurSong->m_SongTiming.GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iLastRowCrossed ) ); // Most songs are in 4/4 time. The frequency for checking tick counts should reflect that. iCheckpointFrequencyRows = ROWS_PER_BEAT * tSignature.m_iDenominator / (tSignature.m_iNumerator * 4); @@ -2957,7 +2957,7 @@ void Player::HandleTapRowScore( unsigned row ) #endif // Warp hackery. -aj - if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( row ) ) + if( GAMESTATE->m_pCurSong->m_SongTiming.IsWarpAtRow( row ) ) return; if( GAMESTATE->m_bDemonstrationOrJukebox ) @@ -3061,7 +3061,7 @@ void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumH #endif // More warp hackery. -aj - if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iRow ) ) + if( GAMESTATE->m_pCurSong->m_SongTiming.IsWarpAtRow( iRow ) ) return; // don't accumulate combo if AutoPlay is on. diff --git a/src/ScoreKeeperNormal.cpp b/src/ScoreKeeperNormal.cpp index b3e106bfaf..36c405501e 100644 --- a/src/ScoreKeeperNormal.cpp +++ b/src/ScoreKeeperNormal.cpp @@ -443,7 +443,7 @@ void ScoreKeeperNormal::HandleComboInternal( int iNumHitContinueCombo, int iNumH if( iNumBreakCombo == 0 ) { - TimingData td = GAMESTATE->m_pCurSong->m_Timing; + TimingData td = GAMESTATE->m_pCurSong->m_SongTiming; int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).m_iCombo ); m_pPlayerStageStats->m_iCurCombo += iNumHitContinueCombo * multiplier; } @@ -463,7 +463,7 @@ void ScoreKeeperNormal::HandleRowComboInternal( TapNoteScore tns, int iNumTapsIn if ( tns >= m_MinScoreToContinueCombo ) { m_pPlayerStageStats->m_iCurMissCombo = 0; - TimingData td = GAMESTATE->m_pCurSong->m_Timing; + TimingData td = GAMESTATE->m_pCurSong->m_SongTiming; int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).m_iCombo ); m_pPlayerStageStats->m_iCurCombo += iNumTapsInRow * multiplier; } diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index d5d9e0d06d..ce69563960 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -913,7 +913,7 @@ void ScreenEdit::Update( float fDeltaTime ) { RageTimer tm; const float fSeconds = m_pSoundMusic->GetPositionSeconds( NULL, &tm ); - GAMESTATE->UpdateSongPosition( fSeconds, GAMESTATE->m_pCurSong->m_Timing, tm ); + GAMESTATE->UpdateSongPosition( fSeconds, GAMESTATE->m_pCurSong->m_SongTiming, tm ); } if( m_EditState == STATE_RECORDING ) @@ -931,7 +931,7 @@ void ScreenEdit::Update( float fDeltaTime ) continue; float fStartedHoldingSeconds = m_pSoundMusic->GetPositionSeconds() - fSecsHeld; - float fStartBeat = max( fStartPlayingAtBeat, m_pSong->GetBeatFromElapsedTime(fStartedHoldingSeconds) ); + float fStartBeat = max( fStartPlayingAtBeat, m_pSong->m_SongTiming.GetBeatFromElapsedTime(fStartedHoldingSeconds) ); float fEndBeat = max( fStartBeat, GAMESTATE->m_fSongBeat ); fEndBeat = min( fEndBeat, NoteRowToBeat(m_iStopPlayingAt) ); @@ -976,11 +976,11 @@ void ScreenEdit::Update( float fDeltaTime ) float fLastBeat = NoteRowToBeat(m_iStopPlayingAt); if( bButtonIsBeingPressed && m_EditState == STATE_RECORDING ) { - float fSeconds = m_pSong->m_Timing.GetElapsedTimeFromBeat( fLastBeat ); - fLastBeat = m_pSong->m_Timing.GetBeatFromElapsedTime( fSeconds + 0.5f ); + float fSeconds = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( fLastBeat ); + fLastBeat = m_pSong->m_SongTiming.GetBeatFromElapsedTime( fSeconds + 0.5f ); } - float fStopAtSeconds = m_pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_iStopPlayingAt) ) + 1; + float fStopAtSeconds = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( NoteRowToBeat(m_iStopPlayingAt) ) + 1; if( GAMESTATE->m_fMusicSeconds > fStopAtSeconds ) { // loop @@ -1071,7 +1071,7 @@ void ScreenEdit::UpdateTextInfo() RString sText; sText += ssprintf( CURRENT_BEAT_FORMAT.GetValue(), CURRENT_BEAT.GetValue().c_str(), GAMESTATE->m_fSongBeat ); - sText += ssprintf( CURRENT_SECOND_FORMAT.GetValue(), CURRENT_SECOND.GetValue().c_str(), m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat) ); + sText += ssprintf( CURRENT_SECOND_FORMAT.GetValue(), CURRENT_SECOND.GetValue().c_str(), m_pSong->m_SongTiming.GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat) ); switch( EDIT_MODE.GetValue() ) { DEFAULT_FAIL( EDIT_MODE.GetValue() ); @@ -1129,7 +1129,7 @@ void ScreenEdit::UpdateTextInfo() case EditMode_Home: break; case EditMode_Full: - sText += ssprintf( BEAT_0_OFFSET_FORMAT.GetValue(), BEAT_0_OFFSET.GetValue().c_str(), m_pSong->m_Timing.m_fBeat0OffsetInSeconds ); + sText += ssprintf( BEAT_0_OFFSET_FORMAT.GetValue(), BEAT_0_OFFSET.GetValue().c_str(), m_pSong->m_SongTiming.m_fBeat0OffsetInSeconds ); sText += ssprintf( PREVIEW_START_FORMAT.GetValue(), PREVIEW_START.GetValue().c_str(), m_pSong->m_fMusicSampleStartSeconds ); sText += ssprintf( PREVIEW_LENGTH_FORMAT.GetValue(), PREVIEW_LENGTH.GetValue().c_str(), m_pSong->m_fMusicSampleLengthSeconds ); break; @@ -1243,7 +1243,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) m_iShiftAnchor = -1; return; } - int beatsPerMeasure = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator; + int beatsPerMeasure = GAMESTATE->m_pCurSong->m_SongTiming.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator; switch( EditB ) { @@ -1443,13 +1443,13 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) break; case EDIT_BUTTON_LABEL_NEXT: { - ScrollTo( GAMESTATE->m_pCurSong->m_Timing. + ScrollTo( GAMESTATE->m_pCurSong->m_SongTiming. GetNextLabelSegmentBeatAtBeat( GAMESTATE->m_fSongBeat ) ); } break; case EDIT_BUTTON_LABEL_PREV: { - ScrollTo( GAMESTATE->m_pCurSong->m_Timing. + ScrollTo( GAMESTATE->m_pCurSong->m_SongTiming. GetPreviousLabelSegmentBeatAtBeat( GAMESTATE->m_fSongBeat ) ); } break; @@ -1579,7 +1579,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) case EDIT_BUTTON_BPM_UP: case EDIT_BUTTON_BPM_DOWN: { - float fBPM = m_pSong->GetBPMAtBeat( GAMESTATE->m_fSongBeat ); + float fBPM = m_pSong->m_SongTiming.GetBPMAtBeat( GAMESTATE->m_fSongBeat ); float fDelta; switch( EditB ) { @@ -1600,7 +1600,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } float fNewBPM = fBPM + fDelta; - m_pSong->SetBPMAtBeat( GAMESTATE->m_fSongBeat, fNewBPM ); + m_pSong->m_SongTiming.SetBPMAtBeat( GAMESTATE->m_fSongBeat, fNewBPM ); (fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play(); SetDirty( true ); } @@ -1627,24 +1627,24 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) fDelta *= 40; } unsigned i; - for( i=0; im_Timing.m_StopSegments.size(); i++ ) + for( i=0; im_SongTiming.m_StopSegments.size(); i++ ) { - if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) ) + if( m_pSong->m_SongTiming.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) ) break; } - if( i == m_pSong->m_Timing.m_StopSegments.size() ) // there is no StopSegment at the current beat + if( i == m_pSong->m_SongTiming.m_StopSegments.size() ) // there is no StopSegment at the current beat { // create a new StopSegment if( fDelta > 0 ) - m_pSong->AddStopSegment( StopSegment(BeatToNoteRow(GAMESTATE->m_fSongBeat), fDelta) ); + m_pSong->m_SongTiming.AddStopSegment( StopSegment(BeatToNoteRow(GAMESTATE->m_fSongBeat), fDelta) ); } - else // StopSegment being modified is m_Timing.m_StopSegments[i] + else // StopSegment being modified is m_SongTiming.m_StopSegments[i] { - m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds += fDelta; - if( m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds <= 0 ) - m_pSong->m_Timing.m_StopSegments.erase( m_pSong->m_Timing.m_StopSegments.begin()+i, - m_pSong->m_Timing.m_StopSegments.begin()+i+1); + m_pSong->m_SongTiming.m_StopSegments[i].m_fStopSeconds += fDelta; + if( m_pSong->m_SongTiming.m_StopSegments[i].m_fStopSeconds <= 0 ) + m_pSong->m_SongTiming.m_StopSegments.erase( m_pSong->m_SongTiming.m_StopSegments.begin()+i, + m_pSong->m_SongTiming.m_StopSegments.begin()+i+1); } (fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play(); SetDirty( true ); @@ -1673,24 +1673,24 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) fDelta *= 40; } unsigned i; - for( i=0; im_Timing.m_StopSegments.size(); i++ ) + for( i=0; im_SongTiming.m_StopSegments.size(); i++ ) { - if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) ) + if( m_pSong->m_SongTiming.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) ) break; } - if( i == m_pSong->m_Timing.m_StopSegments.size() ) // there is no delay segment at the current beat + if( i == m_pSong->m_SongTiming.m_StopSegments.size() ) // there is no delay segment at the current beat { // create a new delay segment if( fDelta > 0 ) m_pSong->AddStopSegment( StopSegment(BeatToNoteRow(GAMESTATE->m_fSongBeat), fDelta, true) ); } - else // delay segment being modified is m_Timing.m_StopSegments[i] + else // delay segment being modified is m_SongTiming.m_StopSegments[i] { - m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds += fDelta; - if( m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds <= 0 ) - m_pSong->m_Timing.m_StopSegments.erase( m_pSong->m_Timing.m_StopSegments.begin()+i, - m_pSong->m_Timing.m_StopSegments.begin()+i+1); + m_pSong->m_SongTiming.m_StopSegments[i].m_fStopSeconds += fDelta; + if( m_pSong->m_SongTiming.m_StopSegments[i].m_fStopSeconds <= 0 ) + m_pSong->m_SongTiming.m_StopSegments.erase( m_pSong->m_SongTiming.m_StopSegments.begin()+i, + m_pSong->m_SongTiming.m_StopSegments.begin()+i+1); } (fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play(); SetDirty( true ); @@ -1718,7 +1718,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) else fDelta *= 40; } - m_pSong->m_Timing.m_fBeat0OffsetInSeconds += fDelta; + m_pSong->m_SongTiming.m_fBeat0OffsetInSeconds += fDelta; (fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play(); SetDirty( true ); } @@ -1900,7 +1900,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) if( pCourse == NULL ) break; CourseEntry &ce = pCourse->m_vEntries[GAMESTATE->m_iEditCourseEntryIndex]; - float fStartTime = m_pSong->GetElapsedTimeFromBeat( GAMESTATE->m_fSongBeat ); + float fStartTime = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_fSongBeat ); int iAttack = FindAttackAtTime( ce.attacks, fStartTime ); if( iAttack >= 0 ) @@ -1941,7 +1941,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } else { - fStart = m_pSong->GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); + fStart = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); int iAttack = FindAttackAtTime( ce.attacks, fStart ); if( iAttack >= 0 ) @@ -1950,7 +1950,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) if( m_NoteFieldEdit.m_iEndMarker == -1 ) fEnd = m_pSong->m_fMusicLengthSeconds; else - fEnd = m_pSong->GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); + fEnd = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); } g_fLastInsertAttackPositionSeconds = fStart; g_fLastInsertAttackDurationSeconds = fEnd - fStart; @@ -2265,7 +2265,7 @@ void ScreenEdit::InputPlay( const InputEventPlus &input, EditButton EditB ) fOffsetDelta *= 40; } - m_pSong->m_Timing.m_fBeat0OffsetInSeconds += fOffsetDelta; + m_pSong->m_SongTiming.m_fBeat0OffsetInSeconds += fOffsetDelta; } break; } @@ -2381,8 +2381,8 @@ void ScreenEdit::TransitionEditState( EditState em ) AdjustSync::ResetOriginalSyncData(); /* Give a 1 second lead-in. If we're loading Player, this must be done first. */ - float fSeconds = m_pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_iStartPlayingAt) ) - 1; - GAMESTATE->UpdateSongPosition( fSeconds, m_pSong->m_Timing ); + float fSeconds = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( NoteRowToBeat(m_iStartPlayingAt) ) - 1; + GAMESTATE->UpdateSongPosition( fSeconds, m_pSong->m_SongTiming ); GAMESTATE->m_bGameplayLeadIn.Set( false ); @@ -2463,7 +2463,7 @@ void ScreenEdit::TransitionEditState( EditState em ) { case STATE_PLAYING: case STATE_RECORDING: - const float fStartSeconds = m_pSong->GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat); + const float fStartSeconds = m_pSong->m_SongTiming.GetElapsedTimeFromBeat(GAMESTATE->m_fSongBeat); LOG->Trace( "Starting playback at %f", fStartSeconds ); RageSoundParams p; @@ -2627,21 +2627,21 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) { float fBPM = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fBPM > 0 ) - m_pSong->SetBPMAtBeat( GAMESTATE->m_fSongBeat, fBPM ); + m_pSong->m_SongTiming.SetBPMAtBeat( GAMESTATE->m_fSongBeat, fBPM ); SetDirty( true ); } else if( SM == SM_BackFromStopChange ) { float fStop = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fStop >= 0 ) - m_pSong->m_Timing.SetStopAtBeat( GAMESTATE->m_fSongBeat, fStop ); + m_pSong->m_SongTiming.SetStopAtBeat( GAMESTATE->m_fSongBeat, fStop ); SetDirty( true ); } else if( SM == SM_BackFromDelayChange ) { float fDelay = StringToFloat( ScreenTextEntry::s_sLastAnswer ); if( fDelay >= 0 ) - m_pSong->m_Timing.SetStopAtBeat( GAMESTATE->m_fSongBeat, fDelay, true ); + m_pSong->m_SongTiming.SetStopAtBeat( GAMESTATE->m_fSongBeat, fDelay, true ); SetDirty( true ); } else if( SM == SM_BackFromTimeSignatureNumeratorChange ) @@ -2649,7 +2649,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) int iNum = atoi( ScreenTextEntry::s_sLastAnswer ); if( iNum > 0 ) { - m_pSong->m_Timing.SetTimeSignatureNumeratorAtBeat( GAMESTATE->m_fSongBeat, iNum ); + m_pSong->m_SongTiming.SetTimeSignatureNumeratorAtBeat( GAMESTATE->m_fSongBeat, iNum ); } SetDirty( true ); } @@ -2658,7 +2658,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) int iDen = atoi( ScreenTextEntry::s_sLastAnswer ); if( iDen > 0) { - m_pSong->m_Timing.SetTimeSignatureDenominatorAtBeat( GAMESTATE->m_fSongBeat, iDen ); + m_pSong->m_SongTiming.SetTimeSignatureDenominatorAtBeat( GAMESTATE->m_fSongBeat, iDen ); } SetDirty( true ); } @@ -2667,7 +2667,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) int iTick = atoi( ScreenTextEntry::s_sLastAnswer ); if ( iTick >= 0 && iTick <= ROWS_PER_BEAT ) { - m_pSong->m_Timing.SetTickcountAtBeat( GAMESTATE->m_fSongBeat, iTick ); + m_pSong->m_SongTiming.SetTickcountAtBeat( GAMESTATE->m_fSongBeat, iTick ); } SetDirty( true ); } @@ -2676,25 +2676,25 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) int iCombo = atoi( ScreenTextEntry::s_sLastAnswer ); if ( iCombo >= 0 ) { - m_pSong->m_Timing.SetComboAtBeat( GAMESTATE->m_fSongBeat, iCombo ); + m_pSong->m_SongTiming.SetComboAtBeat( GAMESTATE->m_fSongBeat, iCombo ); } SetDirty( true ); } else if ( SM == SM_BackFromLabelChange ) { RString sLabel = ScreenTextEntry::s_sLastAnswer; - if ( !m_pSong->m_Timing.DoesLabelExist(sLabel) ) + if ( !m_pSong->m_SongTiming.DoesLabelExist(sLabel) ) { sLabel.Replace("=", "_"); sLabel.Replace(",", "_"); - m_pSong->m_Timing.SetLabelAtBeat( GAMESTATE->m_fSongBeat, sLabel ); + m_pSong->m_SongTiming.SetLabelAtBeat( GAMESTATE->m_fSongBeat, sLabel ); SetDirty( true ); } } else if ( SM == SM_BackFromWarpChange ) { float fWarp = StringToFloat( ScreenTextEntry::s_sLastAnswer ); - m_pSong->m_Timing.SetWarpAtBeat( GAMESTATE->m_fSongBeat, fWarp ); + m_pSong->m_SongTiming.SetWarpAtBeat( GAMESTATE->m_fSongBeat, fWarp ); SetDirty( true ); } else if( SM == SM_BackFromBGChange ) @@ -2767,7 +2767,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) CourseEntry &ce = pCourse->m_vEntries[GAMESTATE->m_iEditCourseEntryIndex]; int iAttack; - g_fLastInsertAttackPositionSeconds = m_pSong->GetElapsedTimeFromBeat( GAMESTATE->m_fSongBeat ); + g_fLastInsertAttackPositionSeconds = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_fSongBeat ); g_fLastInsertAttackDurationSeconds = StringToFloat( g_InsertCourseAttack.rows[0].choices[iDurationChoice] ); iAttack = FindAttackAtTime( ce.attacks, g_fLastInsertAttackPositionSeconds ); @@ -3024,7 +3024,7 @@ static void ChangeArtistTranslit( const RString &sNew ) static void ChangeBeat0Offset( const RString &sNew ) { - GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sNew ); + GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds = StringToFloat( sNew ); } static void ChangeLastBeatHint( const RString &sNew ) @@ -3135,7 +3135,7 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns } g_StepsInformation.rows[difficulty].iDefaultChoice = pSteps->GetDifficulty(); g_StepsInformation.rows[difficulty].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full); - g_StepsInformation.rows[meter].SetOneUnthemedChoice( ssprintf("%d", pSteps->GetMeter()-1) ); + g_StepsInformation.rows[meter].SetOneUnthemedChoice( ssprintf("%d", pSteps->GetMeter()) ); g_StepsInformation.rows[meter].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Home); g_StepsInformation.rows[predict_meter].SetOneUnthemedChoice( ssprintf("%.2f",pSteps->PredictMeter()) ); g_StepsInformation.rows[description].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full); @@ -3242,7 +3242,7 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns g_SongInformation.rows[main_title_transliteration].SetOneUnthemedChoice( pSong->m_sMainTitleTranslit ); g_SongInformation.rows[sub_title_transliteration].SetOneUnthemedChoice( pSong->m_sSubTitleTranslit ); g_SongInformation.rows[artist_transliteration].SetOneUnthemedChoice( pSong->m_sArtistTranslit ); - g_SongInformation.rows[beat_0_offset].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_Timing.m_fBeat0OffsetInSeconds) ); + g_SongInformation.rows[beat_0_offset].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_SongTiming.m_fBeat0OffsetInSeconds) ); g_SongInformation.rows[last_beat_hint].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fSpecifiedLastBeat) ); g_SongInformation.rows[preview_start].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fMusicSampleStartSeconds) ); g_SongInformation.rows[preview_length].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fMusicSampleLengthSeconds) ); @@ -3256,9 +3256,9 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns case edit_timing_data: { const Song* pSong = GAMESTATE->m_pCurSong; - TimingData pTime = pSong->m_Timing; + TimingData pTime = pSong->m_SongTiming; const float fBeat = GAMESTATE->m_fSongBeat; - g_TimingDataInformation.rows[bpm].SetOneUnthemedChoice( ssprintf("%.5f", pSong->GetBPMAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[bpm].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetBPMAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[stop].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetStopAtBeat( fBeat ) ) ) ; g_TimingDataInformation.rows[delay].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetDelayAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[time_signature_numerator].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTimeSignatureNumeratorAtBeat( fBeat ) ) ); @@ -3501,7 +3501,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns NoteDataUtil::ScaleRegion( m_NoteDataEdit, fScale, iStartIndex, iEndIndex ); // scale timing data - m_pSong->m_Timing.ScaleRegion( fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker, true ); + m_pSong->m_SongTiming.ScaleRegion( fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker, true ); // scale all other steps. const vector sIter = m_pSong->GetAllSteps(); @@ -3546,16 +3546,16 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns NoteDataUtil::DeleteRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(1) ); break; case shift_pauses_forward: - m_pSong->m_Timing.InsertRows( BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(1) ); + m_pSong->m_SongTiming.InsertRows( BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(1) ); break; case shift_pauses_backward: - m_pSong->m_Timing.DeleteRows( BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(1) ); + m_pSong->m_SongTiming.DeleteRows( BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(1) ); break; case convert_to_pause: { ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); - float fMarkerStart = m_pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); - float fMarkerEnd = m_pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); + float fMarkerStart = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); + float fMarkerEnd = m_pSong->m_SongTiming.GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); // The length of the stop segment we're going to create. This includes time spent in any // stops in the selection, which will be deleted and subsumed into the new stop. @@ -3567,9 +3567,9 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns m_NoteFieldEdit.m_iBeginMarker + 1, m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); - m_pSong->m_Timing.DeleteRows( m_NoteFieldEdit.m_iBeginMarker, + m_pSong->m_SongTiming.DeleteRows( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); - m_pSong->m_Timing.SetStopAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); + m_pSong->m_SongTiming.SetStopAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); m_NoteFieldEdit.m_iBeginMarker = -1; m_NoteFieldEdit.m_iEndMarker = -1; break; @@ -3577,14 +3577,14 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns case convert_pause_to_beat: { // TODO: Convert both Delays and Stops at once. - float fStopSeconds = m_pSong->m_Timing.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ); - m_pSong->m_Timing.SetStopAtBeat( GAMESTATE->m_fSongBeat, 0 ); + float fStopSeconds = m_pSong->m_SongTiming.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ); + m_pSong->m_SongTiming.SetStopAtBeat( GAMESTATE->m_fSongBeat, 0 ); - float fStopBeats = fStopSeconds * m_pSong->GetBPMAtBeat(GAMESTATE->m_fSongBeat) / 60; + float fStopBeats = fStopSeconds * m_pSong->m_SongTiming.GetBPMAtBeat(GAMESTATE->m_fSongBeat) / 60; // don't move the step from where it is, just move everything later NoteDataUtil::InsertRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopBeats) ); - m_pSong->m_Timing.InsertRows( BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopBeats) ); + m_pSong->m_SongTiming.InsertRows( BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopBeats) ); } break; case undo: @@ -3701,7 +3701,7 @@ void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vec break; case beat_0_offset: ScreenTextEntry::TextEntry( SM_None, ENTER_BEAT_0_OFFSET, - ssprintf("%.5f", pSong->m_Timing.m_fBeat0OffsetInSeconds), 20, + ssprintf("%.5f", pSong->m_SongTiming.m_fBeat0OffsetInSeconds), 20, ScreenTextEntry::FloatValidate, ChangeBeat0Offset, NULL ); break; case last_beat_hint: @@ -3750,7 +3750,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromBPMChange, ENTER_BPM_VALUE, - ssprintf( "%.4f", m_pSong->GetBPMAtBeat(GAMESTATE->m_fSongBeat) ), + ssprintf( "%.4f", m_pSong->m_SongTiming.GetBPMAtBeat(GAMESTATE->m_fSongBeat) ), 10 ); break; @@ -3758,7 +3758,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromStopChange, ENTER_STOP_VALUE, - ssprintf( "%.4f", m_pSong->m_Timing.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ), + ssprintf( "%.4f", m_pSong->m_SongTiming.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ), 10 ); break; @@ -3766,7 +3766,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromDelayChange, ENTER_DELAY_VALUE, - ssprintf( "%.4f", m_pSong->m_Timing.GetDelayAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ), + ssprintf( "%.4f", m_pSong->m_SongTiming.GetDelayAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ), 10 ); break; @@ -3774,7 +3774,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromTimeSignatureNumeratorChange, ENTER_TIME_SIGNATURE_NUMERATOR_VALUE, - ssprintf( "%d", m_pSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator ), + ssprintf( "%d", m_pSong->m_SongTiming.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator ), 3 ); break; @@ -3782,7 +3782,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromTimeSignatureDenominatorChange, ENTER_TIME_SIGNATURE_DENOMINATOR_VALUE, - ssprintf( "%d", m_pSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iDenominator ), + ssprintf( "%d", m_pSong->m_SongTiming.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iDenominator ), 3 ); break; @@ -3790,7 +3790,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromTickcountChange, ENTER_TICKCOUNT_VALUE, - ssprintf( "%d", m_pSong->m_Timing.GetTickcountAtBeat( GAMESTATE->m_fSongBeat ) ), + ssprintf( "%d", m_pSong->m_SongTiming.GetTickcountAtBeat( GAMESTATE->m_fSongBeat ) ), 2 ); break; @@ -3798,7 +3798,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromComboChange, ENTER_COMBO_VALUE, - ssprintf( "%d", m_pSong->m_Timing.GetComboAtBeat( GAMESTATE->m_fSongBeat ) ), + ssprintf( "%d", m_pSong->m_SongTiming.GetComboAtBeat( GAMESTATE->m_fSongBeat ) ), 4 ); break; @@ -3806,7 +3806,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromLabelChange, ENTER_LABEL_VALUE, - ssprintf( "%s", m_pSong->m_Timing.GetLabelAtBeat( GAMESTATE->m_fSongBeat ).c_str() ), + ssprintf( "%s", m_pSong->m_SongTiming.GetLabelAtBeat( GAMESTATE->m_fSongBeat ).c_str() ), 64 ); break; @@ -3814,7 +3814,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromWarpChange, ENTER_WARP_VALUE, - ssprintf( "%.4f", m_pSong->m_Timing.GetWarpAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ), + ssprintf( "%.4f", m_pSong->m_SongTiming.GetWarpAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ), 10 ); break; @@ -4021,7 +4021,7 @@ void ScreenEdit::CheckNumberOfNotesAndUndo() if( EDIT_MODE.GetValue() != EditMode_Home ) return; - TimeSignatureSegment curTime = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ); + TimeSignatureSegment curTime = GAMESTATE->m_pCurSong->m_SongTiming.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ); int rowsPerMeasure = curTime.m_iDenominator * curTime.m_iNumerator; for( int row=0; row<=m_NoteDataEdit.GetLastRow(); row+=rowsPerMeasure ) @@ -4073,7 +4073,7 @@ float ScreenEdit::GetMaximumBeatForNewNote() const /* Round up to the next measure end. Some songs end on weird beats * mid-measure, and it's odd to have movement capped to these weird * beats. */ - int beatsPerMeasure = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator; + int beatsPerMeasure = GAMESTATE->m_pCurSong->m_SongTiming.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator; fEndBeat += beatsPerMeasure; fEndBeat = ftruncf( fEndBeat, (float)beatsPerMeasure ); diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index c9bf604ffb..ea10ca22a2 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -128,8 +128,7 @@ enum EditButton EDIT_BUTTON_SAMPLE_LENGTH_UP, EDIT_BUTTON_SAMPLE_LENGTH_DOWN, - // This modifies offset, BPM, and stop segment changes. - EDIT_BUTTON_ADJUST_FINE, + EDIT_BUTTON_ADJUST_FINE, /**< This button modifies offset, BPM, and stop segment changes. */ EDIT_BUTTON_SAVE, /**< Save the present changes into the chart. */ @@ -166,7 +165,9 @@ struct MapEditToDI } }; -// Like MapEditToDI, but maps GameButton instead of DeviceInput. +/** + * @brief This is similar to MapEditToDI, + * but maps GameButton instead of DeviceInput. */ struct MapEditButtonToMenuButton { GameButton button[NUM_EditButton][NUM_EDIT_TO_MENU_SLOTS]; @@ -214,11 +215,14 @@ protected: // Call this before modifying m_NoteDataEdit. void SaveUndo(); - // Revert m_NoteDataEdit using m_Undo. + /** @brief Revert the last change made to m_NoteDataEdit. */ void Undo(); + /** @brief Remove the previously stored NoteData to prevent undoing. */ void ClearUndo(); - // Call this after modifying m_NoteDataEdit. It will Undo() if - // MAX_NOTES_PER_MEASURE was exceeded. + /** + * @brief This is to be called after modifying m_NoteDataEdit. + * + * It will Undo itself if MAX_NOTES_PER_MEASURE was exceeded. */ void CheckNumberOfNotesAndUndo(); void OnSnapModeChange(); @@ -252,7 +256,10 @@ protected: // keep track of where we are and what we're doing float m_fTrailingBeat; // this approaches GAMESTATE->m_fSongBeat, which is the actual beat - // The location we were at when shift was pressed, or -1 when shift isn't pressed: + /** + * @brief The location we were at when shift was pressed. + * + * If shift wasn't pressed, this will be -1. */ int m_iShiftAnchor; /** @brief The NoteData that has been cut or copied. */ @@ -311,22 +318,23 @@ protected: ThemeMetric EDIT_MODE; public: + /** @brief What are the choices that one can make on the main menu? */ enum MainMenuChoice { play_selection, set_selection_start, set_selection_end, edit_steps_information, - play_whole_song, + play_whole_song, /**< Play the entire chart from the beginning. */ play_selection_start_to_end, play_current_beat_to_end, - save, + save, /**< Save the current chart to disk. */ revert_to_last_save, revert_from_disk, - options, - edit_song_info, - edit_timing_data, - play_preview_music, + options, /**< Modify the PlayerOptions and SongOptions. */ + edit_song_info, /**< Edit some general information about the song. */ + edit_timing_data, /**< Edit the chart's timing data. */ + play_preview_music, /**< Play the song's preview music. */ exit, save_on_exit, NUM_MAIN_MENU_CHOICES, @@ -361,13 +369,14 @@ public: }; void HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAnswers, bool bAllowUndo = true ); void HandleAreaMenuChoice( AreaMenuChoice c, bool bAllowUndo = true ) { const vector v; HandleAreaMenuChoice( c, v, bAllowUndo ); } + /** @brief How should the selected notes be transformed? */ enum TurnType { - left, - right, - mirror, - shuffle, - super_shuffle, + left, /**< Turn the notes as if you were facing to the left. */ + right, /**< Turn the notes as if you were facing to the right. */ + mirror, /**< Turn the notes as if you were facing away from the machine. */ + shuffle, /**< Replace one column with another column. */ + super_shuffle, /**< Replace each note individually. */ NUM_TURN_TYPES }; enum TransformType @@ -421,10 +430,10 @@ public: { difficulty, meter, - description, - chartstyle, - step_credit, - predict_meter, + description, /**< What is the description of this chart? */ + chartstyle, /**< How is this chart meant to be played? */ + step_credit, /**< Who wrote this individual chart? */ + predict_meter, /**< What does the game think this chart's rating should be? */ tap_notes, jumps, hands, diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index 1ac4b6d8c5..f2cba6c337 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -1423,7 +1423,7 @@ void ScreenGameplay::UpdateSongPosition( float fDeltaTime ) RageTimer tm; const float fSeconds = m_pSoundMusic->GetPositionSeconds( NULL, &tm ); const float fAdjust = SOUND->GetFrameTimingAdjustment( fDeltaTime ); - GAMESTATE->UpdateSongPosition( fSeconds+fAdjust, GAMESTATE->m_pCurSong->m_Timing, tm+fAdjust ); + GAMESTATE->UpdateSongPosition( fSeconds+fAdjust, GAMESTATE->m_pCurSong->m_SongTiming, tm+fAdjust ); } void ScreenGameplay::BeginScreen() @@ -1480,7 +1480,7 @@ bool ScreenGameplay::AllAreFailing() void ScreenGameplay::GetMusicEndTiming( float &fSecondsToStartFadingOutMusic, float &fSecondsToStartTransitioningOut ) { - float fLastStepSeconds = GAMESTATE->m_pCurSong->GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat ); + float fLastStepSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat ); fLastStepSeconds += Player::GetMaxStepDistanceSeconds(); float fTransitionLength; @@ -1995,7 +1995,7 @@ void ScreenGameplay::SendCrossedMessages() static int iRowLastCrossed = 0; float fPositionSeconds = GAMESTATE->m_fMusicSeconds; - float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds ); + float fSongBeat = GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime( fPositionSeconds ); int iRowNow = BeatToNoteRowNotRounded( fSongBeat ); iRowNow = max( 0, iRowNow ); @@ -2033,7 +2033,7 @@ void ScreenGameplay::SendCrossedMessages() float fNoteWillCrossInSeconds = MESSAGE_SPACING_SECONDS * i; float fPositionSeconds = GAMESTATE->m_fMusicSeconds + fNoteWillCrossInSeconds; - float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds ); + float fSongBeat = GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime( fPositionSeconds ); int iRowNow = BeatToNoteRowNotRounded( fSongBeat ); iRowNow = max( 0, iRowNow ); diff --git a/src/ScreenHowToPlay.cpp b/src/ScreenHowToPlay.cpp index 7deca6dd40..877fb693c4 100644 --- a/src/ScreenHowToPlay.cpp +++ b/src/ScreenHowToPlay.cpp @@ -244,7 +244,7 @@ void ScreenHowToPlay::Update( float fDelta ) { if( GAMESTATE->m_pCurSong != NULL ) { - GAMESTATE->UpdateSongPosition( m_fFakeSecondsIntoSong, GAMESTATE->m_pCurSong->m_Timing ); + GAMESTATE->UpdateSongPosition( m_fFakeSecondsIntoSong, GAMESTATE->m_pCurSong->m_SongTiming ); m_fFakeSecondsIntoSong += fDelta; static int iLastNoteRowCounted = 0; diff --git a/src/ScreenSelectMusic.cpp b/src/ScreenSelectMusic.cpp index fe4aee3aab..4ecb227b3b 100644 --- a/src/ScreenSelectMusic.cpp +++ b/src/ScreenSelectMusic.cpp @@ -1763,7 +1763,7 @@ void ScreenSelectMusic::AfterMusicChange() case SampleMusicPreviewMode_LastSong: // fall through // play the sample music m_sSampleMusicToPlay = pSong->GetMusicPath(); - m_pSampleMusicTimingData = &pSong->m_Timing; + m_pSampleMusicTimingData = &pSong->m_SongTiming; m_fSampleStartSeconds = pSong->m_fMusicSampleStartSeconds; m_fSampleLengthSeconds = pSong->m_fMusicSampleLengthSeconds; break; diff --git a/src/ScreenSyncOverlay.cpp b/src/ScreenSyncOverlay.cpp index a0038b083f..baf240d54d 100644 --- a/src/ScreenSyncOverlay.cpp +++ b/src/ScreenSyncOverlay.cpp @@ -221,7 +221,7 @@ bool ScreenSyncOverlay::OverlayInput( const InputEventPlus &input ) } if( GAMESTATE->m_pCurSong != NULL ) { - BPMSegment& seg = GAMESTATE->m_pCurSong->GetBPMSegmentAtBeat( GAMESTATE->m_fSongBeat ); + BPMSegment& seg = GAMESTATE->m_pCurSong->m_SongTiming.GetBPMSegmentAtBeat( GAMESTATE->m_fSongBeat ); seg.m_fBPS += fDelta; } } @@ -253,7 +253,7 @@ bool ScreenSyncOverlay::OverlayInput( const InputEventPlus &input ) case ChangeSongOffset: if( GAMESTATE->m_pCurSong != NULL ) - GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += fDelta; + GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += fDelta; break; } } diff --git a/src/Song.cpp b/src/Song.cpp index 6d9022177b..a2c5184425 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -167,7 +167,7 @@ void Song::GetDisplayBpms( DisplayBpms &AddTo ) const else { float fMinBPM, fMaxBPM; - m_Timing.GetActualBPM( fMinBPM, fMaxBPM ); + m_SongTiming.GetActualBPM( fMinBPM, fMaxBPM ); AddTo.Add( fMinBPM ); AddTo.Add( fMaxBPM ); } @@ -488,29 +488,30 @@ void Song::TidyUpData() m_sArtist = "Unknown artist"; TranslateTitles(); - if( m_Timing.m_BPMSegments.empty() ) + if( m_SongTiming.m_BPMSegments.empty() ) { LOG->UserLog( "Song file", m_sSongDir + m_sSongFileName, "has no BPM segments, default provided." ); - m_Timing.AddBPMSegment( BPMSegment(0, 60) ); + m_SongTiming.AddBPMSegment( BPMSegment(0, 60) ); } // Make sure the first BPM segment starts at beat 0. - if( m_Timing.m_BPMSegments[0].m_iStartRow != 0 ) - m_Timing.m_BPMSegments[0].m_iStartRow = 0; + if( m_SongTiming.m_BPMSegments[0].m_iStartRow != 0 ) + m_SongTiming.m_BPMSegments[0].m_iStartRow = 0; if( m_fMusicSampleStartSeconds == -1 || m_fMusicSampleStartSeconds == 0 || m_fMusicSampleStartSeconds+m_fMusicSampleLengthSeconds > this->m_fMusicLengthSeconds ) { - m_fMusicSampleStartSeconds = this->GetElapsedTimeFromBeat( 100 ); + const TimingData &timing = this->m_SongTiming; + m_fMusicSampleStartSeconds = timing.GetElapsedTimeFromBeat( 100 ); if( m_fMusicSampleStartSeconds+m_fMusicSampleLengthSeconds > this->m_fMusicLengthSeconds ) { int iBeat = lrintf( m_fLastBeat/2 ); iBeat -= iBeat%4; - m_fMusicSampleStartSeconds = this->GetElapsedTimeFromBeat( (float)iBeat ); + m_fMusicSampleStartSeconds = timing.GetElapsedTimeFromBeat( (float)iBeat ); } } @@ -791,10 +792,10 @@ void Song::TidyUpData() } // If no time signature specified, assume 4/4 time for the whole song. - if( m_Timing.m_vTimeSignatureSegments.empty() ) + if( m_SongTiming.m_vTimeSignatureSegments.empty() ) { TimeSignatureSegment seg(0, 4, 4); - m_Timing.m_vTimeSignatureSegments.push_back( seg ); + m_SongTiming.m_vTimeSignatureSegments.push_back( seg ); } /* @@ -802,24 +803,24 @@ void Song::TidyUpData() * per beat for the entire song. The default of 2 is chosen more * for compatibility with the Pump Pro series than anything else. */ - if( m_Timing.m_TickcountSegments.empty() ) + if( m_SongTiming.m_TickcountSegments.empty() ) { TickcountSegment seg(0, 2); - m_Timing.m_TickcountSegments.push_back( seg ); + m_SongTiming.m_TickcountSegments.push_back( seg ); } // Have a default combo segment of one just in case. - if( m_Timing.m_ComboSegments.empty() ) + if( m_SongTiming.m_ComboSegments.empty() ) { ComboSegment seg(0, 1); - m_Timing.m_ComboSegments.push_back( seg ); + m_SongTiming.m_ComboSegments.push_back( seg ); } // Have a default label segment just in case. - if( m_Timing.m_LabelSegments.empty() ) + if( m_SongTiming.m_LabelSegments.empty() ) { LabelSegment seg(0, "Song Start"); - m_Timing.m_LabelSegments.push_back( seg ); + m_SongTiming.m_LabelSegments.push_back( seg ); } } @@ -1465,7 +1466,7 @@ bool Song::IsEditAlreadyLoaded( Steps* pSteps ) const bool Song::HasSignificantBpmChangesOrStops() const { - if( m_Timing.HasStops() ) + if( m_SongTiming.HasStops() ) return true; // Don't consider BPM changes that only are only for maintaining sync as @@ -1475,7 +1476,7 @@ bool Song::HasSignificantBpmChangesOrStops() const if( m_fSpecifiedBPMMin != m_fSpecifiedBPMMax ) return true; } - else if( m_Timing.HasBpmChanges() ) + else if( m_SongTiming.HasBpmChanges() ) { return true; } @@ -1485,7 +1486,8 @@ bool Song::HasSignificantBpmChangesOrStops() const float Song::GetStepsSeconds() const { - return GetElapsedTimeFromBeat( m_fLastBeat ) - GetElapsedTimeFromBeat( m_fFirstBeat ); + const TimingData &timing = this->m_SongTiming; + return timing.GetElapsedTimeFromBeat( m_fLastBeat ) - timing.GetElapsedTimeFromBeat( m_fFirstBeat ); } bool Song::IsLong() const @@ -1568,7 +1570,7 @@ public: } static int GetTimingData( T* p, lua_State *L ) { - p->m_Timing.PushSelf(L); + p->m_SongTiming.PushSelf(L); return 1; } // has functions diff --git a/src/Song.h b/src/Song.h index 1d49724795..ac41bf476c 100644 --- a/src/Song.h +++ b/src/Song.h @@ -17,7 +17,7 @@ struct lua_State; struct BackgroundChange; /** @brief The version of the .ssc file format. */ -const static float STEPFILE_VERSION_NUMBER = 0.59f; +const static float STEPFILE_VERSION_NUMBER = 0.7f; /** @brief How many edits for this song can each profile have? */ const int MAX_EDITS_PER_SONG_PER_PROFILE = 5; diff --git a/src/TimingData.cpp b/src/TimingData.cpp index bb6911fad4..022976a349 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -8,10 +8,16 @@ #include -TimingData::TimingData() +TimingData::TimingData() : + m_fBeat0OffsetInSeconds(0), + m_bHasNegativeBpms(false) { - m_fBeat0OffsetInSeconds = 0; - m_bHasNegativeBpms = false; +} + +TimingData::TimingData(float fOffset) : + m_fBeat0OffsetInSeconds(fOffset), + m_bHasNegativeBpms(false) +{ } void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut ) const diff --git a/src/TimingData.h b/src/TimingData.h index 5464a8748e..36f1d33456 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -658,6 +658,10 @@ public: * @brief Sets up initial timing data. */ TimingData(); + /** + * @brief Sets up initial timing data with a defined offset. + * @param fOffset the offset from the 0th beat. */ + TimingData(float fOffset); /** * @brief Gets the actual BPM of the song. * @param fMinBPMOut the minimium specified BPM.