add echo, planted, stomp transforms

This commit is contained in:
Chris Danford
2003-11-07 05:17:41 +00:00
parent 0e05d91242
commit cf579908cb
10 changed files with 203 additions and 29 deletions
+9 -3
View File
@@ -1741,8 +1741,8 @@ ExplanationTogetherX=70
ExplanationTogetherY=412
ExplanationTogetherOnCommand=wrapwidthpixels,1000;horizalign,left;cropright,1;linear,0.5;cropright,0
ExplanationZoom=0.5
ExplanationP1OnCommand=wrapwidthpixels,600;horizalign,left;cropright,1;linear,0.5;cropright,0
ExplanationP2OnCommand=wrapwidthpixels,600;horizalign,right;cropright,1;linear,0.5;cropright,0
ExplanationP1OnCommand=wrapwidthpixels,500;horizalign,left;cropright,1;linear,0.5;cropright,0
ExplanationP2OnCommand=wrapwidthpixels,500;horizalign,right;cropright,1;linear,0.5;cropright,0
ColorSelected=1,1,1,1 // normal
ColorNotSelected=0.5,0.5,0.5,1 // grayed
NumShownItems=10
@@ -2940,7 +2940,7 @@ TurnName,5=SHUFFLE
Turn,6=mod,supershuffle
TurnName,6=S.SHUFFLE
Transform=7
Transform=10
TransformDefault=mod,no transform
Transform,1=
TransformName,1=OFF
@@ -2956,6 +2956,12 @@ Transform,6=mod,skippy
TransformName,6=SKIPPY
Transform,7=mod,mines
TransformName,7=MINES
Transform,8=mod,echo
TransformName,8=ECHO
Transform,9=mod,planted
TransformName,9=PLANTED
Transform,10=mod,stomp
TransformName,10=STOMP
Scroll=4
ScrollDefault=mod,no reverse,no split,no alternate
+15 -9
View File
@@ -174,15 +174,6 @@ void NoteData::RemoveHoldNote( int iHoldIndex )
m_HoldNotes.erase(m_HoldNotes.begin()+iHoldIndex, m_HoldNotes.begin()+iHoldIndex+1);
}
bool NoteData::IsThereATapAtRow( int iRow ) const
{
for( int t=0; t<m_iNumTracks; t++ )
if( GetTapNote(t, iRow) != TAP_EMPTY )
return true;
return false;
}
int NoteData::GetFirstRow() const
{
return BeatToNoteRow( GetFirstBeat() );
@@ -606,3 +597,18 @@ void NoteData::EliminateAllButOneTap(int row)
m_TapNotes[track][row] = TAP_EMPTY;
}
}
int NoteData::GetNumTracksHeldAtRow( int row )
{
// Optimization opportunity:
// Search more efficiently knowing that m_HoldNotes is sorted.
int iNumTracksHeld = 0;
float fBeat = NoteRowToBeat(row);
for( unsigned i=0; i<m_HoldNotes.size(); i++ )
{
const HoldNote& hn = m_HoldNotes[i];
if( fBeat >= hn.fStartBeat && fBeat <= hn.fEndBeat )
iNumTracksHeld++;
}
return iNumTracksHeld;
}
+5 -1
View File
@@ -98,6 +98,11 @@ public:
return t;
return -1;
}
inline bool IsThereATapAtRow( int index ) const
{
return GetFirstTrackWithTap( index ) != -1;
}
int GetNumTracksHeldAtRow( int row );
// used in edit/record
void AddHoldNote( HoldNote newNote ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath
@@ -106,7 +111,6 @@ public:
const HoldNote &GetHoldNote( int index ) const { return m_HoldNotes[index]; }
// statistics
bool IsThereATapAtRow( int iRow ) const;
/* Return the highest beat/row that might contain notes. (Use GetLastBeat if you need
* accuracy.) */
+145
View File
@@ -689,6 +689,148 @@ void NoteDataUtil::Mines( NoteData &in, float fStartBeat, float fEndBeat )
}
}
void NoteDataUtil::Echo( NoteData &in, float fStartBeat, float fEndBeat )
{
// add 8th note tap "echos" after all taps
int iEchoTrack = -1;
fStartBeat = froundf( fStartBeat, 0.5 );
const int first_row = BeatToNoteRow( fStartBeat );
const int last_row = min( BeatToNoteRow(fEndBeat), in.GetLastRow() );
const int rows_per_interval = BeatToNoteRow( 0.5 );
// window is one beat wide and slides 1/2 a beat at a time
for( int r=first_row; r<last_row; r+=rows_per_interval )
{
int iRowWindowBegin = r;
int iRowWindowEnd = r + rows_per_interval*2;
float fBeatWindowBegin = NoteRowToBeat(iRowWindowBegin);
float fBeatWindowEnd = NoteRowToBeat(iRowWindowEnd);
int iRowEcho = r + rows_per_interval;
int iFirstTapInRow = in.GetFirstTrackWithTap(iRowWindowBegin);
if( iFirstTapInRow != -1 )
{
iEchoTrack = iFirstTapInRow;
}
// don't insert a new note if there's already a tap within this interval
bool bTapInMiddle = false;
for( int r2=iRowWindowBegin+1; r2<=iRowWindowEnd-1; r2++ )
if( in.IsThereATapAtRow(r2) )
{
bTapInMiddle = true;
break;
}
if( bTapInMiddle )
continue;
// don't insert a new note if there's already a hold headwithin this interval
// TODO: Why is this necessary? Isn't there a TAP_TAP at the HoldNote head spot?
for( int i=0; i<in.GetNumHoldNotes(); i++ )
{
int iHoldHeadRow = BeatToNoteRow(in.GetHoldNote(i).fStartBeat);
if( iHoldHeadRow >= iRowWindowBegin+1 && iHoldHeadRow <= iRowWindowEnd-1 )
{
bTapInMiddle = true;
break;
}
}
if( bTapInMiddle )
continue;
if( iEchoTrack==-1 )
continue;
int iNumTracksHeld = in.GetNumTracksHeldAtRow(iRowEcho);
if( iNumTracksHeld >= 2 )
continue;
in.SetTapNote( iEchoTrack, iRowEcho, TAP_ADDITION );
}
}
void NoteDataUtil::Planted( NoteData &in, float fStartBeat, float fEndBeat )
{
// Convert all taps to freezes.
const int first_row = BeatToNoteRow( fStartBeat );
const int last_row = min( BeatToNoteRow(fEndBeat), in.GetLastRow() );
for( int r=first_row; r<=last_row; r++ )
{
for( int t=0; t<in.GetNumTracks(); t++ )
{
if( in.GetTapNote(t,r) == TAP_TAP )
{
// search for row of next TAP_TAP
for( int r2=r+1; r2<=last_row; r2++ )
{
if( in.IsThereATapAtRow(r2) )
{
// If there are two taps in a row on the same track,
// don't convert the earlier one to a hold.
if( in.GetFirstTrackWithTap(r2) == t )
goto dont_add_hold;
break; // stop searching
}
}
float fStartBeat = NoteRowToBeat(r);
float fEndBeat = NoteRowToBeat(r2);
// If the steps end in a tap, convert that tap
// to a hold that lasts for at least one beat.
if( r2==r+1 )
fEndBeat = fStartBeat+1;
in.AddHoldNote( HoldNote(t,fStartBeat,fEndBeat) );
}
dont_add_hold:
int blah = 0; // shut compiler up
}
}
}
void NoteDataUtil::Stomp( NoteData &in, float fStartBeat, float fEndBeat )
{
// Make all non jumps with ample space around them into jumps.
const int first_row = BeatToNoteRow( fStartBeat );
const int last_row = min( BeatToNoteRow(fEndBeat), in.GetLastRow() );
for( int r=first_row; r<last_row; r++ )
{
if( in.GetNumTracksWithTap(r) != 1 )
continue; // skip
for( int t=0; t<in.GetNumTracks(); t++ )
{
if( in.GetTapNote(t, r) == TAP_TAP ) // there is a tap here
{
// Look to see if there is enough empty space on either side of the note
// to turn this into a jump.
int iRowWindowBegin = r - BeatToNoteRow(0.5);
int iRowWindowEnd = r + BeatToNoteRow(0.5);
bool bTapInMiddle = false;
for( int r2=iRowWindowBegin+1; r2<=iRowWindowEnd-1; r2++ )
if( in.IsThereATapAtRow(r2) && r2 != r ) // don't count the note we're looking around
{
bTapInMiddle = true;
break;
}
if( bTapInMiddle )
continue;
// don't convert to jump if there's a hold here
int iNumTracksHeld = in.GetNumTracksHeldAtRow(r);
if( iNumTracksHeld >= 1 )
continue;
// TODO: Make this accurate for StepsTypes other than 4 panel cross.
int iOppositeTrack = in.GetNumTracks()-1-t;
in.SetTapNote( iOppositeTrack, r, TAP_ADDITION );
}
}
}
}
void NoteDataUtil::SnapToNearestNoteType( NoteData &in, NoteType nt1, NoteType nt2, float fBeginBeat, float fEndBeat )
{
@@ -984,6 +1126,9 @@ void NoteDataUtil::TransformNoteData( NoteData &nd, const PlayerOptions &po, Ste
case PlayerOptions::TRANSFORM_QUICK: NoteDataUtil::Quick(nd, fStartBeat, fEndBeat); break;
case PlayerOptions::TRANSFORM_SKIPPY: NoteDataUtil::Skippy(nd, fStartBeat, fEndBeat); break;
case PlayerOptions::TRANSFORM_MINES: NoteDataUtil::Mines(nd, fStartBeat, fEndBeat); break;
case PlayerOptions::TRANSFORM_ECHO: NoteDataUtil::Echo(nd, fStartBeat, fEndBeat); break;
case PlayerOptions::TRANSFORM_PLANTED: NoteDataUtil::Planted(nd, fStartBeat, fEndBeat); break;
case PlayerOptions::TRANSFORM_STOMP: NoteDataUtil::Stomp(nd, fStartBeat, fEndBeat); break;
default: ASSERT(0);
}
}
+4 -1
View File
@@ -47,8 +47,11 @@ namespace NoteDataUtil
void Big( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void Quick( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void Skippy( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void Mines( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void InsertIntelligentTaps( NoteData &in, float fBeatInterval, float fInsertBeatOffset, bool bSkippy, float fStartBeat = 0, float fEndBeat = 99999 );
void Mines( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void Echo( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void Planted( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void Stomp( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void SuperShuffleTaps( NoteData &in );
// change all TAP_ADDITIONs to TAP_TAPs
+6
View File
@@ -154,6 +154,9 @@ CString PlayerOptions::GetString() const
case TRANSFORM_QUICK: sReturn += "Quick, "; break;
case TRANSFORM_SKIPPY: sReturn += "Skippy, "; break;
case TRANSFORM_MINES: sReturn += "Mines, "; break;
case TRANSFORM_ECHO: sReturn += "Echo, "; break;
case TRANSFORM_PLANTED: sReturn += "Planted, "; break;
case TRANSFORM_STOMP: sReturn += "Stomp, "; break;
default: ASSERT(0); // invalid
}
@@ -280,6 +283,9 @@ void PlayerOptions::FromString( CString sOptions )
else if( sBit == "quick" ) m_Transform = TRANSFORM_QUICK;
else if( sBit == "skippy" ) m_Transform = TRANSFORM_SKIPPY;
else if( sBit == "mines" ) m_Transform = TRANSFORM_MINES;
else if( sBit == "echo" ) m_Transform = TRANSFORM_ECHO;
else if( sBit == "planted" ) m_Transform = TRANSFORM_PLANTED;
else if( sBit == "stomp" ) m_Transform = TRANSFORM_STOMP;
else if( sBit == "reverse" ) SET_FLOAT( fScrolls[SCROLL_REVERSE] )
else if( sBit == "split" ) SET_FLOAT( fScrolls[SCROLL_SPLIT] )
else if( sBit == "alternate" ) SET_FLOAT( fScrolls[SCROLL_ALTERNATE] )
+3
View File
@@ -65,6 +65,9 @@ struct PlayerOptions
TRANSFORM_QUICK,
TRANSFORM_SKIPPY,
TRANSFORM_MINES,
TRANSFORM_ECHO,
TRANSFORM_PLANTED,
TRANSFORM_STOMP,
NUM_TRANSFORMS
};
enum Scroll {
+5 -1
View File
@@ -156,7 +156,7 @@ Menu g_AreaMenu
MenuRow( "Clear", true ),
MenuRow( "Quantize", true, 0, "4TH","8TH","12TH","16TH","24TH","32ND","48TH","64TH" ),
MenuRow( "Turn", true, 0, "Left","Right","Mirror","Shuffle","Super Shuffle" ),
MenuRow( "Transform", true, 0, "Little","Wide","Big","Quick","Skippy" ),
MenuRow( "Transform", true, 0, "Little","Wide","Big","Quick","Skippy","Mines","Echo","Planted","Stomp" ),
MenuRow( "Alter", true, 0, "Backwards","Swap Sides","Copy Left To Right","Copy Right To Left","Clear Left","Clear Right","Collapse To One","Shift Left","Shift Right" ),
MenuRow( "Tempo", true, 0, "Compress 2x","Compress 3->2","Compress 4->3","Expand 3->4","Expand 2->3","Expand 2x" ),
MenuRow( "Play selection", true ),
@@ -1538,6 +1538,10 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
case big: NoteDataUtil::Big( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
case quick: NoteDataUtil::Quick( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
case skippy: NoteDataUtil::Skippy( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
case mines: NoteDataUtil::Mines( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
case echo: NoteDataUtil::Echo( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
case planted: NoteDataUtil::Planted( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
case stomp: NoteDataUtil::Stomp( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
default: ASSERT(0);
}
+1 -1
View File
@@ -137,7 +137,7 @@ public:
};
void HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers );
enum TurnType { left, right, mirror, shuffle, super_shuffle, NUM_TURN_TYPES };
enum TransformType { little, wide, big, quick, skippy, NUM_TRANSFORM_TYPES };
enum TransformType { little, wide, big, quick, skippy, mines, echo, planted, stomp, NUM_TRANSFORM_TYPES };
enum AlterType { backwards, swap_sides, copy_left_to_right, copy_right_to_left, clear_left, clear_right, collapse_to_one, shift_left, shift_right, NUM_ALTER_TYPES };
// MD 11/02/03 - added additional tempo adjusts which make "sense"
enum TempoType { compress_2x, compress_3_2, compress_4_3, expand_4_3, expand_3_2, expand_2x, NUM_TEMPO_TYPES };
+10 -13
View File
@@ -210,24 +210,21 @@ void ScreenOptions::Init( InputMode im, OptionRow OptionRows[], int iNumOptionLi
}
// add explanation here so it appears on top
for( p=0; p<NUM_PLAYERS; p++ )
{
m_textExplanation[p].LoadFromFont( THEME->GetPathToF("ScreenOptions explanation") );
m_textExplanation[p].SetZoom( EXPLANATION_ZOOM );
m_textExplanation[p].SetShadowLength( 0 );
m_framePage.AddChild( &m_textExplanation[p] );
}
switch( m_InputMode )
{
case INPUTMODE_INDIVIDUAL:
for( p=0; p<NUM_PLAYERS; p++ )
{
m_textExplanation[p].LoadFromFont( THEME->GetPathToF("ScreenOptions explanation") );
m_textExplanation[p].SetXY( EXPLANATION_X(p), EXPLANATION_Y(p) );
m_textExplanation[p].SetZoom( EXPLANATION_ZOOM );
m_textExplanation[p].SetShadowLength( 0 );
m_framePage.AddChild( &m_textExplanation[p] );
}
break;
case INPUTMODE_TOGETHER:
m_textExplanation[0].LoadFromFont( THEME->GetPathToF("ScreenOptions explanation") );
m_textExplanation[0].SetXY( EXPLANATION_TOGETHER_X, EXPLANATION_TOGETHER_Y );
m_textExplanation[0].SetZoom( EXPLANATION_ZOOM );
m_textExplanation[0].SetShadowLength( 0 );
m_framePage.AddChild( &m_textExplanation[0] );
break;
default:
ASSERT(0);
@@ -891,7 +888,7 @@ void ScreenOptions::ChangeValue( PlayerNumber pn, int iDelta )
m_iSelectedOption[p][iCurRow] = iNewSel;
UpdateText( (PlayerNumber)p, iCurRow );
}
OnChange( pn );
OnChange( (PlayerNumber)p );
}
m_SoundChangeCol.Play();
}
@@ -908,7 +905,7 @@ void ScreenOptions::MenuUp( PlayerNumber pn )
m_iCurrentRow[p] = m_iNumOptionRows; // on exit
else
m_iCurrentRow[p]--;
OnChange( pn );
OnChange( (PlayerNumber)p );
}
m_SoundPrevRow.Play();
}
@@ -925,7 +922,7 @@ void ScreenOptions::MenuDown( PlayerNumber pn )
m_iCurrentRow[p] = 0; // on first row
else
m_iCurrentRow[p]++;
OnChange( pn );
OnChange( (PlayerNumber)p );
}
m_SoundNextRow.Play();
}