2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2002-09-06 23:24:40 +00:00
|
|
|
#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"
|
2003-06-30 08:40:10 +00:00
|
|
|
#include "RageUtil_CharConversions.h"
|
2002-09-07 11:43:36 +00:00
|
|
|
#include "NoteData.h"
|
2004-05-31 21:55:14 +00:00
|
|
|
#include "song.h"
|
|
|
|
|
#include "Steps.h"
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2002-09-07 07:49:15 +00:00
|
|
|
#include <map>
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
static std::map<int,int> g_mapDanceNoteToNoteDataColumn;
|
|
|
|
|
|
2004-05-31 22:07:09 +00:00
|
|
|
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
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void DWILoader::DWIcharToNote( char c, GameController i, int ¬e1Out, int ¬e2Out )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
|
|
|
|
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:
|
2003-07-15 19:55:06 +00:00
|
|
|
LOG->Warn( "Encountered invalid DWI note character '%c' in '%s'", c, m_sLoadingFile.c_str() );
|
2002-09-06 23:24:40 +00:00
|
|
|
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 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
void DWILoader::DWIcharToNoteCol( char c, GameController i, int &col1Out, int &col2Out )
|
|
|
|
|
{
|
2004-05-31 22:07:09 +00:00
|
|
|
int note1, note2;
|
2003-07-02 01:52:06 +00:00
|
|
|
DWIcharToNote( c, i, note1, note2 );
|
|
|
|
|
|
|
|
|
|
if( note1 != DANCE_NOTE_NONE )
|
|
|
|
|
col1Out = g_mapDanceNoteToNoteDataColumn[note1];
|
|
|
|
|
else
|
|
|
|
|
col1Out = -1;
|
|
|
|
|
|
|
|
|
|
if( note2 != DANCE_NOTE_NONE )
|
|
|
|
|
col2Out = g_mapDanceNoteToNoteDataColumn[note2];
|
|
|
|
|
else
|
|
|
|
|
col2Out = -1;
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
/* Ack. DWI used to use <...> to indicate 1/192nd notes; at some
|
|
|
|
|
* point, <...> was changed to indicate jumps, and `' was used for
|
|
|
|
|
* 1/192nds. So, we have to do a check to figure out what it really
|
|
|
|
|
* means. If it contains 0s, it's most likely 192nds; otherwise,
|
|
|
|
|
* it's most likely a jump. Search for a 0 before the next >: */
|
2006-01-22 01:00:06 +00:00
|
|
|
bool DWILoader::Is192( const RString &sStepData, size_t pos )
|
2003-07-02 01:52:06 +00:00
|
|
|
{
|
2005-12-23 09:51:09 +00:00
|
|
|
while( pos < sStepData.size() )
|
2003-07-02 01:52:06 +00:00
|
|
|
{
|
|
|
|
|
if( sStepData[pos] == '>' )
|
|
|
|
|
return false;
|
|
|
|
|
if( sStepData[pos] == '0' )
|
|
|
|
|
return true;
|
|
|
|
|
++pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
bool DWILoader::LoadFromDWITokens(
|
2006-01-22 01:00:06 +00:00
|
|
|
RString sMode,
|
|
|
|
|
RString sDescription,
|
|
|
|
|
RString sNumFeet,
|
|
|
|
|
RString sStepData1,
|
|
|
|
|
RString sStepData2,
|
2003-08-03 00:13:55 +00:00
|
|
|
Steps &out)
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2003-10-04 00:44:19 +00:00
|
|
|
CHECKPOINT_M( "DWILoader::LoadFromDWITokens()" );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-08-07 06:36:34 +00:00
|
|
|
out.m_StepsType = STEPS_TYPE_INVALID;
|
2002-09-07 05:04:04 +00:00
|
|
|
|
2003-08-07 06:36:34 +00:00
|
|
|
if( sMode == "SINGLE" ) out.m_StepsType = STEPS_TYPE_DANCE_SINGLE;
|
|
|
|
|
else if( sMode == "DOUBLE" ) out.m_StepsType = STEPS_TYPE_DANCE_DOUBLE;
|
|
|
|
|
else if( sMode == "COUPLE" ) out.m_StepsType = STEPS_TYPE_DANCE_COUPLE;
|
|
|
|
|
else if( sMode == "SOLO" ) out.m_StepsType = STEPS_TYPE_DANCE_SOLO;
|
2002-09-06 23:24:40 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ASSERT(0); // Unrecognized DWI notes format
|
2003-08-07 06:36:34 +00:00
|
|
|
out.m_StepsType = STEPS_TYPE_DANCE_SINGLE;
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
g_mapDanceNoteToNoteDataColumn.clear();
|
2003-08-07 06:36:34 +00:00
|
|
|
switch( out.m_StepsType )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2003-08-07 06:16:17 +00:00
|
|
|
case STEPS_TYPE_DANCE_SINGLE:
|
2003-07-02 01:52:06 +00:00
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3;
|
2002-09-06 23:24:40 +00:00
|
|
|
break;
|
2003-08-07 06:16:17 +00:00
|
|
|
case STEPS_TYPE_DANCE_DOUBLE:
|
|
|
|
|
case STEPS_TYPE_DANCE_COUPLE:
|
2003-07-02 01:52:06 +00:00
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_LEFT] = 4;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_DOWN] = 5;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_UP] = 6;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_RIGHT] = 7;
|
2002-09-06 23:24:40 +00:00
|
|
|
break;
|
2003-08-07 06:16:17 +00:00
|
|
|
case STEPS_TYPE_DANCE_SOLO:
|
2003-07-02 01:52:06 +00:00
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPLEFT] = 1;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 2;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 3;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPRIGHT] = 4;
|
|
|
|
|
g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 5;
|
2002-09-06 23:24:40 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ASSERT(0);
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-21 22:23:01 +00:00
|
|
|
int iNumFeet = atoi(sNumFeet);
|
2004-03-29 21:08:59 +00:00
|
|
|
// out.SetDescription(sDescription); // Don't put garbage in the description.
|
2003-01-21 22:23:01 +00:00
|
|
|
out.SetMeter(iNumFeet);
|
2004-03-29 21:08:59 +00:00
|
|
|
out.SetDifficulty( StringToDifficulty(sDescription) );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-12-03 00:00:30 +00:00
|
|
|
NoteData newNoteData;
|
|
|
|
|
newNoteData.SetNumTracks( g_mapDanceNoteToNoteDataColumn.size() );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
for( int pad=0; pad<2; pad++ ) // foreach pad
|
|
|
|
|
{
|
2006-01-22 01:00:06 +00:00
|
|
|
RString sStepData;
|
2002-09-06 23:24:40 +00:00
|
|
|
switch( pad )
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sStepData = sStepData1;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
if( sStepData2 == "" ) // no data
|
|
|
|
|
continue; // skip
|
|
|
|
|
sStepData = sStepData2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ASSERT( false );
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-03 01:47:03 +00:00
|
|
|
sStepData.Replace("\n", "");
|
|
|
|
|
sStepData.Replace("\r", "");
|
2003-01-27 01:58:24 +00:00
|
|
|
sStepData.Replace("\t", "");
|
2003-07-02 01:52:06 +00:00
|
|
|
sStepData.Replace(" ", "");
|
2003-01-27 01:58:24 +00:00
|
|
|
|
2002-09-06 23:24:40 +00:00
|
|
|
double fCurrentBeat = 0;
|
|
|
|
|
double fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE;
|
|
|
|
|
|
2005-12-21 07:50:14 +00:00
|
|
|
for( size_t i=0; i<sStepData.size(); )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
|
|
|
|
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;
|
2003-07-02 01:52:06 +00:00
|
|
|
case '`':
|
2002-09-06 23:24:40 +00:00
|
|
|
fCurrentIncrementer = 1.0/192 * BEATS_PER_MEASURE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// ends a series
|
|
|
|
|
case ')':
|
|
|
|
|
case ']':
|
|
|
|
|
case '}':
|
2003-07-02 01:52:06 +00:00
|
|
|
case '\'':
|
2002-09-06 23:24:40 +00:00
|
|
|
case '>':
|
|
|
|
|
fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE;
|
|
|
|
|
break;
|
|
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
default: // this is a note character
|
|
|
|
|
{
|
|
|
|
|
if( c == '!' )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2003-07-15 19:55:06 +00:00
|
|
|
LOG->Warn( "Unexpected character in '%s': '!'", m_sLoadingFile.c_str() );
|
2003-07-02 01:52:06 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
bool jump = false;
|
|
|
|
|
if( c == '<' )
|
|
|
|
|
{
|
|
|
|
|
/* Arr. Is this a jump or a 1/192 marker? */
|
|
|
|
|
if( Is192( sStepData, i ) )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2003-07-02 01:52:06 +00:00
|
|
|
fCurrentIncrementer = 1.0/192 * BEATS_PER_MEASURE;
|
|
|
|
|
break;
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
2003-07-02 01:52:06 +00:00
|
|
|
|
|
|
|
|
/* It's a jump. We need to keep reading notes until we hit a >. */
|
|
|
|
|
jump = true;
|
|
|
|
|
i++;
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
2003-07-02 01:52:06 +00:00
|
|
|
|
|
|
|
|
const int iIndex = BeatToNoteRow( (float)fCurrentBeat );
|
|
|
|
|
i--;
|
|
|
|
|
do {
|
|
|
|
|
c = sStepData[i++];
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
if( jump && c == '>' )
|
|
|
|
|
break;
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
int iCol1, iCol2;
|
|
|
|
|
DWIcharToNoteCol( c, (GameController)pad, iCol1, iCol2 );
|
|
|
|
|
|
|
|
|
|
if( iCol1 != -1 )
|
2004-09-12 05:56:24 +00:00
|
|
|
newNoteData.SetTapNote(iCol1, iIndex, TAP_ORIGINAL_TAP);
|
2003-07-02 01:52:06 +00:00
|
|
|
if( iCol2 != -1 )
|
2004-09-12 05:56:24 +00:00
|
|
|
newNoteData.SetTapNote(iCol2, iIndex, TAP_ORIGINAL_TAP);
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-07-02 01:52:06 +00:00
|
|
|
if( sStepData[i] == '!' )
|
|
|
|
|
{
|
|
|
|
|
i++;
|
|
|
|
|
const char holdChar = sStepData[i++];
|
|
|
|
|
|
|
|
|
|
DWIcharToNoteCol( holdChar, (GameController)pad, iCol1, iCol2 );
|
|
|
|
|
|
|
|
|
|
if( iCol1 != -1 )
|
2004-09-12 05:56:24 +00:00
|
|
|
newNoteData.SetTapNote(iCol1, iIndex, TAP_ORIGINAL_HOLD_HEAD);
|
2003-07-02 01:52:06 +00:00
|
|
|
if( iCol2 != -1 )
|
2004-09-12 05:56:24 +00:00
|
|
|
newNoteData.SetTapNote(iCol2, iIndex, TAP_ORIGINAL_HOLD_HEAD);
|
2003-07-02 01:52:06 +00:00
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
2003-07-02 01:52:06 +00:00
|
|
|
while( jump );
|
|
|
|
|
fCurrentBeat += fCurrentIncrementer;
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
2003-07-02 01:52:06 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-25 05:02:35 +00:00
|
|
|
/* Fill in iDuration. */
|
|
|
|
|
for( int t=0; t<newNoteData.GetNumTracks(); ++t )
|
|
|
|
|
{
|
|
|
|
|
FOREACH_NONEMPTY_ROW_IN_TRACK( newNoteData, t, iHeadRow )
|
|
|
|
|
{
|
|
|
|
|
TapNote tn = newNoteData.GetTapNote( t, iHeadRow );
|
|
|
|
|
if( tn.type != TapNote::hold_head )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
int iTailRow = iHeadRow;
|
2005-02-12 08:18:31 +00:00
|
|
|
bool bFound = false;
|
|
|
|
|
while( !bFound && newNoteData.GetNextTapNoteRowForTrack(t, iTailRow) )
|
2005-01-25 05:02:35 +00:00
|
|
|
{
|
|
|
|
|
const TapNote &TailTap = newNoteData.GetTapNote( t, iTailRow );
|
|
|
|
|
if( TailTap.type == TapNote::empty )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
newNoteData.SetTapNote( t, iTailRow, TAP_EMPTY );
|
|
|
|
|
tn.iDuration = iTailRow - iHeadRow;
|
|
|
|
|
newNoteData.SetTapNote( t, iHeadRow, tn );
|
2005-02-12 08:18:31 +00:00
|
|
|
bFound = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !bFound )
|
|
|
|
|
{
|
|
|
|
|
/* The hold was never closed. */
|
|
|
|
|
LOG->Warn( "File \"%s\":\"%s\" failed to close a hold note on track %i",
|
|
|
|
|
m_sLoadingFile.c_str(),
|
|
|
|
|
sDescription.c_str(),
|
|
|
|
|
t );
|
|
|
|
|
|
|
|
|
|
newNoteData.SetTapNote( t, iHeadRow, TAP_EMPTY );
|
2005-01-25 05:02:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-12-03 00:00:30 +00:00
|
|
|
ASSERT( newNoteData.GetNumTracks() > 0 );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2004-10-23 17:43:49 +00:00
|
|
|
out.SetNoteData( newNoteData );
|
2002-09-07 05:04:04 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
|
2005-01-25 05:02:35 +00:00
|
|
|
/* This value can be in either "HH:MM:SS.sssss", "MM:SS.sssss", "SSS.sssss"
|
|
|
|
|
* or milliseconds. */
|
2006-01-22 01:00:06 +00:00
|
|
|
float DWILoader::ParseBrokenDWITimestamp(const RString &arg1, const RString &arg2, const RString &arg3)
|
2002-12-27 21:39:25 +00:00
|
|
|
{
|
2003-01-14 22:44:30 +00:00
|
|
|
if(arg1.empty()) return 0;
|
|
|
|
|
|
|
|
|
|
/* 1+ args */
|
|
|
|
|
if(arg2.empty())
|
|
|
|
|
{
|
|
|
|
|
/* If the value contains a period, treat it as seconds; otherwise ms. */
|
|
|
|
|
if(arg1.find_first_of(".") != arg1.npos)
|
2004-08-10 20:57:59 +00:00
|
|
|
return strtof( arg1, NULL );
|
2003-01-14 22:44:30 +00:00
|
|
|
else
|
2004-08-10 20:57:59 +00:00
|
|
|
return strtof( arg1, NULL ) / 1000.f;
|
2003-01-14 22:44:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 2+ args */
|
|
|
|
|
if(arg3.empty())
|
2004-02-22 19:51:46 +00:00
|
|
|
return HHMMSSToSeconds( arg1+":"+arg2 );
|
2003-01-14 22:44:30 +00:00
|
|
|
|
|
|
|
|
/* 3+ args */
|
2004-02-22 19:51:46 +00:00
|
|
|
return HHMMSSToSeconds( arg1+":"+arg2+":"+arg3 );
|
2002-12-27 21:39:25 +00:00
|
|
|
}
|
|
|
|
|
|
2006-02-02 23:52:28 +00:00
|
|
|
bool DWILoader::LoadFromDWIFile( const RString &sPath, Song &out )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2003-04-25 00:01:35 +00:00
|
|
|
LOG->Trace( "Song::LoadFromDWIFile(%s)", sPath.c_str() );
|
2003-07-15 19:55:06 +00:00
|
|
|
m_sLoadingFile = sPath;
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
MsdFile msd;
|
2004-07-12 23:47:39 +00:00
|
|
|
if( !msd.ReadFile( sPath ) )
|
|
|
|
|
RageException::Throw( "Error opening file \"%s\": %s", sPath.c_str(), msd.GetError().c_str() );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-01-14 22:10:04 +00:00
|
|
|
for( unsigned i=0; i<msd.GetNumValues(); i++ )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2003-01-14 22:44:30 +00:00
|
|
|
int iNumParams = msd.GetNumParams(i);
|
|
|
|
|
const MsdFile::value_t &sParams = msd.GetValue(i);
|
2006-01-22 01:00:06 +00:00
|
|
|
RString sValueName = sParams[0];
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2002-12-27 21:39:25 +00:00
|
|
|
if(iNumParams < 1)
|
|
|
|
|
{
|
2003-07-15 19:55:06 +00:00
|
|
|
LOG->Warn("Got \"%s\" tag with no parameters in '%s'", sValueName.c_str(), m_sLoadingFile.c_str() );
|
2002-12-27 21:39:25 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-06 23:24:40 +00:00
|
|
|
// handle the data
|
|
|
|
|
if( 0==stricmp(sValueName,"FILE") )
|
|
|
|
|
out.m_sMusicFile = sParams[1];
|
|
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"TITLE") )
|
2003-06-30 08:40:10 +00:00
|
|
|
{
|
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
|
|
|
|
2003-06-30 08:40:10 +00:00
|
|
|
/* As far as I know, there's no spec on the encoding of this text. (I didn't
|
|
|
|
|
* look very hard, though.) I've seen at least one file in ISO-8859-1. */
|
|
|
|
|
ConvertString( out.m_sMainTitle, "utf-8,english" );
|
|
|
|
|
ConvertString( out.m_sSubTitle, "utf-8,english" );
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-06 23:24:40 +00:00
|
|
|
else if( 0==stricmp(sValueName,"ARTIST") )
|
2003-06-30 08:40:10 +00:00
|
|
|
{
|
2002-09-06 23:24:40 +00:00
|
|
|
out.m_sArtist = sParams[1];
|
2003-06-30 08:40:10 +00:00
|
|
|
ConvertString( out.m_sArtist, "utf-8,english" );
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"CDTITLE") )
|
|
|
|
|
out.m_sCDTitleFile = sParams[1];
|
|
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"BPM") )
|
2005-01-23 23:17:12 +00:00
|
|
|
out.AddBPMSegment( BPMSegment(0, strtof(sParams[1], NULL)) );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-05-23 01:14:43 +00:00
|
|
|
else if( 0==stricmp(sValueName,"DISPLAYBPM") )
|
|
|
|
|
{
|
|
|
|
|
// #DISPLAYBPM:[xxx..xxx]|[xxx]|[*];
|
2003-06-13 23:15:09 +00:00
|
|
|
int iMin, iMax;
|
|
|
|
|
/* We can't parse this as a float with sscanf, since '.' is a valid
|
|
|
|
|
* character in a float. (We could do it with a regex, but it's not
|
|
|
|
|
* worth bothering with since we don't display fractional BPM anyway.) */
|
|
|
|
|
if( sscanf( sParams[1], "%i..%i", &iMin, &iMax ) == 2 )
|
2003-05-23 01:14:43 +00:00
|
|
|
{
|
|
|
|
|
out.m_DisplayBPMType = Song::DISPLAY_SPECIFIED;
|
2003-06-16 17:28:58 +00:00
|
|
|
out.m_fSpecifiedBPMMin = (float) iMin;
|
|
|
|
|
out.m_fSpecifiedBPMMax = (float) iMax;
|
2003-05-23 01:14:43 +00:00
|
|
|
}
|
2003-06-13 23:15:09 +00:00
|
|
|
else if( sscanf( sParams[1], "%i", &iMin ) == 1 )
|
2003-05-23 01:14:43 +00:00
|
|
|
{
|
|
|
|
|
out.m_DisplayBPMType = Song::DISPLAY_SPECIFIED;
|
2003-06-16 17:28:58 +00:00
|
|
|
out.m_fSpecifiedBPMMin = out.m_fSpecifiedBPMMax = (float) iMin;
|
2003-05-23 01:14:43 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
out.m_DisplayBPMType = Song::DISPLAY_RANDOM;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-06 23:24:40 +00:00
|
|
|
else if( 0==stricmp(sValueName,"GAP") )
|
|
|
|
|
// the units of GAP is 1/1000 second
|
2003-12-18 04:48:26 +00:00
|
|
|
out.m_Timing.m_fBeat0OffsetInSeconds = -atoi( sParams[1] ) / 1000.0f;
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"SAMPLESTART") )
|
2003-01-14 22:44:30 +00:00
|
|
|
out.m_fMusicSampleStartSeconds = ParseBrokenDWITimestamp(sParams[1], sParams[2], sParams[3]);
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"SAMPLELENGTH") )
|
2003-01-14 22:44:30 +00:00
|
|
|
out.m_fMusicSampleLengthSeconds = ParseBrokenDWITimestamp(sParams[1], sParams[2], sParams[3]);
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"FREEZE") )
|
|
|
|
|
{
|
2006-01-22 01:00:06 +00:00
|
|
|
vector<RString> arrayFreezeExpressions;
|
2002-09-06 23:24:40 +00:00
|
|
|
split( sParams[1], ",", arrayFreezeExpressions );
|
|
|
|
|
|
2002-10-31 03:16:02 +00:00
|
|
|
for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2006-01-22 01:00:06 +00:00
|
|
|
vector<RString> arrayFreezeValues;
|
2002-09-06 23:24:40 +00:00
|
|
|
split( arrayFreezeExpressions[f], "=", arrayFreezeValues );
|
2004-03-26 22:56:17 +00:00
|
|
|
if( arrayFreezeValues.size() != 2 )
|
|
|
|
|
{
|
|
|
|
|
LOG->Warn( "Invalid FREEZE in '%s': '%s'", m_sLoadingFile.c_str(), arrayFreezeExpressions[f].c_str() );
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2005-01-23 21:55:01 +00:00
|
|
|
int iFreezeRow = BeatToNoteRow( strtof( arrayFreezeValues[0],NULL ) / 4.0f );
|
2004-08-10 20:57:59 +00:00
|
|
|
float fFreezeSeconds = strtof( arrayFreezeValues[1], NULL ) / 1000.0f;
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2005-01-23 21:55:01 +00:00
|
|
|
out.AddStopSegment( StopSegment(iFreezeRow, fFreezeSeconds) );
|
2004-05-19 04:09:08 +00:00
|
|
|
// LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", fFreezeBeat, fFreezeSeconds );
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"CHANGEBPM") || 0==stricmp(sValueName,"BPMCHANGE") )
|
|
|
|
|
{
|
2006-01-22 01:00:06 +00:00
|
|
|
vector<RString> arrayBPMChangeExpressions;
|
2002-09-06 23:24:40 +00:00
|
|
|
split( sParams[1], ",", arrayBPMChangeExpressions );
|
|
|
|
|
|
2002-10-31 03:16:02 +00:00
|
|
|
for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2006-01-22 01:00:06 +00:00
|
|
|
vector<RString> arrayBPMChangeValues;
|
2002-09-06 23:24:40 +00:00
|
|
|
split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues );
|
2004-03-26 22:56:17 +00:00
|
|
|
if( arrayBPMChangeValues.size() != 2 )
|
|
|
|
|
{
|
2003-07-15 19:55:06 +00:00
|
|
|
LOG->Warn( "Invalid CHANGEBPM in '%s': '%s'", m_sLoadingFile.c_str(), arrayBPMChangeExpressions[b].c_str() );
|
2002-09-08 22:02:01 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2005-01-23 21:55:01 +00:00
|
|
|
BPMSegment bs;
|
|
|
|
|
bs.m_iStartIndex = BeatToNoteRow( strtof( arrayBPMChangeValues[0],NULL ) / 4.0f );
|
|
|
|
|
bs.SetBPM( strtof( arrayBPMChangeValues[1], NULL ) );
|
|
|
|
|
out.AddBPMSegment( bs );
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"SINGLE") ||
|
|
|
|
|
0==stricmp(sValueName,"DOUBLE") ||
|
|
|
|
|
0==stricmp(sValueName,"COUPLE") ||
|
|
|
|
|
0==stricmp(sValueName,"SOLO"))
|
|
|
|
|
{
|
2003-08-03 00:13:55 +00:00
|
|
|
Steps* pNewNotes = new Steps;
|
2002-09-06 23:24:40 +00:00
|
|
|
LoadFromDWITokens(
|
|
|
|
|
sParams[0],
|
|
|
|
|
sParams[1],
|
|
|
|
|
sParams[2],
|
|
|
|
|
sParams[3],
|
2006-01-22 01:00:06 +00:00
|
|
|
(iNumParams==5) ? sParams[4] : RString(""),
|
2002-09-12 08:37:12 +00:00
|
|
|
*pNewNotes
|
2002-09-06 23:24:40 +00:00
|
|
|
);
|
2003-08-07 06:36:34 +00:00
|
|
|
if(pNewNotes->m_StepsType != STEPS_TYPE_INVALID)
|
2004-06-05 05:13:23 +00:00
|
|
|
out.AddSteps( pNewNotes );
|
2002-09-07 05:04:04 +00:00
|
|
|
else
|
|
|
|
|
delete pNewNotes;
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
2003-07-28 08:24:16 +00:00
|
|
|
else if( 0==stricmp(sValueName,"DISPLAYTITLE") ||
|
|
|
|
|
0==stricmp(sValueName,"DISPLAYARTIST") )
|
|
|
|
|
{
|
|
|
|
|
/* We don't want to support these tags. However, we don't want
|
|
|
|
|
* to pick up images used here as song images (eg. banners). */
|
2006-01-22 01:00:06 +00:00
|
|
|
RString param = sParams[1];
|
2003-07-28 08:24:16 +00:00
|
|
|
/* "{foo} ... {foo2}" */
|
2004-06-16 07:03:25 +00:00
|
|
|
size_t pos = 0;
|
2006-01-22 01:00:06 +00:00
|
|
|
while( pos < RString::npos )
|
2003-07-28 08:24:16 +00:00
|
|
|
{
|
|
|
|
|
|
2004-06-16 07:03:25 +00:00
|
|
|
size_t startpos = param.find('{', pos);
|
2006-01-22 01:00:06 +00:00
|
|
|
if( startpos == RString::npos )
|
2003-07-28 08:24:16 +00:00
|
|
|
break;
|
2004-06-16 07:03:25 +00:00
|
|
|
size_t endpos = param.find('}', startpos);
|
2006-01-22 01:00:06 +00:00
|
|
|
if( endpos == RString::npos )
|
2003-07-28 08:24:16 +00:00
|
|
|
break;
|
|
|
|
|
|
2006-01-22 01:00:06 +00:00
|
|
|
RString sub = param.substr( startpos+1, endpos-startpos-1 );
|
2003-07-28 08:24:16 +00:00
|
|
|
|
|
|
|
|
pos = endpos + 1;
|
|
|
|
|
|
2006-02-28 23:04:24 +00:00
|
|
|
sub.ToLower();
|
|
|
|
|
BlacklistedImages.insert( sub );
|
2003-07-28 08:24:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
|
2006-02-02 23:52:28 +00:00
|
|
|
void DWILoader::GetApplicableFiles( const RString &sPath, vector<RString> &out )
|
2002-09-11 05:15:46 +00:00
|
|
|
{
|
2006-01-22 01:00:06 +00:00
|
|
|
GetDirListing( sPath + RString("*.dwi"), out );
|
2002-09-11 05:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
2006-02-02 23:52:28 +00:00
|
|
|
bool DWILoader::LoadFromDir( const RString &sPath, Song &out )
|
2002-09-11 05:15:46 +00:00
|
|
|
{
|
2006-01-22 01:00:06 +00:00
|
|
|
vector<RString> aFileNames;
|
2002-09-11 05:15:46 +00:00
|
|
|
GetApplicableFiles( sPath, aFileNames );
|
|
|
|
|
|
2002-10-31 03:16:02 +00:00
|
|
|
if( aFileNames.size() > 1 )
|
2003-04-25 00:01:35 +00:00
|
|
|
RageException::Throw( "There is more than one DWI file in '%s'. There should be only one!", sPath.c_str() );
|
2002-09-11 05:15:46 +00:00
|
|
|
|
|
|
|
|
/* We should have exactly one; if we had none, we shouldn't have been
|
|
|
|
|
* called to begin with. */
|
2002-10-31 03:16:02 +00:00
|
|
|
ASSERT( aFileNames.size() == 1 );
|
2002-09-11 05:15:46 +00:00
|
|
|
|
|
|
|
|
return LoadFromDWIFile( sPath + aFileNames[0], out );
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-31 21:55:14 +00:00
|
|
|
/*
|
|
|
|
|
* (c) 2001-2004 Chris Danford, Glenn Maynard
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|