Represent TimingData values (except for "seconds") in fixed-point.

Maybe we should stop calling note indexes "rows" and "indexes", and just
call them "beats"; if they're stored as an integer, they're in fixed-point.  Things
like "note rows per second" are a lot less intuitive than just calling them "beats
per second".
This commit is contained in:
Glenn Maynard
2005-01-23 21:55:01 +00:00
parent 1929824277
commit 3634c07656
12 changed files with 186 additions and 127 deletions
+5 -3
View File
@@ -308,19 +308,21 @@ void Background::LoadFromRandom( float fFirstBeat, float fLastBeat, const Timing
}
// change BG every BPM change that is at the beginning of a measure
int iStartIndex = BeatToNoteRow(fFirstBeat);
int iEndIndex = BeatToNoteRow(fLastBeat);
for( unsigned i=0; i<timing.m_BPMSegments.size(); i++ )
{
const BPMSegment& bpmseg = timing.m_BPMSegments[i];
if( fmodf(bpmseg.m_fStartBeat, (float)BEATS_PER_MEASURE) != 0 )
if( bpmseg.m_iStartIndex % BeatToNoteRow((float) BEATS_PER_MEASURE) != 0 )
continue; // skip
if( bpmseg.m_fStartBeat < fFirstBeat || bpmseg.m_fStartBeat > fLastBeat )
if( bpmseg.m_iStartIndex < iStartIndex || bpmseg.m_iStartIndex > iEndIndex )
continue; // skip
CString sBGName = CreateRandomBGA();
if( sBGName != "" )
m_aBGChanges.push_back( BackgroundChange(bpmseg.m_fStartBeat,sBGName) );
m_aBGChanges.push_back( BackgroundChange(NoteRowToBeat(bpmseg.m_iStartIndex),sBGName) );
}
}
+6 -6
View File
@@ -485,9 +485,9 @@ void NoteField::DrawPrimitives()
vector<BPMSegment> &aBPMSegments = GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments;
for( unsigned i=0; i<aBPMSegments.size(); i++ )
{
if(aBPMSegments[i].m_fStartBeat >= fFirstBeatToDraw &&
aBPMSegments[i].m_fStartBeat <= fLastBeatToDraw)
DrawBPMText( aBPMSegments[i].m_fStartBeat, aBPMSegments[i].m_fBPM );
if(aBPMSegments[i].m_iStartIndex >= iFirstIndexToDraw &&
aBPMSegments[i].m_iStartIndex <= iLastIndexToDraw)
DrawBPMText( NoteRowToBeat(aBPMSegments[i].m_iStartIndex), aBPMSegments[i].GetBPM() );
}
//
// Freeze text
@@ -495,9 +495,9 @@ void NoteField::DrawPrimitives()
vector<StopSegment> &aStopSegments = GAMESTATE->m_pCurSong->m_Timing.m_StopSegments;
for( unsigned i=0; i<aStopSegments.size(); i++ )
{
if(aStopSegments[i].m_fStartBeat >= fFirstBeatToDraw &&
aStopSegments[i].m_fStartBeat <= fLastBeatToDraw)
DrawFreezeText( aStopSegments[i].m_fStartBeat, aStopSegments[i].m_fStopSeconds );
if(aStopSegments[i].m_iStartRow >= iFirstIndexToDraw &&
aStopSegments[i].m_iStartRow <= iLastIndexToDraw)
DrawFreezeText( NoteRowToBeat(aStopSegments[i].m_iStartRow), NoteRowToBeat(aStopSegments[i].m_iStartRow) );
}
//
+16 -11
View File
@@ -10,6 +10,7 @@
#include "song.h"
#include "Steps.h"
#include "RageUtil_CharConversions.h"
#include "NoteTypes.h"
/* BMS encoding: tap-hold
4&8panel: Player1 Player2
@@ -602,10 +603,10 @@ void BMSLoader::ReadGlobalTags( const NameToData_t &mapNameToData, Song &out )
if( GetTagFromMap( mapNameToData, "#bpm", sData ) )
{
BPMSegment newSeg( 0, strtof(sData, NULL) );
BPMSegment newSeg( 0, BeatToNoteRow(strtof(sData, NULL)) );
out.AddBPMSegment( newSeg );
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", newSeg.m_fStartBeat, newSeg.m_fBPM );
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(newSeg.m_iStartIndex), newSeg.GetBPM() );
}
NameToData_t::const_iterator it;
@@ -691,9 +692,11 @@ void BMSLoader::ReadGlobalTags( const NameToData_t &mapNameToData, Song &out )
{
float fBPM = strtof( sBPM, NULL );
BPMSegment newSeg( fBeat, fBPM );
BPMSegment newSeg;
newSeg.m_iStartIndex = BeatToNoteRow(fBeat);
newSeg.SetBPM( fBPM );
out.AddBPMSegment( newSeg );
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", newSeg.m_fStartBeat, newSeg.m_fBPM );
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", fBeat, newSeg.GetBPM() );
}
else
LOG->Warn( "Couldn't find tag '%s' in '%s'.", sTagToLookFor.c_str(), m_sDir.c_str() );
@@ -710,9 +713,9 @@ void BMSLoader::ReadGlobalTags( const NameToData_t &mapNameToData, Song &out )
float fBeats = strtof(sBeats,NULL) / 48.0f;
float fFreezeSecs = fBeats / fBPS;
StopSegment newSeg( fBeat, fFreezeSecs );
StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs );
out.AddStopSegment( newSeg );
LOG->Trace( "Inserting new Freeze at beat %f, secs %f", newSeg.m_fStartBeat, newSeg.m_fStopSeconds );
LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.m_fStopSeconds );
}
else
LOG->Warn( "Couldn't find tag '%s' in '%s'.", sTagToLookFor.c_str(), m_sDir.c_str() );
@@ -735,9 +738,11 @@ void BMSLoader::ReadGlobalTags( const NameToData_t &mapNameToData, Song &out )
{
float fBPM = strtof( sBPM, NULL );
BPMSegment newSeg( NoteRowToBeat(iStepIndex), fBPM );
BPMSegment newSeg;
newSeg.m_iStartIndex = iStepIndex;
newSeg.SetBPM( fBPM );
out.AddBPMSegment( newSeg );
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", newSeg.m_fStartBeat, newSeg.m_fBPM );
LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(newSeg.m_iStartIndex), newSeg.GetBPM() );
}
else
LOG->Warn( "Couldn't find tag '%s' in '%s'.", sTagToLookFor.c_str(), m_sDir.c_str() );
@@ -834,9 +839,9 @@ void BMSLoader::SetTimeSigAdjustments( const MeasureToTimeSig_t &sigs, Song *pOu
* adjustment and the BPM adjustment together, everything remains consistent.
* Adjust m_TimeSigAdjustments first, or fAdjustmentEndBeat will be wrong. */
m_TimeSigAdjustments[iMeasure] = 1.0f / fFactor;
float fAdjustmentStartBeat = NoteRowToBeat( GetMeasureStartRow( sigs, iMeasure ) );
float fAdjustmentEndBeat = NoteRowToBeat( GetMeasureStartRow( sigs, iMeasure+1 ) );
pOut->m_Timing.MultiplyBPMInBeatRange( fAdjustmentStartBeat, fAdjustmentEndBeat, 1.0f / fFactor );
int iAdjustmentStartRow = GetMeasureStartRow( sigs, iMeasure );
int iAdjustmentEndRow = GetMeasureStartRow( sigs, iMeasure+1 );
pOut->m_Timing.MultiplyBPMInBeatRange( iAdjustmentStartRow, iAdjustmentEndRow, 1.0f / fFactor );
}
}
+7 -8
View File
@@ -375,7 +375,7 @@ bool DWILoader::LoadFromDWIFile( CString sPath, Song &out )
out.m_sCDTitleFile = sParams[1];
else if( 0==stricmp(sValueName,"BPM") )
out.AddBPMSegment( BPMSegment(0, strtof(sParams[1], NULL)) );
out.AddBPMSegment( BPMSegment(0, BeatToNoteRow(strtof(sParams[1], NULL))) );
else if( 0==stricmp(sValueName,"DISPLAYBPM") )
{
@@ -425,11 +425,10 @@ bool DWILoader::LoadFromDWIFile( CString sPath, Song &out )
LOG->Warn( "Invalid FREEZE in '%s': '%s'", m_sLoadingFile.c_str(), arrayFreezeExpressions[f].c_str() );
continue;
}
float fIndex = strtof( arrayFreezeValues[0],NULL ) * ROWS_PER_BEAT / 4.0f;
float fFreezeBeat = NoteRowToBeat( fIndex );
int iFreezeRow = BeatToNoteRow( strtof( arrayFreezeValues[0],NULL ) / 4.0f );
float fFreezeSeconds = strtof( arrayFreezeValues[1], NULL ) / 1000.0f;
out.AddStopSegment( StopSegment(fFreezeBeat, fFreezeSeconds) );
out.AddStopSegment( StopSegment(iFreezeRow, fFreezeSeconds) );
// LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", fFreezeBeat, fFreezeSeconds );
}
}
@@ -448,11 +447,11 @@ bool DWILoader::LoadFromDWIFile( CString sPath, Song &out )
LOG->Warn( "Invalid CHANGEBPM in '%s': '%s'", m_sLoadingFile.c_str(), arrayBPMChangeExpressions[b].c_str() );
continue;
}
float fIndex = strtof( arrayBPMChangeValues[0], NULL ) * ROWS_PER_BEAT / 4.0f;
float fBeat = NoteRowToBeat( fIndex );
float fNewBPM = strtof( arrayBPMChangeValues[1], NULL );
out.AddBPMSegment( BPMSegment(fBeat, fNewBPM) );
BPMSegment bs;
bs.m_iStartIndex = BeatToNoteRow( strtof( arrayBPMChangeValues[0],NULL ) / 4.0f );
bs.SetBPM( strtof( arrayBPMChangeValues[1], NULL ) );
out.AddBPMSegment( bs );
}
}
+4 -3
View File
@@ -7,6 +7,7 @@
#include "RageUtil.h"
#include "SongManager.h"
#include "RageFileManager.h"
#include "NoteTypes.h"
#define MAX_EDIT_SIZE_BYTES 20*1024 // 20 KB
@@ -110,7 +111,7 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
const float fFreezeSeconds = strtof( arrayFreezeValues[1], NULL );
StopSegment new_seg;
new_seg.m_fStartBeat = fFreezeBeat;
new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat);
new_seg.m_fStopSeconds = fFreezeSeconds;
// LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds );
@@ -141,8 +142,8 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
const float fNewBPM = strtof( arrayBPMChangeValues[1], NULL );
BPMSegment new_seg;
new_seg.m_fStartBeat = fBeat;
new_seg.m_fBPM = fNewBPM;
new_seg.m_iStartIndex = BeatToNoteRow(fBeat);
new_seg.SetBPM( fNewBPM );
out.AddBPMSegment( new_seg );
}
+4 -4
View File
@@ -350,9 +350,9 @@ bool NotesWriterDWI::Write( CString sPath, const Song &out )
/* Write transliterations, if we have them, since DWI doesn't support UTF-8. */
f.PutLine( ssprintf("#TITLE:%s;", out.GetFullTranslitTitle().c_str()) );
f.PutLine( ssprintf("#ARTIST:%s;", out.GetTranslitArtist().c_str()) );
ASSERT( out.m_Timing.m_BPMSegments[0].m_fStartBeat == 0 );
ASSERT( out.m_Timing.m_BPMSegments[0].m_iStartIndex == 0 );
f.PutLine( ssprintf("#FILE:%s;", out.m_sMusicFile.c_str()) );
f.PutLine( ssprintf("#BPM:%.3f;", out.m_Timing.m_BPMSegments[0].m_fBPM) );
f.PutLine( ssprintf("#BPM:%.3f;", out.m_Timing.m_BPMSegments[0].GetBPM()) );
f.PutLine( ssprintf("#GAP:%d;", int(-roundf( out.m_Timing.m_fBeat0OffsetInSeconds*1000 ))) );
f.PutLine( ssprintf("#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds) );
f.PutLine( ssprintf("#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds) );
@@ -381,7 +381,7 @@ bool NotesWriterDWI::Write( CString sPath, const Song &out )
for( unsigned i=0; i<out.m_Timing.m_StopSegments.size(); i++ )
{
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
f.Write( ssprintf("%.3f=%.3f", BeatToNoteRow( fs.m_fStartBeat ) * 4.0f / ROWS_PER_BEAT,
f.Write( ssprintf("%.3f=%.3f", fs.m_iStartRow * 4.0f / ROWS_PER_BEAT,
roundf(fs.m_fStopSeconds*1000)) );
if( i != out.m_Timing.m_StopSegments.size()-1 )
f.Write( "," );
@@ -395,7 +395,7 @@ bool NotesWriterDWI::Write( CString sPath, const Song &out )
for( unsigned i=1; i<out.m_Timing.m_BPMSegments.size(); i++ )
{
const BPMSegment &bs = out.m_Timing.m_BPMSegments[i];
f.Write( ssprintf("%.3f=%.3f", BeatToNoteRow( bs.m_fStartBeat ) * 4.0f / ROWS_PER_BEAT, bs.m_fBPM ) );
f.Write( ssprintf("%.3f=%.3f", bs.m_iStartIndex * 4.0f / ROWS_PER_BEAT, bs.GetBPM() ) );
if( i != out.m_Timing.m_BPMSegments.size()-1 )
f.Write( "," );
}
+3 -2
View File
@@ -7,6 +7,7 @@
#include "RageFile.h"
#include "RageFileManager.h"
#include "song.h"
#include "NoteTypes.h"
#include <cstring>
#include <cerrno>
@@ -62,7 +63,7 @@ void NotesWriterSM::WriteGlobalTags( RageFile &f, const Song &out )
{
const BPMSegment &bs = out.m_Timing.m_BPMSegments[i];
f.Write( ssprintf( "%.3f=%.3f", bs.m_fStartBeat, bs.m_fBPM ) );
f.Write( ssprintf( "%.3f=%.3f", NoteRowToBeat(bs.m_iStartIndex), bs.GetBPM() ) );
if( i != out.m_Timing.m_BPMSegments.size()-1 )
f.Write( "," );
}
@@ -73,7 +74,7 @@ void NotesWriterSM::WriteGlobalTags( RageFile &f, const Song &out )
{
const StopSegment &fs = out.m_Timing.m_StopSegments[i];
f.PutLine( ssprintf( "%.3f=%.3f", fs.m_fStartBeat, fs.m_fStopSeconds ) );
f.PutLine( ssprintf( "%.3f=%.3f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
if( i != out.m_Timing.m_StopSegments.size()-1 )
f.Write( "," );
}
+15 -14
View File
@@ -1190,7 +1190,7 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
unsigned i;
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
{
if( m_pSong->m_Timing.m_StopSegments[i].m_fStartBeat == GAMESTATE->m_fSongBeat )
if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) )
break;
}
@@ -1198,7 +1198,7 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
{
// create a new StopSegment
if( fStopDelta > 0 )
m_pSong->AddStopSegment( StopSegment(GAMESTATE->m_fSongBeat, fStopDelta) );
m_pSong->AddStopSegment( StopSegment(BeatToNoteRow(GAMESTATE->m_fSongBeat), fStopDelta) );
}
else // StopSegment being modified is m_Timing.m_StopSegments[i]
{
@@ -1801,7 +1801,8 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, int* iAnswers )
unsigned i;
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
{
if( m_pSong->m_Timing.m_StopSegments[i].m_fStartBeat == GAMESTATE->m_fSongBeat )
// XXX
if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) )
break;
}
if ( i == m_pSong->m_Timing.m_StopSegments.size() )
@@ -2071,7 +2072,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
float fDeltaBeats = fNewClipboardBeats - fOldClipboardBeats;
float fNewClipboardEndBeat = m_NoteFieldEdit.m_fBeginMarker + fNewClipboardBeats;
NoteDataUtil::ShiftRows( m_NoteDataEdit, BeatToNoteRow(m_NoteFieldEdit.m_fBeginMarker), BeatToNoteRow(fDeltaBeats) );
m_pSong->m_Timing.ScaleRegion( fScale, m_NoteFieldEdit.m_fBeginMarker, m_NoteFieldEdit.m_fEndMarker );
m_pSong->m_Timing.ScaleRegion( fScale, BeatToNoteRow(m_NoteFieldEdit.m_fBeginMarker), BeatToNoteRow(m_NoteFieldEdit.m_fEndMarker) );
HandleAreaMenuChoice( paste_at_begin_marker, NULL );
@@ -2199,10 +2200,10 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
NoteDataUtil::ShiftRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(-1) );
break;
case shift_pauses_forward:
m_pSong->m_Timing.ShiftRows( GAMESTATE->m_fSongBeat, 1 );
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(+1) );
break;
case shift_pauses_backward:
m_pSong->m_Timing.ShiftRows( GAMESTATE->m_fSongBeat, -1 );
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(GAMESTATE->m_fSongBeat), BeatToNoteRow(-1) );
break;
// MD 11/02/03 - Converting selected region to a pause of the same length.
case convert_beat_to_pause:
@@ -2218,26 +2219,26 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
BeatToNoteRow(m_NoteFieldEdit.m_fBeginMarker) + 1,
BeatToNoteRow(-m_NoteFieldEdit.m_fEndMarker+m_NoteFieldEdit.m_fBeginMarker)
);
m_pSong->m_Timing.ShiftRows( m_NoteFieldEdit.m_fBeginMarker + 0.003f,
(-m_NoteFieldEdit.m_fEndMarker+m_NoteFieldEdit.m_fBeginMarker)
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(m_NoteFieldEdit.m_fBeginMarker) + 1,
BeatToNoteRow(-m_NoteFieldEdit.m_fEndMarker+m_NoteFieldEdit.m_fBeginMarker)
);
unsigned i;
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
{
float fStart = m_pSong->m_Timing.GetElapsedTimeFromBeat(m_pSong->m_Timing.m_StopSegments[i].m_fStartBeat);
float fStart = m_pSong->m_Timing.GetElapsedTimeFromBeat(NoteRowToBeat(m_pSong->m_Timing.m_StopSegments[i].m_iStartRow));
float fEnd = fStart + m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds;
if( fStart > fMarkerEnd || fEnd < fMarkerStart )
continue;
else {
if (fStart > fMarkerStart)
m_pSong->m_Timing.m_StopSegments[i].m_fStartBeat = m_NoteFieldEdit.m_fBeginMarker;
if( fStart > fMarkerStart )
m_pSong->m_Timing.m_StopSegments[i].m_iStartRow = BeatToNoteRow(m_NoteFieldEdit.m_fBeginMarker);
m_pSong->m_Timing.m_StopSegments[i].m_fStopSeconds = fStopLength;
break;
}
}
if( i == m_pSong->m_Timing.m_StopSegments.size() ) // there is no BPMSegment at the current beat
m_pSong->AddStopSegment( StopSegment(m_NoteFieldEdit.m_fBeginMarker, fStopLength) );
m_pSong->AddStopSegment( StopSegment(BeatToNoteRow(m_NoteFieldEdit.m_fBeginMarker), fStopLength) );
m_NoteFieldEdit.m_fEndMarker = -1;
break;
}
@@ -2255,7 +2256,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
unsigned i;
for( i=0; i<m_pSong->m_Timing.m_StopSegments.size(); i++ )
{
if( m_pSong->m_Timing.m_StopSegments[i].m_fStartBeat == GAMESTATE->m_fSongBeat )
if( m_pSong->m_Timing.m_StopSegments[i].m_iStartRow == BeatToNoteRow(GAMESTATE->m_fSongBeat) )
break;
}
@@ -2271,7 +2272,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
// don't move the step from where it is, just move everything later
m_NoteDataEdit.ConvertHoldNotesTo2sAnd3s();
NoteDataUtil::ShiftRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopLength) );
m_pSong->m_Timing.ShiftRows( GAMESTATE->m_fSongBeat + 0.003f, fStopLength );
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopLength) );
m_NoteDataEdit.Convert2sAnd3sToHoldNotes();
}
+2 -2
View File
@@ -1829,9 +1829,9 @@ void ScreenGameplay::Input( const DeviceInput& DeviceI, const InputEventType typ
fOffsetDelta *= 10;
BPMSegment& seg = GAMESTATE->m_pCurSong->GetBPMSegmentAtBeat( GAMESTATE->m_fSongBeat );
seg.m_fBPM += fOffsetDelta;
seg.m_iBPS += BeatToNoteRow(fOffsetDelta);
m_textDebug.SetText( ssprintf("Cur BPM = %.2f", seg.m_fBPM) );
m_textDebug.SetText( ssprintf("Cur BPM = %.2f", seg.GetBPM()) );
m_textDebug.StopTweening();
m_textDebug.SetDiffuse( RageColor(1,1,1,1) );
m_textDebug.BeginTweening( 3 ); // sleep
+2 -2
View File
@@ -524,8 +524,8 @@ void Song::TidyUpData()
}
/* Make sure the first BPM segment starts at beat 0. */
if( m_Timing.m_BPMSegments[0].m_fStartBeat != 0 )
m_Timing.m_BPMSegments[0].m_fStartBeat = 0;
if( m_Timing.m_BPMSegments[0].m_iStartIndex != 0 )
m_Timing.m_BPMSegments[0].m_iStartIndex = 0;
if( m_fMusicSampleStartSeconds == -1 ||
+107 -62
View File
@@ -3,6 +3,17 @@
#include "PrefsManager.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "NoteTypes.h"
void BPMSegment::SetBPM( float f )
{
m_iBPS = BeatToNoteRow( f / 60.0f );
}
float BPMSegment::GetBPM() const
{
return NoteRowToBeat(m_iBPS * 60);
}
TimingData::TimingData()
{
@@ -11,7 +22,7 @@ TimingData::TimingData()
static int CompareBPMSegments(const BPMSegment &seg1, const BPMSegment &seg2)
{
return seg1.m_fStartBeat < seg2.m_fStartBeat;
return seg1.m_iStartIndex < seg2.m_iStartIndex;
}
void SortBPMSegmentsArray( vector<BPMSegment> &arrayBPMSegments )
@@ -21,7 +32,7 @@ void SortBPMSegmentsArray( vector<BPMSegment> &arrayBPMSegments )
static int CompareStopSegments(const StopSegment &seg1, const StopSegment &seg2)
{
return seg1.m_fStartBeat < seg2.m_fStartBeat;
return seg1.m_iStartRow < seg2.m_iStartRow;
}
void SortStopSegmentsArray( vector<StopSegment> &arrayStopSegments )
@@ -31,14 +42,16 @@ void SortStopSegmentsArray( vector<StopSegment> &arrayStopSegments )
void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut ) const
{
fMaxBPMOut = 0;
fMinBPMOut = 100000; // inf
int iMinBPS = MAX_NOTE_ROW;
int iMaxBPS = 0;
for( unsigned i=0; i<m_BPMSegments.size(); i++ )
{
const BPMSegment &seg = m_BPMSegments[i];
fMaxBPMOut = max( seg.m_fBPM, fMaxBPMOut );
fMinBPMOut = min( seg.m_fBPM, fMinBPMOut );
iMaxBPS = max( seg.m_iBPS, iMaxBPS );
iMinBPS = min( seg.m_iBPS, iMinBPS );
}
fMinBPMOut = NoteRowToBeat( iMinBPS );
fMaxBPMOut = NoteRowToBeat( iMaxBPS );
}
@@ -57,41 +70,43 @@ void TimingData::AddStopSegment( const StopSegment &seg )
/* Change an existing BPM segment, merge identical segments together or insert a new one. */
void TimingData::SetBPMAtBeat( float fBeat, float fBPM )
{
int iNoteRow = BeatToNoteRow( fBeat );
int iBPS = BeatToNoteRow( fBPM ) / 60;
unsigned i;
for( i=0; i<m_BPMSegments.size(); i++ )
if( m_BPMSegments[i].m_fStartBeat >= fBeat )
if( m_BPMSegments[i].m_iStartIndex >= iNoteRow )
break;
if( i == m_BPMSegments.size() ||
fabsf(m_BPMSegments[i].m_fStartBeat-fBeat) > 0.001f )
if( i == m_BPMSegments.size() || m_BPMSegments[i].m_iStartIndex == iNoteRow )
{
// There is no BPMSegment at the specified beat. If the BPM being set differs
// from the last BPMSegment's BPM, create a new BPMSegment.
if( i == 0 || fabsf(m_BPMSegments[i-1].m_fBPM - fBPM) > 0.009f )
AddBPMSegment( BPMSegment(fBeat, fBPM) );
if( i == 0 || m_BPMSegments[i-1].m_iBPS != iBPS )
AddBPMSegment( BPMSegment(iNoteRow, iBPS) );
}
else // BPMSegment being modified is m_BPMSegments[i]
{
if( i > 0 && fabsf(m_BPMSegments[i-1].m_fBPM - fBPM) < 0.009f )
if( i > 0 && m_BPMSegments[i-1].m_iBPS == iBPS )
m_BPMSegments.erase( m_BPMSegments.begin()+i,
m_BPMSegments.begin()+i+1);
else
m_BPMSegments[i].m_fBPM = fBPM;
m_BPMSegments[i].m_iBPS = iBPS;
}
}
void TimingData::SetStopAtBeat( float fBeat, float fSeconds )
{
int iRow = BeatToNoteRow( fBeat );
unsigned i;
for( i=0; i<m_StopSegments.size(); i++ )
if( m_StopSegments[i].m_fStartBeat == fBeat )
if( m_StopSegments[i].m_iStartRow == iRow )
break;
if( i == m_StopSegments.size() ) // there is no BPMSegment at the current beat
{
// create a new StopSegment
if( fSeconds > 0 )
AddStopSegment( StopSegment(fBeat, fSeconds) );
AddStopSegment( StopSegment(iRow, fSeconds) );
}
else // StopSegment being modified is m_StopSegments[i]
{
@@ -103,37 +118,60 @@ void TimingData::SetStopAtBeat( float fBeat, float fSeconds )
}
/* Multiply the BPM in the range [fStartBeat,fEndBeat) by fFactor. */
void TimingData::MultiplyBPMInBeatRange( float fStartBeat, float fEndBeat, float fFactor )
void TimingData::MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor )
{
/* Record the BPM at fEndBeat, so we can make sure it doesn't change. */
float fEndBPM = GetBPMAtBeat( fEndBeat );
/* Set the first beat. */
SetBPMAtBeat( fStartBeat, GetBPMAtBeat(fStartBeat) * fFactor );
/* Change all other BPM segments in this range. */
for( unsigned i=0; i<m_BPMSegments.size(); i++ )
if( m_BPMSegments[i].m_fStartBeat > fStartBeat && m_BPMSegments[i].m_fStartBeat < fEndBeat )
m_BPMSegments[i].m_fBPM *= fFactor;
{
const int iStartIndexThisSegment = m_BPMSegments[i].m_iStartIndex;
const bool bIsLastBPMSegment = i==m_BPMSegments.size()-1;
const int iStartIndexNextSegment = bIsLastBPMSegment ? 40000/*inf*/ : m_BPMSegments[i+1].m_iStartIndex;
/* Don't change the BPM at the end of the range. */
SetBPMAtBeat( fEndBeat, fEndBPM );
if( iStartIndexThisSegment <= iStartIndex && iStartIndexNextSegment <= iStartIndex )
continue;
/* If this BPM segment crosses the beginning of the range, split it into two. */
if( iStartIndexThisSegment < iStartIndex && iStartIndexNextSegment > iStartIndex )
{
BPMSegment b = m_BPMSegments[i];
b.m_iStartIndex = iStartIndexNextSegment;
m_BPMSegments.insert( m_BPMSegments.begin()+i+1, b );
/* Don't apply the BPM change to the first half of the segment we just split,
* since it lies outside the range. */
continue;
}
/* If this BPM segment crosses the end of the range, split it into two. */
if( iStartIndexThisSegment < iEndIndex && iStartIndexNextSegment > iEndIndex )
{
BPMSegment b = m_BPMSegments[i];
b.m_iStartIndex = iEndIndex;
m_BPMSegments.insert( m_BPMSegments.begin()+i+1, b );
}
else if( iStartIndexNextSegment > iEndIndex )
continue;
m_BPMSegments[i].m_iBPS = lrintf( m_BPMSegments[i].m_iBPS * fFactor );
}
}
float TimingData::GetBPMAtBeat( float fBeat ) const
{
int iIndex = BeatToNoteRow( fBeat );
unsigned i;
for( i=0; i<m_BPMSegments.size()-1; i++ )
if( m_BPMSegments[i+1].m_fStartBeat > fBeat )
if( m_BPMSegments[i+1].m_iStartIndex > iIndex )
break;
return m_BPMSegments[i].m_fBPM;
return m_BPMSegments[i].GetBPM();
}
BPMSegment& TimingData::GetBPMSegmentAtBeat( float fBeat )
{
int iIndex = BeatToNoteRow( fBeat );
unsigned i;
for( i=0; i<m_BPMSegments.size()-1; i++ )
if( m_BPMSegments[i+1].m_fStartBeat > fBeat )
if( m_BPMSegments[i+1].m_iStartIndex > iIndex )
break;
return m_BPMSegments[i];
}
@@ -150,21 +188,25 @@ void TimingData::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatO
for( unsigned i=0; i<m_BPMSegments.size(); i++ ) // foreach BPMSegment
{
const float fStartBeatThisSegment = m_BPMSegments[i].m_fStartBeat;
const int iStartRowThisSegment = m_BPMSegments[i].m_iStartIndex;
const float fStartBeatThisSegment = NoteRowToBeat( iStartRowThisSegment );
const bool bIsFirstBPMSegment = i==0;
const bool bIsLastBPMSegment = i==m_BPMSegments.size()-1;
const float fStartBeatNextSegment = bIsLastBPMSegment ? 40000/*inf*/ : m_BPMSegments[i+1].m_fStartBeat;
const float fBPS = m_BPMSegments[i].m_fBPM / 60.0f;
const int iStartRowNextSegment = bIsLastBPMSegment ? MAX_NOTE_ROW : m_BPMSegments[i+1].m_iStartIndex;
const float fStartBeatNextSegment = NoteRowToBeat( iStartRowNextSegment );
const int iBPS = m_BPMSegments[i].m_iBPS;
const float fBPS = NoteRowToBeat( iBPS );
for( unsigned j=0; j<m_StopSegments.size(); j++ ) // foreach freeze
{
if( !bIsFirstBPMSegment && fStartBeatThisSegment >= m_StopSegments[j].m_fStartBeat )
if( !bIsFirstBPMSegment && iStartRowThisSegment >= m_StopSegments[j].m_iStartRow )
continue;
if( !bIsLastBPMSegment && m_StopSegments[j].m_fStartBeat > fStartBeatNextSegment )
if( !bIsLastBPMSegment && m_StopSegments[j].m_iStartRow > iStartRowNextSegment )
continue;
// this freeze lies within this BPMSegment
const float fBeatsSinceStartOfSegment = m_StopSegments[j].m_fStartBeat - fStartBeatThisSegment;
const int iRowsBeatsSinceStartOfSegment = m_StopSegments[j].m_iStartRow - iStartRowThisSegment;
const float fBeatsSinceStartOfSegment = NoteRowToBeat(iRowsBeatsSinceStartOfSegment);
const float fFreezeStartSecond = fBeatsSinceStartOfSegment / fBPS;
if( fFreezeStartSecond >= fElapsedTime )
@@ -176,7 +218,7 @@ void TimingData::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatO
if( fFreezeStartSecond >= fElapsedTime )
{
/* The time lies within the stop. */
fBeatOut = m_StopSegments[j].m_fStartBeat;
fBeatOut = NoteRowToBeat(m_StopSegments[j].m_iStartRow);
fBPSOut = fBPS;
bFreezeOut = true;
return;
@@ -206,10 +248,11 @@ float TimingData::GetElapsedTimeFromBeat( float fBeat ) const
fElapsedTime -= PREFSMAN->m_fGlobalOffsetSeconds;
fElapsedTime -= m_fBeat0OffsetInSeconds;
int iRow = BeatToNoteRow(fBeat);
for( unsigned j=0; j<m_StopSegments.size(); j++ ) // foreach freeze
{
/* The exact beat of a stop comes before the stop, not after, so use >=, not >. */
if( m_StopSegments[j].m_fStartBeat >= fBeat )
if( m_StopSegments[j].m_iStartRow >= iRow )
break;
fElapsedTime += m_StopSegments[j].m_fStopSeconds;
}
@@ -217,7 +260,7 @@ float TimingData::GetElapsedTimeFromBeat( float fBeat ) const
for( unsigned i=0; i<m_BPMSegments.size(); i++ ) // foreach BPMSegment
{
const bool bIsLastBPMSegment = i==m_BPMSegments.size()-1;
const float fBPS = m_BPMSegments[i].m_fBPM / 60.0f;
const float fBPS = NoteRowToBeat( m_BPMSegments[i].m_iBPS );
if( bIsLastBPMSegment )
{
@@ -225,8 +268,10 @@ float TimingData::GetElapsedTimeFromBeat( float fBeat ) const
}
else
{
const float fStartBeatThisSegment = m_BPMSegments[i].m_fStartBeat;
const float fStartBeatNextSegment = m_BPMSegments[i+1].m_fStartBeat;
const int iStartIndexThisSegment = m_BPMSegments[i].m_iStartIndex;
const float fStartBeatThisSegment = NoteRowToBeat( iStartIndexThisSegment );
const int iStartIndexNextSegment = m_BPMSegments[i+1].m_iStartIndex;
const float fStartBeatNextSegment = NoteRowToBeat( iStartIndexNextSegment );
const float fBeatsInThisSegment = fStartBeatNextSegment - fStartBeatThisSegment;
fElapsedTime += min(fBeat, fBeatsInThisSegment) / fBPS;
fBeat -= fBeatsInThisSegment;
@@ -239,58 +284,58 @@ float TimingData::GetElapsedTimeFromBeat( float fBeat ) const
return fElapsedTime;
}
void TimingData::ScaleRegion( float fScale, float fStartBeat, float fEndBeat )
void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex )
{
ASSERT( fScale > 0 );
ASSERT( fStartBeat >= 0 );
ASSERT( fStartBeat < fEndBeat );
ASSERT( iStartIndex >= 0 );
ASSERT( iStartIndex < iEndIndex );
unsigned ix = 0;
for ( ix = 0; ix < m_BPMSegments.size(); ix++ )
{
const float fSegStart = m_BPMSegments[ix].m_fStartBeat;
if( fSegStart < fStartBeat )
const int iSegStart = m_BPMSegments[ix].m_iStartIndex;
if( iSegStart < iStartIndex )
continue;
else if( fSegStart > fEndBeat )
m_BPMSegments[ix].m_fStartBeat += (fEndBeat - fStartBeat) * (fScale - 1);
else if( iSegStart > iEndIndex )
m_BPMSegments[ix].m_iStartIndex += lrintf( (iEndIndex - iStartIndex) * (fScale - 1) );
else
m_BPMSegments[ix].m_fStartBeat = (fSegStart - fStartBeat) * fScale + fStartBeat;
m_BPMSegments[ix].m_iStartIndex = lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex;
}
for( ix = 0; ix < m_StopSegments.size(); ix++ )
{
const float fSegStart = m_StopSegments[ix].m_fStartBeat;
if( fSegStart < fStartBeat )
const int iSegStartRow = m_StopSegments[ix].m_iStartRow;
if( iSegStartRow < iStartIndex )
continue;
else if( fSegStart > fEndBeat )
m_StopSegments[ix].m_fStartBeat += (fEndBeat - fStartBeat) * (fScale - 1);
else if( iSegStartRow > iEndIndex )
m_StopSegments[ix].m_iStartRow += lrintf((iEndIndex - iStartIndex) * (fScale - 1));
else
m_StopSegments[ix].m_fStartBeat = (fSegStart - fStartBeat) * fScale + fStartBeat;
m_StopSegments[ix].m_iStartRow = lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex;
}
}
void TimingData::ShiftRows( float fStartBeat, float fBeatsToShift )
void TimingData::ShiftRows( int iStartRow, int iRowsToShift )
{
unsigned ix = 0;
for( ix = 0; ix < m_BPMSegments.size(); ix++ )
{
float &fSegStart = m_BPMSegments[ix].m_fStartBeat;
if( fSegStart < fStartBeat )
int &iSegStart = m_BPMSegments[ix].m_iStartIndex;
if( iSegStart < iStartRow )
continue;
fSegStart += fBeatsToShift;
fSegStart = max( fSegStart, fStartBeat );
iSegStart += iRowsToShift;
iSegStart = max( iSegStart, iStartRow );
}
for( ix = 0; ix < m_StopSegments.size(); ix++ )
{
float &fSegStart = m_StopSegments[ix].m_fStartBeat;
if( fSegStart < fStartBeat )
int &iSegStartRow = m_StopSegments[ix].m_iStartRow;
if( iSegStartRow < iStartRow )
continue;
fSegStart += fBeatsToShift;
fSegStart = max( fSegStart, fStartBeat );
iSegStartRow += iRowsToShift;
iSegStartRow = max( iSegStartRow, iStartRow );
}
}
+15 -10
View File
@@ -3,19 +3,24 @@
#ifndef TIMING_DATA_H
#define TIMING_DATA_H
#include "NoteTypes.h"
struct BPMSegment
{
BPMSegment() { m_fStartBeat = m_fBPM = -1; };
BPMSegment( float s, float b ) { m_fStartBeat = s; m_fBPM = b; };
float m_fStartBeat;
float m_fBPM;
BPMSegment() { m_iStartIndex = -1; m_iBPS = -1; }
BPMSegment( int s, int b ) { m_iStartIndex = s; m_iBPS = b; }
int m_iStartIndex;
int m_iBPS; /* rows per second */
void SetBPM( float f );
float GetBPM() const;
};
struct StopSegment
{
StopSegment() { m_fStartBeat = m_fStopSeconds = -1; };
StopSegment( float s, float f ) { m_fStartBeat = s; m_fStopSeconds = f; };
float m_fStartBeat;
StopSegment() { m_fStopSeconds = -1; m_iStartRow = -1; }
StopSegment( int s, float f ) { m_iStartRow = s; m_fStopSeconds = f; }
int m_iStartRow;
float m_fStopSeconds;
};
@@ -28,7 +33,7 @@ public:
float GetBPMAtBeat( float fBeat ) const;
void SetBPMAtBeat( float fBeat, float fBPM );
void SetStopAtBeat( float fBeat, float fSeconds );
void MultiplyBPMInBeatRange( float fStartBeat, float fEndBeat, float fFactor );
void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor );
void AddBPMSegment( const BPMSegment &seg );
void AddStopSegment( const StopSegment &seg );
BPMSegment& GetBPMSegmentAtBeat( float fBeat );
@@ -54,8 +59,8 @@ public:
// of the range that was deleted (say if rows 1680-1728 are deleted, and
// a BPM change or a stop occurs at row 1704, we'll move it to row
// 1680).
void ScaleRegion( float fScale = 1, float fStartBeat = 0, float fEndBeat = 99999 );
void ShiftRows( float fStartBeat, float fBeatsToShift );
void ScaleRegion( float fScale = 1, int iStartRow = 0, int iEndRow = MAX_NOTE_ROW );
void ShiftRows( int iStartRow, int iRowsToShift );
CString m_sFile; // informational only
vector<BPMSegment> m_BPMSegments; // this must be sorted before gameplay