4f07a0ea8b
I'm preserving our numbering Pohly. ;)
744 lines
22 KiB
C++
744 lines
22 KiB
C++
#ifndef TIMING_SEGMENTS_H
|
|
#define TIMING_SEGMENTS_H
|
|
|
|
#include "NoteTypes.h" // Converting rows to beats and vice~versa.
|
|
|
|
enum TimingSegmentType
|
|
{
|
|
SEGMENT_BPM,
|
|
SEGMENT_STOP,
|
|
SEGMENT_DELAY,
|
|
SEGMENT_TIME_SIG,
|
|
SEGMENT_WARP,
|
|
SEGMENT_LABEL,
|
|
SEGMENT_TICKCOUNT,
|
|
SEGMENT_COMBO,
|
|
SEGMENT_SPEED,
|
|
SEGMENT_SCROLL,
|
|
SEGMENT_FAKE,
|
|
NUM_TimingSegmentType,
|
|
TimingSegmentType_Invalid,
|
|
};
|
|
|
|
// XXX: dumb names
|
|
enum SegmentEffectType
|
|
{
|
|
SegmentEffectType_Row, // takes effect on a single row
|
|
SegmentEffectType_Range, // takes effect for a definite amount of rows
|
|
SegmentEffectType_Indefinite, // takes effect until the next segment of its type
|
|
NUM_SegmentEffectType,
|
|
SegmentEffectType_Invalid,
|
|
};
|
|
|
|
#define FOREACH_TimingSegmentType(tst) FOREACH_ENUM(TimingSegmentType, tst)
|
|
|
|
const RString& TimingSegmentTypeToString( TimingSegmentType tst );
|
|
|
|
const int ROW_INVALID = -1;
|
|
|
|
#define COMPARE(x) if( this->x!=other.x ) return false
|
|
#define COMPARE_FLOAT(x) if( fabsf(this->x - other.x) > EPSILON ) return false
|
|
|
|
/**
|
|
* @brief The base timing segment for make glorious benefit wolfman
|
|
* XXX: this should be an abstract class.
|
|
*/
|
|
struct TimingSegment
|
|
{
|
|
virtual TimingSegmentType GetType() const { return TimingSegmentType_Invalid; }
|
|
virtual SegmentEffectType GetEffectType() const { return SegmentEffectType_Invalid; }
|
|
virtual TimingSegment* Copy() const = 0;
|
|
|
|
virtual bool IsNotable() const = 0;
|
|
virtual void DebugPrint() const;
|
|
|
|
// don't allow base TimingSegments to be instantiated directly
|
|
TimingSegment( int iRow = ROW_INVALID ) : m_iStartRow(iRow) { }
|
|
TimingSegment( float fBeat ) : m_iStartRow(ToNoteRow(fBeat)) { }
|
|
|
|
TimingSegment(const TimingSegment &other) :
|
|
m_iStartRow( other.GetRow() ) { }
|
|
|
|
// for our purposes, two floats within this level of error are equal
|
|
static const double EPSILON;
|
|
|
|
virtual ~TimingSegment() { }
|
|
|
|
/**
|
|
* @brief Scales itself.
|
|
* @param start Starting row
|
|
* @param length Length in rows
|
|
* @param newLength The new length in rows
|
|
*/
|
|
virtual void Scale( int start, int length, int newLength );
|
|
|
|
int GetRow() const { return m_iStartRow; }
|
|
void SetRow( int iRow ) { m_iStartRow = iRow; }
|
|
|
|
float GetBeat() const { return NoteRowToBeat(m_iStartRow); }
|
|
void SetBeat( float fBeat ) { SetRow( BeatToNoteRow(fBeat) ); }
|
|
|
|
virtual RString ToString(int /* dec */) const
|
|
{
|
|
return FloatToString(GetBeat());
|
|
}
|
|
|
|
bool operator<( const TimingSegment &other ) const
|
|
{
|
|
return GetRow() < other.GetRow();
|
|
}
|
|
|
|
// overloads should not call this base version; derived classes
|
|
// should only compare contents, and this compares position.
|
|
virtual bool operator==( const TimingSegment &other ) const
|
|
{
|
|
return GetRow() == other.GetRow();
|
|
}
|
|
|
|
virtual bool operator!=( const TimingSegment &other ) const
|
|
{
|
|
return !this->operator==(other);
|
|
}
|
|
|
|
private:
|
|
/** @brief The row in which this segment activates. */
|
|
int m_iStartRow;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when a whole region of arrows is to be ignored.
|
|
*
|
|
* FakeSegments are similar to the Fake Tap Notes in that the contents
|
|
* inside are neither for nor against the player. They can be useful for
|
|
* mission modes, in conjunction with WarpSegments, or perhaps other
|
|
* uses not thought up at the time of this comment. Unlike the Warp
|
|
* Segments, these are not magically jumped over: instead, these are
|
|
* drawn normally.
|
|
*
|
|
* These were inspired by the Pump It Up series. */
|
|
struct FakeSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_FAKE; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Range; }
|
|
|
|
TimingSegment* Copy() const { return new FakeSegment(*this); }
|
|
|
|
bool IsNotable() const { return m_iLengthRows > 0; }
|
|
void DebugPrint() const;
|
|
|
|
FakeSegment() : TimingSegment(), m_iLengthRows(-1) { }
|
|
|
|
FakeSegment( int iStartRow, int iLengthRows ) :
|
|
TimingSegment(iStartRow), m_iLengthRows(iLengthRows) { }
|
|
|
|
FakeSegment( int iStartRow, float fBeats ) :
|
|
TimingSegment(iStartRow), m_iLengthRows(ToNoteRow(fBeats)) { }
|
|
|
|
FakeSegment( const FakeSegment &other ) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_iLengthRows( other.GetLengthRows() ) { }
|
|
|
|
int GetLengthRows() const { return m_iLengthRows; }
|
|
float GetLengthBeats() const { return ToBeat(m_iLengthRows); }
|
|
float GetLength() const { return GetLengthBeats(); } // compatibility
|
|
|
|
void SetLength( int iRows ) { m_iLengthRows = ToNoteRow(iRows); }
|
|
void SetLength( float fBeats ) { m_iLengthRows = ToNoteRow(fBeats); }
|
|
|
|
void Scale( int start, int length, int newLength );
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const FakeSegment &other ) const
|
|
{
|
|
COMPARE( m_iLengthRows );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const FakeSegment&>(other) );
|
|
}
|
|
|
|
private:
|
|
/** @brief The number of rows the FakeSegment is alive for. */
|
|
int m_iLengthRows;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when a song needs to warp to a new beat.
|
|
*
|
|
* A warp segment is used to replicate the effects of Negative BPMs without
|
|
* abusing negative BPMs. Negative BPMs should be converted to warp segments.
|
|
* WarpAt=WarpToRelative is the format, where both are in beats.
|
|
* (Technically they're both rows though.) */
|
|
struct WarpSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_WARP; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Range; }
|
|
TimingSegment* Copy() const { return new WarpSegment(*this); }
|
|
|
|
bool IsNotable() const { return m_iLengthRows > 0; }
|
|
void DebugPrint() const;
|
|
|
|
WarpSegment() : TimingSegment(), m_iLengthRows(0) { }
|
|
|
|
WarpSegment( const WarpSegment &other ) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_iLengthRows( other.GetLengthRows() ) { }
|
|
|
|
WarpSegment( int iStartRow, int iLengthRows ) :
|
|
TimingSegment(iStartRow), m_iLengthRows(iLengthRows) { }
|
|
|
|
WarpSegment( int iStartRow, float fBeats ) :
|
|
TimingSegment(iStartRow), m_iLengthRows(ToNoteRow(fBeats)) { }
|
|
|
|
int GetLengthRows() const { return m_iLengthRows; }
|
|
float GetLengthBeats() const { return ToBeat(m_iLengthRows); }
|
|
float GetLength() const { return GetLengthBeats(); } // compatibility
|
|
|
|
void SetLength( int iRows ) { m_iLengthRows = ToNoteRow(iRows); }
|
|
void SetLength( float fBeats ) { m_iLengthRows = ToNoteRow(fBeats); }
|
|
|
|
void Scale( int start, int length, int newLength );
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const WarpSegment &other ) const
|
|
{
|
|
COMPARE( m_iLengthRows );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const WarpSegment&>(other) );
|
|
}
|
|
|
|
private:
|
|
/** @brief The number of rows the WarpSegment will warp past. */
|
|
int m_iLengthRows;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when a chart is to have a different tickcount value
|
|
* for hold notes.
|
|
*
|
|
* A tickcount segment is used to better replicate the checkpoint hold
|
|
* system used by various based video games. The number is used to
|
|
* represent how many ticks can be counted in one beat.
|
|
*/
|
|
|
|
|
|
struct TickcountSegment : public TimingSegment
|
|
{
|
|
/** @brief The default amount of ticks per beat. */
|
|
static const unsigned DEFAULT_TICK_COUNT = 4;
|
|
|
|
TimingSegmentType GetType() const { return SEGMENT_TICKCOUNT; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Indefinite; }
|
|
|
|
bool IsNotable() const { return true; } // indefinite segments are always true
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new TickcountSegment(*this); }
|
|
|
|
TickcountSegment( int iStartRow = ROW_INVALID, int iTicks = DEFAULT_TICK_COUNT ) :
|
|
TimingSegment(iStartRow), m_iTicksPerBeat(iTicks) { }
|
|
|
|
TickcountSegment( const TickcountSegment &other ) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_iTicksPerBeat( other.GetTicks() ) { }
|
|
|
|
int GetTicks() const { return m_iTicksPerBeat; }
|
|
void SetTicks( int iTicks ) { m_iTicksPerBeat = iTicks; }
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const TickcountSegment &other ) const
|
|
{
|
|
COMPARE( m_iTicksPerBeat );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const TickcountSegment&>(other) );
|
|
}
|
|
private:
|
|
/** @brief The amount of hold checkpoints counted per beat */
|
|
int m_iTicksPerBeat;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when a chart is to have a different combo multiplier value.
|
|
*
|
|
* Admitedly, this would primarily be used for mission mode style charts. However,
|
|
* it can have its place during normal gameplay.
|
|
*/
|
|
struct ComboSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_COMBO; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Indefinite; }
|
|
|
|
bool IsNotable() const { return true; } // indefinite segments are always true
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new ComboSegment(*this); }
|
|
|
|
ComboSegment( int iStartRow = ROW_INVALID, int iCombo = 1, int iMissCombo = 1 ) :
|
|
TimingSegment(iStartRow), m_iCombo(iCombo),
|
|
m_iMissCombo(iMissCombo) { }
|
|
|
|
ComboSegment(const ComboSegment &other) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_iCombo( other.GetCombo() ),
|
|
m_iMissCombo( other.GetMissCombo() ) { }
|
|
|
|
int GetCombo() const { return m_iCombo; }
|
|
int GetMissCombo() const { return m_iMissCombo; }
|
|
|
|
void SetCombo( int iCombo ) { m_iCombo = iCombo; }
|
|
void SetMissCombo( int iCombo ) { m_iMissCombo = iCombo; }
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const ComboSegment &other ) const
|
|
{
|
|
COMPARE( m_iCombo );
|
|
COMPARE( m_iMissCombo );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const ComboSegment&>(other) );
|
|
}
|
|
private:
|
|
/** @brief The amount the combo increases at this point. */
|
|
int m_iCombo;
|
|
|
|
/** @brief The amount of miss combos given at this point. */
|
|
int m_iMissCombo;
|
|
};
|
|
|
|
|
|
/**
|
|
* @brief Identifies when a chart is entering a different section.
|
|
*
|
|
* This is meant for helping to identify different sections of a chart
|
|
* versus relying on measures and beats alone.
|
|
*/
|
|
struct LabelSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_LABEL; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Indefinite; }
|
|
|
|
bool IsNotable() const { return true; } // indefinite segments are always true
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new LabelSegment(*this); }
|
|
|
|
LabelSegment( int iStartRow = ROW_INVALID, const RString& sLabel = RString() ) :
|
|
TimingSegment(iStartRow), m_sLabel(sLabel) { }
|
|
|
|
LabelSegment(const LabelSegment &other) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_sLabel( other.GetLabel() ) { }
|
|
|
|
const RString& GetLabel() const { return m_sLabel; }
|
|
void SetLabel( const RString& sLabel ) { m_sLabel.assign(sLabel); }
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const LabelSegment &other ) const
|
|
{
|
|
COMPARE( m_sLabel );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const LabelSegment&>(other) );
|
|
}
|
|
private:
|
|
/** @brief The label/section name for this point. */
|
|
RString m_sLabel;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when a song changes its BPM.
|
|
*/
|
|
struct BPMSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_BPM; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Indefinite; }
|
|
|
|
bool IsNotable() const { return true; } // indefinite segments are always true
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new BPMSegment(*this); }
|
|
|
|
// note that this takes a BPM, not a BPS (compatibility)
|
|
BPMSegment( int iStartRow = ROW_INVALID, float fBPM = 0.0f ) :
|
|
TimingSegment(iStartRow) { SetBPM(fBPM); }
|
|
|
|
BPMSegment( const BPMSegment &other ) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_fBPS( other.GetBPS() ) { }
|
|
|
|
float GetBPS() const { return m_fBPS; }
|
|
float GetBPM() const { return m_fBPS * 60.0f; }
|
|
|
|
void SetBPS( float fBPS ) { m_fBPS = fBPS; }
|
|
void SetBPM( float fBPM ) { m_fBPS = fBPM / 60.0f; }
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const BPMSegment &other ) const
|
|
{
|
|
COMPARE_FLOAT( m_fBPS );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const BPMSegment&>(other) );
|
|
}
|
|
|
|
private:
|
|
/** @brief The number of beats per second within this BPMSegment. */
|
|
float m_fBPS;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when a song changes its time signature.
|
|
*
|
|
* This only supports simple time signatures. The upper number
|
|
* (called the numerator here, though this isn't properly a
|
|
* fraction) is the number of beats per measure. The lower number
|
|
* (denominator here) is the note value representing one beat. */
|
|
struct TimeSignatureSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_TIME_SIG; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Indefinite; }
|
|
|
|
bool IsNotable() const { return true; } // indefinite segments are always true
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new TimeSignatureSegment(*this); }
|
|
|
|
TimeSignatureSegment( int iStartRow = ROW_INVALID,
|
|
int iNum = 4, int iDenom = 4 ) :
|
|
TimingSegment(iStartRow), m_iNumerator(iNum),
|
|
m_iDenominator(iDenom) { }
|
|
|
|
TimeSignatureSegment( const TimeSignatureSegment &other ) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_iNumerator( other.GetNum() ),
|
|
m_iDenominator( other.GetDen() ) { }
|
|
|
|
int GetNum() const { return m_iNumerator; }
|
|
void SetNum( int num ) { m_iNumerator = num; }
|
|
|
|
int GetDen() const { return m_iDenominator; }
|
|
void SetDen( int den ) { m_iDenominator = den; }
|
|
|
|
void Set( int num, int den ) { m_iNumerator = num; m_iDenominator = den; }
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
/**
|
|
* @brief Retrieve the number of note rows per measure within the TimeSignatureSegment.
|
|
*
|
|
* With BeatToNoteRow(1) rows per beat, then we should have BeatToNoteRow(1)*m_iNumerator
|
|
* beats per measure. But if we assume that every BeatToNoteRow(1) rows is a quarter note,
|
|
* and we want the beats to be 1/m_iDenominator notes, then we should have
|
|
* BeatToNoteRow(1)*4 is rows per whole note and thus BeatToNoteRow(1)*4/m_iDenominator is
|
|
* rows per beat. Multiplying by m_iNumerator gives rows per measure.
|
|
* @returns the number of note rows per measure.
|
|
*/
|
|
int GetNoteRowsPerMeasure() const
|
|
{
|
|
return BeatToNoteRow(1) * 4 * m_iNumerator / m_iDenominator;
|
|
}
|
|
|
|
bool operator==( const TimeSignatureSegment &other ) const
|
|
{
|
|
COMPARE( m_iNumerator );
|
|
COMPARE( m_iDenominator );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const TimeSignatureSegment&>(other) );
|
|
}
|
|
|
|
private:
|
|
int m_iNumerator, m_iDenominator;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when the arrow scroll changes.
|
|
*
|
|
* SpeedSegments take a Player's scrolling BPM (Step's BPM * speed mod),
|
|
* and then multiplies it with the percentage value. No matter the player's
|
|
* speed mod, the ratio will be the same. Unlike forced attacks, these
|
|
* cannot be turned off at a set time: reset it by setting the percentage
|
|
* back to 1.
|
|
*
|
|
* These were inspired by the Pump It Up series. */
|
|
struct SpeedSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_SPEED; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Indefinite; }
|
|
|
|
bool IsNotable() const { return true; } // indefinite segments are always true
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new SpeedSegment(*this); }
|
|
|
|
/** @brief The type of unit used for segment scaling. */
|
|
enum BaseUnit { UNIT_BEATS, UNIT_SECONDS };
|
|
|
|
SpeedSegment( int iStartRow = ROW_INVALID, float fRatio = 1.0f,
|
|
float fDelay = 0.0f, BaseUnit unit = UNIT_BEATS ) :
|
|
TimingSegment(iStartRow), m_fRatio(fRatio), m_fDelay(fDelay),
|
|
m_Unit(unit) { }
|
|
|
|
SpeedSegment(const SpeedSegment &other) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_fRatio( other.GetRatio() ),
|
|
m_fDelay( other.GetDelay() ),
|
|
m_Unit( other.GetUnit() ) { }
|
|
|
|
float GetRatio() const { return m_fRatio; }
|
|
void SetRatio( float fRatio ) { m_fRatio = fRatio; }
|
|
|
|
float GetDelay() const { return m_fDelay; }
|
|
void SetDelay( float fDelay ) { m_fDelay = fDelay; }
|
|
|
|
BaseUnit GetUnit() const { return m_Unit; }
|
|
void SetUnit( BaseUnit unit ) { m_Unit = unit; }
|
|
|
|
void Scale( int start, int length, int newLength );
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const SpeedSegment &other ) const
|
|
{
|
|
COMPARE_FLOAT( m_fRatio );
|
|
COMPARE_FLOAT( m_fDelay );
|
|
COMPARE( m_Unit );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const SpeedSegment&>(other) );
|
|
}
|
|
|
|
private:
|
|
/** @brief The percentage by which the Player's BPM is multiplied. */
|
|
float m_fRatio;
|
|
|
|
/**
|
|
* @brief The number of beats or seconds to wait before applying.
|
|
* A value of 0 means this is immediate. */
|
|
float m_fDelay;
|
|
|
|
/** @brief The mode that this segment uses for the math. */
|
|
BaseUnit m_Unit;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when the chart scroll changes.
|
|
*
|
|
* ScrollSegments adjusts the scrolling speed of the note field.
|
|
* Unlike forced attacks, these cannot be turned off at a set time:
|
|
* reset it by setting the precentage back to 1.
|
|
*
|
|
* These were inspired by the Pump It Up series. */
|
|
struct ScrollSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_SCROLL; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Indefinite; }
|
|
|
|
bool IsNotable() const { return true; } // indefinite segments are always true
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new ScrollSegment(*this); }
|
|
|
|
ScrollSegment( int iStartRow = ROW_INVALID, float fRatio = 1.0f ) :
|
|
TimingSegment(iStartRow), m_fRatio(fRatio) { }
|
|
|
|
ScrollSegment(const ScrollSegment &other) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_fRatio( other.GetRatio() ) { }
|
|
|
|
float GetRatio() const { return m_fRatio; }
|
|
void SetRatio( float fRatio ) { m_fRatio = fRatio; }
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const ScrollSegment &other ) const
|
|
{
|
|
COMPARE_FLOAT( m_fRatio );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const ScrollSegment&>(other) );
|
|
}
|
|
|
|
private:
|
|
/** @brief The percentage by which the chart's scroll rate is multiplied. */
|
|
float m_fRatio;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when a song has a stop, DDR/ITG style.
|
|
*/
|
|
struct StopSegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_STOP; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Row; }
|
|
|
|
bool IsNotable() const { return m_fSeconds > 0; }
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new StopSegment(*this); }
|
|
|
|
StopSegment( int iStartRow = ROW_INVALID, float fSeconds = 0.0f ) :
|
|
TimingSegment(iStartRow), m_fSeconds(fSeconds) { }
|
|
|
|
StopSegment (const StopSegment &other) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_fSeconds( other.GetPause() ) { }
|
|
|
|
float GetPause() const { return m_fSeconds; }
|
|
void SetPause( float fSeconds ) { m_fSeconds = fSeconds; }
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const StopSegment &other ) const
|
|
{
|
|
COMPARE_FLOAT( m_fSeconds );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const StopSegment&>(other) );
|
|
}
|
|
private:
|
|
/** @brief The number of seconds to pause at the segment's row. */
|
|
float m_fSeconds;
|
|
};
|
|
|
|
/**
|
|
* @brief Identifies when a song has a delay, or pump style stop.
|
|
*/
|
|
struct DelaySegment : public TimingSegment
|
|
{
|
|
TimingSegmentType GetType() const { return SEGMENT_DELAY; }
|
|
SegmentEffectType GetEffectType() const { return SegmentEffectType_Row; }
|
|
|
|
bool IsNotable() const { return m_fSeconds > 0; }
|
|
void DebugPrint() const;
|
|
|
|
TimingSegment* Copy() const { return new DelaySegment(*this); }
|
|
|
|
DelaySegment( int iStartRow = ROW_INVALID, float fSeconds = 0 ) :
|
|
TimingSegment(iStartRow), m_fSeconds(fSeconds) { }
|
|
|
|
DelaySegment( const DelaySegment &other ) :
|
|
TimingSegment( other.GetRow() ),
|
|
m_fSeconds( other.GetPause() ) { }
|
|
|
|
float GetPause() const { return m_fSeconds; }
|
|
void SetPause( float fSeconds ) { m_fSeconds = fSeconds; }
|
|
|
|
RString ToString( int dec ) const;
|
|
|
|
bool operator==( const DelaySegment &other ) const
|
|
{
|
|
COMPARE_FLOAT( m_fSeconds );
|
|
return true;
|
|
}
|
|
|
|
bool operator==( const TimingSegment &other ) const
|
|
{
|
|
if( GetType() != other.GetType() )
|
|
return false;
|
|
|
|
return operator==( static_cast<const DelaySegment&>(other) );
|
|
}
|
|
private:
|
|
/** @brief The number of seconds to pause at the segment's row. */
|
|
float m_fSeconds;
|
|
};
|
|
|
|
#undef COMPARE
|
|
#undef COMPARE_FLOAT
|
|
|
|
#endif
|
|
|
|
/**
|
|
* @file
|
|
* @author Jason Felds (c) 2011
|
|
* @section LICENSE
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
* whom the Software is furnished to do so, provided that the above
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
* the Software and that both the above copyright notice(s) and this
|
|
* permission notice appear in supporting documentation.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|