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 ExplanationTogetherY=412
ExplanationTogetherOnCommand=wrapwidthpixels,1000;horizalign,left;cropright,1;linear,0.5;cropright,0 ExplanationTogetherOnCommand=wrapwidthpixels,1000;horizalign,left;cropright,1;linear,0.5;cropright,0
ExplanationZoom=0.5 ExplanationZoom=0.5
ExplanationP1OnCommand=wrapwidthpixels,600;horizalign,left;cropright,1;linear,0.5;cropright,0 ExplanationP1OnCommand=wrapwidthpixels,500;horizalign,left;cropright,1;linear,0.5;cropright,0
ExplanationP2OnCommand=wrapwidthpixels,600;horizalign,right;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 ColorSelected=1,1,1,1 // normal
ColorNotSelected=0.5,0.5,0.5,1 // grayed ColorNotSelected=0.5,0.5,0.5,1 // grayed
NumShownItems=10 NumShownItems=10
@@ -2940,7 +2940,7 @@ TurnName,5=SHUFFLE
Turn,6=mod,supershuffle Turn,6=mod,supershuffle
TurnName,6=S.SHUFFLE TurnName,6=S.SHUFFLE
Transform=7 Transform=10
TransformDefault=mod,no transform TransformDefault=mod,no transform
Transform,1= Transform,1=
TransformName,1=OFF TransformName,1=OFF
@@ -2956,6 +2956,12 @@ Transform,6=mod,skippy
TransformName,6=SKIPPY TransformName,6=SKIPPY
Transform,7=mod,mines Transform,7=mod,mines
TransformName,7=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 Scroll=4
ScrollDefault=mod,no reverse,no split,no alternate 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); 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 int NoteData::GetFirstRow() const
{ {
return BeatToNoteRow( GetFirstBeat() ); return BeatToNoteRow( GetFirstBeat() );
@@ -606,3 +597,18 @@ void NoteData::EliminateAllButOneTap(int row)
m_TapNotes[track][row] = TAP_EMPTY; 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 t;
return -1; return -1;
} }
inline bool IsThereATapAtRow( int index ) const
{
return GetFirstTrackWithTap( index ) != -1;
}
int GetNumTracksHeldAtRow( int row );
// used in edit/record // used in edit/record
void AddHoldNote( HoldNote newNote ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath 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]; } const HoldNote &GetHoldNote( int index ) const { return m_HoldNotes[index]; }
// statistics // statistics
bool IsThereATapAtRow( int iRow ) const;
/* Return the highest beat/row that might contain notes. (Use GetLastBeat if you need /* Return the highest beat/row that might contain notes. (Use GetLastBeat if you need
* accuracy.) */ * 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 ) 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_QUICK: NoteDataUtil::Quick(nd, fStartBeat, fEndBeat); break;
case PlayerOptions::TRANSFORM_SKIPPY: NoteDataUtil::Skippy(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_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); default: ASSERT(0);
} }
} }
+4 -1
View File
@@ -47,8 +47,11 @@ namespace NoteDataUtil
void Big( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 ); void Big( NoteData &in, float fStartBeat = 0, float fEndBeat = 99999 );
void Quick( 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 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 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 ); void SuperShuffleTaps( NoteData &in );
// change all TAP_ADDITIONs to TAP_TAPs // 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_QUICK: sReturn += "Quick, "; break;
case TRANSFORM_SKIPPY: sReturn += "Skippy, "; break; case TRANSFORM_SKIPPY: sReturn += "Skippy, "; break;
case TRANSFORM_MINES: sReturn += "Mines, "; 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 default: ASSERT(0); // invalid
} }
@@ -280,6 +283,9 @@ void PlayerOptions::FromString( CString sOptions )
else if( sBit == "quick" ) m_Transform = TRANSFORM_QUICK; else if( sBit == "quick" ) m_Transform = TRANSFORM_QUICK;
else if( sBit == "skippy" ) m_Transform = TRANSFORM_SKIPPY; else if( sBit == "skippy" ) m_Transform = TRANSFORM_SKIPPY;
else if( sBit == "mines" ) m_Transform = TRANSFORM_MINES; 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 == "reverse" ) SET_FLOAT( fScrolls[SCROLL_REVERSE] )
else if( sBit == "split" ) SET_FLOAT( fScrolls[SCROLL_SPLIT] ) else if( sBit == "split" ) SET_FLOAT( fScrolls[SCROLL_SPLIT] )
else if( sBit == "alternate" ) SET_FLOAT( fScrolls[SCROLL_ALTERNATE] ) else if( sBit == "alternate" ) SET_FLOAT( fScrolls[SCROLL_ALTERNATE] )
+3
View File
@@ -65,6 +65,9 @@ struct PlayerOptions
TRANSFORM_QUICK, TRANSFORM_QUICK,
TRANSFORM_SKIPPY, TRANSFORM_SKIPPY,
TRANSFORM_MINES, TRANSFORM_MINES,
TRANSFORM_ECHO,
TRANSFORM_PLANTED,
TRANSFORM_STOMP,
NUM_TRANSFORMS NUM_TRANSFORMS
}; };
enum Scroll { enum Scroll {
+5 -1
View File
@@ -156,7 +156,7 @@ Menu g_AreaMenu
MenuRow( "Clear", true ), MenuRow( "Clear", true ),
MenuRow( "Quantize", true, 0, "4TH","8TH","12TH","16TH","24TH","32ND","48TH","64TH" ), MenuRow( "Quantize", true, 0, "4TH","8TH","12TH","16TH","24TH","32ND","48TH","64TH" ),
MenuRow( "Turn", true, 0, "Left","Right","Mirror","Shuffle","Super Shuffle" ), 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( "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( "Tempo", true, 0, "Compress 2x","Compress 3->2","Compress 4->3","Expand 3->4","Expand 2->3","Expand 2x" ),
MenuRow( "Play selection", true ), 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 big: NoteDataUtil::Big( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
case quick: NoteDataUtil::Quick( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break; case quick: NoteDataUtil::Quick( m_NoteFieldEdit, fBeginBeat, fEndBeat ); break;
case skippy: NoteDataUtil::Skippy( 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); default: ASSERT(0);
} }
+1 -1
View File
@@ -137,7 +137,7 @@ public:
}; };
void HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers ); void HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers );
enum TurnType { left, right, mirror, shuffle, super_shuffle, NUM_TURN_TYPES }; 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 }; 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" // 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 }; enum TempoType { compress_2x, compress_3_2, compress_4_3, expand_4_3, expand_3_2, expand_2x, NUM_TEMPO_TYPES };
+8 -11
View File
@@ -210,24 +210,21 @@ void ScreenOptions::Init( InputMode im, OptionRow OptionRows[], int iNumOptionLi
} }
// add explanation here so it appears on top // add explanation here so it appears on top
switch( m_InputMode )
{
case INPUTMODE_INDIVIDUAL:
for( p=0; p<NUM_PLAYERS; p++ ) for( p=0; p<NUM_PLAYERS; p++ )
{ {
m_textExplanation[p].LoadFromFont( THEME->GetPathToF("ScreenOptions explanation") ); 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].SetZoom( EXPLANATION_ZOOM );
m_textExplanation[p].SetShadowLength( 0 ); m_textExplanation[p].SetShadowLength( 0 );
m_framePage.AddChild( &m_textExplanation[p] ); m_framePage.AddChild( &m_textExplanation[p] );
} }
switch( m_InputMode )
{
case INPUTMODE_INDIVIDUAL:
for( p=0; p<NUM_PLAYERS; p++ )
m_textExplanation[p].SetXY( EXPLANATION_X(p), EXPLANATION_Y(p) );
break; break;
case INPUTMODE_TOGETHER: case INPUTMODE_TOGETHER:
m_textExplanation[0].LoadFromFont( THEME->GetPathToF("ScreenOptions explanation") );
m_textExplanation[0].SetXY( EXPLANATION_TOGETHER_X, EXPLANATION_TOGETHER_Y ); 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; break;
default: default:
ASSERT(0); ASSERT(0);
@@ -891,7 +888,7 @@ void ScreenOptions::ChangeValue( PlayerNumber pn, int iDelta )
m_iSelectedOption[p][iCurRow] = iNewSel; m_iSelectedOption[p][iCurRow] = iNewSel;
UpdateText( (PlayerNumber)p, iCurRow ); UpdateText( (PlayerNumber)p, iCurRow );
} }
OnChange( pn ); OnChange( (PlayerNumber)p );
} }
m_SoundChangeCol.Play(); m_SoundChangeCol.Play();
} }
@@ -908,7 +905,7 @@ void ScreenOptions::MenuUp( PlayerNumber pn )
m_iCurrentRow[p] = m_iNumOptionRows; // on exit m_iCurrentRow[p] = m_iNumOptionRows; // on exit
else else
m_iCurrentRow[p]--; m_iCurrentRow[p]--;
OnChange( pn ); OnChange( (PlayerNumber)p );
} }
m_SoundPrevRow.Play(); m_SoundPrevRow.Play();
} }
@@ -925,7 +922,7 @@ void ScreenOptions::MenuDown( PlayerNumber pn )
m_iCurrentRow[p] = 0; // on first row m_iCurrentRow[p] = 0; // on first row
else else
m_iCurrentRow[p]++; m_iCurrentRow[p]++;
OnChange( pn ); OnChange( (PlayerNumber)p );
} }
m_SoundNextRow.Play(); m_SoundNextRow.Play();
} }