[sm130labels] Add labels to the SSC format.
Also do cleanup on the Loader and Writer comments. Editor hooks to follow soon.
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
+37
-161
@@ -514,6 +514,34 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if( sValueName=="LABELS" )
|
||||
{
|
||||
vector<RString> arrayLabelExpressions;
|
||||
split( sParams[1], ",", arrayLabelExpressions );
|
||||
|
||||
for( unsigned b=0; b<arrayLabelExpressions.size(); b++ )
|
||||
{
|
||||
vector<RString> 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<RString> arrayFreezeExpressions;
|
||||
split( sParams[1], ",", arrayFreezeExpressions );
|
||||
|
||||
for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ )
|
||||
{
|
||||
vector<RString> 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<RString> arrayDelayExpressions;
|
||||
split( sParams[1], ",", arrayDelayExpressions );
|
||||
|
||||
for( unsigned f=0; f<arrayDelayExpressions.size(); f++ )
|
||||
{
|
||||
vector<RString> 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<RString> vs1;
|
||||
split( sParams[1], ",", vs1 );
|
||||
|
||||
FOREACH_CONST( RString, vs1, s1 )
|
||||
{
|
||||
vector<RString> 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<RString> arrayTickcountExpressions;
|
||||
split( sParams[1], ",", arrayTickcountExpressions );
|
||||
|
||||
for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ )
|
||||
{
|
||||
vector<RString> 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<RString> arrayComboExpressions;
|
||||
split( sParams[1], ",", arrayComboExpressions );
|
||||
|
||||
for( unsigned f=0; f<arrayComboExpressions.size(); f++ )
|
||||
{
|
||||
vector<RString> 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" )
|
||||
{
|
||||
|
||||
+15
-82
@@ -194,6 +194,17 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
|
||||
}
|
||||
f.PutLine( ";" );
|
||||
|
||||
f.Write( "#LABELS:" );
|
||||
for( unsigned i=0; i<out.m_Timing.m_LabelSegments.size(); i++ )
|
||||
{
|
||||
const LabelSegment &ls = out.m_Timing.m_LabelSegments[i];
|
||||
|
||||
f.PutLine( ssprintf( "%.6f=%s", NoteRowToBeat(ls.m_iStartRow), ls.m_sLabel.c_str() ) );
|
||||
if( i != out.m_Timing.m_LabelSegments.size()-1 )
|
||||
f.Write( "," );
|
||||
}
|
||||
f.PutLine( ";" );
|
||||
|
||||
FOREACH_BackgroundLayer( b )
|
||||
{
|
||||
if( b==0 )
|
||||
@@ -295,97 +306,19 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa
|
||||
|
||||
lines.push_back( ssprintf( "#CREDIT:%s;", SmEscape(in.GetCredit()).c_str() ) );
|
||||
|
||||
// TODO: Remove this block, uncomment below block for Split Timing. -Wolfman2000
|
||||
/*
|
||||
* TODO: Remove this block, transplant above code
|
||||
* below for Split Timing. -Wolfman2000 */
|
||||
lines.push_back( "#BPMS:;" );
|
||||
lines.push_back( "#STOPS:;" );
|
||||
lines.push_back( "#DELAYS:;" );
|
||||
lines.push_back( "#WARPS:;" );
|
||||
lines.push_back( "#LABELS:;" );
|
||||
lines.push_back( "#TIMESIGNATURES:;" );
|
||||
lines.push_back( "#TICKCOUNTS:;" );
|
||||
lines.push_back( "#ATTACKS:;" );
|
||||
lines.push_back( "#COMBOS:;" );
|
||||
|
||||
/*
|
||||
vector<RString> asBPMValues;
|
||||
for( unsigned i=0; i<in.m_Timing.m_BPMSegments.size(); i++ )
|
||||
{
|
||||
const BPMSegment &bs = in.m_Timing.m_BPMSegments[i];
|
||||
asBPMValues.push_back( ssprintf("%.6f=%.6f", NoteRowToBeat(bs.m_iStartRow), bs.GetBPM() ) );
|
||||
}
|
||||
lines.push_back( ssprintf( "#BPMS:%s;", join("\n,", asBPMValues).c_str() ) );
|
||||
|
||||
vector<RString> asStopValues;
|
||||
for( unsigned i=0; i<in.m_Timing.m_StopSegments.size(); i++ )
|
||||
{
|
||||
const StopSegment &fs = in.m_Timing.m_StopSegments[i];
|
||||
|
||||
if(!fs.m_bDelay)
|
||||
{
|
||||
asStopValues.push_back( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
|
||||
}
|
||||
}
|
||||
lines.push_back( ssprintf( "#STOPS:%s;", join("\n,", asStopValues).c_str() ) );
|
||||
|
||||
vector<RString> asDelayValues;
|
||||
for( unsigned i=0; i<in.m_Timing.m_StopSegments.size(); i++ )
|
||||
{
|
||||
const StopSegment &fs = in.m_Timing.m_StopSegments[i];
|
||||
|
||||
if( fs.m_bDelay )
|
||||
{
|
||||
asDelayValues.push_back( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fStopSeconds ) );
|
||||
}
|
||||
}
|
||||
lines.push_back( ssprintf( "#DELAYS:%s;", join("\n,", asDelayValues).c_str() ) );
|
||||
|
||||
vector<RString> asWarpValues;
|
||||
for( unsigned i=0; i<in.m_Timing.m_WarpSegments.size(); i++ )
|
||||
{
|
||||
const WarpSegment &ws = in.m_Timing.m_WarpSegments[i];
|
||||
|
||||
if( ws.m_bDelay )
|
||||
{
|
||||
asWarpValues.push_back( ssprintf( "%.6f=%.6f", NoteRowToBeat(fs.m_iStartRow), fs.m_fWarpBeats ) );
|
||||
}
|
||||
}
|
||||
lines.push_back( ssprintf( "#WARPS:%s;", join("\n,", asWarpValues).c_str() ) );
|
||||
|
||||
ASSERT( !in.m_Timing.m_vTimeSignatureSegments.empty() );
|
||||
vector<RString> 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<TimeSignatureSegment>::const_iterator iter2 = iter;
|
||||
iter2++;
|
||||
}
|
||||
lines.push_back( ssprintf( "#TIMESIGNATURES:%s;", join("\n,", asTimeSigValues).c_str() ) );
|
||||
|
||||
ASSERT( !in.m_Timing.m_TickcountSegments.empty() );
|
||||
vector<RString> asTickValues;
|
||||
for( unsigned i=0; i<in.m_Timing.m_TickcountSegments.size(); i++ )
|
||||
{
|
||||
const TickcountSegment &ts = in.m_Timing.m_TickcountSegments[i];
|
||||
|
||||
asTickValues.push_back( ssprintf( "%.6f=%d", NoteRowToBeat(ts.m_iStartRow), ts.m_iTicks ) );
|
||||
}
|
||||
lines.push_back( ssprintf( "#TICKCOUNTS:%s;", join("\n,", asTickValues).c_str() ) );
|
||||
|
||||
ASSERT( !in.m_Timing.m_ComboSegments.empty() );
|
||||
vector<RString> asComboValues;
|
||||
for( unsigned i=0; i<in.m_Timing.m_ComboSegments.size(); i++ )
|
||||
{
|
||||
const ComboSegment &cs = in.m_Timing.m_ComboSegments[i];
|
||||
|
||||
asComboValues.push_back( ssprintf( "%.6f=%d", NoteRowToBeat(cs.m_iStartRow), cs.m_iComboFactor ) );
|
||||
}
|
||||
|
||||
lines.push_back( "#ATTACKS:;" );
|
||||
|
||||
lines.push_back( ssprintf( "#COMBOS:%s;", join("\n,", asComboValues).c_str() ) );
|
||||
|
||||
lines.push_back( ssprintf( "#OFFSET:%.6f;", in.m_Timing.m_fBeat0OffsetInSeconds ) );
|
||||
*/
|
||||
|
||||
RString sNoteData;
|
||||
in.GetSMNoteData( sNoteData );
|
||||
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
* @brief The internal version of the cache for StepMania.
|
||||
*
|
||||
* Increment this value to invalidate the current cache. */
|
||||
const int FILE_CACHE_VERSION = 167;
|
||||
const int FILE_CACHE_VERSION = 168;
|
||||
|
||||
/** @brief How long does a song sample last by default? */
|
||||
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ struct lua_State;
|
||||
struct BackgroundChange;
|
||||
|
||||
/** @brief The version of the .ssc file format. */
|
||||
const static float STEPFILE_VERSION_NUMBER = 0.56f;
|
||||
const static float STEPFILE_VERSION_NUMBER = 0.57f;
|
||||
|
||||
/** @brief How many edits for this song can each profile have? */
|
||||
const int MAX_EDITS_PER_SONG_PER_PROFILE = 5;
|
||||
|
||||
+8
-1
@@ -584,7 +584,14 @@ struct LabelSegment
|
||||
* @param l the label for this section.
|
||||
*/
|
||||
LabelSegment( int s, RString l ): m_iStartRow(max(0, s)),
|
||||
m_sLabel(l) {}
|
||||
m_sLabel(l) {}
|
||||
/**
|
||||
* @brief Creates a Label Segment with the specified starting beat and label.
|
||||
* @param s the starting beat of this segment.
|
||||
* @param l the label for this section.
|
||||
*/
|
||||
LabelSegment( float s, RString l ):
|
||||
m_iStartRow(max(0, BeatToNoteRow(s))), m_sLabel(l) {}
|
||||
/**
|
||||
* @brief The row in which the ComboSegment activates.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user