Mission accomplished: [warps] are in default.
Let the fun times roll!
This commit is contained in:
@@ -72,6 +72,7 @@ Data/SpeedMods.txt
|
|||||||
Program/StepMania*.lib
|
Program/StepMania*.lib
|
||||||
crashinfo.txt
|
crashinfo.txt
|
||||||
Utils/temp*
|
Utils/temp*
|
||||||
|
*.lnk
|
||||||
|
|
||||||
syntax: regexp
|
syntax: regexp
|
||||||
.*\#.*\#$
|
.*\#.*\#$
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ change to JSON, but it is unsure if this will be done.
|
|||||||
Implement .ssc at your own risk.
|
Implement .ssc at your own risk.
|
||||||
________________________________________________________________________________
|
________________________________________________________________________________
|
||||||
|
|
||||||
|
[v0.66] - Wolfman2000
|
||||||
|
* Implement #WARPS tag to replace negative bpm/stop gimmicks.
|
||||||
|
|
||||||
[v0.55] - Wolfman2000
|
[v0.55] - Wolfman2000
|
||||||
* Add #COMBOS tag to the Song and Steps (does nothing here).
|
* Add #COMBOS tag to the Song and Steps (does nothing here).
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ _____________________________________________________________________________
|
|||||||
sm-ssc v1.2.4 | 2011032?
|
sm-ssc v1.2.4 | 2011032?
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
20110326
|
||||||
|
--------
|
||||||
|
* [NotesLoaderSM, NotesWriterSSC] Officially add the #WARPS tag. The negative
|
||||||
|
tricks of the past are now officially standardized. Please tell us about
|
||||||
|
files which have broken sync or are otherwise unplayable/incorrect.
|
||||||
|
[AJ, Thai, Wolfman2000]
|
||||||
|
|
||||||
20110320
|
20110320
|
||||||
--------
|
--------
|
||||||
* [PlayerOptions] Added SetNoteSkin(string) Lua binding. [AJ]
|
* [PlayerOptions] Added SetNoteSkin(string) Lua binding. [AJ]
|
||||||
|
|||||||
@@ -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 time signature (bottom)=Edit time signature (single beat note value)
|
||||||
Edit tickcount=Edit tickcount
|
Edit tickcount=Edit tickcount
|
||||||
Edit combo=Edit combo
|
Edit combo=Edit combo
|
||||||
|
Edit warp=Edit warp
|
||||||
Editor options=Options
|
Editor options=Options
|
||||||
EditorShowBGChangesPlay=Show Backgrounds
|
EditorShowBGChangesPlay=Show Backgrounds
|
||||||
Effect=Effect
|
Effect=Effect
|
||||||
@@ -1209,6 +1210,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 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 Tickcount value.=Enter a new Tickcount value.
|
||||||
Enter a new Combo value.=Enter a new Combo value.
|
Enter a new Combo value.=Enter a new Combo value.
|
||||||
|
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 transliteration.=Enter a new artist transliteration.
|
||||||
Enter a new artist.=Enter a new artist.
|
Enter a new artist.=Enter a new artist.
|
||||||
Enter a new genre.=Enter a new genre.
|
Enter a new genre.=Enter a new genre.
|
||||||
|
|||||||
@@ -963,6 +963,7 @@ RoutineNoteSkinP2=RoutineSkinP2()
|
|||||||
BPMColor=color("1,0,0,1")
|
BPMColor=color("1,0,0,1")
|
||||||
StopColor=color("0.8,0.8,0,1")
|
StopColor=color("0.8,0.8,0,1")
|
||||||
DelayColor=color("0,0.8,0.8,1")
|
DelayColor=color("0,0.8,0.8,1")
|
||||||
|
WarpColor=color("1,0,0.5,1")
|
||||||
TimeSignatureColor=color("1,0.55,0,1")
|
TimeSignatureColor=color("1,0.55,0,1")
|
||||||
TickcountColor=color("0,1,0,1")
|
TickcountColor=color("0,1,0,1")
|
||||||
ComboColor=color("0.55,1,0,1")
|
ComboColor=color("0.55,1,0,1")
|
||||||
@@ -970,13 +971,15 @@ ComboColor=color("0.55,1,0,1")
|
|||||||
BPMIsLeftSide=true
|
BPMIsLeftSide=true
|
||||||
StopIsLeftSide=true
|
StopIsLeftSide=true
|
||||||
DelayIsLeftSide=true
|
DelayIsLeftSide=true
|
||||||
|
WarpIsLeftSide=false
|
||||||
TimeSignatureIsLeftSide=true
|
TimeSignatureIsLeftSide=true
|
||||||
TickcountIsLeftSide=false
|
TickcountIsLeftSide=false
|
||||||
ComboIsLeftSide=false
|
ComboIsLeftSide=false
|
||||||
#
|
#
|
||||||
BPMOffsetX=60
|
BPMOffsetX=60
|
||||||
StopOffsetX=10
|
StopOffsetX=50
|
||||||
DelayOffsetX=10
|
DelayOffsetX=120
|
||||||
|
WarpOffsetX=60
|
||||||
TimeSignatureOffsetX=30
|
TimeSignatureOffsetX=30
|
||||||
TickcountOffsetX=10
|
TickcountOffsetX=10
|
||||||
ComboOffsetX=30
|
ComboOffsetX=30
|
||||||
|
|||||||
+3
-11
@@ -897,7 +897,7 @@ void GameState::ResetMusicStatistics()
|
|||||||
m_bFreeze = false;
|
m_bFreeze = false;
|
||||||
m_bDelay = false;
|
m_bDelay = false;
|
||||||
m_iWarpBeginRow = -1; // Set to -1 because some song may want to warp to row 0. -aj
|
m_iWarpBeginRow = -1; // Set to -1 because some song may want to warp to row 0. -aj
|
||||||
m_fWarpLength = -1; // Set when a warp is encountered. also see above. -aj
|
m_fWarpDestination = -1; // Set when a warp is encountered. also see above. -aj
|
||||||
m_fMusicSecondsVisible = 0;
|
m_fMusicSecondsVisible = 0;
|
||||||
m_fSongBeatVisible = 0;
|
m_fSongBeatVisible = 0;
|
||||||
Actor::SetBGMTime( 0, 0, 0, 0 );
|
Actor::SetBGMTime( 0, 0, 0, 0 );
|
||||||
@@ -943,7 +943,7 @@ void GameState::ResetStageStatistics()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Preference<float> g_fVisualDelaySeconds( "VisualDelaySeconds", 0.0f );
|
static Preference<float> g_fVisualDelaySeconds( "VisualDelaySeconds", 0.0f );
|
||||||
// todo: modify for warps -aj
|
|
||||||
void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp )
|
void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &timing, const RageTimer ×tamp )
|
||||||
{
|
{
|
||||||
if( !timestamp.IsZero() )
|
if( !timestamp.IsZero() )
|
||||||
@@ -957,18 +957,10 @@ void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &ti
|
|||||||
LOG->Trace( ssprintf("[GameState::UpdateSongPosition] cur BPS = %f, fPositionSeconds = %f",m_fCurBPS,fPositionSeconds) );
|
LOG->Trace( ssprintf("[GameState::UpdateSongPosition] cur BPS = %f, fPositionSeconds = %f",m_fCurBPS,fPositionSeconds) );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
timing.GetBeatAndBPSFromElapsedTime( fPositionSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze, m_bDelay, m_iWarpBeginRow, m_fWarpLength );
|
timing.GetBeatAndBPSFromElapsedTime( fPositionSeconds, m_fSongBeat, m_fCurBPS, m_bFreeze, m_bDelay, m_iWarpBeginRow, m_fWarpDestination );
|
||||||
// "Crash reason : -243478.890625 -48695.773438"
|
// "Crash reason : -243478.890625 -48695.773438"
|
||||||
ASSERT_M( m_fSongBeat > -2000, ssprintf("Song beat %f at %f seconds", m_fSongBeat, fPositionSeconds) );
|
ASSERT_M( m_fSongBeat > -2000, ssprintf("Song beat %f at %f seconds", m_fSongBeat, fPositionSeconds) );
|
||||||
|
|
||||||
//if( m_iWarpBeginRow != -1 || m_iWarpEndRow == -1 )
|
|
||||||
if( m_iWarpBeginRow != -1 && m_fWarpLength > 0.0f )
|
|
||||||
{
|
|
||||||
// There is a warp in this section.
|
|
||||||
LOG->Trace("warp at %i lasts for %f, jumps to %i",m_iWarpBeginRow,m_fWarpLength,m_iWarpBeginRow+BeatToNoteRow(m_fWarpLength));
|
|
||||||
//fPositionSeconds += (m_fWarpLength * m_fCurBPS);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_fMusicSeconds = fPositionSeconds;
|
m_fMusicSeconds = fPositionSeconds;
|
||||||
|
|
||||||
m_fLightSongBeat = timing.GetBeatFromElapsedTime( fPositionSeconds + g_fLightsAheadSeconds );
|
m_fLightSongBeat = timing.GetBeatFromElapsedTime( fPositionSeconds + g_fLightsAheadSeconds );
|
||||||
|
|||||||
+3
-2
@@ -208,9 +208,10 @@ public:
|
|||||||
bool m_bFreeze;
|
bool m_bFreeze;
|
||||||
/** @brief A flag to determine if we're in the middle of a delay (Pump style stop). */
|
/** @brief A flag to determine if we're in the middle of a delay (Pump style stop). */
|
||||||
bool m_bDelay;
|
bool m_bDelay;
|
||||||
// used for warping:
|
/** @brief The row used to start a warp. */
|
||||||
int m_iWarpBeginRow;
|
int m_iWarpBeginRow;
|
||||||
float m_fWarpLength;
|
/** @brief The beat to warp to afterwards. */
|
||||||
|
float m_fWarpDestination;
|
||||||
RageTimer m_LastBeatUpdate; // time of last m_fSongBeat, etc. update
|
RageTimer m_LastBeatUpdate; // time of last m_fSongBeat, etc. update
|
||||||
BroadcastOnChange<bool> m_bGameplayLeadIn;
|
BroadcastOnChange<bool> m_bGameplayLeadIn;
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -864,8 +864,8 @@ void LuaHelpers::ParseCommandList( Lua *L, const RString &sCommands, const RStri
|
|||||||
FOREACH_CONST( Command, cmds.v, c )
|
FOREACH_CONST( Command, cmds.v, c )
|
||||||
{
|
{
|
||||||
const Command& cmd = (*c);
|
const Command& cmd = (*c);
|
||||||
RString sName = cmd.GetName();
|
RString local_sName = cmd.GetName();
|
||||||
s << "\tself:" << sName << "(";
|
s << "\tself:" << local_sName << "(";
|
||||||
|
|
||||||
for( unsigned i=1; i<cmd.m_vsArgs.size(); i++ )
|
for( unsigned i=1; i<cmd.m_vsArgs.size(); i++ )
|
||||||
{
|
{
|
||||||
@@ -877,10 +877,10 @@ void LuaHelpers::ParseCommandList( Lua *L, const RString &sCommands, const RStri
|
|||||||
|
|
||||||
if( sArg[0] == '#' ) // HTML color
|
if( sArg[0] == '#' ) // HTML color
|
||||||
{
|
{
|
||||||
RageColor c; // in case FromString fails
|
RageColor col; // in case FromString fails
|
||||||
c.FromString( sArg );
|
col.FromString( sArg );
|
||||||
// c is still valid if FromString fails
|
// col is still valid if FromString fails
|
||||||
s << c.r << "," << c.g << "," << c.b << "," << c.a;
|
s << col.r << "," << col.g << "," << col.b << "," << col.a;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+33
-2
@@ -422,18 +422,21 @@ void NoteField::DrawAreaHighlight( int iStartBeat, int iEndBeat )
|
|||||||
static ThemeMetric<RageColor> BPM_COLOR ( "NoteField", "BPMColor" );
|
static ThemeMetric<RageColor> BPM_COLOR ( "NoteField", "BPMColor" );
|
||||||
static ThemeMetric<RageColor> STOP_COLOR ( "NoteField", "StopColor" );
|
static ThemeMetric<RageColor> STOP_COLOR ( "NoteField", "StopColor" );
|
||||||
static ThemeMetric<RageColor> DELAY_COLOR ( "NoteField", "DelayColor" );
|
static ThemeMetric<RageColor> DELAY_COLOR ( "NoteField", "DelayColor" );
|
||||||
|
static ThemeMetric<RageColor> WARP_COLOR ( "NoteField", "WarpColor" );
|
||||||
static ThemeMetric<RageColor> TIME_SIGNATURE_COLOR ( "NoteField", "TimeSignatureColor" );
|
static ThemeMetric<RageColor> TIME_SIGNATURE_COLOR ( "NoteField", "TimeSignatureColor" );
|
||||||
static ThemeMetric<RageColor> TICKCOUNT_COLOR ( "NoteField", "TickcountColor" );
|
static ThemeMetric<RageColor> TICKCOUNT_COLOR ( "NoteField", "TickcountColor" );
|
||||||
static ThemeMetric<RageColor> COMBO_COLOR ( "NoteField", "ComboColor" );
|
static ThemeMetric<RageColor> COMBO_COLOR ( "NoteField", "ComboColor" );
|
||||||
static ThemeMetric<bool> BPM_IS_LEFT_SIDE ( "NoteField", "BPMIsLeftSide" );
|
static ThemeMetric<bool> BPM_IS_LEFT_SIDE ( "NoteField", "BPMIsLeftSide" );
|
||||||
static ThemeMetric<bool> STOP_IS_LEFT_SIDE ( "NoteField", "StopIsLeftSide" );
|
static ThemeMetric<bool> STOP_IS_LEFT_SIDE ( "NoteField", "StopIsLeftSide" );
|
||||||
static ThemeMetric<bool> DELAY_IS_LEFT_SIDE ( "NoteField", "DelayIsLeftSide" );
|
static ThemeMetric<bool> DELAY_IS_LEFT_SIDE ( "NoteField", "DelayIsLeftSide" );
|
||||||
|
static ThemeMetric<bool> WARP_IS_LEFT_SIDE ( "NoteField", "WarpIsLeftSide" );
|
||||||
static ThemeMetric<bool> TIME_SIGNATURE_IS_LEFT_SIDE ( "NoteField", "TimeSignatureIsLeftSide" );
|
static ThemeMetric<bool> TIME_SIGNATURE_IS_LEFT_SIDE ( "NoteField", "TimeSignatureIsLeftSide" );
|
||||||
static ThemeMetric<bool> TICKCOUNT_IS_LEFT_SIDE ( "NoteField", "TickcountIsLeftSide" );
|
static ThemeMetric<bool> TICKCOUNT_IS_LEFT_SIDE ( "NoteField", "TickcountIsLeftSide" );
|
||||||
static ThemeMetric<bool> COMBO_IS_LEFT_SIDE ( "NoteField", "ComboIsLeftSide" );
|
static ThemeMetric<bool> COMBO_IS_LEFT_SIDE ( "NoteField", "ComboIsLeftSide" );
|
||||||
static ThemeMetric<float> BPM_OFFSETX ( "NoteField", "BPMOffsetX" );
|
static ThemeMetric<float> BPM_OFFSETX ( "NoteField", "BPMOffsetX" );
|
||||||
static ThemeMetric<float> STOP_OFFSETX ( "NoteField", "StopOffsetX" );
|
static ThemeMetric<float> STOP_OFFSETX ( "NoteField", "StopOffsetX" );
|
||||||
static ThemeMetric<float> DELAY_OFFSETX ( "NoteField", "DelayOffsetX" );
|
static ThemeMetric<float> DELAY_OFFSETX ( "NoteField", "DelayOffsetX" );
|
||||||
|
static ThemeMetric<float> WARP_OFFSETX ( "NoteField", "WarpOffsetX" );
|
||||||
static ThemeMetric<float> TIME_SIGNATURE_OFFSETX ( "NoteField", "TimeSignatureOffsetX" );
|
static ThemeMetric<float> TIME_SIGNATURE_OFFSETX ( "NoteField", "TimeSignatureOffsetX" );
|
||||||
static ThemeMetric<float> TICKCOUNT_OFFSETX ( "NoteField", "TickcountOffsetX" );
|
static ThemeMetric<float> TICKCOUNT_OFFSETX ( "NoteField", "TickcountOffsetX" );
|
||||||
static ThemeMetric<float> COMBO_OFFSETX ( "NoteField", "ComboOffsetX" );
|
static ThemeMetric<float> COMBO_OFFSETX ( "NoteField", "ComboOffsetX" );
|
||||||
@@ -481,6 +484,23 @@ void NoteField::DrawFreezeText( const float fBeat, const float fSecs, const floa
|
|||||||
m_textMeasureNumber.Draw();
|
m_textMeasureNumber.Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NoteField::DrawWarpText( const float fBeat, const float fNewBeat )
|
||||||
|
{
|
||||||
|
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 = WARP_OFFSETX * fZoom;
|
||||||
|
|
||||||
|
m_textMeasureNumber.SetZoom( fZoom );
|
||||||
|
m_textMeasureNumber.SetHorizAlign( WARP_IS_LEFT_SIDE ? align_right : align_left );
|
||||||
|
m_textMeasureNumber.SetDiffuse( WARP_COLOR );
|
||||||
|
m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) );
|
||||||
|
m_textMeasureNumber.SetText( ssprintf("%.3f", fNewBeat) );
|
||||||
|
m_textMeasureNumber.SetXY( (WARP_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos );
|
||||||
|
m_textMeasureNumber.Draw();
|
||||||
|
}
|
||||||
|
|
||||||
void NoteField::DrawTimeSignatureText( const float fBeat, int iNumerator, int iDenominator )
|
void NoteField::DrawTimeSignatureText( const float fBeat, int iNumerator, int iDenominator )
|
||||||
{
|
{
|
||||||
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat );
|
||||||
@@ -771,6 +791,19 @@ void NoteField::DrawPrimitives()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warp text
|
||||||
|
const vector<WarpSegment> &aWarpSegments = GAMESTATE->m_pCurSong->m_Timing.m_WarpSegments;
|
||||||
|
for( unsigned i=0; i<aWarpSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
if( aWarpSegments[i].m_iStartRow >= iFirstRowToDraw &&
|
||||||
|
aWarpSegments[i].m_iStartRow <= iLastRowToDraw)
|
||||||
|
{
|
||||||
|
float fBeat = NoteRowToBeat(aWarpSegments[i].m_iStartRow);
|
||||||
|
if( IS_ON_SCREEN(fBeat) )
|
||||||
|
DrawWarpText( fBeat, aWarpSegments[i].m_fEndBeat );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Time Signature text
|
// Time Signature text
|
||||||
const vector<TimeSignatureSegment> &vTimeSignatureSegments = GAMESTATE->m_pCurSong->m_Timing.m_vTimeSignatureSegments;
|
const vector<TimeSignatureSegment> &vTimeSignatureSegments = GAMESTATE->m_pCurSong->m_Timing.m_vTimeSignatureSegments;
|
||||||
for( unsigned i=0; i<vTimeSignatureSegments.size(); i++ )
|
for( unsigned i=0; i<vTimeSignatureSegments.size(); i++ )
|
||||||
@@ -810,8 +843,6 @@ void NoteField::DrawPrimitives()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: add warp text -aj
|
|
||||||
|
|
||||||
// Course mods text
|
// Course mods text
|
||||||
const Course *pCourse = GAMESTATE->m_pCurCourse;
|
const Course *pCourse = GAMESTATE->m_pCurCourse;
|
||||||
if( pCourse )
|
if( pCourse )
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ protected:
|
|||||||
void DrawAreaHighlight( int iStartBeat, int iEndBeat );
|
void DrawAreaHighlight( int iStartBeat, int iEndBeat );
|
||||||
void DrawBPMText( const float fBeat, const float fBPM );
|
void DrawBPMText( const float fBeat, const float fBPM );
|
||||||
void DrawFreezeText( const float fBeat, const float fBPM, const float bDelay );
|
void DrawFreezeText( const float fBeat, const float fBPM, const float bDelay );
|
||||||
|
void DrawWarpText( const float fBeat, const float fNewBeat );
|
||||||
void DrawTimeSignatureText( const float fBeat, int iNumerator, int iDenominator );
|
void DrawTimeSignatureText( const float fBeat, int iNumerator, int iDenominator );
|
||||||
void DrawTickcountText( const float fBeat, int iTicks );
|
void DrawTickcountText( const float fBeat, int iTicks );
|
||||||
void DrawComboText( const float fBeat, int iCombo );
|
void DrawComboText( const float fBeat, int iCombo );
|
||||||
|
|||||||
+115
-162
@@ -12,7 +12,13 @@
|
|||||||
#include "Steps.h"
|
#include "Steps.h"
|
||||||
#include "PrefsManager.h"
|
#include "PrefsManager.h"
|
||||||
|
|
||||||
|
/** @brief The maximum file size for edits. */
|
||||||
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
|
const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB
|
||||||
|
/**
|
||||||
|
* @brief The highest allowable speed before Warps come in.
|
||||||
|
*
|
||||||
|
* This was brought in from StepMania 4's recent betas. */
|
||||||
|
const float FAST_BPM_WARP = 9999999.f;
|
||||||
|
|
||||||
void SMLoader::LoadFromSMTokens(
|
void SMLoader::LoadFromSMTokens(
|
||||||
RString sStepsType,
|
RString sStepsType,
|
||||||
@@ -104,9 +110,6 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
out.m_WarpSegments.clear();
|
out.m_WarpSegments.clear();
|
||||||
out.m_vTimeSignatureSegments.clear();
|
out.m_vTimeSignatureSegments.clear();
|
||||||
|
|
||||||
vector<WarpSegment> arrayWarpsFromNegativeBPMs;
|
|
||||||
//vector<WarpSegment> arrayWarpsFromNegativeStops;
|
|
||||||
|
|
||||||
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
||||||
{
|
{
|
||||||
const MsdFile::value_t &sParams = msd.GetValue(i);
|
const MsdFile::value_t &sParams = msd.GetValue(i);
|
||||||
@@ -117,11 +120,83 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
{
|
{
|
||||||
out.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] );
|
out.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] );
|
||||||
}
|
}
|
||||||
|
else if( sValueName=="BPMS" )
|
||||||
|
{
|
||||||
|
vector<RString> arrayBPMChangeExpressions;
|
||||||
|
split( sParams[1], ",", arrayBPMChangeExpressions );
|
||||||
|
|
||||||
|
// prepare storage variables for negative BPMs -> Warps.
|
||||||
|
float negBeat = -1;
|
||||||
|
float negBPM = 1;
|
||||||
|
float highspeedBeat = -1;
|
||||||
|
|
||||||
|
for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ )
|
||||||
|
{
|
||||||
|
vector<RString> arrayBPMChangeValues;
|
||||||
|
split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues );
|
||||||
|
// XXX: Hard to tell which file caused this.
|
||||||
|
if( arrayBPMChangeValues.size() != 2 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
|
||||||
|
sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float fBeat = StringToFloat( arrayBPMChangeValues[0] );
|
||||||
|
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
|
||||||
|
|
||||||
|
if( fNewBPM < 0.0f )
|
||||||
|
{
|
||||||
|
out.m_bHasNegativeBpms = true;
|
||||||
|
negBeat = fBeat;
|
||||||
|
negBPM = fNewBPM;
|
||||||
|
}
|
||||||
|
else if( fNewBPM > 0.0f )
|
||||||
|
{
|
||||||
|
// add in a warp.
|
||||||
|
if( negBPM < 0 )
|
||||||
|
{
|
||||||
|
float endBeat = fBeat + (fNewBPM / -negBPM) * (fBeat - negBeat);
|
||||||
|
WarpSegment new_seg(negBeat, endBeat);
|
||||||
|
out.AddWarpSegment( new_seg );
|
||||||
|
|
||||||
|
negBeat = -1;
|
||||||
|
negBPM = 1;
|
||||||
|
}
|
||||||
|
// too fast. make it a warp.
|
||||||
|
if( fNewBPM > FAST_BPM_WARP )
|
||||||
|
{
|
||||||
|
highspeedBeat = fBeat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// add in a warp.
|
||||||
|
if( highspeedBeat > 0 )
|
||||||
|
{
|
||||||
|
WarpSegment new_seg(highspeedBeat, fBeat);
|
||||||
|
out.AddWarpSegment( new_seg );
|
||||||
|
highspeedBeat = -1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
BPMSegment new_seg;
|
||||||
|
new_seg.m_iStartRow = BeatToNoteRow(fBeat);
|
||||||
|
new_seg.SetBPM( fNewBPM );
|
||||||
|
out.AddBPMSegment( new_seg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if( sValueName=="STOPS" || sValueName=="FREEZES" )
|
else if( sValueName=="STOPS" || sValueName=="FREEZES" )
|
||||||
{
|
{
|
||||||
vector<RString> arrayFreezeExpressions;
|
vector<RString> arrayFreezeExpressions;
|
||||||
split( sParams[1], ",", arrayFreezeExpressions );
|
split( sParams[1], ",", arrayFreezeExpressions );
|
||||||
|
|
||||||
|
// Prepare variables for negative stop conversion.
|
||||||
|
float negBeat = -1;
|
||||||
|
float negPause = 0;
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ )
|
for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ )
|
||||||
{
|
{
|
||||||
vector<RString> arrayFreezeValues;
|
vector<RString> arrayFreezeValues;
|
||||||
@@ -136,29 +211,49 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
|
|
||||||
const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] );
|
const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] );
|
||||||
const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] );
|
const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] );
|
||||||
StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds );
|
|
||||||
// XXX: Remove Negatives Bug?
|
|
||||||
new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat);
|
|
||||||
new_seg.m_fStopSeconds = fFreezeSeconds;
|
|
||||||
|
|
||||||
if(fFreezeSeconds > 0.0f)
|
// Process the prior stop.
|
||||||
|
if( negPause > 0 )
|
||||||
{
|
{
|
||||||
// LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds );
|
BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat));
|
||||||
out.AddStopSegment( new_seg );
|
float fSecondsPerBeat = 60 / oldBPM.GetBPM();
|
||||||
|
float fSkipBeats = negPause / fSecondsPerBeat;
|
||||||
|
|
||||||
|
if( negBeat + fSkipBeats > fFreezeBeat )
|
||||||
|
fSkipBeats = fFreezeBeat - negBeat;
|
||||||
|
|
||||||
|
WarpSegment ws( negBeat, negBeat + fSkipBeats);
|
||||||
|
out.AddWarpSegment( ws );
|
||||||
|
|
||||||
|
negBeat = -1;
|
||||||
|
negPause = 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if( fFreezeSeconds < 0.0f )
|
||||||
{
|
{
|
||||||
// negative stops (hi JS!) -aj
|
negBeat = fFreezeBeat;
|
||||||
if( PREFSMAN->m_bQuirksMode )
|
negPause = -fFreezeSeconds;
|
||||||
|
}
|
||||||
|
else if( fFreezeSeconds > 0.0f )
|
||||||
{
|
{
|
||||||
// LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds );
|
StopSegment ss( BeatToNoteRow(fFreezeBeat), fFreezeSeconds );
|
||||||
out.AddStopSegment( new_seg );
|
out.AddStopSegment( ss );
|
||||||
}
|
|
||||||
else
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the prior stop if there was one.
|
||||||
|
if( negPause > 0 )
|
||||||
|
{
|
||||||
|
BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat));
|
||||||
|
float fSecondsPerBeat = 60 / oldBPM.GetBPM();
|
||||||
|
float fSkipBeats = negPause / fSecondsPerBeat;
|
||||||
|
|
||||||
|
WarpSegment ws( negBeat, negBeat + fSkipBeats);
|
||||||
|
out.AddWarpSegment( ws );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="DELAYS" )
|
else if( sValueName=="DELAYS" )
|
||||||
{
|
{
|
||||||
vector<RString> arrayDelayExpressions;
|
vector<RString> arrayDelayExpressions;
|
||||||
@@ -193,95 +288,6 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if( sValueName=="BPMS" )
|
|
||||||
{
|
|
||||||
vector<RString> arrayBPMChangeExpressions;
|
|
||||||
split( sParams[1], ",", arrayBPMChangeExpressions );
|
|
||||||
|
|
||||||
for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ )
|
|
||||||
{
|
|
||||||
vector<RString> arrayBPMChangeValues;
|
|
||||||
split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues );
|
|
||||||
// XXX: Hard to tell which file caused this.
|
|
||||||
if( arrayBPMChangeValues.size() != 2 )
|
|
||||||
{
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
|
|
||||||
sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fBeat = StringToFloat( arrayBPMChangeValues[0] );
|
|
||||||
const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] );
|
|
||||||
// XXX: Remove Negatives Bug?
|
|
||||||
BPMSegment new_seg;
|
|
||||||
new_seg.m_iStartRow = BeatToNoteRow(fBeat);
|
|
||||||
new_seg.SetBPM( fNewBPM );
|
|
||||||
|
|
||||||
// convert negative BPMs into Warp segments
|
|
||||||
if( fNewBPM < 0.0f )
|
|
||||||
{
|
|
||||||
vector<RString> arrayNextBPMChangeValues;
|
|
||||||
// get next bpm in sequence
|
|
||||||
if((b+1) < arrayBPMChangeExpressions.size())
|
|
||||||
{
|
|
||||||
split( arrayBPMChangeExpressions[b+1], "=", arrayNextBPMChangeValues );
|
|
||||||
const float fNextPositiveBeat = StringToFloat( arrayNextBPMChangeValues[0] );
|
|
||||||
const float fNextPositiveBPM = StringToFloat( arrayNextBPMChangeValues[1] );
|
|
||||||
|
|
||||||
// tJumpPos = (tPosBPS-abs(negBPS)) + (gPosBPMPosition - fNegPosition)
|
|
||||||
float fDeltaBeat = ((fNextPositiveBPM/60.0f)-abs(fNewBPM/60.0f)) + (fNextPositiveBeat-fBeat);
|
|
||||||
//float fWarpLengthBeats = fNextPositiveBeat + fDeltaBeat;
|
|
||||||
WarpSegment wsTemp(BeatToNoteRow(fBeat),fDeltaBeat);
|
|
||||||
arrayWarpsFromNegativeBPMs.push_back(wsTemp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
LOG->Trace( ssprintf("==NotesLoSM negbpm==\nfnextposbeat = %f, fnextposbpm = %f,\nfdelta = %f, fwarpto = %f",
|
|
||||||
fNextPositiveBeat,
|
|
||||||
fNextPositiveBPM,
|
|
||||||
fDeltaBeat,
|
|
||||||
fWarpToBeat
|
|
||||||
) );
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
LOG->Trace( ssprintf("==Negative/Subtractive BPM in NotesLoader==\nNegBPM has noterow = %i, BPM = %f\nNextBPM @ noterow %i\nDelta value = %i noterows\nThis warp will have us end up at noterow %i",
|
|
||||||
BeatToNoteRow(fBeat), fNewBPM,
|
|
||||||
BeatToNoteRow(fNextPositiveBeat),
|
|
||||||
BeatToNoteRow(fDeltaBeat),
|
|
||||||
BeatToNoteRow(fWarpToBeat))
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
//float fDeltaBeat = ((fNextPositiveBPM/60.0f)-abs(fNewBPM/60.0f)) + (fNextPositiveBeat-fBeat);
|
|
||||||
/*
|
|
||||||
LOG->Trace( ssprintf("==NotesLoader Delta as NoteRows==\nfDeltaBeat = %f (beat)\nfDeltaBeat = (NextBPMSeg %f - abs(fBPS %f)) + (nextStartRow %i - thisRow %i)",
|
|
||||||
fDeltaBeat,(fNextPositiveBPM/60.0f),abs(fNewBPM/60.0f),BeatToNoteRow(fNextPositiveBeat),BeatToNoteRow(fBeat))
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// last BPM is a negative one? ugh. -aj (MAX_NOTE_ROW exists btw)
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fNewBPM > 0.0f)
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
out.m_bHasNegativeBpms = true;
|
|
||||||
// only add Negative BPMs in quirks mode -aj
|
|
||||||
if( PREFSMAN->m_bQuirksMode )
|
|
||||||
out.AddBPMSegment( new_seg );
|
|
||||||
else
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if( sValueName=="TIMESIGNATURES" )
|
else if( sValueName=="TIMESIGNATURES" )
|
||||||
{
|
{
|
||||||
vector<RString> vs1;
|
vector<RString> vs1;
|
||||||
@@ -366,61 +372,8 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Ensure all of the warps are handled right.
|
||||||
// warps (replacement for Negative BPM and Negative Stops)
|
sort(out.m_WarpSegments.begin(), out.m_WarpSegments.end());
|
||||||
/*
|
|
||||||
else if( sValueName=="WARPS" )
|
|
||||||
{
|
|
||||||
vector<RString> arrayWarpExpressions;
|
|
||||||
split( sParams[1], ",", arrayWarpExpressions );
|
|
||||||
|
|
||||||
for( unsigned f=0; f<arrayWarpExpressions.size(); f++ )
|
|
||||||
{
|
|
||||||
vector<RString> arrayWarpValues;
|
|
||||||
split( arrayWarpExpressions[f], "=", arrayWarpValues );
|
|
||||||
if( arrayWarpValues.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(), arrayWarpExpressions[f].c_str() );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fWarpStart = StringToFloat( arrayWarpValues[0] );
|
|
||||||
const float fWarpBeats = StringToFloat( arrayWarpValues[1] );
|
|
||||||
|
|
||||||
if( fWarpStart > 0.0f && fWarpBeats > 0.0f )
|
|
||||||
{
|
|
||||||
WarpSegment new_seg( BeatToNoteRow(fWarpStart), fWarpBeats );
|
|
||||||
out.AddWarpSegment( new_seg );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Currently disallow negative warps, to prevent the same
|
|
||||||
// kind of problem that happened when Negative/Subtractive
|
|
||||||
// BPMs arrived on the StepMania scene. -aj
|
|
||||||
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid warp at beat %f lasting %f beats.", fWarpStart, fWarpBeats );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Note: Even though it is possible to have Negative BPMs and Stops in
|
|
||||||
// a song along with Warps, we should not support files that contain
|
|
||||||
// both styles of warp tricks (Negatives vs. #WARPS).
|
|
||||||
// If Warps have been populated from Negative BPMs, then go through that
|
|
||||||
// instead of using the data in the Warps tag. This should be above,
|
|
||||||
// but it breaks compiling so...
|
|
||||||
if(arrayWarpsFromNegativeBPMs.size() > 0)
|
|
||||||
{
|
|
||||||
// zomg we already have some warps...
|
|
||||||
for( unsigned j=0; j<arrayWarpsFromNegativeBPMs.size(); j++ )
|
|
||||||
{
|
|
||||||
out.AddWarpSegment( arrayWarpsFromNegativeBPMs[j] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// warp sorting will need to take place.
|
|
||||||
//sort(out.m_WarpSegments.begin(), out.m_WarpSegments.end());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -486,6 +486,35 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if( sValueName=="WARPS" )
|
||||||
|
{
|
||||||
|
vector<RString> arrayWarpExpressions;
|
||||||
|
split( sParams[1], ",", arrayWarpExpressions );
|
||||||
|
|
||||||
|
for( unsigned b=0; b<arrayWarpExpressions.size(); b++ )
|
||||||
|
{
|
||||||
|
vector<RString> arrayWarpValues;
|
||||||
|
split( arrayWarpExpressions[b], "=", arrayWarpValues );
|
||||||
|
// XXX: Hard to tell which file caused this.
|
||||||
|
if( arrayWarpValues.size() != 2 )
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.",
|
||||||
|
sValueName.c_str(), arrayWarpExpressions[b].c_str() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float fBeat = StringToFloat( arrayWarpValues[0] );
|
||||||
|
const float fNewBeat = StringToFloat( arrayWarpValues[1] );
|
||||||
|
|
||||||
|
if(fNewBeat > fBeat)
|
||||||
|
out.m_Timing.AddWarpSegment( WarpSegment(fBeat, fNewBeat) );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Warp at beat %f, BPM %f.", fBeat, fNewBeat );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if( sValueName=="TIMESIGNATURES" )
|
else if( sValueName=="TIMESIGNATURES" )
|
||||||
{
|
{
|
||||||
vector<RString> vs1;
|
vector<RString> vs1;
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ enum SSCLoadingStates
|
|||||||
NUM_SSCLoadingStates /**< The number of states used. */
|
NUM_SSCLoadingStates /**< The number of states used. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief The version where fakes started to be used as a radar category. */
|
||||||
const float VERSION_RADAR_FAKE = 0.53f;
|
const float VERSION_RADAR_FAKE = 0.53f;
|
||||||
|
/** @brief The version where WarpSegments started to be utilized. */
|
||||||
|
const float VERSION_WARP_SEGMENT = 0.56f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
|
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
|
||||||
|
|||||||
+16
-3
@@ -144,18 +144,18 @@ static void WriteGlobalTags( RageFile &f, const Song &out )
|
|||||||
}
|
}
|
||||||
f.PutLine( ";" );
|
f.PutLine( ";" );
|
||||||
|
|
||||||
/*
|
|
||||||
f.Write( "#WARPS:" );
|
f.Write( "#WARPS:" );
|
||||||
for( unsigned i=0; i<out.m_Timing.m_WarpSegments.size(); i++ )
|
for( unsigned i=0; i<out.m_Timing.m_WarpSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
const WarpSegment &ws = out.m_Timing.m_WarpSegments[i];
|
const WarpSegment &ws = out.m_Timing.m_WarpSegments[i];
|
||||||
|
|
||||||
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(ws.m_iStartRow), ws.m_fWarpBeats ) );
|
f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(ws.m_iStartRow), ws.m_fEndBeat ) );
|
||||||
if( i != out.m_Timing.m_WarpSegments.size()-1 )
|
if( i != out.m_Timing.m_WarpSegments.size()-1 )
|
||||||
f.Write( "," );
|
f.Write( "," );
|
||||||
}
|
}
|
||||||
f.PutLine( ";" );
|
f.PutLine( ";" );
|
||||||
*/
|
|
||||||
|
|
||||||
ASSERT( !out.m_Timing.m_vTimeSignatureSegments.empty() );
|
ASSERT( !out.m_Timing.m_vTimeSignatureSegments.empty() );
|
||||||
f.Write( "#TIMESIGNATURES:" );
|
f.Write( "#TIMESIGNATURES:" );
|
||||||
@@ -299,6 +299,7 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa
|
|||||||
lines.push_back( "#BPMS:;" );
|
lines.push_back( "#BPMS:;" );
|
||||||
lines.push_back( "#STOPS:;" );
|
lines.push_back( "#STOPS:;" );
|
||||||
lines.push_back( "#DELAYS:;" );
|
lines.push_back( "#DELAYS:;" );
|
||||||
|
lines.push_back( "#WARPS:;" );
|
||||||
lines.push_back( "#TIMESIGNATURES:;" );
|
lines.push_back( "#TIMESIGNATURES:;" );
|
||||||
lines.push_back( "#TICKCOUNTS:;" );
|
lines.push_back( "#TICKCOUNTS:;" );
|
||||||
lines.push_back( "#ATTACKS:;" );
|
lines.push_back( "#ATTACKS:;" );
|
||||||
@@ -337,6 +338,18 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa
|
|||||||
}
|
}
|
||||||
lines.push_back( ssprintf( "#DELAYS:%s;", join("\n,", asDelayValues).c_str() ) );
|
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() );
|
ASSERT( !in.m_Timing.m_vTimeSignatureSegments.empty() );
|
||||||
vector<RString> asTimeSigValues;
|
vector<RString> asTimeSigValues;
|
||||||
FOREACH_CONST( TimeSignatureSegment, in.m_Timing.m_vTimeSignatureSegments, iter )
|
FOREACH_CONST( TimeSignatureSegment, in.m_Timing.m_vTimeSignatureSegments, iter )
|
||||||
|
|||||||
+17
-16
@@ -1520,6 +1520,8 @@ int Player::GetClosestNoteDirectional( int col, int iStartRow, int iEndRow, bool
|
|||||||
// Is this the row we want?
|
// Is this the row we want?
|
||||||
do {
|
do {
|
||||||
const TapNote &tn = begin->second;
|
const TapNote &tn = begin->second;
|
||||||
|
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( begin->first ) )
|
||||||
|
break;
|
||||||
if( tn.type == TapNote::empty )
|
if( tn.type == TapNote::empty )
|
||||||
break;
|
break;
|
||||||
if( !bAllowGraded && tn.result.tns != TNS_None )
|
if( !bAllowGraded && tn.result.tns != TNS_None )
|
||||||
@@ -1569,6 +1571,11 @@ int Player::GetClosestNonEmptyRowDirectional( int iStartRow, int iEndRow, bool b
|
|||||||
++iter;
|
++iter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iter.Row() ) )
|
||||||
|
{
|
||||||
|
++iter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
return iter.Row();
|
return iter.Row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1966,7 +1973,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
|
|||||||
* Either option would fundamentally change the grading of two quick notes
|
* Either option would fundamentally change the grading of two quick notes
|
||||||
* "jack hammers." Hmm.
|
* "jack hammers." Hmm.
|
||||||
*/
|
*/
|
||||||
const int iStepSearchRows = BeatToNoteRow( StepSearchDistance * GAMESTATE->m_fCurBPS * GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate );
|
const int iStepSearchRows = BeatToNoteRow( GAMESTATE->m_pCurSong->m_Timing.GetBeatFromElapsedTime( GAMESTATE->m_fMusicSeconds + StepSearchDistance ) ) - iSongRow;
|
||||||
int iRowOfOverlappingNoteOrRow = row;
|
int iRowOfOverlappingNoteOrRow = row;
|
||||||
if( row == -1 )
|
if( row == -1 )
|
||||||
{
|
{
|
||||||
@@ -2040,7 +2047,9 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b
|
|||||||
{
|
{
|
||||||
case TapNote::mine:
|
case TapNote::mine:
|
||||||
// Stepped too close to mine?
|
// Stepped too close to mine?
|
||||||
if( !bRelease && ( REQUIRE_STEP_ON_MINES == !bHeld ) && fSecondsFromExact <= GetWindowSeconds(TW_Mine) )
|
if( !bRelease && ( REQUIRE_STEP_ON_MINES == !bHeld ) &&
|
||||||
|
fSecondsFromExact <= GetWindowSeconds(TW_Mine) &&
|
||||||
|
!GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow(iSongRow) )
|
||||||
score = TNS_HitMine;
|
score = TNS_HitMine;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2522,8 +2531,8 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds )
|
|||||||
{
|
{
|
||||||
//LOG->Trace( "Steps::UpdateTapNotesMissedOlderThan(%f)", fMissIfOlderThanThisBeat );
|
//LOG->Trace( "Steps::UpdateTapNotesMissedOlderThan(%f)", fMissIfOlderThanThisBeat );
|
||||||
int iMissIfOlderThanThisRow;
|
int iMissIfOlderThanThisRow;
|
||||||
{
|
|
||||||
const float fEarliestTime = GAMESTATE->m_fMusicSeconds - fMissIfOlderThanSeconds;
|
const float fEarliestTime = GAMESTATE->m_fMusicSeconds - fMissIfOlderThanSeconds;
|
||||||
|
{
|
||||||
bool bFreeze, bDelay;
|
bool bFreeze, bDelay;
|
||||||
float fMissIfOlderThanThisBeat;
|
float fMissIfOlderThanThisBeat;
|
||||||
float fThrowAway;
|
float fThrowAway;
|
||||||
@@ -2551,8 +2560,8 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds )
|
|||||||
if( !NeedsTapJudging(tn) )
|
if( !NeedsTapJudging(tn) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// warp hackery
|
// Ignore all notes that are skipped via WARPS.
|
||||||
if( iter.Row() >= GAMESTATE->m_iWarpBeginRow && iter.Row() <= (GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) )
|
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iter.Row() ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( tn.type == TapNote::mine )
|
if( tn.type == TapNote::mine )
|
||||||
@@ -2568,11 +2577,6 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// warp hackery: don't score notes within the warp region.
|
|
||||||
// (Only useful when QuirksMode is enabled.) -aj
|
|
||||||
if( iter.Row() >= GAMESTATE->m_iWarpBeginRow && iter.Row() <= (GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tn.result.tns = TNS_Miss;
|
tn.result.tns = TNS_Miss;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2592,8 +2596,7 @@ void Player::UpdateJudgedRows()
|
|||||||
int iRow = iter.Row();
|
int iRow = iter.Row();
|
||||||
|
|
||||||
// if row is within a warp section, ignore it. -aj
|
// if row is within a warp section, ignore it. -aj
|
||||||
if( iRow >= GAMESTATE->m_iWarpBeginRow &&
|
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow(iRow) )
|
||||||
iRow <= (GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( iLastSeenRow != iRow )
|
if( iLastSeenRow != iRow )
|
||||||
@@ -2928,8 +2931,7 @@ void Player::HandleTapRowScore( unsigned row )
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// more warp hackery. -aj
|
// more warp hackery. -aj
|
||||||
if( row >= (unsigned)GAMESTATE->m_iWarpBeginRow &&
|
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( row ) )
|
||||||
row <= (unsigned)(GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( GAMESTATE->m_bDemonstrationOrJukebox )
|
if( GAMESTATE->m_bDemonstrationOrJukebox )
|
||||||
@@ -3033,8 +3035,7 @@ void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumH
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// more warp hackery. -aj
|
// more warp hackery. -aj
|
||||||
if( iRow >= GAMESTATE->m_iWarpBeginRow &&
|
if( GAMESTATE->m_pCurSong->m_Timing.IsWarpAtRow( iRow ) )
|
||||||
iRow <= (GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// don't accumulate combo if AutoPlay is on.
|
// don't accumulate combo if AutoPlay is on.
|
||||||
|
|||||||
+22
-2
@@ -80,6 +80,7 @@ AutoScreenMessage( SM_BackFromTimeSignatureNumeratorChange );
|
|||||||
AutoScreenMessage( SM_BackFromTimeSignatureDenominatorChange );
|
AutoScreenMessage( SM_BackFromTimeSignatureDenominatorChange );
|
||||||
AutoScreenMessage( SM_BackFromTickcountChange );
|
AutoScreenMessage( SM_BackFromTickcountChange );
|
||||||
AutoScreenMessage( SM_BackFromComboChange );
|
AutoScreenMessage( SM_BackFromComboChange );
|
||||||
|
AutoScreenMessage( SM_BackFromWarpChange );
|
||||||
AutoScreenMessage( SM_DoSaveAndExit );
|
AutoScreenMessage( SM_DoSaveAndExit );
|
||||||
AutoScreenMessage( SM_DoExit );
|
AutoScreenMessage( SM_DoExit );
|
||||||
AutoScreenMessage( SM_SaveSuccessful );
|
AutoScreenMessage( SM_SaveSuccessful );
|
||||||
@@ -549,7 +550,8 @@ static MenuDef g_TimingDataInformation(
|
|||||||
MenuRowDef( ScreenEdit::time_signature_numerator, "Edit time signature (top)", true, EditMode_Full, true, true, 0, NULL ),
|
MenuRowDef( ScreenEdit::time_signature_numerator, "Edit time signature (top)", true, EditMode_Full, true, true, 0, NULL ),
|
||||||
MenuRowDef( ScreenEdit::time_signature_denominator, "Edit time signature (bottom)", true, EditMode_Full, true, true, 0, NULL ),
|
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::tickcount, "Edit tickcount", true, EditMode_Full, true, true, 0, NULL ),
|
||||||
MenuRowDef( ScreenEdit::combo, "Edit combo", true, EditMode_Full, true, true, 0, NULL )
|
MenuRowDef( ScreenEdit::combo, "Edit combo", true, EditMode_Full, true, true, 0, NULL ),
|
||||||
|
MenuRowDef( ScreenEdit::warp, "Edit warp", true, EditMode_Full, true, true, 0, NULL )
|
||||||
);
|
);
|
||||||
|
|
||||||
enum { song_bganimation, song_movie, song_bitmap, global_bganimation, global_movie, global_movie_song_group, global_movie_song_group_and_genre, dynamic_random, baked_random, none };
|
enum { song_bganimation, song_movie, song_bitmap, global_bganimation, global_movie, global_movie_song_group, global_movie_song_group_and_genre, dynamic_random, baked_random, none };
|
||||||
@@ -2639,6 +2641,13 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
|
|||||||
}
|
}
|
||||||
SetDirty( true );
|
SetDirty( true );
|
||||||
}
|
}
|
||||||
|
else if ( SM == SM_BackFromWarpChange )
|
||||||
|
{
|
||||||
|
float fWarp = StringToFloat( ScreenTextEntry::s_sLastAnswer );
|
||||||
|
if( fWarp > 0 )
|
||||||
|
m_pSong->m_Timing.SetWarpAtBeat( GAMESTATE->m_fSongBeat, fWarp );
|
||||||
|
SetDirty( true );
|
||||||
|
}
|
||||||
else if( SM == SM_BackFromBGChange )
|
else if( SM == SM_BackFromBGChange )
|
||||||
{
|
{
|
||||||
HandleBGChangeChoice( (BGChangeChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
|
HandleBGChangeChoice( (BGChangeChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
|
||||||
@@ -3176,6 +3185,7 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &iAns
|
|||||||
g_TimingDataInformation.rows[time_signature_denominator].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTimeSignatureDenominatorAtBeat( fBeat ) ) );
|
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[tickcount].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTickcountAtBeat( fBeat ) ) );
|
||||||
g_TimingDataInformation.rows[combo].SetOneUnthemedChoice( ssprintf("%d", pTime.GetComboAtBeat( fBeat ) ) );
|
g_TimingDataInformation.rows[combo].SetOneUnthemedChoice( ssprintf("%d", pTime.GetComboAtBeat( fBeat ) ) );
|
||||||
|
g_TimingDataInformation.rows[warp].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetWarpAtBeat( fBeat ) ) );
|
||||||
|
|
||||||
EditMiniMenu( &g_TimingDataInformation, SM_BackFromTimingDataInformation );
|
EditMiniMenu( &g_TimingDataInformation, SM_BackFromTimingDataInformation );
|
||||||
}
|
}
|
||||||
@@ -3493,7 +3503,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAns
|
|||||||
|
|
||||||
// don't move the step from where it is, just move everything later
|
// don't move the step from where it is, just move everything later
|
||||||
NoteDataUtil::InsertRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopBeats) );
|
NoteDataUtil::InsertRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopBeats) );
|
||||||
m_pSong->m_Timing.InsertRows( BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopSeconds) );
|
m_pSong->m_Timing.InsertRows( BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopBeats) );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case undo:
|
case undo:
|
||||||
@@ -3609,6 +3619,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_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_TICKCOUNT_VALUE ( "ScreenEdit", "Enter a new Tickcount value." );
|
||||||
static LocalizedString ENTER_COMBO_VALUE ( "ScreenEdit", "Enter a new Combo value." );
|
static LocalizedString ENTER_COMBO_VALUE ( "ScreenEdit", "Enter a new Combo value." );
|
||||||
|
static LocalizedString ENTER_WARP_VALUE ( "ScreenEdit", "Enter a new Warp value." );
|
||||||
void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice c, const vector<int> &iAnswers )
|
void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice c, const vector<int> &iAnswers )
|
||||||
{
|
{
|
||||||
switch( c )
|
switch( c )
|
||||||
@@ -3673,6 +3684,15 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
|
|||||||
4
|
4
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case warp:
|
||||||
|
// todo: Call a screen with class ScreenTextEntry instead. -aj
|
||||||
|
ScreenTextEntry::TextEntry(
|
||||||
|
SM_BackFromWarpChange,
|
||||||
|
ENTER_WARP_VALUE,
|
||||||
|
ssprintf( "%.4f", m_pSong->m_Timing.GetWarpAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ),
|
||||||
|
10
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -456,6 +456,7 @@ public:
|
|||||||
time_signature_denominator,
|
time_signature_denominator,
|
||||||
tickcount,
|
tickcount,
|
||||||
combo,
|
combo,
|
||||||
|
warp,
|
||||||
NUM_TIMING_DATA_INFORMATION_CHOICES
|
NUM_TIMING_DATA_INFORMATION_CHOICES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@
|
|||||||
* @brief The internal version of the cache for StepMania.
|
* @brief The internal version of the cache for StepMania.
|
||||||
*
|
*
|
||||||
* Increment this value to invalidate the current cache. */
|
* Increment this value to invalidate the current cache. */
|
||||||
const int FILE_CACHE_VERSION = 166;
|
const int FILE_CACHE_VERSION = 167;
|
||||||
|
|
||||||
/** @brief How long does a song sample last by default? */
|
/** @brief How long does a song sample last by default? */
|
||||||
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
|
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
|
||||||
|
|||||||
+2
-2
@@ -17,7 +17,7 @@ struct lua_State;
|
|||||||
struct BackgroundChange;
|
struct BackgroundChange;
|
||||||
|
|
||||||
/** @brief The version of the .ssc file format. */
|
/** @brief The version of the .ssc file format. */
|
||||||
const static float STEPFILE_VERSION_NUMBER = 0.55f;
|
const static float STEPFILE_VERSION_NUMBER = 0.56f;
|
||||||
|
|
||||||
/** @brief How many edits for this song can each profile have? */
|
/** @brief How many edits for this song can each profile have? */
|
||||||
const int MAX_EDITS_PER_SONG_PER_PROFILE = 5;
|
const int MAX_EDITS_PER_SONG_PER_PROFILE = 5;
|
||||||
@@ -307,7 +307,7 @@ public:
|
|||||||
|
|
||||||
void AddBPMSegment( const BPMSegment &seg ) { m_Timing.AddBPMSegment( seg ); }
|
void AddBPMSegment( const BPMSegment &seg ) { m_Timing.AddBPMSegment( seg ); }
|
||||||
void AddStopSegment( const StopSegment &seg ) { m_Timing.AddStopSegment( seg ); }
|
void AddStopSegment( const StopSegment &seg ) { m_Timing.AddStopSegment( seg ); }
|
||||||
//void AddWarpSegment( const WarpSegment &seg ) { m_Timing.AddWarpSegment( seg ); }
|
void AddWarpSegment( const WarpSegment &seg ) { m_Timing.AddWarpSegment( seg ); }
|
||||||
void AddBackgroundChange( BackgroundLayer blLayer, BackgroundChange seg );
|
void AddBackgroundChange( BackgroundLayer blLayer, BackgroundChange seg );
|
||||||
void AddForegroundChange( BackgroundChange seg );
|
void AddForegroundChange( BackgroundChange seg );
|
||||||
void AddLyricSegment( LyricSegment seg );
|
void AddLyricSegment( LyricSegment seg );
|
||||||
|
|||||||
+313
-199
@@ -150,12 +150,30 @@ void TimingData::SetTimeSignatureDenominatorAtRow( int iRow, int iDenominator )
|
|||||||
SetTimeSignatureAtRow( iRow, GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iRow ) ).m_iNumerator, iDenominator );
|
SetTimeSignatureAtRow( iRow, GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iRow ) ).m_iNumerator, iDenominator );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void TimingData::SetWarpAtRow( int iRow, float fNew )
|
||||||
void TimingData::SetWarpAtRow( int iRowAt, float fLengthBeats )
|
|
||||||
{
|
{
|
||||||
// todo: code this -aj
|
unsigned i;
|
||||||
|
for( i=0; i<m_WarpSegments.size(); i++ )
|
||||||
|
if( m_WarpSegments[i].m_iStartRow == iRow )
|
||||||
|
break;
|
||||||
|
bool valid = iRow > 0 && NoteRowToBeat(iRow) < fNew;
|
||||||
|
if( i == m_WarpSegments.size() )
|
||||||
|
{
|
||||||
|
if( valid )
|
||||||
|
{
|
||||||
|
AddWarpSegment( WarpSegment(iRow, fNew) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( valid )
|
||||||
|
{
|
||||||
|
m_WarpSegments[i].m_fEndBeat = fNew;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_WarpSegments.erase( m_WarpSegments.begin()+i, m_WarpSegments.begin()+i+1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/* Change an existing Tickcount segment, merge identical segments together or insert a new one. */
|
/* Change an existing Tickcount segment, merge identical segments together or insert a new one. */
|
||||||
void TimingData::SetTickcountAtRow( int iRow, int iTicks )
|
void TimingData::SetTickcountAtRow( int iRow, int iTicks )
|
||||||
@@ -229,13 +247,13 @@ int TimingData::GetComboAtRow( int iNoteRow ) const
|
|||||||
return m_ComboSegments[GetComboSegmentIndexAtRow( iNoteRow )].m_iCombo;
|
return m_ComboSegments[GetComboSegmentIndexAtRow( iNoteRow )].m_iCombo;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TimingData::GetWarpToRow( int iWarpBeginRow ) const
|
float TimingData::GetWarpAtRow( int iWarpRow ) const
|
||||||
{
|
{
|
||||||
for( unsigned i=0; i<m_WarpSegments.size(); i++ )
|
for( unsigned i=0; i<m_WarpSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
if( m_WarpSegments[i].m_iStartRow == iWarpBeginRow )
|
if( m_WarpSegments[i].m_iStartRow == iWarpRow )
|
||||||
{
|
{
|
||||||
return iWarpBeginRow + BeatToNoteRow(m_WarpSegments[i].m_fWarpBeats);
|
return m_WarpSegments[i].m_fEndBeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -296,7 +314,7 @@ int TimingData::GetBPMSegmentIndexAtRow( int iNoteRow ) const
|
|||||||
for( i=0; i<m_BPMSegments.size()-1; i++ )
|
for( i=0; i<m_BPMSegments.size()-1; i++ )
|
||||||
if( m_BPMSegments[i+1].m_iStartRow > iNoteRow )
|
if( m_BPMSegments[i+1].m_iStartRow > iNoteRow )
|
||||||
break;
|
break;
|
||||||
return (int)i;
|
return static_cast<int>(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TimingData::GetStopSegmentIndexAtRow( int iNoteRow, bool bDelay ) const
|
int TimingData::GetStopSegmentIndexAtRow( int iNoteRow, bool bDelay ) const
|
||||||
@@ -308,16 +326,72 @@ int TimingData::GetStopSegmentIndexAtRow( int iNoteRow, bool bDelay ) const
|
|||||||
if( s.m_iStartRow > iNoteRow && s.m_bDelay == bDelay )
|
if( s.m_iStartRow > iNoteRow && s.m_bDelay == bDelay )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (int)i;
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TimingData::GetWarpSegmentIndexAtRow( int iNoteRow ) const
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for( i=0; i<m_WarpSegments.size()-1; i++ )
|
||||||
|
{
|
||||||
|
const WarpSegment& s = m_WarpSegments[i+1];
|
||||||
|
if( s.m_iStartRow > iNoteRow )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimingData::IsWarpAtRow( int iNoteRow ) const
|
||||||
|
{
|
||||||
|
if( m_WarpSegments.empty() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int i = GetWarpSegmentIndexAtRow( iNoteRow );
|
||||||
|
const WarpSegment& s = m_WarpSegments[i];
|
||||||
|
if( s.m_iStartRow <= iNoteRow && iNoteRow < BeatToNoteRow(s.m_fEndBeat) )
|
||||||
|
{
|
||||||
|
if( m_StopSegments.empty() )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if( GetStopAtRow(iNoteRow) != 0.0f )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TimingData::GetTimeSignatureSegmentIndexAtRow( int iRow ) const
|
int TimingData::GetTimeSignatureSegmentIndexAtRow( int iRow ) const
|
||||||
{
|
{
|
||||||
int i;
|
unsigned i;
|
||||||
for (i=0; i < (int)(m_vTimeSignatureSegments.size()) - 1; i++ )
|
for (i=0; i < m_vTimeSignatureSegments.size() - 1; i++ )
|
||||||
if( m_vTimeSignatureSegments[i+1].m_iStartRow > iRow )
|
if( m_vTimeSignatureSegments[i+1].m_iStartRow > iRow )
|
||||||
break;
|
break;
|
||||||
return i;
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TimingData::GetComboSegmentIndexAtRow( int iRow ) const
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for( i=0; i<m_ComboSegments.size()-1; i++ )
|
||||||
|
{
|
||||||
|
const ComboSegment& s = m_ComboSegments[i+1];
|
||||||
|
if( s.m_iStartRow > iRow )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPMSegment& TimingData::GetBPMSegmentAtRow( int iNoteRow )
|
||||||
|
{
|
||||||
|
static BPMSegment empty;
|
||||||
|
if( m_BPMSegments.empty() )
|
||||||
|
return empty;
|
||||||
|
|
||||||
|
int i = GetBPMSegmentIndexAtRow( iNoteRow );
|
||||||
|
return m_BPMSegments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeSignatureSegment& TimingData::GetTimeSignatureSegmentAtRow( int iRow )
|
TimeSignatureSegment& TimingData::GetTimeSignatureSegmentAtRow( int iRow )
|
||||||
@@ -339,28 +413,6 @@ int TimingData::GetTimeSignatureDenominatorAtRow( int iRow )
|
|||||||
return GetTimeSignatureSegmentAtRow( iRow ).m_iDenominator;
|
return GetTimeSignatureSegmentAtRow( iRow ).m_iDenominator;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TimingData::GetComboSegmentIndexAtRow( int iRow ) const
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
for( i=0; i<m_ComboSegments.size()-1; i++ )
|
|
||||||
{
|
|
||||||
const ComboSegment& s = m_ComboSegments[i+1];
|
|
||||||
if( s.m_iStartRow > iRow )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (int)i;
|
|
||||||
}
|
|
||||||
|
|
||||||
BPMSegment& TimingData::GetBPMSegmentAtRow( int iNoteRow )
|
|
||||||
{
|
|
||||||
static BPMSegment empty;
|
|
||||||
if( m_BPMSegments.empty() )
|
|
||||||
return empty;
|
|
||||||
|
|
||||||
int i = GetBPMSegmentIndexAtRow( iNoteRow );
|
|
||||||
return m_BPMSegments[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
ComboSegment& TimingData::GetComboSegmentAtRow( int iRow )
|
ComboSegment& TimingData::GetComboSegmentAtRow( int iRow )
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@@ -380,6 +432,16 @@ StopSegment& TimingData::GetStopSegmentAtRow( int iNoteRow, bool bDelay )
|
|||||||
return m_StopSegments[i];
|
return m_StopSegments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WarpSegment& TimingData::GetWarpSegmentAtRow( int iRow )
|
||||||
|
{
|
||||||
|
static WarpSegment empty;
|
||||||
|
if( m_WarpSegments.empty() )
|
||||||
|
return empty;
|
||||||
|
|
||||||
|
int i = GetWarpSegmentIndexAtRow( iRow );
|
||||||
|
return m_WarpSegments[i];
|
||||||
|
}
|
||||||
|
|
||||||
int TimingData::GetTickcountSegmentIndexAtRow( int iRow ) const
|
int TimingData::GetTickcountSegmentIndexAtRow( int iRow ) const
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -411,150 +473,118 @@ void TimingData::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatO
|
|||||||
GetBeatAndBPSFromElapsedTimeNoOffset( fElapsedTime, fBeatOut, fBPSOut, bFreezeOut, bDelayOut, iWarpBeginOut, fWarpLengthOut );
|
GetBeatAndBPSFromElapsedTimeNoOffset( fElapsedTime, fBeatOut, fBPSOut, bFreezeOut, bDelayOut, iWarpBeginOut, fWarpLengthOut );
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpLengthOut ) const
|
enum
|
||||||
{
|
{
|
||||||
// LOG->Trace( "GetBeatAndBPSFromElapsedTime( fElapsedTime = %f )", fElapsedTime );
|
FOUND_WARP,
|
||||||
const float fTime = fElapsedTime;
|
FOUND_WARP_DESTINATION,
|
||||||
fElapsedTime += m_fBeat0OffsetInSeconds;
|
FOUND_BPM_CHANGE,
|
||||||
|
FOUND_STOP,
|
||||||
|
FOUND_MARKER,
|
||||||
|
NOT_FOUND
|
||||||
|
};
|
||||||
|
|
||||||
for( unsigned i=0; i<m_BPMSegments.size(); i++ ) // foreach BPMSegment
|
void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpDestinationOut ) const
|
||||||
|
{
|
||||||
|
|
||||||
|
vector<BPMSegment>::const_iterator itBPMS = m_BPMSegments.begin();
|
||||||
|
vector<WarpSegment>::const_iterator itWS = m_WarpSegments.begin();
|
||||||
|
vector<StopSegment>::const_iterator itSS = m_StopSegments.begin();
|
||||||
|
|
||||||
|
bFreezeOut = false;
|
||||||
|
bDelayOut = false;
|
||||||
|
|
||||||
|
iWarpBeginOut = -1;
|
||||||
|
|
||||||
|
int iLastRow = 0;
|
||||||
|
float fLastTime = -m_fBeat0OffsetInSeconds;
|
||||||
|
float fBPS = GetBPMAtRow(0) / 60.0;
|
||||||
|
|
||||||
|
float bIsWarping = false;
|
||||||
|
float fWarpDestination = 0.0;
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
{
|
{
|
||||||
const int iStartRowThisSegment = m_BPMSegments[i].m_iStartRow;
|
int iEventRow = INT_MAX;
|
||||||
const float fStartBeatThisSegment = NoteRowToBeat( iStartRowThisSegment );
|
int iEventType = NOT_FOUND;
|
||||||
const bool bIsFirstBPMSegment = i==0;
|
if( bIsWarping && BeatToNoteRow(fWarpDestination) < iEventRow )
|
||||||
const bool bIsLastBPMSegment = i==m_BPMSegments.size()-1;
|
{
|
||||||
const int iStartRowNextSegment = bIsLastBPMSegment ? MAX_NOTE_ROW : m_BPMSegments[i+1].m_iStartRow;
|
iEventRow = BeatToNoteRow(fWarpDestination);
|
||||||
const float fStartBeatNextSegment = NoteRowToBeat( iStartRowNextSegment );
|
iEventType = FOUND_WARP_DESTINATION;
|
||||||
const float fBPS = m_BPMSegments[i].m_fBPS;
|
}
|
||||||
|
if( itBPMS != m_BPMSegments.end() && itBPMS->m_iStartRow < iEventRow )
|
||||||
for( unsigned j=0; j<m_StopSegments.size(); j++ ) // foreach freeze
|
{
|
||||||
|
iEventRow = itBPMS->m_iStartRow;
|
||||||
|
iEventType = FOUND_BPM_CHANGE;
|
||||||
|
}
|
||||||
|
if( itSS != m_StopSegments.end() && itSS->m_iStartRow < iEventRow )
|
||||||
|
{
|
||||||
|
iEventRow = itSS->m_iStartRow;
|
||||||
|
iEventType = FOUND_STOP;
|
||||||
|
}
|
||||||
|
if( itWS != m_WarpSegments.end() && itWS->m_iStartRow < iEventRow )
|
||||||
|
{
|
||||||
|
iEventRow = itWS->m_iStartRow;
|
||||||
|
iEventType = FOUND_WARP;
|
||||||
|
}
|
||||||
|
if( iEventType == NOT_FOUND )
|
||||||
{
|
{
|
||||||
const bool bIsDelay = m_StopSegments[j].m_bDelay;
|
|
||||||
if( !bIsFirstBPMSegment && iStartRowThisSegment >= m_StopSegments[j].m_iStartRow )
|
|
||||||
continue;
|
|
||||||
if( !bIsLastBPMSegment && m_StopSegments[j].m_iStartRow > iStartRowNextSegment )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// this freeze lies within this BPMSegment
|
|
||||||
const int iRowsBeatsSinceStartOfSegment = m_StopSegments[j].m_iStartRow - iStartRowThisSegment;
|
|
||||||
const float fBeatsSinceStartOfSegment = NoteRowToBeat(iRowsBeatsSinceStartOfSegment);
|
|
||||||
const float fFreezeStartSecond = fBeatsSinceStartOfSegment / fBPS;
|
|
||||||
|
|
||||||
// modified for delays
|
|
||||||
if( !bIsDelay && fFreezeStartSecond >= fElapsedTime )
|
|
||||||
break;
|
break;
|
||||||
if( bIsDelay && fFreezeStartSecond > fElapsedTime )
|
}
|
||||||
|
float fTimeToNextEvent = bIsWarping ? 0 : NoteRowToBeat( iEventRow - iLastRow ) / fBPS;
|
||||||
|
float fNextEventTime = fLastTime + fTimeToNextEvent;
|
||||||
|
if ( fElapsedTime < fNextEventTime )
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// the freeze segment is <= current time
|
fLastTime = fNextEventTime;
|
||||||
fElapsedTime -= m_StopSegments[j].m_fStopSeconds;
|
switch( iEventType )
|
||||||
|
{
|
||||||
if( (fFreezeStartSecond >= fElapsedTime && !bIsDelay) ||
|
case FOUND_WARP_DESTINATION:
|
||||||
(fFreezeStartSecond > fElapsedTime && bIsDelay) )
|
bIsWarping = false;
|
||||||
|
break;
|
||||||
|
case FOUND_BPM_CHANGE:
|
||||||
|
fBPS = itBPMS->m_fBPS;
|
||||||
|
itBPMS ++;
|
||||||
|
break;
|
||||||
|
case FOUND_STOP: // TODO: update for Delays.
|
||||||
|
{
|
||||||
|
fTimeToNextEvent = itSS->m_fStopSeconds;
|
||||||
|
fNextEventTime = fLastTime + fTimeToNextEvent;
|
||||||
|
const bool bIsDelay = itSS->m_bDelay;
|
||||||
|
if ( fElapsedTime < fNextEventTime )
|
||||||
{
|
{
|
||||||
// The time lies within the stop.
|
|
||||||
fBeatOut = NoteRowToBeat(m_StopSegments[j].m_iStartRow);
|
|
||||||
fBPSOut = fBPS;
|
|
||||||
bFreezeOut = !bIsDelay;
|
bFreezeOut = !bIsDelay;
|
||||||
bDelayOut = bIsDelay;
|
bDelayOut = bIsDelay;
|
||||||
//iWarpBeginOut = -1;
|
fBeatOut = NoteRowToBeat( itSS->m_iStartRow );
|
||||||
//fWarpLengthOut = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// by this point we should have the warps in their own place.
|
|
||||||
for( unsigned j=0; j<m_WarpSegments.size(); j++ ) // foreach warp
|
|
||||||
{
|
|
||||||
if( !bIsFirstBPMSegment && iStartRowThisSegment >= m_WarpSegments[j].m_iStartRow )
|
|
||||||
continue;
|
|
||||||
if( !bIsLastBPMSegment && m_WarpSegments[j].m_iStartRow > iStartRowNextSegment )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
const int iRowsBeatsSinceStartOfSegment = m_WarpSegments[j].m_iStartRow - iStartRowThisSegment;
|
|
||||||
const float fBeatsSinceStartOfSegment = NoteRowToBeat(iRowsBeatsSinceStartOfSegment);
|
|
||||||
const float fWarpStartSecond = fBeatsSinceStartOfSegment / fBPS;
|
|
||||||
*/
|
|
||||||
|
|
||||||
// the freeze segment is <= current time
|
|
||||||
//fElapsedTime -= m_WarpSegments[j].m_fWarpBeats;
|
|
||||||
|
|
||||||
// this warp lies within this BPMSegment.
|
|
||||||
/*
|
|
||||||
if( fWarpStartSecond >= fElapsedTime )
|
|
||||||
{
|
|
||||||
// this WarpSegment IS the current segment.
|
|
||||||
// don't know how to properly handle beatout -aj
|
|
||||||
//fBeatOut = NoteRowToBeat(m_WarpSegments[j].m_iStartRow);
|
|
||||||
fBeatOut = fStartBeatThisSegment + fElapsedTime*fBPS;
|
|
||||||
fBPSOut = m_BPMSegments[i+1].m_fBPS;
|
|
||||||
bFreezeOut = false;
|
|
||||||
bDelayOut = false;
|
|
||||||
iWarpBeginOut = m_WarpSegments[j].m_iStartRow;
|
|
||||||
fWarpLengthOut = m_WarpSegments[j].m_fWarpBeats;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
const float fBeatsInThisSegment = fStartBeatNextSegment - fStartBeatThisSegment;
|
|
||||||
const float fSecondsInThisSegment = fBeatsInThisSegment / fBPS;
|
|
||||||
//if(fBPS < 0.0f)
|
|
||||||
/*
|
|
||||||
if(fStartBeatThisSegment == 445.500f || fStartBeatThisSegment == 449.500)
|
|
||||||
{
|
|
||||||
LOG->Trace( ssprintf("segment (beat %f) beats: %f / seconds: %f / BPS: %f",fStartBeatThisSegment,fBeatsInThisSegment,fSecondsInThisSegment,fBPS) );
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if( bIsLastBPMSegment || fElapsedTime <= fSecondsInThisSegment )
|
|
||||||
{
|
|
||||||
// this BPMSegment IS the current segment.
|
|
||||||
fBeatOut = fStartBeatThisSegment + fElapsedTime*fBPS;
|
|
||||||
fBPSOut = fBPS;
|
fBPSOut = fBPS;
|
||||||
bFreezeOut = false;
|
|
||||||
bDelayOut = false;
|
|
||||||
//iWarpBeginOut;
|
|
||||||
//fWarpLengthOut;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
fLastTime = fNextEventTime;
|
||||||
// this BPMSegment is NOT the current segment.
|
itSS ++;
|
||||||
fElapsedTime -= fSecondsInThisSegment;
|
}
|
||||||
// xxx: negative testing [aj]
|
break;
|
||||||
/*
|
case FOUND_WARP:
|
||||||
//if(fBPS < 0.0f)
|
bIsWarping = true;
|
||||||
if( (fStartBeatNextSegment >= 445.490f && fStartBeatNextSegment <= 453.72f) || fBPS < 0.0f )
|
if( itWS->m_fEndBeat > fWarpDestination )
|
||||||
{
|
{
|
||||||
//LOG->Trace( ssprintf("beat %f is %f BPS (%f BPM)",fBeatOut,fBPSOut,fBPSOut*60.0f) );
|
fWarpDestination = itWS->m_fEndBeat;
|
||||||
//LOG->Trace( ssprintf("start beat %f + elapsed time %f",fStartBeatThisSegment,fElapsedTime) );
|
|
||||||
//LOG->Trace( ssprintf("elapsed time is now %f",fElapsedTime) );
|
|
||||||
}
|
}
|
||||||
*/
|
iWarpBeginOut = iEventRow;
|
||||||
|
fWarpDestinationOut = fWarpDestination;
|
||||||
|
itWS ++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// If we get here, something has gone wrong. Is everything sorted?
|
iLastRow = iEventRow;
|
||||||
vector<BPMSegment> vBPMS = m_BPMSegments;
|
}
|
||||||
vector<StopSegment> vSS = m_StopSegments;
|
|
||||||
vector<WarpSegment> vWS = m_WarpSegments;
|
fBeatOut = NoteRowToBeat( iLastRow ) + (fElapsedTime - fLastTime) * fBPS;
|
||||||
vector<TimeSignatureSegment> vTSS = m_vTimeSignatureSegments;
|
fBPSOut = fBPS;
|
||||||
vector<TickcountSegment> vTS = m_TickcountSegments;
|
|
||||||
vector<ComboSegment> vCS = m_ComboSegments;
|
|
||||||
sort( vBPMS.begin(), vBPMS.end() );
|
|
||||||
sort( vSS.begin(), vSS.end() );
|
|
||||||
sort( vWS.begin(), vWS.end() );
|
|
||||||
sort( vTSS.begin(), vTSS.end() );
|
|
||||||
sort( vTS.begin(), vTS.end() );
|
|
||||||
sort( vCS.begin(), vCS.end() );
|
|
||||||
ASSERT_M( vBPMS == m_BPMSegments, "The BPM segments were not sorted!" );
|
|
||||||
ASSERT_M( vSS == m_StopSegments, "The Stop segments were not sorted!" );
|
|
||||||
ASSERT_M( vWS == m_WarpSegments, "The Warp segments were not sorted!" );
|
|
||||||
ASSERT_M( vTSS == m_vTimeSignatureSegments, "The Time Signature segments were not sorted!" );
|
|
||||||
ASSERT_M( vTS == m_TickcountSegments, "The Tickcount segments were not sorted!" );
|
|
||||||
ASSERT_M( vCS == m_ComboSegments, "The Combo segments were not sorted!" );
|
|
||||||
FAIL_M( ssprintf("Failed to find the appropriate segment for elapsed time %f.", fTime) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float TimingData::GetElapsedTimeFromBeat( float fBeat ) const
|
float TimingData::GetElapsedTimeFromBeat( float fBeat ) const
|
||||||
{
|
{
|
||||||
return TimingData::GetElapsedTimeFromBeatNoOffset( fBeat ) - PREFSMAN->m_fGlobalOffsetSeconds;
|
return TimingData::GetElapsedTimeFromBeatNoOffset( fBeat ) - PREFSMAN->m_fGlobalOffsetSeconds;
|
||||||
@@ -562,53 +592,86 @@ float TimingData::GetElapsedTimeFromBeat( float fBeat ) const
|
|||||||
|
|
||||||
float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const
|
float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const
|
||||||
{
|
{
|
||||||
float fElapsedTime = 0;
|
|
||||||
fElapsedTime -= m_fBeat0OffsetInSeconds;
|
|
||||||
|
|
||||||
int iRow = BeatToNoteRow(fBeat);
|
vector<BPMSegment>::const_iterator itBPMS = m_BPMSegments.begin();
|
||||||
for( unsigned j=0; j<m_StopSegments.size(); j++ ) // foreach freeze
|
vector<WarpSegment>::const_iterator itWS = m_WarpSegments.begin();
|
||||||
|
vector<StopSegment>::const_iterator itSS = m_StopSegments.begin();
|
||||||
|
|
||||||
|
int iLastRow = 0;
|
||||||
|
float fLastTime = -m_fBeat0OffsetInSeconds;
|
||||||
|
float fBPS = GetBPMAtRow(0) / 60.0;
|
||||||
|
|
||||||
|
float bIsWarping = false;
|
||||||
|
float fWarpDestination = 0.0;
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
{
|
{
|
||||||
/* A traditional stop has the beat happening before the stop. (>=)
|
int iEventRow = INT_MAX;
|
||||||
* A Pump delay acts differently: the pause is before the beat. (>)
|
int iEventType = NOT_FOUND;
|
||||||
*/
|
if( bIsWarping && BeatToNoteRow(fWarpDestination) < iEventRow )
|
||||||
if( ( m_StopSegments[j].m_iStartRow >= iRow && !m_StopSegments[j].m_bDelay ) ||
|
{
|
||||||
( m_StopSegments[j].m_iStartRow > iRow && m_StopSegments[j].m_bDelay ) )
|
iEventRow = BeatToNoteRow(fWarpDestination);
|
||||||
|
iEventType = FOUND_WARP_DESTINATION;
|
||||||
|
}
|
||||||
|
if( itBPMS != m_BPMSegments.end() && itBPMS->m_iStartRow < iEventRow )
|
||||||
|
{
|
||||||
|
iEventRow = itBPMS->m_iStartRow;
|
||||||
|
iEventType = FOUND_BPM_CHANGE;
|
||||||
|
}
|
||||||
|
if( itSS != m_StopSegments.end() && itSS->m_bDelay && itSS->m_iStartRow < iEventRow ) // delays (come before marker)
|
||||||
|
{
|
||||||
|
iEventRow = itSS->m_iStartRow;
|
||||||
|
iEventType = FOUND_STOP;
|
||||||
|
}
|
||||||
|
if( BeatToNoteRow(fBeat) < iEventRow )
|
||||||
|
{
|
||||||
|
iEventRow = BeatToNoteRow(fBeat);
|
||||||
|
iEventType = FOUND_MARKER;
|
||||||
|
}
|
||||||
|
if( itSS != m_StopSegments.end() && !itSS->m_bDelay && itSS->m_iStartRow < iEventRow ) // stops (come after marker)
|
||||||
|
{
|
||||||
|
iEventRow = itSS->m_iStartRow;
|
||||||
|
iEventType = FOUND_STOP;
|
||||||
|
}
|
||||||
|
if( itWS != m_WarpSegments.end() && itWS->m_iStartRow < iEventRow )
|
||||||
|
{
|
||||||
|
iEventRow = itWS->m_iStartRow;
|
||||||
|
iEventType = FOUND_WARP;
|
||||||
|
}
|
||||||
|
float fTimeToNextEvent = bIsWarping ? 0 : NoteRowToBeat( iEventRow - iLastRow ) / fBPS;
|
||||||
|
float fNextEventTime = fLastTime + fTimeToNextEvent;
|
||||||
|
fLastTime = fNextEventTime;
|
||||||
|
switch( iEventType )
|
||||||
|
{
|
||||||
|
case FOUND_WARP_DESTINATION:
|
||||||
|
bIsWarping = false;
|
||||||
break;
|
break;
|
||||||
fElapsedTime += m_StopSegments[j].m_fStopSeconds;
|
case FOUND_BPM_CHANGE:
|
||||||
}
|
fBPS = itBPMS->m_fBPS;
|
||||||
|
itBPMS ++;
|
||||||
for( unsigned i=0; i<m_BPMSegments.size(); i++ ) // foreach BPMSegment
|
break;
|
||||||
|
case FOUND_STOP:
|
||||||
|
fTimeToNextEvent = itSS->m_fStopSeconds;
|
||||||
|
fNextEventTime = fLastTime + fTimeToNextEvent;
|
||||||
|
fLastTime = fNextEventTime;
|
||||||
|
itSS ++;
|
||||||
|
break;
|
||||||
|
case FOUND_MARKER:
|
||||||
|
return fLastTime;
|
||||||
|
case FOUND_WARP:
|
||||||
|
bIsWarping = true;
|
||||||
|
if( itWS->m_fEndBeat > fWarpDestination )
|
||||||
{
|
{
|
||||||
const bool bIsLastBPMSegment = i==m_BPMSegments.size()-1;
|
fWarpDestination = itWS->m_fEndBeat;
|
||||||
const float fBPS = m_BPMSegments[i].m_fBPS;
|
|
||||||
|
|
||||||
if( bIsLastBPMSegment )
|
|
||||||
{
|
|
||||||
fElapsedTime += NoteRowToBeat( iRow ) / fBPS;
|
|
||||||
}
|
}
|
||||||
else
|
itWS ++;
|
||||||
{
|
break;
|
||||||
const int iStartIndexThisSegment = m_BPMSegments[i].m_iStartRow;
|
}
|
||||||
const int iStartIndexNextSegment = m_BPMSegments[i+1].m_iStartRow;
|
iLastRow = iEventRow;
|
||||||
const int iRowsInThisSegment = min( iStartIndexNextSegment - iStartIndexThisSegment, iRow );
|
|
||||||
fElapsedTime += NoteRowToBeat( iRowsInThisSegment ) / fBPS;
|
|
||||||
iRow -= iRowsInThisSegment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( iRow <= 0 )
|
// won't reach here, unless BeatToNoteRow(fBeat == INT_MAX) (impossible)
|
||||||
return fElapsedTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
for( unsigned i=0; i<m_WarpSegments.size(); i++ ) // foreach WarpSegment
|
|
||||||
{
|
|
||||||
// todo: is this correct? -aj
|
|
||||||
const int iWarpToRow = m_WarpSegments[i].m_iEndRow;
|
|
||||||
fElapsedTime += NoteRowToBeat( iWarpToRow );
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return fElapsedTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex, bool bAdjustBPM )
|
void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex, bool bAdjustBPM )
|
||||||
@@ -639,6 +702,25 @@ void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex, bool
|
|||||||
m_StopSegments[i].m_iStartRow = lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex;
|
m_StopSegments[i].m_iStartRow = lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < m_WarpSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
const int iSegStartRow = m_WarpSegments[i].m_iStartRow;
|
||||||
|
const int iSegEndRow = BeatToNoteRow( m_WarpSegments[i].m_fEndBeat );
|
||||||
|
if( iSegEndRow >= iStartIndex )
|
||||||
|
{
|
||||||
|
if( iSegEndRow > iEndIndex )
|
||||||
|
m_WarpSegments[i].m_fEndBeat += NoteRowToBeat(lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
|
||||||
|
else
|
||||||
|
m_WarpSegments[i].m_fEndBeat = NoteRowToBeat(lrintf((iSegEndRow - iStartIndex) * fScale) + iStartIndex);
|
||||||
|
}
|
||||||
|
if( iSegStartRow < iStartIndex )
|
||||||
|
continue;
|
||||||
|
else if( iSegStartRow > iEndIndex )
|
||||||
|
m_WarpSegments[i].m_iStartRow += lrintf((iEndIndex - iStartIndex) * (fScale - 1));
|
||||||
|
else
|
||||||
|
m_WarpSegments[i].m_iStartRow = lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex;
|
||||||
|
}
|
||||||
|
|
||||||
// adjust BPM changes to preserve timing
|
// adjust BPM changes to preserve timing
|
||||||
if( bAdjustBPM )
|
if( bAdjustBPM )
|
||||||
{
|
{
|
||||||
@@ -683,6 +765,16 @@ void TimingData::InsertRows( int iStartRow, int iRowsToAdd )
|
|||||||
stop.m_iStartRow += iRowsToAdd;
|
stop.m_iStartRow += iRowsToAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < m_WarpSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
WarpSegment &warp = m_WarpSegments[i];
|
||||||
|
if( BeatToNoteRow(warp.m_fEndBeat) >= iStartRow )
|
||||||
|
warp.m_fEndBeat += NoteRowToBeat(iRowsToAdd);
|
||||||
|
if( warp.m_iStartRow < iStartRow )
|
||||||
|
continue;
|
||||||
|
warp.m_iStartRow += iRowsToAdd;
|
||||||
|
}
|
||||||
|
|
||||||
for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ )
|
for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
TimeSignatureSegment &time = m_vTimeSignatureSegments[i];
|
TimeSignatureSegment &time = m_vTimeSignatureSegments[i];
|
||||||
@@ -764,6 +856,26 @@ void TimingData::DeleteRows( int iStartRow, int iRowsToDelete )
|
|||||||
stop.m_iStartRow -= iRowsToDelete;
|
stop.m_iStartRow -= iRowsToDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( unsigned i = 0; i < m_WarpSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
WarpSegment &warp = m_WarpSegments[i];
|
||||||
|
|
||||||
|
if( BeatToNoteRow(warp.m_fEndBeat) >= iStartRow )
|
||||||
|
warp.m_fEndBeat = max( NoteRowToBeat(iStartRow), warp.m_fEndBeat - NoteRowToBeat(iRowsToDelete) );
|
||||||
|
|
||||||
|
if( warp.m_iStartRow < iStartRow )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( warp.m_iStartRow < iStartRow+iRowsToDelete )
|
||||||
|
{
|
||||||
|
m_WarpSegments.erase( m_WarpSegments.begin()+i, m_WarpSegments.begin()+i+1 );
|
||||||
|
--i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
warp.m_iStartRow -= iRowsToDelete;
|
||||||
|
}
|
||||||
|
|
||||||
for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ )
|
for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ )
|
||||||
{
|
{
|
||||||
TimeSignatureSegment &time = m_vTimeSignatureSegments[i];
|
TimeSignatureSegment &time = m_vTimeSignatureSegments[i];
|
||||||
@@ -891,6 +1003,7 @@ class LunaTimingData: public Luna<TimingData>
|
|||||||
public:
|
public:
|
||||||
static int HasStops( T* p, lua_State *L ) { lua_pushboolean(L, p->HasStops()); return 1; }
|
static int HasStops( T* p, lua_State *L ) { lua_pushboolean(L, p->HasStops()); return 1; }
|
||||||
static int HasBPMChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasBpmChanges()); return 1; }
|
static int HasBPMChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasBpmChanges()); return 1; }
|
||||||
|
static int HasWarps( T* p, lua_State *L ) { lua_pushboolean(L, p->HasWarps()); return 1; }
|
||||||
static int GetStops( T* p, lua_State *L )
|
static int GetStops( T* p, lua_State *L )
|
||||||
{
|
{
|
||||||
vector<RString> vStops;
|
vector<RString> vStops;
|
||||||
@@ -965,6 +1078,7 @@ public:
|
|||||||
{
|
{
|
||||||
ADD_METHOD( HasStops );
|
ADD_METHOD( HasStops );
|
||||||
ADD_METHOD( HasBPMChanges );
|
ADD_METHOD( HasBPMChanges );
|
||||||
|
ADD_METHOD( HasWarps );
|
||||||
ADD_METHOD( GetStops );
|
ADD_METHOD( GetStops );
|
||||||
ADD_METHOD( GetDelays );
|
ADD_METHOD( GetDelays );
|
||||||
ADD_METHOD( GetBPMs );
|
ADD_METHOD( GetBPMs );
|
||||||
|
|||||||
+84
-16
@@ -318,25 +318,41 @@ struct TimeSignatureSegment
|
|||||||
struct WarpSegment
|
struct WarpSegment
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @brief Creates a simple Warp Segment with default values.
|
* @brief Create a simple Warp Segment with default values.
|
||||||
*
|
*
|
||||||
* It is best to override the values as soon as possible.
|
* It is best to override the values as soon as possible.
|
||||||
*/
|
*/
|
||||||
WarpSegment() : m_iStartRow(-1), m_fWarpBeats(-1) { }
|
WarpSegment() : m_iStartRow(-1), m_fEndBeat(-1) { }
|
||||||
/**
|
/**
|
||||||
* @brief Creates a Warp Segment with the specified starting row and row to warp to.
|
* @brief Create a Warp Segment with the specified starting row and row to warp to.
|
||||||
* @param s the starting row of this segment.
|
* @param s the starting row of this segment.
|
||||||
* @param r the row to warp to.
|
* @param r the row to warp to.
|
||||||
*/
|
*/
|
||||||
WarpSegment( int s, int r ): m_iStartRow(max(0, s)),
|
WarpSegment( int s, int r ): m_iStartRow(max(0, (s < r ? s : r))),
|
||||||
m_fWarpBeats(max(0, NoteRowToBeat(r))) {}
|
m_fEndBeat(max(0, NoteRowToBeat((r > s ? r : s)))) {}
|
||||||
/**
|
/**
|
||||||
* @brief Creates a Warp Segment with the specified starting row and beat to warp to.
|
* @brief Creates a Warp Segment with the specified starting row and beat to warp to.
|
||||||
* @param s the starting row of this segment.
|
* @param s the starting row of this segment.
|
||||||
* @param b the beat to warp to.
|
* @param b the beat to warp to.
|
||||||
*/
|
*/
|
||||||
WarpSegment( int s, float b ): m_iStartRow(max(0, s)),
|
WarpSegment( int s, float b ): m_iStartRow(max(0, s)),
|
||||||
m_fWarpBeats(max(0, b)) {}
|
m_fEndBeat(max(0, b)) {}
|
||||||
|
/**
|
||||||
|
* @brief Create a Warp Segment with the specified starting beat and row to warp to.
|
||||||
|
* @param s the starting beat in this segment.
|
||||||
|
* @param r the row to warp to.
|
||||||
|
*/
|
||||||
|
WarpSegment( float s, int r ):
|
||||||
|
m_iStartRow(max(0, BeatToNoteRow(s))),
|
||||||
|
m_fEndBeat(max(0, NoteRowToBeat(r))) {}
|
||||||
|
/**
|
||||||
|
* @brief Creates a Warp Segment with the specified starting beat and beat to warp to.
|
||||||
|
* @param s the starting beat of this segment.
|
||||||
|
* @param b the beat to warp to.
|
||||||
|
*/
|
||||||
|
WarpSegment( float s, float b ):
|
||||||
|
m_iStartRow(max(0, BeatToNoteRow((s < b ? s : b)))),
|
||||||
|
m_fEndBeat(max(0, (b > s ? b : s))) {}
|
||||||
/**
|
/**
|
||||||
* @brief The row in which the WarpSegment activates.
|
* @brief The row in which the WarpSegment activates.
|
||||||
*/
|
*/
|
||||||
@@ -344,7 +360,7 @@ struct WarpSegment
|
|||||||
/**
|
/**
|
||||||
* @brief The beat to warp to.
|
* @brief The beat to warp to.
|
||||||
*/
|
*/
|
||||||
float m_fWarpBeats;
|
float m_fEndBeat;
|
||||||
/**
|
/**
|
||||||
* @brief Compares two WarpSegments to see if they are equal to each other.
|
* @brief Compares two WarpSegments to see if they are equal to each other.
|
||||||
* @param other the other WarpSegment to compare to.
|
* @param other the other WarpSegment to compare to.
|
||||||
@@ -353,7 +369,7 @@ struct WarpSegment
|
|||||||
bool operator==( const WarpSegment &other ) const
|
bool operator==( const WarpSegment &other ) const
|
||||||
{
|
{
|
||||||
COMPARE( m_iStartRow );
|
COMPARE( m_iStartRow );
|
||||||
COMPARE( m_fWarpBeats );
|
COMPARE( m_fEndBeat );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -370,7 +386,7 @@ struct WarpSegment
|
|||||||
bool operator<( const WarpSegment &other ) const
|
bool operator<( const WarpSegment &other ) const
|
||||||
{
|
{
|
||||||
return m_iStartRow < other.m_iStartRow ||
|
return m_iStartRow < other.m_iStartRow ||
|
||||||
( m_iStartRow == other.m_iStartRow && m_fWarpBeats < other.m_fWarpBeats );
|
( m_iStartRow == other.m_iStartRow && m_fEndBeat < other.m_fEndBeat );
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Compares two WarpSegments to see if one is less than or equal to the other.
|
* @brief Compares two WarpSegments to see if one is less than or equal to the other.
|
||||||
@@ -875,19 +891,71 @@ public:
|
|||||||
* @param seg the new TimeSignatureSegment.
|
* @param seg the new TimeSignatureSegment.
|
||||||
*/
|
*/
|
||||||
void AddTimeSignatureSegment( const TimeSignatureSegment &seg );
|
void AddTimeSignatureSegment( const TimeSignatureSegment &seg );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Determine the row to warp to.
|
* @brief Determine the beat to warp to.
|
||||||
* @param iWarpBeginRow The row you start on.
|
* @param iRow The row you start on.
|
||||||
* @return the row you warp to.
|
* @return the beat you warp to.
|
||||||
*/
|
*/
|
||||||
int GetWarpToRow( int iWarpBeginRow ) const;
|
float GetWarpAtRow( int iRow ) const;
|
||||||
|
/**
|
||||||
|
* @brief Determine the beat to warp to.
|
||||||
|
* @param fBeat The beat you start on.
|
||||||
|
* @return the beat you warp to.
|
||||||
|
*/
|
||||||
|
float GetWarpAtBeat( float fBeat ) const { return GetWarpAtRow( BeatToNoteRow( fBeat ) ); }
|
||||||
|
/**
|
||||||
|
* @brief Set the beat to warp to given a starting row.
|
||||||
|
* @param iRow The row to start on.
|
||||||
|
* @param fNew The destination beat.
|
||||||
|
*/
|
||||||
|
void SetWarpAtRow( int iRow, float fNew );
|
||||||
|
/**
|
||||||
|
* @brief Set the beat to warp to given a starting beat.
|
||||||
|
* @param fBeat The beat to start on.
|
||||||
|
* @param fNew The destination beat.
|
||||||
|
*/
|
||||||
|
void SetWarpAtBeat( float fBeat, float fNew ) { SetWarpAtRow( BeatToNoteRow( fBeat ), fNew ); }
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the WarpSegment at the specified row.
|
||||||
|
* @param iRow the row to focus on.
|
||||||
|
* @return the WarpSegment in question.
|
||||||
|
*/
|
||||||
|
WarpSegment& GetWarpSegmentAtRow( int iRow );
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the WarpSegment at the specified beat.
|
||||||
|
* @param fBeat the beat to focus on.
|
||||||
|
* @return the WarpSegment in question.
|
||||||
|
*/
|
||||||
|
WarpSegment& GetWarpSegmentAtBeat( float fBeat ) { return GetWarpSegmentAtRow( BeatToNoteRow( fBeat ) ); }
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the index of the WarpSegment at the specified row.
|
||||||
|
* @param iRow the row to focus on.
|
||||||
|
* @return the index in question.
|
||||||
|
*/
|
||||||
|
int GetWarpSegmentIndexAtRow( int iRow ) const;
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the index of the WarpSegment at the specified beat.
|
||||||
|
* @param fBeat the beat to focus on.
|
||||||
|
* @return the index in question.
|
||||||
|
*/
|
||||||
|
int GetWarpSegmentIndexAtBeat( float fBeat ) const { return GetWarpSegmentIndexAtRow( BeatToNoteRow( fBeat ) ); }
|
||||||
|
/**
|
||||||
|
* @brief Checks if the row is inside a warp.
|
||||||
|
* @param iRow the row to focus on.
|
||||||
|
* @return true if the row is inside a warp, false otherwise.
|
||||||
|
*/
|
||||||
|
bool IsWarpAtRow( int iRow ) const;
|
||||||
|
/**
|
||||||
|
* @brief Checks if the beat is inside a warp.
|
||||||
|
* @param fBeat the beat to focus on.
|
||||||
|
* @return true if the row is inside a warp, false otherwise.
|
||||||
|
*/
|
||||||
|
bool IsWarpAtBeat( float fBeat ) const { return IsWarpAtRow( BeatToNoteRow( fBeat ) ); }
|
||||||
/**
|
/**
|
||||||
* @brief Add the WarpSegment to the TimingData.
|
* @brief Add the WarpSegment to the TimingData.
|
||||||
* @param seg the new WarpSegment.
|
* @param seg the new WarpSegment.
|
||||||
*/
|
*/
|
||||||
void AddWarpSegment( const WarpSegment &seg );
|
void AddWarpSegment( const WarpSegment &seg );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the Tickcount at the given row.
|
* @brief Retrieve the Tickcount at the given row.
|
||||||
* @param iNoteRow the row in question.
|
* @param iNoteRow the row in question.
|
||||||
@@ -1011,7 +1079,7 @@ public:
|
|||||||
}
|
}
|
||||||
float GetElapsedTimeFromBeat( float fBeat ) const;
|
float GetElapsedTimeFromBeat( float fBeat ) const;
|
||||||
|
|
||||||
void GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &iWarpLengthOut ) const;
|
void GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpDestinationOut ) const;
|
||||||
float GetBeatFromElapsedTimeNoOffset( float fElapsedTime ) const // shortcut for places that care only about the beat
|
float GetBeatFromElapsedTimeNoOffset( float fElapsedTime ) const // shortcut for places that care only about the beat
|
||||||
{
|
{
|
||||||
float fBeat, fThrowAway, fThrowAway2;
|
float fBeat, fThrowAway, fThrowAway2;
|
||||||
|
|||||||
Reference in New Issue
Block a user