Add NoteData "compression".
This commit is contained in:
+100
-3
@@ -31,6 +31,7 @@ NoteData::NoteData()
|
|||||||
void NoteData::Init()
|
void NoteData::Init()
|
||||||
{
|
{
|
||||||
m_iNumTracks = 0;
|
m_iNumTracks = 0;
|
||||||
|
TapRowDivisor = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteData::~NoteData()
|
NoteData::~NoteData()
|
||||||
@@ -101,6 +102,8 @@ void NoteData::LoadFromSMNoteDataString( CString sSMNoteData )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->Convert2sAnd3sToHoldNotes();
|
this->Convert2sAnd3sToHoldNotes();
|
||||||
|
|
||||||
|
Compress();
|
||||||
}
|
}
|
||||||
|
|
||||||
CString NoteData::GetSMNoteDataString()
|
CString NoteData::GetSMNoteDataString()
|
||||||
@@ -195,6 +198,19 @@ void NoteData::CopyRange( NoteData* pFrom, int iFromIndexBegin, int iFromIndexEn
|
|||||||
this->Convert4sToHoldNotes();
|
this->Convert4sToHoldNotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NoteData::Config( const NoteData &From )
|
||||||
|
{
|
||||||
|
m_iNumTracks = From.m_iNumTracks;
|
||||||
|
TapRowDivisor = From.TapRowDivisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteData::CopyAll( NoteData* pFrom )
|
||||||
|
{
|
||||||
|
Config(*pFrom);
|
||||||
|
m_HoldNotes.clear();
|
||||||
|
CopyRange( pFrom, 0, MAX_TAP_NOTE_ROWS );
|
||||||
|
}
|
||||||
|
|
||||||
void NoteData::AddHoldNote( HoldNote add )
|
void NoteData::AddHoldNote( HoldNote add )
|
||||||
{
|
{
|
||||||
ASSERT( add.m_fStartBeat>=0 && add.m_fEndBeat>=0 );
|
ASSERT( add.m_fStartBeat>=0 && add.m_fEndBeat>=0 );
|
||||||
@@ -312,7 +328,7 @@ float NoteData::GetLastBeat()
|
|||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for( i = int(m_TapNotes[0].size()); i>=0; i-- ) // iterate back to front
|
for( i = TapRowDivisor * int(m_TapNotes[0].size()); i>=0; i-- ) // iterate back to front
|
||||||
{
|
{
|
||||||
if( !IsRowEmpty(i) )
|
if( !IsRowEmpty(i) )
|
||||||
{
|
{
|
||||||
@@ -589,7 +605,7 @@ void NoteData::Turn( PlayerOptions::TurnType tt )
|
|||||||
}
|
}
|
||||||
|
|
||||||
NoteData tempNoteData; // write into here as we tranform
|
NoteData tempNoteData; // write into here as we tranform
|
||||||
tempNoteData.m_iNumTracks = m_iNumTracks;
|
tempNoteData.Config(*this);
|
||||||
|
|
||||||
this->ConvertHoldNotesTo2sAnd3s();
|
this->ConvertHoldNotesTo2sAnd3s();
|
||||||
|
|
||||||
@@ -613,7 +629,7 @@ void NoteData::Turn( PlayerOptions::TurnType tt )
|
|||||||
|
|
||||||
// clear tempNoteData because we're going to use it as a scratch buffer again
|
// clear tempNoteData because we're going to use it as a scratch buffer again
|
||||||
tempNoteData.Init();
|
tempNoteData.Init();
|
||||||
tempNoteData.m_iNumTracks = this->m_iNumTracks;
|
tempNoteData.Config(*this);
|
||||||
|
|
||||||
// copy all HoldNotes before copying taps
|
// copy all HoldNotes before copying taps
|
||||||
for( int i=0; i<this->GetNumHoldNotes(); i++ )
|
for( int i=0; i<this->GetNumHoldNotes(); i++ )
|
||||||
@@ -899,6 +915,7 @@ void NoteData::LoadTransformed( NoteData* pOriginal, int iNewNumTracks, const in
|
|||||||
|
|
||||||
pOriginal->ConvertHoldNotesTo4s();
|
pOriginal->ConvertHoldNotesTo4s();
|
||||||
|
|
||||||
|
Config(*pOriginal);
|
||||||
m_iNumTracks = iNewNumTracks;
|
m_iNumTracks = iNewNumTracks;
|
||||||
|
|
||||||
// copy tracks
|
// copy tracks
|
||||||
@@ -921,6 +938,7 @@ void NoteData::LoadTransformedSlidingWindow( NoteData* pOriginal, int iNewNumTra
|
|||||||
Init();
|
Init();
|
||||||
|
|
||||||
pOriginal->ConvertHoldNotesTo4s();
|
pOriginal->ConvertHoldNotesTo4s();
|
||||||
|
Config(*pOriginal);
|
||||||
m_iNumTracks = iNewNumTracks;
|
m_iNumTracks = iNewNumTracks;
|
||||||
|
|
||||||
int iCurTrackOffset = 0;
|
int iCurTrackOffset = 0;
|
||||||
@@ -1044,6 +1062,85 @@ void NoteData::MoveTapNoteTrack(int dest, int src)
|
|||||||
void NoteData::SetTapNote(int track, int row, TapNote t)
|
void NoteData::SetTapNote(int track, int row, TapNote t)
|
||||||
{
|
{
|
||||||
if(row < 0) return;
|
if(row < 0) return;
|
||||||
|
|
||||||
|
Decompress();
|
||||||
|
|
||||||
PadTapNotes(row);
|
PadTapNotes(row);
|
||||||
m_TapNotes[track][row]=t;
|
m_TapNotes[track][row]=t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NoteData::SetDivisor(int div)
|
||||||
|
{
|
||||||
|
if(div == TapRowDivisor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int src_step = div,
|
||||||
|
dst_step = TapRowDivisor;
|
||||||
|
|
||||||
|
/* I think this should work to go from one divisor to another, but
|
||||||
|
* I havn't tested it and don't see a need. */
|
||||||
|
ASSERT(src_step == 1 || dst_step == 1);
|
||||||
|
|
||||||
|
for(int t=0; t < m_iNumTracks; t++)
|
||||||
|
{
|
||||||
|
vector<TapNote> TapNotes = m_TapNotes[t];
|
||||||
|
/* Try to make sure the memory is actually released. */
|
||||||
|
int dst_size = m_TapNotes[0].size() * dst_step / src_step;
|
||||||
|
m_TapNotes[t].clear();
|
||||||
|
m_TapNotes[t] = vector<TapNote>(dst_size, TAP_EMPTY);
|
||||||
|
|
||||||
|
unsigned src_row = 0, dst_row = 0;
|
||||||
|
while(src_row < TapNotes.size() && dst_row < m_TapNotes[t].size())
|
||||||
|
{
|
||||||
|
m_TapNotes[t][dst_row] = TapNotes[src_row];
|
||||||
|
dst_row += dst_step;
|
||||||
|
src_row += src_step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TapRowDivisor = div;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteData::Compress()
|
||||||
|
{
|
||||||
|
/* We could optimize a little by being able to compress compressed data,
|
||||||
|
* but let's not bother for now. */
|
||||||
|
Decompress();
|
||||||
|
|
||||||
|
/* Find the largest divisor; the largest D such that all notes M such that
|
||||||
|
* (M%D) != 0 are empty. */
|
||||||
|
const int max_divisor = 64;
|
||||||
|
bool *ok = new bool[max_divisor];
|
||||||
|
memset(ok, 1, sizeof(ok));
|
||||||
|
|
||||||
|
int t, row, rows = GetLastRow();
|
||||||
|
|
||||||
|
for(t=0; t < m_iNumTracks; t++)
|
||||||
|
{
|
||||||
|
for(row = 0; row < rows; ++row)
|
||||||
|
{
|
||||||
|
/* If there's nothing here, then it doesn't make any divisors invalid. */
|
||||||
|
if(GetTapNote(t, row) == TAP_EMPTY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for(int div = 2; div < max_divisor; ++div)
|
||||||
|
{
|
||||||
|
if((row % div) != 0) ok[div] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(ok[1]);
|
||||||
|
int best_div = max_divisor-1;
|
||||||
|
while(!ok[best_div])
|
||||||
|
best_div--;
|
||||||
|
|
||||||
|
delete [] ok;
|
||||||
|
|
||||||
|
SetDivisor(best_div);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteData::Decompress()
|
||||||
|
{
|
||||||
|
SetDivisor(1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,9 +27,15 @@ class NoteData
|
|||||||
{
|
{
|
||||||
/* Keep this aligned, so that they all have the same size. */
|
/* Keep this aligned, so that they all have the same size. */
|
||||||
vector<TapNote> m_TapNotes[MAX_NOTE_TRACKS];
|
vector<TapNote> m_TapNotes[MAX_NOTE_TRACKS];
|
||||||
|
int TapRowDivisor;
|
||||||
|
void SetDivisor(int div);
|
||||||
|
|
||||||
vector<HoldNote> m_HoldNotes;
|
vector<HoldNote> m_HoldNotes;
|
||||||
|
|
||||||
|
/* 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 );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NoteData();
|
NoteData();
|
||||||
~NoteData();
|
~NoteData();
|
||||||
@@ -37,13 +43,19 @@ public:
|
|||||||
|
|
||||||
int m_iNumTracks;
|
int m_iNumTracks;
|
||||||
|
|
||||||
|
void Compress();
|
||||||
|
void Decompress();
|
||||||
|
|
||||||
/* Return the note at the given track and row. Row may be out of
|
/* Return the note at the given track and row. Row may be out of
|
||||||
* range; pretend the song goes on with TAP_EMPTYs indefinitely. */
|
* range; pretend the song goes on with TAP_EMPTYs indefinitely. */
|
||||||
inline TapNote GetTapNote(unsigned track, unsigned row) const
|
inline TapNote GetTapNote(unsigned track, unsigned row) const
|
||||||
{
|
{
|
||||||
|
if((row % TapRowDivisor) != 0) return TapNote(TAP_EMPTY);
|
||||||
|
row /= TapRowDivisor;
|
||||||
if(row < 0 || row >= m_TapNotes[track].size()) return TapNote(TAP_EMPTY);
|
if(row < 0 || row >= m_TapNotes[track].size()) return TapNote(TAP_EMPTY);
|
||||||
return m_TapNotes[track][row];
|
return m_TapNotes[track][row];
|
||||||
}
|
}
|
||||||
|
int GetTapNoteIncrement() const { return TapRowDivisor; }
|
||||||
void MoveTapNoteTrack(int dest, int src);
|
void MoveTapNoteTrack(int dest, int src);
|
||||||
/* Pad m_TapNotes so it includes the row "rows". */
|
/* Pad m_TapNotes so it includes the row "rows". */
|
||||||
void PadTapNotes(int rows);
|
void PadTapNotes(int rows);
|
||||||
@@ -55,7 +67,7 @@ public:
|
|||||||
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 ) { m_iNumTracks = pFrom->m_iNumTracks; m_HoldNotes.clear(); CopyRange( pFrom, 0, MAX_TAP_NOTE_ROWS ); };
|
void CopyAll( NoteData* pFrom );
|
||||||
|
|
||||||
inline bool IsRowEmpty( int index )
|
inline bool IsRowEmpty( int index )
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user