[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:
Jason Felds
2011-04-04 23:24:32 -04:00
parent 53971e16e3
commit 3991f81101
6 changed files with 65 additions and 246 deletions
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*/