evil big commit (sorry):
Remove m_HoldNote array entirely. Remove 2sAnd3s. Store hold note durations in the hold head. hold_tail only still exists when InsertHoldTails is used, to make SM parsing a little easier (may go away). Add helpers for iterating over ranges while including or excluding adjacent and overlapping hold notes. Range operations are now [start,end) instead of [start,end]. (probably more details coming to sm-dev soon)
This commit is contained in:
+317
-318
@@ -30,69 +30,82 @@ void NoteData::SetNumTracks( int iNewNumTracks )
|
|||||||
ASSERT( iNewNumTracks > 0 );
|
ASSERT( iNewNumTracks > 0 );
|
||||||
|
|
||||||
m_TapNotes.resize( iNewNumTracks );
|
m_TapNotes.resize( iNewNumTracks );
|
||||||
|
|
||||||
/* Remove all hold notes that are out of bounds. */
|
|
||||||
// Iterate backwards so that we can delete.
|
|
||||||
for( int h = m_HoldNotes.size()-1; h >= 0; --h )
|
|
||||||
if( m_HoldNotes[h].iTrack >= iNewNumTracks )
|
|
||||||
m_HoldNotes.erase( m_HoldNotes.begin()+h );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Clear [rowBegin,rowEnd]; that is, including rowEnd. */
|
/* Clear [rowBegin,rowEnd). */
|
||||||
void NoteData::ClearRangeForTrack( int rowBegin, int rowEnd, int iTrack )
|
void NoteData::ClearRangeForTrack( int rowBegin, int rowEnd, int iTrack )
|
||||||
{
|
{
|
||||||
/* Optimization: if the range encloses everything, just clear the whole maps. */
|
/* Optimization: if the range encloses everything, just clear the whole maps. */
|
||||||
if( rowBegin == 0 && rowEnd == MAX_NOTE_ROW )
|
if( rowBegin == 0 && rowEnd == MAX_NOTE_ROW )
|
||||||
{
|
{
|
||||||
m_TapNotes[iTrack].clear();
|
m_TapNotes[iTrack].clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for( int i = GetNumHoldNotes()-1; i >= 0; --i )
|
iterator begin, end;
|
||||||
|
GetTapNoteRangeInclusive( iTrack, rowBegin, rowEnd, begin, end );
|
||||||
|
|
||||||
|
if( begin != end && begin->first < rowBegin && begin->first + begin->second.iDuration > rowEnd )
|
||||||
{
|
{
|
||||||
HoldNote hn = GetHoldNote(i);
|
/* A hold note overlaps the whole range. Truncate it, and add the remainder to
|
||||||
if( hn.iTrack != iTrack )
|
* the end. */
|
||||||
continue;
|
TapNote tn1 = begin->second;
|
||||||
this->RemoveHoldNote( i );
|
TapNote tn2 = tn1;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Crop or split hold notes overlapping the range. */
|
int iEndRow = begin->first + tn1.iDuration;
|
||||||
for( int i = GetNumHoldNotes()-1; i >= 0; --i ) // for each HoldNote
|
int iRow = begin->first;
|
||||||
|
|
||||||
|
tn1.iDuration = rowBegin - iRow;
|
||||||
|
tn2.iDuration = iEndRow - rowEnd;
|
||||||
|
|
||||||
|
SetTapNote( iTrack, iRow, tn1 );
|
||||||
|
SetTapNote( iTrack, rowEnd, tn2 );
|
||||||
|
|
||||||
|
/* We may have invalidated our iterators. */
|
||||||
|
GetTapNoteRangeInclusive( iTrack, rowBegin, rowEnd, begin, end );
|
||||||
|
}
|
||||||
|
else if( begin != end && begin->first < rowBegin )
|
||||||
{
|
{
|
||||||
HoldNote hn = GetHoldNote(i);
|
/* A hold note overlaps the beginning of the range. Truncate it. */
|
||||||
if( hn.iTrack != iTrack )
|
TapNote &tn1 = begin->second;
|
||||||
continue;
|
int iRow = begin->first;
|
||||||
|
tn1.iDuration = rowBegin - iRow;
|
||||||
|
|
||||||
if( !hn.RangeOverlaps(rowBegin, rowEnd) )
|
++begin;
|
||||||
continue;
|
}
|
||||||
|
|
||||||
this->RemoveHoldNote( i );
|
if( begin != end )
|
||||||
|
|
||||||
/* If the range encloses the hold note completely, just delete it. */
|
|
||||||
if( hn.ContainedByRange(rowBegin, rowEnd) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( hn.RangeInside(rowBegin, rowEnd) )
|
|
||||||
{
|
{
|
||||||
/* The hold note encloses the range, so we need to split the hold note. */
|
iterator prev = end;
|
||||||
HoldNote hnLater(hn);
|
--prev;
|
||||||
hn.iEndRow = rowBegin;
|
TapNote tn = begin->second;
|
||||||
hnLater.iStartRow = rowEnd;
|
int iRow = prev->first;
|
||||||
this->AddHoldNote( hn );
|
if( tn.type == TapNote::hold_head && iRow + tn.iDuration > rowEnd )
|
||||||
this->AddHoldNote( hnLater );
|
{
|
||||||
continue;
|
/* A hold note overlaps the end of the range. Separate it. */
|
||||||
|
SetTapNote( iTrack, iRow, TAP_EMPTY );
|
||||||
|
|
||||||
|
int iAdd = rowEnd - iRow;
|
||||||
|
tn.iDuration -= iAdd;
|
||||||
|
iRow += iAdd;
|
||||||
|
SetTapNote( iTrack, iRow, tn );
|
||||||
|
end = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( hn.iStartRow < rowBegin )
|
/* We may have invalidated our iterators. */
|
||||||
hn.iEndRow = min( hn.iEndRow, rowBegin );
|
GetTapNoteRangeInclusive( iTrack, rowBegin, rowEnd, begin, end );
|
||||||
else
|
|
||||||
hn.iStartRow = max( hn.iStartRow, rowEnd );
|
|
||||||
this->AddHoldNote( hn );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear other notes in the region. */
|
while( begin != end )
|
||||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, iTrack, r, rowBegin, rowEnd )
|
{
|
||||||
SetTapNote( iTrack, r, TAP_EMPTY );
|
iterator next = begin;
|
||||||
|
++next;
|
||||||
|
|
||||||
|
RemoveTapNote( iTrack, begin );
|
||||||
|
|
||||||
|
begin = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteData::ClearRange( int rowBegin, int rowEnd )
|
void NoteData::ClearRange( int rowBegin, int rowEnd )
|
||||||
@@ -105,7 +118,6 @@ void NoteData::ClearAll()
|
|||||||
{
|
{
|
||||||
for( int t=0; t<GetNumTracks(); t++ )
|
for( int t=0; t<GetNumTracks(); t++ )
|
||||||
m_TapNotes[t].clear();
|
m_TapNotes[t].clear();
|
||||||
m_HoldNotes.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy a range from pFrom to this. (Note that this does *not* overlay;
|
/* Copy a range from pFrom to this. (Note that this does *not* overlay;
|
||||||
@@ -114,97 +126,52 @@ void NoteData::CopyRange( const NoteData& from, int rowFromBegin, int rowFromEnd
|
|||||||
{
|
{
|
||||||
ASSERT( from.GetNumTracks() == GetNumTracks() );
|
ASSERT( from.GetNumTracks() == GetNumTracks() );
|
||||||
|
|
||||||
int rowToEnd = (rowFromEnd-rowFromBegin) + rowToBegin;
|
if( rowFromBegin > rowFromEnd )
|
||||||
|
return; /* empty range */
|
||||||
|
|
||||||
|
const int rowToEnd = (rowFromEnd-rowFromBegin) + rowToBegin;
|
||||||
|
const int iMoveBy = rowToBegin-rowFromBegin;
|
||||||
|
|
||||||
/* Clear the region. */
|
/* Clear the region. */
|
||||||
ClearRange( rowToBegin, rowToEnd );
|
ClearRange( rowToBegin, rowToEnd );
|
||||||
|
|
||||||
/* Copy everything except for hold notes. */
|
|
||||||
for( int t=0; t<GetNumTracks(); t++ )
|
for( int t=0; t<GetNumTracks(); t++ )
|
||||||
{
|
{
|
||||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( from, t, iFrom, rowFromBegin, rowFromEnd )
|
const_iterator begin, end;
|
||||||
|
from.GetTapNoteRangeInclusive( t, rowFromBegin, rowFromEnd, begin, end );
|
||||||
|
for( ; begin != end; ++begin )
|
||||||
{
|
{
|
||||||
const TapNote &tn = from.GetTapNote( t, iFrom );
|
TapNote head = begin->second;
|
||||||
switch( tn.type )
|
if( head.type == TapNote::empty )
|
||||||
{
|
|
||||||
case TapNote::empty:
|
|
||||||
case TapNote::hold_tail:
|
|
||||||
case TapNote::hold_head:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int iTo = rowToBegin + iFrom - rowFromBegin;
|
|
||||||
this->SetTapNote( t, iTo, tn );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy hold notes. */
|
|
||||||
for( int i=0; i<from.GetNumHoldNotes(); i++ ) // for each HoldNote
|
|
||||||
{
|
|
||||||
HoldNote hn = from.GetHoldNote(i);
|
|
||||||
|
|
||||||
if( !hn.RangeOverlaps(rowFromBegin, rowFromEnd) )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Move the hold note. */
|
if( head.type == TapNote::hold_head )
|
||||||
int iMoveBy = rowToBegin-rowFromBegin;
|
|
||||||
hn.iStartRow += iMoveBy;
|
|
||||||
hn.iEndRow += iMoveBy;
|
|
||||||
|
|
||||||
/* Crop the hold note to the region. */
|
|
||||||
hn.iStartRow = max( hn.iStartRow, rowToBegin );
|
|
||||||
hn.iEndRow = min( hn.iEndRow, rowToEnd );
|
|
||||||
|
|
||||||
/* The beginning of the hold might match up to the end of an existing hold, the end
|
|
||||||
* may match with the beginning, or both. */
|
|
||||||
int iEarlierHoldNote = -1, iLaterHoldNote = -1;
|
|
||||||
for( int j=0; j<this->GetNumHoldNotes(); ++j ) // for each HoldNote
|
|
||||||
{
|
{
|
||||||
const HoldNote &hn2 = this->GetHoldNote(j);
|
int iStartRow = begin->first + iMoveBy;
|
||||||
if( hn2.iEndRow == hn.iStartRow )
|
int iEndRow = iStartRow + head.iDuration;
|
||||||
iEarlierHoldNote = j;
|
|
||||||
if( hn2.iStartRow == hn.iEndRow )
|
|
||||||
iLaterHoldNote = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( iEarlierHoldNote != -1 && iLaterHoldNote != -1 )
|
iStartRow = clamp( iStartRow, rowToBegin, rowToEnd );
|
||||||
{
|
iEndRow = clamp( iEndRow, rowToBegin, rowToEnd );
|
||||||
HoldNote &hnEarlier = this->GetHoldNote( iEarlierHoldNote );
|
|
||||||
const HoldNote &hnLater = this->GetHoldNote( iLaterHoldNote );
|
|
||||||
hnEarlier.iEndRow = hnLater.iEndRow;
|
|
||||||
|
|
||||||
this->RemoveHoldNote( iLaterHoldNote );
|
this->AddHoldNote( t, iStartRow, iEndRow, head );
|
||||||
}
|
|
||||||
else if( iEarlierHoldNote == -1 && iLaterHoldNote == -1 )
|
|
||||||
AddHoldNote( hn );
|
|
||||||
else if( iEarlierHoldNote != -1 )
|
|
||||||
{
|
|
||||||
HoldNote &hn2 = this->GetHoldNote(iEarlierHoldNote);
|
|
||||||
hn2.iEndRow = hn.iEndRow;
|
|
||||||
}
|
|
||||||
else if( iLaterHoldNote != -1 )
|
|
||||||
{
|
|
||||||
HoldNote &hn2 = this->GetHoldNote(iLaterHoldNote);
|
|
||||||
hn2.iStartRow = hn.iStartRow;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
FAIL_M(ssprintf("%i,%i", iEarlierHoldNote, iLaterHoldNote));
|
{
|
||||||
|
int iTo = begin->first + iMoveBy;
|
||||||
|
if( iTo >= rowToBegin && iTo <= rowToEnd )
|
||||||
|
this->SetTapNote( t, iTo, head );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void NoteData::Config( const NoteData& from )
|
|
||||||
{
|
|
||||||
SetNumTracks( from.GetNumTracks() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteData::CopyAll( const NoteData& from )
|
void NoteData::CopyAll( const NoteData& from )
|
||||||
{
|
{
|
||||||
Config(from);
|
SetNumTracks( from.GetNumTracks() );
|
||||||
ClearAll();
|
ClearAll();
|
||||||
|
|
||||||
for( int c=0; c<GetNumTracks(); c++ )
|
for( int c=0; c<GetNumTracks(); c++ )
|
||||||
m_TapNotes[c] = from.m_TapNotes[c];
|
m_TapNotes[c] = from.m_TapNotes[c];
|
||||||
m_HoldNotes = from.m_HoldNotes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NoteData::IsRowEmpty( int row ) const
|
bool NoteData::IsRowEmpty( int row ) const
|
||||||
@@ -326,66 +293,65 @@ int NoteData::GetFirstTrackWithTapOrHoldHead( int row ) const
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteData::AddHoldNote( HoldNote add )
|
void NoteData::AddHoldNote( int iTrack, int iStartRow, int iEndRow, TapNote tn )
|
||||||
{
|
{
|
||||||
ASSERT( add.iStartRow>=0 && add.iEndRow>=0 );
|
ASSERT( iStartRow>=0 && iEndRow>=0 );
|
||||||
|
ASSERT( iEndRow >= iStartRow );
|
||||||
|
|
||||||
// look for other hold notes that overlap and merge them
|
tn.iDuration = iEndRow - iStartRow;
|
||||||
for( int i=0; i<GetNumHoldNotes(); i++ ) // for each HoldNote
|
/* Include adjacent (non-overlapping) hold notes, since we need to merge with them. */
|
||||||
{
|
iterator begin, end;
|
||||||
HoldNote &other = GetHoldNote(i);
|
GetTapNoteRangeInclusive( iTrack, iStartRow, iStartRow+tn.iDuration, begin, end, true );
|
||||||
if( add.iTrack == other.iTrack && // the tracks correspond
|
|
||||||
add.RangeOverlaps(other) ) // they overlap
|
|
||||||
{
|
|
||||||
add.iStartRow = min(add.iStartRow, other.iStartRow);
|
|
||||||
add.iEndRow = max(add.iEndRow, other.iEndRow);
|
|
||||||
|
|
||||||
// delete this HoldNote
|
/* Look for other hold notes that overlap and merge them into add. */
|
||||||
RemoveHoldNote( i );
|
for( iterator it = begin; it != end; ++it )
|
||||||
--i;
|
{
|
||||||
|
int iRow = it->first;
|
||||||
|
if( it->second.type == TapNote::hold_head )
|
||||||
|
{
|
||||||
|
if( iRow < iStartRow )
|
||||||
|
{
|
||||||
|
/* extend tn up */
|
||||||
|
int iExtendBy = iStartRow - iRow;
|
||||||
|
tn.iDuration += iExtendBy;
|
||||||
|
iStartRow -= iExtendBy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* extend tn down */
|
||||||
|
int iEndRow = iRow + it->second.iDuration;
|
||||||
|
tn.iDuration = iEndRow - iStartRow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int iAddStartIndex = add.iStartRow;
|
/* Remove everything in the range. */
|
||||||
int iAddEndIndex = add.iEndRow;
|
while( begin != end )
|
||||||
|
{
|
||||||
|
iterator next = begin;
|
||||||
|
++next;
|
||||||
|
|
||||||
// delete TapNotes under this HoldNote
|
RemoveTapNote( iTrack, begin );
|
||||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, add.iTrack, i, iAddStartIndex+1, iAddEndIndex )
|
|
||||||
SetTapNote( add.iTrack, i, TAP_EMPTY );
|
begin = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Additionally, if there's a tap note lying at the end of our range, remove it,
|
||||||
|
* too. */
|
||||||
|
SetTapNote( iTrack, iEndRow, TAP_EMPTY );
|
||||||
|
|
||||||
// add a tap note at the start of this hold
|
// add a tap note at the start of this hold
|
||||||
SetTapNote( add.iTrack, iAddStartIndex, TAP_ORIGINAL_HOLD_HEAD ); // Hold begin marker. Don't draw this, but do grade it.
|
SetTapNote( iTrack, iStartRow, tn );
|
||||||
|
|
||||||
m_HoldNotes.push_back(add);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteData::RemoveHoldNote( int iHoldIndex )
|
/* Return true if a hold note lies on or adjacent to the given spot. */
|
||||||
|
bool NoteData::IsHoldNoteAtBeat( int iTrack, int iRow, int *pHeadRow ) const
|
||||||
{
|
{
|
||||||
ASSERT( iHoldIndex >= 0 && iHoldIndex < GetNumHoldNotes() );
|
|
||||||
|
|
||||||
HoldNote& hn = GetHoldNote(iHoldIndex);
|
|
||||||
|
|
||||||
const int iHoldStartIndex = hn.iStartRow;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if a hold note lies on the given spot. Must be in 2sAnd3s. */
|
|
||||||
bool NoteData::IsHoldNoteAtBeat( int iTrack, int iRow, int *pHeadRow, int *pTailRow ) const
|
|
||||||
{
|
|
||||||
/* If neither the actual head nor tail row were requested, search for the head to
|
|
||||||
* determine the return value. */
|
|
||||||
int iDummy;
|
int iDummy;
|
||||||
if( pHeadRow == NULL )
|
if( pHeadRow == NULL )
|
||||||
pHeadRow = &iDummy;
|
pHeadRow = &iDummy;
|
||||||
|
|
||||||
bool bFoundHead = false;
|
bool bFoundHead = false;
|
||||||
if( pHeadRow != NULL )
|
|
||||||
{
|
|
||||||
/* Starting at iRow, search upwards. If we find a TapNote::hold_head, we're within
|
/* Starting at iRow, search upwards. If we find a TapNote::hold_head, we're within
|
||||||
* a hold. If we find a tap, mine or attack, we're not--those never lie within hold
|
* a hold. If we find a tap, mine or attack, we're not--those never lie within hold
|
||||||
* notes. Ignore autoKeysound. */
|
* notes. Ignore autoKeysound. */
|
||||||
@@ -395,15 +361,17 @@ bool NoteData::IsHoldNoteAtBeat( int iTrack, int iRow, int *pHeadRow, int *pTail
|
|||||||
switch( tn.type )
|
switch( tn.type )
|
||||||
{
|
{
|
||||||
case TapNote::hold_head:
|
case TapNote::hold_head:
|
||||||
|
// if( tn.iDuration + r <= iRow )
|
||||||
|
if( tn.iDuration + r < iRow )
|
||||||
|
return false;
|
||||||
*pHeadRow = r;
|
*pHeadRow = r;
|
||||||
bFoundHead = true;
|
return true;
|
||||||
break;
|
|
||||||
|
|
||||||
case TapNote::tap:
|
case TapNote::tap:
|
||||||
case TapNote::mine:
|
case TapNote::mine:
|
||||||
case TapNote::attack:
|
case TapNote::attack:
|
||||||
case TapNote::hold_tail:
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case TapNote::empty:
|
case TapNote::empty:
|
||||||
case TapNote::autoKeysound:
|
case TapNote::autoKeysound:
|
||||||
/* ignore */
|
/* ignore */
|
||||||
@@ -416,54 +384,7 @@ bool NoteData::IsHoldNoteAtBeat( int iTrack, int iRow, int *pHeadRow, int *pTail
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we didn't find a matching head, we're not within a hold note, so don't bother
|
return bFoundHead;
|
||||||
* searching for a tail. */
|
|
||||||
if( !bFoundHead )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bFoundTail = false;
|
|
||||||
if( pTailRow != NULL )
|
|
||||||
{
|
|
||||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, iTrack, r, iRow, MAX_NOTE_ROW )
|
|
||||||
{
|
|
||||||
const TapNote &tn = GetTapNote( iTrack, r );
|
|
||||||
|
|
||||||
switch( tn.type )
|
|
||||||
{
|
|
||||||
case TapNote::hold_tail:
|
|
||||||
*pTailRow = r;
|
|
||||||
bFoundTail = true;
|
|
||||||
break;
|
|
||||||
case TapNote::tap:
|
|
||||||
case TapNote::mine:
|
|
||||||
case TapNote::attack:
|
|
||||||
return false;
|
|
||||||
case TapNote::hold_head:
|
|
||||||
/* If iRow is a hold head, we're within a hold note, and need to continue searching;
|
|
||||||
* if any row after that is a head, we're not in it, so stop. This is different
|
|
||||||
* than above, since holds are [head,tail); the row of the tail isn't actually
|
|
||||||
* part of the hold. */
|
|
||||||
if( r == iRow )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case TapNote::empty:
|
|
||||||
case TapNote::autoKeysound:
|
|
||||||
/* ignore */
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
FAIL_M( ssprintf("%i", tn.type) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( bFoundTail )
|
|
||||||
break;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bFoundHead || bFoundTail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int NoteData::GetFirstRow() const
|
int NoteData::GetFirstRow() const
|
||||||
@@ -482,13 +403,6 @@ int NoteData::GetFirstRow() const
|
|||||||
iEarliestRowFoundSoFar = min( iEarliestRowFoundSoFar, iRow );
|
iEarliestRowFoundSoFar = min( iEarliestRowFoundSoFar, iRow );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( int i=0; i<GetNumHoldNotes(); i++ )
|
|
||||||
{
|
|
||||||
if( iEarliestRowFoundSoFar == -1 ||
|
|
||||||
GetHoldNote(i).iStartRow < iEarliestRowFoundSoFar )
|
|
||||||
iEarliestRowFoundSoFar = GetHoldNote(i).iStartRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( iEarliestRowFoundSoFar == -1 ) // there are no notes
|
if( iEarliestRowFoundSoFar == -1 ) // there are no notes
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -504,13 +418,14 @@ int NoteData::GetLastRow() const
|
|||||||
int iRow = MAX_NOTE_ROW;
|
int iRow = MAX_NOTE_ROW;
|
||||||
if( !GetPrevTapNoteRowForTrack( t, iRow ) )
|
if( !GetPrevTapNoteRowForTrack( t, iRow ) )
|
||||||
continue;
|
continue;
|
||||||
iOldestRowFoundSoFar = max( iOldestRowFoundSoFar, iRow );
|
|
||||||
}
|
|
||||||
|
|
||||||
for( int i=0; i<GetNumHoldNotes(); i++ )
|
/* XXX: We might have a hold note near the end with autoplay sounds
|
||||||
{
|
* after it. Do something else with autoplay sounds ... */
|
||||||
if( GetHoldNote(i).iEndRow > iOldestRowFoundSoFar )
|
const TapNote &tn = GetTapNote( t, iRow );
|
||||||
iOldestRowFoundSoFar = GetHoldNote(i).iEndRow;
|
if( tn.type == TapNote::hold_head )
|
||||||
|
iRow += tn.iDuration;
|
||||||
|
|
||||||
|
iOldestRowFoundSoFar = max( iOldestRowFoundSoFar, iRow );
|
||||||
}
|
}
|
||||||
|
|
||||||
return iOldestRowFoundSoFar;
|
return iOldestRowFoundSoFar;
|
||||||
@@ -576,7 +491,7 @@ int NoteData::RowNeedsHands( const int row ) const
|
|||||||
{
|
{
|
||||||
case TapNote::mine:
|
case TapNote::mine:
|
||||||
case TapNote::empty:
|
case TapNote::empty:
|
||||||
case TapNote::hold_tail:
|
case TapNote::hold_head: // handled below
|
||||||
continue; // skip these types - they don't count
|
continue; // skip these types - they don't count
|
||||||
}
|
}
|
||||||
++iNumNotesThisIndex;
|
++iNumNotesThisIndex;
|
||||||
@@ -588,11 +503,10 @@ int NoteData::RowNeedsHands( const int row ) const
|
|||||||
|
|
||||||
if( iNumNotesThisIndex < 3 )
|
if( iNumNotesThisIndex < 3 )
|
||||||
{
|
{
|
||||||
/* We have at least one, but not enough. Count holds. */
|
/* We have at least one, but not enough. Count holds. Do count adjacent holds. */
|
||||||
for( int j=0; j<GetNumHoldNotes(); j++ )
|
for( int t=0; t<GetNumTracks(); ++t )
|
||||||
{
|
{
|
||||||
const HoldNote &hn = GetHoldNote(j);
|
if( IsHoldNoteAtBeat(t, row) )
|
||||||
if( hn.iStartRow+1 <= row && row <= hn.iEndRow )
|
|
||||||
++iNumNotesThisIndex;
|
++iNumNotesThisIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -641,84 +555,20 @@ int NoteData::GetNumN( int iMinTaps, int iStartIndex, int iEndIndex ) const
|
|||||||
int NoteData::GetNumHoldNotes( int iStartIndex, int iEndIndex ) const
|
int NoteData::GetNumHoldNotes( int iStartIndex, int iEndIndex ) const
|
||||||
{
|
{
|
||||||
int iNumHolds = 0;
|
int iNumHolds = 0;
|
||||||
for( int i=0; i<GetNumHoldNotes(); i++ )
|
for( int t=0; t<GetNumTracks(); ++t )
|
||||||
{
|
{
|
||||||
const HoldNote &hn = GetHoldNote(i);
|
const_iterator begin, end;
|
||||||
if( iStartIndex <= hn.iStartRow && hn.iEndRow <= iEndIndex )
|
GetTapNoteRangeExclusive( t, iStartIndex, iEndIndex, begin, end );
|
||||||
|
for( ; begin != end; ++begin )
|
||||||
|
{
|
||||||
|
if( begin->second.type != TapNote::hold_head )
|
||||||
|
continue;
|
||||||
iNumHolds++;
|
iNumHolds++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return iNumHolds;
|
return iNumHolds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteData::Convert2sAnd3sToHoldNotes()
|
|
||||||
{
|
|
||||||
// Any note will end a hold (not just a TAP_HOLD_TAIL). This makes parsing DWIs much easier.
|
|
||||||
// Plus, allowing tap notes in the middle of a hold doesn't make sense!
|
|
||||||
|
|
||||||
for( int t=0; t<GetNumTracks(); t++ ) // foreach column
|
|
||||||
{
|
|
||||||
FOREACH_NONEMPTY_ROW_IN_TRACK( *this, t, r )
|
|
||||||
{
|
|
||||||
TapNote head = GetTapNote(t,r);
|
|
||||||
if( head.type != TapNote::hold_head )
|
|
||||||
continue; // skip
|
|
||||||
|
|
||||||
SetTapNote(t, r, TAP_EMPTY); // clear the hold head marker
|
|
||||||
|
|
||||||
// search for end of HoldNote
|
|
||||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, t, j, r+1, MAX_NOTE_ROW )
|
|
||||||
{
|
|
||||||
// End hold on the next note we see. This should be a hold_tail if the
|
|
||||||
// data is in a consistent state, but doesn't have to be.
|
|
||||||
if( GetTapNote(t, j).type == TapNote::empty )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SetTapNote(t, j, TAP_EMPTY);
|
|
||||||
|
|
||||||
HoldNote hold(t, r, j);
|
|
||||||
hold.result = head.HoldResult;
|
|
||||||
AddHoldNote( hold );
|
|
||||||
break; // done searching for the end of this hold
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* "102000301" ==
|
|
||||||
* "104444001" */
|
|
||||||
void NoteData::ConvertHoldNotesTo2sAnd3s()
|
|
||||||
{
|
|
||||||
// copy HoldNotes into the new structure, but expand them into 2s and 3s
|
|
||||||
for( int i=0; i<GetNumHoldNotes(); i++ )
|
|
||||||
{
|
|
||||||
const HoldNote &hn = GetHoldNote(i);
|
|
||||||
|
|
||||||
/* If they're the same, then they got clamped together, so just ignore it. */
|
|
||||||
if( hn.iStartRow == hn.iEndRow )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
TapNote head = TAP_ORIGINAL_HOLD_HEAD;
|
|
||||||
head.HoldResult = hn.result;
|
|
||||||
SetTapNote( hn.iTrack, hn.iStartRow, head );
|
|
||||||
SetTapNote( hn.iTrack, hn.iEndRow, TAP_ORIGINAL_HOLD_TAIL );
|
|
||||||
}
|
|
||||||
m_HoldNotes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void NoteData::To2sAnd3s( const NoteData& from )
|
|
||||||
{
|
|
||||||
CopyAll( from );
|
|
||||||
ConvertHoldNotesTo2sAnd3s();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NoteData::From2sAnd3s( const NoteData& from )
|
|
||||||
{
|
|
||||||
CopyAll( from );
|
|
||||||
Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -1 for iOriginalTracksToTakeFrom means no track
|
// -1 for iOriginalTracksToTakeFrom means no track
|
||||||
void NoteData::LoadTransformed( const NoteData& in, int iNewNumTracks, const int iOriginalTrackToTakeFrom[] )
|
void NoteData::LoadTransformed( const NoteData& in, int iNewNumTracks, const int iOriginalTrackToTakeFrom[] )
|
||||||
{
|
{
|
||||||
@@ -726,10 +576,6 @@ void NoteData::LoadTransformed( const NoteData& in, int iNewNumTracks, const int
|
|||||||
Init();
|
Init();
|
||||||
|
|
||||||
SetNumTracks( iNewNumTracks );
|
SetNumTracks( iNewNumTracks );
|
||||||
ConvertHoldNotesTo2sAnd3s();
|
|
||||||
|
|
||||||
NoteData Input;
|
|
||||||
Input.To2sAnd3s( in );
|
|
||||||
|
|
||||||
// copy tracks
|
// copy tracks
|
||||||
for( int t=0; t<GetNumTracks(); t++ )
|
for( int t=0; t<GetNumTracks(); t++ )
|
||||||
@@ -740,10 +586,8 @@ void NoteData::LoadTransformed( const NoteData& in, int iNewNumTracks, const int
|
|||||||
|
|
||||||
if( iOriginalTrack == -1 )
|
if( iOriginalTrack == -1 )
|
||||||
continue;
|
continue;
|
||||||
m_TapNotes[t] = Input.m_TapNotes[iOriginalTrack];
|
m_TapNotes[t] = in.m_TapNotes[iOriginalTrack];
|
||||||
}
|
}
|
||||||
|
|
||||||
Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteData::MoveTapNoteTrack( int dest, int src )
|
void NoteData::MoveTapNoteTrack( int dest, int src )
|
||||||
@@ -779,12 +623,9 @@ void NoteData::SetTapNote( int track, int row, const TapNote& t )
|
|||||||
|
|
||||||
void NoteData::GetTracksHeldAtRow( int row, set<int>& addTo )
|
void NoteData::GetTracksHeldAtRow( int row, set<int>& addTo )
|
||||||
{
|
{
|
||||||
for( unsigned i=0; i<m_HoldNotes.size(); i++ )
|
for( int t=0; t<GetNumTracks(); ++t )
|
||||||
{
|
if( IsHoldNoteAtBeat( t, row ) )
|
||||||
const HoldNote& hn = m_HoldNotes[i];
|
addTo.insert( t );
|
||||||
if( hn.RowIsInRange(row) )
|
|
||||||
addTo.insert( hn.iTrack );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int NoteData::GetNumTracksHeldAtRow( int row )
|
int NoteData::GetNumTracksHeldAtRow( int row )
|
||||||
@@ -832,21 +673,117 @@ bool NoteData::GetPrevTapNoteRowForTrack( int track, int &rowInOut ) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return an iterator range. This can be used to iterate trackwise over a range of
|
/* Return an iterator range for [rowBegin,rowEnd). This can be used to efficiently
|
||||||
* notes. It's like FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE, except it only requires
|
* iterate trackwise over a range of notes. It's like FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE,
|
||||||
* two map searches (iterating is O(1)), but the iterators will become invalid if
|
* except it only requires two map searches (iterating is constant time), but the iterators will
|
||||||
* the notes they represent disappear, so you need to pay attention to how you modify
|
* become invalid if the notes they represent disappear, so you need to pay attention to
|
||||||
* the data. */
|
* how you modify the data. */
|
||||||
void NoteData::GetTapNoteRange( int iTrack, int iStartRow, int iEndRow, TrackMap::const_iterator &begin, TrackMap::const_iterator &end ) const
|
void NoteData::GetTapNoteRange( int iTrack, int iStartRow, int iEndRow, TrackMap::iterator &begin, TrackMap::iterator &end )
|
||||||
{
|
{
|
||||||
ASSERT_M( iTrack < GetNumTracks(), ssprintf("%i,%i", iTrack, GetNumTracks()) );
|
ASSERT_M( iTrack < GetNumTracks(), ssprintf("%i,%i", iTrack, GetNumTracks()) );
|
||||||
ASSERT_M( iStartRow <= iEndRow, ssprintf("%i > %i", iStartRow, iEndRow) );
|
TrackMap &mapTrack = m_TapNotes[iTrack];
|
||||||
|
|
||||||
const TrackMap &mapTrack = m_TapNotes[iTrack];
|
if( iStartRow > iEndRow )
|
||||||
|
{
|
||||||
|
begin = end = mapTrack.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( iStartRow == 0 )
|
||||||
|
begin = mapTrack.begin(); /* optimization */
|
||||||
|
else if( iStartRow == MAX_NOTE_ROW )
|
||||||
|
begin = mapTrack.end(); /* optimization */
|
||||||
|
else
|
||||||
begin = mapTrack.lower_bound( iStartRow );
|
begin = mapTrack.lower_bound( iStartRow );
|
||||||
end = mapTrack.upper_bound( iEndRow );
|
|
||||||
|
if( iEndRow == 0 )
|
||||||
|
end = mapTrack.begin(); /* optimization */
|
||||||
|
else if( iEndRow == MAX_NOTE_ROW )
|
||||||
|
end = mapTrack.end(); /* optimization */
|
||||||
|
else
|
||||||
|
end = mapTrack.lower_bound( iEndRow );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Include hold notes that overlap the edges. If a hold note completely surrounds the given
|
||||||
|
* range, included it, too. If bIncludeAdjacent is true, also include hold notes adjacent to,
|
||||||
|
* but not overlapping, the edge. */
|
||||||
|
void NoteData::GetTapNoteRangeInclusive( int iTrack, int iStartRow, int iEndRow, iterator &begin, iterator &end, bool bIncludeAdjacent )
|
||||||
|
{
|
||||||
|
GetTapNoteRange( iTrack, iStartRow, iEndRow, begin, end );
|
||||||
|
|
||||||
|
if( begin != this->begin(iTrack) )
|
||||||
|
{
|
||||||
|
iterator prev = Decrement(begin);
|
||||||
|
|
||||||
|
const TapNote &tn = prev->second;
|
||||||
|
if( tn.type == TapNote::hold_head )
|
||||||
|
{
|
||||||
|
int iHoldStartRow = prev->first;
|
||||||
|
int iHoldEndRow = iHoldStartRow + tn.iDuration;
|
||||||
|
if( iHoldEndRow > iStartRow || (bIncludeAdjacent && iHoldEndRow == iStartRow ) )
|
||||||
|
{
|
||||||
|
/* The previous note is a hold. */
|
||||||
|
begin = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bIncludeAdjacent && end != this->end(iTrack) )
|
||||||
|
{
|
||||||
|
/* Include the next note if it's a hold and starts on iEndRow. */
|
||||||
|
const TapNote &tn = end->second;
|
||||||
|
int iHoldStartRow = end->first;
|
||||||
|
if( tn.type == TapNote::hold_head && iHoldStartRow == iEndRow )
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteData::GetTapNoteRangeExclusive( int iTrack, int iStartRow, int iEndRow, iterator &begin, iterator &end )
|
||||||
|
{
|
||||||
|
GetTapNoteRange( iTrack, iStartRow, iEndRow, begin, end );
|
||||||
|
|
||||||
|
/* If end-1 is a hold_head, and extends beyond iEndRow, exclude it. */
|
||||||
|
if( begin != end && end != this->begin(iTrack) )
|
||||||
|
{
|
||||||
|
iterator prev = end;
|
||||||
|
--prev;
|
||||||
|
if( prev->second.type == TapNote::hold_head )
|
||||||
|
{
|
||||||
|
int iStartRow = prev->first;
|
||||||
|
const TapNote &tn = prev->second;
|
||||||
|
if( iStartRow + tn.iDuration >= iEndRow )
|
||||||
|
end = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteData::GetTapNoteRange( int iTrack, int iStartRow, int iEndRow, TrackMap::const_iterator &begin, TrackMap::const_iterator &end ) const
|
||||||
|
{
|
||||||
|
TrackMap::iterator const_begin, const_end;
|
||||||
|
const_cast<NoteData *>(this)->GetTapNoteRange( iTrack, iStartRow, iEndRow, const_begin, const_end );
|
||||||
|
begin = const_begin;
|
||||||
|
end = const_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteData::GetTapNoteRangeInclusive( int iTrack, int iStartRow, int iEndRow, TrackMap::const_iterator &begin, TrackMap::const_iterator &end, bool bIncludeAdjacent ) const
|
||||||
|
{
|
||||||
|
TrackMap::iterator const_begin, const_end;
|
||||||
|
const_cast<NoteData *>(this)->GetTapNoteRangeInclusive( iTrack, iStartRow, iEndRow, const_begin, const_end, bIncludeAdjacent );
|
||||||
|
begin = const_begin;
|
||||||
|
end = const_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteData::GetTapNoteRangeExclusive( int iTrack, int iStartRow, int iEndRow, TrackMap::const_iterator &begin, TrackMap::const_iterator &end ) const
|
||||||
|
{
|
||||||
|
TrackMap::iterator const_begin, const_end;
|
||||||
|
const_cast<NoteData *>(this)->GetTapNoteRange( iTrack, iStartRow, iEndRow, const_begin, const_end );
|
||||||
|
begin = const_begin;
|
||||||
|
end = const_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool NoteData::GetNextTapNoteRowForAllTracks( int &rowInOut ) const
|
bool NoteData::GetNextTapNoteRowForAllTracks( int &rowInOut ) const
|
||||||
{
|
{
|
||||||
int iClosestNextRow = MAX_NOTE_ROW;
|
int iClosestNextRow = MAX_NOTE_ROW;
|
||||||
@@ -873,6 +810,68 @@ bool NoteData::GetNextTapNoteRowForAllTracks( int &rowInOut ) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NoteData::InsertHoldTails()
|
||||||
|
{
|
||||||
|
for( int t=0; t<GetNumTracks(); t++ )
|
||||||
|
{
|
||||||
|
iterator begin, end;
|
||||||
|
GetTapNoteRange( t, 0, MAX_NOTE_ROW, begin, end );
|
||||||
|
|
||||||
|
for( ; begin != end; ++begin )
|
||||||
|
{
|
||||||
|
int iRow = begin->first;
|
||||||
|
const TapNote &tn = begin->second;
|
||||||
|
if( tn.type != TapNote::hold_head )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TapNote tail = tn;
|
||||||
|
tail.type = TapNote::hold_tail;
|
||||||
|
SetTapNote( t, iRow + tn.iDuration, tail );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteData::RemoveHoldTails()
|
||||||
|
{
|
||||||
|
for( int t=0; t<GetNumTracks(); t++ )
|
||||||
|
{
|
||||||
|
iterator begin, end;
|
||||||
|
GetTapNoteRange( t, 0, MAX_NOTE_ROW, begin, end );
|
||||||
|
|
||||||
|
iterator next;
|
||||||
|
for( ; begin != end; begin = next )
|
||||||
|
{
|
||||||
|
next = begin; ++next;
|
||||||
|
|
||||||
|
int iStartRow = begin->first;
|
||||||
|
const TapNote &tn = begin->second;
|
||||||
|
if( tn.type != TapNote::hold_head )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Search forward until we find a hold_tail. */
|
||||||
|
iterator tail = begin;
|
||||||
|
|
||||||
|
while( tail != end && tail->second.type != TapNote::hold_tail )
|
||||||
|
++tail;
|
||||||
|
|
||||||
|
if( tail == end )
|
||||||
|
{
|
||||||
|
/* If we didn't find one, the hold is invalid; delete it. */
|
||||||
|
RemoveTapNote( t, begin );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Delete the tail, and update iDuration of the head. */
|
||||||
|
if( next == tail )
|
||||||
|
++next;
|
||||||
|
int iEndRow = tail->first;
|
||||||
|
begin->second.iDuration = iEndRow - iStartRow;
|
||||||
|
RemoveTapNote( t, tail );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (c) 2001-2004 Chris Danford, Glenn Maynard
|
* (c) 2001-2004 Chris Danford, Glenn Maynard
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|||||||
+36
-30
@@ -11,32 +11,27 @@
|
|||||||
#define FOREACH_NONEMPTY_ROW_IN_TRACK( nd, track, row ) \
|
#define FOREACH_NONEMPTY_ROW_IN_TRACK( nd, track, row ) \
|
||||||
for( int row = -1; (nd).GetNextTapNoteRowForTrack(track,row); )
|
for( int row = -1; (nd).GetNextTapNoteRowForTrack(track,row); )
|
||||||
#define FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( nd, track, row, start, last ) \
|
#define FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( nd, track, row, start, last ) \
|
||||||
for( int row = start-1; (nd).GetNextTapNoteRowForTrack(track,row) && row <= (last); )
|
for( int row = start-1; (nd).GetNextTapNoteRowForTrack(track,row) && row < (last); )
|
||||||
#define FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE_REVERSE( nd, track, row, start, last ) \
|
#define FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE_REVERSE( nd, track, row, start, last ) \
|
||||||
for( int row = last+1; (nd).GetPrevTapNoteRowForTrack(track,row) && row >= (start); )
|
for( int row = last; (nd).GetPrevTapNoteRowForTrack(track,row) && row >= (start); )
|
||||||
#define FOREACH_NONEMPTY_ROW_ALL_TRACKS( nd, row ) \
|
#define FOREACH_NONEMPTY_ROW_ALL_TRACKS( nd, row ) \
|
||||||
for( int row = -1; (nd).GetNextTapNoteRowForAllTracks(row); )
|
for( int row = -1; (nd).GetNextTapNoteRowForAllTracks(row); )
|
||||||
#define FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( nd, row, start, last ) \
|
#define FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( nd, row, start, last ) \
|
||||||
for( int row = start-1; (nd).GetNextTapNoteRowForAllTracks(row) && row <= (last); )
|
for( int row = start-1; (nd).GetNextTapNoteRowForAllTracks(row) && row < (last); )
|
||||||
|
|
||||||
class NoteData
|
class NoteData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef map<int,TapNote> TrackMap;
|
typedef map<int,TapNote> TrackMap;
|
||||||
|
typedef map<int,TapNote>::iterator iterator;
|
||||||
|
typedef map<int,TapNote>::const_iterator const_iterator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// There's no point in inserting empty notes into the map.
|
// There's no point in inserting empty notes into the map.
|
||||||
// Any blank space in the map is defined to be empty.
|
// Any blank space in the map is defined to be empty.
|
||||||
vector<TrackMap> m_TapNotes;
|
vector<TrackMap> m_TapNotes;
|
||||||
|
|
||||||
vector<HoldNote> m_HoldNotes;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Set up to hold the data in From; same number of tracks, same
|
|
||||||
* divisor. Doesn't allocate or copy anything. */
|
|
||||||
void Config( const NoteData& from );
|
|
||||||
|
|
||||||
NoteData();
|
NoteData();
|
||||||
~NoteData();
|
~NoteData();
|
||||||
void Init();
|
void Init();
|
||||||
@@ -56,6 +51,30 @@ public:
|
|||||||
return TAP_EMPTY;
|
return TAP_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator begin( int iTrack ) { return m_TapNotes[iTrack].begin(); }
|
||||||
|
const_iterator begin( int iTrack ) const { return m_TapNotes[iTrack].begin(); }
|
||||||
|
iterator end( int iTrack ) { return m_TapNotes[iTrack].end(); }
|
||||||
|
const_iterator end( int iTrack ) const { return m_TapNotes[iTrack].end(); }
|
||||||
|
|
||||||
|
inline iterator FindTapNote( unsigned iTrack, int iRow ) { return m_TapNotes[iTrack].find( iRow ); }
|
||||||
|
inline const_iterator FindTapNote( unsigned iTrack, int iRow ) const { return m_TapNotes[iTrack].find( iRow ); }
|
||||||
|
void RemoveTapNote( unsigned iTrack, iterator it ) { m_TapNotes[iTrack].erase( it ); }
|
||||||
|
|
||||||
|
/* Return an iterator range including exactly iStartRow to iEndRow. */
|
||||||
|
void GetTapNoteRange( int iTrack, int iStartRow, int iEndRow, const_iterator &begin, const_iterator &end ) const;
|
||||||
|
void GetTapNoteRange( int iTrack, int iStartRow, int iEndRow, TrackMap::iterator &begin, TrackMap::iterator &end );
|
||||||
|
|
||||||
|
/* Return an iterator range include iStartRow to iEndRow. Extend the range to include
|
||||||
|
* hold notes overlapping the boundary. */
|
||||||
|
void GetTapNoteRangeInclusive( int iTrack, int iStartRow, int iEndRow, const_iterator &begin, const_iterator &end, bool bIncludeAdjacent=false ) const;
|
||||||
|
void GetTapNoteRangeInclusive( int iTrack, int iStartRow, int iEndRow, iterator &begin, iterator &end, bool bIncludeAdjacent=false );
|
||||||
|
|
||||||
|
/* Return an iterator range include iStartRow to iEndRow. Shrink the range to exclude
|
||||||
|
* hold notes overlapping the boundary. */
|
||||||
|
void GetTapNoteRangeExclusive( int iTrack, int iStartRow, int iEndRow, const_iterator &begin, const_iterator &end ) const;
|
||||||
|
void GetTapNoteRangeExclusive( int iTrack, int iStartRow, int iEndRow, iterator &begin, iterator &end );
|
||||||
|
|
||||||
|
|
||||||
// Use this to iterate over notes.
|
// Use this to iterate over notes.
|
||||||
// Returns the row index of the first TapNote on the track that has a row
|
// Returns the row index of the first TapNote on the track that has a row
|
||||||
// index > afterRow.
|
// index > afterRow.
|
||||||
@@ -63,10 +82,9 @@ public:
|
|||||||
bool GetNextTapNoteRowForAllTracks( int &rowInOut ) const;
|
bool GetNextTapNoteRowForAllTracks( int &rowInOut ) const;
|
||||||
bool GetPrevTapNoteRowForTrack( int track, int &rowInOut ) const;
|
bool GetPrevTapNoteRowForTrack( int track, int &rowInOut ) const;
|
||||||
|
|
||||||
void GetTapNoteRange( int iTrack, int iStartRow, int iEndRow, TrackMap::const_iterator &begin, TrackMap::const_iterator &end ) const;
|
|
||||||
|
|
||||||
void MoveTapNoteTrack( int dest, int src );
|
void MoveTapNoteTrack( int dest, int src );
|
||||||
void SetTapNote( int track, int row, const TapNote& tn );
|
void SetTapNote( int track, int row, const TapNote& tn );
|
||||||
|
void AddHoldNote( int iTrack, int iStartRow, int iEndRow, TapNote tn ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath
|
||||||
|
|
||||||
void ClearRangeForTrack( int rowBegin, int rowEnd, int iTrack );
|
void ClearRangeForTrack( int rowBegin, int rowEnd, int iTrack );
|
||||||
void ClearRange( int rowBegin, int rowEnd );
|
void ClearRange( int rowBegin, int rowEnd );
|
||||||
@@ -97,19 +115,10 @@ public:
|
|||||||
void GetTracksHeldAtRow( int row, set<int>& addTo );
|
void GetTracksHeldAtRow( int row, set<int>& addTo );
|
||||||
int GetNumTracksHeldAtRow( int row );
|
int GetNumTracksHeldAtRow( int row );
|
||||||
|
|
||||||
//
|
|
||||||
// used in edit/record
|
|
||||||
//
|
|
||||||
void AddHoldNote( HoldNote newNote ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath
|
|
||||||
void RemoveHoldNote( int index );
|
|
||||||
HoldNote &GetHoldNote( int index ) { ASSERT( index < (int) m_HoldNotes.size() ); return m_HoldNotes[index]; }
|
|
||||||
const HoldNote &GetHoldNote( int index ) const { ASSERT( index < (int) m_HoldNotes.size() ); return m_HoldNotes[index]; }
|
|
||||||
|
|
||||||
/* Determine if a given spot is within a hold note (being on the tail doesn't count).
|
/* Determine if a given spot is within a hold note (being on the tail doesn't count).
|
||||||
* Return true if so. If pHeadRow is non-NULL, return the row of the head. If pTailRow is
|
* Return true if so. If pHeadRow is non-NULL, return the row of the head. If pTailRow is
|
||||||
* non-NULL, return the row of the tail. This function is faster if pTailRow is NULL.
|
* non-NULL, return the row of the tail. This function is faster if pTailRow is NULL. */
|
||||||
* Must be in 2sAnd3s. */
|
bool IsHoldNoteAtBeat( int iTrack, int iRow, int *pHeadRow = NULL ) const;
|
||||||
bool IsHoldNoteAtBeat( int iTrack, int iRow, int *pHeadRow = NULL, int *pTailRow = NULL ) const;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// statistics
|
// statistics
|
||||||
@@ -127,18 +136,15 @@ public:
|
|||||||
// should hands also count as a jump?
|
// should hands also count as a jump?
|
||||||
int GetNumDoubles( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const { return GetNumN( 2, iStartIndex, iEndIndex ); }
|
int GetNumDoubles( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const { return GetNumN( 2, iStartIndex, iEndIndex ); }
|
||||||
/* optimization: for the default of start to end, use the second (faster) */
|
/* optimization: for the default of start to end, use the second (faster) */
|
||||||
int GetNumHoldNotes( const int iStartIndex, const int iEndIndex = MAX_NOTE_ROW ) const;
|
int GetNumHoldNotes( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const;
|
||||||
int GetNumHoldNotes() const { return m_HoldNotes.size(); }
|
|
||||||
int RowNeedsHands( int row ) const;
|
int RowNeedsHands( int row ) const;
|
||||||
|
|
||||||
// Transformations
|
// Transformations
|
||||||
void LoadTransformed( const NoteData& original, int iNewNumTracks, const int iOriginalTrackToTakeFrom[] ); // -1 for iOriginalTracksToTakeFrom means no track
|
void LoadTransformed( const NoteData& original, int iNewNumTracks, const int iOriginalTrackToTakeFrom[] ); // -1 for iOriginalTracksToTakeFrom means no track
|
||||||
|
|
||||||
// Convert between HoldNote representation and '2' and '3' markers in TapNotes
|
/* hold_tail is only used to make SM parsing easier. */
|
||||||
void Convert2sAnd3sToHoldNotes();
|
void InsertHoldTails();
|
||||||
void ConvertHoldNotesTo2sAnd3s();
|
void RemoveHoldTails(); /* adjusts iDuration */
|
||||||
void To2sAnd3s( const NoteData& from );
|
|
||||||
void From2sAnd3s( const NoteData& from );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+161
-162
@@ -181,7 +181,8 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.Convert2sAnd3sToHoldNotes();
|
|
||||||
|
out.RemoveHoldTails();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDataUtil::GetSMNoteDataString( const NoteData &in_, CString ¬es_out )
|
void NoteDataUtil::GetSMNoteDataString( const NoteData &in_, CString ¬es_out )
|
||||||
@@ -189,8 +190,8 @@ void NoteDataUtil::GetSMNoteDataString( const NoteData &in_, CString ¬es_out
|
|||||||
//
|
//
|
||||||
// Get note data
|
// Get note data
|
||||||
//
|
//
|
||||||
NoteData in;
|
NoteData in( in_ );
|
||||||
in.To2sAnd3s( in_ );
|
in.InsertHoldTails();
|
||||||
|
|
||||||
float fLastBeat = in.GetLastBeat();
|
float fLastBeat = in.GetLastBeat();
|
||||||
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
|
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
|
||||||
@@ -264,21 +265,17 @@ void NoteDataUtil::LoadTransformedSlidingWindow( const NoteData &in, NoteData &o
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteData Original;
|
|
||||||
Original.To2sAnd3s( in );
|
|
||||||
|
|
||||||
out.Config( in );
|
|
||||||
out.SetNumTracks( iNewNumTracks );
|
out.SetNumTracks( iNewNumTracks );
|
||||||
|
|
||||||
|
|
||||||
int iCurTrackOffset = 0;
|
int iCurTrackOffset = 0;
|
||||||
int iTrackOffsetMin = 0;
|
int iTrackOffsetMin = 0;
|
||||||
int iTrackOffsetMax = abs( iNewNumTracks - Original.GetNumTracks() );
|
int iTrackOffsetMax = abs( iNewNumTracks - in.GetNumTracks() );
|
||||||
int bOffsetIncreasing = true;
|
int bOffsetIncreasing = true;
|
||||||
|
|
||||||
int iLastMeasure = 0;
|
int iLastMeasure = 0;
|
||||||
int iMeasuresSinceChange = 0;
|
int iMeasuresSinceChange = 0;
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS( Original, r )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS( in, r )
|
||||||
{
|
{
|
||||||
const int iMeasure = r / ROWS_PER_MEASURE;
|
const int iMeasure = r / ROWS_PER_MEASURE;
|
||||||
if( iMeasure != iLastMeasure )
|
if( iMeasure != iLastMeasure )
|
||||||
@@ -289,10 +286,10 @@ void NoteDataUtil::LoadTransformedSlidingWindow( const NoteData &in, NoteData &o
|
|||||||
// See if there is a hold crossing the beginning of this measure
|
// See if there is a hold crossing the beginning of this measure
|
||||||
bool bHoldCrossesThisMeasure = false;
|
bool bHoldCrossesThisMeasure = false;
|
||||||
|
|
||||||
for( int t=0; t<Original.GetNumTracks(); t++ )
|
for( int t=0; t<in.GetNumTracks(); t++ )
|
||||||
{
|
{
|
||||||
if( Original.IsHoldNoteAtBeat( t, r-1 ) &&
|
if( in.IsHoldNoteAtBeat( t, r-1 ) &&
|
||||||
Original.IsHoldNoteAtBeat( t, r ) )
|
in.IsHoldNoteAtBeat( t, r ) )
|
||||||
{
|
{
|
||||||
bHoldCrossesThisMeasure = true;
|
bHoldCrossesThisMeasure = true;
|
||||||
break;
|
break;
|
||||||
@@ -313,25 +310,20 @@ void NoteDataUtil::LoadTransformedSlidingWindow( const NoteData &in, NoteData &o
|
|||||||
iLastMeasure = iMeasure;
|
iLastMeasure = iMeasure;
|
||||||
|
|
||||||
// copy notes in this measure
|
// copy notes in this measure
|
||||||
for( int t=0; t<Original.GetNumTracks(); t++ )
|
for( int t=0; t<in.GetNumTracks(); t++ )
|
||||||
{
|
{
|
||||||
int iOldTrack = t;
|
int iOldTrack = t;
|
||||||
int iNewTrack = (iOldTrack + iCurTrackOffset) % iNewNumTracks;
|
int iNewTrack = (iOldTrack + iCurTrackOffset) % iNewNumTracks;
|
||||||
const TapNote &tn = Original.GetTapNote( iOldTrack, r );
|
const TapNote &tn = in.GetTapNote( iOldTrack, r );
|
||||||
out.SetTapNote( iNewTrack, r, tn );
|
out.SetTapNote( iNewTrack, r, tn );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDataUtil::LoadOverlapped( const NoteData &input, NoteData &out, int iNewNumTracks )
|
void NoteDataUtil::LoadOverlapped( const NoteData &in, NoteData &out, int iNewNumTracks )
|
||||||
{
|
{
|
||||||
out.SetNumTracks( iNewNumTracks );
|
out.SetNumTracks( iNewNumTracks );
|
||||||
|
|
||||||
NoteData in;
|
|
||||||
in.To2sAnd3s( input );
|
|
||||||
|
|
||||||
/* Keep track of the last source track that put a tap into each destination track,
|
/* Keep track of the last source track that put a tap into each destination track,
|
||||||
* and the row of that tap. Then, if two rows are trying to put taps into the
|
* and the row of that tap. Then, if two rows are trying to put taps into the
|
||||||
* same row within the shift threshold, shift the newcomer source row. */
|
* same row within the shift threshold, shift the newcomer source row. */
|
||||||
@@ -356,13 +348,11 @@ void NoteDataUtil::LoadOverlapped( const NoteData &input, NoteData &out, int iNe
|
|||||||
const TapNote &tnFrom = in.GetTapNote( iTrackFrom, row );
|
const TapNote &tnFrom = in.GetTapNote( iTrackFrom, row );
|
||||||
if( tnFrom.type == TapNote::empty )
|
if( tnFrom.type == TapNote::empty )
|
||||||
continue;
|
continue;
|
||||||
if( tnFrom.type == TapNote::hold_tail )
|
|
||||||
continue; /* copied with hold_head */
|
|
||||||
|
|
||||||
/* If this is a hold note, find the end. */
|
/* If this is a hold note, find the end. */
|
||||||
int iEndIndex = row;
|
int iEndIndex = row;
|
||||||
if( tnFrom.type == TapNote::hold_head )
|
if( tnFrom.type == TapNote::hold_head )
|
||||||
in.IsHoldNoteAtBeat( iTrackFrom, row, NULL, &iEndIndex );
|
iEndIndex = row + tnFrom.iDuration;
|
||||||
|
|
||||||
int &iTrackTo = DestRow[iTrackFrom];
|
int &iTrackTo = DestRow[iTrackFrom];
|
||||||
if( LastSourceTrack[iTrackTo] != iTrackFrom )
|
if( LastSourceTrack[iTrackTo] != iTrackFrom )
|
||||||
@@ -391,8 +381,6 @@ void NoteDataUtil::LoadOverlapped( const NoteData &input, NoteData &out, int iNe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int FindLongestOverlappingHoldNoteForAnyTrack( const NoteData &in, int iRow )
|
int FindLongestOverlappingHoldNoteForAnyTrack( const NoteData &in, int iRow )
|
||||||
@@ -400,11 +388,12 @@ int FindLongestOverlappingHoldNoteForAnyTrack( const NoteData &in, int iRow )
|
|||||||
int iMaxTailRow = -1;
|
int iMaxTailRow = -1;
|
||||||
for( int t=0; t<in.GetNumTracks(); t++ )
|
for( int t=0; t<in.GetNumTracks(); t++ )
|
||||||
{
|
{
|
||||||
int iTailRow;
|
for( int t=0; t<in.GetNumTracks(); t++ )
|
||||||
if( !in.IsHoldNoteAtBeat( t, iRow, NULL, &iTailRow ) )
|
{
|
||||||
continue;
|
const TapNote &tn = in.GetTapNote( t, iRow );
|
||||||
|
if( tn.type == TapNote::hold_head )
|
||||||
iMaxTailRow = max( iMaxTailRow, iTailRow );
|
iMaxTailRow = max( iMaxTailRow, iRow + tn.iDuration );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return iMaxTailRow;
|
return iMaxTailRow;
|
||||||
@@ -415,9 +404,6 @@ void NoteDataUtil::LoadTransformedLights( const NoteData &in, NoteData &out, int
|
|||||||
// reset all notes
|
// reset all notes
|
||||||
out.Init();
|
out.Init();
|
||||||
|
|
||||||
NoteData Original;
|
|
||||||
Original.To2sAnd3s( in );
|
|
||||||
|
|
||||||
out.SetNumTracks( iNewNumTracks );
|
out.SetNumTracks( iNewNumTracks );
|
||||||
|
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS( in, r )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS( in, r )
|
||||||
@@ -428,7 +414,7 @@ void NoteDataUtil::LoadTransformedLights( const NoteData &in, NoteData &out, int
|
|||||||
int iHoldEnd = -1;
|
int iHoldEnd = -1;
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
int iMaxTailRow = FindLongestOverlappingHoldNoteForAnyTrack( Original, r );
|
int iMaxTailRow = FindLongestOverlappingHoldNoteForAnyTrack( in, r );
|
||||||
if( iMaxTailRow == -1 )
|
if( iMaxTailRow == -1 )
|
||||||
break;
|
break;
|
||||||
iHoldEnd = iMaxTailRow;
|
iHoldEnd = iMaxTailRow;
|
||||||
@@ -438,16 +424,12 @@ void NoteDataUtil::LoadTransformedLights( const NoteData &in, NoteData &out, int
|
|||||||
if( iHoldEnd != -1 )
|
if( iHoldEnd != -1 )
|
||||||
{
|
{
|
||||||
/* If we found a hold note, add it to all tracks. */
|
/* If we found a hold note, add it to all tracks. */
|
||||||
HoldNote hn( 0, iHoldStart, iHoldEnd );
|
for( int t=0; t<in.GetNumTracks(); t++ )
|
||||||
for( int t=0; t<Original.GetNumTracks(); t++ )
|
out.AddHoldNote( t, iHoldStart, iHoldEnd, TAP_ORIGINAL_HOLD_HEAD );
|
||||||
{
|
|
||||||
hn.iTrack = t;
|
|
||||||
out.AddHoldNote( hn );
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Original.IsRowEmpty( r ) )
|
if( in.IsRowEmpty( r ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Enable every track in the output. */
|
/* Enable every track in the output. */
|
||||||
@@ -554,14 +536,16 @@ float NoteDataUtil::GetChaosRadarValue( const NoteData &in, float fSongSeconds )
|
|||||||
void NoteDataUtil::RemoveHoldNotes( NoteData &in, int iStartIndex, int iEndIndex )
|
void NoteDataUtil::RemoveHoldNotes( NoteData &in, int iStartIndex, int iEndIndex )
|
||||||
{
|
{
|
||||||
// turn all the HoldNotes into TapNotes
|
// turn all the HoldNotes into TapNotes
|
||||||
for( int i=in.GetNumHoldNotes()-1; i>=0; i-- ) // iterate backwards so we can delete
|
for( int t=0; t<in.GetNumTracks(); ++t )
|
||||||
{
|
{
|
||||||
const HoldNote hn = in.GetHoldNote( i );
|
NoteData::iterator begin, end;
|
||||||
if( !hn.RangeOverlaps(iStartIndex,iEndIndex) )
|
in.GetTapNoteRangeInclusive( t, iStartIndex, iEndIndex, begin, end );
|
||||||
continue; // skip
|
for( ; begin != end; ++begin )
|
||||||
|
{
|
||||||
in.RemoveHoldNote( i );
|
if( begin->second.type != TapNote::hold_head )
|
||||||
in.SetTapNote( hn.iTrack, hn.iStartRow, TAP_ORIGINAL_TAP );
|
continue;
|
||||||
|
begin->second.type = TapNote::tap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,22 +563,19 @@ void NoteDataUtil::RemoveSimultaneousNotes( NoteData &in, int iMaxSimultaneous,
|
|||||||
int iTracksToRemove = max( 0, iTotalTracksPressed - iMaxSimultaneous );
|
int iTracksToRemove = max( 0, iTotalTracksPressed - iMaxSimultaneous );
|
||||||
for( int t=0; iTracksToRemove>0 && t<in.GetNumTracks(); t++ )
|
for( int t=0; iTracksToRemove>0 && t<in.GetNumTracks(); t++ )
|
||||||
{
|
{
|
||||||
if( in.GetTapNote(t,r).type == TapNote::tap )
|
const TapNote &tn = in.GetTapNote(t,r);
|
||||||
|
if( tn.type == TapNote::tap )
|
||||||
{
|
{
|
||||||
in.SetTapNote( t, r, TAP_EMPTY );
|
in.SetTapNote( t, r, TAP_EMPTY );
|
||||||
iTracksToRemove--;
|
iTracksToRemove--;
|
||||||
}
|
}
|
||||||
else if( in.GetTapNote(t,r).type == TapNote::hold_head )
|
else if( tn.type == TapNote::hold_head )
|
||||||
{
|
{
|
||||||
int i;
|
int iStartTrack;
|
||||||
for( i=0; i<in.GetNumHoldNotes(); i++ )
|
if( !in.IsHoldNoteAtBeat( t, r, &iStartTrack ) )
|
||||||
{
|
continue;
|
||||||
const HoldNote& hn = in.GetHoldNote(i);
|
|
||||||
if( hn.iStartRow == r )
|
in.SetTapNote( t, iStartTrack, TAP_EMPTY );
|
||||||
break;
|
|
||||||
}
|
|
||||||
ASSERT( i<in.GetNumHoldNotes() ); // if we hit this, there was a hold head with no hold
|
|
||||||
in.RemoveHoldNote( i );
|
|
||||||
iTracksToRemove--;
|
iTracksToRemove--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -782,14 +763,13 @@ static void GetTrackMapping( StepsType st, NoteDataUtil::TrackMapping tt, int Nu
|
|||||||
|
|
||||||
static void SuperShuffleTaps( NoteData &inout, int iStartIndex, int iEndIndex )
|
static void SuperShuffleTaps( NoteData &inout, int iStartIndex, int iEndIndex )
|
||||||
{
|
{
|
||||||
// convert to 2sAnd3s before calling this
|
/*
|
||||||
ASSERT( inout.GetNumHoldNotes() == 0 );
|
* We already did the normal shuffling code above, which did a good job
|
||||||
|
|
||||||
/* We already did the normal shuffling code above, which did a good job
|
|
||||||
* of shuffling HoldNotes without creating impossible patterns.
|
* of shuffling HoldNotes without creating impossible patterns.
|
||||||
* Now, go in and shuffle the TapNotes per-row.
|
* Now, go in and shuffle the TapNotes per-row.
|
||||||
*
|
*
|
||||||
* This is only called by NoteDataUtil::Turn. "in" is in 2sAnd3s. */
|
* This is only called by NoteDataUtil::Turn.
|
||||||
|
*/
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, r, iStartIndex, iEndIndex )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, r, iStartIndex, iEndIndex )
|
||||||
{
|
{
|
||||||
for( int t1=0; t1<inout.GetNumTracks(); t1++ )
|
for( int t1=0; t1<inout.GetNumTracks(); t1++ )
|
||||||
@@ -799,7 +779,6 @@ static void SuperShuffleTaps( NoteData &inout, int iStartIndex, int iEndIndex )
|
|||||||
{
|
{
|
||||||
case TapNote::empty:
|
case TapNote::empty:
|
||||||
case TapNote::hold_head:
|
case TapNote::hold_head:
|
||||||
case TapNote::hold_tail:
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -834,12 +813,7 @@ void NoteDataUtil::Turn( NoteData &inout, StepsType st, TrackMapping tt, int iSt
|
|||||||
tempNoteData.LoadTransformed( inout, inout.GetNumTracks(), iTakeFromTrack );
|
tempNoteData.LoadTransformed( inout, inout.GetNumTracks(), iTakeFromTrack );
|
||||||
|
|
||||||
if( tt == super_shuffle )
|
if( tt == super_shuffle )
|
||||||
{
|
SuperShuffleTaps( tempNoteData, iStartIndex, iEndIndex );
|
||||||
NoteData tempNoteData2; // write into here as we tranform
|
|
||||||
tempNoteData2.To2sAnd3s( tempNoteData );
|
|
||||||
SuperShuffleTaps( tempNoteData2, iStartIndex, iEndIndex ); /* expects 2sAnd3s */
|
|
||||||
tempNoteData.From2sAnd3s( tempNoteData2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
inout.CopyAll( tempNoteData );
|
inout.CopyAll( tempNoteData );
|
||||||
}
|
}
|
||||||
@@ -849,7 +823,6 @@ void NoteDataUtil::Backwards( NoteData &inout )
|
|||||||
NoteData out;
|
NoteData out;
|
||||||
out.SetNumTracks( inout.GetNumTracks() );
|
out.SetNumTracks( inout.GetNumTracks() );
|
||||||
|
|
||||||
inout.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
int max_row = inout.GetLastRow();
|
int max_row = inout.GetLastRow();
|
||||||
for( int t=0; t<inout.GetNumTracks(); t++ )
|
for( int t=0; t<inout.GetNumTracks(); t++ )
|
||||||
{
|
{
|
||||||
@@ -859,34 +832,14 @@ void NoteDataUtil::Backwards( NoteData &inout )
|
|||||||
int iRowLater = max_row-r;
|
int iRowLater = max_row-r;
|
||||||
|
|
||||||
TapNote tnEarlier = inout.GetTapNote(t, iRowEarlier);
|
TapNote tnEarlier = inout.GetTapNote(t, iRowEarlier);
|
||||||
|
if( tnEarlier.type == TapNote::hold_head )
|
||||||
|
iRowLater -= tnEarlier.iDuration;
|
||||||
|
|
||||||
out.SetTapNote(t, iRowLater, tnEarlier);
|
out.SetTapNote(t, iRowLater, tnEarlier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Un-flip hold_head and hold_tail. */
|
|
||||||
for( int t=0; t<out.GetNumTracks(); t++ )
|
|
||||||
{
|
|
||||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( out, t, r, 0, out.GetLastRow() )
|
|
||||||
{
|
|
||||||
TapNote tn = out.GetTapNote( t, r );
|
|
||||||
if( tn.type != TapNote::hold_tail )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int iTailRow = r;
|
|
||||||
while( out.GetNextTapNoteRowForTrack(t,iTailRow) )
|
|
||||||
{
|
|
||||||
TapNote tn2 = out.GetTapNote( t, iTailRow );
|
|
||||||
if( tn2.type != TapNote::hold_head )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
out.SetTapNote( t, r, tn2 );
|
|
||||||
out.SetTapNote( t, iTailRow, tn );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inout = out;
|
inout = out;
|
||||||
inout.Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDataUtil::SwapSides( NoteData &inout )
|
void NoteDataUtil::SwapSides( NoteData &inout )
|
||||||
@@ -908,27 +861,28 @@ void NoteDataUtil::Little( NoteData &inout, int iStartIndex, int iEndIndex )
|
|||||||
{
|
{
|
||||||
// filter out all non-quarter notes
|
// filter out all non-quarter notes
|
||||||
for( int t=0; t<inout.GetNumTracks(); t++ )
|
for( int t=0; t<inout.GetNumTracks(); t++ )
|
||||||
|
{
|
||||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( inout, t, i, iStartIndex, iEndIndex )
|
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( inout, t, i, iStartIndex, iEndIndex )
|
||||||
if( i % ROWS_PER_BEAT != 0 )
|
{
|
||||||
inout.SetTapNote( t, i, TAP_EMPTY );
|
if( i % ROWS_PER_BEAT == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
for( int i=inout.GetNumHoldNotes()-1; i>=0; i-- )
|
inout.SetTapNote( t, i, TAP_EMPTY );
|
||||||
if( fmodf(inout.GetHoldNote(i).GetStartBeat(),1) != 0 ) // doesn't start on a beat
|
}
|
||||||
inout.RemoveHoldNote( i );
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make all all quarter notes into jumps.
|
||||||
void NoteDataUtil::Wide( NoteData &inout, int iStartIndex, int iEndIndex )
|
void NoteDataUtil::Wide( NoteData &inout, int iStartIndex, int iEndIndex )
|
||||||
{
|
{
|
||||||
// Make all all quarter notes into jumps.
|
|
||||||
inout.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
|
|
||||||
/* Start on an even beat. */
|
/* Start on an even beat. */
|
||||||
iStartIndex = Quantize( iStartIndex, BeatToNoteRow(2.0f) );
|
iStartIndex = Quantize( iStartIndex, BeatToNoteRow(2.0f) );
|
||||||
|
|
||||||
iEndIndex = min( iEndIndex, inout.GetLastRow() );
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, i, iStartIndex, iEndIndex )
|
||||||
|
|
||||||
for( int i=iStartIndex; i<iEndIndex; i+=ROWS_PER_BEAT*2 ) // every even beat
|
|
||||||
{
|
{
|
||||||
|
if( i % BeatToNoteRow(2.0f) != 0 )
|
||||||
|
continue; // even beats only
|
||||||
|
|
||||||
bool bHoldNoteAtBeat = false;
|
bool bHoldNoteAtBeat = false;
|
||||||
for( int t = 0; !bHoldNoteAtBeat && t < inout.GetNumTracks(); ++t )
|
for( int t = 0; !bHoldNoteAtBeat && t < inout.GetNumTracks(); ++t )
|
||||||
if( inout.IsHoldNoteAtBeat(t, i) )
|
if( inout.IsHoldNoteAtBeat(t, i) )
|
||||||
@@ -968,8 +922,6 @@ void NoteDataUtil::Wide( NoteData &inout, int iStartIndex, int iEndIndex )
|
|||||||
}
|
}
|
||||||
inout.SetTapNote(iTrackToAdd, i, TAP_ADDITION_TAP);
|
inout.SetTapNote(iTrackToAdd, i, TAP_ADDITION_TAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
inout.Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDataUtil::Big( NoteData &inout, int iStartIndex, int iEndIndex )
|
void NoteDataUtil::Big( NoteData &inout, int iStartIndex, int iEndIndex )
|
||||||
@@ -1010,8 +962,6 @@ void NoteDataUtil::InsertIntelligentTaps(
|
|||||||
ASSERT( iInsertOffsetRows <= iWindowSizeRows );
|
ASSERT( iInsertOffsetRows <= iWindowSizeRows );
|
||||||
ASSERT( iWindowSizeRows <= iWindowStrideRows );
|
ASSERT( iWindowSizeRows <= iWindowStrideRows );
|
||||||
|
|
||||||
inout.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
|
|
||||||
bool bRequireNoteAtBeginningOfWindow = !bSkippy;
|
bool bRequireNoteAtBeginningOfWindow = !bSkippy;
|
||||||
bool bRequireNoteAtEndOfWindow = true;
|
bool bRequireNoteAtEndOfWindow = true;
|
||||||
|
|
||||||
@@ -1085,9 +1035,72 @@ void NoteDataUtil::InsertIntelligentTaps(
|
|||||||
done_looking_for_track_to_add:
|
done_looking_for_track_to_add:
|
||||||
inout.SetTapNote(iTrackOfNoteToAdd, iRowToAdd, TAP_ADDITION_TAP);
|
inout.SetTapNote(iTrackOfNoteToAdd, iRowToAdd, TAP_ADDITION_TAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
inout.Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
class TrackIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TrackIterator();
|
||||||
|
|
||||||
|
/* If called, iterate only over [iStart,iEnd]. */
|
||||||
|
void SetRange( int iStart, int iEnd )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If called, pay attention to iTrack only. */
|
||||||
|
void SetTrack( iTrack );
|
||||||
|
|
||||||
|
/* Extend iStart and iEnd to include hold notes overlapping the boundaries. Call SetRange()
|
||||||
|
* and SetTrack() first. */
|
||||||
|
void HoldInclusive();
|
||||||
|
|
||||||
|
/* Reduce iStart and iEnd to exclude hold notes overlapping the boundaries. Call SetRange()
|
||||||
|
* and SetTrack() first. */
|
||||||
|
void HoldExclusive();
|
||||||
|
|
||||||
|
/* If called, keep the iterator around. This results in much faster iteration. If used,
|
||||||
|
* ensure that the current row will always remain valid. SetTrack() must be called first. */
|
||||||
|
void Fast();
|
||||||
|
|
||||||
|
/* Retrieve an iterator for the current row. SetTrack() must be called first (but Fast()
|
||||||
|
* does not). */
|
||||||
|
TapNote::iterator Get();
|
||||||
|
|
||||||
|
int GetRow() const { return m_iCurrentRow; }
|
||||||
|
bool Prev();
|
||||||
|
bool Next();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_iStart, m_iEnd;
|
||||||
|
int m_iTrack;
|
||||||
|
|
||||||
|
bool m_bFast;
|
||||||
|
|
||||||
|
int m_iCurrentRow;
|
||||||
|
|
||||||
|
NoteData::iterator m_Iterator;
|
||||||
|
|
||||||
|
/* m_bFast only: */
|
||||||
|
NoteData::iterator m_Begin, m_End;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool TrackIterator::Next()
|
||||||
|
{
|
||||||
|
if( m_bFast )
|
||||||
|
{
|
||||||
|
if( m_Iterator ==
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackIterator::TrackIterator()
|
||||||
|
{
|
||||||
|
m_iStart = 0;
|
||||||
|
m_iEnd = MAX_NOTE_ROW;
|
||||||
|
m_iTrack = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void NoteDataUtil::AddMines( NoteData &inout, int iStartIndex, int iEndIndex )
|
void NoteDataUtil::AddMines( NoteData &inout, int iStartIndex, int iEndIndex )
|
||||||
{
|
{
|
||||||
@@ -1120,31 +1133,35 @@ void NoteDataUtil::AddMines( NoteData &inout, int iStartIndex, int iEndIndex )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Place mines right after hold so player must lift their foot.
|
// Place mines right after hold so player must lift their foot.
|
||||||
for( int i=0; i<inout.GetNumHoldNotes(); i++ )
|
for( int iTrack=0; iTrack<inout.GetNumTracks(); ++iTrack )
|
||||||
{
|
{
|
||||||
HoldNote &hn = inout.GetHoldNote(i);
|
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( inout, iTrack, r, iStartIndex, iEndIndex )
|
||||||
int iHoldEndRow = hn.iEndRow;
|
{
|
||||||
int iMineRow = iHoldEndRow+BeatToNoteRow(0.5f);
|
const TapNote &tn = inout.GetTapNote( iTrack, r );
|
||||||
|
if( tn.type != TapNote::hold_head )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int iMineRow = r + tn.iDuration + BeatToNoteRow(0.5f);
|
||||||
if( iMineRow < iStartIndex || iMineRow > iEndIndex )
|
if( iMineRow < iStartIndex || iMineRow > iEndIndex )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Only place a mines if there's not another step nearby
|
// Only place a mines if there's not another step nearby
|
||||||
int iMineRangeBegin = iMineRow - BeatToNoteRow( 0.5f ) + 1;
|
int iMineRangeBegin = iMineRow - BeatToNoteRow( 0.5f ) + 1;
|
||||||
int iMineRangeEnd = iMineRow + BeatToNoteRow( 0.5f ) - 1;
|
int iMineRangeEnd = iMineRow + BeatToNoteRow( 0.5f ) - 1;
|
||||||
if( !inout.IsRangeEmpty(hn.iTrack, iMineRangeBegin, iMineRangeEnd) )
|
if( !inout.IsRangeEmpty(iTrack, iMineRangeBegin, iMineRangeEnd) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Add a mine right after the hold end.
|
// Add a mine right after the hold end.
|
||||||
inout.SetTapNote( hn.iTrack, iMineRow, TAP_ADDITION_MINE );
|
inout.SetTapNote( iTrack, iMineRow, TAP_ADDITION_MINE );
|
||||||
|
|
||||||
// Convert all notes inout this row to mines.
|
// Convert all notes in this row to mines.
|
||||||
for( int t=0; t<inout.GetNumTracks(); t++ )
|
for( int t=0; t<inout.GetNumTracks(); t++ )
|
||||||
if( inout.GetTapNote(t,iMineRow).type == TapNote::tap )
|
if( inout.GetTapNote(t,iMineRow).type == TapNote::tap )
|
||||||
inout.SetTapNote(t,iMineRow,TAP_ADDITION_MINE);
|
inout.SetTapNote(t,iMineRow,TAP_ADDITION_MINE);
|
||||||
|
|
||||||
iRowCount = 0;
|
iRowCount = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDataUtil::Echo( NoteData &inout, int iStartIndex, int iEndIndex )
|
void NoteDataUtil::Echo( NoteData &inout, int iStartIndex, int iEndIndex )
|
||||||
@@ -1152,14 +1169,15 @@ void NoteDataUtil::Echo( NoteData &inout, int iStartIndex, int iEndIndex )
|
|||||||
// add 8th note tap "echos" after all taps
|
// add 8th note tap "echos" after all taps
|
||||||
int iEchoTrack = -1;
|
int iEchoTrack = -1;
|
||||||
|
|
||||||
iStartIndex = Quantize( iStartIndex, BeatToNoteRow(0.5f) );
|
|
||||||
|
|
||||||
iEndIndex = min( iEndIndex, inout.GetLastRow() );
|
|
||||||
const int rows_per_interval = BeatToNoteRow( 0.5f );
|
const int rows_per_interval = BeatToNoteRow( 0.5f );
|
||||||
|
iStartIndex = Quantize( iStartIndex, rows_per_interval );
|
||||||
|
|
||||||
// window is one beat wide and slides 1/2 a beat at a time
|
// window is one beat wide and slides 1/2 a beat at a time
|
||||||
for( int r=iStartIndex; r<iEndIndex; r+=rows_per_interval )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, r, iStartIndex, iEndIndex )
|
||||||
{
|
{
|
||||||
|
if( r % rows_per_interval != 0 )
|
||||||
|
continue; // 8th notes only
|
||||||
|
|
||||||
const int iRowWindowBegin = r;
|
const int iRowWindowBegin = r;
|
||||||
const int iRowWindowEnd = r + rows_per_interval*2;
|
const int iRowWindowEnd = r + rows_per_interval*2;
|
||||||
|
|
||||||
@@ -1211,7 +1229,6 @@ void NoteDataUtil::Twister( NoteData &inout, int iStartIndex, int iEndIndex )
|
|||||||
void NoteDataUtil::ConvertTapsToHolds( NoteData &inout, int iSimultaneousHolds, int iStartIndex, int iEndIndex )
|
void NoteDataUtil::ConvertTapsToHolds( NoteData &inout, int iSimultaneousHolds, int iStartIndex, int iEndIndex )
|
||||||
{
|
{
|
||||||
// Convert all taps to freezes.
|
// Convert all taps to freezes.
|
||||||
iEndIndex = min( iEndIndex, inout.GetLastRow() );
|
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, r, iStartIndex, iEndIndex )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, r, iStartIndex, iEndIndex )
|
||||||
{
|
{
|
||||||
int iTrackAddedThisRow = 0;
|
int iTrackAddedThisRow = 0;
|
||||||
@@ -1250,7 +1267,7 @@ void NoteDataUtil::ConvertTapsToHolds( NoteData &inout, int iSimultaneousHolds,
|
|||||||
if( r2 == r+1 )
|
if( r2 == r+1 )
|
||||||
r2 = r+BeatToNoteRow(1);
|
r2 = r+BeatToNoteRow(1);
|
||||||
|
|
||||||
inout.AddHoldNote( HoldNote(t,r,r2) );
|
inout.AddHoldNote( t, r, r2, TAP_ORIGINAL_HOLD_HEAD );
|
||||||
iTrackAddedThisRow++;
|
iTrackAddedThisRow++;
|
||||||
}
|
}
|
||||||
dont_add_hold:
|
dont_add_hold:
|
||||||
@@ -1263,10 +1280,6 @@ dont_add_hold:
|
|||||||
void NoteDataUtil::Stomp( NoteData &inout, StepsType st, int iStartIndex, int iEndIndex )
|
void NoteDataUtil::Stomp( NoteData &inout, StepsType st, int iStartIndex, int iEndIndex )
|
||||||
{
|
{
|
||||||
// Make all non jumps with ample space around them into jumps.
|
// Make all non jumps with ample space around them into jumps.
|
||||||
|
|
||||||
|
|
||||||
iEndIndex = min( iEndIndex, inout.GetLastRow() );
|
|
||||||
|
|
||||||
int iTrackMapping[MAX_NOTE_TRACKS];
|
int iTrackMapping[MAX_NOTE_TRACKS];
|
||||||
GetTrackMapping( st, stomp, inout.GetNumTracks(), iTrackMapping );
|
GetTrackMapping( st, stomp, inout.GetNumTracks(), iTrackMapping );
|
||||||
|
|
||||||
@@ -1315,8 +1328,6 @@ void NoteDataUtil::SnapToNearestNoteType( NoteData &inout, NoteType nt1, NoteTyp
|
|||||||
if( nt2 != NOTE_TYPE_INVALID )
|
if( nt2 != NOTE_TYPE_INVALID )
|
||||||
fSnapInterval2 = NoteTypeToBeat( nt2 );
|
fSnapInterval2 = NoteTypeToBeat( nt2 );
|
||||||
|
|
||||||
inout.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
|
|
||||||
// iterate over all TapNotes in the interval and snap them
|
// iterate over all TapNotes in the interval and snap them
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, iOldIndex, iStartIndex, iEndIndex )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( inout, iOldIndex, iStartIndex, iEndIndex )
|
||||||
{
|
{
|
||||||
@@ -1338,21 +1349,16 @@ void NoteDataUtil::SnapToNearestNoteType( NoteData &inout, NoteType nt1, NoteTyp
|
|||||||
inout.SetTapNote(c, iOldIndex, TAP_EMPTY);
|
inout.SetTapNote(c, iOldIndex, TAP_EMPTY);
|
||||||
|
|
||||||
const TapNote &tnOld = inout.GetTapNote(c, iNewIndex);
|
const TapNote &tnOld = inout.GetTapNote(c, iNewIndex);
|
||||||
if( tnNew.type == TapNote::tap &&
|
if( tnNew.type == TapNote::tap && tnOld.type == TapNote::hold_head )
|
||||||
(tnOld.type == TapNote::hold_head || tnOld.type == TapNote::hold_tail) )
|
|
||||||
continue; // HoldNotes override TapNotes
|
continue; // HoldNotes override TapNotes
|
||||||
|
|
||||||
/* If two hold tnNew boundaries are getting snapped together,
|
int iNewDuration = Quantize( tnNew.iDuration, BeatToNoteRow(fSnapInterval1) );
|
||||||
* merge them. */
|
if( iNewDuration == 0 )
|
||||||
if( (tnNew.type == TapNote::hold_head && tnOld.type == TapNote::hold_tail) ||
|
continue;
|
||||||
(tnNew.type == TapNote::hold_tail && tnOld.type == TapNote::hold_head) )
|
|
||||||
tnNew = TAP_EMPTY;
|
|
||||||
|
|
||||||
inout.SetTapNote(c, iNewIndex, tnNew );
|
inout.SetTapNote(c, iNewIndex, tnNew );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inout.Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1408,7 +1414,6 @@ void NoteDataUtil::ClearRight( NoteData &inout )
|
|||||||
|
|
||||||
void NoteDataUtil::CollapseToOne( NoteData &inout )
|
void NoteDataUtil::CollapseToOne( NoteData &inout )
|
||||||
{
|
{
|
||||||
inout.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS( inout, r )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS( inout, r )
|
||||||
for( int t=0; t<inout.GetNumTracks(); t++ )
|
for( int t=0; t<inout.GetNumTracks(); t++ )
|
||||||
if( inout.GetTapNote(t,r).type != TapNote::empty )
|
if( inout.GetTapNote(t,r).type != TapNote::empty )
|
||||||
@@ -1417,12 +1422,10 @@ void NoteDataUtil::CollapseToOne( NoteData &inout )
|
|||||||
inout.SetTapNote(t, r, TAP_EMPTY);
|
inout.SetTapNote(t, r, TAP_EMPTY);
|
||||||
inout.SetTapNote(0, r, tn);
|
inout.SetTapNote(0, r, tn);
|
||||||
}
|
}
|
||||||
inout.Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDataUtil::CollapseLeft( NoteData &inout )
|
void NoteDataUtil::CollapseLeft( NoteData &inout )
|
||||||
{
|
{
|
||||||
inout.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
FOREACH_NONEMPTY_ROW_ALL_TRACKS( inout, r )
|
FOREACH_NONEMPTY_ROW_ALL_TRACKS( inout, r )
|
||||||
{
|
{
|
||||||
int iNumTracksFilled = 0;
|
int iNumTracksFilled = 0;
|
||||||
@@ -1440,7 +1443,6 @@ void NoteDataUtil::CollapseLeft( NoteData &inout )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inout.Convert2sAnd3sToHoldNotes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDataUtil::ShiftTracks( NoteData &inout, int iShiftBy )
|
void NoteDataUtil::ShiftTracks( NoteData &inout, int iShiftBy )
|
||||||
@@ -1655,30 +1657,27 @@ void NoteDataUtil::Scale( NoteData &nd, float fScale )
|
|||||||
|
|
||||||
void NoteDataUtil::ScaleRegion( NoteData &nd, float fScale, int iStartIndex, int iEndIndex )
|
void NoteDataUtil::ScaleRegion( NoteData &nd, float fScale, int iStartIndex, int iEndIndex )
|
||||||
{
|
{
|
||||||
// convert to 2sAnd3s before calling this
|
|
||||||
ASSERT( nd.GetNumHoldNotes() == 0 );
|
|
||||||
|
|
||||||
ASSERT( fScale > 0 );
|
ASSERT( fScale > 0 );
|
||||||
ASSERT( iStartIndex < iEndIndex );
|
ASSERT( iStartIndex < iEndIndex );
|
||||||
ASSERT( iStartIndex >= 0 );
|
ASSERT( iStartIndex >= 0 );
|
||||||
|
|
||||||
NoteData temp1, temp2;
|
NoteData temp1, temp2;
|
||||||
temp1.Config( nd );
|
temp1.SetNumTracks( nd.GetNumTracks() );
|
||||||
temp2.Config( nd );
|
temp2.SetNumTracks( nd.GetNumTracks() );
|
||||||
|
|
||||||
const int iFirstRowAtEndOfRegion = min( nd.GetLastRow(), iEndIndex );
|
|
||||||
const int iScaledFirstRowAfterRegion = int(iStartIndex + (iEndIndex - iStartIndex) * fScale);
|
|
||||||
|
|
||||||
if( iStartIndex != 0 )
|
if( iStartIndex != 0 )
|
||||||
temp1.CopyRange( nd, 0, iStartIndex );
|
temp1.CopyRange( nd, 0, iStartIndex );
|
||||||
if( nd.GetLastRow() > iFirstRowAtEndOfRegion )
|
if( iEndIndex != MAX_NOTE_ROW )
|
||||||
temp1.CopyRange( nd, iFirstRowAtEndOfRegion, nd.GetLastRow(), iScaledFirstRowAfterRegion);
|
{
|
||||||
temp2.CopyRange( nd, iStartIndex, iFirstRowAtEndOfRegion );
|
const int iScaledFirstRowAfterRegion = int(iStartIndex + (iEndIndex - iStartIndex) * fScale);
|
||||||
|
temp1.CopyRange( nd, iEndIndex, MAX_NOTE_ROW, iScaledFirstRowAfterRegion );
|
||||||
|
}
|
||||||
|
temp2.CopyRange( nd, iStartIndex, iEndIndex );
|
||||||
nd.ClearAll();
|
nd.ClearAll();
|
||||||
|
|
||||||
for( int r=0; r<=temp2.GetLastRow(); r++ )
|
|
||||||
{
|
|
||||||
for( int t=0; t<temp2.GetNumTracks(); t++ )
|
for( int t=0; t<temp2.GetNumTracks(); t++ )
|
||||||
|
{
|
||||||
|
FOREACH_NONEMPTY_ROW_IN_TRACK( temp2, t, r )
|
||||||
{
|
{
|
||||||
TapNote tn = temp2.GetTapNote( t, r );
|
TapNote tn = temp2.GetTapNote( t, r );
|
||||||
if( tn.type != TapNote::empty )
|
if( tn.type != TapNote::empty )
|
||||||
@@ -1696,8 +1695,6 @@ void NoteDataUtil::ScaleRegion( NoteData &nd, float fScale, int iStartIndex, int
|
|||||||
|
|
||||||
void NoteDataUtil::ShiftRows( NoteData &nd, int iStartIndex, int iRowsToShift )
|
void NoteDataUtil::ShiftRows( NoteData &nd, int iStartIndex, int iRowsToShift )
|
||||||
{
|
{
|
||||||
NoteData temp;
|
|
||||||
temp.SetNumTracks( nd.GetNumTracks() );
|
|
||||||
int iTakeFromRow = iStartIndex;
|
int iTakeFromRow = iStartIndex;
|
||||||
int iPasteAtRow = iStartIndex;
|
int iPasteAtRow = iStartIndex;
|
||||||
|
|
||||||
@@ -1706,9 +1703,11 @@ void NoteDataUtil::ShiftRows( NoteData &nd, int iStartIndex, int iRowsToShift )
|
|||||||
else // delete rows
|
else // delete rows
|
||||||
iTakeFromRow -= iRowsToShift;
|
iTakeFromRow -= iRowsToShift;
|
||||||
|
|
||||||
temp.CopyRange( nd, iTakeFromRow, nd.GetLastRow() );
|
NoteData temp;
|
||||||
nd.ClearRange( min(iTakeFromRow,iPasteAtRow), nd.GetLastRow() );
|
temp.SetNumTracks( nd.GetNumTracks() );
|
||||||
nd.CopyRange( temp, 0, temp.GetLastRow(), iPasteAtRow );
|
temp.CopyRange( nd, iTakeFromRow, MAX_NOTE_ROW );
|
||||||
|
nd.ClearRange( min(iTakeFromRow,iPasteAtRow), MAX_NOTE_ROW );
|
||||||
|
nd.CopyRange( temp, 0, MAX_NOTE_ROW, iPasteAtRow );
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteDataUtil::RemoveAllTapsOfType( NoteData& ndInOut, TapNote::Type typeToRemove )
|
void NoteDataUtil::RemoveAllTapsOfType( NoteData& ndInOut, TapNote::Type typeToRemove )
|
||||||
|
|||||||
@@ -47,17 +47,24 @@ int GetNumNWithScore( const NoteData &in, TapNoteScore tns, int MinTaps, int iSt
|
|||||||
return iNumSuccessfulDoubles;
|
return iNumSuccessfulDoubles;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetNumHoldNotesWithScore( const NoteData &in, HoldNoteScore hns, int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW )
|
int GetNumHoldNotesWithScore( const NoteData &in, HoldNoteScore hns )
|
||||||
{
|
{
|
||||||
int iNumSuccessfulHolds = 0;
|
int iNumSuccessfulHolds = 0;
|
||||||
for( int i=0; i<in.GetNumHoldNotes(); i++ )
|
for( int t=0; t<in.GetNumTracks(); ++t )
|
||||||
{
|
{
|
||||||
const HoldNote &hn = in.GetHoldNote(i);
|
NoteData::TrackMap::const_iterator begin, end;
|
||||||
if( !hn.ContainedByRange(iStartIndex, iEndIndex) )
|
in.GetTapNoteRange( t, 0, MAX_NOTE_ROW, begin, end );
|
||||||
|
|
||||||
|
for( ; begin != end; ++begin )
|
||||||
|
{
|
||||||
|
const TapNote &tn = begin->second;
|
||||||
|
if( tn.type != TapNote::hold_head )
|
||||||
continue;
|
continue;
|
||||||
if( hn.result.hns == hns )
|
if( tn.HoldResult.hns == hns )
|
||||||
iNumSuccessfulHolds++;
|
++iNumSuccessfulHolds;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return iNumSuccessfulHolds;
|
return iNumSuccessfulHolds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +96,7 @@ int GetSuccessfulHands( const NoteData &in, int iStartIndex = 0, int iEndIndex =
|
|||||||
bool Missed = false;
|
bool Missed = false;
|
||||||
for( int t=0; t<in.GetNumTracks(); t++ )
|
for( int t=0; t<in.GetNumTracks(); t++ )
|
||||||
{
|
{
|
||||||
TapNote tn = in.GetTapNote(t, i);
|
const TapNote &tn = in.GetTapNote(t, i);
|
||||||
if( tn.type == TapNote::empty )
|
if( tn.type == TapNote::empty )
|
||||||
continue;
|
continue;
|
||||||
if( tn.type == TapNote::mine ) // mines don't count
|
if( tn.type == TapNote::mine ) // mines don't count
|
||||||
@@ -102,20 +109,19 @@ int GetSuccessfulHands( const NoteData &in, int iStartIndex = 0, int iEndIndex =
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Check hold scores. */
|
/* Check hold scores. */
|
||||||
for( int j=0; j<in.GetNumHoldNotes(); j++ )
|
for( int t=0; t<in.GetNumTracks(); ++t )
|
||||||
{
|
{
|
||||||
const HoldNote &hn = in.GetHoldNote(j);
|
int iHeadRow;
|
||||||
|
if( !in.IsHoldNoteAtBeat( t, i, &iHeadRow ) )
|
||||||
/* Check if the row we're checking is in range. */
|
|
||||||
if( !hn.RowIsInRange(i) )
|
|
||||||
continue;
|
continue;
|
||||||
|
const TapNote &tn = in.GetTapNote(t, i);
|
||||||
|
|
||||||
/* If a hold is released *after* a hands containing it, the hands is
|
/* If a hold is released *after* a hands containing it, the hands is
|
||||||
* still good. So, ignore the judgement and only examine iLastHeldRow
|
* still good. So, ignore the judgement and only examine iLastHeldRow
|
||||||
* to be sure that the hold was still held at the point of this row.
|
* to be sure that the hold was still held at the point of this row.
|
||||||
* (Note that if the hold head tap was missed, then iLastHeldRow == i
|
* (Note that if the hold head tap was missed, then iLastHeldRow == i
|
||||||
* and this won't fail--but the tap check above will have already failed.) */
|
* and this won't fail--but the tap check above will have already failed.) */
|
||||||
if( hn.result.iLastHeldRow < i )
|
if( tn.HoldResult.iLastHeldRow < i )
|
||||||
Missed = true;
|
Missed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-26
@@ -291,7 +291,7 @@ void NoteField::DrawAreaHighlight( int iStartBeat, int iEndBeat )
|
|||||||
fYStartPos = max( fYStartPos, -1000 );
|
fYStartPos = max( fYStartPos, -1000 );
|
||||||
fYEndPos = min( fYEndPos, +5000 );
|
fYEndPos = min( fYEndPos, +5000 );
|
||||||
|
|
||||||
m_rectAreaHighlight.StretchTo( RectF(-GetWidth()/2, fYStartPos-ARROW_SIZE/2, GetWidth()/2, fYEndPos+ARROW_SIZE/2) );
|
m_rectAreaHighlight.StretchTo( RectF(-GetWidth()/2, fYStartPos, GetWidth()/2, fYEndPos) );
|
||||||
m_rectAreaHighlight.SetDiffuse( RageColor(1,0,0,0.3f) );
|
m_rectAreaHighlight.SetDiffuse( RageColor(1,0,0,0.3f) );
|
||||||
m_rectAreaHighlight.Draw();
|
m_rectAreaHighlight.Draw();
|
||||||
}
|
}
|
||||||
@@ -558,25 +558,29 @@ void NoteField::DrawPrimitives()
|
|||||||
NDMap::iterator CurDisplay = m_BeatToNoteDisplays.begin();
|
NDMap::iterator CurDisplay = m_BeatToNoteDisplays.begin();
|
||||||
ASSERT( CurDisplay != m_BeatToNoteDisplays.end() );
|
ASSERT( CurDisplay != m_BeatToNoteDisplays.end() );
|
||||||
NDMap::iterator NextDisplay = CurDisplay; ++NextDisplay;
|
NDMap::iterator NextDisplay = CurDisplay; ++NextDisplay;
|
||||||
for( int i=0; i < m_pNoteData->GetNumHoldNotes(); i++ )
|
|
||||||
{
|
|
||||||
const HoldNote &hn = m_pNoteData->GetHoldNote(i);
|
|
||||||
if( hn.iTrack != c ) // this HoldNote doesn't belong to this column
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const HoldNoteResult &Result = hn.result;
|
{
|
||||||
|
NoteData::TrackMap::const_iterator begin, end;
|
||||||
|
m_pNoteData->GetTapNoteRangeInclusive( c, iFirstIndexToDraw, iLastIndexToDraw, begin, end );
|
||||||
|
|
||||||
|
for( ; begin != end; ++begin )
|
||||||
|
{
|
||||||
|
const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, i);
|
||||||
|
if( tn.type != TapNote::hold_head )
|
||||||
|
continue; // skip
|
||||||
|
|
||||||
|
const HoldNoteResult &Result = tn.HoldResult;
|
||||||
if( Result.hns == HNS_OK ) // if this HoldNote was completed
|
if( Result.hns == HNS_OK ) // if this HoldNote was completed
|
||||||
continue; // don't draw anything
|
continue; // don't draw anything
|
||||||
|
|
||||||
// If no part of this HoldNote is on the screen, skip it
|
int iStartRow = begin->first;
|
||||||
if( !hn.RangeOverlaps(iFirstIndexToDraw, iLastIndexToDraw) )
|
int iEndRow = iStartRow + tn.iDuration;
|
||||||
continue; // skip
|
|
||||||
|
|
||||||
// TRICKY: If boomerang is on, then all notes in the range
|
// TRICKY: If boomerang is on, then all notes in the range
|
||||||
// [iFirstIndexToDraw,iLastIndexToDraw] aren't necessarily visible.
|
// [iFirstIndexToDraw,iLastIndexToDraw] aren't necessarily visible.
|
||||||
// Test every note to make sure it's on screen before drawing
|
// Test every note to make sure it's on screen before drawing
|
||||||
float fYStartOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(hn.iStartRow) );
|
float fYStartOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(iStartRow) );
|
||||||
float fYEndOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(hn.iEndRow) );
|
float fYEndOffset = ArrowEffects::GetYOffset( m_pPlayerState, c, NoteRowToBeat(iEndRow) );
|
||||||
if( !( iFirstPixelToDraw <= fYEndOffset && fYEndOffset <= iLastPixelToDraw ||
|
if( !( iFirstPixelToDraw <= fYEndOffset && fYEndOffset <= iLastPixelToDraw ||
|
||||||
iFirstPixelToDraw <= fYStartOffset && fYStartOffset <= iLastPixelToDraw ||
|
iFirstPixelToDraw <= fYStartOffset && fYStartOffset <= iLastPixelToDraw ||
|
||||||
fYStartOffset < iFirstPixelToDraw && fYEndOffset > iLastPixelToDraw ) )
|
fYStartOffset < iFirstPixelToDraw && fYEndOffset > iLastPixelToDraw ) )
|
||||||
@@ -584,22 +588,27 @@ void NoteField::DrawPrimitives()
|
|||||||
continue; // skip
|
continue; // skip
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool bIsActive = hn.result.bActive;
|
const bool bIsActive = tn.HoldResult.bActive;
|
||||||
const bool bIsHoldingNote = hn.result.bHeld;
|
const bool bIsHoldingNote = tn.HoldResult.bHeld;
|
||||||
if( bIsActive )
|
if( bIsActive )
|
||||||
SearchForSongBeat()->m_GhostArrowRow.SetHoldIsActive( hn.iTrack );
|
SearchForSongBeat()->m_GhostArrowRow.SetHoldIsActive( c );
|
||||||
|
|
||||||
ASSERT_M( NoteRowToBeat(hn.iStartRow) > -2000, ssprintf("%i %i %i", hn.iStartRow, hn.iEndRow, hn.iTrack) );
|
ASSERT_M( NoteRowToBeat(iStartRow) > -2000, ssprintf("%i %i %i", iStartRow, iEndRow, c) );
|
||||||
SearchForBeat( CurDisplay, NextDisplay, NoteRowToBeat(hn.iStartRow) );
|
SearchForBeat( CurDisplay, NextDisplay, NoteRowToBeat(iStartRow) );
|
||||||
|
|
||||||
bool bIsInSelectionRange = false;
|
bool bIsInSelectionRange = false;
|
||||||
if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 )
|
if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 )
|
||||||
bIsInSelectionRange = hn.ContainedByRange( m_iBeginMarker, m_iEndMarker );
|
bIsInSelectionRange = (m_iBeginMarker <= iStartRow && iEndRow < m_iEndMarker);
|
||||||
|
|
||||||
NoteDisplayCols *nd = CurDisplay->second;
|
NoteDisplayCols *nd = CurDisplay->second;
|
||||||
|
HoldNote hn(c, iStartRow, iEndRow);
|
||||||
|
hn.result = tn.HoldResult;
|
||||||
|
|
||||||
nd->display[c].DrawHold( hn, bIsHoldingNote, bIsActive, Result, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, false, m_fYReverseOffsetPixels );
|
nd->display[c].DrawHold( hn, bIsHoldingNote, bIsActive, Result, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, false, m_fYReverseOffsetPixels );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Draw all TapNotes in this column
|
// Draw all TapNotes in this column
|
||||||
@@ -615,11 +624,12 @@ void NoteField::DrawPrimitives()
|
|||||||
{
|
{
|
||||||
int i = begin->first;
|
int i = begin->first;
|
||||||
const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, i);
|
const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, i);
|
||||||
if( tn.type == TapNote::empty ) // no note here
|
switch( tn.type )
|
||||||
continue; // skip
|
{
|
||||||
|
case TapNote::empty: // no note here
|
||||||
if( tn.type == TapNote::hold_head ) // this is a HoldNote begin marker. Grade it, but don't draw
|
case TapNote::hold_head:
|
||||||
continue; // skip
|
continue; // skip
|
||||||
|
}
|
||||||
|
|
||||||
/* Don't draw hidden (fully judged) steps. */
|
/* Don't draw hidden (fully judged) steps. */
|
||||||
if( tn.result.bHidden )
|
if( tn.result.bHidden )
|
||||||
@@ -656,10 +666,7 @@ void NoteField::DrawPrimitives()
|
|||||||
|
|
||||||
bool bIsInSelectionRange = false;
|
bool bIsInSelectionRange = false;
|
||||||
if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 )
|
if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 )
|
||||||
{
|
bIsInSelectionRange = m_iBeginMarker<=i && i<m_iEndMarker;
|
||||||
int iBeat = i;
|
|
||||||
bIsInSelectionRange = m_iBeginMarker<=iBeat && iBeat<=m_iEndMarker;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bIsAddition = (tn.source == TapNote::addition);
|
bool bIsAddition = (tn.source == TapNote::addition);
|
||||||
bool bIsMine = (tn.type == TapNote::mine);
|
bool bIsMine = (tn.type == TapNote::mine);
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ struct TapNoteResult
|
|||||||
bool bHidden;
|
bool bHidden;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This HoldNote data is persisted when converted to 2sAnd3s. */
|
|
||||||
struct HoldNoteResult
|
struct HoldNoteResult
|
||||||
{
|
{
|
||||||
HoldNoteScore hns;
|
HoldNoteScore hns;
|
||||||
@@ -112,13 +111,17 @@ struct TapNote
|
|||||||
COMPARE(fAttackDurationSeconds);
|
COMPARE(fAttackDurationSeconds);
|
||||||
COMPARE(bKeysound);
|
COMPARE(bKeysound);
|
||||||
COMPARE(iKeysoundIndex);
|
COMPARE(iKeysoundIndex);
|
||||||
|
COMPARE(iDuration);
|
||||||
#undef COMPARE
|
#undef COMPARE
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* hold_head only: */
|
||||||
|
int iDuration;
|
||||||
|
|
||||||
TapNoteResult result;
|
TapNoteResult result;
|
||||||
|
|
||||||
/* This is valid for hold_head when in 2sAnd3s. */
|
/* hold_head only: */
|
||||||
HoldNoteResult HoldResult;
|
HoldNoteResult HoldResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -280,7 +280,6 @@ bool DWILoader::LoadFromDWITokens(
|
|||||||
newNoteData.SetTapNote(iCol1, iIndex, TAP_ORIGINAL_HOLD_HEAD);
|
newNoteData.SetTapNote(iCol1, iIndex, TAP_ORIGINAL_HOLD_HEAD);
|
||||||
if( iCol2 != -1 )
|
if( iCol2 != -1 )
|
||||||
newNoteData.SetTapNote(iCol2, iIndex, TAP_ORIGINAL_HOLD_HEAD);
|
newNoteData.SetTapNote(iCol2, iIndex, TAP_ORIGINAL_HOLD_HEAD);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while( jump );
|
while( jump );
|
||||||
@@ -291,8 +290,29 @@ bool DWILoader::LoadFromDWITokens(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this will expand the HoldNote begin markers we wrote into actual HoldNotes
|
/* Fill in iDuration. */
|
||||||
newNoteData.Convert2sAnd3sToHoldNotes();
|
for( int t=0; t<newNoteData.GetNumTracks(); ++t )
|
||||||
|
{
|
||||||
|
FOREACH_NONEMPTY_ROW_IN_TRACK( newNoteData, t, iHeadRow )
|
||||||
|
{
|
||||||
|
TapNote tn = newNoteData.GetTapNote( t, iHeadRow );
|
||||||
|
if( tn.type != TapNote::hold_head )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int iTailRow = iHeadRow;
|
||||||
|
while( newNoteData.GetNextTapNoteRowForTrack(t, iTailRow) )
|
||||||
|
{
|
||||||
|
const TapNote &TailTap = newNoteData.GetTapNote( t, iTailRow );
|
||||||
|
if( TailTap.type == TapNote::empty )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
newNoteData.SetTapNote( t, iTailRow, TAP_EMPTY );
|
||||||
|
tn.iDuration = iTailRow - iHeadRow;
|
||||||
|
newNoteData.SetTapNote( t, iHeadRow, tn );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT( newNoteData.GetNumTracks() > 0 );
|
ASSERT( newNoteData.GetNumTracks() > 0 );
|
||||||
|
|
||||||
@@ -303,11 +323,8 @@ bool DWILoader::LoadFromDWITokens(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STUPID ALERT!
|
/* This value can be in either "HH:MM:SS.sssss", "MM:SS.sssss", "SSS.sssss"
|
||||||
* This value can be in either "HH:MM:SS.sssss", "MM:SS.sssss", "SSS.sssss"
|
* or milliseconds. */
|
||||||
* or milliseconds.
|
|
||||||
* What's even more dumb is that the value can contain a ':'. Colon is supposed to be a parameter separator!
|
|
||||||
*/
|
|
||||||
float DWILoader::ParseBrokenDWITimestamp(const CString &arg1, const CString &arg2, const CString &arg3)
|
float DWILoader::ParseBrokenDWITimestamp(const CString &arg1, const CString &arg2, const CString &arg3)
|
||||||
{
|
{
|
||||||
if(arg1.empty()) return 0;
|
if(arg1.empty()) return 0;
|
||||||
|
|||||||
@@ -28,14 +28,13 @@ void KSFLoader::RemoveHoles( NoteData &out, const Song &song )
|
|||||||
// else
|
// else
|
||||||
// LastRow = out.GetLastRow();
|
// LastRow = out.GetLastRow();
|
||||||
NoteData tmp;
|
NoteData tmp;
|
||||||
tmp.SetNumTracks(out.GetNumTracks());
|
tmp.SetNumTracks( out.GetNumTracks() );
|
||||||
tmp.CopyRange( &out, FromRow, out.GetLastRow() );
|
tmp.CopyRange( &out, FromRow, MAX_NOTE_ROW );
|
||||||
out.ClearRange( FromRow, out.GetLastRow() );
|
out.ClearRange( FromRow, MAX_NOTE_ROW );
|
||||||
out.CopyRange( &tmp, 0, tmp.GetLastRow(), ToRow );
|
out.CopyRange( &tmp, 0, MAX_NOTE_ROW, ToRow );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
out.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
for( t = 0; t < notedata.GetNumTracks(); ++t )
|
for( t = 0; t < notedata.GetNumTracks(); ++t )
|
||||||
{
|
{
|
||||||
const float CurBPM = song.GetBPMAtBeat( NoteRowToBeat(row) );
|
const float CurBPM = song.GetBPMAtBeat( NoteRowToBeat(row) );
|
||||||
@@ -54,7 +53,6 @@ void KSFLoader::RemoveHoles( NoteData &out, const Song &song )
|
|||||||
notedata.SetTapNote( t, row, TAP_EMPTY );
|
notedata.SetTapNote( t, row, TAP_EMPTY );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.Convert2sAnd3sToHoldNotes();
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -188,12 +186,7 @@ bool KSFLoader::LoadFromKSFFile( const CString &sPath, Steps &out, const Song &s
|
|||||||
|
|
||||||
if( iHoldStartRow[t] != -1 ) // this ends the hold
|
if( iHoldStartRow[t] != -1 ) // this ends the hold
|
||||||
{
|
{
|
||||||
HoldNote hn (
|
notedata.AddHoldNote( t, BeatToNoteRow(iHoldStartRow[t]/(float)iTickCount), BeatToNoteRow((r-1)/(float)iTickCount), TAP_ORIGINAL_HOLD_HEAD );
|
||||||
t, /* button */
|
|
||||||
BeatToNoteRow(iHoldStartRow[t]/(float)iTickCount), /* start */
|
|
||||||
BeatToNoteRow((r-1)/(float)iTickCount) /* end */
|
|
||||||
);
|
|
||||||
notedata.AddHoldNote( hn );
|
|
||||||
iHoldStartRow[t] = -1;
|
iHoldStartRow[t] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,6 @@ void NotesWriterDWI::WriteDWINotesField( RageFile &f, const Steps &out, int star
|
|||||||
{
|
{
|
||||||
NoteData notedata;
|
NoteData notedata;
|
||||||
out.GetNoteData( notedata );
|
out.GetNoteData( notedata );
|
||||||
notedata.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
|
|
||||||
const int iLastMeasure = int( notedata.GetLastBeat()/BEATS_PER_MEASURE );
|
const int iLastMeasure = int( notedata.GetLastBeat()/BEATS_PER_MEASURE );
|
||||||
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
|
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
|
||||||
|
|||||||
+43
-45
@@ -338,52 +338,65 @@ void Player::Update( float fDeltaTime )
|
|||||||
//
|
//
|
||||||
// update HoldNotes logic
|
// update HoldNotes logic
|
||||||
//
|
//
|
||||||
for( int i=0; i < m_NoteData.GetNumHoldNotes(); i++ ) // for each HoldNote
|
for( int iTrack=0; iTrack<m_NoteData.GetNumTracks(); ++iTrack )
|
||||||
{
|
{
|
||||||
HoldNote &hn = m_NoteData.GetHoldNote(i);
|
// Since this is being called every frame, let's not check the whole array every time.
|
||||||
|
// Instead, only check 1 beat back. Even 1 is overkill.
|
||||||
|
const int iStartCheckingAt = max( 0, iSongRow-BeatToNoteRow(1) );
|
||||||
|
NoteData::iterator begin, end;
|
||||||
|
m_NoteData.GetTapNoteRangeInclusive( iTrack, iStartCheckingAt, iSongRow, begin, end );
|
||||||
|
for( ; begin != end; ++begin )
|
||||||
|
{
|
||||||
|
TapNote &tn = begin->second;
|
||||||
|
if( tn.type != TapNote::hold_head )
|
||||||
|
continue;
|
||||||
|
int iRow = begin->first;
|
||||||
|
|
||||||
// set hold flags so NoteField can do intelligent drawing
|
// set hold flags so NoteField can do intelligent drawing
|
||||||
hn.result.bHeld = false;
|
tn.HoldResult.bHeld = false;
|
||||||
hn.result.bActive = false;
|
tn.HoldResult.bActive = false;
|
||||||
|
|
||||||
|
HoldNoteScore hns = tn.HoldResult.hns;
|
||||||
HoldNoteScore hns = hn.result.hns;
|
|
||||||
if( hns != HNS_NONE ) // if this HoldNote already has a result
|
if( hns != HNS_NONE ) // if this HoldNote already has a result
|
||||||
continue; // we don't need to update the logic for this one
|
continue; // we don't need to update the logic for this one
|
||||||
if( iSongRow < hn.iStartRow )
|
|
||||||
continue; // hold hasn't happened yet
|
|
||||||
|
|
||||||
// TODO: Remove use of PlayerNumber.
|
// TODO: Remove use of PlayerNumber.
|
||||||
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
|
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
|
||||||
|
|
||||||
const StyleInput StyleI( pn, hn.iTrack );
|
|
||||||
const GameInput GameI = GAMESTATE->GetCurrentStyle()->StyleInputToGameInput( StyleI );
|
|
||||||
|
|
||||||
// if they got a bad score or haven't stepped on the corresponding tap yet
|
// if they got a bad score or haven't stepped on the corresponding tap yet
|
||||||
const TapNoteScore tns = m_NoteData.GetTapNote( hn.iTrack, hn.iStartRow ).result.tns;
|
const TapNoteScore tns = tn.result.tns;
|
||||||
const bool bSteppedOnTapNote = tns != TNS_NONE && tns != TNS_MISS; // did they step on the start of this hold?
|
const bool bSteppedOnTapNote = tns != TNS_NONE && tns != TNS_MISS; // did they step on the start of this hold?
|
||||||
|
|
||||||
float fLife = hn.result.fLife;
|
bool bIsHoldingButton;
|
||||||
|
|
||||||
bool bIsHoldingButton = INPUTMAPPER->IsButtonDown( GameI );
|
|
||||||
// TODO: Make the CPU miss sometimes.
|
|
||||||
if( m_pPlayerState->m_PlayerController != PC_HUMAN )
|
if( m_pPlayerState->m_PlayerController != PC_HUMAN )
|
||||||
|
{
|
||||||
|
// TODO: Make the CPU miss sometimes.
|
||||||
bIsHoldingButton = true;
|
bIsHoldingButton = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const StyleInput StyleI( pn, iTrack );
|
||||||
|
const GameInput GameI = GAMESTATE->GetCurrentStyle()->StyleInputToGameInput( StyleI );
|
||||||
|
bIsHoldingButton = INPUTMAPPER->IsButtonDown( GameI );
|
||||||
|
}
|
||||||
|
|
||||||
|
int iEndRow = iRow + tn.iDuration;
|
||||||
|
|
||||||
|
float fLife = tn.HoldResult.fLife;
|
||||||
if( bSteppedOnTapNote && fLife != 0 )
|
if( bSteppedOnTapNote && fLife != 0 )
|
||||||
{
|
{
|
||||||
/* This hold note is not judged and we stepped on its head. Update iLastHeldRow.
|
/* This hold note is not judged and we stepped on its head. Update iLastHeldRow.
|
||||||
* Do this even if we're a little beyond the end of the hold note, to make sure
|
* Do this even if we're a little beyond the end of the hold note, to make sure
|
||||||
* iLastHeldRow is clamped to iEndRow if the hold note is held all the way. */
|
* iLastHeldRow is clamped to iEndRow if the hold note is held all the way. */
|
||||||
hn.result.iLastHeldRow = min( iSongRow, hn.iEndRow );
|
tn.HoldResult.iLastHeldRow = min( iSongRow, iEndRow );
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the song beat is in the range of this hold:
|
// If the song beat is in the range of this hold:
|
||||||
if( hn.RowIsInRange(iSongRow) )
|
if( iRow <= iSongRow && iRow <= iEndRow )
|
||||||
{
|
{
|
||||||
// set hold flag so NoteField can do intelligent drawing
|
// set hold flag so NoteField can do intelligent drawing
|
||||||
hn.result.bHeld = bIsHoldingButton && bSteppedOnTapNote;
|
tn.HoldResult.bHeld = bIsHoldingButton && bSteppedOnTapNote;
|
||||||
hn.result.bActive = bSteppedOnTapNote;
|
tn.HoldResult.bActive = bSteppedOnTapNote;
|
||||||
|
|
||||||
if( bSteppedOnTapNote && bIsHoldingButton )
|
if( bSteppedOnTapNote && bIsHoldingButton )
|
||||||
{
|
{
|
||||||
@@ -391,42 +404,34 @@ void Player::Update( float fDeltaTime )
|
|||||||
fLife = 1;
|
fLife = 1;
|
||||||
|
|
||||||
if( m_pNoteField )
|
if( m_pNoteField )
|
||||||
m_pNoteField->DidHoldNote( hn.iTrack ); // update the "electric ghost" effect
|
m_pNoteField->DidHoldNote( iTrack ); // update the "electric ghost" effect
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* What is this conditional for? It causes a problem: if a hold note
|
|
||||||
* begins on a freeze, you can tap it and then release it for the
|
|
||||||
* duration of the freeze; life doesn't count down until we're
|
|
||||||
* past the first beat. */
|
|
||||||
// if( fSongBeat-hn.fStartBeat > GAMESTATE->m_fCurBPS * GetMaxStepDistanceSeconds() )
|
|
||||||
// {
|
|
||||||
// Decrease life
|
// Decrease life
|
||||||
fLife -= fDeltaTime/ADJUSTED_WINDOW(OK);
|
fLife -= fDeltaTime/ADJUSTED_WINDOW(OK);
|
||||||
fLife = max( fLife, 0 ); // clamp
|
fLife = max( fLife, 0 ); // clamp
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for NG. If the head was missed completely, don't count
|
/* check for NG. If the head was missed completely, don't count an NG. */
|
||||||
* an NG. */
|
|
||||||
if( bSteppedOnTapNote && fLife == 0 ) // the player has not pressed the button for a long time!
|
if( bSteppedOnTapNote && fLife == 0 ) // the player has not pressed the button for a long time!
|
||||||
hns = HNS_NG;
|
hns = HNS_NG;
|
||||||
|
|
||||||
// check for OK
|
// check for OK
|
||||||
if( iSongRow >= hn.iEndRow && bSteppedOnTapNote && fLife > 0 ) // if this HoldNote is in the past
|
if( iSongRow >= iEndRow && bSteppedOnTapNote && fLife > 0 ) // if this HoldNote is in the past
|
||||||
{
|
{
|
||||||
fLife = 1;
|
fLife = 1;
|
||||||
hns = HNS_OK;
|
hns = HNS_OK;
|
||||||
if( m_pNoteField )
|
if( m_pNoteField )
|
||||||
m_pNoteField->DidTapNote( StyleI.col, TNS_PERFECT, true ); // bright ghost flash
|
m_pNoteField->DidTapNote( iTrack, TNS_PERFECT, true ); // bright ghost flash
|
||||||
}
|
}
|
||||||
|
|
||||||
if( hns != HNS_NONE )
|
if( hns != HNS_NONE )
|
||||||
{
|
{
|
||||||
/* this note has been judged */
|
/* this note has been judged */
|
||||||
HandleHoldScore( hns, tns );
|
HandleHoldScore( hns, tns );
|
||||||
m_HoldJudgment[hn.iTrack].SetHoldJudgment( hns );
|
m_HoldJudgment[iTrack].SetHoldJudgment( hns );
|
||||||
|
|
||||||
int ms_error = (hns == HNS_OK)? 0:MAX_PRO_TIMING_ERROR;
|
int ms_error = (hns == HNS_OK)? 0:MAX_PRO_TIMING_ERROR;
|
||||||
|
|
||||||
@@ -436,8 +441,9 @@ void Player::Update( float fDeltaTime )
|
|||||||
m_ProTimingDisplay.SetJudgment( ms_error, TNS_MISS );
|
m_ProTimingDisplay.SetJudgment( ms_error, TNS_MISS );
|
||||||
}
|
}
|
||||||
|
|
||||||
hn.result.fLife = fLife;
|
tn.HoldResult.fLife = fLife;
|
||||||
hn.result.hns = hns;
|
tn.HoldResult.hns = hns;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove use of PlayerNumber.
|
// TODO: Remove use of PlayerNumber.
|
||||||
@@ -475,7 +481,6 @@ void Player::Update( float fDeltaTime )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// process transforms that are waiting to be applied
|
// process transforms that are waiting to be applied
|
||||||
ApplyWaitingTransforms();
|
ApplyWaitingTransforms();
|
||||||
|
|
||||||
@@ -1095,7 +1100,7 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Since this is being called every frame, let's not check the whole array every time.
|
// Since this is being called every frame, let's not check the whole array every time.
|
||||||
// Instead, only check 1 beat back. Even 10 is overkill.
|
// Instead, only check 1 beat back. Even 1 is overkill.
|
||||||
const int iStartCheckingAt = max( 0, iMissIfOlderThanThisIndex-BeatToNoteRow(1) );
|
const int iStartCheckingAt = max( 0, iMissIfOlderThanThisIndex-BeatToNoteRow(1) );
|
||||||
|
|
||||||
//LOG->Trace( "iStartCheckingAt: %d iMissIfOlderThanThisIndex: %d", iStartCheckingAt, iMissIfOlderThanThisIndex );
|
//LOG->Trace( "iStartCheckingAt: %d iMissIfOlderThanThisIndex: %d", iStartCheckingAt, iMissIfOlderThanThisIndex );
|
||||||
@@ -1217,14 +1222,7 @@ void Player::RandomizeNotes( int iNoteRow )
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Make sure the destination row isn't in the middle of a hold. */
|
/* Make sure the destination row isn't in the middle of a hold. */
|
||||||
bool bSkip = false;
|
if( m_NoteData.IsHoldNoteAtBeat(iSwapWith, iNoteRow) )
|
||||||
for( int i = 0; !bSkip && i < m_NoteData.GetNumHoldNotes(); ++i )
|
|
||||||
{
|
|
||||||
const HoldNote &hn = m_NoteData.GetHoldNote(i);
|
|
||||||
if( hn.iTrack == iSwapWith && hn.RowIsInRange(iNewNoteRow) )
|
|
||||||
bSkip = true;
|
|
||||||
}
|
|
||||||
if( bSkip )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_NoteData.SetTapNote( t, iNewNoteRow, t2 );
|
m_NoteData.SetTapNote( t, iNewNoteRow, t2 );
|
||||||
|
|||||||
@@ -682,8 +682,7 @@ void ScreenEdit::Update( float fDeltaTime )
|
|||||||
fEndBeat = Quantize( fEndBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
|
fEndBeat = Quantize( fEndBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
|
||||||
|
|
||||||
// create a new hold note
|
// create a new hold note
|
||||||
HoldNote newHN( t, BeatToNoteRow(fStartBeat), BeatToNoteRow(fEndBeat) );
|
m_NoteDataRecord.AddHoldNote( t, BeatToNoteRow(fStartBeat), BeatToNoteRow(fEndBeat), TAP_ORIGINAL_HOLD_HEAD );
|
||||||
m_NoteDataRecord.AddHoldNote( newHN );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -910,13 +909,11 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// check for to see if the user intended to remove a HoldNote
|
// check for to see if the user intended to remove a HoldNote
|
||||||
for( int i=0; i<m_NoteDataEdit.GetNumHoldNotes(); i++ ) // for each HoldNote
|
|
||||||
{
|
{
|
||||||
const HoldNote &hn = m_NoteDataEdit.GetHoldNote(i);
|
int iHeadRow;
|
||||||
if( iCol == hn.iTrack && // the notes correspond
|
if( m_NoteDataEdit.IsHoldNoteAtBeat( iCol, iSongIndex, &iHeadRow ) )
|
||||||
hn.RowIsInRange(iSongIndex) ) // the cursor lies within this HoldNote
|
|
||||||
{
|
{
|
||||||
m_NoteDataEdit.RemoveHoldNote( i );
|
m_NoteDataEdit.SetTapNote( iCol, iHeadRow, TAP_EMPTY );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1003,7 +1000,9 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
|
|||||||
}
|
}
|
||||||
|
|
||||||
const float fStartBeat = GAMESTATE->m_fSongBeat;
|
const float fStartBeat = GAMESTATE->m_fSongBeat;
|
||||||
const float fEndBeat = GAMESTATE->m_fSongBeat + fBeatsToMove;
|
float fEndBeat = max( GAMESTATE->m_fSongBeat + fBeatsToMove, 0 );
|
||||||
|
fEndBeat = Quantize( fEndBeat , NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
|
||||||
|
GAMESTATE->m_fSongBeat = fEndBeat;
|
||||||
|
|
||||||
// check to see if they're holding a button
|
// check to see if they're holding a button
|
||||||
for( int n=0; n<=9; n++ ) // for each number key
|
for( int n=0; n<=9; n++ ) // for each number key
|
||||||
@@ -1022,12 +1021,13 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// create a new hold note
|
// create a new hold note
|
||||||
HoldNote newHN( iCol, BeatToNoteRow(min(fStartBeat, fEndBeat)), BeatToNoteRow(max(fStartBeat, fEndBeat)) );
|
int iStartRow = BeatToNoteRow( min(fStartBeat, fEndBeat) );
|
||||||
|
int iEndRow = BeatToNoteRow( max(fStartBeat, fEndBeat) );
|
||||||
|
|
||||||
newHN.iStartRow = max(newHN.iStartRow, 0);
|
iStartRow = max( iStartRow, 0 );
|
||||||
newHN.iEndRow = max(newHN.iEndRow, 0);
|
iEndRow = max( iEndRow, 0 );
|
||||||
|
|
||||||
m_NoteDataEdit.AddHoldNote( newHN );
|
m_NoteDataEdit.AddHoldNote( iCol, iStartRow, iEndRow, TAP_ORIGINAL_HOLD_HEAD );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( EditIsBeingPressed(EDIT_BUTTON_SCROLL_SELECT) )
|
if( EditIsBeingPressed(EDIT_BUTTON_SCROLL_SELECT) )
|
||||||
@@ -1054,9 +1054,6 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GAMESTATE->m_fSongBeat += fBeatsToMove;
|
|
||||||
GAMESTATE->m_fSongBeat = max( GAMESTATE->m_fSongBeat, 0 );
|
|
||||||
GAMESTATE->m_fSongBeat = Quantize( GAMESTATE->m_fSongBeat, NoteTypeToBeat(m_SnapDisplay.GetNoteType()) );
|
|
||||||
m_soundChangeLine.Play();
|
m_soundChangeLine.Play();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1947,16 +1944,14 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
|
|||||||
break;
|
break;
|
||||||
case paste_at_current_beat:
|
case paste_at_current_beat:
|
||||||
{
|
{
|
||||||
int iSrcFirstRow = 0;
|
|
||||||
int iSrcLastRow = BeatToNoteRow( m_Clipboard.GetLastBeat() );
|
|
||||||
int iDestFirstRow = BeatToNoteRow( GAMESTATE->m_fSongBeat );
|
int iDestFirstRow = BeatToNoteRow( GAMESTATE->m_fSongBeat );
|
||||||
m_NoteDataEdit.CopyRange( m_Clipboard, iSrcFirstRow, iSrcLastRow, iDestFirstRow );
|
m_NoteDataEdit.CopyRange( m_Clipboard, 0, MAX_NOTE_ROW, iDestFirstRow );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case paste_at_begin_marker:
|
case paste_at_begin_marker:
|
||||||
{
|
{
|
||||||
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 );
|
ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 );
|
||||||
m_NoteDataEdit.CopyRange( m_Clipboard, 0, m_Clipboard.GetLastRow(), m_NoteFieldEdit.m_iBeginMarker );
|
m_NoteDataEdit.CopyRange( m_Clipboard, 0, MAX_NOTE_ROW, m_NoteFieldEdit.m_iBeginMarker );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case clear:
|
case clear:
|
||||||
@@ -2069,8 +2064,6 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
|
|||||||
default: ASSERT(0);
|
default: ASSERT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Clipboard.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
|
|
||||||
switch( at )
|
switch( at )
|
||||||
{
|
{
|
||||||
case compress_2x: NoteDataUtil::Scale( m_Clipboard, fScale ); break;
|
case compress_2x: NoteDataUtil::Scale( m_Clipboard, fScale ); break;
|
||||||
@@ -2082,8 +2075,6 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
|
|||||||
default: ASSERT(0);
|
default: ASSERT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Clipboard.Convert2sAnd3sToHoldNotes();
|
|
||||||
|
|
||||||
int iOldClipboardBeats = m_NoteFieldEdit.m_iEndMarker - m_NoteFieldEdit.m_iBeginMarker;
|
int iOldClipboardBeats = m_NoteFieldEdit.m_iEndMarker - m_NoteFieldEdit.m_iBeginMarker;
|
||||||
int iNewClipboardBeats = lrintf( iOldClipboardBeats * fScale );
|
int iNewClipboardBeats = lrintf( iOldClipboardBeats * fScale );
|
||||||
int iDeltaBeats = iNewClipboardBeats - iOldClipboardBeats;
|
int iDeltaBeats = iNewClipboardBeats - iOldClipboardBeats;
|
||||||
@@ -2094,7 +2085,6 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
|
|||||||
HandleAreaMenuChoice( paste_at_begin_marker, NULL );
|
HandleAreaMenuChoice( paste_at_begin_marker, NULL );
|
||||||
|
|
||||||
const vector<Steps*> sIter = m_pSong->GetAllSteps();
|
const vector<Steps*> sIter = m_pSong->GetAllSteps();
|
||||||
NoteData ndTemp;
|
|
||||||
CString sTempStyle, sTempDiff;
|
CString sTempStyle, sTempDiff;
|
||||||
for( unsigned i = 0; i < sIter.size(); i++ )
|
for( unsigned i = 0; i < sIter.size(); i++ )
|
||||||
{
|
{
|
||||||
@@ -2106,10 +2096,9 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
|
|||||||
(sIter[i]->GetDifficulty() == GAMESTATE->m_pCurSteps[PLAYER_1]->GetDifficulty()) )
|
(sIter[i]->GetDifficulty() == GAMESTATE->m_pCurSteps[PLAYER_1]->GetDifficulty()) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
NoteData ndTemp;
|
||||||
sIter[i]->GetNoteData( ndTemp );
|
sIter[i]->GetNoteData( ndTemp );
|
||||||
ndTemp.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
NoteDataUtil::ScaleRegion( ndTemp, fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
|
NoteDataUtil::ScaleRegion( ndTemp, fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker );
|
||||||
ndTemp.Convert2sAnd3sToHoldNotes();
|
|
||||||
sIter[i]->SetNoteData( ndTemp );
|
sIter[i]->SetNoteData( ndTemp );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2286,11 +2275,8 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, int* iAnswers )
|
|||||||
fStopLength *= fBPMatPause;
|
fStopLength *= fBPMatPause;
|
||||||
fStopLength /= 60;
|
fStopLength /= 60;
|
||||||
// don't move the step from where it is, just move everything later
|
// don't move the step from where it is, just move everything later
|
||||||
m_NoteDataEdit.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
NoteDataUtil::ShiftRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopLength) );
|
NoteDataUtil::ShiftRows( m_NoteDataEdit, BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopLength) );
|
||||||
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopLength) );
|
m_pSong->m_Timing.ShiftRows( BeatToNoteRow(GAMESTATE->m_fSongBeat) + 1, BeatToNoteRow(fStopLength) );
|
||||||
m_NoteDataEdit.Convert2sAnd3sToHoldNotes();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// Hello and welcome to I FEEL STUPID :-)
|
// Hello and welcome to I FEEL STUPID :-)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1114,9 +1114,6 @@ void ScreenGameplay::LoadNextSong()
|
|||||||
NoteDataUtil::LoadTransformedLights( TapNoteData, m_CabinetLightsNoteData, GameManager::StepsTypeToNumTracks(STEPS_TYPE_LIGHTS_CABINET) );
|
NoteDataUtil::LoadTransformedLights( TapNoteData, m_CabinetLightsNoteData, GameManager::StepsTypeToNumTracks(STEPS_TYPE_LIGHTS_CABINET) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to 2sAnd3s so that we can check if we're inside a hold with IsHoldNoteAtBeat.
|
|
||||||
m_CabinetLightsNoteData.ConvertHoldNotesTo2sAnd3s();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1615,12 +1612,11 @@ void ScreenGameplay::UpdateLights()
|
|||||||
FOREACH_EnabledPlayer( pn )
|
FOREACH_EnabledPlayer( pn )
|
||||||
{
|
{
|
||||||
// check if a hold should be active
|
// check if a hold should be active
|
||||||
for( int i=0; i < m_Player[pn].m_NoteData.GetNumHoldNotes(); i++ ) // for each HoldNote
|
for( int t=0; t < m_Player[pn].m_NoteData.GetNumTracks(); ++t )
|
||||||
{
|
{
|
||||||
const HoldNote &hn = m_Player[pn].m_NoteData.GetHoldNote(i);
|
if( m_Player[pn].m_NoteData.IsHoldNoteAtBeat( t, iSongRow ) )
|
||||||
if( hn.iStartRow <= iSongRow && iSongRow <= hn.iEndRow )
|
|
||||||
{
|
{
|
||||||
StyleInput si( pn, hn.iTrack );
|
StyleInput si( pn, t );
|
||||||
GameInput gi = pStyle->StyleInputToGameInput( si );
|
GameInput gi = pStyle->StyleInputToGameInput( si );
|
||||||
bBlinkGameButton[gi.controller][gi.button] |= true;
|
bBlinkGameButton[gi.controller][gi.button] |= true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user