From 3bbfa5baf060919b0b47ba69307b47c6d6a5b5a7 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Fri, 6 Sep 2002 23:24:40 +0000 Subject: [PATCH] Move loaders into their own classes. (These should have a common base class, but that can be done later; I'm doing this to make it a bit more manageable so I can add the new couples format to these.) --- stepmania/src/NotesLoader.h | 21 ++ stepmania/src/NotesLoaderBMS.cpp | 562 +++++++++++++++++++++++++++++++ stepmania/src/NotesLoaderBMS.h | 14 + stepmania/src/NotesLoaderDWI.cpp | 341 +++++++++++++++++++ stepmania/src/NotesLoaderDWI.h | 27 ++ stepmania/src/NotesLoaderKSF.cpp | 250 ++++++++++++++ stepmania/src/NotesLoaderKSF.h | 15 + stepmania/src/NotesLoaderSM.cpp | 209 ++++++++++++ stepmania/src/NotesLoaderSM.h | 22 ++ 9 files changed, 1461 insertions(+) create mode 100644 stepmania/src/NotesLoader.h create mode 100644 stepmania/src/NotesLoaderBMS.cpp create mode 100644 stepmania/src/NotesLoaderBMS.h create mode 100644 stepmania/src/NotesLoaderDWI.cpp create mode 100644 stepmania/src/NotesLoaderDWI.h create mode 100644 stepmania/src/NotesLoaderKSF.cpp create mode 100644 stepmania/src/NotesLoaderKSF.h create mode 100644 stepmania/src/NotesLoaderSM.cpp create mode 100644 stepmania/src/NotesLoaderSM.h diff --git a/stepmania/src/NotesLoader.h b/stepmania/src/NotesLoader.h new file mode 100644 index 0000000000..92997187e5 --- /dev/null +++ b/stepmania/src/NotesLoader.h @@ -0,0 +1,21 @@ +#ifndef NOTES_LOADER_H +#define NOTES_LOADER_H + +typedef int DanceNote; +enum { + DANCE_NOTE_NONE = 0, + DANCE_NOTE_PAD1_LEFT, + DANCE_NOTE_PAD1_UPLEFT, + DANCE_NOTE_PAD1_DOWN, + DANCE_NOTE_PAD1_UP, + DANCE_NOTE_PAD1_UPRIGHT, + DANCE_NOTE_PAD1_RIGHT, + DANCE_NOTE_PAD2_LEFT, + DANCE_NOTE_PAD2_UPLEFT, + DANCE_NOTE_PAD2_DOWN, + DANCE_NOTE_PAD2_UP, + DANCE_NOTE_PAD2_UPRIGHT, + DANCE_NOTE_PAD2_RIGHT +}; + +#endif \ No newline at end of file diff --git a/stepmania/src/NotesLoaderBMS.cpp b/stepmania/src/NotesLoaderBMS.cpp new file mode 100644 index 0000000000..f08acbff79 --- /dev/null +++ b/stepmania/src/NotesLoaderBMS.cpp @@ -0,0 +1,562 @@ +#include "stdafx.h" + +#include "NotesLoaderBMS.h" +#include "NotesLoader.h" +#include "NoteData.h" +#include "GameConstantsAndTypes.h" +#include "RageUtil.h" +#include "RageLog.h" +#include "GameManager.h" +#include "RageException.h" + +// BMS encoding: tap-hold +// 4&8panel: Player1 Player2 +// Left 11-51 21-61 +// Down 13-53 23-63 +// Up 15-55 25-65 +// Right 16-56 26-66 +// 6panel: Player1 +// Left 11-51 +// Left+Up 12-52 +// Down 13-53 +// Up 14-54 +// Up+Right 15-55 +// Right 16-56 +// +// Notice that 15 and 25 have double meanings! What were they thinking??? +// While reading in, use the 6 panel mapping. After reading in, detect if only 4 notes +// are used. If so, shift the Up+Right column back to the Up column +// +void mapBMSTrackToDanceNote( int iBMSTrack, int &iDanceColOut, char &cNoteCharOut ) +{ + if( iBMSTrack > 40 ) + { + cNoteCharOut = '2'; + iBMSTrack -= 40; + } + else + { + cNoteCharOut = '1'; + } + + switch( iBMSTrack ) + { + case 11: iDanceColOut = DANCE_NOTE_PAD1_LEFT; break; + case 12: iDanceColOut = DANCE_NOTE_PAD1_UPLEFT; break; + case 13: iDanceColOut = DANCE_NOTE_PAD1_DOWN; break; + case 14: iDanceColOut = DANCE_NOTE_PAD1_UP; break; + case 15: iDanceColOut = DANCE_NOTE_PAD1_UPRIGHT; break; + case 16: iDanceColOut = DANCE_NOTE_PAD1_RIGHT; break; + case 21: iDanceColOut = DANCE_NOTE_PAD2_LEFT; break; + case 22: iDanceColOut = DANCE_NOTE_PAD2_UPLEFT; break; + case 23: iDanceColOut = DANCE_NOTE_PAD2_DOWN; break; + case 24: iDanceColOut = DANCE_NOTE_PAD2_UP; break; + case 25: iDanceColOut = DANCE_NOTE_PAD2_UPRIGHT; break; + case 26: iDanceColOut = DANCE_NOTE_PAD2_RIGHT; break; + default: iDanceColOut = -1; break; + } +} + + +bool BMSLoader::LoadFromBMSFile( const CString &sPath, Notes &out ) +{ + LOG->Trace( "Notes::LoadFromBMSFile( '%s' )", sPath ); + + NoteData* pNoteData = new NoteData; + pNoteData->m_iNumTracks = MAX_NOTE_TRACKS; + + CStdioFile file; + if( !file.Open( sPath, CFile::modeRead|CFile::shareDenyNone ) ) + { + throw RageException( "Failed to open %s.", sPath ); + return false; + } + + CString line; + while( file.ReadString(line) ) // foreach line + { + CString value_name; // fill these in + CString value_data; + + // BMS value names can be separated by a space or a colon. + int iIndexOfFirstColon = line.Find( ":" ); + int iIndexOfFirstSpace = line.Find( " " ); + + if( iIndexOfFirstColon == -1 ) + iIndexOfFirstColon = 10000; + if( iIndexOfFirstSpace == -1 ) + iIndexOfFirstSpace = 10000; + + int iIndexOfSeparator = min( iIndexOfFirstSpace, iIndexOfFirstColon ); + + if( iIndexOfSeparator != 10000 ) + { + value_name = line.Mid( 0, iIndexOfSeparator ); + value_data = line; // the rest + value_data.Delete(0,iIndexOfSeparator+1); + } + else // no separator + { + value_name = line; + } + + value_name.MakeLower(); + + if( -1 != value_name.Find("#player") ) + { + switch( atoi(value_data) ) + { + case 1: // 4 or 6 single + out.m_NotesType = NOTES_TYPE_DANCE_SINGLE; + // if the mode should be solo, then we'll update m_DanceStyle below when we read in step data + break; + case 2: // couple/battle + out.m_NotesType = NOTES_TYPE_DANCE_COUPLE; + break; + case 3: // double + out.m_NotesType = NOTES_TYPE_DANCE_DOUBLE; + break; + } + } + if( -1 != value_name.Find("#title") ) + { + out.m_sDescription = value_data; + + // extract the Notes description (looks like 'Music ') + int iPosOpenBracket = out.m_sDescription.Find( "<" ); + if( iPosOpenBracket == -1 ) + iPosOpenBracket = out.m_sDescription.Find( "(" ); + int iPosCloseBracket = out.m_sDescription.Find( ">" ); + if( iPosCloseBracket == -1 ) + iPosCloseBracket = out.m_sDescription.Find( ")" ); + + if( iPosOpenBracket != -1 && iPosCloseBracket != -1 ) + out.m_sDescription = out.m_sDescription.Mid( iPosOpenBracket+1, iPosCloseBracket-iPosOpenBracket-1 ); + out.m_sDescription.MakeLower(); + LOG->Trace( "Notes description found to be '%s'", out.m_sDescription ); + + // if there's a 6 in the description, it's probably part of "6panel" or "6-panel" + if( out.m_sDescription.Find("6") != -1 ) + out.m_NotesType = NOTES_TYPE_DANCE_SOLO; + + } + if( -1 != value_name.Find("#playlevel") ) + { + out.m_iMeter = atoi( value_data ); + } + else if( value_name.Left(1) == "#" + && IsAnInt( value_name.Mid(1,3) ) + && IsAnInt( value_name.Mid(4,2) ) ) // this is step or offset data. Looks like "#00705" + { + int iMeasureNo = atoi( value_name.Mid(1,3) ); + int iTrackNum = atoi( value_name.Mid(4,2) ); + + CString &sNoteData = value_data; + CArray arrayNotes; + + for( int i=0; iTrace( "%s:%s: iMeasureNo = %d, iNoteNum = %d, iNumNotesInThisMeasure = %d", + // valuename, sNoteData, iMeasureNo, iNoteNum, iNumNotesInThisMeasure ); + for( int j=0; jm_TapNotes[iColumnNumber][iNoteIndex] = cNoteChar; + } + } + } + } + + if( out.m_NotesType == NOTES_TYPE_DANCE_SINGLE || + out.m_NotesType == NOTES_TYPE_DANCE_DOUBLE || + out.m_NotesType == NOTES_TYPE_DANCE_COUPLE// || + //out.m_NotesType == NOTES_TYPE_DANCE_COUPLE_2 + ) // if there are 4 panels, then the Up+Right track really contains the notes for Up + { + for( int i=0; im_TapNotes[DANCE_NOTE_PAD1_UP], + pNoteData->m_TapNotes[DANCE_NOTE_PAD1_UPRIGHT], + MAX_TAP_NOTE_ROWS*sizeof(pNoteData->m_TapNotes[0][0]) + ); + memcpy( + pNoteData->m_TapNotes[DANCE_NOTE_PAD2_UP], + pNoteData->m_TapNotes[DANCE_NOTE_PAD2_UPRIGHT], + MAX_TAP_NOTE_ROWS*sizeof(pNoteData->m_TapNotes[0][0]) + ); + } + } + + // we're done reading in all of the BMS values + int iNumNewTracks = GameManager::NotesTypeToNumTracks( out.m_NotesType ); + int iTransformNewToOld[MAX_NOTE_TRACKS]; + + switch( out.m_NotesType ) + { + case NOTES_TYPE_DANCE_SINGLE: + case NOTES_TYPE_DANCE_COUPLE: +// case NOTES_TYPE_DANCE_COUPLE_2: + iTransformNewToOld[0] = DANCE_NOTE_PAD1_LEFT; + iTransformNewToOld[1] = DANCE_NOTE_PAD1_DOWN; + iTransformNewToOld[2] = DANCE_NOTE_PAD1_UP; + iTransformNewToOld[3] = DANCE_NOTE_PAD1_RIGHT; + break; + case NOTES_TYPE_DANCE_DOUBLE: + iTransformNewToOld[0] = DANCE_NOTE_PAD1_LEFT; + iTransformNewToOld[1] = DANCE_NOTE_PAD1_DOWN; + iTransformNewToOld[2] = DANCE_NOTE_PAD1_UP; + iTransformNewToOld[3] = DANCE_NOTE_PAD1_RIGHT; + iTransformNewToOld[4] = DANCE_NOTE_PAD2_LEFT; + iTransformNewToOld[5] = DANCE_NOTE_PAD2_DOWN; + iTransformNewToOld[6] = DANCE_NOTE_PAD2_UP; + iTransformNewToOld[7] = DANCE_NOTE_PAD2_RIGHT; + break; + case NOTES_TYPE_DANCE_SOLO: + iTransformNewToOld[0] = DANCE_NOTE_PAD1_LEFT; + iTransformNewToOld[1] = DANCE_NOTE_PAD1_UPLEFT; + iTransformNewToOld[2] = DANCE_NOTE_PAD1_DOWN; + iTransformNewToOld[3] = DANCE_NOTE_PAD1_UP; + iTransformNewToOld[4] = DANCE_NOTE_PAD1_UPRIGHT; + iTransformNewToOld[5] = DANCE_NOTE_PAD1_RIGHT; + break; + default: + throw RageException( "Invalid NotesType." ); + } + + NoteData* pNoteData2 = new NoteData; + pNoteData2->m_iNumTracks = iNumNewTracks; + pNoteData2->LoadTransformed( pNoteData, iNumNewTracks, iTransformNewToOld ); + + out.SetNoteData(pNoteData2); + + delete pNoteData; + delete pNoteData2; + + out.TidyUpData(); + + return true; +} + +bool BMSLoader::LoadFromBMSDir( CString sDir, Song &out ) +{ + LOG->Trace( "Song::LoadFromBMSDir(%s)", sDir ); + + CStringArray arrayBMSFileNames; + GetDirListing( sDir + CString("*.bms"), arrayBMSFileNames ); + + if( arrayBMSFileNames.GetSize() == 0 ) + throw RageException( "Couldn't find any BMS files in '%s'", sDir ); + + // load the Notes from the rest of the BMS files + for( int i=0; i' + int iIndex = value_data.ReverseFind('<'); + if( iIndex == -1 ) + iIndex = value_data.ReverseFind('('); + if( iIndex != -1 ) + { + value_data = value_data.Left( iIndex ); + out.GetMainAndSubTitlesFromFullTitle( value_data, out.m_sMainTitle, out.m_sSubTitle ); + } + else + out.m_sMainTitle = value_data; + } + else if( value_name == "#artist" ) + { + out.m_sArtist = value_data; + } + else if( value_name == "#bpm" ) + { + BPMSegment newSeg( 0, (float)atof(value_data) ); + out.AddBPMSegment( newSeg ); + + LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", newSeg.m_fStartBeat, newSeg.m_fBPM ); + } + else if( value_name == "#backbmp" ) + { + out.m_sBackgroundFile = value_data; + } + else if( value_name == "#wav" ) + { + out.m_sMusicFile = value_data; + } + else if( value_name.Left(1) == "#" + && IsAnInt( value_name.Mid(1,3) ) + && IsAnInt( value_name.Mid(4,2) ) ) // this is step or offset data. Looks like "#00705" + { + int iMeasureNo = atoi( value_name.Mid(1,3) ); + int iBMSTrackNo = atoi( value_name.Mid(4,2) ); + + CString sNoteData = value_data; + CArray arrayNotes; + + for( int i=0; iTrace( "%s:%s: iMeasureNo = %d, iBMSTrackNo = %d, iNumNotesInThisMeasure = %d", + // valuename, sNoteData, iMeasureNo, iBMSTrackNo, iNumNotesInThisMeasure ); + for( int j=0; j 10 ) // some BPMs's play the music again at the end. Why? Who knows... + break; + float fBPS; + fBPS = out.m_BPMSegments[0].m_fBPM/60.0f; + out.m_fBeat0OffsetInSeconds = fBeatOffset / fBPS; + //LOG->Trace( "Found offset to be index %d, beat %f", iStepIndex, NoteRowToBeat(iStepIndex) ); + break; + } + case 3: { // bpm change + BPMSegment newSeg( NoteRowToBeat(iStepIndex), (float)arrayNotes[j] ); + out.AddBPMSegment( newSeg ); + LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", newSeg.m_fStartBeat, newSeg.m_fBPM ); + break; + } + + // Let me just take a moment to express how frustrated I am with the new, + // poorly-designed changes to the BMS format. + // + // + // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahhhhhhhhhhhhhhhhhhhhhhhh!!!!!!!!!!!!!!! + // + // Thank you. + + case 8: { // indirect bpm + // This is a very inefficient way to parse, but it doesn't matter much + // because this is only parsed on the first run after the song is installed. + CString sTagToLookFor = ssprintf( "#BPM%02x", arrayNotes[j] ); + float fBPM = -1; + + + // open the song file again and and look for this tag's value + CStdioFile file; + if( !file.Open( sPath, CFile::modeRead|CFile::shareDenyNone ) ) + { + throw RageException( "Failed to open %s.", sPath ); + return false; + } + + CString line; + while( file.ReadString(line) ) // foreach line + { + CString value_name; // fill these in + CString value_data; + + // BMS value names can be separated by a space or a colon. + int iIndexOfFirstColon = line.Find( ":" ); + int iIndexOfFirstSpace = line.Find( " " ); + + if( iIndexOfFirstColon == -1 ) + iIndexOfFirstColon = 10000; + if( iIndexOfFirstSpace == -1 ) + iIndexOfFirstSpace = 10000; + + int iIndexOfSeparator = min( iIndexOfFirstSpace, iIndexOfFirstColon ); + + if( iIndexOfSeparator != 10000 ) + { + value_name = line.Mid( 0, iIndexOfSeparator ); + value_data = line; // the rest + value_data.Delete(0,iIndexOfSeparator+1); + } + else // no separator + { + value_name = line; + } + + if( 0==stricmp(value_name, sTagToLookFor) ) + { + fBPM = (float)atof( value_data ); + break; + } + } + + if( fBPM == -1 ) // we didn't find the line we were looking for + { + LOG->Trace( "WARNING: Couldn't find tag '%s' in '%s'.", sTagToLookFor, sPath ); + } + else + { + BPMSegment newSeg( NoteRowToBeat(iStepIndex), fBPM ); + out.AddBPMSegment( newSeg ); + LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", newSeg.m_fStartBeat, newSeg.m_fBPM ); + } + + file.Close(); + break; + } + case 9: { // stop + // This is a very inefficient way to parse, but it doesn't + // matter much because this is only parsed on the first run after the song is installed. + CString sTagToLookFor = ssprintf( "#STOP%02x", arrayNotes[j] ); + float fFreezeStartBeat = NoteRowToBeat(iStepIndex); + float fFreezeSecs = -1; + + + // open the song file again and and look for this tag's value + CStdioFile file; + if( !file.Open( sPath, CFile::modeRead|CFile::shareDenyNone ) ) + throw RageException( "Failed to open %s.", sPath ); + + CString line; + while( file.ReadString(line) ) // foreach line + { + CString value_name; // fill these in + CString value_data; + + // BMS value names can be separated by a space or a colon. + int iIndexOfFirstColon = line.Find( ":" ); + int iIndexOfFirstSpace = line.Find( " " ); + + if( iIndexOfFirstColon == -1 ) + iIndexOfFirstColon = 10000; + if( iIndexOfFirstSpace == -1 ) + iIndexOfFirstSpace = 10000; + + int iIndexOfSeparator = min( iIndexOfFirstSpace, iIndexOfFirstColon ); + + if( iIndexOfSeparator != 10000 ) + { + value_name = line.Mid( 0, iIndexOfSeparator ); + value_data = line; // the rest + value_data.Delete(0,iIndexOfSeparator+1); + } + else // no separator + { + value_name = line; + } + + if( 0==stricmp(value_name, sTagToLookFor) ) + { + // find the BPM at the time of this freeze + float fBPM = -1; + for( int i=0; i fFreezeStartBeat ) + { + fBPM = out.m_BPMSegments[i].m_fBPM; + break; + } + } + // the BPM segment of this beat is the last BPM segment + if( fBPM == -1 ) + fBPM = out.m_BPMSegments[out.m_BPMSegments.GetSize()-1].m_fBPM; + + fFreezeSecs = (float)atof(value_data)/(fBPM*0.81f); // I have no idea what units these are in, so I experimented until finding this factor. + break; + } + } + + if( fFreezeSecs == -1 ) // we didn't find the line we were looking for + { + LOG->Trace( "WARNING: Couldn't find tag '%s' in '%s'.", sTagToLookFor, sPath ); + } + else + { + StopSegment newSeg( fFreezeStartBeat, fFreezeSecs ); + out.AddStopSegment( newSeg ); + LOG->Trace( "Inserting new Freeze at beat %f, secs %f", newSeg.m_fStartBeat, newSeg.m_fStopSeconds ); + } + + file.Close(); + break; + } + } + } + } + } + + for( i=0; iTrace( "There is a BPM change at beat %f, BPM %f, index %d", + out.m_BPMSegments[i].m_fStartBeat, out.m_BPMSegments[i].m_fBPM, i ); + + file.Close(); + + return TRUE; +} + diff --git a/stepmania/src/NotesLoaderBMS.h b/stepmania/src/NotesLoaderBMS.h new file mode 100644 index 0000000000..82e46f1b5f --- /dev/null +++ b/stepmania/src/NotesLoaderBMS.h @@ -0,0 +1,14 @@ +#ifndef NOTES_LOADER_BMS_H +#define NOTES_LOADER_BMS_H + +#include "Song.h" +#include "Notes.h" + +class BMSLoader { + bool LoadFromBMSFile( const CString &sPath, Notes &out ); + +public: + bool LoadFromBMSDir( CString sDir, Song &out ); +}; + +#endif diff --git a/stepmania/src/NotesLoaderDWI.cpp b/stepmania/src/NotesLoaderDWI.cpp new file mode 100644 index 0000000000..03bf9d711a --- /dev/null +++ b/stepmania/src/NotesLoaderDWI.cpp @@ -0,0 +1,341 @@ +#include "stdafx.h" + +#include "NotesLoaderDWI.h" +#include "NotesLoader.h" +#include "RageLog.h" +#include "RageException.h" +#include "MsdFile.h" + +void DWILoader::DWIcharToNote( char c, GameController i, DanceNote ¬e1Out, DanceNote ¬e2Out ) +{ + switch( c ) + { + case '0': note1Out = DANCE_NOTE_NONE; note2Out = DANCE_NOTE_NONE; break; + case '1': note1Out = DANCE_NOTE_PAD1_DOWN; note2Out = DANCE_NOTE_PAD1_LEFT; break; + case '2': note1Out = DANCE_NOTE_PAD1_DOWN; note2Out = DANCE_NOTE_NONE; break; + case '3': note1Out = DANCE_NOTE_PAD1_DOWN; note2Out = DANCE_NOTE_PAD1_RIGHT; break; + case '4': note1Out = DANCE_NOTE_PAD1_LEFT; note2Out = DANCE_NOTE_NONE; break; + case '5': note1Out = DANCE_NOTE_NONE; note2Out = DANCE_NOTE_NONE; break; + case '6': note1Out = DANCE_NOTE_PAD1_RIGHT; note2Out = DANCE_NOTE_NONE; break; + case '7': note1Out = DANCE_NOTE_PAD1_UP; note2Out = DANCE_NOTE_PAD1_LEFT; break; + case '8': note1Out = DANCE_NOTE_PAD1_UP; note2Out = DANCE_NOTE_NONE; break; + case '9': note1Out = DANCE_NOTE_PAD1_UP; note2Out = DANCE_NOTE_PAD1_RIGHT; break; + case 'A': note1Out = DANCE_NOTE_PAD1_UP; note2Out = DANCE_NOTE_PAD1_DOWN; break; + case 'B': note1Out = DANCE_NOTE_PAD1_LEFT; note2Out = DANCE_NOTE_PAD1_RIGHT; break; + case 'C': note1Out = DANCE_NOTE_PAD1_UPLEFT; note2Out = DANCE_NOTE_NONE; break; + case 'D': note1Out = DANCE_NOTE_PAD1_UPRIGHT; note2Out = DANCE_NOTE_NONE; break; + case 'E': note1Out = DANCE_NOTE_PAD1_LEFT; note2Out = DANCE_NOTE_PAD1_UPLEFT; break; + case 'F': note1Out = DANCE_NOTE_PAD1_UPLEFT; note2Out = DANCE_NOTE_PAD1_DOWN; break; + case 'G': note1Out = DANCE_NOTE_PAD1_UPLEFT; note2Out = DANCE_NOTE_PAD1_UP; break; + case 'H': note1Out = DANCE_NOTE_PAD1_UPLEFT; note2Out = DANCE_NOTE_PAD1_RIGHT; break; + case 'I': note1Out = DANCE_NOTE_PAD1_LEFT; note2Out = DANCE_NOTE_PAD1_UPRIGHT; break; + case 'J': note1Out = DANCE_NOTE_PAD1_DOWN; note2Out = DANCE_NOTE_PAD1_UPRIGHT; break; + case 'K': note1Out = DANCE_NOTE_PAD1_UP; note2Out = DANCE_NOTE_PAD1_UPRIGHT; break; + case 'L': note1Out = DANCE_NOTE_PAD1_UPRIGHT; note2Out = DANCE_NOTE_PAD1_RIGHT; break; + case 'M': note1Out = DANCE_NOTE_PAD1_UPLEFT; note2Out = DANCE_NOTE_PAD1_UPRIGHT; break; + default: + LOG->Warn( "Encountered invalid DWI note characer '%c'", c ); + note1Out = DANCE_NOTE_NONE; note2Out = DANCE_NOTE_NONE; break; + } + + switch( i ) + { + case GAME_CONTROLLER_1: + break; + case GAME_CONTROLLER_2: + if( note1Out != DANCE_NOTE_NONE ) + note1Out += 6; + if( note2Out != DANCE_NOTE_NONE ) + note2Out += 6; + break; + default: + ASSERT( false ); + } +} + + + +bool DWILoader::LoadFromDWITokens( + CString sMode, + CString sDescription, + CString sNumFeet, + CString sStepData1, + CString sStepData2, + Notes &out) +{ + LOG->Trace( "Notes::LoadFromDWITokens()" ); + + sStepData1.Replace( "\n", "" ); + sStepData1.Replace( " ", "" ); + sStepData2.Replace( "\n", "" ); + sStepData2.Replace( " ", "" ); + + if( sMode == "SINGLE" ) out.m_NotesType = NOTES_TYPE_DANCE_SINGLE; + else if( sMode == "DOUBLE" ) out.m_NotesType = NOTES_TYPE_DANCE_DOUBLE; + else if( sMode == "COUPLE" ) out.m_NotesType = NOTES_TYPE_DANCE_COUPLE; + else if( sMode == "SOLO" ) out.m_NotesType = NOTES_TYPE_DANCE_SOLO; + else + { + ASSERT(0); // Unrecognized DWI notes format + out.m_NotesType = NOTES_TYPE_DANCE_SINGLE; + } + + + CMap mapDanceNoteToNoteDataColumn; + switch( out.m_NotesType ) + { + case NOTES_TYPE_DANCE_SINGLE: + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3; + break; + case NOTES_TYPE_DANCE_DOUBLE: + case NOTES_TYPE_DANCE_COUPLE: + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_LEFT] = 4; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_DOWN] = 5; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_UP] = 6; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_RIGHT] = 7; + break; + case NOTES_TYPE_DANCE_SOLO: + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPLEFT] = 1; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 2; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 3; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPRIGHT] = 4; + mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 5; + break; + default: + ASSERT(0); + } + + out.m_sDescription = sDescription; + + out.m_iMeter = atoi( sNumFeet ); + + //m_DifficultyClass = DifficultyClassFromDescriptionAndMeter( m_sDescription, m_iMeter ); + + NoteData* pNoteData = new NoteData; + ASSERT( pNoteData ); + pNoteData->m_iNumTracks = mapDanceNoteToNoteDataColumn.GetCount(); + + for( int pad=0; pad<2; pad++ ) // foreach pad + { + CString sStepData; + switch( pad ) + { + case 0: + sStepData = sStepData1; + break; + case 1: + if( sStepData2 == "" ) // no data + continue; // skip + sStepData = sStepData2; + break; + default: + ASSERT( false ); + } + + double fCurrentBeat = 0; + double fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; + + for( int i=0; i': + fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; + break; + + case ' ': + break; // do nothing! + + case '!': // hold start + { + // rewind and get the last step we inserted + double fLastStepBeat = fCurrentBeat - fCurrentIncrementer; + int iIndex = BeatToNoteRow( (float)fLastStepBeat ); + + char holdChar = sStepData[i++]; + + DanceNote note1, note2; + DWIcharToNote( holdChar, (GameController)pad, note1, note2 ); + + if( note1 != DANCE_NOTE_NONE ) + { + int iCol1 = mapDanceNoteToNoteDataColumn[note1]; + pNoteData->m_TapNotes[iCol1][iIndex] = '2'; + } + if( note2 != DANCE_NOTE_NONE ) + { + int iCol2 = mapDanceNoteToNoteDataColumn[note2]; + pNoteData->m_TapNotes[iCol2][iIndex] = '2'; + } + } + break; + default: // this is a note character + { + int iIndex = BeatToNoteRow( (float)fCurrentBeat ); + + DanceNote note1, note2; + DWIcharToNote( c, (GameController)pad, note1, note2 ); + + if( note1 != DANCE_NOTE_NONE ) + { + int iCol1 = mapDanceNoteToNoteDataColumn[note1]; + pNoteData->m_TapNotes[iCol1][iIndex] = '1'; + } + if( note2 != DANCE_NOTE_NONE ) + { + int iCol2 = mapDanceNoteToNoteDataColumn[note2]; + pNoteData->m_TapNotes[iCol2][iIndex] = '1'; + } + + fCurrentBeat += fCurrentIncrementer; + } + break; + } + } + } + + // this will expand the HoldNote begin markers we wrote into actual HoldNotes + pNoteData->Convert2sAnd3sToHoldNotes(); + + ASSERT( pNoteData->m_iNumTracks > 0 ); + + out.m_sSMNoteData = pNoteData->GetSMNoteDataString(); + + delete pNoteData; + + out.TidyUpData(); + + return true; +} + + + + +bool DWILoader::LoadFromDWIFile( CString sPath, Song &out ) +{ + LOG->Trace( "Song::LoadFromDWIFile(%s)", sPath ); + + + MsdFile msd; + bool bResult = msd.ReadFile( sPath ); + if( !bResult ) + throw RageException( "Error opening file '%s'.", sPath ); + + for( int i=0; iTrace( "Notes::LoadFromKSFFile( '%s' )", sPath ); + + MsdFile msd; + bool bResult = msd.ReadFile( sPath ); + if( !bResult ) + throw RageException( "Error opening file '%s'.", sPath ); + + int iTickCount = -1; // this is the value we read for TICKCOUNT + CString iStep; // this is the value we read for STEP + + for( int i=0; iWarn( "%s:\nTICKCOUNT not found; defaulting to %i", sPath, iTickCount ); + } + + NoteData notedata; // read it into here + + CStringArray asRows; + iStep.TrimLeft(); + split( iStep, "\n", asRows, true ); + + int iHoldStartRow[13]; + for( int t=0; t<13; t++ ) + iHoldStartRow[t] = -1; + + for( int r=0; rTrace( "Song::LoadFromKSFDir(%s)", sDir ); + + CStringArray arrayKSFFileNames; + GetDirListing( sDir + CString("*.ksf"), arrayKSFFileNames ); + + if( arrayKSFFileNames.GetSize() == 0 ) + throw RageException( "Couldn't find any KSF files in '%s'", sDir ); + + // load the Notes from the rest of the KSF files + for( int i=0; iTrace( "Unexpected value named '%s'", sValueName ); + } + + // search for music with song in the file name + CStringArray arrayPossibleMusic; + GetDirListing( out.m_sSongDir + CString("song.mp3"), arrayPossibleMusic ); + GetDirListing( out.m_sSongDir + CString("song.ogg"), arrayPossibleMusic ); + GetDirListing( out.m_sSongDir + CString("song.wav"), arrayPossibleMusic ); + + if( arrayPossibleMusic.GetSize() > 0 ) // we found a match + out.m_sMusicFile = arrayPossibleMusic[0]; + + return TRUE; +} + + diff --git a/stepmania/src/NotesLoaderKSF.h b/stepmania/src/NotesLoaderKSF.h new file mode 100644 index 0000000000..81e4927bfb --- /dev/null +++ b/stepmania/src/NotesLoaderKSF.h @@ -0,0 +1,15 @@ +#ifndef NOTES_LOADER_KSF_H +#define NOTES_LOADER_KSF_H + +#include "Song.h" +#include "Notes.h" + +class KSFLoader { + bool LoadFromKSFFile( const CString &sPath, Notes &out ); + +public: + bool LoadFromKSFDir( CString sDir, Song &out ); + +}; + +#endif diff --git a/stepmania/src/NotesLoaderSM.cpp b/stepmania/src/NotesLoaderSM.cpp new file mode 100644 index 0000000000..90799b6854 --- /dev/null +++ b/stepmania/src/NotesLoaderSM.cpp @@ -0,0 +1,209 @@ +#include "stdafx.h" + +#include "NotesLoaderSM.h" +#include "GameManager.h" +#include "RageException.h" +#include "MsdFile.h" +#include "RageLog.h" + +void SMLoader::LoadFromSMTokens( + CString sNotesType, + CString sDescription, + CString sDifficultyClass, + CString sMeter, + CString sRadarValues, + CString sNoteData, + Notes &out +) +{ + sNotesType.TrimLeft(); + sNotesType.TrimRight(); + sDescription.TrimLeft(); + sDescription.TrimRight(); + sDifficultyClass.TrimLeft(); + sDifficultyClass.TrimRight(); + + +// LOG->Trace( "Notes::LoadFromSMTokens()" ); + + out.m_NotesType = GameManager::StringToNotesType(sNotesType); + out.m_sDescription = sDescription; + out.m_DifficultyClass = StringToDifficultyClass( sDifficultyClass ); + out.m_iMeter = atoi(sMeter); + CStringArray saValues; + split( sRadarValues, ",", saValues, true ); + if( saValues.GetSize() == NUM_RADAR_VALUES ) + for( int r=0; rTrace( "Song::LoadFromSMDir(%s)", sPath ); + + out.m_BPMSegments.RemoveAll(); + out.m_StopSegments.RemoveAll(); + + int i; + + MsdFile msd; + bool bResult = msd.ReadFile( sPath ); + if( !bResult ) + throw RageException( "Error opening file '%s'.", sPath ); + + for( i=0; iWarn( "The song file '%s' has an unknown #SELECTABLE value, \"%s\"; ignored.", sPath, sParams[1]); + } + + else if( 0==stricmp(sValueName,"STOPS") || 0==stricmp(sValueName,"FREEZES") ) + { + CStringArray arrayFreezeExpressions; + split( sParams[1], ",", arrayFreezeExpressions ); + + for( int f=0; fTrace( "Unexpected value named '%s'", sValueName ); + } + + return true; +} diff --git a/stepmania/src/NotesLoaderSM.h b/stepmania/src/NotesLoaderSM.h new file mode 100644 index 0000000000..c5eae2ddea --- /dev/null +++ b/stepmania/src/NotesLoaderSM.h @@ -0,0 +1,22 @@ +#ifndef NOTES_LOADER_SM_H +#define NOTES_LOADER_SM_H + +#include "Song.h" +#include "Notes.h" + +class SMLoader { + void LoadFromSMTokens( + CString sNotesType, + CString sDescription, + CString sDifficultyClass, + CString sMeter, + CString sRadarValues, + CString sNoteData, + Notes &out); + +public: + bool LoadFromSMFile( CString sPath, Song &out ); + +}; + +#endif