2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2002-04-16 17:31:00 +00:00
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
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"
|
2003-10-04 04:14:30 +00:00
|
|
|
#include "RageLog.h"
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
NoteData::NoteData()
|
2002-06-24 22:04:31 +00:00
|
|
|
{
|
2003-11-01 19:46:05 +00:00
|
|
|
m_iNumTracks = 0;
|
2002-06-24 22:04:31 +00:00
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteData::Init()
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2003-02-09 19:16:25 +00:00
|
|
|
ClearAll();
|
2003-11-01 19:46:05 +00:00
|
|
|
m_iNumTracks = 0; // must do this after calling ClearAll()!
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
NoteData::~NoteData()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-26 17:53:31 +00:00
|
|
|
int NoteData::GetNumTracks() const
|
2003-02-01 05:16:38 +00:00
|
|
|
{
|
|
|
|
|
return m_iNumTracks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteData::SetNumTracks( int iNewNumTracks )
|
|
|
|
|
{
|
|
|
|
|
m_iNumTracks = iNewNumTracks;
|
2003-02-01 05:27:49 +00:00
|
|
|
|
|
|
|
|
// Make sure that all tracks are of the same length
|
|
|
|
|
ASSERT( m_iNumTracks > 0 );
|
|
|
|
|
int rows = m_TapNotes[0].size();
|
|
|
|
|
|
|
|
|
|
for( int t=0; t<MAX_NOTE_TRACKS; t++ )
|
|
|
|
|
{
|
|
|
|
|
if( t<m_iNumTracks )
|
|
|
|
|
m_TapNotes[t].resize( rows, TAP_EMPTY );
|
|
|
|
|
else
|
|
|
|
|
m_TapNotes[t].clear();
|
|
|
|
|
}
|
2003-02-01 05:16:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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.) */
|
2003-10-04 04:05:29 +00:00
|
|
|
void NoteData::CopyRange( const 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
|
|
|
|
2003-10-04 04:05:29 +00:00
|
|
|
NoteData From, To;
|
|
|
|
|
From.To4s( *pFrom );
|
|
|
|
|
To.To4s( *this );
|
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
|
|
|
|
2003-08-18 17:21:18 +00:00
|
|
|
while( f<=iFromIndexEnd )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
|
|
|
|
for( int c=0; c<m_iNumTracks; c++ )
|
2003-10-04 04:05:29 +00:00
|
|
|
To.SetTapNote(c, t, From.GetTapNote(c, f));
|
2002-06-29 11:59:09 +00:00
|
|
|
f++;
|
|
|
|
|
t++;
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2003-10-04 04:05:29 +00:00
|
|
|
this->From4s( To );
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-04 02:30:06 +00:00
|
|
|
void NoteData::CopyAll( const NoteData* pFrom )
|
2002-12-13 01:23:26 +00:00
|
|
|
{
|
|
|
|
|
Config(*pFrom);
|
2003-01-21 03:12:24 +00:00
|
|
|
ClearAll();
|
2003-10-04 02:30:06 +00:00
|
|
|
|
|
|
|
|
for( int c=0; c<m_iNumTracks; c++ )
|
|
|
|
|
m_TapNotes[c] = pFrom->m_TapNotes[c];
|
|
|
|
|
m_HoldNotes = pFrom->m_HoldNotes;
|
2002-12-13 01:23:26 +00:00
|
|
|
}
|
|
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
void NoteData::AddHoldNote( HoldNote add )
|
|
|
|
|
{
|
2003-02-16 20:27:53 +00:00
|
|
|
ASSERT( add.fStartBeat>=0 && add.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);
|
2003-02-16 20:27:53 +00:00
|
|
|
if( add.iTrack == other.iTrack && // the tracks correspond
|
2002-10-05 14:47:03 +00:00
|
|
|
// they overlap
|
|
|
|
|
(
|
2003-02-16 20:27:53 +00:00
|
|
|
( other.fStartBeat <= add.fStartBeat && other.fEndBeat >= add.fEndBeat ) || // other consumes add
|
|
|
|
|
( other.fStartBeat >= add.fStartBeat && other.fEndBeat <= add.fEndBeat ) || // other inside add
|
|
|
|
|
( add.fStartBeat <= other.fStartBeat && other.fStartBeat <= add.fEndBeat ) || // other overlaps add
|
|
|
|
|
( add.fStartBeat <= other.fEndBeat && other.fEndBeat <= add.fEndBeat ) // other overlaps add
|
2002-10-05 14:47:03 +00:00
|
|
|
)
|
|
|
|
|
)
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2003-02-16 20:27:53 +00:00
|
|
|
add.fStartBeat = min(add.fStartBeat, other.fStartBeat);
|
|
|
|
|
add.fEndBeat = max(add.fEndBeat, other.fEndBeat);
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
// delete this HoldNote
|
2003-09-15 05:41:11 +00:00
|
|
|
RemoveHoldNote( i );
|
|
|
|
|
--i;
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-16 20:27:53 +00:00
|
|
|
int iAddStartIndex = BeatToNoteRow(add.fStartBeat);
|
|
|
|
|
int iAddEndIndex = BeatToNoteRow(add.fEndBeat);
|
2002-08-13 23:26:46 +00:00
|
|
|
|
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++ )
|
2003-02-16 20:27:53 +00:00
|
|
|
SetTapNote(add.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
|
2003-02-16 20:27:53 +00:00
|
|
|
SetTapNote(add.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
|
|
|
|
2003-02-16 20:27:53 +00:00
|
|
|
int iHoldStartIndex = BeatToNoteRow(hn.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
|
2003-02-16 20:27:53 +00:00
|
|
|
SetTapNote(hn.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
|
|
|
}
|
|
|
|
|
|
2003-03-16 18:57:34 +00:00
|
|
|
bool NoteData::IsThereATapAtRow( 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;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2003-03-06 22:40:04 +00:00
|
|
|
float fEarliestBeatFoundSoFar = -1;
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
2003-03-06 22:40:04 +00:00
|
|
|
for( i=0; i <= int(m_TapNotes[0].size()); 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++ )
|
2003-03-06 22:40:04 +00:00
|
|
|
{
|
|
|
|
|
if( fEarliestBeatFoundSoFar == -1 ||
|
|
|
|
|
GetHoldNote(i).fStartBeat < fEarliestBeatFoundSoFar )
|
2003-02-16 20:27:53 +00:00
|
|
|
fEarliestBeatFoundSoFar = GetHoldNote(i).fStartBeat;
|
2003-03-06 22:40:04 +00:00
|
|
|
}
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2003-03-06 22:40:04 +00:00
|
|
|
if( fEarliestBeatFoundSoFar == -1 ) // there are no notes
|
2002-08-13 23:26:46 +00:00
|
|
|
return 0;
|
2003-03-06 22:40:04 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2003-02-16 20:27:53 +00:00
|
|
|
if( GetHoldNote(i).fEndBeat > fOldestBeatFoundSoFar )
|
|
|
|
|
fOldestBeatFoundSoFar = GetHoldNote(i).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
|
|
|
}
|
|
|
|
|
|
2003-02-25 19:49:16 +00:00
|
|
|
int NoteData::GetNumTapNotes( float fStartBeat, 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
|
|
|
|
2003-02-25 19:49:16 +00:00
|
|
|
if(fEndBeat == -1) fEndBeat = GetMaxBeat();
|
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
|
|
|
}
|
|
|
|
|
|
2003-03-16 18:57:34 +00:00
|
|
|
int NoteData::GetNumRowsWithTaps( float fStartBeat, float fEndBeat ) const
|
|
|
|
|
{
|
|
|
|
|
int iNumNotes = 0;
|
|
|
|
|
|
|
|
|
|
if(fEndBeat == -1) fEndBeat = GetMaxBeat();
|
|
|
|
|
int iStartIndex = BeatToNoteRow( fStartBeat );
|
|
|
|
|
int iEndIndex = BeatToNoteRow( fEndBeat );
|
|
|
|
|
|
|
|
|
|
for( int i=iStartIndex; i<=iEndIndex; i++ )
|
|
|
|
|
if( IsThereATapAtRow(i) )
|
|
|
|
|
iNumNotes++;
|
|
|
|
|
|
|
|
|
|
return iNumNotes;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-25 19:49:16 +00:00
|
|
|
int NoteData::GetNumDoubles( float fStartBeat, float fEndBeat ) const
|
2002-05-19 01:59:48 +00:00
|
|
|
{
|
|
|
|
|
int iNumDoubles = 0;
|
|
|
|
|
|
2003-02-25 19:49:16 +00:00
|
|
|
if(fEndBeat == -1) fEndBeat = GetMaxBeat();
|
2002-05-19 01:59:48 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-25 19:49:16 +00:00
|
|
|
int NoteData::GetNumHoldNotes( float fStartBeat, 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
|
|
|
|
2003-02-25 19:49:16 +00:00
|
|
|
if(fEndBeat == -1) fEndBeat = GetMaxBeat();
|
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);
|
2003-02-16 20:27:53 +00:00
|
|
|
if( fStartBeat <= hn.fStartBeat && hn.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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2003-04-05 21:18:18 +00:00
|
|
|
AddHoldNote( HoldNote(col, NoteRowToBeat(i), NoteRowToBeat(j)) );
|
2002-09-06 00:21:49 +00:00
|
|
|
break;
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-04 03:02:26 +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);
|
2003-02-16 20:27:53 +00:00
|
|
|
int iHoldStartIndex = max(BeatToNoteRow(hn.fStartBeat), 0);
|
|
|
|
|
int iHoldEndIndex = max(BeatToNoteRow(hn.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) {
|
2003-02-16 20:27:53 +00:00
|
|
|
SetTapNote(hn.iTrack, iHoldStartIndex, TAP_HOLD_HEAD);
|
|
|
|
|
SetTapNote(hn.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
|
|
|
}
|
|
|
|
|
|
2003-10-04 03:02:26 +00:00
|
|
|
|
2003-10-04 03:12:45 +00:00
|
|
|
void NoteData::To2sAnd3s( const NoteData &out )
|
2003-10-04 03:02:26 +00:00
|
|
|
{
|
2003-10-04 03:12:45 +00:00
|
|
|
CopyAll( &out );
|
|
|
|
|
ConvertHoldNotesTo2sAnd3s();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteData::From2sAnd3s( const NoteData &out )
|
|
|
|
|
{
|
|
|
|
|
CopyAll( &out );
|
|
|
|
|
Convert2sAnd3sToHoldNotes();
|
2003-10-04 03:02:26 +00:00
|
|
|
}
|
|
|
|
|
|
2003-10-04 04:05:29 +00:00
|
|
|
void NoteData::To4s( const NoteData &out )
|
|
|
|
|
{
|
|
|
|
|
CopyAll( &out );
|
|
|
|
|
ConvertHoldNotesTo4s();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteData::From4s( const NoteData &out )
|
|
|
|
|
{
|
|
|
|
|
CopyAll( &out );
|
|
|
|
|
Convert4sToHoldNotes();
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
2003-04-05 21:18:18 +00:00
|
|
|
HoldNote hn( col, NoteRowToBeat(i), 0 );
|
2002-08-25 05:00:23 +00:00
|
|
|
// 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
|
|
|
|
2003-02-16 20:27:53 +00:00
|
|
|
hn.fEndBeat = NoteRowToBeat(i);
|
2002-08-25 05:00:23 +00:00
|
|
|
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);
|
2003-02-16 20:27:53 +00:00
|
|
|
int iHoldStartIndex = max(BeatToNoteRow(hn.fStartBeat), 0);
|
|
|
|
|
int iHoldEndIndex = max(BeatToNoteRow(hn.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)
|
2003-02-16 20:27:53 +00:00
|
|
|
SetTapNote(hn.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
|
2003-10-04 04:14:30 +00:00
|
|
|
void NoteData::LoadTransformed( const 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
|
|
|
|
2003-10-04 04:14:30 +00:00
|
|
|
NoteData Original;
|
|
|
|
|
Original.To4s( *pOriginal );
|
2002-10-20 19:34:17 +00:00
|
|
|
|
2003-10-04 04:14:30 +00:00
|
|
|
Config( Original );
|
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];
|
2003-11-01 19:46:05 +00:00
|
|
|
RAGE_ASSERT_M( iOriginalTrack < Original.m_iNumTracks, ssprintf("from %i >= %i (to %i)",
|
|
|
|
|
iOriginalTrack, Original.m_iNumTracks, iOriginalTrackToTakeFrom[t]));
|
2002-12-28 16:07:19 +00:00
|
|
|
|
2002-08-25 19:00:12 +00:00
|
|
|
if( iOriginalTrack == -1 )
|
|
|
|
|
continue;
|
2003-10-04 04:14:30 +00:00
|
|
|
m_TapNotes[t] = Original.m_TapNotes[iOriginalTrack];
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
2002-09-06 00:21:49 +00:00
|
|
|
Convert4sToHoldNotes();
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
2002-06-24 22:04:31 +00:00
|
|
|
|
2003-10-04 04:14:30 +00:00
|
|
|
void NoteData::LoadTransformedSlidingWindow( const NoteData* pOriginal, int iNewNumTracks )
|
2002-10-05 14:47:03 +00:00
|
|
|
{
|
2002-10-20 19:34:17 +00:00
|
|
|
// reset all notes
|
|
|
|
|
Init();
|
|
|
|
|
|
2003-10-04 04:14:30 +00:00
|
|
|
NoteData Original;
|
|
|
|
|
Original.To4s( *pOriginal );
|
|
|
|
|
|
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;
|
2003-10-04 04:14:30 +00:00
|
|
|
int iTrackOffsetMax = abs( iNewNumTracks - Original.m_iNumTracks );
|
2002-10-05 20:03:14 +00:00
|
|
|
int bOffsetIncreasing = true;
|
|
|
|
|
|
2003-10-04 04:14:30 +00:00
|
|
|
int iLastRow = Original.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
|
2003-10-04 04:14:30 +00:00
|
|
|
for( int t=0; t<Original.m_iNumTracks; t++ )
|
2002-12-19 04:39:16 +00:00
|
|
|
{
|
|
|
|
|
int iOldTrack = t;
|
|
|
|
|
int iNewTrack = (iOldTrack + iCurTrackOffset) % iNewNumTracks;
|
2003-10-04 04:14:30 +00:00
|
|
|
this->SetTapNote(iNewTrack, r, Original.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 )
|
2003-10-04 04:14:30 +00:00
|
|
|
for( int t=0; t<=Original.m_iNumTracks; t++ )
|
2002-10-11 20:51:12 +00:00
|
|
|
{
|
2003-10-04 04:14:30 +00:00
|
|
|
if( Original.GetTapNote(t, r) == TAP_HOLD &&
|
|
|
|
|
Original.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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Convert4sToHoldNotes();
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-25 23:32:50 +00:00
|
|
|
void NoteData::PadTapNotes(int rows)
|
|
|
|
|
{
|
2003-02-01 05:27:49 +00:00
|
|
|
int needed = rows - m_TapNotes[0].size() + 1;
|
|
|
|
|
if(needed < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
needed += 100; /* optimization: give it a little more than it needs */
|
|
|
|
|
|
2002-11-03 01:33:33 +00:00
|
|
|
for(int track = 0; track < m_iNumTracks; ++track)
|
2002-11-03 21:37:08 +00:00
|
|
|
m_TapNotes[track].insert(m_TapNotes[track].end(), needed, TAP_EMPTY);
|
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;
|
|
|
|
|
}
|
2003-09-21 23:16:44 +00:00
|
|
|
|
|
|
|
|
void NoteData::EliminateAllButOneTap(int row)
|
|
|
|
|
{
|
|
|
|
|
if(row < 0) return;
|
|
|
|
|
|
|
|
|
|
PadTapNotes(row);
|
|
|
|
|
|
2003-09-22 00:51:10 +00:00
|
|
|
int track;
|
|
|
|
|
for(track = 0; track < m_iNumTracks; ++track)
|
2003-09-21 23:16:44 +00:00
|
|
|
{
|
|
|
|
|
if( m_TapNotes[track][row] == TAP_TAP )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track++;
|
|
|
|
|
|
|
|
|
|
for( ; track < m_iNumTracks; ++track)
|
|
|
|
|
{
|
|
|
|
|
if( m_TapNotes[track][row] == TAP_TAP )
|
|
|
|
|
m_TapNotes[track][row] = TAP_EMPTY;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-29 23:17:00 +00:00
|
|
|
// MD 10/29/03 - This is necessary, for whatever reason.
|
|
|
|
|
void NoteData::CombineTracks( int iTrackTo, int iTrackFrom )
|
|
|
|
|
{
|
|
|
|
|
LOG->Trace("NoteData::CombineTracks( %i , %i )", iTrackTo, iTrackFrom);
|
|
|
|
|
if(iTrackFrom < 0 || iTrackTo < 0) return;
|
|
|
|
|
int iLastRow = GetMaxRow();
|
|
|
|
|
LOG->Trace("NoteData::CombineTracks - %i rows", iLastRow);
|
|
|
|
|
|
|
|
|
|
for (int row = 0; row < iLastRow; ++row)
|
|
|
|
|
{
|
|
|
|
|
LOG->Trace("NoteData::CombineTracks - row %i", row);
|
|
|
|
|
int iStepFrom = m_TapNotes[iTrackFrom][row];
|
|
|
|
|
int iStepTo = m_TapNotes[iTrackTo][row];
|
|
|
|
|
|
|
|
|
|
if( iStepFrom == iStepTo )
|
|
|
|
|
{
|
|
|
|
|
// no reason to combine same steps
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if( iStepTo != TAP_EMPTY )
|
|
|
|
|
{
|
|
|
|
|
// Mines from "from" track will not knock out any steps in
|
|
|
|
|
// the "to" track, but this behavior is fine, I think...
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
m_TapNotes[iTrackTo][row] = iStepFrom;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|