From 315aaf774dfe1a9461561e0503d1f47da43c5ff9 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Mon, 4 Apr 2011 22:47:59 -0400 Subject: [PATCH 01/12] New branch from [sm130futures]: [sm130labels] Time to simulate the Rock Band/Guitar Hero styled labeling of note sections. --- src/TimingData.cpp | 5 ++ src/TimingData.h | 137 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 0fa5d50889..a5b632e92b 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -57,6 +57,11 @@ void TimingData::AddComboSegment( const ComboSegment &seg ) m_ComboSegments.insert( upper_bound(m_ComboSegments.begin(), m_ComboSegments.end(), seg), seg ); } +void TimingData::AddLabelSegment( const LabelSegment &seg ) +{ + m_LabelSegments.insert( upper_bound(m_LabelSegments.begin(), m_LabelSegments.end(), seg), seg ); +} + /* Change an existing BPM segment, merge identical segments together or insert a new one. */ void TimingData::SetBPMAtRow( int iNoteRow, float fBPM ) { diff --git a/src/TimingData.h b/src/TimingData.h index f61afb6d9c..4b49e93825 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -564,6 +564,83 @@ struct ComboSegment bool operator>=( const ComboSegment &other ) const { return !operator<(other); } }; +/** + * @brief Identifies when a chart is entering a different section. + * + * This is meant for helping to identify different sections of a chart + * versus relying on measures and beats alone. + */ +struct LabelSegment +{ + /** + * @brief Creates a simple Label Segment with default values. + * + * It is best to override the values as soon as possible. + */ + LabelSegment() : m_iStartRow(-1), m_sLabel("") { } + /** + * @brief Creates a Label Segment with the specified starting row and label. + * @param s the starting row of this segment. + * @param l the label for this section. + */ + LabelSegment( int s, RString l ): m_iStartRow(max(0, s)), + m_sLabel(l) {} + /** + * @brief The row in which the ComboSegment activates. + */ + int m_iStartRow; + /** + * @brief The label/section name for this point. + */ + RString m_sLabel; + + /** + * @brief Compares two LabelSegments to see if they are equal to each other. + * @param other the other LabelSegment to compare to. + * @return the equality of the two segments. + */ + bool operator==( const LabelSegment &other ) const + { + COMPARE( m_iStartRow ); + COMPARE( m_sLabel ); + return true; + } + /** + * @brief Compares two LabelSegments to see if they are not equal to each other. + * @param other the other LabelSegment to compare to. + * @return the inequality of the two segments. + */ + bool operator!=( const LabelSegment &other ) const { return !operator==(other); } + /** + * @brief Compares two LabelSegments to see if one is less than the other. + * @param other the other LabelSegment to compare to. + * @return the truth/falsehood of if the first is less than the second. + */ + bool operator<( const LabelSegment &other ) const { return m_iStartRow < other.m_iStartRow; } + /** + * @brief Compares two LabelSegments to see if one is less than or equal to the other. + * @param other the other LabelSegment to compare to. + * @return the truth/falsehood of if the first is less or equal to than the second. + */ + bool operator<=( const LabelSegment &other ) const + { + return ( operator<(other) || operator==(other) ); + } + /** + * @brief Compares two LabelSegments to see if one is greater than the other. + * @param other the other LabelSegment to compare to. + * @return the truth/falsehood of if the first is greater than the second. + */ + bool operator>( const LabelSegment &other ) const { return !operator<=(other); } + /** + * @brief Compares two LabelSegments to see if one is greater than or equal to the other. + * @param other the other LabelSegment to compare to. + * @return the truth/falsehood of if the first is greater than or equal to the second. + */ + bool operator>=( const LabelSegment &other ) const { return !operator<(other); } +}; + + /** * @brief Holds data for translating beats<->seconds. */ @@ -1064,6 +1141,60 @@ public: */ void AddComboSegment( const ComboSegment &seg ); + /** + * @brief Retrieve the Label at the given row. + * @param iNoteRow the row in question. + * @return the Label. + */ + RString GetLabelAtRow( int iNoteRow ) const; + /** + * @brief Retrieve the Label at the given beat. + * @param fBeat the beat in question. + * @return the Label. + */ + RString GetLabelAtBeat( float fBeat ) const { return GetLabelAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Set the row to have the new Label. + * @param iNoteRow the row to have the new Label. + * @param sLabel the Label. + */ + void SetLabelAtRow( int iNoteRow, RString sLabel ); + /** + * @brief Set the beat to have the new Label. + * @param fBeat the beat to have the new Label. + * @param sLabel the Label. + */ + void SetLabelAtBeat( float fBeat, RString sLabel ) { SetLabelAtRow( BeatToNoteRow( fBeat ), sLabel ); } + /** + * @brief Retrieve the LabelSegment at the specified row. + * @param iNoteRow the row that has a LabelSegment. + * @return the LabelSegment in question. + */ + LabelSegment& GetLabelSegmentAtRow( int iNoteRow ); + /** + * @brief Retrieve the LabelSegment at the specified beat. + * @param fBeat the beat that has a LabelSegment. + * @return the LabelSegment in question. + */ + LabelSegment& GetLabelSegmentAtBeat( float fBeat ) { return GetLabelSegmentAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Retrieve the index of the LabelSegments at the specified row. + * @param iNoteRow the row that has a LabelSegment. + * @return the LabelSegment's index in question. + */ + int GetLabelSegmentIndexAtRow( int iNoteRow ) const; + /** + * @brief Retrieve the index of the LabelSegments at the specified beat. + * @param fBeat the beat that has a LabelSegment. + * @return the LabelSegment's index in question. + */ + int GetLabelSegmentIndexAtBeat( float fBeat ) const { return GetLabelSegmentIndexAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Add the LabelSegment to the TimingData. + * @param seg the new LabelSegment. + */ + void AddLabelSegment( const LabelSegment &seg ); + void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor ); void NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const; @@ -1131,6 +1262,8 @@ public: COMPARE( m_ComboSegments.size() ); for( unsigned i=0; i m_ComboSegments; + /** + * @brief The collection of LabelSegments. + */ + vector m_LabelSegments; /** * @brief The initial offset of a song. */ From 53971e16e38f0151f4f91634ccd6a54d5663d6a8 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Mon, 4 Apr 2011 23:03:10 -0400 Subject: [PATCH 02/12] [sm130labels] Add the other definitions. --- src/TimingData.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++++++ src/TimingData.h | 4 +-- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/TimingData.cpp b/src/TimingData.cpp index a5b632e92b..b1f36960fa 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -224,6 +224,27 @@ void TimingData::SetComboAtRow( int iRow, int iCombo ) } } +void TimingData::SetLabelAtRow( int iRow, const RString sLabel ) +{ + unsigned i; + for( i=0; i= iRow ) + break; + + if( i == m_LabelSegments.size() || m_LabelSegments[i].m_iStartRow != iRow ) + { + if( i == 0 || m_LabelSegments[i-1].m_sLabel != sLabel ) + AddLabelSegment( LabelSegment(iRow, sLabel ) ); + } + else + { + if( i > 0 && m_LabelSegments[i-1].m_sLabel == sLabel ) + m_LabelSegments.erase( m_LabelSegments.begin()+i, m_LabelSegments.begin()+i+1 ); + else + m_LabelSegments[i].m_sLabel = sLabel; + } +} + float TimingData::GetStopAtRow( int iNoteRow, bool bDelay ) const { for( unsigned i=0; i(i); } +int TimingData::GetLabelSegmentIndexAtRow( int iRow ) const +{ + unsigned i; + for( i=0; i iRow ) + break; + } + return static_cast(i); +} + BPMSegment& TimingData::GetBPMSegmentAtRow( int iNoteRow ) { static BPMSegment empty; @@ -427,6 +465,15 @@ ComboSegment& TimingData::GetComboSegmentAtRow( int iRow ) return m_ComboSegments[i]; } +LabelSegment& TimingData::GetLabelSegmentAtRow( int iRow ) +{ + unsigned i; + for( i=0; i iRow ) + break; + return m_LabelSegments[i]; +} + StopSegment& TimingData::GetStopSegmentAtRow( int iNoteRow, bool bDelay ) { static StopSegment empty; @@ -803,6 +850,13 @@ void TimingData::InsertRows( int iStartRow, int iRowsToAdd ) continue; comb.m_iStartRow += iRowsToAdd; } + for( unsigned i = 0; i < m_LabelSegments.size(); i++ ) + { + LabelSegment &labl = m_LabelSegments[i]; + if( labl.m_iStartRow < iStartRow ) + continue; + labl.m_iStartRow += iRowsToAdd; + } if( iStartRow == 0 ) { @@ -944,6 +998,22 @@ void TimingData::DeleteRows( int iStartRow, int iRowsToDelete ) // After deleted region: comb.m_iStartRow -= iRowsToDelete; } + + for( unsigned i = 0; i < m_LabelSegments.size(); i++ ) + { + LabelSegment &labl = m_LabelSegments[i]; + + if( labl.m_iStartRow < iStartRow ) + continue; + + if( labl.m_iStartRow < iStartRow+iRowsToDelete ) + { + m_LabelSegments.erase( m_LabelSegments.begin()+i, m_LabelSegments.begin()+i+1 ); + --i; + continue; + } + labl.m_iStartRow -= iRowsToDelete; + } this->SetBPMAtRow( iStartRow, fNewBPM ); } @@ -1049,6 +1119,18 @@ public: LuaHelpers::CreateTableFromArray(vBPMs, L); return 1; } + static int GetLabels( T* p, lua_State *L ) + { + vector vLabels; + FOREACH_CONST( LabelSegment, p->m_LabelSegments, seg ) + { + const float fStartRow = NoteRowToBeat(seg->m_iStartRow); + const RString sLabel = seg->m_sLabel; + vLabels.push_back( ssprintf("%f=%s", fStartRow, sLabel.c_str()) ); + } + LuaHelpers::CreateTableFromArray(vLabels, L); + return 1; + } static int GetBPMsAndTimes( T* p, lua_State *L ) { vector vBPMs; @@ -1087,6 +1169,7 @@ public: ADD_METHOD( GetStops ); ADD_METHOD( GetDelays ); ADD_METHOD( GetBPMs ); + ADD_METHOD( GetLabels ); ADD_METHOD( GetBPMsAndTimes ); ADD_METHOD( GetActualBPM ); ADD_METHOD( HasNegativeBPMs ); diff --git a/src/TimingData.h b/src/TimingData.h index 4b49e93825..c8f7c9dce4 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -1158,13 +1158,13 @@ public: * @param iNoteRow the row to have the new Label. * @param sLabel the Label. */ - void SetLabelAtRow( int iNoteRow, RString sLabel ); + void SetLabelAtRow( int iNoteRow, const RString sLabel ); /** * @brief Set the beat to have the new Label. * @param fBeat the beat to have the new Label. * @param sLabel the Label. */ - void SetLabelAtBeat( float fBeat, RString sLabel ) { SetLabelAtRow( BeatToNoteRow( fBeat ), sLabel ); } + void SetLabelAtBeat( float fBeat, const RString sLabel ) { SetLabelAtRow( BeatToNoteRow( fBeat ), sLabel ); } /** * @brief Retrieve the LabelSegment at the specified row. * @param iNoteRow the row that has a LabelSegment. From 3991f81101879db724777d16d1eb7dea29a836d8 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Mon, 4 Apr 2011 23:24:32 -0400 Subject: [PATCH 03/12] [sm130labels] Add labels to the SSC format. Also do cleanup on the Loader and Writer comments. Editor hooks to follow soon. --- Docs/Changelog_SSCformat.txt | 3 + src/NotesLoaderSSC.cpp | 198 +++++++---------------------------- src/NotesWriterSSC.cpp | 97 +++-------------- src/Song.cpp | 2 +- src/Song.h | 2 +- src/TimingData.h | 9 +- 6 files changed, 65 insertions(+), 246 deletions(-) diff --git a/Docs/Changelog_SSCformat.txt b/Docs/Changelog_SSCformat.txt index 205aac7c06..4aa7024de4 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.57] - Wolfman2000 +* Implement #LABELS tag for easier Editor work/Rock Band section mimicry. + [v0.56] - Wolfman2000 * Implement #WARPS tag to replace negative bpm/stop gimmicks. diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 1868dfd19d..5d2c9ce188 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -514,6 +514,34 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach } } } + + 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] ); + const RString sLabel = arrayLabelValues[1]; + 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() ); + } + + } + } else if( sValueName=="TIMESIGNATURES" ) { @@ -763,180 +791,28 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach { 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 ); - pNewNotes->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 ); - pNewNotes->m_Timing.AddStopSegment( new_seg ); - } - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } - } - */ + // copy from above when it's time. } 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) - pNewNotes->m_Timing.AddStopSegment( new_seg ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } - */ + // copy from above when it's time. } 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; - } - - pNewNotes->m_Timing.AddTimeSignatureSegment( seg ); - } - */ + // copy from above when it's time. } 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 ); - pNewNotes->m_Timing.AddTickcountSegment( new_seg ); - } - else - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); - } - } - */ + // copy from above when it's time. } 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 ); - pNewNotes->m_Timing.AddComboSegment( new_seg ); - } - */ + // copy from above when it's time. + } + else if( sValueName=="WARPS" || sValueName=="LABELS" ) + { + // copy from above when it's time. } else if( sValueName=="ATTACKS" ) { diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index 36c170b475..71e57ef042 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -194,6 +194,17 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) } f.PutLine( ";" ); + f.Write( "#LABELS:" ); + for( unsigned i=0; i asBPMValues; - for( unsigned i=0; i asStopValues; - for( unsigned i=0; i asDelayValues; - for( unsigned i=0; i asWarpValues; - for( unsigned i=0; i asTimeSigValues; - FOREACH_CONST( TimeSignatureSegment, in.m_Timing.m_vTimeSignatureSegments, iter ) - { - asTimeSigValues.push_back( ssprintf( "%.6f=%d=%d", NoteRowToBeat(iter->m_iStartRow), iter->m_iNumerator, iter->m_iDenominator ) ); - vector::const_iterator iter2 = iter; - iter2++; - } - lines.push_back( ssprintf( "#TIMESIGNATURES:%s;", join("\n,", asTimeSigValues).c_str() ) ); - - ASSERT( !in.m_Timing.m_TickcountSegments.empty() ); - vector asTickValues; - for( unsigned i=0; i asComboValues; - for( unsigned i=0; i Date: Mon, 4 Apr 2011 23:27:09 -0400 Subject: [PATCH 04/12] [sm130labels] Yes, I remembered the lua docs. --- Docs/Luadoc/Lua.xml | 1 + Docs/Luadoc/LuaDocumentation.xml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index 334204ea30..beda92ad34 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -1391,6 +1391,7 @@ + diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index cf44a947be..b82e145a03 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -3241,6 +3241,9 @@ Returns a table of the Delays and the times they happen as strings with the format "beat=stop seconds". + + Returns a table of the Labels and the times they happen as strings with the format "beat=label name." + Returns true if the TimingData contains BPM changes. From a6b5187856b2700a90ee0103df83a34f68de0dac Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 5 Apr 2011 00:35:45 -0400 Subject: [PATCH 05/12] [sm130labels] Code ready for testing. If a mistake was made here, let the cherry picking/blame game commence! --- Themes/_fallback/Languages/en.ini | 2 ++ Themes/_fallback/metrics.ini | 3 +++ src/NoteField.cpp | 20 ++++++++++++++++ src/NoteField.h | 1 + src/ScreenEdit.cpp | 40 +++++++++++++++++++++++++++++++ src/ScreenEdit.h | 4 ++++ src/TimingData.cpp | 40 ++++++++++++++++++++++++++----- src/TimingData.h | 26 ++++++++++++++++++++ 8 files changed, 130 insertions(+), 6 deletions(-) diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index 2b44eee848..a140e09d77 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -843,6 +843,7 @@ Edit time signature (top)=Edit time signature (beats per measure) Edit time signature (bottom)=Edit time signature (single beat note value) Edit tickcount=Edit tickcount Edit combo=Edit combo +Edit label=Edit label Edit warp=Edit warp Editor options=Options EditorShowBGChangesPlay=Show Backgrounds @@ -1210,6 +1211,7 @@ Enter a new Time Signature numerator value.=Enter the number of beats per measur Enter a new Time Signature denominator value.=Enter the note value that represents one beat. Enter a new Tickcount value.=Enter a new Tickcount value. Enter a new Combo value.=Enter a new Combo value. +Enter a new Label value.=Enter a name for this section of the chart. Enter a new Warp value.=Enter the beat you will warp to when you reach this point. Enter a new artist transliteration.=Enter a new artist transliteration. Enter a new artist.=Enter a new artist. diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index 524bda0550..ab4339e527 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -981,6 +981,7 @@ WarpColor=color("1,0,0.5,1") TimeSignatureColor=color("1,0.55,0,1") TickcountColor=color("0,1,0,1") ComboColor=color("0.55,1,0,1") +LabelColor=color("1,0,0,1") # BPMIsLeftSide=true StopIsLeftSide=true @@ -989,6 +990,7 @@ WarpIsLeftSide=false TimeSignatureIsLeftSide=true TickcountIsLeftSide=false ComboIsLeftSide=false +LabelIsLeftSide=false # BPMOffsetX=60 StopOffsetX=50 @@ -997,6 +999,7 @@ WarpOffsetX=60 TimeSignatureOffsetX=30 TickcountOffsetX=10 ComboOffsetX=30 +LabelOffsetX=80 [PlayerStageStats] # Original CVS Grading diff --git a/src/NoteField.cpp b/src/NoteField.cpp index 958866b0a5..c1b7a9f0e7 100644 --- a/src/NoteField.cpp +++ b/src/NoteField.cpp @@ -426,6 +426,7 @@ static ThemeMetric WARP_COLOR ( "NoteField", "WarpColor" ); static ThemeMetric TIME_SIGNATURE_COLOR ( "NoteField", "TimeSignatureColor" ); static ThemeMetric TICKCOUNT_COLOR ( "NoteField", "TickcountColor" ); static ThemeMetric COMBO_COLOR ( "NoteField", "ComboColor" ); +static ThemeMetric LABEL_COLOR ( "NoteField", "LabelColor" ); static ThemeMetric BPM_IS_LEFT_SIDE ( "NoteField", "BPMIsLeftSide" ); static ThemeMetric STOP_IS_LEFT_SIDE ( "NoteField", "StopIsLeftSide" ); static ThemeMetric DELAY_IS_LEFT_SIDE ( "NoteField", "DelayIsLeftSide" ); @@ -433,6 +434,7 @@ static ThemeMetric WARP_IS_LEFT_SIDE ( "NoteField", "WarpIsLeftSide" ); static ThemeMetric TIME_SIGNATURE_IS_LEFT_SIDE ( "NoteField", "TimeSignatureIsLeftSide" ); static ThemeMetric TICKCOUNT_IS_LEFT_SIDE ( "NoteField", "TickcountIsLeftSide" ); static ThemeMetric COMBO_IS_LEFT_SIDE ( "NoteField", "ComboIsLeftSide" ); +static ThemeMetric LABEL_IS_LEFT_SIDE ( "NoteField", "LabelIsLeftSide" ); static ThemeMetric BPM_OFFSETX ( "NoteField", "BPMOffsetX" ); static ThemeMetric STOP_OFFSETX ( "NoteField", "StopOffsetX" ); static ThemeMetric DELAY_OFFSETX ( "NoteField", "DelayOffsetX" ); @@ -440,6 +442,7 @@ static ThemeMetric WARP_OFFSETX ( "NoteField", "WarpOffsetX" ); static ThemeMetric TIME_SIGNATURE_OFFSETX ( "NoteField", "TimeSignatureOffsetX" ); static ThemeMetric TICKCOUNT_OFFSETX ( "NoteField", "TickcountOffsetX" ); static ThemeMetric COMBO_OFFSETX ( "NoteField", "ComboOffsetX" ); +static ThemeMetric LABEL_OFFSETX ( "NoteField", "LabelOffsetX" ); void NoteField::DrawBPMText( const float fBeat, const float fBPM ) { @@ -552,6 +555,23 @@ void NoteField::DrawComboText( const float fBeat, int iCombo ) m_textMeasureNumber.Draw(); } +void NoteField::DrawLabelText( const float fBeat, RString sLabel ) +{ + const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); + const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels ); + const float fZoom = ArrowEffects::GetZoom( m_pPlayerState ); + const float xBase = GetWidth()/2.f; + const float xOffset = LABEL_OFFSETX * fZoom; + + m_textMeasureNumber.SetZoom( fZoom ); + m_textMeasureNumber.SetHorizAlign( LABEL_IS_LEFT_SIDE ? align_right : align_left ); + m_textMeasureNumber.SetDiffuse( LABEL_COLOR ); + m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) ); + m_textMeasureNumber.SetText( sLabel.c_str() ); + m_textMeasureNumber.SetXY( (LABEL_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos ); + m_textMeasureNumber.Draw(); +} + void NoteField::DrawAttackText( const float fBeat, const Attack &attack ) { const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); diff --git a/src/NoteField.h b/src/NoteField.h index 08a83e11aa..23502eca00 100644 --- a/src/NoteField.h +++ b/src/NoteField.h @@ -61,6 +61,7 @@ protected: void DrawTimeSignatureText( const float fBeat, int iNumerator, int iDenominator ); void DrawTickcountText( const float fBeat, int iTicks ); void DrawComboText( const float fBeat, int iCombo ); + void DrawLabelText( const float fBeat, RString sLabel ); void DrawAttackText( const float fBeat, const Attack &attack ); void DrawBGChangeText( const float fBeat, const RString sNewBGName ); float GetWidth() const; diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index b315b74098..c483ca0a7c 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -80,6 +80,7 @@ AutoScreenMessage( SM_BackFromTimeSignatureNumeratorChange ); AutoScreenMessage( SM_BackFromTimeSignatureDenominatorChange ); AutoScreenMessage( SM_BackFromTickcountChange ); AutoScreenMessage( SM_BackFromComboChange ); +AutoScreenMessage( SM_BackFromLabelChange ); AutoScreenMessage( SM_BackFromWarpChange ); AutoScreenMessage( SM_DoSaveAndExit ); AutoScreenMessage( SM_DoExit ); @@ -255,6 +256,14 @@ void ScreenEdit::InitEditMappings() m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_SELECT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_SELECT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_LABEL_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PERIOD); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_NEXT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); + + m_EditMappingsDeviceInput.button[EDIT_BUTTON_LABEL_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_COMMA); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_PREV][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SNAP_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LEFT); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SNAP_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_RIGHT); @@ -551,6 +560,7 @@ static MenuDef g_TimingDataInformation( MenuRowDef( ScreenEdit::time_signature_denominator, "Edit time signature (bottom)", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::tickcount, "Edit tickcount", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::combo, "Edit combo", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::label, "Edit label", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::warp, "Edit warp", true, EditMode_Full, true, true, 0, NULL ) ); @@ -1425,6 +1435,18 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) ScrollTo( NoteRowToBeat(iRow) ); } break; + case EDIT_BUTTON_LABEL_NEXT: + { + ScrollTo( GAMESTATE->m_pCurSong->m_Timing. + GetNextLabelSegmentBeatAtBeat( GAMESTATE->m_fSongBeat ) ); + } + break; + case EDIT_BUTTON_LABEL_PREV: + { + ScrollTo( GAMESTATE->m_pCurSong->m_Timing. + GetPreviousLabelSegmentBeatAtBeat( GAMESTATE->m_fSongBeat ) ); + } + break; case EDIT_BUTTON_SNAP_NEXT: if( m_SnapDisplay.PrevSnapMode() ) OnSnapModeChange(); @@ -2644,6 +2666,14 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) } SetDirty( true ); } + else if ( SM == SM_BackFromLabelChange ) + { + RString sLabel = ScreenTextEntry::s_sLastAnswer; + sLabel.Replace("=", "_"); + sLabel.Replace(",", "_"); + m_pSong->m_Timing.SetLabelAtBeat( GAMESTATE->m_fSongBeat, sLabel ); + SetDirty( true ); + } else if ( SM == SM_BackFromWarpChange ) { float fWarp = StringToFloat( ScreenTextEntry::s_sLastAnswer ); @@ -3187,6 +3217,7 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns g_TimingDataInformation.rows[time_signature_denominator].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTimeSignatureDenominatorAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[tickcount].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTickcountAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[combo].SetOneUnthemedChoice( ssprintf("%d", pTime.GetComboAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[label].SetOneUnthemedChoice( pTime.GetLabelAtBeat( fBeat ).c_str() ); g_TimingDataInformation.rows[warp].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetWarpAtBeat( fBeat ) ) ); EditMiniMenu( &g_TimingDataInformation, SM_BackFromTimingDataInformation ); @@ -3618,6 +3649,7 @@ static LocalizedString ENTER_TIME_SIGNATURE_NUMERATOR_VALUE ( "ScreenEdit", "Ent static LocalizedString ENTER_TIME_SIGNATURE_DENOMINATOR_VALUE ( "ScreenEdit", "Enter a new Time Signature denominator value." ); static LocalizedString ENTER_TICKCOUNT_VALUE ( "ScreenEdit", "Enter a new Tickcount value." ); static LocalizedString ENTER_COMBO_VALUE ( "ScreenEdit", "Enter a new Combo value." ); +static LocalizedString ENTER_LABEL_VALUE ( "ScreenEdit", "Enter a new Label value." ); static LocalizedString ENTER_WARP_VALUE ( "ScreenEdit", "Enter a new Warp value." ); void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice c, const vector &iAnswers ) { @@ -3680,6 +3712,14 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice 4 ); break; + case label: + ScreenTextEntry::TextEntry( + SM_BackFromLabelChange, + ENTER_LABEL_VALUE, + ssprintf( "%s", m_pSong->m_Timing.GetLabelAtBeat( GAMESTATE->m_fSongBeat ).c_str() ), + 64 + ); + break; case warp: ScreenTextEntry::TextEntry( SM_BackFromWarpChange, diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index 1f79b78528..f64772cc27 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -70,6 +70,9 @@ enum EditButton EDIT_BUTTON_SCROLL_NEXT, EDIT_BUTTON_SCROLL_PREV, + EDIT_BUTTON_LABEL_NEXT, + EDIT_BUTTON_LABEL_PREV, + // These are modifiers to EDIT_BUTTON_SCROLL_*. EDIT_BUTTON_SCROLL_SELECT, @@ -456,6 +459,7 @@ public: time_signature_denominator, tickcount, combo, + label, warp, NUM_TIMING_DATA_INFORMATION_CHOICES }; diff --git a/src/TimingData.cpp b/src/TimingData.cpp index b1f36960fa..68f0a81431 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -496,11 +496,11 @@ WarpSegment& TimingData::GetWarpSegmentAtRow( int iRow ) int TimingData::GetTickcountSegmentIndexAtRow( int iRow ) const { - int i; - for (i=0; i < (int)(m_TickcountSegments.size()) - 1; i++ ) + unsigned i; + for (i=0; i < m_TickcountSegments.size() - 1; i++ ) if( m_TickcountSegments[i+1].m_iStartRow > iRow ) break; - return i; + return static_cast(i); } TickcountSegment& TimingData::GetTickcountSegmentAtRow( int iRow ) @@ -518,6 +518,37 @@ int TimingData::GetTickcountAtRow( int iRow ) const return m_TickcountSegments[GetTickcountSegmentIndexAtRow( iRow )].m_iTicks; } +float TimingData::GetPreviousLabelSegmentBeatAtRow( int iRow ) const +{ + float backup = -1; + for (unsigned i = 0; i < m_LabelSegments.size(); i++ ) + { + if( m_LabelSegments[i].m_iStartRow > iRow ) + { + if( backup > -1 ) + { + return backup; + } + break; + } + backup = NoteRowToBeat(m_LabelSegments[i].m_iStartRow); + } + return NoteRowToBeat(iRow); +} + +float TimingData::GetNextLabelSegmentBeatAtRow( int iRow ) const +{ + for (unsigned i = 0; i < m_LabelSegments.size(); i++ ) + { + if( m_LabelSegments[i].m_iStartRow <= iRow ) + { + continue; + } + return NoteRowToBeat(m_LabelSegments[i].m_iStartRow); + } + return NoteRowToBeat(iRow); +} + void TimingData::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpLengthOut ) const { fElapsedTime += PREFSMAN->m_fGlobalOffsetSeconds; @@ -634,9 +665,6 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float } - - - float TimingData::GetElapsedTimeFromBeat( float fBeat ) const { return TimingData::GetElapsedTimeFromBeatNoOffset( fBeat ) - PREFSMAN->m_fGlobalOffsetSeconds; diff --git a/src/TimingData.h b/src/TimingData.h index e542c60d89..1c0a7edcb2 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -1202,6 +1202,32 @@ public: */ void AddLabelSegment( const LabelSegment &seg ); + /** + * @brief Retrieve the previous beat that contains a LabelSegment. + * @param iRow the present row. + * @return the previous beat with a LabelSegment, or fBeat if there is none prior. + */ + float GetPreviousLabelSegmentBeatAtRow( int iRow ) const; + /** + * @brief Retrieve the previous beat that contains a LabelSegment. + * @param fBeat the present beat. + * @return the previous beat with a LabelSegment, or fBeat if there is none prior. + */ + float GetPreviousLabelSegmentBeatAtBeat( float fBeat ) const { return GetPreviousLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); } + + /** + * @brief Retrieve the next beat that contains a LabelSegment. + * @param iRow the present row. + * @return the next beat with a LabelSegment, or fBeat if there is none ahead. + */ + float GetNextLabelSegmentBeatAtRow( int iRow ) const; + /** + * @brief Retrieve the previous beat that contains a LabelSegment. + * @param fBeat the present beat. + * @return the next beat with a LabelSegment, or fBeat if there is none ahead. + */ + float GetNextLabelSegmentBeatAtBeat( float fBeat ) const { return GetNextLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); } + void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor ); void NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const; From 9e6ea7b3a66fca395683a962c8bb217d34443592 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 5 Apr 2011 01:04:19 -0400 Subject: [PATCH 06/12] [sm130labels] Force starting label, display all. Now to fix the keyboard command... --- src/NoteField.cpp | 13 +++++++++++++ src/Song.cpp | 16 +++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/NoteField.cpp b/src/NoteField.cpp index c1b7a9f0e7..4d1a7ef0b2 100644 --- a/src/NoteField.cpp +++ b/src/NoteField.cpp @@ -862,6 +862,19 @@ void NoteField::DrawPrimitives() DrawComboText( fBeat, tComboSegments[i].m_iCombo ); } } + + // Label text + const vector &lLabelSegments = GAMESTATE->m_pCurSong->m_Timing.m_LabelSegments; + for( unsigned i=0; i= iFirstRowToDraw && + lLabelSegments[i].m_iStartRow <= iLastRowToDraw) + { + float fBeat = NoteRowToBeat(lLabelSegments[i].m_iStartRow); + if( IS_ON_SCREEN(fBeat) ) + DrawLabelText( fBeat, lLabelSegments[i].m_sLabel ); + } + } // Course mods text const Course *pCourse = GAMESTATE->m_pCurCourse; diff --git a/src/Song.cpp b/src/Song.cpp index a9ea071738..5e76729eac 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -781,10 +781,7 @@ void Song::TidyUpData() // If no time signature specified, assume 4/4 time for the whole song. if( m_Timing.m_vTimeSignatureSegments.empty() ) { - TimeSignatureSegment seg; - seg.m_iStartRow = 0; - seg.m_iNumerator = 4; - seg.m_iDenominator = 4; + TimeSignatureSegment seg(0, 4, 4); m_Timing.m_vTimeSignatureSegments.push_back( seg ); } @@ -795,9 +792,7 @@ void Song::TidyUpData() */ if( m_Timing.m_TickcountSegments.empty() ) { - TickcountSegment seg; - seg.m_iStartRow = 0; - seg.m_iTicks = 2; + TickcountSegment seg(0, 2); m_Timing.m_TickcountSegments.push_back( seg ); } @@ -809,6 +804,13 @@ void Song::TidyUpData() seg.m_iCombo = 1; m_Timing.m_ComboSegments.push_back( seg ); } + + // Have a default label segment just in case. + if( m_Timing.m_LabelSegments.empty() ) + { + LabelSegment seg(0, "Song Start"); + m_Timing.m_LabelSegments.push_back( seg ); + } } void Song::TranslateTitles() From 25b5e24b9325885c251d85066595565f27db5d98 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 5 Apr 2011 01:16:31 -0400 Subject: [PATCH 07/12] [sm130labels] Have to trim newline chars. --- src/NotesLoaderSSC.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 5d2c9ce188..19602e937f 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -532,7 +532,8 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach } const float fBeat = StringToFloat( arrayLabelValues[0] ); - const RString sLabel = arrayLabelValues[1]; + RString sLabel = arrayLabelValues[1]; + TrimRight(sLabel); if( fBeat > 0.0f ) out.m_Timing.AddLabelSegment( LabelSegment(fBeat, sLabel) ); else From 9a3a524a11108eaaeb38c7166750aa490f66d21f Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 5 Apr 2011 01:21:54 -0400 Subject: [PATCH 08/12] [sm130labels] Consistency: no empty labels. --- src/ScreenEdit.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index c483ca0a7c..8b7671fba1 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -2669,9 +2669,12 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) else if ( SM == SM_BackFromLabelChange ) { RString sLabel = ScreenTextEntry::s_sLastAnswer; - sLabel.Replace("=", "_"); - sLabel.Replace(",", "_"); - m_pSong->m_Timing.SetLabelAtBeat( GAMESTATE->m_fSongBeat, sLabel ); + if ( sLabel.length() > 0 ) + { + sLabel.Replace("=", "_"); + sLabel.Replace(",", "_"); + m_pSong->m_Timing.SetLabelAtBeat( GAMESTATE->m_fSongBeat, sLabel ); + } SetDirty( true ); } else if ( SM == SM_BackFromWarpChange ) From f01e37854ae923299f9040b8fdee666623ac1016 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 5 Apr 2011 01:28:06 -0400 Subject: [PATCH 09/12] [sm130labels] Fix keyboard function. --- src/TimingData.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 68f0a81431..2f808b503c 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -523,17 +523,13 @@ float TimingData::GetPreviousLabelSegmentBeatAtRow( int iRow ) const float backup = -1; for (unsigned i = 0; i < m_LabelSegments.size(); i++ ) { - if( m_LabelSegments[i].m_iStartRow > iRow ) + if( m_LabelSegments[i].m_iStartRow >= iRow ) { - if( backup > -1 ) - { - return backup; - } break; } backup = NoteRowToBeat(m_LabelSegments[i].m_iStartRow); } - return NoteRowToBeat(iRow); + return (backup > -1) ? backup : NoteRowToBeat(iRow); } float TimingData::GetNextLabelSegmentBeatAtRow( int iRow ) const From a8ce71fd8173bc7551b31692c69e748fb0326afc Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 5 Apr 2011 01:33:47 -0400 Subject: [PATCH 10/12] [sm130labels] Prepare changelog. --- Docs/Changelog_sm-ssc.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Docs/Changelog_sm-ssc.txt b/Docs/Changelog_sm-ssc.txt index 9b7c9fd1a0..f480c29717 100644 --- a/Docs/Changelog_sm-ssc.txt +++ b/Docs/Changelog_sm-ssc.txt @@ -9,6 +9,16 @@ Not all changes are documented, for various reasons. supported but exist anyways.) _____________________________________________________________________________ +================================================================================ +sm-ssc $SM5VERSION | 2011???? +-------------------------------------------------------------------------------- + +20110405 +-------- +* [NotesLoaderSSC, NotesWriterSSC] Add the #LABELS tag. This is meant for step + editors to label different parts of their stepcharts. Use Control + , or . to + jump to different labels made. [Wolfman2000] + ================================================================================ sm-ssc $NEXTVERSION | 2011???? -------------------------------------------------------------------------------- From 48fd81c5157a92ec12c199966b023cb8387fc7df Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 5 Apr 2011 14:13:19 -0400 Subject: [PATCH 11/12] [sm130labels] > != >= --- src/NotesLoaderSSC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 19602e937f..00c2503f2b 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -534,7 +534,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach const float fBeat = StringToFloat( arrayLabelValues[0] ); RString sLabel = arrayLabelValues[1]; TrimRight(sLabel); - if( fBeat > 0.0f ) + if( fBeat >= 0.0f ) out.m_Timing.AddLabelSegment( LabelSegment(fBeat, sLabel) ); else { From 5e61884941cf77ac5ba59c022b74f45a406ab8f5 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 5 Apr 2011 14:18:29 -0400 Subject: [PATCH 12/12] [sm130labels] Do not allow duplicate label names. --- src/ScreenEdit.cpp | 4 ++-- src/TimingData.cpp | 12 +++++++++++- src/TimingData.h | 6 ++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 8b7671fba1..a01d5aa25c 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -2669,13 +2669,13 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) else if ( SM == SM_BackFromLabelChange ) { RString sLabel = ScreenTextEntry::s_sLastAnswer; - if ( sLabel.length() > 0 ) + if ( !m_pSong->m_Timing.DoesLabelExist(sLabel) ) { sLabel.Replace("=", "_"); sLabel.Replace(",", "_"); m_pSong->m_Timing.SetLabelAtBeat( GAMESTATE->m_fSongBeat, sLabel ); + SetDirty( true ); } - SetDirty( true ); } else if ( SM == SM_BackFromWarpChange ) { diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 2f808b503c..26991f3d67 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -238,7 +238,7 @@ void TimingData::SetLabelAtRow( int iRow, const RString sLabel ) } else { - if( i > 0 && m_LabelSegments[i-1].m_sLabel == sLabel ) + if( i > 0 && ( m_LabelSegments[i-1].m_sLabel == sLabel || sLabel == "" ) ) m_LabelSegments.erase( m_LabelSegments.begin()+i, m_LabelSegments.begin()+i+1 ); else m_LabelSegments[i].m_sLabel = sLabel; @@ -545,6 +545,16 @@ float TimingData::GetNextLabelSegmentBeatAtRow( int iRow ) const return NoteRowToBeat(iRow); } +bool TimingData::DoesLabelExist( RString sLabel ) const +{ + FOREACH_CONST( LabelSegment, m_LabelSegments, seg ) + { + if( seg->m_sLabel == sLabel ) + return true; + } + return false; +} + void TimingData::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpLengthOut ) const { fElapsedTime += PREFSMAN->m_fGlobalOffsetSeconds; diff --git a/src/TimingData.h b/src/TimingData.h index 1c0a7edcb2..5464a8748e 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -1215,6 +1215,12 @@ public: */ float GetPreviousLabelSegmentBeatAtBeat( float fBeat ) const { return GetPreviousLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Determine if the requisite label already exists. + * @param sLabel the label to check. + * @return true if it exists, false otherwise. */ + bool DoesLabelExist( RString sLabel ) const; + /** * @brief Retrieve the next beat that contains a LabelSegment. * @param iRow the present row.