From 4316579e897b6730abfc178dcbcd77d0d4e67b2f Mon Sep 17 00:00:00 2001 From: Thai Pangsakulyanont Date: Fri, 25 Mar 2011 23:19:31 +0700 Subject: [PATCH] [warps] my attempt at making warps work. see commit message. + TimingData: rewrote GetBeatAndBPSFromElapsedTimeNoOffset and GetBeatFromElapsedTimeNoOffset to make it simpler and compute times correctly, by going through 3 arrays at the same time. + TimingData: added TimingData::IsWarpAtRow(int) just in case. + The skipping part is now handled by TimingData. Current issues: + the rewritten function does not check if the vectors are sorted. + if you press the notes after the skip before the skip is reached, the notes in the warp range got hit instead because m_iWarpBeginRow was not set before the warp is reached. + the notes after the skipped part are not judged if hit before the warp is reached and the warp is big enough. --- src/GameState.cpp | 4 +- src/Player.cpp | 9 +- src/TimingData.cpp | 357 +++++++++++++++++++++++---------------------- src/TimingData.h | 8 +- 4 files changed, 196 insertions(+), 182 deletions(-) diff --git a/src/GameState.cpp b/src/GameState.cpp index 7bceea64db..581c882b08 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -962,7 +962,8 @@ void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &ti ASSERT_M( m_fSongBeat > -2000, ssprintf("Song beat %f at %f seconds", m_fSongBeat, fPositionSeconds) ); //if( m_iWarpBeginRow != -1 || m_iWarpEndRow == -1 ) - + + /* if( m_iWarpBeginRow != -1 && m_fWarpDestination > 0.0f ) { float fWarpLength = m_fWarpDestination-NoteRowToBeat(m_iWarpBeginRow); @@ -973,6 +974,7 @@ void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &ti BeatToNoteRow(m_fWarpDestination)); fPositionSeconds += (fWarpLength * m_fCurBPS); } + */ m_fMusicSeconds = fPositionSeconds; diff --git a/src/Player.cpp b/src/Player.cpp index 92ef0dc81d..da11ff8cdf 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -2522,8 +2522,8 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) { //LOG->Trace( "Steps::UpdateTapNotesMissedOlderThan(%f)", fMissIfOlderThanThisBeat ); int iMissIfOlderThanThisRow; + const float fEarliestTime = GAMESTATE->m_fMusicSeconds - fMissIfOlderThanSeconds; { - const float fEarliestTime = GAMESTATE->m_fMusicSeconds - fMissIfOlderThanSeconds; bool bFreeze, bDelay; float fMissIfOlderThanThisBeat; float fThrowAway; @@ -2550,7 +2550,7 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) if( !NeedsTapJudging(tn) ) continue; - + // Ignore all notes that are skipped via WARPS. if( iter.Row() >= GAMESTATE->m_iWarpBeginRow && iter.Row() < BeatToNoteRow(GAMESTATE->m_fWarpDestination) ) continue; @@ -2568,11 +2568,6 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) } else { - // warp hackery: don't score notes within the warp region. - // (Only useful when QuirksMode is enabled.) -aj - if( iter.Row() >= GAMESTATE->m_iWarpBeginRow && iter.Row() < BeatToNoteRow(GAMESTATE->m_fWarpDestination) ) - continue; - tn.result.tns = TNS_Miss; } } diff --git a/src/TimingData.cpp b/src/TimingData.cpp index a8eaaf2704..ea0c30b937 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -341,6 +341,18 @@ int TimingData::GetWarpSegmentIndexAtRow( int iNoteRow ) const return static_cast(i); } +bool TimingData::IsWarpAtRow( int iNoteRow ) const +{ + unsigned i; + for( i=0; i= iNoteRow ) + return iNoteRow < BeatToNoteRow(m_WarpSegments[i].m_fEndBeat); + } + return false; +} + int TimingData::GetTimeSignatureSegmentIndexAtRow( int iRow ) const { unsigned i; @@ -451,150 +463,116 @@ void TimingData::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatO GetBeatAndBPSFromElapsedTimeNoOffset( fElapsedTime, fBeatOut, fBPSOut, bFreezeOut, bDelayOut, iWarpBeginOut, fWarpLengthOut ); } -void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpLengthOut ) const +enum { -// LOG->Trace( "GetBeatAndBPSFromElapsedTime( fElapsedTime = %f )", fElapsedTime ); - const float fTime = fElapsedTime; - fElapsedTime += m_fBeat0OffsetInSeconds; + FOUND_WARP, + FOUND_WARP_DESTINATION, + FOUND_BPM_CHANGE, + FOUND_STOP, + FOUND_MARKER, + NOT_FOUND +}; - for( unsigned i=0; i::const_iterator itBPMS = m_BPMSegments.begin(); + vector::const_iterator itWS = m_WarpSegments.begin(); + vector::const_iterator itSS = m_StopSegments.begin(); + + bFreezeOut = false; + bDelayOut = false; + + iWarpBeginOut = -1; + + int iLastRow = 0; + float fLastTime = -m_fBeat0OffsetInSeconds; + float fBPS = GetBPMAtRow(0) / 60.0; + + float bIsWarping = false; + float fWarpDestination = 0.0; + + for( ;; ) { - const int iStartRowThisSegment = m_BPMSegments[i].m_iStartRow; - const float fStartBeatThisSegment = NoteRowToBeat( iStartRowThisSegment ); - const bool bIsFirstBPMSegment = i==0; - const bool bIsLastBPMSegment = i==m_BPMSegments.size()-1; - const int iStartRowNextSegment = bIsLastBPMSegment ? MAX_NOTE_ROW : m_BPMSegments[i+1].m_iStartRow; - const float fStartBeatNextSegment = NoteRowToBeat( iStartRowNextSegment ); - const float fBPS = m_BPMSegments[i].m_fBPS; - - for( unsigned j=0; j= m_StopSegments[j].m_iStartRow ) - continue; - if( !bIsLastBPMSegment && m_StopSegments[j].m_iStartRow > iStartRowNextSegment ) - continue; - - // this freeze lies within this BPMSegment - const int iRowsBeatsSinceStartOfSegment = m_StopSegments[j].m_iStartRow - iStartRowThisSegment; - const float fBeatsSinceStartOfSegment = NoteRowToBeat(iRowsBeatsSinceStartOfSegment); - const float fFreezeStartSecond = fBeatsSinceStartOfSegment / fBPS; - - // modified for delays - if( !bIsDelay && fFreezeStartSecond >= fElapsedTime ) - break; - if( bIsDelay && fFreezeStartSecond > fElapsedTime ) - break; - - // the freeze segment is <= current time - fElapsedTime -= m_StopSegments[j].m_fStopSeconds; - - if( (fFreezeStartSecond >= fElapsedTime && !bIsDelay) || - (fFreezeStartSecond > fElapsedTime && bIsDelay) ) + iEventRow = BeatToNoteRow(fWarpDestination); + iEventType = FOUND_WARP_DESTINATION; + } + if( itWS != m_WarpSegments.end() && itWS->m_iStartRow < iEventRow ) + { + iEventRow = itWS->m_iStartRow; + iEventType = FOUND_WARP; + } + if( itBPMS != m_BPMSegments.end() && itBPMS->m_iStartRow < iEventRow ) + { + iEventRow = itBPMS->m_iStartRow; + iEventType = FOUND_BPM_CHANGE; + } + if( itSS != m_StopSegments.end() && itSS->m_iStartRow < iEventRow ) + { + iEventRow = itSS->m_iStartRow; + iEventType = FOUND_STOP; + } + if( iEventType == NOT_FOUND ) + { + break; + } + float fTimeToNextEvent = bIsWarping ? 0 : NoteRowToBeat( iEventRow - iLastRow ) / fBPS; + float fNextEventTime = fLastTime + fTimeToNextEvent; + if ( fElapsedTime < fNextEventTime ) + { + break; + } + fLastTime = fNextEventTime; + switch( iEventType ) + { + case FOUND_WARP_DESTINATION: + bIsWarping = false; + break; + case FOUND_WARP: + bIsWarping = true; + if( itWS->m_fEndBeat > fWarpDestination ) + { + fWarpDestination = itWS->m_fEndBeat; + } + iWarpBeginOut = iEventRow; + fWarpDestinationOut = fWarpDestination; + itWS ++; + break; + case FOUND_BPM_CHANGE: + fBPS = itBPMS->m_fBPS; + itBPMS ++; + break; + case FOUND_STOP: + fTimeToNextEvent = bIsWarping ? 0 : itSS->m_fStopSeconds; + fNextEventTime = fLastTime + fTimeToNextEvent; + const bool bIsDelay = itSS->m_bDelay; + if ( fElapsedTime < fNextEventTime ) { - // The time lies within the stop. - fBeatOut = NoteRowToBeat(m_StopSegments[j].m_iStartRow); - fBPSOut = fBPS; bFreezeOut = !bIsDelay; - bDelayOut = bIsDelay; - //iWarpBeginOut = -1; - //fWarpLengthOut = -1; + bDelayOut = bIsDelay; + fBeatOut = NoteRowToBeat( itSS->m_iStartRow ); + fBPSOut = fBPS; return; } + fLastTime = fNextEventTime; + itSS ++; + break; } - - // by this point we should have the warps in their own place. - for( unsigned j=0; j= m_WarpSegments[j].m_iStartRow ) - continue; - if( !bIsLastBPMSegment && m_WarpSegments[j].m_iStartRow > iStartRowNextSegment ) - continue; - - /* - const int iRowsBeatsSinceStartOfSegment = m_WarpSegments[j].m_iStartRow - iStartRowThisSegment; - const float fBeatsSinceStartOfSegment = NoteRowToBeat(iRowsBeatsSinceStartOfSegment); - const float fWarpStartSecond = fBeatsSinceStartOfSegment / fBPS; - */ - - // the freeze segment is <= current time - //fElapsedTime -= m_WarpSegments[j].m_fEndBeat; - - // this warp lies within this BPMSegment. - /* - if( fWarpStartSecond >= fElapsedTime ) - { - // this WarpSegment IS the current segment. - // don't know how to properly handle beatout -aj - //fBeatOut = NoteRowToBeat(m_WarpSegments[j].m_iStartRow); - fBeatOut = fStartBeatThisSegment + fElapsedTime*fBPS; - fBPSOut = m_BPMSegments[i+1].m_fBPS; - bFreezeOut = false; - bDelayOut = false; - iWarpBeginOut = m_WarpSegments[j].m_iStartRow; - fWarpLengthOut = m_WarpSegments[j].m_fEndBeat; - return; - } - */ - } - - const float fBeatsInThisSegment = fStartBeatNextSegment - fStartBeatThisSegment; - const float fSecondsInThisSegment = fBeatsInThisSegment / fBPS; - //if(fBPS < 0.0f) - /* - if(fStartBeatThisSegment == 445.500f || fStartBeatThisSegment == 449.500) - { - LOG->Trace( ssprintf("segment (beat %f) beats: %f / seconds: %f / BPS: %f",fStartBeatThisSegment,fBeatsInThisSegment,fSecondsInThisSegment,fBPS) ); - } - */ - if( bIsLastBPMSegment || fElapsedTime <= fSecondsInThisSegment ) - { - // this BPMSegment IS the current segment. - fBeatOut = fStartBeatThisSegment + fElapsedTime*fBPS; - fBPSOut = fBPS; - bFreezeOut = false; - bDelayOut = false; - //iWarpBeginOut; - //fWarpLengthOut; - return; - } - - // this BPMSegment is NOT the current segment. - fElapsedTime -= fSecondsInThisSegment; - // xxx: negative testing [aj] - /* - //if(fBPS < 0.0f) - if( (fStartBeatNextSegment >= 445.490f && fStartBeatNextSegment <= 453.72f) || fBPS < 0.0f ) - { - //LOG->Trace( ssprintf("beat %f is %f BPS (%f BPM)",fBeatOut,fBPSOut,fBPSOut*60.0f) ); - //LOG->Trace( ssprintf("start beat %f + elapsed time %f",fStartBeatThisSegment,fElapsedTime) ); - //LOG->Trace( ssprintf("elapsed time is now %f",fElapsedTime) ); - } - */ + iLastRow = iEventRow; } - // If we get here, something has gone wrong. Is everything sorted? - vector vBPMS = m_BPMSegments; - vector vSS = m_StopSegments; - vector vWS = m_WarpSegments; - vector vTSS = m_vTimeSignatureSegments; - vector vTS = m_TickcountSegments; - vector vCS = m_ComboSegments; - sort( vBPMS.begin(), vBPMS.end() ); - sort( vSS.begin(), vSS.end() ); - sort( vWS.begin(), vWS.end() ); - sort( vTSS.begin(), vTSS.end() ); - sort( vTS.begin(), vTS.end() ); - sort( vCS.begin(), vCS.end() ); - ASSERT_M( vBPMS == m_BPMSegments, "The BPM segments were not sorted!" ); - ASSERT_M( vSS == m_StopSegments, "The Stop segments were not sorted!" ); - ASSERT_M( vWS == m_WarpSegments, "The Warp segments were not sorted!" ); - ASSERT_M( vTSS == m_vTimeSignatureSegments, "The Time Signature segments were not sorted!" ); - ASSERT_M( vTS == m_TickcountSegments, "The Tickcount segments were not sorted!" ); - ASSERT_M( vCS == m_ComboSegments, "The Combo segments were not sorted!" ); - FAIL_M( ssprintf("Failed to find the appropriate segment for elapsed time %f.", fTime) ); + + fBeatOut = NoteRowToBeat( iLastRow ) + (fElapsedTime - fLastTime) * fBPS; + fBPSOut = fBPS; + } + + float TimingData::GetElapsedTimeFromBeat( float fBeat ) const { return TimingData::GetElapsedTimeFromBeatNoOffset( fBeat ) - PREFSMAN->m_fGlobalOffsetSeconds; @@ -602,53 +580,86 @@ float TimingData::GetElapsedTimeFromBeat( float fBeat ) const float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const { - float fElapsedTime = 0; - fElapsedTime -= m_fBeat0OffsetInSeconds; - int iRow = BeatToNoteRow(fBeat); - for( unsigned j=0; j::const_iterator itBPMS = m_BPMSegments.begin(); + vector::const_iterator itWS = m_WarpSegments.begin(); + vector::const_iterator itSS = m_StopSegments.begin(); + + int iLastRow = 0; + float fLastTime = -m_fBeat0OffsetInSeconds; + float fBPS = GetBPMAtRow(0) / 60.0; + + float bIsWarping = false; + float fWarpDestination = 0.0; + + for( ;; ) { - /* A traditional stop has the beat happening before the stop. (>=) - * A Pump delay acts differently: the pause is before the beat. (>) - */ - if( ( m_StopSegments[j].m_iStartRow >= iRow && !m_StopSegments[j].m_bDelay ) || - ( m_StopSegments[j].m_iStartRow > iRow && m_StopSegments[j].m_bDelay ) ) + int iEventRow = INT_MAX; + int iEventType = NOT_FOUND; + if( bIsWarping && BeatToNoteRow(fWarpDestination) < iEventRow ) + { + iEventRow = BeatToNoteRow(fWarpDestination); + iEventType = FOUND_WARP_DESTINATION; + } + if( itWS != m_WarpSegments.end() && itWS->m_iStartRow < iEventRow ) + { + iEventRow = itWS->m_iStartRow; + iEventType = FOUND_WARP; + } + if( itBPMS != m_BPMSegments.end() && itBPMS->m_iStartRow < iEventRow ) + { + iEventRow = itBPMS->m_iStartRow; + iEventType = FOUND_BPM_CHANGE; + } + if( itSS != m_StopSegments.end() && itSS->m_bDelay && itSS->m_iStartRow < iEventRow ) + { + iEventRow = itSS->m_iStartRow; + iEventType = FOUND_STOP; + } + if( BeatToNoteRow(fBeat) < iEventRow ) + { + iEventRow = BeatToNoteRow(fBeat); + iEventType = FOUND_MARKER; + } + if( itSS != m_StopSegments.end() && !itSS->m_bDelay && itSS->m_iStartRow < iEventRow ) + { + iEventRow = itSS->m_iStartRow; + iEventType = FOUND_STOP; + } + float fTimeToNextEvent = bIsWarping ? 0 : NoteRowToBeat( iEventRow - iLastRow ) / fBPS; + float fNextEventTime = fLastTime + fTimeToNextEvent; + fLastTime = fNextEventTime; + switch( iEventType ) + { + case FOUND_WARP_DESTINATION: + bIsWarping = false; break; - fElapsedTime += m_StopSegments[j].m_fStopSeconds; - } - - for( unsigned i=0; im_fEndBeat > fWarpDestination ) + { + fWarpDestination = itWS->m_fEndBeat; + } + itWS ++; + break; + case FOUND_BPM_CHANGE: + fBPS = itBPMS->m_fBPS; + itBPMS ++; + break; + case FOUND_STOP: + fTimeToNextEvent = bIsWarping ? 0 : itSS->m_fStopSeconds; + fNextEventTime = fLastTime + fTimeToNextEvent; + fLastTime = fNextEventTime; + itSS ++; + break; + case FOUND_MARKER: + return fLastTime; } - else - { - const int iStartIndexThisSegment = m_BPMSegments[i].m_iStartRow; - const int iStartIndexNextSegment = m_BPMSegments[i+1].m_iStartRow; - const int iRowsInThisSegment = min( iStartIndexNextSegment - iStartIndexThisSegment, iRow ); - fElapsedTime += NoteRowToBeat( iRowsInThisSegment ) / fBPS; - iRow -= iRowsInThisSegment; - } - - if( iRow <= 0 ) - return fElapsedTime; + iLastRow = iEventRow; } - - /* - for( unsigned i=0; i