From adc450a3aca0c2191c9cb2e3d22b463899ba7908 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Sat, 5 Oct 2002 14:47:03 +0000 Subject: [PATCH] AutoGen now will fill in all missing NotesTypes. The patterns generated by AutoGen are now more intelligent. Fixed crash in MsdFile. --- stepmania/src/MsdFile.cpp | 33 ++++++++--------- stepmania/src/MsdFile.h | 2 +- stepmania/src/NoteData.cpp | 69 ++++++++++++++++++++++++++++++++++-- stepmania/src/NoteData.h | 5 ++- stepmania/src/ScreenEdit.cpp | 4 +-- stepmania/src/Song.cpp | 69 +++++++++++++++++++----------------- 6 files changed, 125 insertions(+), 57 deletions(-) diff --git a/stepmania/src/MsdFile.cpp b/stepmania/src/MsdFile.cpp index 6af98cffb7..f8b79e1d43 100644 --- a/stepmania/src/MsdFile.cpp +++ b/stepmania/src/MsdFile.cpp @@ -11,6 +11,8 @@ */ #include "MsdFile.h" +#include "io.h" +#include "fcntl.h" MsdFile::MsdFile() @@ -25,19 +27,15 @@ MsdFile::~MsdFile() //returns true if successful, false otherwise bool MsdFile::ReadFile( CString sNewPath ) { - // Get file size in bytes - HANDLE hFile = CreateFile( - sNewPath, // pointer to name of the file - GENERIC_READ, // access (read-write) mode - FILE_SHARE_READ|FILE_SHARE_WRITE, // share mode - NULL, // pointer to security attributes - OPEN_EXISTING, // how to create - FILE_ATTRIBUTE_NORMAL, // file attributes - NULL // handle to file with attributes to - ); + int fh; + + /* Open a file */ + if( (fh = _open(sNewPath, _O_RDONLY, 0)) == -1 ) + return false; + + int iBufferSize = _filelength( fh ) + 1000; // +1000 because sometimes the bytes read is > filelength. Why? + _close( fh ); - int iBufferSize = GetFileSize( hFile, NULL ) + 1000; // +1000 just in case - CloseHandle( hFile ); FILE* fp = fopen(sNewPath, "r"); if( fp == NULL ) @@ -45,13 +43,13 @@ bool MsdFile::ReadFile( CString sNewPath ) // allocate a string to hold the file char* szFileString = new char[iBufferSize]; - char* szParams[MAX_VALUES][MAX_PARAMS_PER_VALUE]; + ASSERT( szFileString ); int iBytesRead = fread( szFileString, 1, iBufferSize, fp ); - ASSERT( iBufferSize > iBytesRead ); - /* why are we using Windows API calls for simple file access, anyway? XXX -glenn */ - /* What is the C way to get the file size? I don't see 'fstat' in C library... -Chris */ + szFileString[iBytesRead] = '\0'; + + char* szParams[MAX_VALUES][MAX_PARAMS_PER_VALUE]; m_iNumValues = 0; @@ -90,6 +88,7 @@ bool MsdFile::ReadFile( CString sNewPath ) ReadingValue=true; m_iNumValues++; + ASSERT( m_iNumValues < MAX_VALUES ); int iCurValueIndex = m_iNumValues-1; m_iNumParams[iCurValueIndex] = 1; szParams[iCurValueIndex][0] = &szFileString[i+1]; @@ -131,8 +130,6 @@ bool MsdFile::ReadFile( CString sNewPath ) } } - szFileString[i] = '\0'; - for( i=0; i= add.m_fStartBeat ) // these HoldNotes overlap (this isn't entirely correct!) + if( add.m_iTrack == other.m_iTrack && // the tracks correspond + // they overlap + ( + ( other.m_fStartBeat <= add.m_fStartBeat && other.m_fEndBeat >= add.m_fEndBeat ) || // other consumes add + ( other.m_fStartBeat >= add.m_fStartBeat && other.m_fEndBeat <= add.m_fEndBeat ) || // other inside add + ( add.m_fStartBeat <= other.m_fStartBeat && other.m_fStartBeat <= add.m_fEndBeat ) || // other overlaps add + ( add.m_fStartBeat <= other.m_fEndBeat && other.m_fEndBeat <= add.m_fEndBeat ) // other overlaps add + ) + ) { add.m_fStartBeat = min(add.m_fStartBeat, other.m_fStartBeat); add.m_fEndBeat = max(add.m_fEndBeat, other.m_fEndBeat); @@ -854,6 +860,63 @@ void NoteData::LoadTransformed( NoteData* pOriginal, int iNewNumTracks, const in Convert4sToHoldNotes(); } +void NoteData::LoadTransformedSlidingWindow( NoteData* pOriginal, int iNewNumTracks ) +{ + pOriginal->ConvertHoldNotesTo4s(); + m_iNumTracks = iNewNumTracks; + + int iLastRow = pOriginal->GetLastRow(); + for( int r=0; r<=iLastRow; r++ ) + { + int iMeasure = (int)(NoteRowToBeat(r) / BEATS_PER_MEASURE); + + for( int t=0; t<=pOriginal->m_iNumTracks; t++ ) + { + int iOldTrack = t; + int iNewTrack = (iOldTrack + iMeasure/4) % iNewNumTracks; // change sliding window every 4 measures + + if( pOriginal->m_TapNotes[iOldTrack][r] != '0' ) + this->m_TapNotes[iNewTrack][r] = pOriginal->m_TapNotes[iOldTrack][r]; + } + } + + pOriginal->Convert4sToHoldNotes(); + Convert4sToHoldNotes(); +} + +void NoteData::LoadTransformedMirrorOnCross( NoteData* pOriginal, int iNewNumTracks ) +{ + ASSERT( iNewNumTracks == pOriginal->m_iNumTracks*2 ); + + m_iNumTracks = iNewNumTracks; + + pOriginal->ConvertHoldNotesTo4s(); + + bool bMirror = false; + int iMirrorTrack = pOriginal->m_iNumTracks/2-1; + + int iLastRow = pOriginal->GetLastRow(); + for( int r=0; r<=iLastRow; r++ ) + { + for( int t=0; t<=pOriginal->m_iNumTracks; t++ ) + { + int iOldTrack = t; + int iNewTrack = bMirror ? m_iNumTracks - iOldTrack : iOldTrack; + + if( pOriginal->m_TapNotes[iOldTrack][r] != '0' ) + { + this->m_TapNotes[iNewTrack][r] = pOriginal->m_TapNotes[iOldTrack][r]; + + if( iOldTrack == iMirrorTrack ) + bMirror ^= true; + } + } + } + + pOriginal->Convert4sToHoldNotes(); + Convert4sToHoldNotes(); +} + NoteType NoteData::GetSmallestNoteTypeForMeasure( int iMeasureIndex ) { const int iMeasureStartIndex = iMeasureIndex * ROWS_PER_MEASURE; diff --git a/stepmania/src/NoteData.h b/stepmania/src/NoteData.h index 0557fede11..ce9840bfaa 100644 --- a/stepmania/src/NoteData.h +++ b/stepmania/src/NoteData.h @@ -23,7 +23,6 @@ // ... for future expansion - class NoteData { public: @@ -58,6 +57,7 @@ public: // statistics bool IsThereANoteAtRow( int iRow ); + float GetFirstBeat(); // return the beat number of the first note int GetFirstRow(); float GetLastBeat(); // return the beat number of the last note @@ -89,6 +89,9 @@ public: // Transformations void LoadTransformed( NoteData* pOriginal, int iNewNumTracks, const int iOriginalTrackToTakeFrom[] ); // -1 for iOriginalTracksToTakeFrom means no track + void LoadTransformedSlidingWindow( NoteData* pOriginal, int iNewNumTracks ); // useful for autogenerating DDR->Pump, Pump->DDR + void LoadTransformedMirrorOnCross( NoteData* pOriginal, int iNewNumTracks ); // useful for autogenerating double patterns + void CropToLeftSide(); void CropToRightSide(); diff --git a/stepmania/src/ScreenEdit.cpp b/stepmania/src/ScreenEdit.cpp index 52a6d7b65d..2caadfd79e 100644 --- a/stepmania/src/ScreenEdit.cpp +++ b/stepmania/src/ScreenEdit.cpp @@ -903,7 +903,7 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ case DIK_P: { if( m_NoteFieldEdit.m_fBeginMarker == -1 ) - m_NoteFieldEdit.m_fBeginMarker = m_pSong->m_fFirstBeat; + m_NoteFieldEdit.m_fBeginMarker = GAMESTATE->m_fSongBeat; if( m_NoteFieldEdit.m_fEndMarker == -1 ) m_NoteFieldEdit.m_fEndMarker = m_pSong->m_fLastBeat; @@ -924,7 +924,7 @@ void ScreenEdit::InputEdit( const DeviceInput& DeviceI, const InputEventType typ case DIK_R: { if( m_NoteFieldEdit.m_fBeginMarker == -1 ) - m_NoteFieldEdit.m_fBeginMarker = m_pSong->m_fFirstBeat; + m_NoteFieldEdit.m_fBeginMarker = GAMESTATE->m_fSongBeat; if( m_NoteFieldEdit.m_fEndMarker == -1 ) m_NoteFieldEdit.m_fEndMarker = m_pSong->m_fLastBeat; diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index eb8e8ec2fe..0d695c19be 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -33,7 +33,7 @@ #include "NotesLoaderKSF.h" #include "NotesWriterDWI.h" -const int FILE_CACHE_VERSION = 73; // increment this when Song or Notes changes to invalidate cache +const int FILE_CACHE_VERSION = 92; // increment this when Song or Notes changes to invalidate cache int CompareBPMSegments(const void *arg1, const void *arg2) @@ -714,45 +714,50 @@ void Song::SaveToDWIFile() wr.Write(sPath, *this); } -struct AutoGenMapping -{ - NotesType ntMissing; - NotesType ntGenerateFrom; - int iOriginalTrackToTakeFrom[MAX_NOTE_TRACKS]; -}; -const AutoGenMapping AUTO_GEN_MAPPINGS[] = { - { NOTES_TYPE_PUMP_SINGLE, NOTES_TYPE_DANCE_SINGLE, { 0, 1, -1, 2, 3 } }, - { NOTES_TYPE_DANCE_SINGLE, NOTES_TYPE_PUMP_SINGLE, { 0, 1, 3, 4 } }, - { NOTES_TYPE_PUMP_DOUBLE, NOTES_TYPE_DANCE_DOUBLE, { 0, 1, -1, 2, 3, 4, 5, -1, 6, 7 } }, - { NOTES_TYPE_DANCE_DOUBLE, NOTES_TYPE_PUMP_DOUBLE, { 0, 1, 3, 4, 5, 6, 8, 9 } }, -}; -const NUM_AUTOGEN_MAPPINGS = sizeof(AUTO_GEN_MAPPINGS) / sizeof(AutoGenMapping); void Song::AddAutoGenNotes() { - for( int i=0; iNotesTypeToNumTracks(ntMissing); + + // look for closest match + NotesType ntBestMatch = (NotesType)-1; + int iBestTrackDifference = 10000; // inf + + for( NotesType nt=(NotesType)0; ntm_NotesType != mapping.ntGenerateFrom ) - continue; + int iNumTracks = GAMEMAN->NotesTypeToNumTracks(nt); + int iTrackDifference = abs(iNumTracks-iNumTracksOfMissing); + if( SongHasNotesType(nt) && iTrackDifferencem_Difficulty = pOriginalNotes->m_Difficulty; - pNewNotes->m_iMeter = pOriginalNotes->m_iMeter; - pNewNotes->m_sDescription = pOriginalNotes->m_sDescription + " (autogen)"; - pNewNotes->m_NotesType = mapping.ntMissing; + if( ntBestMatch != -1 ) + { + for( int j=0; jm_NotesType != ntBestMatch ) + continue; // skip - NoteData originalNoteData, newNoteData; - pOriginalNotes->GetNoteData( &originalNoteData ); - newNoteData.LoadTransformed( &originalNoteData, GAMEMAN->NotesTypeToNumTracks(mapping.ntMissing), mapping.iOriginalTrackToTakeFrom ); - pNewNotes->SetNoteData( &newNoteData ); - this->m_apNotes.Add( pNewNotes ); + Notes* pNewNotes = new Notes; + pNewNotes->m_Difficulty = pOriginalNotes->m_Difficulty; + pNewNotes->m_iMeter = pOriginalNotes->m_iMeter; + pNewNotes->m_sDescription = pOriginalNotes->m_sDescription + " (autogen)"; + pNewNotes->m_NotesType = ntMissing; + + NoteData originalNoteData, newNoteData; + pOriginalNotes->GetNoteData( &originalNoteData ); + newNoteData.LoadTransformedSlidingWindow( &originalNoteData, iNumTracksOfMissing ); + pNewNotes->SetNoteData( &newNoteData ); + this->m_apNotes.Add( pNewNotes ); + } } } }