#include "global.h" /* ----------------------------------------------------------------------------- Class: NoteData Desc: See header. Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. Chris Danford ----------------------------------------------------------------------------- */ #include "NoteData.h" #include "RageUtil.h" NoteData::NoteData() { Init(); } void NoteData::Init() { m_iNumTracks = 0; // must do this before calling ClearAll()! ClearAll(); } NoteData::~NoteData() { } int NoteData::GetNumTracks() const { return m_iNumTracks; } void NoteData::SetNumTracks( int iNewNumTracks ) { m_iNumTracks = iNewNumTracks; // Make sure that all tracks are of the same length ASSERT( m_iNumTracks > 0 ); int rows = m_TapNotes[0].size(); for( int t=0; tConvertHoldNotesTo4s(); for( int c=0; cConvert4sToHoldNotes(); } void NoteData::ClearAll() { for( int t=0; tm_iNumTracks == m_iNumTracks ); if( iToIndexBegin == -1 ) iToIndexBegin = 0; pFrom->ConvertHoldNotesTo4s(); this->ConvertHoldNotesTo4s(); // copy recorded TapNotes int f = iFromIndexBegin, t = iToIndexBegin; while( fGetTapNote(c, f)); f++; t++; } pFrom->Convert4sToHoldNotes(); this->Convert4sToHoldNotes(); } void NoteData::Config( const NoteData &From ) { m_iNumTracks = From.m_iNumTracks; } void NoteData::CopyAll( NoteData* pFrom ) { Config(*pFrom); ClearAll(); CopyRange( pFrom, 0, pFrom->GetLastRow() ); } void NoteData::AddHoldNote( HoldNote add ) { ASSERT( add.fStartBeat>=0 && add.fEndBeat>=0 ); int i; // look for other hold notes that overlap and merge them // XXX: this is done implicitly with 4s, but 4s uses this function. // Rework this later. for( i=0; i= 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 ) ) { add.fStartBeat = min(add.fStartBeat, other.fStartBeat); add.fEndBeat = max(add.fEndBeat, other.fEndBeat); // delete this HoldNote m_HoldNotes.erase(m_HoldNotes.begin()+i, m_HoldNotes.begin()+i+1); } } int iAddStartIndex = BeatToNoteRow(add.fStartBeat); int iAddEndIndex = BeatToNoteRow(add.fEndBeat); // delete TapNotes under this HoldNote for( i=iAddStartIndex+1; i<=iAddEndIndex; i++ ) SetTapNote(add.iTrack, i, TAP_EMPTY); // add a tap note at the start of this hold SetTapNote(add.iTrack, iAddStartIndex, TAP_HOLD_HEAD); // Hold begin marker. Don't draw this, but do grade it. m_HoldNotes.push_back(add); } void NoteData::RemoveHoldNote( int iHoldIndex ) { ASSERT( iHoldIndex >= 0 && iHoldIndex < GetNumHoldNotes() ); HoldNote& hn = GetHoldNote(iHoldIndex); int iHoldStartIndex = BeatToNoteRow(hn.fStartBeat); // delete a tap note at the start of this hold SetTapNote(hn.iTrack, iHoldStartIndex, TAP_EMPTY); // remove from list m_HoldNotes.erase(m_HoldNotes.begin()+iHoldIndex, m_HoldNotes.begin()+iHoldIndex+1); } bool NoteData::IsThereATapAtRow( int iRow ) const { for( int t=0; t=0; i-- ) // iterate back to front { if( !IsRowEmpty(i) ) { fOldestBeatFoundSoFar = NoteRowToBeat(i); break; } } for( i=0; i fOldestBeatFoundSoFar ) fOldestBeatFoundSoFar = GetHoldNote(i).fEndBeat; } return fOldestBeatFoundSoFar; } int NoteData::GetNumTapNotes( float fStartBeat, float fEndBeat ) const { int iNumNotes = 0; if(fEndBeat == -1) fEndBeat = GetMaxBeat(); int iStartIndex = BeatToNoteRow( fStartBeat ); int iEndIndex = BeatToNoteRow( fEndBeat ); for( int t=0; t= 2 ) iNumDoubles++; } return iNumDoubles; } int NoteData::GetNumHoldNotes( float fStartBeat, float fEndBeat ) const { int iNumHolds = 0; if(fEndBeat == -1) fEndBeat = GetMaxBeat(); for( int i=0; iConvertHoldNotesTo4s(); Config(*pOriginal); m_iNumTracks = iNewNumTracks; // copy tracks for( int t=0; tm_iNumTracks ); if( iOriginalTrack == -1 ) continue; m_TapNotes[t] = pOriginal->m_TapNotes[iOriginalTrack]; } pOriginal->Convert4sToHoldNotes(); Convert4sToHoldNotes(); } #include "RageLog.h" void NoteData::LoadTransformedSlidingWindow( NoteData* pOriginal, int iNewNumTracks ) { // reset all notes Init(); pOriginal->ConvertHoldNotesTo4s(); Config(*pOriginal); m_iNumTracks = iNewNumTracks; int iCurTrackOffset = 0; int iTrackOffsetMin = 0; int iTrackOffsetMax = abs( iNewNumTracks - pOriginal->m_iNumTracks ); int bOffsetIncreasing = true; int iLastRow = pOriginal->GetLastRow(); for( int r=0; r<=iLastRow; ) { // copy notes in this measure for( int t=0; tm_iNumTracks; t++ ) { int iOldTrack = t; int iNewTrack = (iOldTrack + iCurTrackOffset) % iNewNumTracks; this->SetTapNote(iNewTrack, r, pOriginal->GetTapNote(iOldTrack, r)); } r++; if( r % (ROWS_PER_MEASURE*4) == 0 ) // adjust sliding window every 4 measures { // See if there is a hold crossing the beginning of this measure bool bHoldCrossesThisMeasure = false; if( r ) for( int t=0; t<=pOriginal->m_iNumTracks; t++ ) { if( pOriginal->GetTapNote(t, r) == TAP_HOLD && pOriginal->GetTapNote(t, r-1) == TAP_HOLD) { bHoldCrossesThisMeasure = true; break; } } // adjust offset if( !bHoldCrossesThisMeasure ) { iCurTrackOffset += bOffsetIncreasing ? 1 : -1; if( iCurTrackOffset == iTrackOffsetMin || iCurTrackOffset == iTrackOffsetMax ) bOffsetIncreasing ^= true; CLAMP( iCurTrackOffset, iTrackOffsetMin, iTrackOffsetMax ); } } } pOriginal->Convert4sToHoldNotes(); Convert4sToHoldNotes(); } void NoteData::PadTapNotes(int rows) { int needed = rows - m_TapNotes[0].size() + 1; if(needed < 0) return; needed += 100; /* optimization: give it a little more than it needs */ for(int track = 0; track < m_iNumTracks; ++track) m_TapNotes[track].insert(m_TapNotes[track].end(), needed, TAP_EMPTY); } void NoteData::MoveTapNoteTrack(int dest, int src) { if(dest == src) return; m_TapNotes[dest] = m_TapNotes[src]; m_TapNotes[src].clear(); } void NoteData::SetTapNote(int track, int row, TapNote t) { if(row < 0) return; PadTapNotes(row); m_TapNotes[track][row]=t; }