diff --git a/Docs/Changelog_SSCformat.txt b/Docs/Changelog_SSCformat.txt
index 12cb56d7b8..20088bb92b 100644
--- a/Docs/Changelog_SSCformat.txt
+++ b/Docs/Changelog_SSCformat.txt
@@ -9,6 +9,11 @@ change to JSON, but it is unsure if this will be done.
Implement .ssc at your own risk.
________________________________________________________________________________
+[v0.73] - Wolfman2000
+* Use #FIRSTSECOND, #LASTSECOND, and #LASTSECONDHINT instead of the BEAT
+ equivalents.
+* Move #LASTSECONDHINT to after the Timing tags.
+
[v0.72] - Wolfman2000
* Have #OFFSET come before #ATTACKS in the Step data.
diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt
index 3becdfa38c..51ae1cbde6 100644
--- a/Docs/Changelog_sm5.txt
+++ b/Docs/Changelog_sm5.txt
@@ -8,6 +8,12 @@ ________________________________________________________________________________
StepMania 5.0 Preview 2 | 201106??
--------------------------------------------------------------------------------
+2011/06/30
+----------
+* [NotesAll] Use #FIRSTSECOND, #LASTSECOND, and #LASTSECONDHINT instead of the
+ former BEAT equivalents. Split Timing has made this a necessity thanks to
+ certain files that abuse Stops/Delays more than usual. [Wolfman2000]
+
2011/06/28
----------
* [ScreenEdit] Add a function to copy/paste the TimingData of a player's
diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml
index 1785b00b94..ed192118a5 100644
--- a/Docs/Luadoc/Lua.xml
+++ b/Docs/Luadoc/Lua.xml
@@ -1244,9 +1244,11 @@
+
+
diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml
index 2098898a41..40d229921d 100644
--- a/Docs/Luadoc/LuaDocumentation.xml
+++ b/Docs/Luadoc/LuaDocumentation.xml
@@ -3084,6 +3084,9 @@
Returns the first beat of the song.
+
+ Returns the first second of the song.
+
Returns the genre of the song.
@@ -3093,6 +3096,9 @@
Returns the last beat of the song.
+
+ Returns the last second of the song.
+
Gets the path to the lyrics.
diff --git a/Docs/SimfileFormats/ssc_msd5.txt b/Docs/SimfileFormats/ssc_msd5.txt
index 119f61b297..9c00273a64 100644
--- a/Docs/SimfileFormats/ssc_msd5.txt
+++ b/Docs/SimfileFormats/ssc_msd5.txt
@@ -21,11 +21,11 @@
#DELAYS:;
#LABELS:;
#TIMESIGNATURES:;
-#LASTBEATHINT:;
#SAMPLESTART:;
#SAMPLELENGTH:;
#DISPLAYBPM:[xxx][xxx:xxx]|[*];
#SELECTABLE:;
+#LASTBEATHINT:;
#BGCHANGES:;
#FGCHANGES:;
#KEYSOUNDS:;
diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini
index 1c796abc6b..e9f39cb930 100644
--- a/Themes/_fallback/Languages/en.ini
+++ b/Themes/_fallback/Languages/en.ini
@@ -916,7 +916,7 @@ Insert Entry=Insert Entry
Jumps=Jumps
Key Joy Mappings=Config Key/Joy Mappings
Language=Language
-Last beat hint=Last beat hint
+Last second hint=Last second hint
Layer=Layer
LifeDifficulty=Life Difficulty
LifeType=Life Type
@@ -1256,7 +1256,7 @@ Enter a new chart style.=Enter a new chart style (e.g. "Pad", "Keyboard").
Enter a new meter.=Enter the difficulty rating for this chart.
Enter the author who made this step pattern.=Enter the author who made this step pattern.
Enter the offset for the song.=Enter the beat 0 offset for the song.
-Enter a new last beat hint.=Enter a new last beat hint.
+Enter a new last second hint.=Enter a new last second hint.
Enter a new main title transliteration.=Enter a new main title transliteration.
Enter a new main title.=Enter a new main title.
Enter a new sub title transliteration.=Enter a new sub title transliteration.
diff --git a/src/Background.cpp b/src/Background.cpp
index 19e21abf7a..b86a86027e 100644
--- a/src/Background.cpp
+++ b/src/Background.cpp
@@ -577,13 +577,16 @@ void BackgroundImpl::LoadFromSong( const Song* pSong )
else // pSong doesn't have an animation plan
{
Layer &layer = m_Layer[0];
+ const TimingData &t = pSong->m_SongTiming;
+ float firstBeat = t.GetBeatFromElapsedTime(pSong->firstSecond);
+ float lastBeat = t.GetBeatFromElapsedTime(pSong->lastSecond);
- LoadFromRandom( pSong->m_fFirstBeat, pSong->m_fLastBeat, BackgroundChange() );
+ LoadFromRandom( firstBeat, lastBeat, BackgroundChange() );
// end showing the static song background
BackgroundChange change;
change.m_def = m_StaticBackgroundDef;
- change.m_fStartBeat = pSong->m_fLastBeat;
+ change.m_fStartBeat = lastBeat;
layer.m_aBGChanges.push_back( change );
}
@@ -642,7 +645,7 @@ void BackgroundImpl::LoadFromSong( const Song* pSong )
continue;
float fStartBeat = change.m_fStartBeat;
- float fEndBeat = pSong->m_fLastBeat;
+ float fEndBeat = pSong->m_SongTiming.GetBeatFromElapsedTime(pSong->lastSecond);
if( i+1 < mainlayer.m_aBGChanges.size() )
fEndBeat = mainlayer.m_aBGChanges[i+1].m_fStartBeat;
diff --git a/src/DancingCharacters.cpp b/src/DancingCharacters.cpp
index 08088290eb..d9382c42d1 100644
--- a/src/DancingCharacters.cpp
+++ b/src/DancingCharacters.cpp
@@ -166,7 +166,8 @@ void DancingCharacters::LoadNextSong()
m_fThisCameraEndBeat = 0;
ASSERT( GAMESTATE->m_pCurSong );
- m_fThisCameraEndBeat = GAMESTATE->m_pCurSong->m_fFirstBeat;
+ Song &s = *GAMESTATE->m_pCurSong;
+ m_fThisCameraEndBeat = s.m_SongTiming.GetBeatFromElapsedTime(s.firstSecond);
FOREACH_PlayerNumber( p )
if( GAMESTATE->IsPlayerEnabled(p) )
@@ -212,9 +213,10 @@ void DancingCharacters::Update( float fDelta )
bWasGameplayStarting = bGameplayStarting;
static float fLastBeat = GAMESTATE->m_Position.m_fSongBeat;
+ Song &s = *GAMESTATE->m_pCurSong;
+ float firstBeat = s.m_SongTiming.GetBeatFromElapsedTime(s.firstSecond);
float fThisBeat = GAMESTATE->m_Position.m_fSongBeat;
- if( fLastBeat < GAMESTATE->m_pCurSong->m_fFirstBeat &&
- fThisBeat >= GAMESTATE->m_pCurSong->m_fFirstBeat )
+ if( fLastBeat < firstBeat && fThisBeat >= firstBeat )
{
FOREACH_PlayerNumber( p )
m_pCharacter[p]->PlayAnimation( "dance" );
diff --git a/src/GameState.cpp b/src/GameState.cpp
index fe0d7099de..1ba34d53f9 100644
--- a/src/GameState.cpp
+++ b/src/GameState.cpp
@@ -991,7 +991,8 @@ update player position code goes here
float GameState::GetSongPercent( float beat ) const
{
// 0 = first step; 1 = last step
- return (beat - m_pCurSong->m_fFirstBeat) / m_pCurSong->m_fLastBeat;
+ float curTime = this->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat(beat);
+ return (curTime - m_pCurSong->firstSecond) / m_pCurSong->lastSecond;
}
int GameState::GetNumStagesLeft( PlayerNumber pn ) const
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index d3f563c30a..71a30a9ba9 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -119,10 +119,10 @@ void Inventory::Update( float fDelta )
}
}
-
+ Song &song = *GAMESTATE->m_pCurSong;
// use items if this player is CPU-controlled
if( m_pPlayerState->m_PlayerController != PC_HUMAN &&
- GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fLastBeat )
+ GAMESTATE->m_Position.m_fSongBeat < song.m_SongTiming.GetBeatFromElapsedTime(song.lastSecond) )
{
// every 1 seconds, try to use an item
int iLastSecond = (int)(RageTimer::GetTimeSinceStartFast() - fDelta);
diff --git a/src/LyricDisplay.cpp b/src/LyricDisplay.cpp
index 7284d2dc17..a6bdfea918 100644
--- a/src/LyricDisplay.cpp
+++ b/src/LyricDisplay.cpp
@@ -59,8 +59,8 @@ void LyricDisplay::Update( float fDeltaTime )
if( m_iCurLyricNumber+1 < GAMESTATE->m_pCurSong->m_LyricSegments.size() )
fEndTime = pSong->m_LyricSegments[m_iCurLyricNumber+1].m_fStartTime;
else
- fEndTime = pSong->m_SongTiming.GetElapsedTimeFromBeat( pSong->m_fLastBeat );
-
+ fEndTime = pSong->lastSecond;
+
const float fDistance = fEndTime - pSong->m_LyricSegments[m_iCurLyricNumber].m_fStartTime;
const float fTweenBufferTime = IN_LENGTH.GetValue() + OUT_LENGTH.GetValue();
diff --git a/src/MeterDisplay.cpp b/src/MeterDisplay.cpp
index 641b50d73c..5bc9da2e6a 100644
--- a/src/MeterDisplay.cpp
+++ b/src/MeterDisplay.cpp
@@ -73,8 +73,8 @@ void SongMeterDisplay::Update( float fDeltaTime )
{
if( GAMESTATE->m_pCurSong )
{
- float fSongStartSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fFirstBeat );
- float fSongEndSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat );
+ float fSongStartSeconds = GAMESTATE->m_pCurSong->firstSecond;
+ float fSongEndSeconds = GAMESTATE->m_pCurSong->lastSecond;
float fPercentPositionSong = SCALE( GAMESTATE->m_Position.m_fMusicSeconds, fSongStartSeconds, fSongEndSeconds, 0.0f, 1.0f );
CLAMP( fPercentPositionSong, 0, 1 );
diff --git a/src/NotesLoaderJson.cpp b/src/NotesLoaderJson.cpp
index 9d422d5177..dab70f29ee 100644
--- a/src/NotesLoaderJson.cpp
+++ b/src/NotesLoaderJson.cpp
@@ -150,8 +150,6 @@ static void Deserialize( Song &out, const Json::Value &root )
else if( sSelectable.EqualsNoCase("NO") )
out.m_SelectionDisplay = out.SHOW_NEVER;
- out.m_fFirstBeat = (float)root["FirstBeat"].asDouble();
- out.m_fLastBeat = (float)root["LastBeat"].asDouble();
out.m_sSongFileName = root["SongFileName"].asString();
out.m_bHasMusic = root["HasMusic"].asBool();
out.m_bHasBanner = root["HasBanner"].asBool();
diff --git a/src/NotesLoaderSM.cpp b/src/NotesLoaderSM.cpp
index fc5a59273e..82da1ffbbc 100644
--- a/src/NotesLoaderSM.cpp
+++ b/src/NotesLoaderSM.cpp
@@ -812,37 +812,19 @@ bool SMLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache
}
else if( sValueName=="LASTBEATHINT" )
- out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] );
+ {
+ // unable to identify at this point: ignore
+ }
else if( sValueName=="MUSICBYTES" )
; /* ignore */
- /* We calculate these. Some SMs in circulation have bogus values for
- * these, so make sure we always calculate it ourself. */
- else if( sValueName=="FIRSTBEAT" )
+ // cache tags from older SM files: ignore.
+ else if(sValueName=="FIRSTBEAT" || sValueName=="LASTBEAT" ||
+ sValueName=="SONGFILENAME" || sValueName=="HASMUSIC" ||
+ sValueName=="HASBANNER")
{
- if( bFromCache )
- out.m_fFirstBeat = StringToFloat( sParams[1] );
- }
- else if( sValueName=="LASTBEAT" )
- {
- if( bFromCache )
- out.m_fLastBeat = StringToFloat( sParams[1] );
- }
- else if( sValueName=="SONGFILENAME" )
- {
- if( bFromCache )
- out.m_sSongFileName = sParams[1];
- }
- else if( sValueName=="HASMUSIC" )
- {
- if( bFromCache )
- out.m_bHasMusic = StringToInt( sParams[1] ) != 0;
- }
- else if( sValueName=="HASBANNER" )
- {
- if( bFromCache )
- out.m_bHasBanner = StringToInt( sParams[1] ) != 0;
+ ;
}
else if( sValueName=="SAMPLESTART" )
@@ -1108,9 +1090,10 @@ void SMLoader::TidyUpData( Song &song, bool bFromCache )
if( bFromCache )
break;
+ float lastBeat = song.m_SongTiming.GetBeatFromElapsedTime(song.lastSecond);
/* If BGChanges already exist after the last beat, don't add the
* background in the middle. */
- if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= song.m_fLastBeat )
+ if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= lastBeat )
break;
// If the last BGA is already the song BGA, don't add a duplicate.
@@ -1120,7 +1103,8 @@ void SMLoader::TidyUpData( Song &song, bool bFromCache )
if( !IsAFile( song.GetBackgroundPath() ) )
break;
- bg.push_back( BackgroundChange(song.m_fLastBeat,song.m_sBackgroundFile) );
+
+ bg.push_back( BackgroundChange(lastBeat,song.m_sBackgroundFile) );
} while(0);
}
song.TidyUpData( bFromCache );
diff --git a/src/NotesLoaderSMA.cpp b/src/NotesLoaderSMA.cpp
index 648d54dcca..05db8d42b0 100644
--- a/src/NotesLoaderSMA.cpp
+++ b/src/NotesLoaderSMA.cpp
@@ -225,30 +225,16 @@ bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach
}
else if( sValueName=="LASTBEATHINT" )
- out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] );
-
+ {
+ // can't identify at this position: ignore.
+ }
else if( sValueName=="MUSICBYTES" )
; /* ignore */
- /* We calculate these. Some SMs in circulation have bogus values for
- * these, so make sure we always calculate it ourself. */
- else if( sValueName=="FIRSTBEAT" )
- {
- ;
- }
- else if( sValueName=="LASTBEAT" )
- {
- ;
- }
- else if( sValueName=="SONGFILENAME" )
- {
- ;
- }
- else if( sValueName=="HASMUSIC" )
- {
- ;
- }
- else if( sValueName=="HASBANNER" )
+ // Cache tags: ignore.
+ else if (sValueName=="FIRSTBEAT" || sValueName=="LASTBEAT" ||
+ sValueName=="SONGFILENAME" || sValueName=="HASMUSIC" ||
+ sValueName=="HASBANNER" )
{
;
}
diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp
index fe02b9181b..d2d92daf51 100644
--- a/src/NotesLoaderSSC.cpp
+++ b/src/NotesLoaderSSC.cpp
@@ -265,7 +265,12 @@ bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach
else if( sValueName=="LASTBEATHINT" )
{
- out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] );
+ // unable to parse due to tag position. Ignore.
+ }
+
+ else if (sValueName == "LASTSECONDHINT")
+ {
+ out.specifiedLastSecond = StringToFloat(sParams[1]);
}
else if( sValueName=="MUSICBYTES" )
@@ -395,16 +400,20 @@ bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach
/* The following are cache tags. Never fill their values
* directly: only from the cached version. */
- else if( sValueName=="FIRSTBEAT" )
+ else if( sValueName=="FIRSTBEAT" || sValueName=="LASTBEAT" )
+ {
+ // no longer used.
+ }
+ else if (sValueName=="FIRSTSECOND")
{
if( bFromCache )
- out.m_fFirstBeat = StringToFloat( sParams[1] );
+ out.firstSecond = StringToFloat( sParams[1] );
}
else if( sValueName=="LASTBEAT" )
{
if( bFromCache )
- out.m_fLastBeat = StringToFloat( sParams[1] );
+ out.lastSecond = StringToFloat( sParams[1] );
}
else if( sValueName=="SONGFILENAME" )
diff --git a/src/NotesWriterJson.cpp b/src/NotesWriterJson.cpp
index e5ad6338d9..f0df061323 100644
--- a/src/NotesWriterJson.cpp
+++ b/src/NotesWriterJson.cpp
@@ -147,8 +147,8 @@ bool NotesWriterJson::WriteSong( const RString &sFile, const Song &out, bool bWr
else
root["Selectable"] = "YES";
- root["FirstBeat"] = out.m_fFirstBeat;
- root["LastBeat"] = out.m_fLastBeat;
+ root["FirstBeat"] = out.m_SongTiming.GetBeatFromElapsedTime(out.firstSecond);
+ root["LastBeat"] = out.m_SongTiming.GetBeatFromElapsedTime(out.lastSecond);
root["SongFileName"] = out.m_sSongFileName;
root["HasMusic"] = out.m_bHasMusic;
root["HasBanner"] = out.m_bHasBanner;
diff --git a/src/NotesWriterSM.cpp b/src/NotesWriterSM.cpp
index 6b9f89c1fe..06934bb06e 100644
--- a/src/NotesWriterSM.cpp
+++ b/src/NotesWriterSM.cpp
@@ -66,8 +66,8 @@ static void WriteGlobalTags( RageFile &f, Song &out )
f.PutLine( ssprintf( "#OFFSET:%.3f;", out.m_SongTiming.m_fBeat0OffsetInSeconds ) );
f.PutLine( ssprintf( "#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds ) );
f.PutLine( ssprintf( "#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds ) );
- if( out.m_fSpecifiedLastBeat > 0 )
- f.PutLine( ssprintf("#LASTBEATHINT:%.3f;", out.m_fSpecifiedLastBeat) );
+ if( out.specifiedLastSecond > 0 )
+ f.PutLine( ssprintf("#LASTBEATHINT:%.3f;", out.m_SongTiming.GetBeatFromElapsedTime(out.specifiedLastSecond)) );
f.Write( "#SELECTABLE:" );
switch(out.m_SelectionDisplay)
diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp
index 528f438c66..261cf73c05 100644
--- a/src/NotesWriterSSC.cpp
+++ b/src/NotesWriterSSC.cpp
@@ -203,8 +203,6 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
f.PutLine( ssprintf( "#OFFSET:%.6f;", out.m_SongTiming.m_fBeat0OffsetInSeconds ) );
f.PutLine( ssprintf( "#SAMPLESTART:%.6f;", out.m_fMusicSampleStartSeconds ) );
f.PutLine( ssprintf( "#SAMPLELENGTH:%.6f;", out.m_fMusicSampleLengthSeconds ) );
- if( out.m_fSpecifiedLastBeat > 0 )
- f.PutLine( ssprintf("#LASTBEATHINT:%.6f;", out.m_fSpecifiedLastBeat) );
f.Write( "#SELECTABLE:" );
switch(out.m_SelectionDisplay)
@@ -234,6 +232,9 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
WriteTimingTags( f, out.m_SongTiming, true );
+ if( out.specifiedLastSecond > 0 )
+ f.PutLine( ssprintf("#LASTSECONDHINT:%.6f;", out.specifiedLastSecond) );
+
FOREACH_BackgroundLayer( b )
{
if( b==0 )
@@ -367,8 +368,8 @@ bool NotesWriterSSC::Write( RString sPath, const Song &out, const vector
if( bSavingCache )
{
f.PutLine( ssprintf( "// cache tags:" ) );
- f.PutLine( ssprintf( "#FIRSTBEAT:%.6f;", out.m_fFirstBeat ) );
- f.PutLine( ssprintf( "#LASTBEAT:%.6f;", out.m_fLastBeat ) );
+ f.PutLine( ssprintf( "#FIRSTSECOND:%.6f;", out.firstSecond ) );
+ f.PutLine( ssprintf( "#LASTSECOND:%.6f;", out.lastSecond ) );
f.PutLine( ssprintf( "#SONGFILENAME:%s;", out.m_sSongFileName.c_str() ) );
f.PutLine( ssprintf( "#HASMUSIC:%i;", out.m_bHasMusic ) );
f.PutLine( ssprintf( "#HASBANNER:%i;", out.m_bHasBanner ) );
diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp
index 55660d2c05..c14cb5c3b9 100644
--- a/src/ScreenEdit.cpp
+++ b/src/ScreenEdit.cpp
@@ -618,7 +618,7 @@ static MenuDef g_SongInformation(
MenuRowDef( ScreenEdit::main_title_transliteration, "Main title transliteration", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::sub_title_transliteration, "Sub title transliteration", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::artist_transliteration, "Artist transliteration", true, EditMode_Practice, true, true, 0, NULL ),
- MenuRowDef( ScreenEdit::last_beat_hint, "Last beat hint", true, EditMode_Full, true, true, 0, NULL ),
+ MenuRowDef( ScreenEdit::last_second_hint, "Last second hint", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::preview_start, "Preview Start", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::preview_length, "Preview Length", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::display_bpm, "Display BPM", true, EditMode_Full, true, true, 0, "Actual", "Specified", "Random" ),
@@ -2127,7 +2127,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
if (index >= 0)
{
- const RString sDuration = ssprintf( "%.5f", attacks[index].fSecsRemaining );
+ const RString sDuration = ssprintf( "%.6f", attacks[index].fSecsRemaining );
g_InsertCourseAttack.rows[remove].bEnabled = true;
if( g_InsertCourseAttack.rows[duration].choices.size() == 9 )
@@ -2158,7 +2158,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
if( iAttack >= 0 )
{
- const RString sDuration = ssprintf( "%.5f", ce.attacks[iAttack].fSecsRemaining );
+ const RString sDuration = ssprintf( "%.6f", ce.attacks[iAttack].fSecsRemaining );
g_InsertCourseAttack.rows[remove].bEnabled = true;
if( g_InsertCourseAttack.rows[duration].choices.size() == 9 )
@@ -3426,13 +3426,19 @@ static void ChangeArtistTranslit( const RString &sNew )
static void ChangeBeat0Offset( const RString &sNew )
{
- TimingData &timing = GAMESTATE->m_bIsUsingStepTiming ? GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing : GAMESTATE->m_pCurSong->m_SongTiming;
+ TimingData &timing = (GAMESTATE->m_bIsUsingStepTiming ?
+ GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing :
+ GAMESTATE->m_pCurSong->m_SongTiming);
timing.m_fBeat0OffsetInSeconds = StringToFloat( sNew );
}
-static void ChangeLastBeatHint( const RString &sNew )
+static void ChangeLastSecondHint( const RString &sNew )
{
- GAMESTATE->m_pCurSong->m_fSpecifiedLastBeat = StringToFloat( sNew );
+ Song &s = *GAMESTATE->m_pCurSong;
+ TimingData &timing = (GAMESTATE->m_bIsUsingStepTiming ?
+ GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing :
+ s.m_SongTiming);
+ s.specifiedLastSecond = StringToFloat(sNew);
}
static void ChangePreviewStart( const RString &sNew )
@@ -3507,23 +3513,23 @@ void ScreenEdit::DisplayTimingMenu()
TimingData &pTime = GetAppropriateTiming();
bool bHasSpeedOnThisRow = pTime.GetSpeedSegmentAtBeat( fBeat ).GetBeat() == fBeat;
- g_TimingDataInformation.rows[beat_0_offset].SetOneUnthemedChoice( ssprintf("%.5f", pTime.m_fBeat0OffsetInSeconds) );
- g_TimingDataInformation.rows[bpm].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetBPMAtBeat( fBeat ) ) );
- g_TimingDataInformation.rows[stop].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetStopAtBeat( fBeat ) ) ) ;
- g_TimingDataInformation.rows[delay].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetDelayAtBeat( fBeat ) ) );
+ g_TimingDataInformation.rows[beat_0_offset].SetOneUnthemedChoice( ssprintf("%.6f", pTime.m_fBeat0OffsetInSeconds) );
+ g_TimingDataInformation.rows[bpm].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetBPMAtBeat( fBeat ) ) );
+ g_TimingDataInformation.rows[stop].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetStopAtBeat( fBeat ) ) ) ;
+ g_TimingDataInformation.rows[delay].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetDelayAtBeat( fBeat ) ) );
g_TimingDataInformation.rows[time_signature].SetOneUnthemedChoice( ssprintf("%d / %d", pTime.GetTimeSignatureNumeratorAtBeat( fBeat ), pTime.GetTimeSignatureDenominatorAtBeat( fBeat ) ) );
g_TimingDataInformation.rows[label].SetOneUnthemedChoice( pTime.GetLabelAtBeat( fBeat ).c_str() );
g_TimingDataInformation.rows[tickcount].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTickcountAtBeat( fBeat ) ) );
g_TimingDataInformation.rows[combo].SetOneUnthemedChoice( ssprintf("%d", pTime.GetComboAtBeat( fBeat ) ) );
- g_TimingDataInformation.rows[warp].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetWarpAtBeat( fBeat ) ) );
- g_TimingDataInformation.rows[speed_percent].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.5f", pTime.GetSpeedPercentAtBeat( fBeat ) ) : "---" );
- g_TimingDataInformation.rows[speed_wait].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.5f", pTime.GetSpeedWaitAtBeat( fBeat ) ) : "---" );
+ g_TimingDataInformation.rows[warp].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetWarpAtBeat( fBeat ) ) );
+ g_TimingDataInformation.rows[speed_percent].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.6f", pTime.GetSpeedPercentAtBeat( fBeat ) ) : "---" );
+ g_TimingDataInformation.rows[speed_wait].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.6f", pTime.GetSpeedWaitAtBeat( fBeat ) ) : "---" );
RString starting = ( pTime.GetSpeedModeAtBeat( fBeat ) == 1 ? "Seconds" : "Beats" );
g_TimingDataInformation.rows[speed_mode].SetOneUnthemedChoice( starting.c_str() );
- g_TimingDataInformation.rows[scroll].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetScrollAtBeat( fBeat ) ) );
- g_TimingDataInformation.rows[fake].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetFakeAtBeat( fBeat ) ) );
+ g_TimingDataInformation.rows[scroll].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetScrollAtBeat( fBeat ) ) );
+ g_TimingDataInformation.rows[fake].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetFakeAtBeat( fBeat ) ) );
g_TimingDataInformation.rows[tickcount].bEnabled = GAMESTATE->m_bIsUsingStepTiming;
g_TimingDataInformation.rows[combo].bEnabled = GAMESTATE->m_bIsUsingStepTiming;
@@ -3733,12 +3739,12 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns
g_SongInformation.rows[main_title_transliteration].SetOneUnthemedChoice( pSong->m_sMainTitleTranslit );
g_SongInformation.rows[sub_title_transliteration].SetOneUnthemedChoice( pSong->m_sSubTitleTranslit );
g_SongInformation.rows[artist_transliteration].SetOneUnthemedChoice( pSong->m_sArtistTranslit );
- g_SongInformation.rows[last_beat_hint].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fSpecifiedLastBeat) );
- g_SongInformation.rows[preview_start].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fMusicSampleStartSeconds) );
- g_SongInformation.rows[preview_length].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fMusicSampleLengthSeconds) );
+ g_SongInformation.rows[last_second_hint].SetOneUnthemedChoice( ssprintf("%.6f", pSong->specifiedLastSecond) );
+ g_SongInformation.rows[preview_start].SetOneUnthemedChoice( ssprintf("%.6f", pSong->m_fMusicSampleStartSeconds) );
+ g_SongInformation.rows[preview_length].SetOneUnthemedChoice( ssprintf("%.6f", pSong->m_fMusicSampleLengthSeconds) );
g_SongInformation.rows[display_bpm].iDefaultChoice = pSong->m_DisplayBPMType;
- g_SongInformation.rows[min_bpm].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fSpecifiedBPMMin) );
- g_SongInformation.rows[max_bpm].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fSpecifiedBPMMax) );
+ g_SongInformation.rows[min_bpm].SetOneUnthemedChoice( ssprintf("%.6f", pSong->m_fSpecifiedBPMMin) );
+ g_SongInformation.rows[max_bpm].SetOneUnthemedChoice( ssprintf("%.6f", pSong->m_fSpecifiedBPMMax) );
EditMiniMenu( &g_SongInformation, SM_BackFromSongInformation );
}
@@ -4206,7 +4212,7 @@ static LocalizedString ENTER_CREDIT ("ScreenEdit","Enter a new credit.");
static LocalizedString ENTER_MAIN_TITLE_TRANSLIT ("ScreenEdit","Enter a new main title transliteration.");
static LocalizedString ENTER_SUB_TITLE_TRANSLIT ("ScreenEdit","Enter a new sub title transliteration.");
static LocalizedString ENTER_ARTIST_TRANSLIT ("ScreenEdit","Enter a new artist transliteration.");
-static LocalizedString ENTER_LAST_BEAT_HINT ("ScreenEdit","Enter a new last beat hint.");
+static LocalizedString ENTER_LAST_SECOND_HINT ("ScreenEdit","Enter a new last second hint.");
static LocalizedString ENTER_PREVIEW_START ("ScreenEdit","Enter a new preview start.");
static LocalizedString ENTER_PREVIEW_LENGTH ("ScreenEdit","Enter a new preview length.");
static LocalizedString ENTER_MIN_BPM ("ScreenEdit","Enter a new min BPM.");
@@ -4242,29 +4248,29 @@ void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vec
case artist_transliteration:
ScreenTextEntry::TextEntry( SM_None, ENTER_ARTIST_TRANSLIT, pSong->m_sArtistTranslit, 100, NULL, ChangeArtistTranslit, NULL );
break;
- case last_beat_hint:
- ScreenTextEntry::TextEntry( SM_None, ENTER_LAST_BEAT_HINT,
- ssprintf("%.5f", pSong->m_fSpecifiedLastBeat), 20,
- ScreenTextEntry::FloatValidate, ChangeLastBeatHint, NULL );
+ case last_second_hint:
+ ScreenTextEntry::TextEntry( SM_None, ENTER_LAST_SECOND_HINT,
+ ssprintf("%.6f", pSong->specifiedLastSecond), 20,
+ ScreenTextEntry::FloatValidate, ChangeLastSecondHint, NULL );
break;
case preview_start:
ScreenTextEntry::TextEntry( SM_None, ENTER_PREVIEW_START,
- ssprintf("%.5f", pSong->m_fMusicSampleStartSeconds), 20,
+ ssprintf("%.6f", pSong->m_fMusicSampleStartSeconds), 20,
ScreenTextEntry::FloatValidate, ChangePreviewStart, NULL );
break;
case preview_length:
ScreenTextEntry::TextEntry( SM_None, ENTER_PREVIEW_LENGTH,
- ssprintf("%.5f", pSong->m_fMusicSampleLengthSeconds), 20,
+ ssprintf("%.6f", pSong->m_fMusicSampleLengthSeconds), 20,
ScreenTextEntry::FloatValidate, ChangePreviewLength, NULL );
break;
case min_bpm:
ScreenTextEntry::TextEntry( SM_None, ENTER_MIN_BPM,
- ssprintf("%.5f", pSong->m_fSpecifiedBPMMin), 20,
+ ssprintf("%.6f", pSong->m_fSpecifiedBPMMin), 20,
ScreenTextEntry::FloatValidate, ChangeMinBPM, NULL );
break;
case max_bpm:
ScreenTextEntry::TextEntry( SM_None, ENTER_MAX_BPM,
- ssprintf("%.5f", pSong->m_fSpecifiedBPMMax), 20,
+ ssprintf("%.6f", pSong->m_fSpecifiedBPMMax), 20,
ScreenTextEntry::FloatValidate, ChangeMaxBPM, NULL );
break;
};
@@ -4293,7 +4299,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
DEFAULT_FAIL( c );
case beat_0_offset:
ScreenTextEntry::TextEntry( SM_None, ENTER_BEAT_0_OFFSET,
- ssprintf("%.5f", GetAppropriateTiming().m_fBeat0OffsetInSeconds), 20,
+ ssprintf("%.6f", GetAppropriateTiming().m_fBeat0OffsetInSeconds), 20,
ScreenTextEntry::FloatValidate, ChangeBeat0Offset, NULL );
break;
case bpm:
@@ -4359,7 +4365,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
ScreenTextEntry::TextEntry(
SM_BackFromWarpChange,
ENTER_WARP_VALUE,
- ssprintf( "%.4f", GetAppropriateTiming().GetWarpAtBeat( GetBeat() ) ),
+ ssprintf( "%.6f", GetAppropriateTiming().GetWarpAtBeat( GetBeat() ) ),
10
);
break;
@@ -4367,7 +4373,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
ScreenTextEntry::TextEntry(
SM_BackFromSpeedPercentChange,
ENTER_SPEED_PERCENT_VALUE,
- ssprintf( "%.5f", GetAppropriateTiming().GetSpeedSegmentAtBeat( GetBeat() ).GetRatio() ),
+ ssprintf( "%.6f", GetAppropriateTiming().GetSpeedSegmentAtBeat( GetBeat() ).GetRatio() ),
10
);
break;
@@ -4375,7 +4381,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
ScreenTextEntry::TextEntry(
SM_BackFromScrollChange,
ENTER_SCROLL_VALUE,
- ssprintf( "%.5f", GetAppropriateTiming().GetScrollSegmentAtBeat( GetBeat() ).GetRatio() ),
+ ssprintf( "%.6f", GetAppropriateTiming().GetScrollSegmentAtBeat( GetBeat() ).GetRatio() ),
10
);
break;
@@ -4383,7 +4389,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
ScreenTextEntry::TextEntry(
SM_BackFromSpeedWaitChange,
ENTER_SPEED_WAIT_VALUE,
- ssprintf( "%.5f", GetAppropriateTiming().GetSpeedSegmentAtBeat( GetBeat() ).GetLength() ),
+ ssprintf( "%.6f", GetAppropriateTiming().GetSpeedSegmentAtBeat( GetBeat() ).GetLength() ),
10
);
break;
@@ -4403,7 +4409,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
ScreenTextEntry::TextEntry(
SM_BackFromFakeChange,
ENTER_FAKE_VALUE,
- ssprintf("%.5f", GetAppropriateTiming().GetFakeAtBeat( GetBeat() ) ),
+ ssprintf("%.6f", GetAppropriateTiming().GetFakeAtBeat( GetBeat() ) ),
10
);
break;
@@ -4701,14 +4707,15 @@ float ScreenEdit::GetMaximumBeatForNewNote() const
case EditMode_CourseMods:
case EditMode_Home:
{
- float fEndBeat = GAMESTATE->m_pCurSong->m_fLastBeat;
+ Song &s = *GAMESTATE->m_pCurSong;
+ TimingData &timing = s.m_SongTiming;
+ float fEndBeat = timing.GetBeatFromElapsedTime(s.lastSecond);
/* Round up to the next measure end. Some songs end on weird beats
* mid-measure, and it's odd to have movement capped to these weird
* beats. */
- TimingData &songTiming = GAMESTATE->m_pCurSong->m_SongTiming;
float playerBeat = GetAppropriatePosition().m_fSongBeat;
- int beatsPerMeasure = songTiming.GetTimeSignatureSegmentAtBeat( playerBeat ).GetNum();
+ int beatsPerMeasure = timing.GetTimeSignatureSegmentAtBeat( playerBeat ).GetNum();
fEndBeat += beatsPerMeasure;
fEndBeat = ftruncf( fEndBeat, (float)beatsPerMeasure );
@@ -4723,7 +4730,7 @@ float ScreenEdit::GetMaximumBeatForMoving() const
{
float fEndBeat = GetMaximumBeatForNewNote();
- /* Jump to GetLastBeat even if it's past m_pCurSong->m_fLastBeat
+ /* Jump to GetLastBeat even if it's past the song's last beat
* so that users can delete garbage steps past then end that they have
* have inserted in a text editor. Once they delete all steps on
* GetLastBeat() and move off of that beat, they won't be able to return. */
diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h
index 255cf2b425..e75a4a854f 100644
--- a/src/ScreenEdit.h
+++ b/src/ScreenEdit.h
@@ -529,7 +529,7 @@ public:
main_title_transliteration,
sub_title_transliteration,
artist_transliteration,
- last_beat_hint,
+ last_second_hint,
preview_start,
preview_length,
display_bpm,
diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp
index 475ca16250..5379530502 100644
--- a/src/ScreenGameplay.cpp
+++ b/src/ScreenGameplay.cpp
@@ -1329,8 +1329,7 @@ void ScreenGameplay::StartPlayingSong( float fMinTimeToNotes, float fMinTimeToMu
p.StopMode = RageSoundParams::M_CONTINUE;
{
- const float fFirstBeat = GAMESTATE->m_pCurSong->m_fFirstBeat;
- const float fFirstSecond = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( fFirstBeat );
+ const float fFirstSecond = GAMESTATE->m_pCurSong->firstSecond;
float fStartDelay = fMinTimeToNotes - fFirstSecond;
fStartDelay = max( fStartDelay, fMinTimeToMusic );
p.m_StartSecond = -fStartDelay;
@@ -1412,8 +1411,9 @@ void ScreenGameplay::PlayAnnouncer( RString type, float fSeconds )
/* Don't play before the first beat, or after we're finished. */
if( m_DancingState != STATE_DANCING )
return;
- if( GAMESTATE->m_pCurSong == NULL || // this will be true on ScreenDemonstration sometimes
- GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat )
+ if(GAMESTATE->m_pCurSong == NULL || // this will be true on ScreenDemonstration sometimes
+ GAMESTATE->m_Position.m_fSongBeat <
+ GAMESTATE->m_pCurSong->m_SongTiming.GetBeatFromElapsedTime(GAMESTATE->m_pCurSong->firstSecond) )
return;
if( m_fTimeSinceLastDancingComment < fSeconds )
@@ -1488,7 +1488,7 @@ bool ScreenGameplay::AllAreFailing()
void ScreenGameplay::GetMusicEndTiming( float &fSecondsToStartFadingOutMusic, float &fSecondsToStartTransitioningOut )
{
- float fLastStepSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat );
+ float fLastStepSeconds = GAMESTATE->m_pCurSong->lastSecond;
fLastStepSeconds += Player::GetMaxStepDistanceSeconds();
float fTransitionLength;
@@ -1697,7 +1697,11 @@ void ScreenGameplay::Update( float fDeltaTime )
// update fGameplaySeconds
STATSMAN->m_CurStageStats.m_fGameplaySeconds += fUnscaledDeltaTime;
float curBeat = GAMESTATE->m_Position.m_fSongBeat;
- if( curBeat >= GAMESTATE->m_pCurSong->m_fFirstBeat && curBeat < GAMESTATE->m_pCurSong->m_fLastBeat )
+ Song &s = *GAMESTATE->m_pCurSong;
+ TimingData &timing = s.m_SongTiming;
+
+
+ if( curBeat >= timing.GetBeatFromElapsedTime(s.firstSecond) && curBeat < timing.GetBeatFromElapsedTime(s.lastSecond) )
{
STATSMAN->m_CurStageStats.m_fStepsSeconds += fUnscaledDeltaTime;
@@ -1978,7 +1982,8 @@ void ScreenGameplay::UpdateLights()
}
// Before the first beat of the song, all cabinet lights solid on (except for menu buttons).
- bool bOverrideCabinetBlink = (GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat);
+ Song &s = *GAMESTATE->m_pCurSong;
+ bool bOverrideCabinetBlink = (GAMESTATE->m_Position.m_fSongBeat < s.m_SongTiming.GetBeatFromElapsedTime(s.firstSecond));
FOREACH_CabinetLight( cl )
bBlinkCabinetLight[cl] |= bOverrideCabinetBlink;
diff --git a/src/Song.cpp b/src/Song.cpp
index 750605658e..5ac5a64554 100644
--- a/src/Song.cpp
+++ b/src/Song.cpp
@@ -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 = 185;
+const int FILE_CACHE_VERSION = 186;
/** @brief How long does a song sample last by default? */
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
@@ -511,7 +511,8 @@ void Song::TidyUpData( bool bFromCache )
if( m_fMusicSampleStartSeconds+m_fMusicSampleLengthSeconds > this->m_fMusicLengthSeconds )
{
- int iBeat = lrintf( m_fLastBeat/2 );
+ // Attempt to get a reasonable default.
+ int iBeat = lrintf(this->m_SongTiming.GetBeatFromElapsedTime(this->lastSecond)/2);
iBeat -= iBeat%4;
m_fMusicSampleStartSeconds = timing.GetElapsedTimeFromBeat( (float)iBeat );
}
@@ -800,7 +801,7 @@ void Song::TranslateTitles()
void Song::ReCalculateRadarValuesAndLastBeat( bool bFromCache )
{
- if( bFromCache && m_fFirstBeat >= 0 && m_fLastBeat > 0 )
+ if( bFromCache && this->firstSecond >= 0 && this->lastSecond > 0 )
{
// this is loaded from cache, then we just have to calculate the radar values.
for( unsigned i=0; ispecifiedLastSecond; // Make sure we're at least as long as the specified amount.
for( unsigned i=0; iCalculateRadarValues( m_fMusicLengthSeconds );
- // calculate lastBeat
+ // calculate lastSecond
// If it's autogen, then first/last beat will come from the parent.
if( pSteps->IsAutogen() )
@@ -842,12 +843,14 @@ void Song::ReCalculateRadarValuesAndLastBeat( bool bFromCache )
if( tempNoteData.GetLastRow() == 0 )
continue;
- fFirstBeat = min( fFirstBeat, m_SongTiming.GetBeatFromElapsedTime(pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetFirstBeat())) );
- fLastBeat = max( fLastBeat, m_SongTiming.GetBeatFromElapsedTime(pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetLastBeat())) );
+ localFirst = min(localFirst,
+ pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetFirstBeat()));
+ localLast = max(localLast,
+ pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetLastBeat()));
}
- m_fFirstBeat = fFirstBeat;
- m_fLastBeat = fLastBeat;
+ this->firstSecond = localFirst;
+ this->lastSecond = localLast;
}
// Return whether the song is playable in the given style.
@@ -1461,8 +1464,7 @@ bool Song::HasSignificantBpmChangesOrStops() const
float Song::GetStepsSeconds() const
{
- const TimingData &timing = this->m_SongTiming;
- return timing.GetElapsedTimeFromBeat( m_fLastBeat ) - timing.GetElapsedTimeFromBeat( m_fFirstBeat );
+ return this->lastSecond - this->firstSecond;
}
bool Song::IsLong() const
@@ -1579,8 +1581,26 @@ public:
}
static int GetStepsSeconds( T* p, lua_State *L ) { lua_pushnumber(L, p->GetStepsSeconds()); return 1; }
static int NormallyDisplayed( T* p, lua_State *L ){ lua_pushboolean(L, p->NormallyDisplayed()); return 1; }
- static int GetFirstBeat( T* p, lua_State *L ) { lua_pushnumber(L, p->m_fFirstBeat); return 1; }
- static int GetLastBeat( T* p, lua_State *L ) { lua_pushnumber(L, p->m_fLastBeat); return 1; }
+ static int GetFirstSecond(T* p, lua_State *L)
+ {
+ lua_pushnumber(L, p->firstSecond);
+ return 1;
+ }
+ static int GetLastSecond(T* p, lua_State *L)
+ {
+ lua_pushnumber(L, p->lastSecond);
+ return 1;
+ }
+ static int GetFirstBeat( T* p, lua_State *L )
+ {
+ lua_pushnumber(L, p->m_SongTiming.GetBeatFromElapsedTime(p->firstSecond));
+ return 1;
+ }
+ static int GetLastBeat( T* p, lua_State *L )
+ {
+ lua_pushnumber(L, p->m_SongTiming.GetBeatFromElapsedTime(p->lastSecond));
+ return 1;
+ }
static int HasAttacks( T* p, lua_State *L ) { lua_pushboolean(L, p->HasAttacks()); return 1; }
static int GetDisplayBpms( T* p, lua_State *L )
{
@@ -1657,7 +1677,9 @@ public:
ADD_METHOD( GetStepsSeconds );
ADD_METHOD( NormallyDisplayed );
ADD_METHOD( GetFirstBeat );
+ ADD_METHOD( GetFirstSecond );
ADD_METHOD( GetLastBeat );
+ ADD_METHOD( GetLastSecond );
ADD_METHOD( HasAttacks );
ADD_METHOD( GetDisplayBpms );
ADD_METHOD( IsDisplayBpmSecret );
diff --git a/src/Song.h b/src/Song.h
index 95dd3b1a6e..d661347db1 100644
--- a/src/Song.h
+++ b/src/Song.h
@@ -20,7 +20,7 @@ void FixupPath( RString &path, const RString &sSongPath );
RString GetSongAssetPath( RString sPath, const RString &sSongPath );
/** @brief The version of the .ssc file format. */
-const static float STEPFILE_VERSION_NUMBER = 0.72f;
+const static float STEPFILE_VERSION_NUMBER = 0.73f;
/** @brief How many edits for this song can each profile have? */
const int MAX_EDITS_PER_SONG_PER_PROFILE = 15;