Add NoteDataUtil and move some stuff into it
This commit is contained in:
+158
-158
@@ -20,7 +20,7 @@
|
|||||||
#include "RageException.h"
|
#include "RageException.h"
|
||||||
#include "GameState.h"
|
#include "GameState.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
#include "NotesLoaderSM.h"
|
||||||
|
|
||||||
|
|
||||||
NoteData::NoteData()
|
NoteData::NoteData()
|
||||||
@@ -38,126 +38,6 @@ NoteData::~NoteData()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoteData::LoadFromSMNoteDataString( CString sSMNoteData )
|
|
||||||
{
|
|
||||||
int iNumTracks = m_iNumTracks;
|
|
||||||
Init();
|
|
||||||
m_iNumTracks = iNumTracks;
|
|
||||||
|
|
||||||
// strip comments out of sSMNoteData
|
|
||||||
while( sSMNoteData.Find("//") != -1 )
|
|
||||||
{
|
|
||||||
int iIndexCommentStart = sSMNoteData.Find("//");
|
|
||||||
int iIndexCommentEnd = sSMNoteData.Find("\n", iIndexCommentStart);
|
|
||||||
if( iIndexCommentEnd == -1 ) // comment doesn't have an end?
|
|
||||||
sSMNoteData.Delete( iIndexCommentStart, 2 );
|
|
||||||
else
|
|
||||||
sSMNoteData.Delete( iIndexCommentStart, iIndexCommentEnd-iIndexCommentStart );
|
|
||||||
}
|
|
||||||
|
|
||||||
CStringArray asMeasures;
|
|
||||||
split( sSMNoteData, ",", asMeasures, true ); // ignore empty is important
|
|
||||||
for( unsigned m=0; m<asMeasures.size(); m++ ) // foreach measure
|
|
||||||
{
|
|
||||||
CString &sMeasureString = asMeasures[m];
|
|
||||||
TrimLeft(sMeasureString);
|
|
||||||
TrimRight(sMeasureString);
|
|
||||||
|
|
||||||
CStringArray asMeasureLines;
|
|
||||||
split( sMeasureString, "\n", asMeasureLines, true ); // ignore empty is important
|
|
||||||
|
|
||||||
//ASSERT( asMeasureLines.size() == 4 ||
|
|
||||||
// asMeasureLines.size() == 8 ||
|
|
||||||
// asMeasureLines.size() == 12 ||
|
|
||||||
// asMeasureLines.size() == 16 );
|
|
||||||
|
|
||||||
|
|
||||||
for( unsigned l=0; l<asMeasureLines.size(); l++ )
|
|
||||||
{
|
|
||||||
CString &sMeasureLine = asMeasureLines[l];
|
|
||||||
TrimLeft(sMeasureLine);
|
|
||||||
TrimRight(sMeasureLine);
|
|
||||||
|
|
||||||
const float fPercentIntoMeasure = l/(float)asMeasureLines.size();
|
|
||||||
const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE;
|
|
||||||
const int iIndex = BeatToNoteRow( fBeat );
|
|
||||||
|
|
||||||
// if( m_iNumTracks != sMeasureLine.GetLength() )
|
|
||||||
// throw RageException( "Actual number of note columns (%d) is different from the NotesType (%d).", m_iNumTracks, sMeasureLine.GetLength() );
|
|
||||||
|
|
||||||
for( int c=0; c<min(sMeasureLine.GetLength(),m_iNumTracks); c++ )
|
|
||||||
{
|
|
||||||
TapNote t;
|
|
||||||
switch(sMeasureLine[c])
|
|
||||||
{
|
|
||||||
case '0': t = TAP_EMPTY; break;
|
|
||||||
case '1': t = TAP_TAP; break;
|
|
||||||
case '2': t = TAP_HOLD_HEAD; break;
|
|
||||||
case '3': t = TAP_HOLD_TAIL; break;
|
|
||||||
default: ASSERT(0); t = TAP_EMPTY; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetTapNote(c, iIndex, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this->Convert2sAnd3sToHoldNotes();
|
|
||||||
|
|
||||||
Compress();
|
|
||||||
}
|
|
||||||
|
|
||||||
CString NoteData::GetSMNoteDataString()
|
|
||||||
{
|
|
||||||
this->ConvertHoldNotesTo2sAnd3s();
|
|
||||||
|
|
||||||
float fLastBeat = GetLastBeat();
|
|
||||||
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
|
|
||||||
|
|
||||||
CStringArray asMeasureStrings;
|
|
||||||
|
|
||||||
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
|
|
||||||
{
|
|
||||||
NoteType nt = GetSmallestNoteTypeForMeasure( m );
|
|
||||||
int iRowSpacing;
|
|
||||||
if( nt == NOTE_TYPE_INVALID )
|
|
||||||
iRowSpacing = 1;
|
|
||||||
else
|
|
||||||
iRowSpacing = int(roundf( NoteTypeToBeat(nt) * ROWS_PER_BEAT ));
|
|
||||||
|
|
||||||
CStringArray asMeasureLines;
|
|
||||||
asMeasureLines.push_back( ssprintf(" // measure %d", m+1) );
|
|
||||||
|
|
||||||
const int iMeasureStartRow = m * ROWS_PER_MEASURE;
|
|
||||||
const int iMeasureLastRow = (m+1) * ROWS_PER_MEASURE - 1;
|
|
||||||
|
|
||||||
for( int r=iMeasureStartRow; r<=iMeasureLastRow; r+=iRowSpacing )
|
|
||||||
{
|
|
||||||
CString szLineString;
|
|
||||||
for( int t=0; t<m_iNumTracks; t++ ) {
|
|
||||||
char c;
|
|
||||||
switch(GetTapNote(t, r)) {
|
|
||||||
case TAP_EMPTY: c = '0'; break;
|
|
||||||
case TAP_TAP: c = '1'; break;
|
|
||||||
case TAP_HOLD_HEAD: c = '2'; break;
|
|
||||||
case TAP_HOLD_TAIL: c = '3'; break;
|
|
||||||
default: ASSERT(0); c = '0'; break;
|
|
||||||
}
|
|
||||||
szLineString.append(1, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
asMeasureLines.push_back( szLineString );
|
|
||||||
}
|
|
||||||
|
|
||||||
CString sMeasureString = join( "\n", asMeasureLines );
|
|
||||||
|
|
||||||
asMeasureStrings.push_back( sMeasureString );
|
|
||||||
}
|
|
||||||
|
|
||||||
this->Convert2sAnd3sToHoldNotes();
|
|
||||||
|
|
||||||
return join( "\n,", asMeasureStrings );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear [iNoteIndexBegin,iNoteIndexEnd]; that is, including iNoteIndexEnd. */
|
/* Clear [iNoteIndexBegin,iNoteIndexEnd]; that is, including iNoteIndexEnd. */
|
||||||
void NoteData::ClearRange( int iNoteIndexBegin, int iNoteIndexEnd )
|
void NoteData::ClearRange( int iNoteIndexBegin, int iNoteIndexEnd )
|
||||||
{
|
{
|
||||||
@@ -1006,43 +886,6 @@ void NoteData::LoadTransformedSlidingWindow( NoteData* pOriginal, int iNewNumTra
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NoteType NoteData::GetSmallestNoteTypeForMeasure( int iMeasureIndex )
|
|
||||||
{
|
|
||||||
const int iMeasureStartIndex = iMeasureIndex * ROWS_PER_MEASURE;
|
|
||||||
const int iMeasureLastIndex = (iMeasureIndex+1) * ROWS_PER_MEASURE - 1;
|
|
||||||
|
|
||||||
// probe to find the smallest note type
|
|
||||||
NoteType nt;
|
|
||||||
for( nt=(NoteType)0; nt<NUM_NOTE_TYPES; nt=NoteType(nt+1) ) // for each NoteType, largest to largest
|
|
||||||
{
|
|
||||||
float fBeatSpacing = NoteTypeToBeat( nt );
|
|
||||||
int iRowSpacing = int(roundf( fBeatSpacing * ROWS_PER_BEAT ));
|
|
||||||
|
|
||||||
bool bFoundSmallerNote = false;
|
|
||||||
for( int i=iMeasureStartIndex; i<=iMeasureLastIndex; i++ ) // for each index in this measure
|
|
||||||
{
|
|
||||||
if( i % iRowSpacing == 0 )
|
|
||||||
continue; // skip
|
|
||||||
|
|
||||||
if( !IsRowEmpty(i) )
|
|
||||||
{
|
|
||||||
bFoundSmallerNote = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( bFoundSmallerNote )
|
|
||||||
continue; // searching the next NoteType
|
|
||||||
else
|
|
||||||
break; // stop searching. We found the smallest NoteType
|
|
||||||
}
|
|
||||||
|
|
||||||
if( nt == NUM_NOTE_TYPES ) // we didn't find one
|
|
||||||
return NOTE_TYPE_INVALID; // well-formed notes created in the editor should never get here
|
|
||||||
else
|
|
||||||
return nt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NoteData::PadTapNotes(int rows)
|
void NoteData::PadTapNotes(int rows)
|
||||||
{
|
{
|
||||||
int needed = rows - m_TapNotes[0].size() + 1;
|
int needed = rows - m_TapNotes[0].size() + 1;
|
||||||
@@ -1144,3 +987,160 @@ void NoteData::Decompress()
|
|||||||
{
|
{
|
||||||
SetDivisor(1);
|
SetDivisor(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex )
|
||||||
|
{
|
||||||
|
const int iMeasureStartIndex = iMeasureIndex * ROWS_PER_MEASURE;
|
||||||
|
const int iMeasureLastIndex = (iMeasureIndex+1) * ROWS_PER_MEASURE - 1;
|
||||||
|
|
||||||
|
// probe to find the smallest note type
|
||||||
|
NoteType nt;
|
||||||
|
for( nt=(NoteType)0; nt<NUM_NOTE_TYPES; nt=NoteType(nt+1) ) // for each NoteType, largest to largest
|
||||||
|
{
|
||||||
|
float fBeatSpacing = NoteTypeToBeat( nt );
|
||||||
|
int iRowSpacing = int(roundf( fBeatSpacing * ROWS_PER_BEAT ));
|
||||||
|
|
||||||
|
bool bFoundSmallerNote = false;
|
||||||
|
for( int i=iMeasureStartIndex; i<=iMeasureLastIndex; i++ ) // for each index in this measure
|
||||||
|
{
|
||||||
|
if( i % iRowSpacing == 0 )
|
||||||
|
continue; // skip
|
||||||
|
|
||||||
|
if( !n.IsRowEmpty(i) )
|
||||||
|
{
|
||||||
|
bFoundSmallerNote = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bFoundSmallerNote )
|
||||||
|
continue; // searching the next NoteType
|
||||||
|
else
|
||||||
|
break; // stop searching. We found the smallest NoteType
|
||||||
|
}
|
||||||
|
|
||||||
|
if( nt == NUM_NOTE_TYPES ) // we didn't find one
|
||||||
|
return NOTE_TYPE_INVALID; // well-formed notes created in the editor should never get here
|
||||||
|
else
|
||||||
|
return nt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData )
|
||||||
|
{
|
||||||
|
/* Clear notes, but keep the same number of tracks. */
|
||||||
|
int iNumTracks = out.m_iNumTracks;
|
||||||
|
out.Init();
|
||||||
|
out.m_iNumTracks = iNumTracks;
|
||||||
|
|
||||||
|
// strip comments out of sSMNoteData
|
||||||
|
while( sSMNoteData.Find("//") != -1 )
|
||||||
|
{
|
||||||
|
int iIndexCommentStart = sSMNoteData.Find("//");
|
||||||
|
int iIndexCommentEnd = sSMNoteData.Find("\n", iIndexCommentStart);
|
||||||
|
if( iIndexCommentEnd == -1 ) // comment doesn't have an end?
|
||||||
|
sSMNoteData.Delete( iIndexCommentStart, 2 );
|
||||||
|
else
|
||||||
|
sSMNoteData.Delete( iIndexCommentStart, iIndexCommentEnd-iIndexCommentStart );
|
||||||
|
}
|
||||||
|
|
||||||
|
CStringArray asMeasures;
|
||||||
|
split( sSMNoteData, ",", asMeasures, true ); // ignore empty is important
|
||||||
|
for( unsigned m=0; m<asMeasures.size(); m++ ) // foreach measure
|
||||||
|
{
|
||||||
|
CString &sMeasureString = asMeasures[m];
|
||||||
|
TrimLeft(sMeasureString);
|
||||||
|
TrimRight(sMeasureString);
|
||||||
|
|
||||||
|
CStringArray asMeasureLines;
|
||||||
|
split( sMeasureString, "\n", asMeasureLines, true ); // ignore empty is important
|
||||||
|
|
||||||
|
//ASSERT( asMeasureLines.size() == 4 ||
|
||||||
|
// asMeasureLines.size() == 8 ||
|
||||||
|
// asMeasureLines.size() == 12 ||
|
||||||
|
// asMeasureLines.size() == 16 );
|
||||||
|
|
||||||
|
|
||||||
|
for( unsigned l=0; l<asMeasureLines.size(); l++ )
|
||||||
|
{
|
||||||
|
CString &sMeasureLine = asMeasureLines[l];
|
||||||
|
TrimLeft(sMeasureLine);
|
||||||
|
TrimRight(sMeasureLine);
|
||||||
|
|
||||||
|
const float fPercentIntoMeasure = l/(float)asMeasureLines.size();
|
||||||
|
const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE;
|
||||||
|
const int iIndex = BeatToNoteRow( fBeat );
|
||||||
|
|
||||||
|
// if( m_iNumTracks != sMeasureLine.GetLength() )
|
||||||
|
// throw RageException( "Actual number of note columns (%d) is different from the NotesType (%d).", m_iNumTracks, sMeasureLine.GetLength() );
|
||||||
|
|
||||||
|
for( int c=0; c<min(sMeasureLine.GetLength(),out.m_iNumTracks); c++ )
|
||||||
|
{
|
||||||
|
TapNote t;
|
||||||
|
switch(sMeasureLine[c])
|
||||||
|
{
|
||||||
|
case '0': t = TAP_EMPTY; break;
|
||||||
|
case '1': t = TAP_TAP; break;
|
||||||
|
case '2': t = TAP_HOLD_HEAD; break;
|
||||||
|
case '3': t = TAP_HOLD_TAIL; break;
|
||||||
|
default: ASSERT(0); t = TAP_EMPTY; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.SetTapNote(c, iIndex, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Convert2sAnd3sToHoldNotes();
|
||||||
|
|
||||||
|
out.Compress();
|
||||||
|
}
|
||||||
|
|
||||||
|
CString NoteDataUtil::GetSMNoteDataString(NoteData &in)
|
||||||
|
{
|
||||||
|
in.ConvertHoldNotesTo2sAnd3s();
|
||||||
|
|
||||||
|
float fLastBeat = in.GetLastBeat();
|
||||||
|
int iLastMeasure = int( fLastBeat/BEATS_PER_MEASURE );
|
||||||
|
|
||||||
|
CStringArray asMeasureStrings;
|
||||||
|
for( int m=0; m<=iLastMeasure; m++ ) // foreach measure
|
||||||
|
{
|
||||||
|
NoteType nt = GetSmallestNoteTypeForMeasure( in, m );
|
||||||
|
int iRowSpacing;
|
||||||
|
if( nt == NOTE_TYPE_INVALID )
|
||||||
|
iRowSpacing = 1;
|
||||||
|
else
|
||||||
|
iRowSpacing = int(roundf( NoteTypeToBeat(nt) * ROWS_PER_BEAT ));
|
||||||
|
|
||||||
|
CStringArray asMeasureLines;
|
||||||
|
asMeasureLines.push_back( ssprintf(" // measure %d", m+1) );
|
||||||
|
|
||||||
|
const int iMeasureStartRow = m * ROWS_PER_MEASURE;
|
||||||
|
const int iMeasureLastRow = (m+1) * ROWS_PER_MEASURE - 1;
|
||||||
|
|
||||||
|
for( int r=iMeasureStartRow; r<=iMeasureLastRow; r+=iRowSpacing )
|
||||||
|
{
|
||||||
|
CString szLineString;
|
||||||
|
for( int t=0; t<in.m_iNumTracks; t++ ) {
|
||||||
|
char c;
|
||||||
|
switch(in.GetTapNote(t, r)) {
|
||||||
|
case TAP_EMPTY: c = '0'; break;
|
||||||
|
case TAP_TAP: c = '1'; break;
|
||||||
|
case TAP_HOLD_HEAD: c = '2'; break;
|
||||||
|
case TAP_HOLD_TAIL: c = '3'; break;
|
||||||
|
default: ASSERT(0); c = '0'; break;
|
||||||
|
}
|
||||||
|
szLineString.append(1, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
asMeasureLines.push_back( szLineString );
|
||||||
|
}
|
||||||
|
|
||||||
|
CString sMeasureString = join( "\n", asMeasureLines );
|
||||||
|
|
||||||
|
asMeasureStrings.push_back( sMeasureString );
|
||||||
|
}
|
||||||
|
|
||||||
|
in.Convert2sAnd3sToHoldNotes();
|
||||||
|
|
||||||
|
return join( "\n,", asMeasureStrings );
|
||||||
|
}
|
||||||
|
|||||||
@@ -61,15 +61,12 @@ public:
|
|||||||
void PadTapNotes(int rows);
|
void PadTapNotes(int rows);
|
||||||
void SetTapNote(int track, int row, TapNote t);
|
void SetTapNote(int track, int row, TapNote t);
|
||||||
|
|
||||||
void LoadFromSMNoteDataString( CString sSMNoteData );
|
|
||||||
CString GetSMNoteDataString();
|
|
||||||
|
|
||||||
void ClearRange( int iNoteIndexBegin, int iNoteIndexEnd );
|
void ClearRange( int iNoteIndexBegin, int iNoteIndexEnd );
|
||||||
void ClearAll() { ClearRange( 0, MAX_TAP_NOTE_ROWS ); };
|
void ClearAll() { ClearRange( 0, MAX_TAP_NOTE_ROWS ); };
|
||||||
void CopyRange( NoteData* pFrom, int iFromIndexBegin, int iFromIndexEnd, int iToIndexBegin = -1 );
|
void CopyRange( NoteData* pFrom, int iFromIndexBegin, int iFromIndexEnd, int iToIndexBegin = -1 );
|
||||||
void CopyAll( NoteData* pFrom );
|
void CopyAll( NoteData* pFrom );
|
||||||
|
|
||||||
inline bool IsRowEmpty( int index )
|
inline bool IsRowEmpty( int index ) const
|
||||||
{
|
{
|
||||||
for( int t=0; t<m_iNumTracks; t++ )
|
for( int t=0; t<m_iNumTracks; t++ )
|
||||||
if( GetTapNote(t, index) != TAP_EMPTY )
|
if( GetTapNote(t, index) != TAP_EMPTY )
|
||||||
@@ -131,8 +128,6 @@ public:
|
|||||||
void SnapToNearestNoteType( NoteType nt, float fBeginBeat, float fEndBeat ) { SnapToNearestNoteType( nt, (NoteType)-1, fBeginBeat, fEndBeat ); }
|
void SnapToNearestNoteType( NoteType nt, float fBeginBeat, float fEndBeat ) { SnapToNearestNoteType( nt, (NoteType)-1, fBeginBeat, fEndBeat ); }
|
||||||
void SnapToNearestNoteType( NoteType nt1, NoteType nt2, float fBeginBeat, float fEndBeat );
|
void SnapToNearestNoteType( NoteType nt1, NoteType nt2, float fBeginBeat, float fEndBeat );
|
||||||
|
|
||||||
NoteType GetSmallestNoteTypeForMeasure( int iMeasureIndex );
|
|
||||||
|
|
||||||
// Convert between HoldNote representation and '2' and '3' markers in TapNotes
|
// Convert between HoldNote representation and '2' and '3' markers in TapNotes
|
||||||
void Convert2sAnd3sToHoldNotes();
|
void Convert2sAnd3sToHoldNotes();
|
||||||
void ConvertHoldNotesTo2sAnd3s();
|
void ConvertHoldNotesTo2sAnd3s();
|
||||||
@@ -141,4 +136,15 @@ public:
|
|||||||
void ConvertHoldNotesTo4s();
|
void ConvertHoldNotesTo4s();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Utils for NoteData. Things should go in here if they can be (cleanly and
|
||||||
|
* efficiently) implemented using only NoteData's primitives; this improves
|
||||||
|
* abstraction and makes it much easier to change NoteData internally in
|
||||||
|
* the future. */
|
||||||
|
namespace NoteDataUtil
|
||||||
|
{
|
||||||
|
NoteType GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex );
|
||||||
|
void LoadFromSMNoteDataString( NoteData &out, CString sSMNoteData );
|
||||||
|
CString GetSMNoteDataString(NoteData &in);
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -76,13 +76,13 @@ void Notes::WriteSMNotesTag( FILE* fp )
|
|||||||
void Notes::SetNoteData( NoteData* pNewNoteData )
|
void Notes::SetNoteData( NoteData* pNewNoteData )
|
||||||
{
|
{
|
||||||
ASSERT( pNewNoteData->m_iNumTracks == GameManager::NotesTypeToNumTracks(m_NotesType) );
|
ASSERT( pNewNoteData->m_iNumTracks == GameManager::NotesTypeToNumTracks(m_NotesType) );
|
||||||
m_sSMNoteData = pNewNoteData->GetSMNoteDataString();
|
m_sSMNoteData = NoteDataUtil::GetSMNoteDataString(*pNewNoteData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Notes::GetNoteData( NoteData* pNoteDataOut ) const
|
void Notes::GetNoteData( NoteData* pNoteDataOut ) const
|
||||||
{
|
{
|
||||||
pNoteDataOut->m_iNumTracks = GameManager::NotesTypeToNumTracks( m_NotesType );
|
pNoteDataOut->m_iNumTracks = GameManager::NotesTypeToNumTracks( m_NotesType );
|
||||||
pNoteDataOut->LoadFromSMNoteDataString( m_sSMNoteData );
|
NoteDataUtil::LoadFromSMNoteDataString( *pNoteDataOut, m_sSMNoteData );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color is a function of Difficulty and Intended Style
|
// Color is a function of Difficulty and Intended Style
|
||||||
|
|||||||
Reference in New Issue
Block a user