2002-04-16 17:31:00 +00:00
# include "stdafx.h"
/*
-----------------------------------------------------------------------------
2002-07-27 19:29:51 +00:00
Class: NoteData
2002-04-16 17:31:00 +00:00
2002-07-02 00:27:58 +00:00
Desc: See header.
2002-04-16 17:31:00 +00:00
2002-05-19 01:59:48 +00:00
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
2002-04-16 17:31:00 +00:00
Chris Danford
-----------------------------------------------------------------------------
*/
# include "NoteData.h"
# include "RageUtil.h"
2002-05-01 19:14:55 +00:00
# include "GameConstantsAndTypes.h"
2002-07-23 01:41:40 +00:00
# include "PrefsManager.h"
2002-04-16 17:31:00 +00:00
# include "ArrowEffects.h"
# include "PrefsManager.h"
2002-05-01 19:14:55 +00:00
# include "GameConstantsAndTypes.h"
2002-07-27 19:29:51 +00:00
# include "RageException.h"
2002-08-01 20:30:40 +00:00
# include "GameState.h"
2002-10-28 05:30:45 +00:00
# include "math.h"
2002-12-13 22:09:26 +00:00
# include "NotesLoaderSM.h"
2002-04-16 17:31:00 +00:00
NoteData : : NoteData ( )
2002-06-24 22:04:31 +00:00
{
Init ( ) ;
}
void NoteData : : Init ( )
2002-04-16 17:31:00 +00:00
{
m_iNumTracks = 0 ;
}
2002-05-19 01:59:48 +00:00
NoteData : : ~ NoteData ( )
{
}
2003-02-01 05:16:38 +00:00
int NoteData : : GetNumTracks ( )
{
return m_iNumTracks ;
}
void NoteData : : SetNumTracks ( int iNewNumTracks )
{
m_iNumTracks = iNewNumTracks ;
}
2002-10-12 19:57:18 +00:00
/* Clear [iNoteIndexBegin,iNoteIndexEnd]; that is, including iNoteIndexEnd. */
2002-05-27 08:23:27 +00:00
void NoteData : : ClearRange ( int iNoteIndexBegin , int iNoteIndexEnd )
2002-04-16 17:31:00 +00:00
{
2002-08-25 05:00:23 +00:00
this - > ConvertHoldNotesTo4s ( ) ;
for ( int c = 0 ; c < m_iNumTracks ; c + + )
2002-04-16 17:31:00 +00:00
{
2002-12-18 07:35:21 +00:00
for ( int i = iNoteIndexBegin ; i < = iNoteIndexEnd ; i + + )
2002-10-25 05:19:27 +00:00
SetTapNote ( c , i , TAP_EMPTY ) ;
2002-04-16 17:31:00 +00:00
}
2002-08-25 05:00:23 +00:00
this - > Convert4sToHoldNotes ( ) ;
2002-04-16 17:31:00 +00:00
}
2002-08-25 05:00:23 +00:00
2002-12-14 20:30:49 +00:00
void NoteData : : ClearAll ( )
{
for ( int t = 0 ; t < m_iNumTracks ; t + + )
m_TapNotes [ t ] . clear ( ) ;
m_HoldNotes . clear ( ) ;
}
2002-08-25 05:00:23 +00:00
/* Copy a range from pFrom to this. (Note that this does *not* overlay;
* all data in the range is overwritten.) */
2002-06-29 11:59:09 +00:00
void NoteData : : CopyRange ( NoteData * pFrom , int iFromIndexBegin , int iFromIndexEnd , int iToIndexBegin )
2002-04-16 17:31:00 +00:00
{
ASSERT ( pFrom - > m_iNumTracks = = m_iNumTracks ) ;
2002-06-29 11:59:09 +00:00
if ( iToIndexBegin = = - 1 )
2002-07-02 00:27:58 +00:00
iToIndexBegin = 0 ;
2002-06-29 11:59:09 +00:00
2002-08-25 05:00:23 +00:00
pFrom - > ConvertHoldNotesTo4s ( ) ;
this - > ConvertHoldNotesTo4s ( ) ;
2002-04-16 17:31:00 +00:00
// copy recorded TapNotes
2002-08-25 05:00:23 +00:00
int f = iFromIndexBegin , t = iToIndexBegin ;
2002-06-29 11:59:09 +00:00
2002-12-18 07:35:21 +00:00
while ( f < = iFromIndexEnd )
2002-04-16 17:31:00 +00:00
{
for ( int c = 0 ; c < m_iNumTracks ; c + + )
2002-10-12 21:40:55 +00:00
SetTapNote ( c , t , pFrom - > GetTapNote ( c , f ) ) ;
2002-06-29 11:59:09 +00:00
f + + ;
t + + ;
2002-04-16 17:31:00 +00:00
}
2002-08-25 05:00:23 +00:00
pFrom - > Convert4sToHoldNotes ( ) ;
this - > Convert4sToHoldNotes ( ) ;
2002-04-16 17:31:00 +00:00
}
2002-12-13 01:23:26 +00:00
void NoteData : : Config ( const NoteData & From )
{
m_iNumTracks = From . m_iNumTracks ;
}
void NoteData : : CopyAll ( NoteData * pFrom )
{
Config ( * pFrom ) ;
2003-01-21 03:12:24 +00:00
ClearAll ( ) ;
2002-12-18 07:35:21 +00:00
CopyRange ( pFrom , 0 , pFrom - > GetLastRow ( ) ) ;
2002-12-13 01:23:26 +00:00
}
2002-04-16 17:31:00 +00:00
void NoteData : : AddHoldNote ( HoldNote add )
{
2002-09-10 23:53:51 +00:00
ASSERT ( add . m_fStartBeat > = 0 & & add . m_fEndBeat > = 0 ) ;
2002-09-09 05:22:02 +00:00
2002-04-16 17:31:00 +00:00
int i ;
// look for other hold notes that overlap and merge them
2002-10-14 00:28:27 +00:00
// XXX: this is done implicitly with 4s, but 4s uses this function.
// Rework this later.
2002-11-02 22:59:12 +00:00
for ( i = 0 ; i < GetNumHoldNotes ( ) ; i + + ) // for each HoldNote
2002-04-16 17:31:00 +00:00
{
2002-11-02 22:53:04 +00:00
HoldNote & other = GetHoldNote ( i ) ;
2002-10-05 14:47:03 +00:00
if ( add . m_iTrack = = other . m_iTrack & & // the tracks correspond
// they overlap
(
( other . m_fStartBeat < = add . m_fStartBeat & & other . m_fEndBeat > = add . m_fEndBeat ) | | // other consumes add
( other . m_fStartBeat > = add . m_fStartBeat & & other . m_fEndBeat < = add . m_fEndBeat ) | | // other inside add
( add . m_fStartBeat < = other . m_fStartBeat & & other . m_fStartBeat < = add . m_fEndBeat ) | | // other overlaps add
( add . m_fStartBeat < = other . m_fEndBeat & & other . m_fEndBeat < = add . m_fEndBeat ) // other overlaps add
)
)
2002-04-16 17:31:00 +00:00
{
2002-08-13 23:26:46 +00:00
add . m_fStartBeat = min ( add . m_fStartBeat , other . m_fStartBeat ) ;
add . m_fEndBeat = max ( add . m_fEndBeat , other . m_fEndBeat ) ;
2002-04-16 17:31:00 +00:00
// delete this HoldNote
2002-11-02 23:10:38 +00:00
m_HoldNotes . erase ( m_HoldNotes . begin ( ) + i , m_HoldNotes . begin ( ) + i + 1 ) ;
2002-04-16 17:31:00 +00:00
}
}
2002-08-13 23:26:46 +00:00
int iAddStartIndex = BeatToNoteRow ( add . m_fStartBeat ) ;
int iAddEndIndex = BeatToNoteRow ( add . m_fEndBeat ) ;
2002-04-16 17:31:00 +00:00
// delete TapNotes under this HoldNote
2002-08-13 23:26:46 +00:00
for ( i = iAddStartIndex + 1 ; i < = iAddEndIndex ; i + + )
2002-10-25 05:19:27 +00:00
SetTapNote ( add . m_iTrack , i , TAP_EMPTY ) ;
2002-04-16 17:31:00 +00:00
2002-06-14 22:25:22 +00:00
// add a tap note at the start of this hold
2002-10-25 05:19:27 +00:00
SetTapNote ( add . m_iTrack , iAddStartIndex , TAP_HOLD_HEAD ) ; // Hold begin marker. Don't draw this, but do grade it.
2002-06-14 22:25:22 +00:00
2002-11-02 23:10:38 +00:00
m_HoldNotes . push_back ( add ) ;
2002-04-16 17:31:00 +00:00
}
2002-08-13 23:26:46 +00:00
void NoteData : : RemoveHoldNote ( int iHoldIndex )
2002-04-16 17:31:00 +00:00
{
2002-11-02 23:10:38 +00:00
ASSERT ( iHoldIndex > = 0 & & iHoldIndex < GetNumHoldNotes ( ) ) ;
2002-08-13 23:26:46 +00:00
2002-11-02 22:53:04 +00:00
HoldNote & hn = GetHoldNote ( iHoldIndex ) ;
2002-08-13 23:26:46 +00:00
int iHoldStartIndex = BeatToNoteRow ( hn . m_fStartBeat ) ;
2002-04-16 17:31:00 +00:00
2002-06-14 22:25:22 +00:00
// delete a tap note at the start of this hold
2002-10-25 05:19:27 +00:00
SetTapNote ( hn . m_iTrack , iHoldStartIndex , TAP_EMPTY ) ;
2002-06-14 22:25:22 +00:00
// remove from list
2002-11-02 23:10:38 +00:00
m_HoldNotes . erase ( m_HoldNotes . begin ( ) + iHoldIndex , m_HoldNotes . begin ( ) + iHoldIndex + 1 ) ;
2002-04-16 17:31:00 +00:00
}
2002-10-11 20:51:12 +00:00
bool NoteData : : IsThereANoteAtRow ( int iRow ) const
2002-06-24 22:04:31 +00:00
{
for ( int t = 0 ; t < m_iNumTracks ; t + + )
2002-10-25 05:19:27 +00:00
if ( GetTapNote ( t , iRow ) ! = TAP_EMPTY )
2002-06-24 22:04:31 +00:00
return true ;
2002-08-13 23:26:46 +00:00
// There is a tap note at the beginning of every HoldNote start
//
2002-11-02 22:59:12 +00:00
// for( int i=0; i<GetNumHoldNotes(); i++ ) // for each HoldNote
2002-11-02 22:53:04 +00:00
// if( GetHoldNote(i).m_iStartIndex == NoteRowToBeatRow(iRow) )
2002-08-13 23:26:46 +00:00
// return true;
2002-06-24 22:04:31 +00:00
return false ;
}
2002-12-14 20:27:52 +00:00
int NoteData : : GetFirstRow ( ) const
2002-04-16 17:31:00 +00:00
{
2002-08-13 23:26:46 +00:00
return BeatToNoteRow ( GetFirstBeat ( ) ) ;
}
2002-12-14 20:27:52 +00:00
float NoteData : : GetFirstBeat ( ) const
2002-08-13 23:26:46 +00:00
{
float fEarliestBeatFoundSoFar = MAX_BEATS ;
2002-04-16 17:31:00 +00:00
int i ;
2002-11-24 06:59:58 +00:00
int rows = GetLastRow ( ) ;
for ( i = 0 ; i < = rows ; i + + )
2002-07-11 19:02:26 +00:00
{
if ( ! IsRowEmpty ( i ) )
{
2002-08-13 23:26:46 +00:00
fEarliestBeatFoundSoFar = NoteRowToBeat ( i ) ;
2002-07-11 19:02:26 +00:00
break ;
}
}
2002-11-02 22:59:12 +00:00
for ( i = 0 ; i < GetNumHoldNotes ( ) ; i + + )
2002-11-02 22:53:04 +00:00
if ( GetHoldNote ( i ) . m_fStartBeat < fEarliestBeatFoundSoFar )
fEarliestBeatFoundSoFar = GetHoldNote ( i ) . m_fStartBeat ;
2002-04-16 17:31:00 +00:00
2002-07-11 19:02:26 +00:00
2002-08-13 23:26:46 +00:00
if ( fEarliestBeatFoundSoFar = = MAX_BEATS ) // there are no notes
return 0 ;
else
return fEarliestBeatFoundSoFar ;
2002-07-11 19:02:26 +00:00
}
2002-12-13 22:40:42 +00:00
int NoteData : : GetLastRow ( ) const
2002-07-11 19:02:26 +00:00
{
2002-08-13 23:26:46 +00:00
return BeatToNoteRow ( GetLastBeat ( ) ) ;
2002-07-11 19:02:26 +00:00
}
2002-12-13 22:40:42 +00:00
float NoteData : : GetLastBeat ( ) const
2002-07-11 19:02:26 +00:00
{
2002-08-13 23:26:46 +00:00
float fOldestBeatFoundSoFar = 0 ;
2002-07-11 19:02:26 +00:00
int i ;
2002-12-20 02:45:23 +00:00
for ( i = int ( m_TapNotes [ 0 ] . size ( ) ) ; i > = 0 ; i - - ) // iterate back to front
2002-04-16 17:31:00 +00:00
{
2002-07-11 19:02:26 +00:00
if ( ! IsRowEmpty ( i ) )
2002-04-16 17:31:00 +00:00
{
2002-08-13 23:26:46 +00:00
fOldestBeatFoundSoFar = NoteRowToBeat ( i ) ;
2002-07-11 19:02:26 +00:00
break ;
2002-04-16 17:31:00 +00:00
}
}
2002-11-02 22:59:12 +00:00
for ( i = 0 ; i < GetNumHoldNotes ( ) ; i + + )
2002-07-11 19:02:26 +00:00
{
2002-11-02 22:53:04 +00:00
if ( GetHoldNote ( i ) . m_fEndBeat > fOldestBeatFoundSoFar )
fOldestBeatFoundSoFar = GetHoldNote ( i ) . m_fEndBeat ;
2002-07-11 19:02:26 +00:00
}
2002-04-16 17:31:00 +00:00
2002-08-13 23:26:46 +00:00
return fOldestBeatFoundSoFar ;
2002-04-16 17:31:00 +00:00
}
2002-12-13 22:40:42 +00:00
int NoteData : : GetNumTapNotes ( const float fStartBeat , const float fEndBeat ) const
2002-12-14 20:34:38 +00:00
{
2002-06-24 22:04:31 +00:00
int iNumNotes = 0 ;
2003-01-02 09:44:09 +00:00
2002-05-19 01:59:48 +00:00
int iStartIndex = BeatToNoteRow ( fStartBeat ) ;
int iEndIndex = BeatToNoteRow ( fEndBeat ) ;
2003-01-02 09:44:09 +00:00
2002-12-14 20:34:38 +00:00
for ( int t = 0 ; t < m_iNumTracks ; t + + )
2002-09-06 00:21:49 +00:00
{
2002-12-19 04:46:55 +00:00
for ( int i = iStartIndex ; i < = iEndIndex ; i + + )
2002-12-14 20:34:38 +00:00
{
2002-10-25 05:19:27 +00:00
if ( GetTapNote ( t , i ) ! = TAP_EMPTY )
2002-06-24 22:04:31 +00:00
iNumNotes + + ;
2002-12-14 20:34:38 +00:00
}
2002-09-06 00:21:49 +00:00
}
2002-04-16 17:31:00 +00:00
2002-06-24 22:04:31 +00:00
return iNumNotes ;
2002-04-16 17:31:00 +00:00
}
2002-12-13 22:40:42 +00:00
int NoteData : : GetNumDoubles ( const float fStartBeat , const float fEndBeat ) const
2002-05-19 01:59:48 +00:00
{
int iNumDoubles = 0 ;
int iStartIndex = BeatToNoteRow ( fStartBeat ) ;
int iEndIndex = BeatToNoteRow ( fEndBeat ) ;
2002-12-18 07:35:21 +00:00
for ( int i = iStartIndex ; i < = iEndIndex ; i + + )
2002-05-19 01:59:48 +00:00
{
int iNumNotesThisIndex = 0 ;
for ( int t = 0 ; t < m_iNumTracks ; t + + )
{
2002-10-25 05:19:27 +00:00
if ( GetTapNote ( t , i ) ! = TAP_EMPTY )
2002-05-19 01:59:48 +00:00
iNumNotesThisIndex + + ;
}
if ( iNumNotesThisIndex > = 2 )
iNumDoubles + + ;
}
return iNumDoubles ;
}
2002-12-13 22:40:42 +00:00
int NoteData : : GetNumHoldNotes ( const float fStartBeat , const float fEndBeat ) const
2002-05-19 01:59:48 +00:00
{
2002-06-24 22:04:31 +00:00
int iNumHolds = 0 ;
2002-05-19 01:59:48 +00:00
2002-11-02 22:59:12 +00:00
for ( int i = 0 ; i < GetNumHoldNotes ( ) ; i + + )
2002-05-19 01:59:48 +00:00
{
2002-11-02 22:53:04 +00:00
const HoldNote & hn = GetHoldNote ( i ) ;
2002-08-13 23:26:46 +00:00
if ( fStartBeat < = hn . m_fStartBeat & & hn . m_fEndBeat < = fEndBeat )
2002-06-24 22:04:31 +00:00
iNumHolds + + ;
2002-05-19 01:59:48 +00:00
}
2002-06-24 22:04:31 +00:00
return iNumHolds ;
2002-04-16 17:31:00 +00:00
}
2002-06-14 22:25:22 +00:00
int NoteData : : GetPossibleDancePoints ( )
{
//Each song has a certain number of "Dance Points" assigned to it. For regular arrows, this is 2 per arrow. For freeze arrows, it is 6 per arrow. When you add this all up, you get the maximum number of possible "Dance Points".
//
//Your "Dance Points" are calculated as follows:
//
//A "Perfect" is worth 2 points
//A "Great" is worth 1 points
//A "Good" is worth 0 points
//A "Boo" will subtract 4 points
//A "Miss" will subtract 8 points
//An "OK" (Successful Freeze step) will add 6 points
//A "NG" (Unsuccessful Freeze step) is worth 0 points
2003-01-11 08:55:21 +00:00
return GetNumTapNotes ( ) * TapNoteScoreToDancePoints ( TNS_PERFECT ) + // not Marvelous
2002-06-14 22:25:22 +00:00
GetNumHoldNotes ( ) * HoldNoteScoreToDancePoints ( HNS_OK ) ;
}
2002-04-16 17:31:00 +00:00
2002-11-02 23:10:38 +00:00
/* ConvertHoldNotesTo2sAnd3s also clears m_iHoldNotes;
2002-08-25 05:00:23 +00:00
* shouldn't this do likewise and set all 2/3's to 0?
* -glenn
2002-09-06 05:24:59 +00:00
*
2002-10-25 04:59:12 +00:00
* Other code assumes != TAP_EMPTY means there's a tap note, so I changed
2002-09-06 05:24:59 +00:00
* this to do this. -glenn
*
2002-10-25 05:06:52 +00:00
* This code intentially leaves the TAP_HOLD_HEAD behind because a hold head is
2002-10-20 21:39:13 +00:00
* treated exactly like a tap note for scoring purposes.
2002-08-25 05:00:23 +00:00
*/
2002-04-16 17:31:00 +00:00
void NoteData : : Convert2sAnd3sToHoldNotes ( )
{
2002-10-25 05:06:52 +00:00
// Any note will end a hold (not just a TAP_HOLD_TAIL). This makes parsing DWIs much easier.
2002-10-20 21:39:13 +00:00
// Plus, allowing tap notes in the middle of a hold doesn't make sense!
2002-04-16 17:31:00 +00:00
2002-11-24 06:59:58 +00:00
int rows = GetLastRow ( ) ;
2002-04-16 17:31:00 +00:00
for ( int col = 0 ; col < m_iNumTracks ; col + + ) // foreach column
{
2002-11-24 06:59:58 +00:00
for ( int i = 0 ; i < = rows ; i + + ) // foreach TapNote element
2002-04-16 17:31:00 +00:00
{
2002-10-25 05:19:27 +00:00
if ( GetTapNote ( col , i ) ! = TAP_HOLD_HEAD ) // this is a HoldNote begin marker
2002-09-06 00:21:49 +00:00
continue ;
2002-10-25 05:19:27 +00:00
SetTapNote ( col , i , TAP_EMPTY ) ;
2002-09-06 00:21:49 +00:00
2002-11-24 06:59:58 +00:00
for ( int j = i + 1 ; j < = rows ; j + + ) // search for end of HoldNote
2002-04-16 17:31:00 +00:00
{
2002-09-06 00:21:49 +00:00
// end hold on the next note we see
2002-10-25 05:19:27 +00:00
if ( GetTapNote ( col , j ) = = TAP_EMPTY )
2002-09-06 00:21:49 +00:00
continue ;
2002-10-25 05:19:27 +00:00
SetTapNote ( col , j , TAP_EMPTY ) ;
2002-09-06 05:24:59 +00:00
2002-09-06 00:21:49 +00:00
HoldNote hn = { col , NoteRowToBeat ( i ) , NoteRowToBeat ( j ) } ;
AddHoldNote ( hn ) ;
break ;
2002-04-16 17:31:00 +00:00
}
}
}
}
2002-08-25 05:00:23 +00:00
/* "102000301" ==
* "104444001" */
2002-04-16 17:31:00 +00:00
void NoteData : : ConvertHoldNotesTo2sAnd3s ( )
{
// copy HoldNotes into the new structure, but expand them into 2s and 3s
2002-11-02 22:59:12 +00:00
for ( int i = 0 ; i < GetNumHoldNotes ( ) ; i + + )
2002-04-16 17:31:00 +00:00
{
2002-11-02 22:53:04 +00:00
const HoldNote & hn = GetHoldNote ( i ) ;
2002-12-18 07:35:21 +00:00
int iHoldStartIndex = max ( BeatToNoteRow ( hn . m_fStartBeat ) , 0 ) ;
int iHoldEndIndex = max ( BeatToNoteRow ( hn . m_fEndBeat ) , 0 ) ;
2002-10-12 21:40:55 +00:00
/* If they're the same, then they got clamped together, so just ignore it. */
if ( iHoldStartIndex ! = iHoldEndIndex ) {
2002-10-25 05:19:27 +00:00
SetTapNote ( hn . m_iTrack , iHoldStartIndex , TAP_HOLD_HEAD ) ;
SetTapNote ( hn . m_iTrack , iHoldEndIndex , TAP_HOLD_TAIL ) ;
2002-10-12 21:40:55 +00:00
}
2002-04-16 17:31:00 +00:00
}
2002-11-02 23:10:38 +00:00
m_HoldNotes . clear ( ) ;
2002-04-16 17:31:00 +00:00
}
2002-08-25 05:00:23 +00:00
/* "104444001" ==
* "102000301"
*
* "4441" basically means "hold for three rows then hold for another tap";
* since taps don't really have a length, it's equivalent to "4440".
* So, make sure the character after a 4 is always a 0. */
void NoteData : : Convert4sToHoldNotes ( )
{
2002-11-24 05:41:05 +00:00
int rows = GetLastRow ( ) ;
2002-08-25 05:00:23 +00:00
for ( int col = 0 ; col < m_iNumTracks ; col + + ) // foreach column
{
2002-11-24 05:41:05 +00:00
for ( int i = 0 ; i < = rows ; i + + ) // foreach TapNote element
2002-08-25 05:00:23 +00:00
{
2002-10-25 05:19:27 +00:00
if ( GetTapNote ( col , i ) ! = TAP_HOLD ) // this is a HoldNote body
2002-08-25 05:00:23 +00:00
continue ;
HoldNote hn = { col , NoteRowToBeat ( i ) , 0 } ;
// search for end of HoldNote
do {
2002-10-25 04:59:12 +00:00
SetTapNote ( col , i , TAP_EMPTY ) ;
2002-08-25 05:00:23 +00:00
i + + ;
2002-10-25 05:06:52 +00:00
} while ( GetTapNote ( col , i ) = = TAP_HOLD ) ;
2002-10-25 04:59:12 +00:00
SetTapNote ( col , i , TAP_EMPTY ) ;
2002-08-25 05:00:23 +00:00
hn . m_fEndBeat = NoteRowToBeat ( i ) ;
AddHoldNote ( hn ) ;
}
}
}
void NoteData : : ConvertHoldNotesTo4s ( )
{
// copy HoldNotes into the new structure, but expand them into 4s
2002-11-02 22:59:12 +00:00
for ( int i = 0 ; i < GetNumHoldNotes ( ) ; i + + )
2002-08-25 05:00:23 +00:00
{
2002-11-02 22:53:04 +00:00
const HoldNote & hn = GetHoldNote ( i ) ;
2002-12-18 07:35:21 +00:00
int iHoldStartIndex = max ( BeatToNoteRow ( hn . m_fStartBeat ) , 0 ) ;
int iHoldEndIndex = max ( BeatToNoteRow ( hn . m_fEndBeat ) , 0 ) ;
2002-10-12 21:40:55 +00:00
2002-08-25 05:00:23 +00:00
for ( int j = iHoldStartIndex ; j < iHoldEndIndex ; + + j )
2002-10-25 05:19:27 +00:00
SetTapNote ( hn . m_iTrack , j , TAP_HOLD ) ;
2002-08-25 05:00:23 +00:00
}
2002-11-02 23:10:38 +00:00
m_HoldNotes . clear ( ) ;
2002-08-25 05:00:23 +00:00
}
2002-08-25 19:00:12 +00:00
// -1 for iOriginalTracksToTakeFrom means no track
void NoteData : : LoadTransformed ( NoteData * pOriginal , int iNewNumTracks , const int iOriginalTrackToTakeFrom [ ] )
2002-04-16 17:31:00 +00:00
{
2002-08-25 19:00:12 +00:00
// reset all notes
2002-07-03 21:27:26 +00:00
Init ( ) ;
2002-04-16 17:31:00 +00:00
2002-10-20 19:34:17 +00:00
pOriginal - > ConvertHoldNotesTo4s ( ) ;
2002-12-13 01:23:26 +00:00
Config ( * pOriginal ) ;
2002-04-16 17:31:00 +00:00
m_iNumTracks = iNewNumTracks ;
// copy tracks
for ( int t = 0 ; t < m_iNumTracks ; t + + )
{
2002-08-25 19:00:12 +00:00
const int iOriginalTrack = iOriginalTrackToTakeFrom [ t ] ;
2002-12-28 16:07:19 +00:00
2002-12-29 02:02:24 +00:00
ASSERT ( iOriginalTrack < pOriginal - > m_iNumTracks ) ;
2002-12-28 16:07:19 +00:00
2002-08-25 19:00:12 +00:00
if ( iOriginalTrack = = - 1 )
continue ;
2002-10-25 23:32:50 +00:00
m_TapNotes [ t ] = pOriginal - > m_TapNotes [ iOriginalTrack ] ;
2002-04-16 17:31:00 +00:00
}
2002-08-25 19:00:12 +00:00
pOriginal - > Convert4sToHoldNotes ( ) ;
2002-09-06 00:21:49 +00:00
Convert4sToHoldNotes ( ) ;
2002-04-16 17:31:00 +00:00
}
2003-01-02 09:44:09 +00:00
# include "RageLog.h"
2002-06-24 22:04:31 +00:00
2002-10-05 14:47:03 +00:00
void NoteData : : LoadTransformedSlidingWindow ( NoteData * pOriginal , int iNewNumTracks )
{
2002-10-20 19:34:17 +00:00
// reset all notes
Init ( ) ;
2002-10-05 14:47:03 +00:00
pOriginal - > ConvertHoldNotesTo4s ( ) ;
2002-12-13 01:23:26 +00:00
Config ( * pOriginal ) ;
2002-10-05 14:47:03 +00:00
m_iNumTracks = iNewNumTracks ;
2002-12-19 04:39:16 +00:00
2002-10-05 20:03:14 +00:00
int iCurTrackOffset = 0 ;
int iTrackOffsetMin = 0 ;
int iTrackOffsetMax = abs ( iNewNumTracks - pOriginal - > m_iNumTracks ) ;
int bOffsetIncreasing = true ;
2002-10-05 14:47:03 +00:00
int iLastRow = pOriginal - > GetLastRow ( ) ;
2002-12-14 20:27:52 +00:00
for ( int r = 0 ; r < = iLastRow ; )
2002-10-05 14:47:03 +00:00
{
2002-12-19 04:39:16 +00:00
// copy notes in this measure
for ( int t = 0 ; t < pOriginal - > m_iNumTracks ; t + + )
{
int iOldTrack = t ;
int iNewTrack = ( iOldTrack + iCurTrackOffset ) % iNewNumTracks ;
2003-01-02 09:44:09 +00:00
this - > SetTapNote ( iNewTrack , r , pOriginal - > GetTapNote ( iOldTrack , r ) ) ;
2002-10-05 14:47:03 +00:00
}
2002-12-19 04:39:16 +00:00
r + + ;
2002-10-05 14:47:03 +00:00
2002-10-05 23:10:23 +00:00
if ( r % ( ROWS_PER_MEASURE * 4 ) = = 0 ) // adjust sliding window every 4 measures
2002-10-05 14:47:03 +00:00
{
2002-10-05 20:03:14 +00:00
// See if there is a hold crossing the beginning of this measure
bool bHoldCrossesThisMeasure = false ;
2002-10-11 20:51:12 +00:00
if ( r )
for ( int t = 0 ; t < = pOriginal - > m_iNumTracks ; t + + )
{
2002-10-25 05:19:27 +00:00
if ( pOriginal - > GetTapNote ( t , r ) = = TAP_HOLD & &
pOriginal - > GetTapNote ( t , r - 1 ) = = TAP_HOLD )
2002-10-11 20:51:12 +00:00
{
bHoldCrossesThisMeasure = true ;
break ;
}
}
2002-10-05 20:03:14 +00:00
// adjust offset
if ( ! bHoldCrossesThisMeasure )
{
iCurTrackOffset + = bOffsetIncreasing ? 1 : - 1 ;
if ( iCurTrackOffset = = iTrackOffsetMin | | iCurTrackOffset = = iTrackOffsetMax )
bOffsetIncreasing ^ = true ;
CLAMP ( iCurTrackOffset , iTrackOffsetMin , iTrackOffsetMax ) ;
2002-10-05 14:47:03 +00:00
}
}
}
pOriginal - > Convert4sToHoldNotes ( ) ;
Convert4sToHoldNotes ( ) ;
}
2002-10-25 23:32:50 +00:00
void NoteData : : PadTapNotes ( int rows )
{
2003-01-31 21:34:34 +00:00
// Need to resize each track individually. It could be the case that
// m_iNumTracks has changed, and the vectors are different sizes. -Chris
2002-11-03 01:33:33 +00:00
for ( int track = 0 ; track < m_iNumTracks ; + + track )
2003-01-31 21:34:34 +00:00
{
int needed = rows - m_TapNotes [ track ] . size ( ) + 1 ;
if ( needed < 0 )
continue ;
needed + = 100 ; /* optimization: give it a little more than it needs */
2002-11-03 21:37:08 +00:00
m_TapNotes [ track ] . insert ( m_TapNotes [ track ] . end ( ) , needed , TAP_EMPTY ) ;
2003-01-31 21:34:34 +00:00
}
2002-10-25 23:32:50 +00:00
}
2002-11-02 21:04:00 +00:00
void NoteData : : MoveTapNoteTrack ( int dest , int src )
{
if ( dest = = src ) return ;
m_TapNotes [ dest ] = m_TapNotes [ src ] ;
m_TapNotes [ src ] . clear ( ) ;
}
2002-10-25 23:32:50 +00:00
void NoteData : : SetTapNote ( int track , int row , TapNote t )
{
if ( row < 0 ) return ;
2002-12-13 01:23:26 +00:00
2002-10-25 23:32:50 +00:00
PadTapNotes ( row ) ;
m_TapNotes [ track ] [ row ] = t ;
}
2002-12-13 01:23:26 +00:00
2002-12-13 22:09:26 +00:00
NoteType NoteDataUtil : : GetSmallestNoteTypeForMeasure ( const NoteData & n , int iMeasureIndex )
{
const int iMeasureStartIndex = iMeasureIndex * ROWS_PER_MEASURE ;
const int iMeasureLastIndex = ( iMeasureIndex + 1 ) * ROWS_PER_MEASURE - 1 ;
// probe to find the smallest note type
NoteType nt ;
for ( nt = ( NoteType ) 0 ; nt < NUM_NOTE_TYPES ; nt = NoteType ( nt + 1 ) ) // for each NoteType, largest to largest
{
float fBeatSpacing = NoteTypeToBeat ( nt ) ;
int iRowSpacing = int ( roundf ( fBeatSpacing * ROWS_PER_BEAT ) ) ;
bool bFoundSmallerNote = false ;
for ( int i = iMeasureStartIndex ; i < = iMeasureLastIndex ; i + + ) // for each index in this measure
{
if ( i % iRowSpacing = = 0 )
continue ; // skip
if ( ! n . IsRowEmpty ( i ) )
{
bFoundSmallerNote = true ;
break ;
}
}
if ( bFoundSmallerNote )
continue ; // searching the next NoteType
else
break ; // stop searching. We found the smallest NoteType
}
if ( nt = = NUM_NOTE_TYPES ) // we didn't find one
return NOTE_TYPE_INVALID ; // well-formed notes created in the editor should never get here
else
return nt ;
}
void NoteDataUtil : : LoadFromSMNoteDataString ( NoteData & out , CString sSMNoteData )
{
/* Clear notes, but keep the same number of tracks. */
2003-02-01 05:16:38 +00:00
int iNumTracks = out . GetNumTracks ( ) ;
2002-12-13 22:09:26 +00:00
out . Init ( ) ;
2003-02-01 05:16:38 +00:00
out . SetNumTracks ( iNumTracks ) ;
2002-12-13 22:09:26 +00:00
// strip comments out of sSMNoteData
while ( sSMNoteData . Find ( " // " ) ! = - 1 )
{
int iIndexCommentStart = sSMNoteData . Find ( " // " ) ;
int iIndexCommentEnd = sSMNoteData . Find ( " \n " , iIndexCommentStart ) ;
if ( iIndexCommentEnd = = - 1 ) // comment doesn't have an end?
2003-01-03 05:29:45 +00:00
sSMNoteData . erase ( iIndexCommentStart , 2 ) ;
2002-12-13 22:09:26 +00:00
else
2003-01-03 05:29:45 +00:00
sSMNoteData . erase ( iIndexCommentStart , iIndexCommentEnd - iIndexCommentStart ) ;
2002-12-13 22:09:26 +00:00
}
CStringArray asMeasures ;
split ( sSMNoteData , " , " , asMeasures , true ) ; // ignore empty is important
for ( unsigned m = 0 ; m < asMeasures . size ( ) ; m + + ) // foreach measure
{
CString & sMeasureString = asMeasures [ m ] ;
TrimLeft ( sMeasureString ) ;
TrimRight ( sMeasureString ) ;
CStringArray asMeasureLines ;
split ( sMeasureString , " \n " , asMeasureLines , true ) ; // ignore empty is important
//ASSERT( asMeasureLines.size() == 4 ||
// asMeasureLines.size() == 8 ||
// asMeasureLines.size() == 12 ||
// asMeasureLines.size() == 16 );
for ( unsigned l = 0 ; l < asMeasureLines . size ( ) ; l + + )
{
CString & sMeasureLine = asMeasureLines [ l ] ;
TrimLeft ( sMeasureLine ) ;
TrimRight ( sMeasureLine ) ;
const float fPercentIntoMeasure = l / ( float ) asMeasureLines . size ( ) ;
const float fBeat = ( m + fPercentIntoMeasure ) * BEATS_PER_MEASURE ;
const int iIndex = BeatToNoteRow ( fBeat ) ;
// if( m_iNumTracks != sMeasureLine.GetLength() )
2002-12-21 19:34:02 +00:00
// RageException::Throw( "Actual number of note columns (%d) is different from the NotesType (%d).", m_iNumTracks, sMeasureLine.GetLength() );
2002-12-13 22:09:26 +00:00
2003-02-01 05:16:38 +00:00
for ( int c = 0 ; c < min ( sMeasureLine . GetLength ( ) , out . GetNumTracks ( ) ) ; c + + )
2002-12-13 22:09:26 +00:00
{
TapNote t ;
switch ( sMeasureLine [ c ] )
{
case ' 0 ' : t = TAP_EMPTY ; break ;
case ' 1 ' : t = TAP_TAP ; break ;
case ' 2 ' : t = TAP_HOLD_HEAD ; break ;
case ' 3 ' : t = TAP_HOLD_TAIL ; break ;
default : ASSERT ( 0 ) ; t = TAP_EMPTY ; break ;
}
out . SetTapNote ( c , iIndex , t ) ;
}
}
}
out . Convert2sAnd3sToHoldNotes ( ) ;
}
CString NoteDataUtil : : GetSMNoteDataString ( NoteData & in )
{
in . ConvertHoldNotesTo2sAnd3s ( ) ;
float fLastBeat = in . GetLastBeat ( ) ;
int iLastMeasure = int ( fLastBeat / BEATS_PER_MEASURE ) ;
2002-12-14 22:51:59 +00:00
CString sRet ;
2002-12-13 22:09:26 +00:00
for ( int m = 0 ; m < = iLastMeasure ; m + + ) // foreach measure
{
NoteType nt = GetSmallestNoteTypeForMeasure ( in , m ) ;
int iRowSpacing ;
if ( nt = = NOTE_TYPE_INVALID )
iRowSpacing = 1 ;
else
iRowSpacing = int ( roundf ( NoteTypeToBeat ( nt ) * ROWS_PER_BEAT ) ) ;
2002-12-14 22:51:59 +00:00
sRet + = ssprintf ( " // measure %d \n " , m + 1 ) ;
2002-12-13 22:09:26 +00:00
const int iMeasureStartRow = m * ROWS_PER_MEASURE ;
const int iMeasureLastRow = ( m + 1 ) * ROWS_PER_MEASURE - 1 ;
2002-12-19 04:43:30 +00:00
2002-12-13 22:09:26 +00:00
for ( int r = iMeasureStartRow ; r < = iMeasureLastRow ; r + = iRowSpacing )
{
2003-02-01 05:16:38 +00:00
for ( int t = 0 ; t < in . GetNumTracks ( ) ; t + + ) {
2002-12-13 22:09:26 +00:00
char c ;
switch ( in . GetTapNote ( t , r ) ) {
case TAP_EMPTY : c = ' 0 ' ; break ;
case TAP_TAP : c = ' 1 ' ; break ;
case TAP_HOLD_HEAD : c = ' 2 ' ; break ;
case TAP_HOLD_TAIL : c = ' 3 ' ; break ;
default : ASSERT ( 0 ) ; c = ' 0 ' ; break ;
}
2002-12-14 22:51:59 +00:00
sRet . append ( 1 , c ) ;
2002-12-13 22:09:26 +00:00
}
2002-12-14 22:51:59 +00:00
sRet . append ( 1 , ' \n ' ) ;
2002-12-13 22:09:26 +00:00
}
2002-12-14 22:51:59 +00:00
sRet . append ( 1 , ' , ' ) ;
2002-12-13 22:09:26 +00:00
}
in . Convert2sAnd3sToHoldNotes ( ) ;
2002-12-14 22:51:59 +00:00
return sRet ;
2002-12-13 22:09:26 +00:00
}
2002-12-13 22:40:42 +00:00
float NoteDataUtil : : GetRadarValue ( const NoteData & in , RadarCategory rv , float fSongSeconds )
{
switch ( rv )
{
case RADAR_STREAM : return GetStreamRadarValue ( in , fSongSeconds ) ;
case RADAR_VOLTAGE : return GetVoltageRadarValue ( in , fSongSeconds ) ;
case RADAR_AIR : return GetAirRadarValue ( in , fSongSeconds ) ;
case RADAR_FREEZE : return GetFreezeRadarValue ( in , fSongSeconds ) ;
case RADAR_CHAOS : return GetChaosRadarValue ( in , fSongSeconds ) ;
default : ASSERT ( 0 ) ; return 0 ;
}
}
float NoteDataUtil : : GetStreamRadarValue ( const NoteData & in , float fSongSeconds )
{
// density of steps
int iNumNotes = in . GetNumTapNotes ( ) + in . GetNumHoldNotes ( ) ;
float fNotesPerSecond = iNumNotes / fSongSeconds ;
float fReturn = fNotesPerSecond / 7 ;
return min ( fReturn , 1.0f ) ;
}
float NoteDataUtil : : GetVoltageRadarValue ( const NoteData & in , float fSongSeconds )
{
float fAvgBPS = in . GetLastBeat ( ) / fSongSeconds ;
// peak density of steps
float fMaxDensitySoFar = 0 ;
const int BEAT_WINDOW = 8 ;
for ( int i = 0 ; i < MAX_BEATS ; i + = BEAT_WINDOW )
{
int iNumNotesThisWindow = in . GetNumTapNotes ( ( float ) i , ( float ) i + BEAT_WINDOW ) + in . GetNumHoldNotes ( ( float ) i , ( float ) i + BEAT_WINDOW ) ;
float fDensityThisWindow = iNumNotesThisWindow / ( float ) BEAT_WINDOW ;
fMaxDensitySoFar = max ( fMaxDensitySoFar , fDensityThisWindow ) ;
}
float fReturn = fMaxDensitySoFar * fAvgBPS / 10 ;
return min ( fReturn , 1.0f ) ;
}
float NoteDataUtil : : GetAirRadarValue ( const NoteData & in , float fSongSeconds )
{
// number of doubles
int iNumDoubles = in . GetNumDoubles ( ) ;
float fReturn = iNumDoubles / fSongSeconds ;
return min ( fReturn , 1.0f ) ;
}
float NoteDataUtil : : GetFreezeRadarValue ( const NoteData & in , float fSongSeconds )
{
// number of hold steps
float fReturn = in . GetNumHoldNotes ( ) / fSongSeconds ;
return min ( fReturn , 1.0f ) ;
}
float NoteDataUtil : : GetChaosRadarValue ( const NoteData & in , float fSongSeconds )
{
// count number of triplets or 16ths
int iNumChaosNotes = 0 ;
int rows = in . GetLastRow ( ) ;
for ( int r = 0 ; r < = rows ; r + + )
{
if ( ! in . IsRowEmpty ( r ) & & GetNoteType ( r ) > = NOTE_TYPE_12TH )
iNumChaosNotes + + ;
}
float fReturn = iNumChaosNotes / fSongSeconds * 0.5f ;
return min ( fReturn , 1.0f ) ;
}
2002-12-13 23:34:37 +00:00
void NoteDataUtil : : RemoveHoldNotes ( NoteData & in )
{
vector < int > tracks , rows ;
// turn all the HoldNotes into TapNotes
for ( int i = 0 ; i < in . GetNumHoldNotes ( ) ; i + + )
{
const HoldNote & hn = in . GetHoldNote ( i ) ;
tracks . push_back ( hn . m_iTrack ) ;
rows . push_back ( BeatToNoteRow ( hn . m_fStartBeat ) ) ;
}
// Remove all HoldNotes
while ( in . GetNumHoldNotes ( ) )
in . RemoveHoldNote ( in . GetNumHoldNotes ( ) - 1 ) ;
for ( unsigned j = 0 ; j < tracks . size ( ) ; + + j )
in . SetTapNote ( tracks [ j ] , rows [ j ] , TAP_TAP ) ;
}
void NoteDataUtil : : Turn ( NoteData & in , PlayerOptions : : TurnType tt )
{
int iTakeFromTrack [ MAX_NOTE_TRACKS ] ; // New track "t" will take from old track iTakeFromTrack[t]
int t ;
switch ( tt )
{
case PlayerOptions : : TURN_NONE :
return ; // nothing to do
case PlayerOptions : : TURN_MIRROR :
2003-02-01 05:16:38 +00:00
for ( t = 0 ; t < in . GetNumTracks ( ) ; t + + )
iTakeFromTrack [ t ] = in . GetNumTracks ( ) - t - 1 ;
2002-12-13 23:34:37 +00:00
break ;
case PlayerOptions : : TURN_LEFT :
case PlayerOptions : : TURN_RIGHT : // HACK: TurnRight does the same thing as TurnLeft. I'll fix this later...
// Chris: Handling each NotesType case is a terrible way to do this, but oh well...
switch ( GAMESTATE - > GetCurrentStyleDef ( ) - > m_NotesType )
{
case NOTES_TYPE_DANCE_SINGLE :
case NOTES_TYPE_DANCE_DOUBLE :
case NOTES_TYPE_DANCE_COUPLE :
iTakeFromTrack [ 0 ] = 2 ;
iTakeFromTrack [ 1 ] = 0 ;
iTakeFromTrack [ 2 ] = 3 ;
iTakeFromTrack [ 3 ] = 1 ;
iTakeFromTrack [ 4 ] = 6 ;
iTakeFromTrack [ 5 ] = 4 ;
iTakeFromTrack [ 6 ] = 7 ;
iTakeFromTrack [ 7 ] = 5 ;
break ;
case NOTES_TYPE_DANCE_SOLO :
iTakeFromTrack [ 0 ] = 5 ;
iTakeFromTrack [ 1 ] = 4 ;
iTakeFromTrack [ 2 ] = 0 ;
iTakeFromTrack [ 3 ] = 3 ;
iTakeFromTrack [ 4 ] = 1 ;
iTakeFromTrack [ 5 ] = 2 ;
break ;
case NOTES_TYPE_PUMP_SINGLE :
case NOTES_TYPE_PUMP_COUPLE :
iTakeFromTrack [ 0 ] = 3 ;
iTakeFromTrack [ 1 ] = 4 ;
iTakeFromTrack [ 2 ] = 2 ;
iTakeFromTrack [ 3 ] = 0 ;
iTakeFromTrack [ 4 ] = 1 ;
iTakeFromTrack [ 5 ] = 8 ;
iTakeFromTrack [ 6 ] = 9 ;
iTakeFromTrack [ 7 ] = 7 ;
iTakeFromTrack [ 8 ] = 5 ;
iTakeFromTrack [ 9 ] = 6 ;
break ;
case NOTES_TYPE_PUMP_DOUBLE :
iTakeFromTrack [ 0 ] = 8 ;
iTakeFromTrack [ 1 ] = 9 ;
iTakeFromTrack [ 2 ] = 7 ;
iTakeFromTrack [ 3 ] = 5 ;
iTakeFromTrack [ 4 ] = 6 ;
iTakeFromTrack [ 5 ] = 3 ;
iTakeFromTrack [ 6 ] = 4 ;
iTakeFromTrack [ 7 ] = 2 ;
iTakeFromTrack [ 8 ] = 0 ;
iTakeFromTrack [ 9 ] = 1 ;
break ;
case NOTES_TYPE_EZ2_SINGLE :
case NOTES_TYPE_EZ2_DOUBLE :
case NOTES_TYPE_EZ2_REAL :
// identity transform. What should we do here?
iTakeFromTrack [ 0 ] = 0 ;
iTakeFromTrack [ 1 ] = 1 ;
iTakeFromTrack [ 2 ] = 2 ;
iTakeFromTrack [ 3 ] = 3 ;
iTakeFromTrack [ 4 ] = 4 ;
iTakeFromTrack [ 5 ] = 5 ;
iTakeFromTrack [ 6 ] = 6 ;
iTakeFromTrack [ 7 ] = 7 ;
iTakeFromTrack [ 8 ] = 8 ;
iTakeFromTrack [ 9 ] = 9 ;
iTakeFromTrack [ 10 ] = 10 ;
iTakeFromTrack [ 11 ] = 11 ;
break ;
}
break ;
case PlayerOptions : : TURN_SHUFFLE :
case PlayerOptions : : TURN_SUPER_SHUFFLE : // use this code to shuffle the HoldNotes
{
2003-01-03 05:56:28 +00:00
vector < int > aiTracksLeftToMap ;
2003-02-01 05:16:38 +00:00
for ( t = 0 ; t < in . GetNumTracks ( ) ; t + + )
2002-12-13 23:34:37 +00:00
aiTracksLeftToMap . push_back ( t ) ;
2003-02-01 05:16:38 +00:00
for ( t = 0 ; t < in . GetNumTracks ( ) ; t + + )
2002-12-13 23:34:37 +00:00
{
int iRandTrackIndex = rand ( ) % aiTracksLeftToMap . size ( ) ;
int iRandTrack = aiTracksLeftToMap [ iRandTrackIndex ] ;
aiTracksLeftToMap . erase ( aiTracksLeftToMap . begin ( ) + iRandTrackIndex ,
aiTracksLeftToMap . begin ( ) + iRandTrackIndex + 1 ) ;
iTakeFromTrack [ t ] = iRandTrack ;
}
}
break ;
// handle this below
break ;
default :
ASSERT ( 0 ) ;
}
NoteData tempNoteData ; // write into here as we tranform
tempNoteData . Config ( in ) ;
in . ConvertHoldNotesTo2sAnd3s ( ) ;
// transform notes
2002-12-18 07:35:21 +00:00
int max_row = in . GetLastRow ( ) ;
2003-02-01 05:16:38 +00:00
for ( t = 0 ; t < in . GetNumTracks ( ) ; t + + )
2002-12-18 07:35:21 +00:00
for ( int r = 0 ; r < = max_row ; r + + )
2002-12-13 23:34:37 +00:00
tempNoteData . SetTapNote ( t , r , in . GetTapNote ( iTakeFromTrack [ t ] , r ) ) ;
in . CopyAll ( & tempNoteData ) ; // copy note data from newData back into this
in . Convert2sAnd3sToHoldNotes ( ) ;
if ( tt = = PlayerOptions : : TURN_SUPER_SHUFFLE )
{
// We already did the normal shuffling code above, which did a good job
// of shuffling HoldNotes without creating impossible patterns.
// Now, go in and shuffle the TapNotes some more.
// clear tempNoteData because we're going to use it as a scratch buffer again
tempNoteData . Init ( ) ;
tempNoteData . Config ( in ) ;
// copy all HoldNotes before copying taps
for ( int i = 0 ; i < in . GetNumHoldNotes ( ) ; i + + )
tempNoteData . AddHoldNote ( in . GetHoldNote ( i ) ) ;
in . ConvertHoldNotesTo4s ( ) ;
for ( int r = 0 ; r < = in . GetLastRow ( ) ; r + + ) // foreach row
{
if ( in . IsRowEmpty ( r ) )
continue ; // no need to super shuffle this row
// shuffle this row
2003-01-03 05:56:28 +00:00
vector < int > aiTracksThatCouldHaveTapNotes ;
2003-02-01 05:16:38 +00:00
for ( t = 0 ; t < in . GetNumTracks ( ) ; t + + )
2002-12-13 23:34:37 +00:00
if ( in . GetTapNote ( t , r ) ! = TAP_HOLD ) // any point that isn't part of a hold
aiTracksThatCouldHaveTapNotes . push_back ( t ) ;
2003-02-01 05:16:38 +00:00
for ( t = 0 ; t < in . GetNumTracks ( ) ; t + + )
2002-12-13 23:34:37 +00:00
{
if ( in . GetTapNote ( t , r ) ! = TAP_HOLD & & in . GetTapNote ( t , r ) ! = TAP_EMPTY ) // there is a tap note here (and not a HoldNote)
{
int iRandIndex = rand ( ) % aiTracksThatCouldHaveTapNotes . size ( ) ;
int iTo = aiTracksThatCouldHaveTapNotes [ iRandIndex ] ;
aiTracksThatCouldHaveTapNotes . erase ( aiTracksThatCouldHaveTapNotes . begin ( ) + iRandIndex ,
aiTracksThatCouldHaveTapNotes . begin ( ) + iRandIndex + 1 ) ;
tempNoteData . SetTapNote ( iTo , r , in . GetTapNote ( t , r ) ) ;
}
}
}
in . CopyAll ( & tempNoteData ) ; // copy note data from newData back into this
}
}
void NoteDataUtil : : MakeLittle ( NoteData & in )
{
// filter out all non-quarter notes
2002-12-18 07:35:21 +00:00
int max_row = in . GetLastRow ( ) ;
for ( int i = 0 ; i < = max_row ; i + + )
2002-12-13 23:34:37 +00:00
{
if ( i % ROWS_PER_BEAT ! = 0 )
{
// filter out all non-quarter notes
2003-02-01 05:16:38 +00:00
for ( int c = 0 ; c < in . GetNumTracks ( ) ; c + + )
2002-12-13 23:34:37 +00:00
{
in . SetTapNote ( c , i , TAP_EMPTY ) ;
}
}
}
// leave HoldNotes unchanged (what should be do with them?)
}
void NoteDataUtil : : SnapToNearestNoteType ( NoteData & in , NoteType nt1 , NoteType nt2 , float fBeginBeat , float fEndBeat )
{
// nt2 is optional and should be -1 if it is not used
float fSnapInterval1 , fSnapInterval2 ;
switch ( nt1 )
{
case NOTE_TYPE_4TH : fSnapInterval1 = 1 / 1.0f ; break ;
case NOTE_TYPE_8TH : fSnapInterval1 = 1 / 2.0f ; break ;
case NOTE_TYPE_12TH : fSnapInterval1 = 1 / 3.0f ; break ;
case NOTE_TYPE_16TH : fSnapInterval1 = 1 / 4.0f ; break ;
default : ASSERT ( false ) ; return ;
}
switch ( nt2 )
{
case NOTE_TYPE_4TH : fSnapInterval2 = 1 / 1.0f ; break ;
case NOTE_TYPE_8TH : fSnapInterval2 = 1 / 2.0f ; break ;
case NOTE_TYPE_12TH : fSnapInterval2 = 1 / 3.0f ; break ;
case NOTE_TYPE_16TH : fSnapInterval2 = 1 / 4.0f ; break ;
case - 1 : fSnapInterval2 = 10000 ; break ; // nothing will ever snap to this. That's what we want!
default : ASSERT ( false ) ; return ;
}
int iNoteIndexBegin = BeatToNoteRow ( fBeginBeat ) ;
int iNoteIndexEnd = BeatToNoteRow ( fEndBeat ) ;
//ConvertHoldNotesTo2sAnd3s();
// iterate over all TapNotes in the interval and snap them
for ( int i = iNoteIndexBegin ; i < = iNoteIndexEnd ; i + + )
{
int iOldIndex = i ;
float fOldBeat = NoteRowToBeat ( iOldIndex ) ;
float fNewBeat1 = froundf ( fOldBeat , fSnapInterval1 ) ;
float fNewBeat2 = froundf ( fOldBeat , fSnapInterval2 ) ;
bool bNewBeat1IsCloser = fabsf ( fNewBeat1 - fOldBeat ) < fabsf ( fNewBeat2 - fOldBeat ) ;
float fNewBeat = bNewBeat1IsCloser ? fNewBeat1 : fNewBeat2 ;
int iNewIndex = BeatToNoteRow ( fNewBeat ) ;
2003-02-01 05:16:38 +00:00
for ( int c = 0 ; c < in . GetNumTracks ( ) ; c + + )
2002-12-13 23:34:37 +00:00
{
TapNote note = in . GetTapNote ( c , iOldIndex ) ;
in . SetTapNote ( c , iOldIndex , TAP_EMPTY ) ;
// HoldNotes override TapNotes
if ( in . GetTapNote ( c , iNewIndex ) = = TAP_TAP )
note = TAP_HOLD_HEAD ;
in . SetTapNote ( c , iNewIndex , note ) ;
}
}
//Convert2sAnd3sToHoldNotes();
}