diff --git a/src/NotesLoaderSMA.cpp b/src/NotesLoaderSMA.cpp index 23dd584691..de181db967 100644 --- a/src/NotesLoaderSMA.cpp +++ b/src/NotesLoaderSMA.cpp @@ -355,6 +355,35 @@ void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RS } } +void SMALoader::ProcessFakes( TimingData &out, const int iRowsPerBeat, const RString sParam ) +{ + vector arrayFakeExpressions; + split( sParam, ",", arrayFakeExpressions ); + + for( unsigned b=0; b arrayFakeValues; + split( arrayFakeExpressions[b], "=", arrayFakeValues ); + // XXX: Hard to tell which file caused this. + if( arrayFakeValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.", + arrayFakeExpressions[b].c_str() ); + continue; + } + + const float fBeat = RowToBeat( arrayFakeValues[0], iRowsPerBeat ); + const float fNewBeat = StringToFloat( arrayFakeValues[1] ); + + if(fNewBeat > 0) + out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) ); + else + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat ); + } + } +} + void SMALoader::LoadFromSMATokens( RString sStepsType, @@ -685,6 +714,13 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) ProcessMultipliers( pNewNotes->m_Timing, iRowsPerBeat, sParams[1] ); } + else if( sValueName=="FAKES" ) + { + TimingData &timing = (state == SMA_GETTING_STEP_INFO + ? pNewNotes->m_Timing : out.m_SongTiming); + ProcessFakes( timing, iRowsPerBeat, sParams[1] ); + } + else if( sValueName=="METERTYPE" ) { ; // We don't use this...yet. diff --git a/src/NotesLoaderSMA.h b/src/NotesLoaderSMA.h index af397205fb..c9e3dfa811 100644 --- a/src/NotesLoaderSMA.h +++ b/src/NotesLoaderSMA.h @@ -48,6 +48,7 @@ namespace SMALoader void ProcessTickcounts( TimingData &out, const int iRowsPerBeat, const RString sParam ); void ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam ); void ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RString sParam ); + void ProcessFakes( TimingData &out, const int iRowsPerBeat, const RString sParam ); float RowToBeat( RString sLine, const int iRowsPerBeat ); }; diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 352387e7df..b361629db0 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -46,7 +46,7 @@ bool SSCLoader::LoadFromDir( const RString &sPath, Song &out ) return LoadFromSSCFile( sPath + aFileNames[0], out ); } -void SSCLoader::ProcessWarps( TimingData &out, const RString sParam ) +void SSCLoader::ProcessWarps( TimingData &out, const RString sParam, const float fVersion ) { vector arrayWarpExpressions; split( sParam, ",", arrayWarpExpressions ); @@ -65,8 +65,8 @@ void SSCLoader::ProcessWarps( TimingData &out, const RString sParam ) const float fBeat = StringToFloat( arrayWarpValues[0] ); const float fNewBeat = StringToFloat( arrayWarpValues[1] ); - - if(fNewBeat > fBeat) + // Early versions were absolute in beats. They should be relative. + if( ( fVersion < VERSION_SPLIT_TIMING && fNewBeat > fBeat ) || fNewBeat > 0 ) out.AddWarpSegment( WarpSegment(fBeat, fNewBeat) ); else { @@ -172,6 +172,35 @@ void SSCLoader::ProcessSpeeds( TimingData &out, const RString sParam ) } } +void SSCLoader::ProcessFakes( TimingData &out, const RString sParam ) +{ + vector arrayFakeExpressions; + split( sParam, ",", arrayFakeExpressions ); + + for( unsigned b=0; b arrayFakeValues; + split( arrayFakeExpressions[b], "=", arrayFakeValues ); + // XXX: Hard to tell which file caused this. + if( arrayFakeValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.", + arrayFakeExpressions[b].c_str() ); + continue; + } + + const float fBeat = StringToFloat( arrayFakeValues[0] ); + const float fNewBeat = StringToFloat( arrayFakeValues[1] ); + + if(fNewBeat > 0) + out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) ); + else + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat ); + } + } +} + bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache ) { @@ -393,9 +422,9 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach SMLoader::ProcessBPMs(out.m_SongTiming, sParams[1]); } - else if( sValueName=="WARPS" ) + else if( sValueName=="WARPS" ) // Older versions allowed em here. { - ProcessWarps( out.m_SongTiming, sParams[1] ); + ProcessWarps( out.m_SongTiming, sParams[1], out.m_fVersion ); } else if( sValueName=="LABELS" ) @@ -560,7 +589,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach else if( sValueName=="WARPS" ) { - ProcessWarps(stepsTiming, sParams[1]); + ProcessWarps(stepsTiming, sParams[1], out.m_fVersion); } else if( sValueName=="SPEEDS" ) @@ -568,6 +597,11 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach ProcessSpeeds( stepsTiming, sParams[1] ); } + else if( sValueName=="FAKES" ) + { + ProcessFakes( stepsTiming, sParams[1] ); + } + else if( sValueName=="LABELS" ) { ProcessLabels(stepsTiming, sParams[1]); @@ -675,7 +709,12 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat sValueName.MakeUpper(); // handle the data - if( sValueName=="SONG" ) + if( sValueName=="VERSION" ) + { + pSong->m_fVersion = StringToFloat( sParams[1] ); + } + + else if( sValueName=="SONG" ) { if( pSong ) { @@ -795,7 +834,19 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat else if( sValueName=="WARPS" ) { - ProcessWarps(stepsTiming, sParams[1]); + ProcessWarps(stepsTiming, sParams[1], pSong->m_fVersion); + bSSCFormat = true; + } + + else if( sValueName=="SPEEDS" ) + { + ProcessSpeeds( stepsTiming, sParams[1] ); + bSSCFormat = true; + } + + else if( sValueName=="FAKES" ) + { + ProcessFakes( stepsTiming, sParams[1] ); bSSCFormat = true; } diff --git a/src/NotesLoaderSSC.h b/src/NotesLoaderSSC.h index c78231677b..cccf26c45f 100644 --- a/src/NotesLoaderSSC.h +++ b/src/NotesLoaderSSC.h @@ -77,10 +77,11 @@ namespace SSCLoader void TidyUpData( Song &song, bool bFromCache ); - void ProcessWarps( TimingData &, const RString ); + void ProcessWarps( TimingData &, const RString, const float ); void ProcessLabels( TimingData &, const RString ); void ProcessCombos( TimingData &, const RString ); void ProcessSpeeds( TimingData &, const RString ); + void ProcessFakes( TimingData &, const RString ); } #endif /** diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index 3b7c4ae729..3f01843b06 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -140,6 +140,11 @@ static void GetTimingTags( vector &lines, TimingData timing, bool bIsSo FOREACH_CONST( SpeedSegment, timing.m_SpeedSegments, ss ) w.Write( ss->m_iStartRow, ss->m_fPercent, ss->m_fWait, ss->m_usMode ); w.Finish(); + + w.Init( "FAKES" ); + FOREACH_CONST( FakeSegment, timing.m_FakeSegments, fs ) + w.Write( fs->m_iStartRow, fs->m_fEndBeat ); + w.Finish(); } w.Init( "LABELS" ); @@ -312,7 +317,8 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa GetTimingTags( lines, in.m_Timing ); - lines.push_back( "#ATTACKS:;" ); // not sure of how to handle this yet. + // For now, attacks are NOT in use for the step. + lines.push_back( "#ATTACKS:;" ); lines.push_back( ssprintf( "#OFFSET:%.6f;", in.m_Timing.m_fBeat0OffsetInSeconds ) ); RString sNoteData;