Some songs have different time signature tags in different difficulties;

cope with it by adjusting everything according to the primary version.

Attempt to detect when time signature tags are being used to tweak sync,
and convert them to BPM changes.  This is more accurate, prevents some
cases of being off by a couple rows from the beat, and fixes note coloring.
This commit is contained in:
Glenn Maynard
2004-11-08 22:27:34 +00:00
parent 422b1defb7
commit 425299cbd4
2 changed files with 92 additions and 5 deletions
+88 -3
View File
@@ -192,9 +192,20 @@ static StepsType DetermineStepsType( int iPlayer, const NoteData &nd )
float BMSLoader::GetBeatsPerMeasure( const MeasureToTimeSig_t &sigs, int iMeasure )
{
map<int, float>::const_iterator time_sig = sigs.find( iMeasure );
float fRet = 4.0f;
if( time_sig != sigs.end() )
return 4.0f * time_sig->second;
return 4.0f;
{
fRet *= time_sig->second;
}
time_sig = m_TimeSigAdjustments.find( iMeasure );
if( time_sig != m_TimeSigAdjustments.end() )
{
fRet *= time_sig->second;
}
return fRet;
}
int BMSLoader::GetMeasureStartRow( const MeasureToTimeSig_t &sigs, int iMeasureNo )
@@ -312,7 +323,7 @@ bool BMSLoader::LoadFromBMSFile( const CString &sPath, const NameToData_t &mapNa
{
float fPercentThroughMeasure = (float)j/(float)uNumNotesInThisMeasure;
int row = iRowNo + (int) ( fPercentThroughMeasure * fBeatsPerMeasure * ROWS_PER_BEAT );
int row = iRowNo + lrintf( fPercentThroughMeasure * fBeatsPerMeasure * ROWS_PER_BEAT );
// some BMS files seem to have funky alignment, causing us to write gigantic cache files.
// Try to correct for this by quantizing.
@@ -719,6 +730,9 @@ void BMSLoader::ReadGlobalTags( const NameToData_t &mapNameToData, Song &out )
}
}
}
/* Now that we're done reading BPMs, factor out weird time signatures. */
SetTimeSigAdjustments( mapMeasureToTimeSig, &out );
}
void BMSLoader::ReadTimeSigs( const NameToData_t &mapNameToData, MeasureToTimeSig_t &out )
@@ -739,6 +753,77 @@ void BMSLoader::ReadTimeSigs( const NameToData_t &mapNameToData, MeasureToTimeSi
}
}
/*
* Time signatures are often abused to tweak sync. Real time signatures should
* cause us to adjust the row offsets so one beat remains one beat. Fake time signatures,
* like 1.001 or 0.999, should be removed and converted to BPM changes. This is much
* more accurate, and prevents the whole song from being shifted off of the beat, causing
* BeatToNoteType to be wrong.
*
* Evaluate each time signature, and guess which time signatures should be converted
* to BPM changes. This isn't perfect, but errors aren't fatal.
*/
void BMSLoader::SetTimeSigAdjustments( const MeasureToTimeSig_t &sigs, Song *pOut )
{
return;
m_TimeSigAdjustments.clear();
MeasureToTimeSig_t::const_iterator it;
for( it = sigs.begin(); it != sigs.end(); ++it )
{
int iMeasure = it->first;
float fFactor = it->second;
#if 1
static const float ValidFactors[] =
{
0.25f, /* 1/4 */
0.5f, /* 2/4 */
0.75f, /* 3/4 */
0.875f, /* 7/8 */
1.0f,
1.5f, /* 6/4 */
1.75f /* 7/4 */
};
bool bValidTimeSignature = false;
for( unsigned i = 0; i < ARRAYSIZE(ValidFactors); ++i )
if( fabsf(fFactor-ValidFactors[i]) < 0.001 )
bValidTimeSignature = true;
if( bValidTimeSignature )
continue;
#else
/* Alternate approach that I tried first: see if the ratio is sane. However,
* some songs have values like "1.4", which comes out to 7/4 and is not a valid
* time signature. */
/* Convert the factor to a ratio, and reduce it. */
int iNum = lrintf( fFactor * 1000 ), iDen = 1000;
int iDiv = gcd( iNum, iDen );
iNum /= iDiv;
iDen /= iDiv;
/* Real time signatures usually come down to 1/2, 3/4, 7/8, etc. Bogus
* signatures that are only there to adjust sync usually look like 99/100. */
if( iNum <= 8 && iDen <= 8 )
continue;
#endif
/* This time signature is bogus. Convert it to a BPM adjustment for this
* measure. */
LOG->Trace("Converted time signature %f in measure %i to a BPM segment.", fFactor, iMeasure );
/* Note that this GetMeasureStartRow will automatically include any adjustments
* that we've made previously in this loop; as long as we make the timing
* 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 );
}
}
bool BMSLoader::LoadFromDir( CString sDir, Song &out )
{
LOG->Trace( "Song::LoadFromBMSDir(%s)", sDir.c_str() );
+4 -2
View File
@@ -20,8 +20,10 @@ class BMSLoader: public NotesLoader
typedef map<int, float> MeasureToTimeSig_t;
void ReadTimeSigs( const NameToData_t &mapNameToData, MeasureToTimeSig_t &out );
static float GetBeatsPerMeasure( const MeasureToTimeSig_t &sigs, int iMeasure );
static int GetMeasureStartRow( const MeasureToTimeSig_t &sigs, int iMeasureNo );
float GetBeatsPerMeasure( const MeasureToTimeSig_t &sigs, int iMeasure );
int GetMeasureStartRow( const MeasureToTimeSig_t &sigs, int iMeasureNo );
void SetTimeSigAdjustments( const MeasureToTimeSig_t &sigs, Song *pOut );
MeasureToTimeSig_t m_TimeSigAdjustments;
CString m_sDir;
map<CString,int> m_mapWavIdToKeysoundIndex;