2002-09-06 23:24:40 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
|
|
|
|
#include "NotesLoaderKSF.h"
|
|
|
|
|
|
|
|
|
|
#include "RageException.h"
|
|
|
|
|
#include "MsdFile.h"
|
|
|
|
|
#include "RageLog.h"
|
2002-09-07 11:43:36 +00:00
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "NoteData.h"
|
|
|
|
|
#include "NoteTypes.h"
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
bool KSFLoader::LoadFromKSFFile( const CString &sPath, Notes &out )
|
|
|
|
|
{
|
2002-10-29 07:58:44 +00:00
|
|
|
LOG->Trace( "Notes::LoadFromKSFFile( '%s' )", sPath.GetString() );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
MsdFile msd;
|
|
|
|
|
bool bResult = msd.ReadFile( sPath );
|
|
|
|
|
if( !bResult )
|
2002-12-21 18:36:10 +00:00
|
|
|
RageException::Throw( "Error opening file '%s'.", sPath.GetString() );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
int iTickCount = -1; // this is the value we read for TICKCOUNT
|
|
|
|
|
CString iStep; // this is the value we read for STEP
|
|
|
|
|
|
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
|
|
|
const MsdFile::value_t &sParams = msd.GetValue(i);
|
2002-09-06 23:24:40 +00:00
|
|
|
CString sValueName = sParams[0];
|
|
|
|
|
|
|
|
|
|
// handle the data
|
|
|
|
|
if( 0==stricmp(sValueName,"TICKCOUNT") )
|
|
|
|
|
iTickCount = atoi(sParams[1]);
|
|
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"STEP") )
|
|
|
|
|
iStep = sParams[1];
|
|
|
|
|
else if( 0==stricmp(sValueName,"DIFFICULTY") )
|
2003-01-02 22:10:51 +00:00
|
|
|
out.SetMeter(atoi(sParams[1]));
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( iTickCount == -1 )
|
|
|
|
|
{
|
|
|
|
|
iTickCount = 2;
|
2002-10-29 07:58:44 +00:00
|
|
|
LOG->Warn( "%s:\nTICKCOUNT not found; defaulting to %i", sPath.GetString(), iTickCount );
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NoteData notedata; // read it into here
|
|
|
|
|
|
|
|
|
|
CStringArray asRows;
|
2002-10-31 08:05:13 +00:00
|
|
|
TrimLeft(iStep);
|
2002-09-06 23:24:40 +00:00
|
|
|
split( iStep, "\n", asRows, true );
|
|
|
|
|
|
2002-11-03 01:32:47 +00:00
|
|
|
{
|
|
|
|
|
CString sDir, sFName, sExt;
|
|
|
|
|
splitrelpath( sPath, sDir, sFName, sExt );
|
|
|
|
|
sFName.MakeLower();
|
|
|
|
|
|
2003-01-02 22:10:51 +00:00
|
|
|
out.SetDescription(sFName);
|
2002-11-03 01:32:47 +00:00
|
|
|
if( sFName.Find("crazy")!=-1 )
|
|
|
|
|
{
|
2003-01-02 22:10:51 +00:00
|
|
|
out.SetDifficulty(DIFFICULTY_HARD);
|
|
|
|
|
if(!out.GetMeter()) out.SetMeter(8);
|
2002-11-03 01:32:47 +00:00
|
|
|
}
|
|
|
|
|
else if( sFName.Find("hard")!=-1 )
|
|
|
|
|
{
|
2003-01-02 22:10:51 +00:00
|
|
|
out.SetDifficulty(DIFFICULTY_MEDIUM);
|
|
|
|
|
if(!out.GetMeter()) out.SetMeter(5);
|
2002-11-03 01:32:47 +00:00
|
|
|
}
|
|
|
|
|
else if( sFName.Find("easy")!=-1 )
|
|
|
|
|
{
|
2003-01-02 22:10:51 +00:00
|
|
|
out.SetDifficulty(DIFFICULTY_EASY);
|
|
|
|
|
if(!out.GetMeter()) out.SetMeter(2);
|
2002-11-03 01:32:47 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-01-02 22:10:51 +00:00
|
|
|
out.SetDifficulty(DIFFICULTY_MEDIUM);
|
|
|
|
|
if(!out.GetMeter()) out.SetMeter(5);
|
2002-11-03 01:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
2003-02-01 05:16:38 +00:00
|
|
|
notedata.SetNumTracks( 5 );
|
2002-11-03 01:32:47 +00:00
|
|
|
out.m_NotesType = NOTES_TYPE_PUMP_SINGLE;
|
|
|
|
|
if( sFName.Find("double") != -1 )
|
|
|
|
|
{
|
2003-02-01 05:16:38 +00:00
|
|
|
notedata.SetNumTracks( 10 );
|
2002-11-03 01:32:47 +00:00
|
|
|
out.m_NotesType = NOTES_TYPE_PUMP_DOUBLE;
|
|
|
|
|
} else if( sFName.Find("_2") != -1 ) {
|
2003-02-01 05:16:38 +00:00
|
|
|
notedata.SetNumTracks( 10 );
|
2002-11-03 01:32:47 +00:00
|
|
|
out.m_NotesType = NOTES_TYPE_PUMP_COUPLE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-06 23:24:40 +00:00
|
|
|
int iHoldStartRow[13];
|
|
|
|
|
for( int t=0; t<13; t++ )
|
|
|
|
|
iHoldStartRow[t] = -1;
|
|
|
|
|
|
2002-10-31 03:01:35 +00:00
|
|
|
for( unsigned r=0; r<asRows.size(); r++ )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
|
|
|
|
CString& sRowString = asRows[r];
|
|
|
|
|
|
|
|
|
|
if( sRowString == "" )
|
|
|
|
|
continue; // skip
|
|
|
|
|
|
|
|
|
|
/* All 2s indicates the end of the song. */
|
|
|
|
|
if( sRowString == "2222222222222" )
|
|
|
|
|
break;
|
|
|
|
|
|
2003-01-01 09:19:10 +00:00
|
|
|
if(sRowString.size() != 13)
|
|
|
|
|
{
|
|
|
|
|
LOG->Warn("File %s had a RowString with an improper length (\"%s\"); corrupt notes ignored",
|
|
|
|
|
sPath.GetString(), sRowString.GetString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
// the length of a note in a row depends on TICKCOUNT
|
|
|
|
|
float fBeatThisRow = r/(float)iTickCount;
|
|
|
|
|
int row = BeatToNoteRow(fBeatThisRow);
|
2003-02-01 05:16:38 +00:00
|
|
|
for( int t=0; t < notedata.GetNumTracks(); t++ )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
|
|
|
|
if( sRowString[t] == '4' )
|
|
|
|
|
{
|
|
|
|
|
/* Remember when each hold starts; ignore the middle. */
|
|
|
|
|
if( iHoldStartRow[t] == -1 )
|
|
|
|
|
iHoldStartRow[t] = r;
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( iHoldStartRow[t] != -1 ) // this ends the hold
|
|
|
|
|
{
|
|
|
|
|
HoldNote hn = {
|
|
|
|
|
t, /* button */
|
|
|
|
|
iHoldStartRow[t]/(float)iTickCount, /* start */
|
|
|
|
|
(r-1)/(float)iTickCount /* end */
|
|
|
|
|
};
|
|
|
|
|
notedata.AddHoldNote( hn );
|
|
|
|
|
iHoldStartRow[t] = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-02 21:33:56 +00:00
|
|
|
TapNote tap;
|
|
|
|
|
switch(sRowString[t])
|
|
|
|
|
{
|
|
|
|
|
case '0': tap = TAP_EMPTY; break;
|
|
|
|
|
case '1': tap = TAP_TAP; break;
|
|
|
|
|
default: ASSERT(0); tap = TAP_EMPTY; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
notedata.SetTapNote(t, row, tap);
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-03 01:32:47 +00:00
|
|
|
out.SetNoteData(¬edata);
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-11 05:15:46 +00:00
|
|
|
void KSFLoader::GetApplicableFiles( CString sPath, CStringArray &out )
|
|
|
|
|
{
|
|
|
|
|
GetDirListing( sPath + CString("*.ksf"), out );
|
|
|
|
|
}
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2002-09-11 05:15:46 +00:00
|
|
|
bool KSFLoader::LoadFromDir( CString sDir, Song &out )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2002-10-29 07:58:44 +00:00
|
|
|
LOG->Trace( "Song::LoadFromKSFDir(%s)", sDir.GetString() );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
CStringArray arrayKSFFileNames;
|
|
|
|
|
GetDirListing( sDir + CString("*.ksf"), arrayKSFFileNames );
|
|
|
|
|
|
2003-01-01 09:19:10 +00:00
|
|
|
/* We shouldn't have been called to begin with if there were no KSFs. */
|
2002-10-31 03:01:35 +00:00
|
|
|
if( arrayKSFFileNames.empty() )
|
2002-12-21 18:36:10 +00:00
|
|
|
RageException::Throw( "Couldn't find any KSF files in '%s'", sDir.GetString() );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
// load the Notes from the rest of the KSF files
|
2002-11-16 09:12:55 +00:00
|
|
|
unsigned i;
|
|
|
|
|
for( i=0; i<arrayKSFFileNames.size(); i++ )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
|
|
|
|
Notes* pNewNotes = new Notes;
|
2003-01-15 20:36:52 +00:00
|
|
|
if(!LoadFromKSFFile( out.GetSongDir() + arrayKSFFileNames[i], *pNewNotes ))
|
2003-01-01 09:19:10 +00:00
|
|
|
{
|
|
|
|
|
delete pNewNotes;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-31 04:23:39 +00:00
|
|
|
out.m_apNotes.push_back( pNewNotes );
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
|
2002-12-13 23:41:11 +00:00
|
|
|
CString sPath = out.GetSongDir() + arrayKSFFileNames[0];
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-01-01 09:19:10 +00:00
|
|
|
/* XXX: We might have some corrupt KSF's; it'd be better to read global
|
|
|
|
|
* stuff from the first successful one above. */
|
2002-09-06 23:24:40 +00:00
|
|
|
MsdFile msd;
|
|
|
|
|
bool bResult = msd.ReadFile( sPath );
|
|
|
|
|
if( !bResult )
|
2002-12-21 18:36:10 +00:00
|
|
|
RageException::Throw( "Error opening file '%s'.", sPath.GetString() );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2003-01-14 22:10:04 +00:00
|
|
|
for( i=0; i < msd.GetNumValues(); i++ )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
2003-01-14 22:44:30 +00:00
|
|
|
const MsdFile::value_t &sParams = msd.GetValue(i);
|
2002-09-06 23:24:40 +00:00
|
|
|
CString sValueName = sParams[0];
|
|
|
|
|
|
|
|
|
|
// handle the data
|
|
|
|
|
if( 0==stricmp(sValueName,"TITLE") )
|
|
|
|
|
{
|
|
|
|
|
//title is usually in format "artist - songtitle"
|
|
|
|
|
CStringArray asBits;
|
|
|
|
|
split( sParams[1], " - ", asBits, false );
|
|
|
|
|
|
|
|
|
|
/* It's often "artist - songtitle - difficulty". Ignore
|
|
|
|
|
* the difficulty, since we get that from the filename. */
|
2002-10-31 03:01:35 +00:00
|
|
|
if( asBits.size() == 3 &&
|
2002-09-06 23:24:40 +00:00
|
|
|
(!stricmp(asBits[2], "double") ||
|
|
|
|
|
!stricmp(asBits[2], "easy") ||
|
|
|
|
|
!stricmp(asBits[2], "normal") ||
|
|
|
|
|
!stricmp(asBits[2], "hard") ||
|
|
|
|
|
!stricmp(asBits[2], "crazy")) )
|
|
|
|
|
{
|
2002-10-31 04:11:08 +00:00
|
|
|
asBits.erase(asBits.begin()+2, asBits.begin()+3);
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
|
2002-10-31 03:01:35 +00:00
|
|
|
if( asBits.size() == 2 )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
|
|
|
|
out.m_sArtist = asBits[0];
|
|
|
|
|
out.m_sMainTitle = asBits[1];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-01-15 20:36:52 +00:00
|
|
|
out.m_sMainTitle = sParams[1];
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( int j=0; j<out.m_sMainTitle.GetLength(); j++ )
|
|
|
|
|
{
|
|
|
|
|
char c = out.m_sMainTitle[j];
|
|
|
|
|
if( c < 0 ) // this title has a foreign char
|
|
|
|
|
{
|
|
|
|
|
CStringArray asBits;
|
|
|
|
|
split( sDir, "\\", asBits, true);
|
2002-10-31 03:01:35 +00:00
|
|
|
CString sSongFolderName = asBits[ asBits.size()-1 ];
|
2002-10-24 20:15:24 +00:00
|
|
|
asBits.clear();
|
2002-09-06 23:24:40 +00:00
|
|
|
|
|
|
|
|
split( sSongFolderName, " - ", asBits, false );
|
2002-10-31 03:01:35 +00:00
|
|
|
if( asBits.size() == 2 )
|
2002-09-06 23:24:40 +00:00
|
|
|
{
|
|
|
|
|
out.m_sArtist = asBits[0];
|
|
|
|
|
out.m_sMainTitle = asBits[1];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
out.m_sMainTitle = asBits[0];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"BPM") )
|
|
|
|
|
out.AddBPMSegment( BPMSegment(0, (float)atof(sParams[1])) );
|
|
|
|
|
|
|
|
|
|
else if( 0==stricmp(sValueName,"STARTTIME") )
|
|
|
|
|
out.m_fBeat0OffsetInSeconds = -(float)atof(sParams[1])/100;
|
|
|
|
|
else if( 0==stricmp(sValueName,"TICKCOUNT") ||
|
|
|
|
|
0==stricmp(sValueName,"STEP") ||
|
|
|
|
|
0==stricmp(sValueName,"DIFFICULTY"))
|
2002-09-12 07:50:20 +00:00
|
|
|
; /* Handled in LoadFromKSFFile; don't warn. */
|
2002-09-06 23:24:40 +00:00
|
|
|
else
|
2002-10-29 07:58:44 +00:00
|
|
|
LOG->Trace( "Unexpected value named '%s'", sValueName.GetString() );
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// search for music with song in the file name
|
|
|
|
|
CStringArray arrayPossibleMusic;
|
2002-12-13 23:41:11 +00:00
|
|
|
GetDirListing( out.GetSongDir() + CString("song.mp3"), arrayPossibleMusic );
|
|
|
|
|
GetDirListing( out.GetSongDir() + CString("song.ogg"), arrayPossibleMusic );
|
|
|
|
|
GetDirListing( out.GetSongDir() + CString("song.wav"), arrayPossibleMusic );
|
2002-09-06 23:24:40 +00:00
|
|
|
|
2002-10-31 03:01:35 +00:00
|
|
|
if( !arrayPossibleMusic.empty() ) // we found a match
|
2002-09-06 23:24:40 +00:00
|
|
|
out.m_sMusicFile = arrayPossibleMusic[0];
|
|
|
|
|
|
2002-12-17 10:39:33 +00:00
|
|
|
return true;
|
2002-09-06 23:24:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|