2002-09-06 23:24:40 +00:00
# include "stdafx.h"
# include "NotesLoaderDWI.h"
# include "NotesLoader.h"
# include "RageLog.h"
# include "RageException.h"
# include "MsdFile.h"
2002-09-07 11:43:36 +00:00
# include "RageUtil.h"
# include "NoteData.h"
2002-09-06 23:24:40 +00:00
2002-09-07 07:49:15 +00:00
# include <map>
using namespace std ;
2002-09-06 23:24:40 +00:00
void DWILoader : : DWIcharToNote ( char c , GameController i , DanceNote & note1Out , DanceNote & note2Out )
{
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 ,
2002-09-12 08:37:12 +00:00
Notes & out )
2002-09-06 23:24:40 +00:00
{
LOG - > Trace ( " Notes::LoadFromDWITokens() " ) ;
2002-09-07 05:04:04 +00:00
out . m_NotesType = NOTES_TYPE_INVALID ;
2002-09-06 23:24:40 +00:00
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 ;
2002-09-12 08:37:12 +00:00
else if ( sMode = = " COUPLE " ) out . m_NotesType = NOTES_TYPE_DANCE_COUPLE ;
2002-09-06 23:24:40 +00:00
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 ;
}
2002-09-07 07:49:15 +00:00
std : : map < int , int > mapDanceNoteToNoteDataColumn ;
2002-09-06 23:24:40 +00:00
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 :
2002-09-12 08:37:12 +00:00
case NOTES_TYPE_DANCE_COUPLE :
2002-09-06 23:24:40 +00:00
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 ) ;
2002-09-29 05:06:18 +00:00
//m_Difficulty = DifficultyFromDescriptionAndMeter( m_sDescription, m_iMeter );
2002-09-06 23:24:40 +00:00
NoteData * pNoteData = new NoteData ;
ASSERT ( pNoteData ) ;
2002-09-07 07:49:15 +00:00
pNoteData - > m_iNumTracks = mapDanceNoteToNoteDataColumn . size ( ) ;
2002-09-06 23:24:40 +00:00
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 < sStepData . GetLength ( ) ; )
{
char c = sStepData [ i + + ] ;
switch ( c )
{
// begins a series
case ' ( ' :
fCurrentIncrementer = 1.0 / 16 * BEATS_PER_MEASURE ;
break ;
case ' [ ' :
fCurrentIncrementer = 1.0 / 24 * BEATS_PER_MEASURE ;
break ;
case ' { ' :
fCurrentIncrementer = 1.0 / 64 * BEATS_PER_MEASURE ;
break ;
case ' < ' :
fCurrentIncrementer = 1.0 / 192 * BEATS_PER_MEASURE ;
break ;
// ends a series
case ' ) ' :
case ' ] ' :
case ' } ' :
case ' > ' :
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 ) ;
2002-09-07 05:04:04 +00:00
out . SetNoteData ( pNoteData ) ;
delete pNoteData ;
out . TidyUpData ( ) ;
2002-09-06 23:24:40 +00:00
2002-09-07 05:04:04 +00:00
return true ;
}
2002-09-06 23:24:40 +00:00
bool DWILoader : : LoadFromDWIFile ( CString sPath , Song & out )
{
LOG - > Trace ( " Song::LoadFromDWIFile(%s) " , sPath ) ;
MsdFile msd ;
bool bResult = msd . ReadFile ( sPath ) ;
if ( ! bResult )
2002-09-16 00:56:30 +00:00
throw RageException ( " Error opening file '%s' for reading. " , sPath ) ;
2002-09-06 23:24:40 +00:00
for ( int i = 0 ; i < msd . m_iNumValues ; i + + )
{
int iNumParams = msd . m_iNumParams [ i ] ;
2002-09-15 07:03:32 +00:00
CString * sParams = msd . m_sParams [ i ] ;
2002-09-06 23:24:40 +00:00
CString sValueName = sParams [ 0 ] ;
// handle the data
if ( 0 = = stricmp ( sValueName , " FILE " ) )
out . m_sMusicFile = sParams [ 1 ] ;
else if ( 0 = = stricmp ( sValueName , " TITLE " ) )
2002-09-13 18:17:53 +00:00
GetMainAndSubTitlesFromFullTitle ( sParams [ 1 ] , out . m_sMainTitle , out . m_sSubTitle ) ;
2002-09-06 23:24:40 +00:00
else if ( 0 = = stricmp ( sValueName , " ARTIST " ) )
out . m_sArtist = sParams [ 1 ] ;
else if ( 0 = = stricmp ( sValueName , " CDTITLE " ) )
out . m_sCDTitleFile = sParams [ 1 ] ;
else if ( 0 = = stricmp ( sValueName , " BPM " ) )
out . AddBPMSegment ( BPMSegment ( 0 , ( float ) atof ( sParams [ 1 ] ) ) ) ;
else if ( 0 = = stricmp ( sValueName , " GAP " ) )
// the units of GAP is 1/1000 second
out . m_fBeat0OffsetInSeconds = - atoi ( sParams [ 1 ] ) / 1000.0f ;
else if ( 0 = = stricmp ( sValueName , " SAMPLESTART " ) )
2002-09-24 02:55:32 +00:00
out . m_fMusicSampleStartSeconds = TimeToSeconds ( sParams [ 1 ] + " : " + sParams [ 2 ] ) ; // this value has a ':' in it. Colon is supposed to be a parameter separator. Stupid DWI!
2002-09-06 23:24:40 +00:00
else if ( 0 = = stricmp ( sValueName , " SAMPLELENGTH " ) )
2002-09-24 02:55:32 +00:00
out . m_fMusicSampleLengthSeconds = TimeToSeconds ( sParams [ 1 ] + " : " + sParams [ 2 ] ) ;
2002-09-06 23:24:40 +00:00
else if ( 0 = = stricmp ( sValueName , " FREEZE " ) )
{
CStringArray arrayFreezeExpressions ;
split ( sParams [ 1 ] , " , " , arrayFreezeExpressions ) ;
for ( int f = 0 ; f < arrayFreezeExpressions . GetSize ( ) ; f + + )
{
CStringArray arrayFreezeValues ;
split ( arrayFreezeExpressions [ f ] , " = " , arrayFreezeValues ) ;
float fIndex = atoi ( arrayFreezeValues [ 0 ] ) * ROWS_PER_BEAT / 4.0f ;
float fFreezeBeat = NoteRowToBeat ( fIndex ) ;
float fFreezeSeconds = ( float ) atof ( arrayFreezeValues [ 1 ] ) / 1000.0f ;
out . AddStopSegment ( StopSegment ( fFreezeBeat , fFreezeSeconds ) ) ;
LOG - > Trace ( " Adding a freeze segment: beat: %f, seconds = %f " , fFreezeBeat , fFreezeSeconds ) ;
}
}
else if ( 0 = = stricmp ( sValueName , " CHANGEBPM " ) | | 0 = = stricmp ( sValueName , " BPMCHANGE " ) )
{
CStringArray arrayBPMChangeExpressions ;
split ( sParams [ 1 ] , " , " , arrayBPMChangeExpressions ) ;
for ( int b = 0 ; b < arrayBPMChangeExpressions . GetSize ( ) ; b + + )
{
CStringArray arrayBPMChangeValues ;
split ( arrayBPMChangeExpressions [ b ] , " = " , arrayBPMChangeValues ) ;
2002-09-08 22:02:01 +00:00
if ( arrayBPMChangeValues . GetSize ( ) ! = 2 ) {
LOG - > Warn ( " Invalid CHANGEBPM: \" %s \" " , arrayBPMChangeExpressions [ b ] ) ;
continue ;
}
2002-09-06 23:24:40 +00:00
float fIndex = atoi ( arrayBPMChangeValues [ 0 ] ) * ROWS_PER_BEAT / 4.0f ;
float fBeat = NoteRowToBeat ( fIndex ) ;
float fNewBPM = ( float ) atof ( arrayBPMChangeValues [ 1 ] ) ;
out . AddBPMSegment ( BPMSegment ( fBeat , fNewBPM ) ) ;
}
}
else if ( 0 = = stricmp ( sValueName , " SINGLE " ) | |
0 = = stricmp ( sValueName , " DOUBLE " ) | |
0 = = stricmp ( sValueName , " COUPLE " ) | |
0 = = stricmp ( sValueName , " SOLO " ) )
{
Notes * pNewNotes = new Notes ;
LoadFromDWITokens (
sParams [ 0 ] ,
sParams [ 1 ] ,
sParams [ 2 ] ,
sParams [ 3 ] ,
( iNumParams = = 5 ) ? sParams [ 4 ] : " " ,
2002-09-12 08:37:12 +00:00
* pNewNotes
2002-09-06 23:24:40 +00:00
) ;
2002-09-07 05:04:04 +00:00
if ( pNewNotes - > m_NotesType ! = NOTES_TYPE_INVALID )
out . m_apNotes . Add ( pNewNotes ) ;
else
delete pNewNotes ;
2002-09-06 23:24:40 +00:00
}
else
// do nothing. We don't care about this value name
;
}
return true ;
}
2002-09-11 05:15:46 +00:00
void DWILoader : : GetApplicableFiles ( CString sPath , CStringArray & out )
{
GetDirListing ( sPath + CString ( " *.dwi " ) , out ) ;
}
bool DWILoader : : LoadFromDir ( CString sPath , Song & out )
{
CStringArray aFileNames ;
GetApplicableFiles ( sPath , aFileNames ) ;
if ( aFileNames . GetSize ( ) > 1 )
throw RageException ( " There is more than one DWI file in '%s'. There should be only one! " , sPath ) ;
/* We should have exactly one; if we had none, we shouldn't have been
* called to begin with. */
ASSERT ( aFileNames . GetSize ( ) = = 1 ) ;
return LoadFromDWIFile ( sPath + aFileNames [ 0 ] , out ) ;
}