2001-11-03 10:52:42 +00:00
|
|
|
#include "stdafx.h"
|
2001-11-04 19:34:28 +00:00
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
File: Song.h
|
|
|
|
|
|
|
|
|
|
Desc: Holds metadata for a song and the song's step data.
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
2001-11-04 19:34:28 +00:00
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
#include "Notes.h"
|
2001-11-03 10:52:42 +00:00
|
|
|
#include "RageUtil.h"
|
|
|
|
|
|
|
|
|
|
#include "Song.h"
|
2002-02-28 19:40:40 +00:00
|
|
|
#include <math.h> // for fmod
|
2002-05-01 19:14:55 +00:00
|
|
|
#include "RageLog.h"
|
2002-04-16 17:31:00 +00:00
|
|
|
#include "ErrorCatcher/ErrorCatcher.h"
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
|
|
|
|
|
int CompareBPMSegments(const void *arg1, const void *arg2)
|
|
|
|
|
{
|
|
|
|
|
// arg1 and arg2 are of type Step**
|
|
|
|
|
BPMSegment* seg1 = (BPMSegment*)arg1;
|
|
|
|
|
BPMSegment* seg2 = (BPMSegment*)arg2;
|
|
|
|
|
|
|
|
|
|
float score1 = seg1->m_fStartBeat;
|
|
|
|
|
float score2 = seg2->m_fStartBeat;
|
|
|
|
|
|
|
|
|
|
if( score1 == score2 )
|
|
|
|
|
return 0;
|
|
|
|
|
else if( score1 < score2 )
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SortBPMSegmentsArray( CArray<BPMSegment,BPMSegment&> &arrayBPMSegments )
|
|
|
|
|
{
|
|
|
|
|
qsort( arrayBPMSegments.GetData(), arrayBPMSegments.GetSize(), sizeof(BPMSegment), CompareBPMSegments );
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
int CompareFreezeSegments(const void *arg1, const void *arg2)
|
|
|
|
|
{
|
|
|
|
|
// arg1 and arg2 are of type Step**
|
|
|
|
|
FreezeSegment* seg1 = (FreezeSegment*)arg1;
|
|
|
|
|
FreezeSegment* seg2 = (FreezeSegment*)arg2;
|
|
|
|
|
|
|
|
|
|
float score1 = seg1->m_fStartBeat;
|
|
|
|
|
float score2 = seg2->m_fStartBeat;
|
|
|
|
|
|
|
|
|
|
if( score1 == score2 )
|
|
|
|
|
return 0;
|
|
|
|
|
else if( score1 < score2 )
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SortFreezeSegmentsArray( CArray<FreezeSegment,FreezeSegment&> &arrayFreezeSegments )
|
|
|
|
|
{
|
|
|
|
|
qsort( arrayFreezeSegments.GetData(), arrayFreezeSegments.GetSize(), sizeof(FreezeSegment), CompareFreezeSegments );
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
|
2001-11-03 10:52:42 +00:00
|
|
|
//////////////////////////////
|
|
|
|
|
// Song
|
|
|
|
|
//////////////////////////////
|
2001-11-04 19:34:28 +00:00
|
|
|
Song::Song()
|
|
|
|
|
{
|
2001-11-27 22:47:30 +00:00
|
|
|
m_bChangedSinceSave = false;
|
|
|
|
|
m_fOffsetInSeconds = 0;
|
2002-04-28 20:42:32 +00:00
|
|
|
m_fMusicSampleStartSeconds = m_fMusicSampleLengthSeconds = -1;
|
2002-05-19 01:59:48 +00:00
|
|
|
m_iMusicBytes = 0;
|
|
|
|
|
m_fMusicLength = 0;
|
2001-11-04 19:34:28 +00:00
|
|
|
}
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
|
|
|
|
|
void Song::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut )
|
|
|
|
|
{
|
2002-05-01 19:14:55 +00:00
|
|
|
// LOG->WriteLine( "GetBeatAndBPSFromElapsedTime( fElapsedTime = %f )", fElapsedTime );
|
2002-02-28 19:40:40 +00:00
|
|
|
// This function is a nightmare. Don't even try to understand it. :-)
|
|
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
fElapsedTime += m_fOffsetInSeconds;
|
|
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
for( int i=0; i<m_BPMSegments.GetSize(); i++ ) // foreach BPMSegment
|
|
|
|
|
{
|
|
|
|
|
BPMSegment &this_seg = m_BPMSegments[i];
|
|
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
float fStartBeatThisSegment = m_BPMSegments[i].m_fStartBeat;
|
|
|
|
|
bool bIsLastBPMSegment = i==m_BPMSegments.GetSize()-1;
|
|
|
|
|
float fStartBeatNextSegment = bIsLastBPMSegment ? 40000/*inf*/ : m_BPMSegments[i+1].m_fStartBeat;
|
|
|
|
|
float fBeatsInThisSegment = fStartBeatNextSegment - fStartBeatThisSegment;
|
|
|
|
|
float fBPM = m_BPMSegments[i].m_fBPM;
|
|
|
|
|
float fBPS = fBPM / 60.0f;
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
// calculate the number of seconds in this segment
|
2001-12-19 01:50:57 +00:00
|
|
|
float fSecondsInThisSegment = fBeatsInThisSegment / fBPS;
|
2001-12-28 10:15:59 +00:00
|
|
|
for( int j=0; j<m_FreezeSegments.GetSize(); j++ ) // foreach freeze
|
|
|
|
|
{
|
|
|
|
|
if( fStartBeatThisSegment <= m_FreezeSegments[j].m_fStartBeat && m_FreezeSegments[j].m_fStartBeat < fStartBeatNextSegment )
|
|
|
|
|
{
|
|
|
|
|
// this freeze lies within this BPMSegment
|
|
|
|
|
fSecondsInThisSegment += m_FreezeSegments[j].m_fFreezeSeconds;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
|
|
|
|
|
if( fElapsedTime > fSecondsInThisSegment )
|
2001-12-28 10:15:59 +00:00
|
|
|
{
|
|
|
|
|
// this BPMSegement is not the current segment
|
2001-12-19 01:50:57 +00:00
|
|
|
fElapsedTime -= fSecondsInThisSegment;
|
2001-12-28 10:15:59 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// this BPMSegment IS the current segment
|
|
|
|
|
|
|
|
|
|
float fBeatEstimate = fStartBeatThisSegment + fElapsedTime*fBPS;
|
|
|
|
|
|
|
|
|
|
for( int j=0; j<m_FreezeSegments.GetSize(); j++ ) // foreach freeze
|
|
|
|
|
{
|
|
|
|
|
if( fStartBeatThisSegment <= m_FreezeSegments[j].m_fStartBeat && m_FreezeSegments[j].m_fStartBeat <= fStartBeatNextSegment )
|
|
|
|
|
{
|
|
|
|
|
// this freeze lies within this BPMSegment
|
|
|
|
|
|
|
|
|
|
if( m_FreezeSegments[j].m_fStartBeat <= fBeatEstimate )
|
|
|
|
|
{
|
|
|
|
|
fElapsedTime -= m_FreezeSegments[j].m_fFreezeSeconds;
|
|
|
|
|
// re-estimate
|
|
|
|
|
fBeatEstimate = fStartBeatThisSegment + fElapsedTime*fBPS;
|
|
|
|
|
if( fBeatEstimate < m_FreezeSegments[j].m_fStartBeat )
|
|
|
|
|
{
|
|
|
|
|
fBeatOut = m_FreezeSegments[j].m_fStartBeat;
|
|
|
|
|
fBPSOut = fBPS;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fBeatOut = fBeatEstimate;
|
2001-12-19 01:50:57 +00:00
|
|
|
fBPSOut = fBPS;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-12-28 10:15:59 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
// This is a super hack, but it's only called from ScreenEdit, so it's OK :-)
|
2002-04-16 17:31:00 +00:00
|
|
|
// Writing an inverse function of GetBeatAndBPSFromElapsedTime() is impossible,
|
|
|
|
|
// so do a binary search to get close to the correct elapsed time.
|
|
|
|
|
float Song::GetElapsedTimeFromBeat( float fBeat )
|
|
|
|
|
{
|
|
|
|
|
float fElapsedTimeBestGuess = 100; // seconds
|
|
|
|
|
float fSecondsToMove = fElapsedTimeBestGuess/2; // seconds
|
|
|
|
|
float fBeatOut, fBPSOut;
|
|
|
|
|
|
|
|
|
|
while( fSecondsToMove > 0.1f )
|
|
|
|
|
{
|
|
|
|
|
GetBeatAndBPSFromElapsedTime( fElapsedTimeBestGuess, fBeatOut, fBPSOut );
|
|
|
|
|
if( fBeatOut > fBeat )
|
|
|
|
|
fElapsedTimeBestGuess -= fSecondsToMove;
|
|
|
|
|
else
|
|
|
|
|
fElapsedTimeBestGuess += fSecondsToMove;
|
|
|
|
|
|
|
|
|
|
fSecondsToMove /= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fElapsedTimeBestGuess;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-01 19:14:55 +00:00
|
|
|
void Song::GetMainAndSubTitlesFromFullTitle( CString sFullTitle, CString &sMainTitleOut, CString &sSubTitleOut )
|
|
|
|
|
{
|
|
|
|
|
char szSeps[] = { '-', '~' };
|
|
|
|
|
for( int i=0; i<sizeof(szSeps); i++ )
|
|
|
|
|
{
|
|
|
|
|
const char c = szSeps[i];
|
|
|
|
|
int iBeginIndex = sFullTitle.Find( c );
|
|
|
|
|
if( iBeginIndex == -1 )
|
|
|
|
|
continue;
|
|
|
|
|
int iEndIndex = sFullTitle.Find( c, iBeginIndex+1 );
|
|
|
|
|
if( iEndIndex == -1 )
|
|
|
|
|
continue;
|
|
|
|
|
sMainTitleOut = sFullTitle.Left( iBeginIndex-1 );
|
|
|
|
|
sSubTitleOut = sFullTitle.Mid( iBeginIndex, iEndIndex-iBeginIndex+1 );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sMainTitleOut = sFullTitle;
|
|
|
|
|
sSubTitleOut = "";
|
|
|
|
|
};
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
CString Song::GetCacheFilePath()
|
|
|
|
|
{
|
|
|
|
|
ULONG hash = GetHashForString( m_sSongDir );
|
2002-05-27 08:23:27 +00:00
|
|
|
return ssprintf( "Cache\\%u.song", hash );
|
2002-05-19 01:59:48 +00:00
|
|
|
}
|
|
|
|
|
|
2001-11-03 10:52:42 +00:00
|
|
|
bool Song::LoadFromSongDir( CString sDir )
|
|
|
|
|
{
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "Song::LoadFromSongDir(%s)", sDir );
|
2001-11-03 10:52:42 +00:00
|
|
|
|
|
|
|
|
// make sure there is a trailing '\\' at the end of sDir
|
|
|
|
|
if( sDir.Right(1) != "\\" )
|
|
|
|
|
sDir += "\\";
|
|
|
|
|
|
|
|
|
|
// save song dir
|
|
|
|
|
m_sSongDir = sDir;
|
|
|
|
|
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
//
|
|
|
|
|
// First look in the cache for this song (without loading NoteData)
|
|
|
|
|
//
|
|
|
|
|
if( LoadFromCacheFile(false) )
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// There was no entry in the cache for this song.
|
|
|
|
|
// Let's load it from a file, then write a cache entry.
|
|
|
|
|
//
|
2001-11-03 10:52:42 +00:00
|
|
|
CStringArray arrayBMSFileNames;
|
|
|
|
|
GetDirListing( sDir + CString("*.bms"), arrayBMSFileNames );
|
|
|
|
|
int iNumBMSFiles = arrayBMSFileNames.GetSize();
|
|
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
CStringArray arrayDWIFileNames;
|
|
|
|
|
GetDirListing( sDir + CString("*.dwi"), arrayDWIFileNames );
|
|
|
|
|
int iNumDWIFiles = arrayDWIFileNames.GetSize();
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
CStringArray arraySongFileNames;
|
|
|
|
|
GetDirListing( sDir + CString("*.song"), arraySongFileNames );
|
|
|
|
|
int iNumSongFiles = arraySongFileNames.GetSize();
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
if( iNumSongFiles > 1 )
|
2002-05-19 01:59:48 +00:00
|
|
|
FatalError( "There is more than one .song file in '%s'. There should be only one!", sDir );
|
2002-04-16 17:31:00 +00:00
|
|
|
else if( iNumDWIFiles > 1 )
|
2002-05-19 01:59:48 +00:00
|
|
|
FatalError( "There is more than one DWI file in '%s'. There should be only one!", sDir );
|
2002-04-16 17:31:00 +00:00
|
|
|
else if( iNumSongFiles == 1 )
|
|
|
|
|
LoadFromSMDir( sDir );
|
2001-12-19 01:50:57 +00:00
|
|
|
else if( iNumDWIFiles == 1 )
|
2002-04-16 17:31:00 +00:00
|
|
|
LoadFromDWIFile( sDir + arrayDWIFileNames[0] );
|
2001-12-28 10:15:59 +00:00
|
|
|
else if( iNumBMSFiles > 0 )
|
2002-04-16 17:31:00 +00:00
|
|
|
LoadFromBMSDir( sDir );
|
2001-11-03 10:52:42 +00:00
|
|
|
else
|
2002-05-19 01:59:48 +00:00
|
|
|
FatalError( "Couldn't find any .song, BMS, or DWI files in '%s'. This is not a valid song directory.", sDir );
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
TidyUpData();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// In order to save memory, we're going to save the file back to the cache,
|
|
|
|
|
// then unload all the large NoteData.
|
|
|
|
|
//
|
|
|
|
|
SaveToCacheFile();
|
|
|
|
|
LoadFromCacheFile( false );
|
|
|
|
|
|
|
|
|
|
return true;
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
bool Song::LoadFromBMSDir( CString sDir )
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "Song::LoadFromBMSDir(%s)", sDir );
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
// make sure there is a trailing '\\' at the end of sDir
|
|
|
|
|
if( sDir.Right(1) != "\\" )
|
|
|
|
|
sDir += "\\";
|
|
|
|
|
|
|
|
|
|
// save song dir
|
|
|
|
|
m_sSongDir = sDir;
|
|
|
|
|
|
|
|
|
|
// get group name
|
|
|
|
|
CStringArray sDirectoryParts;
|
|
|
|
|
split( m_sSongDir, "\\", sDirectoryParts, true );
|
|
|
|
|
m_sGroupName = sDirectoryParts[1];
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
CStringArray arrayBMSFileNames;
|
|
|
|
|
GetDirListing( sDir + CString("*.bms"), arrayBMSFileNames );
|
|
|
|
|
|
|
|
|
|
if( arrayBMSFileNames.GetSize() == 0 )
|
2002-04-16 17:31:00 +00:00
|
|
|
FatalError( ssprintf("Couldn't find any BMS files in '%s'", sDir) );
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// Load the Song info from the first BMS file. Silly BMS duplicates the song info in every
|
2002-01-24 08:01:24 +00:00
|
|
|
// file. So, we read the song data from only the first BMS file and assume that the info
|
|
|
|
|
// is identical for every BMS file in the directory.
|
2002-02-11 04:46:31 +00:00
|
|
|
m_sSongFilePath = m_sSongDir + arrayBMSFileNames[0];
|
2001-12-28 10:15:59 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
// load the Notes from the rest of the BMS files
|
2001-12-28 10:15:59 +00:00
|
|
|
for( int i=0; i<arrayBMSFileNames.GetSize(); i++ )
|
|
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
m_arrayNotes.SetSize( m_arrayNotes.GetSize()+1 );
|
|
|
|
|
Notes &new_steps = m_arrayNotes[ m_arrayNotes.GetSize()-1 ];
|
2002-03-19 07:09:49 +00:00
|
|
|
new_steps.LoadFromBMSFile( m_sSongDir + arrayBMSFileNames[i] );
|
2001-12-28 10:15:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-01-24 08:01:24 +00:00
|
|
|
CStdioFile file;
|
2002-02-11 04:46:31 +00:00
|
|
|
if( !file.Open( m_sSongFilePath, CFile::modeRead|CFile::shareDenyNone ) )
|
2002-01-24 08:01:24 +00:00
|
|
|
{
|
2002-04-16 17:31:00 +00:00
|
|
|
FatalError( ssprintf("Failed to open %s.", m_sSongFilePath) );
|
2002-01-24 08:01:24 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CString line;
|
|
|
|
|
while( file.ReadString(line) ) // foreach line
|
|
|
|
|
{
|
|
|
|
|
CString value_name; // fill these in
|
|
|
|
|
CString value_data;
|
2001-12-28 10:15:59 +00:00
|
|
|
|
2002-01-24 08:01:24 +00:00
|
|
|
// BMS value names can be separated by a space or a colon.
|
|
|
|
|
int iIndexOfFirstColon = line.Find( ":" );
|
|
|
|
|
int iIndexOfFirstSpace = line.Find( " " );
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2002-01-24 08:01:24 +00:00
|
|
|
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();
|
2001-11-03 10:52:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// handle the data
|
2002-04-28 20:42:32 +00:00
|
|
|
if( -1 != value_name.Find("#title") )
|
2002-01-24 08:01:24 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
// strip Notes type out of description leaving only song title (looks like 'B4U <BASIC>')
|
2002-04-28 20:42:32 +00:00
|
|
|
value_data.Replace( "(ANOTHER)", "" );
|
|
|
|
|
value_data.Replace( "(BASIC)", "" );
|
|
|
|
|
value_data.Replace( "(MANIAC)", "" );
|
|
|
|
|
value_data.Replace( "<ANOTHER>", "" );
|
|
|
|
|
value_data.Replace( "<BASIC>", "" );
|
|
|
|
|
value_data.Replace( "<MANIAC>", "" );
|
|
|
|
|
|
|
|
|
|
GetMainAndSubTitlesFromFullTitle( value_data, m_sMainTitle, m_sSubTitle );
|
2002-01-24 08:01:24 +00:00
|
|
|
}
|
|
|
|
|
else if( -1 != value_name.Find("#artist") )
|
|
|
|
|
{
|
|
|
|
|
m_sArtist = value_data;
|
2001-11-04 19:34:28 +00:00
|
|
|
}
|
2002-01-24 08:01:24 +00:00
|
|
|
else if( -1 != value_name.Find("#bpm") )
|
|
|
|
|
{
|
2001-11-27 22:47:30 +00:00
|
|
|
BPMSegment new_seg;
|
2001-12-19 01:50:57 +00:00
|
|
|
new_seg.m_fStartBeat = 0;
|
2002-01-24 08:01:24 +00:00
|
|
|
new_seg.m_fBPM = (float)atof( value_data );
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
// add, then sort
|
2001-12-19 01:50:57 +00:00
|
|
|
m_BPMSegments.Add( new_seg );
|
2001-12-28 10:15:59 +00:00
|
|
|
SortBPMSegmentsArray( m_BPMSegments );
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "Inserting new BPM change at beat %f, BPM %f", new_seg.m_fStartBeat, new_seg.m_fBPM );
|
2001-11-27 22:47:30 +00:00
|
|
|
}
|
2002-01-24 08:01:24 +00:00
|
|
|
else if( -1 != value_name.Find("#backbmp") )
|
|
|
|
|
{
|
|
|
|
|
m_sBackgroundPath = m_sSongDir + value_data;
|
|
|
|
|
}
|
|
|
|
|
else if( -1 != value_name.Find("#wav") )
|
|
|
|
|
{
|
|
|
|
|
m_sMusicPath = m_sSongDir + 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"
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2001-11-04 19:34:28 +00:00
|
|
|
int iMeasureNo = atoi( value_name.Mid(1,3) );
|
2001-11-27 22:47:30 +00:00
|
|
|
int iTrackNum = atoi( value_name.Mid(4,2) );
|
|
|
|
|
|
2002-01-24 08:01:24 +00:00
|
|
|
CString sNoteData = value_data;
|
2001-12-19 01:50:57 +00:00
|
|
|
CArray<int, int> arrayNotes;
|
2001-11-03 10:52:42 +00:00
|
|
|
|
|
|
|
|
for( int i=0; i<sNoteData.GetLength(); i+=2 )
|
|
|
|
|
{
|
2001-12-19 01:50:57 +00:00
|
|
|
CString sNote = sNoteData.Mid(i,2);
|
|
|
|
|
int iNote;
|
|
|
|
|
sscanf( sNote, "%x", &iNote ); // data is in hexadecimal
|
|
|
|
|
arrayNotes.Add( iNote );
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int iNumNotesInThisMeasure = arrayNotes.GetSize();
|
2002-05-01 19:14:55 +00:00
|
|
|
//LOG->WriteLine( "%s:%s: iMeasureNo = %d, iTrackNum = %d, iNumNotesInThisMeasure = %d",
|
2001-11-27 22:47:30 +00:00
|
|
|
// valuename, sNoteData, iMeasureNo, iTrackNum, iNumNotesInThisMeasure );
|
2001-11-03 10:52:42 +00:00
|
|
|
for( int j=0; j<iNumNotesInThisMeasure; j++ )
|
|
|
|
|
{
|
2001-12-19 01:50:57 +00:00
|
|
|
if( arrayNotes[j] != 0 )
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2001-11-27 22:47:30 +00:00
|
|
|
float fPercentThroughMeasure = (float)j/(float)iNumNotesInThisMeasure;
|
2001-11-03 10:52:42 +00:00
|
|
|
|
|
|
|
|
// index is in quarter beats starting at beat 0
|
|
|
|
|
int iStepIndex = (int) ( (iMeasureNo + fPercentThroughMeasure)
|
2001-11-04 19:34:28 +00:00
|
|
|
* BEATS_PER_MEASURE * ELEMENTS_PER_BEAT );
|
|
|
|
|
|
2001-11-27 22:47:30 +00:00
|
|
|
switch( iTrackNum )
|
2001-11-04 19:34:28 +00:00
|
|
|
{
|
2001-12-19 01:50:57 +00:00
|
|
|
case 01: // background music track
|
|
|
|
|
float fBeatOffset;
|
2002-05-19 01:59:48 +00:00
|
|
|
fBeatOffset = NoteRowToBeat( (float)iStepIndex );
|
2001-12-19 01:50:57 +00:00
|
|
|
float fBPS;
|
|
|
|
|
fBPS = m_BPMSegments[0].m_fBPM/60.0f;
|
2001-11-27 22:47:30 +00:00
|
|
|
m_fOffsetInSeconds = fBeatOffset / fBPS;
|
2002-05-19 01:59:48 +00:00
|
|
|
//LOG->WriteLine( "Found offset to be index %d, beat %f", iStepIndex, NoteRowToBeat(iStepIndex) );
|
2001-11-27 22:47:30 +00:00
|
|
|
break;
|
|
|
|
|
case 03: // bpm
|
2001-12-19 01:50:57 +00:00
|
|
|
BPMSegment new_seg;
|
2002-05-19 01:59:48 +00:00
|
|
|
new_seg.m_fStartBeat = NoteRowToBeat( (float)iStepIndex );
|
2001-12-19 01:50:57 +00:00
|
|
|
new_seg.m_fBPM = (float)arrayNotes[j];
|
2001-12-28 10:15:59 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
m_BPMSegments.Add( new_seg ); // add to back for now (we'll sort later)
|
|
|
|
|
SortBPMSegmentsArray( m_BPMSegments );
|
2001-11-04 19:34:28 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
for( i=0; i<m_BPMSegments.GetSize(); i++ )
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "There is a BPM change at beat %f, BPM %f, index %d",
|
2001-12-19 01:50:57 +00:00
|
|
|
m_BPMSegments[i].m_fStartBeat, m_BPMSegments[i].m_fBPM, i );
|
|
|
|
|
|
|
|
|
|
|
2001-11-03 10:52:42 +00:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
bool Song::LoadFromDWIFile( CString sPath )
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "Song::LoadFromDWIFile(%s)", sPath );
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
// save song file path
|
|
|
|
|
m_sSongFilePath = sPath;
|
|
|
|
|
|
|
|
|
|
// save song dir
|
|
|
|
|
CString sDir, sFName, sExt;
|
|
|
|
|
splitrelpath(sPath, sDir, sFName, sExt);
|
|
|
|
|
m_sSongDir = sDir;
|
|
|
|
|
|
|
|
|
|
// get group name
|
|
|
|
|
sDir.MakeLower();
|
|
|
|
|
if( sDir.Find( "dwi support" ) != -1 ) // loading from DWI support
|
|
|
|
|
{
|
|
|
|
|
int iIndexOfFirstBackslash = sDir.Find('\\');
|
|
|
|
|
int iIndexOfSecondBackslash = sDir.Find('\\', iIndexOfFirstBackslash+1);
|
|
|
|
|
int iIndexOfThirdBackslash = sDir.Find('\\', iIndexOfSecondBackslash+1);
|
|
|
|
|
m_sGroupName = sDir.Mid( iIndexOfSecondBackslash+1, iIndexOfThirdBackslash-iIndexOfSecondBackslash-1 );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// get group name
|
|
|
|
|
CStringArray sDirectoryParts;
|
|
|
|
|
split( m_sSongDir, "\\", sDirectoryParts, true );
|
|
|
|
|
m_sGroupName = sDirectoryParts[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// save probable image paths
|
|
|
|
|
m_sBackgroundPath = ssprintf(".\\DWI Support\\Backgrounds\\%s\\%s.avi", m_sGroupName, sFName);
|
|
|
|
|
if( !DoesFileExist( GetBackgroundPath() ) )
|
|
|
|
|
m_sBackgroundPath = ssprintf(".\\DWI Support\\Backgrounds\\%s\\%s.mpg", m_sGroupName, sFName);
|
|
|
|
|
if( !DoesFileExist( GetBackgroundPath() ) )
|
|
|
|
|
m_sBackgroundPath = ssprintf(".\\DWI Support\\Backgrounds\\%s\\%s.mpeg", m_sGroupName, sFName);
|
|
|
|
|
if( !DoesFileExist( GetBackgroundPath() ) )
|
|
|
|
|
m_sBackgroundPath = ssprintf(".\\DWI Support\\Backgrounds\\%s\\%s.png", m_sGroupName, sFName);
|
|
|
|
|
|
|
|
|
|
m_sBannerPath = ssprintf(".\\DWI Support\\Banners\\%s\\%s.png", m_sGroupName, sFName);
|
2001-11-03 10:52:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
CStdioFile file;
|
2002-01-24 08:01:24 +00:00
|
|
|
if( !file.Open( GetSongFilePath(), CFile::modeRead|CFile::shareDenyNone ) )
|
2002-04-16 17:31:00 +00:00
|
|
|
FatalError( ssprintf("Error opening DWI file '%s'.", GetSongFilePath()) );
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// MessageBox( NULL, sFName, sFName, MB_OK );
|
|
|
|
|
|
2001-11-03 10:52:42 +00:00
|
|
|
|
|
|
|
|
// read the whole file into a sFileText
|
|
|
|
|
CString sFileText;
|
|
|
|
|
CString buffer;
|
|
|
|
|
while( file.ReadString(buffer) )
|
|
|
|
|
sFileText += buffer;
|
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
|
|
// split sFileText into strings containing each value expression
|
|
|
|
|
CStringArray arrayValueStrings;
|
|
|
|
|
split( sFileText, ";", arrayValueStrings );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for each value expression string, parse it into a value name and data
|
|
|
|
|
for( int i=0; i < arrayValueStrings.GetSize(); i++ )
|
|
|
|
|
{
|
|
|
|
|
CString sValueString = arrayValueStrings[i];
|
|
|
|
|
|
|
|
|
|
// split the value string into tokens
|
|
|
|
|
CStringArray arrayValueTokens;
|
|
|
|
|
split( sValueString, ":", arrayValueTokens );
|
|
|
|
|
|
2002-02-12 06:55:04 +00:00
|
|
|
if( arrayValueTokens.GetSize() == 0 )
|
|
|
|
|
continue;
|
|
|
|
|
|
2001-11-03 10:52:42 +00:00
|
|
|
CString sValueName = arrayValueTokens.GetAt( 0 );
|
2002-02-09 18:53:47 +00:00
|
|
|
sValueName.TrimLeft();
|
2001-12-19 01:50:57 +00:00
|
|
|
|
2001-11-03 10:52:42 +00:00
|
|
|
// handle the data
|
2001-12-19 01:50:57 +00:00
|
|
|
if( sValueName == "#FILE" )
|
2001-12-28 10:15:59 +00:00
|
|
|
m_sMusicPath = CString("DWI Support\\") + arrayValueTokens[1];
|
2001-12-19 01:50:57 +00:00
|
|
|
|
|
|
|
|
else if( sValueName == "#TITLE" )
|
2002-04-28 20:42:32 +00:00
|
|
|
{
|
|
|
|
|
GetMainAndSubTitlesFromFullTitle( arrayValueTokens[1], m_sMainTitle, m_sSubTitle );
|
|
|
|
|
}
|
2001-11-03 10:52:42 +00:00
|
|
|
else if( sValueName == "#ARTIST" )
|
|
|
|
|
m_sArtist = arrayValueTokens[1];
|
|
|
|
|
|
|
|
|
|
else if( sValueName == "#BPM" )
|
2001-12-19 01:50:57 +00:00
|
|
|
{
|
|
|
|
|
BPMSegment new_seg;
|
|
|
|
|
new_seg.m_fStartBeat = 0;
|
2001-12-28 10:15:59 +00:00
|
|
|
new_seg.m_fBPM = (float)atof( arrayValueTokens[1] );
|
|
|
|
|
|
|
|
|
|
m_BPMSegments.Add( new_seg );
|
|
|
|
|
SortBPMSegmentsArray( m_BPMSegments );
|
2001-12-19 01:50:57 +00:00
|
|
|
}
|
|
|
|
|
else if( sValueName == "#GAP" )
|
|
|
|
|
// the units of GAP is 1/1000 second
|
|
|
|
|
m_fOffsetInSeconds = -atoi( arrayValueTokens[1] ) / 1000.0f;
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2002-04-28 20:42:32 +00:00
|
|
|
else if( sValueName == "#SAMPLESTART" )
|
|
|
|
|
m_fMusicSampleStartSeconds = TimeToSeconds( arrayValueTokens[1] );
|
|
|
|
|
|
|
|
|
|
else if( sValueName == "#SAMPLELENGTH" )
|
|
|
|
|
m_fMusicSampleLengthSeconds = TimeToSeconds( arrayValueTokens[1] );
|
|
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
else if( sValueName == "#FREEZE" )
|
|
|
|
|
{
|
|
|
|
|
CStringArray arrayFreezeExpressions;
|
|
|
|
|
split( arrayValueTokens[1], ",", arrayFreezeExpressions );
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
for( int f=0; f<arrayFreezeExpressions.GetSize(); f++ )
|
|
|
|
|
{
|
|
|
|
|
CStringArray arrayFreezeValues;
|
|
|
|
|
split( arrayFreezeExpressions[f], "=", arrayFreezeValues );
|
2002-02-28 19:40:40 +00:00
|
|
|
float fIndex = atoi( arrayFreezeValues[0] ) * ELEMENTS_PER_BEAT / 4.0f;
|
2002-05-19 01:59:48 +00:00
|
|
|
float fFreezeBeat = NoteRowToBeat( fIndex );
|
2002-01-16 19:46:22 +00:00
|
|
|
float fFreezeSeconds = (float)atof( arrayFreezeValues[1] ) / 1000.0f;
|
2001-12-19 01:50:57 +00:00
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
FreezeSegment new_seg;
|
|
|
|
|
new_seg.m_fStartBeat = fFreezeBeat;
|
|
|
|
|
new_seg.m_fFreezeSeconds = fFreezeSeconds;
|
2001-12-19 14:56:22 +00:00
|
|
|
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fFreezeSeconds );
|
2001-12-28 10:15:59 +00:00
|
|
|
|
|
|
|
|
m_FreezeSegments.Add( new_seg ); // add to back for now (we'll sort later)
|
|
|
|
|
SortFreezeSegmentsArray( m_FreezeSegments );
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
else if( sValueName == "#CHANGEBPM" || sValueName == "#BPMCHANGE" )
|
|
|
|
|
{
|
|
|
|
|
CStringArray arrayBPMChangeExpressions;
|
|
|
|
|
split( arrayValueTokens[1], ",", arrayBPMChangeExpressions );
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-12-19 01:50:57 +00:00
|
|
|
for( int b=0; b<arrayBPMChangeExpressions.GetSize(); b++ )
|
|
|
|
|
{
|
|
|
|
|
CStringArray arrayBPMChangeValues;
|
|
|
|
|
split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues );
|
2002-02-28 19:40:40 +00:00
|
|
|
float fIndex = atoi( arrayBPMChangeValues[0] ) * ELEMENTS_PER_BEAT / 4.0f;
|
2002-05-19 01:59:48 +00:00
|
|
|
float fBeat = NoteRowToBeat( fIndex );
|
2002-01-16 19:46:22 +00:00
|
|
|
float fNewBPM = (float)atoi( arrayBPMChangeValues[1] );
|
2001-12-19 01:50:57 +00:00
|
|
|
|
|
|
|
|
BPMSegment new_seg;
|
|
|
|
|
new_seg.m_fStartBeat = fBeat;
|
|
|
|
|
new_seg.m_fBPM = fNewBPM;
|
|
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
// add and sort
|
|
|
|
|
m_BPMSegments.Add( new_seg );
|
2001-12-19 01:50:57 +00:00
|
|
|
SortBPMSegmentsArray( m_BPMSegments );
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-11-03 10:52:42 +00:00
|
|
|
|
|
|
|
|
else if( sValueName == "#SINGLE" || sValueName == "#DOUBLE" || sValueName == "#COUPLE" )
|
|
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
m_arrayNotes.SetSize( m_arrayNotes.GetSize()+1, 1 );
|
|
|
|
|
Notes &new_Notes = m_arrayNotes[ m_arrayNotes.GetSize()-1 ];
|
|
|
|
|
new_Notes.LoadFromDWITokens(
|
2002-03-30 20:00:13 +00:00
|
|
|
arrayValueTokens[0],
|
|
|
|
|
arrayValueTokens[1],
|
|
|
|
|
arrayValueTokens[2],
|
|
|
|
|
arrayValueTokens[3],
|
|
|
|
|
arrayValueTokens.GetSize() == 5 ? arrayValueTokens[4] : ""
|
|
|
|
|
);
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
// do nothing. We don't care about this value name
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
bool Song::LoadFromSMDir( CString sDir )
|
|
|
|
|
{
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "Song::LoadFromSMDir(%s)", sDir );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
// make sure there is a trailing '\\' at the end of sDir
|
|
|
|
|
if( sDir.Right(1) != "\\" )
|
|
|
|
|
sDir += "\\";
|
|
|
|
|
|
|
|
|
|
// save song dir
|
|
|
|
|
m_sSongDir = sDir;
|
|
|
|
|
|
|
|
|
|
// get group name
|
|
|
|
|
CStringArray sDirectoryParts;
|
|
|
|
|
split( m_sSongDir, "\\", sDirectoryParts, true );
|
|
|
|
|
m_sGroupName = sDirectoryParts[1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CStringArray arraySongFileNames;
|
|
|
|
|
GetDirListing( sDir + "*.song", arraySongFileNames );
|
|
|
|
|
if( arraySongFileNames.GetSize() == 0 )
|
|
|
|
|
FatalError( "Couldn't find any SM Song files in '%s'", sDir );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Load the Song info from the first BMS file. Silly BMS duplicates the song info in every
|
|
|
|
|
// file. So, we read the song data from only the first BMS file and assume that the info
|
|
|
|
|
// is identical for every BMS file in the directory.
|
|
|
|
|
m_sSongFilePath = m_sSongDir + arraySongFileNames[0];
|
|
|
|
|
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
CStringArray arrayNotesFileNames;
|
|
|
|
|
GetDirListing( sDir + CString("*.notes"), arrayNotesFileNames );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
// load the Notes from the rest of the BMS files
|
|
|
|
|
for( i=0; i<arrayNotesFileNames.GetSize(); i++ )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
m_arrayNotes.SetSize( m_arrayNotes.GetSize()+1 );
|
|
|
|
|
Notes &new_steps = m_arrayNotes[ m_arrayNotes.GetSize()-1 ];
|
|
|
|
|
new_steps.LoadFromNotesFile( m_sSongDir + arrayNotesFileNames[i] );
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CStdioFile file;
|
|
|
|
|
if( !file.Open( GetSongFilePath(), CFile::modeRead|CFile::shareDenyNone ) )
|
|
|
|
|
FatalError( "Error opening DWI file '%s'.", GetSongFilePath() );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// read the whole file into a sFileText
|
|
|
|
|
CString sFileText;
|
|
|
|
|
CString buffer;
|
|
|
|
|
while( file.ReadString(buffer) )
|
|
|
|
|
sFileText += buffer;
|
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
|
|
// split sFileText into strings containing each value expression
|
|
|
|
|
CStringArray arrayValueStrings;
|
|
|
|
|
split( sFileText, ";", arrayValueStrings, false );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for each value expression string, parse it into a value name and data
|
|
|
|
|
for( i=0; i < arrayValueStrings.GetSize(); i++ )
|
|
|
|
|
{
|
|
|
|
|
CString sValueString = arrayValueStrings[i];
|
|
|
|
|
|
|
|
|
|
// split the value string into tokens
|
|
|
|
|
CStringArray arrayValueTokens;
|
|
|
|
|
split( sValueString, ":", arrayValueTokens, false );
|
|
|
|
|
|
|
|
|
|
if( arrayValueTokens.GetSize() == 0 )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
CString sValueName = arrayValueTokens.GetAt( 0 );
|
|
|
|
|
sValueName.TrimLeft();
|
|
|
|
|
|
|
|
|
|
// handle the data
|
|
|
|
|
if( sValueName == "#TITLE" )
|
2002-04-28 20:42:32 +00:00
|
|
|
GetMainAndSubTitlesFromFullTitle( arrayValueTokens[1], m_sMainTitle, m_sSubTitle );
|
|
|
|
|
|
|
|
|
|
if( sValueName == "#MAINTITLE" )
|
|
|
|
|
m_sMainTitle = arrayValueTokens[1];
|
|
|
|
|
|
|
|
|
|
if( sValueName == "#SUBTITLE" )
|
|
|
|
|
m_sSubTitle = arrayValueTokens[1];
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
else if( sValueName == "#ARTIST" )
|
|
|
|
|
m_sArtist = arrayValueTokens[1];
|
|
|
|
|
|
|
|
|
|
else if( sValueName == "#CREDIT" )
|
|
|
|
|
m_sCredit = arrayValueTokens[1];
|
|
|
|
|
|
|
|
|
|
else if( sValueName == "#BANNER" )
|
|
|
|
|
m_sBannerPath = sDir + "\\" + arrayValueTokens[1];
|
|
|
|
|
|
|
|
|
|
else if( sValueName == "#BACKGROUND" )
|
|
|
|
|
m_sBackgroundPath = sDir + "\\" + arrayValueTokens[1];
|
|
|
|
|
|
|
|
|
|
else if( sValueName == "#BACKGROUNDMOVIE" )
|
|
|
|
|
{
|
|
|
|
|
if( arrayValueTokens[1] != "" )
|
|
|
|
|
m_sBackgroundMoviePath = sDir + "\\" + arrayValueTokens[1];
|
|
|
|
|
}
|
|
|
|
|
else if( sValueName == "#CDTITLE" )
|
|
|
|
|
{
|
|
|
|
|
if( arrayValueTokens[1] != "" )
|
|
|
|
|
m_sCDTitlePath = sDir + "\\" + arrayValueTokens[1];
|
|
|
|
|
}
|
|
|
|
|
else if( sValueName == "#MUSIC" )
|
|
|
|
|
m_sMusicPath = sDir + "\\" + arrayValueTokens[1];
|
|
|
|
|
|
|
|
|
|
else if( sValueName == "#MUSICBYTES" )
|
2002-05-19 01:59:48 +00:00
|
|
|
m_iMusicBytes = atoi( arrayValueTokens[1] );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-04-28 20:42:32 +00:00
|
|
|
else if( sValueName == "#SAMPLESTART" )
|
|
|
|
|
m_fMusicSampleStartSeconds = TimeToSeconds( arrayValueTokens[1] );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-04-28 20:42:32 +00:00
|
|
|
else if( sValueName == "#SAMPLELENGTH" )
|
|
|
|
|
m_fMusicSampleLengthSeconds = TimeToSeconds( arrayValueTokens[1] );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-04-28 20:42:32 +00:00
|
|
|
else if( sValueName == "#OFFSET" )
|
|
|
|
|
m_fOffsetInSeconds = (float)atof( arrayValueTokens[1] );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
else if( sValueName == "#FREEZES" )
|
|
|
|
|
{
|
|
|
|
|
CStringArray arrayFreezeExpressions;
|
|
|
|
|
split( arrayValueTokens[1], ",", arrayFreezeExpressions );
|
|
|
|
|
|
|
|
|
|
for( int f=0; f<arrayFreezeExpressions.GetSize(); f++ )
|
|
|
|
|
{
|
|
|
|
|
CStringArray arrayFreezeValues;
|
|
|
|
|
split( arrayFreezeExpressions[f], "=", arrayFreezeValues );
|
|
|
|
|
float fFreezeBeat = (float)atof( arrayFreezeValues[0] );
|
|
|
|
|
float fFreezeSeconds = (float)atof( arrayFreezeValues[1] );
|
|
|
|
|
|
|
|
|
|
FreezeSegment new_seg;
|
|
|
|
|
new_seg.m_fStartBeat = fFreezeBeat;
|
|
|
|
|
new_seg.m_fFreezeSeconds = fFreezeSeconds;
|
|
|
|
|
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fFreezeSeconds );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
m_FreezeSegments.Add( new_seg ); // add to back for now (we'll sort later)
|
|
|
|
|
SortFreezeSegmentsArray( m_FreezeSegments );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if( sValueName == "#BPMS" )
|
|
|
|
|
{
|
|
|
|
|
CStringArray arrayBPMChangeExpressions;
|
|
|
|
|
split( arrayValueTokens[1], ",", arrayBPMChangeExpressions );
|
|
|
|
|
|
|
|
|
|
for( int b=0; b<arrayBPMChangeExpressions.GetSize(); b++ )
|
|
|
|
|
{
|
|
|
|
|
CStringArray arrayBPMChangeValues;
|
|
|
|
|
split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues );
|
|
|
|
|
float fBeat = (float)atof( arrayBPMChangeValues[0] );
|
|
|
|
|
float fNewBPM = (float)atoi( arrayBPMChangeValues[1] );
|
|
|
|
|
|
|
|
|
|
BPMSegment new_seg;
|
|
|
|
|
new_seg.m_fStartBeat = fBeat;
|
|
|
|
|
new_seg.m_fBPM = fNewBPM;
|
|
|
|
|
|
|
|
|
|
// add and sort
|
|
|
|
|
m_BPMSegments.Add( new_seg );
|
|
|
|
|
SortBPMSegmentsArray( m_BPMSegments );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
2002-05-01 19:14:55 +00:00
|
|
|
LOG->WriteLine( "Unexpected value named '%s'", sValueName );
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-11-25 04:31:44 +00:00
|
|
|
void Song::TidyUpData()
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2002-04-28 20:42:32 +00:00
|
|
|
m_sMainTitle.TrimRight();
|
|
|
|
|
if( m_sMainTitle == "" ) m_sMainTitle = "Untitled song";
|
|
|
|
|
m_sSubTitle.TrimRight();
|
|
|
|
|
if( m_sArtist == "" ) m_sArtist = "Unknown artist";
|
2001-11-27 22:47:30 +00:00
|
|
|
if( m_BPMSegments.GetSize() == 0 )
|
2002-04-16 17:31:00 +00:00
|
|
|
FatalError( "No #BPM specified in '%s.'", GetSongFilePath() );
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
if( m_sMusicPath == "" || !DoesFileExist(GetMusicPath()) )
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2001-11-25 04:31:44 +00:00
|
|
|
CStringArray arrayPossibleMusic;
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.mp3"), arrayPossibleMusic );
|
2001-12-19 14:56:22 +00:00
|
|
|
GetDirListing( m_sSongDir + CString("*.ogg"), arrayPossibleMusic );
|
2001-11-25 04:31:44 +00:00
|
|
|
GetDirListing( m_sSongDir + CString("*.wav"), arrayPossibleMusic );
|
2001-11-03 10:52:42 +00:00
|
|
|
|
2001-11-25 04:31:44 +00:00
|
|
|
if( arrayPossibleMusic.GetSize() != 0 ) // we found a match
|
2001-12-28 10:15:59 +00:00
|
|
|
m_sMusicPath = m_sSongDir + arrayPossibleMusic[0];
|
2001-11-25 04:31:44 +00:00
|
|
|
else
|
2001-12-28 10:15:59 +00:00
|
|
|
m_sMusicPath = "";
|
2002-04-16 17:31:00 +00:00
|
|
|
// FatalError( ssprintf("Music could not be found. Please check the Song file '%s' and verify the specified #MUSIC exists.", GetSongFilePath()) );
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
2001-12-28 10:15:59 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
// Save length of music
|
|
|
|
|
if( GetMusicPath() != "" )
|
|
|
|
|
{
|
|
|
|
|
RageSoundStream sound;
|
|
|
|
|
sound.Load( GetMusicPath() );
|
|
|
|
|
m_fMusicLength = sound.GetLengthSeconds();
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
if( !DoesFileExist(GetBannerPath()) )
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2002-01-16 10:01:32 +00:00
|
|
|
m_sBannerPath = "";
|
2001-12-19 14:56:22 +00:00
|
|
|
// find the smallest image in the directory
|
|
|
|
|
|
2001-11-25 04:31:44 +00:00
|
|
|
CStringArray arrayPossibleBanners;
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.png"), arrayPossibleBanners );
|
2001-12-19 14:56:22 +00:00
|
|
|
GetDirListing( m_sSongDir + CString("*.jpg"), arrayPossibleBanners );
|
2001-11-25 04:31:44 +00:00
|
|
|
GetDirListing( m_sSongDir + CString("*.bmp"), arrayPossibleBanners );
|
|
|
|
|
|
2001-12-20 12:37:38 +00:00
|
|
|
DWORD dwSmallestFileSoFar = 0xFFFFFFFF;
|
2001-12-28 10:15:59 +00:00
|
|
|
CString sSmallestFileSoFar = "";
|
2001-12-19 14:56:22 +00:00
|
|
|
|
|
|
|
|
for( int i=0; i<arrayPossibleBanners.GetSize(); i++ )
|
|
|
|
|
{
|
2001-12-20 12:37:38 +00:00
|
|
|
DWORD this_size = GetFileSizeInBytes( m_sSongDir + arrayPossibleBanners[i] );
|
|
|
|
|
if( this_size < dwSmallestFileSoFar ) // we have a new leader!
|
2001-12-19 14:56:22 +00:00
|
|
|
{
|
2001-12-20 12:37:38 +00:00
|
|
|
dwSmallestFileSoFar = this_size;
|
2001-12-28 10:15:59 +00:00
|
|
|
sSmallestFileSoFar = m_sSongDir + arrayPossibleBanners[i];
|
2001-12-19 14:56:22 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
if( sSmallestFileSoFar != "" ) // we found a match
|
|
|
|
|
m_sBannerPath = sSmallestFileSoFar;
|
2001-11-25 04:31:44 +00:00
|
|
|
else
|
2001-12-28 10:15:59 +00:00
|
|
|
m_sBannerPath = "";
|
|
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
//FatalError( ssprintf("Banner could not be found. Please check the Song file '%s' and verify the specified #BANNER exists.", GetSongFilePath()) );
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
2002-01-16 10:01:32 +00:00
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
if( !DoesFileExist(GetBackgroundPath()) )
|
2001-11-03 10:52:42 +00:00
|
|
|
{
|
2002-01-16 10:01:32 +00:00
|
|
|
m_sBackgroundPath = "";
|
2001-12-19 14:56:22 +00:00
|
|
|
// find the largest image in the directory
|
|
|
|
|
|
|
|
|
|
CStringArray arrayPossibleBackgrounds;
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.png"), arrayPossibleBackgrounds );
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.jpg"), arrayPossibleBackgrounds );
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.bmp"), arrayPossibleBackgrounds );
|
|
|
|
|
|
2001-12-20 12:37:38 +00:00
|
|
|
DWORD dwLargestFileSoFar = 0;
|
2001-12-28 10:15:59 +00:00
|
|
|
CString sLargestFileSoFar = "";
|
2001-11-25 04:31:44 +00:00
|
|
|
|
2001-12-19 14:56:22 +00:00
|
|
|
for( int i=0; i<arrayPossibleBackgrounds.GetSize(); i++ )
|
|
|
|
|
{
|
2001-12-20 12:37:38 +00:00
|
|
|
DWORD this_size = GetFileSizeInBytes( m_sSongDir + arrayPossibleBackgrounds[i] );
|
|
|
|
|
if( this_size > dwLargestFileSoFar ) // we have a new leader!
|
2001-12-19 14:56:22 +00:00
|
|
|
{
|
2001-12-20 12:37:38 +00:00
|
|
|
dwLargestFileSoFar = this_size;
|
2001-12-28 10:15:59 +00:00
|
|
|
sLargestFileSoFar = m_sSongDir + arrayPossibleBackgrounds[i];
|
2001-12-19 14:56:22 +00:00
|
|
|
}
|
|
|
|
|
}
|
2002-01-16 10:01:32 +00:00
|
|
|
|
2001-12-28 10:15:59 +00:00
|
|
|
if( sLargestFileSoFar != "" ) // we found a match
|
|
|
|
|
m_sBackgroundPath = sLargestFileSoFar;
|
2001-11-03 10:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
2002-01-16 10:01:32 +00:00
|
|
|
if( !DoesFileExist(GetBackgroundMoviePath()) )
|
|
|
|
|
{
|
|
|
|
|
m_sBackgroundMoviePath = "";
|
|
|
|
|
|
|
|
|
|
CStringArray arrayPossibleBackgroundMovies;
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.avi"), arrayPossibleBackgroundMovies );
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.mpg"), arrayPossibleBackgroundMovies );
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.mpeg"), arrayPossibleBackgroundMovies );
|
|
|
|
|
|
|
|
|
|
if( arrayPossibleBackgroundMovies.GetSize() > 0 ) // we found a match
|
|
|
|
|
m_sBackgroundMoviePath = arrayPossibleBackgroundMovies[0];
|
|
|
|
|
}
|
2001-11-30 09:38:35 +00:00
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
if( !DoesFileExist(GetCDTitlePath()) )
|
2001-11-30 09:38:35 +00:00
|
|
|
{
|
2002-04-16 17:31:00 +00:00
|
|
|
m_sCDTitlePath = "";
|
2001-11-30 09:38:35 +00:00
|
|
|
}
|
2002-05-19 01:59:48 +00:00
|
|
|
|
|
|
|
|
for( int i=0; i<m_arrayNotes.GetSize(); i++ )
|
|
|
|
|
{
|
|
|
|
|
Notes* pNM = &m_arrayNotes[i];
|
|
|
|
|
|
|
|
|
|
float fMusicLength = m_fMusicLength;
|
|
|
|
|
if( fMusicLength == 0 )
|
|
|
|
|
fMusicLength = 100;
|
|
|
|
|
|
|
|
|
|
pNM->m_fRadarValues[RADAR_STREAM] = pNM->GetNoteData()->GetStreamRadarValue( fMusicLength );
|
|
|
|
|
pNM->m_fRadarValues[RADAR_VOLTAGE] = pNM->GetNoteData()->GetVoltageRadarValue( fMusicLength );
|
|
|
|
|
pNM->m_fRadarValues[RADAR_AIR] = pNM->GetNoteData()->GetAirRadarValue( fMusicLength );
|
|
|
|
|
pNM->m_fRadarValues[RADAR_CHAOS] = pNM->GetNoteData()->GetChaosRadarValue( fMusicLength );
|
|
|
|
|
pNM->m_fRadarValues[RADAR_FREEZE] = pNM->GetNoteData()->GetFreezeRadarValue( fMusicLength );
|
|
|
|
|
}
|
2001-11-30 09:38:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-05-27 08:23:27 +00:00
|
|
|
void Song::GetNotesThatMatch( NotesType nt, CArray<Notes*, Notes*>& arrayAddTo )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
for( int i=0; i<m_arrayNotes.GetSize(); i++ ) // for each of the Song's Notes
|
2002-05-27 08:23:27 +00:00
|
|
|
if( m_arrayNotes[i].m_NotesType == nt )
|
|
|
|
|
arrayAddTo.Add( &m_arrayNotes[i] );
|
2001-12-28 10:15:59 +00:00
|
|
|
}
|
|
|
|
|
|
2002-01-16 10:01:32 +00:00
|
|
|
|
2002-05-27 08:23:27 +00:00
|
|
|
const int FILE_CACHE_VERSION = 10; // increment this when the cache file format changes
|
2002-05-19 01:59:48 +00:00
|
|
|
|
|
|
|
|
void Song::SaveToCacheFile()
|
2002-02-11 04:46:31 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
LOG->WriteLine( "Song::SaveToCacheFile()" );
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
int i;
|
|
|
|
|
CString sCacheFilePath = GetCacheFilePath();
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
FILE* file = fopen( sCacheFilePath, "w" );
|
|
|
|
|
ASSERT( file != NULL );
|
|
|
|
|
if( file == NULL )
|
|
|
|
|
return;
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
fprintf( file, "%d\n", FILE_CACHE_VERSION );
|
|
|
|
|
fprintf( file, "%u\n", GetHashForDirectory(m_sSongDir) );
|
|
|
|
|
WriteStringToFile( file, m_sSongDir );
|
|
|
|
|
WriteStringToFile( file, m_sSongFilePath );
|
|
|
|
|
WriteStringToFile( file, m_sGroupName );
|
|
|
|
|
|
|
|
|
|
WriteStringToFile( file, m_sMainTitle );
|
|
|
|
|
WriteStringToFile( file, m_sSubTitle );
|
|
|
|
|
WriteStringToFile( file, m_sArtist );
|
|
|
|
|
WriteStringToFile( file, m_sCredit );
|
|
|
|
|
fprintf( file, "%f\n", m_fOffsetInSeconds );
|
|
|
|
|
|
|
|
|
|
WriteStringToFile( file, m_sMusicPath );
|
|
|
|
|
fprintf( file, "%d\n", m_iMusicBytes );
|
|
|
|
|
fprintf( file, "%f\n", m_fMusicLength );
|
|
|
|
|
fprintf( file, "%f\n", m_fMusicSampleStartSeconds );
|
|
|
|
|
fprintf( file, "%f\n", m_fMusicSampleLengthSeconds );
|
|
|
|
|
WriteStringToFile( file, m_sBannerPath );
|
|
|
|
|
WriteStringToFile( file, m_sBackgroundPath );
|
|
|
|
|
WriteStringToFile( file, m_sBackgroundMoviePath );
|
|
|
|
|
WriteStringToFile( file, m_sCDTitlePath );
|
|
|
|
|
|
|
|
|
|
fprintf( file, "%d\n", m_BPMSegments.GetSize() );
|
|
|
|
|
for( i=0; i<m_BPMSegments.GetSize(); i++ )
|
|
|
|
|
fprintf( file, "%f,%f\n", m_BPMSegments[i].m_fStartBeat, m_BPMSegments[i].m_fBPM );
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
fprintf( file, "%d\n", m_FreezeSegments.GetSize() );
|
|
|
|
|
for( i=0; i<m_FreezeSegments.GetSize(); i++ )
|
|
|
|
|
fprintf( file, "%f,%f\n", m_FreezeSegments[i].m_fStartBeat, m_FreezeSegments[i].m_fFreezeSeconds );
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
fprintf( file, "%d\n", m_arrayNotes.GetSize() );
|
|
|
|
|
for( i=0; i<m_arrayNotes.GetSize(); i++ )
|
|
|
|
|
m_arrayNotes[i].WriteToCacheFile( file );
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
fclose( file );
|
|
|
|
|
}
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
bool Song::LoadFromCacheFile( bool bLoadNoteData )
|
|
|
|
|
{
|
|
|
|
|
LOG->WriteLine( "Song::LoadFromCacheFile( %i )", bLoadNoteData );
|
2002-02-25 08:54:10 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
int i;
|
|
|
|
|
CString sCacheFilePath = GetCacheFilePath();
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
LOG->WriteLine( "cache file is '%s'.", sCacheFilePath );
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
FILE* file = fopen( sCacheFilePath, "r" );
|
|
|
|
|
if( file == NULL )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
int iCacheVersion;
|
|
|
|
|
fscanf( file, "%d\n", &iCacheVersion );
|
|
|
|
|
if( iCacheVersion != FILE_CACHE_VERSION )
|
2002-02-11 04:46:31 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
LOG->WriteLine( "Cache file versions don't match '%s'.", sCacheFilePath );
|
|
|
|
|
fclose( file );
|
|
|
|
|
DeleteCacheFile();
|
|
|
|
|
return false;
|
2002-02-11 04:46:31 +00:00
|
|
|
}
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
ULONG hash;
|
|
|
|
|
fscanf( file, "%u\n", &hash );
|
|
|
|
|
if( hash != GetHashForDirectory(m_sSongDir) )
|
|
|
|
|
{
|
|
|
|
|
LOG->WriteLine( "Cache file is out of date.", sCacheFilePath );
|
|
|
|
|
fclose( file );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
ReadStringFromFile( file, m_sSongDir );
|
|
|
|
|
ReadStringFromFile( file, m_sSongFilePath );
|
|
|
|
|
ReadStringFromFile( file, m_sGroupName );
|
|
|
|
|
|
|
|
|
|
ReadStringFromFile( file, m_sMainTitle );
|
|
|
|
|
ReadStringFromFile( file, m_sSubTitle );
|
|
|
|
|
ReadStringFromFile( file, m_sArtist );
|
|
|
|
|
ReadStringFromFile( file, m_sCredit );
|
|
|
|
|
fscanf( file, "%f\n", &m_fOffsetInSeconds );
|
|
|
|
|
|
|
|
|
|
ReadStringFromFile( file, m_sMusicPath );
|
|
|
|
|
fscanf( file, "%d\n", &m_iMusicBytes );
|
|
|
|
|
fscanf( file, "%f\n", &m_fMusicLength );
|
|
|
|
|
fscanf( file, "%f\n", &m_fMusicSampleStartSeconds );
|
|
|
|
|
fscanf( file, "%f\n", &m_fMusicSampleLengthSeconds );
|
|
|
|
|
ReadStringFromFile( file, m_sBannerPath );
|
|
|
|
|
ReadStringFromFile( file, m_sBackgroundPath );
|
|
|
|
|
ReadStringFromFile( file, m_sBackgroundMoviePath );
|
|
|
|
|
ReadStringFromFile( file, m_sCDTitlePath );
|
|
|
|
|
|
|
|
|
|
int iNumBPMSegments;
|
|
|
|
|
fscanf( file, "%d\n", &iNumBPMSegments );
|
|
|
|
|
m_BPMSegments.SetSize( iNumBPMSegments );
|
|
|
|
|
for( i=0; i<iNumBPMSegments; i++ )
|
|
|
|
|
fscanf( file, "%f,%f\n", &m_BPMSegments[i].m_fStartBeat, &m_BPMSegments[i].m_fBPM );
|
|
|
|
|
|
|
|
|
|
int iNumFreezeSegments;
|
|
|
|
|
fscanf( file, "%d\n", &iNumFreezeSegments );
|
|
|
|
|
m_FreezeSegments.SetSize( iNumFreezeSegments );
|
|
|
|
|
for( i=0; i<iNumFreezeSegments; i++ )
|
|
|
|
|
fscanf( file, "%f,%f\n", &m_FreezeSegments[i].m_fStartBeat, &m_FreezeSegments[i].m_fFreezeSeconds );
|
|
|
|
|
|
|
|
|
|
int iNumNotes;
|
|
|
|
|
fscanf( file, "%d\n", &iNumNotes );
|
|
|
|
|
m_arrayNotes.SetSize( iNumNotes );
|
|
|
|
|
for( i=0; i<iNumNotes; i++ )
|
|
|
|
|
m_arrayNotes[i].ReadFromCacheFile( file, bLoadNoteData );
|
|
|
|
|
|
|
|
|
|
fclose( file );
|
|
|
|
|
return true;
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
2002-05-19 01:59:48 +00:00
|
|
|
|
|
|
|
|
void Song::DeleteCacheFile()
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
DeleteFile( GetCacheFilePath() );
|
|
|
|
|
}
|
2002-04-16 17:31:00 +00:00
|
|
|
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
void Song::SaveToSMDir()
|
|
|
|
|
{
|
|
|
|
|
LOG->WriteLine( "Song::SaveToSMDir()" );
|
2002-04-16 17:31:00 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
int i;
|
2002-04-16 17:31:00 +00:00
|
|
|
//
|
|
|
|
|
// rename all old files to avoid confusion
|
|
|
|
|
//
|
|
|
|
|
CStringArray arrayOldFileNames;
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.bms"), arrayOldFileNames );
|
|
|
|
|
GetDirListing( m_sSongDir + CString("*.dwi"), arrayOldFileNames );
|
|
|
|
|
|
|
|
|
|
for( i=0; i<arrayOldFileNames.GetSize(); i++ )
|
|
|
|
|
{
|
|
|
|
|
CString sOldPath = m_sSongDir + arrayOldFileNames[i];
|
|
|
|
|
CString sNewPath = sOldPath + ".old";
|
|
|
|
|
MoveFile( sOldPath, sNewPath );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CString sDir, sFName, sExt;
|
|
|
|
|
splitrelpath( GetSongFilePath(), sDir, sFName, sExt );
|
|
|
|
|
m_sSongFilePath = m_sSongDir + sFName + ".song";
|
|
|
|
|
|
|
|
|
|
CStdioFile file;
|
|
|
|
|
if( !file.Open( m_sSongFilePath, CFile::modeWrite | CFile::modeCreate ) )
|
|
|
|
|
FatalError( "Error opening song file '%s' for writing.", m_sSongFilePath );
|
|
|
|
|
|
2002-04-28 20:42:32 +00:00
|
|
|
file.WriteString( ssprintf("#MAINTITLE:%s;\n", m_sMainTitle) );
|
|
|
|
|
file.WriteString( ssprintf("#SUBTITLE:%s;\n", m_sSubTitle) );
|
2002-04-16 17:31:00 +00:00
|
|
|
file.WriteString( ssprintf("#ARTIST:%s;\n", m_sArtist) );
|
|
|
|
|
file.WriteString( ssprintf("#CREDIT:%s;\n", m_sCredit) );
|
|
|
|
|
|
|
|
|
|
if( m_sBannerPath != "" )
|
|
|
|
|
{
|
|
|
|
|
splitrelpath( m_sBannerPath, sDir, sFName, sExt );
|
|
|
|
|
file.WriteString( ssprintf("#BANNER:%s;\n", sFName+"."+sExt) );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
file.WriteString( "#BANNER:;\n" );
|
|
|
|
|
|
|
|
|
|
if( m_sBackgroundPath != "" )
|
|
|
|
|
{
|
|
|
|
|
splitrelpath( m_sBackgroundPath, sDir, sFName, sExt );
|
|
|
|
|
file.WriteString( ssprintf("#BACKGROUND:%s;\n", sFName+"."+sExt) );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
file.WriteString( "#BACKGROUND:;\n" );
|
|
|
|
|
|
|
|
|
|
if( m_sBackgroundMoviePath != "" )
|
|
|
|
|
{
|
|
|
|
|
splitrelpath( m_sBackgroundMoviePath, sDir, sFName, sExt );
|
|
|
|
|
file.WriteString( ssprintf("#BACKGROUNDMOVIE:%s;\n", sFName+"."+sExt) );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
file.WriteString( "#BACKGROUNDMOVIE:;\n" );
|
|
|
|
|
|
|
|
|
|
if( m_sCDTitlePath != "" )
|
|
|
|
|
{
|
|
|
|
|
splitrelpath( m_sCDTitlePath, sDir, sFName, sExt );
|
|
|
|
|
file.WriteString( ssprintf("#CDTITLE:%s;\n", sFName+"."+sExt) );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
file.WriteString( "#CDTITLE:;\n" );
|
|
|
|
|
|
|
|
|
|
if( m_sMusicPath != "" )
|
|
|
|
|
{
|
|
|
|
|
splitrelpath( m_sMusicPath, sDir, sFName, sExt );
|
|
|
|
|
file.WriteString( ssprintf("#MUSIC:%s;\n", sFName+"."+sExt) );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
file.WriteString( "#MUSIC:;\n" );
|
|
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
file.WriteString( ssprintf("#MUSICBYTES:%u;\n", m_iMusicBytes) );
|
2002-04-16 17:31:00 +00:00
|
|
|
file.WriteString( ssprintf("#OFFSET:%f;\n", m_fOffsetInSeconds) );
|
|
|
|
|
|
2002-04-28 20:42:32 +00:00
|
|
|
file.WriteString( ssprintf("#SAMPLESTART:%f;\n", m_fMusicSampleStartSeconds) );
|
|
|
|
|
file.WriteString( ssprintf("#SAMPLELENGTH:%f;\n", m_fMusicSampleLengthSeconds) );
|
|
|
|
|
|
2002-04-16 17:31:00 +00:00
|
|
|
file.WriteString( "#FREEZES:" );
|
|
|
|
|
for( i=0; i<m_FreezeSegments.GetSize(); i++ )
|
|
|
|
|
{
|
|
|
|
|
FreezeSegment &fs = m_FreezeSegments[i];
|
|
|
|
|
|
|
|
|
|
file.WriteString( ssprintf("%f=%f", fs.m_fStartBeat, fs.m_fFreezeSeconds) );
|
|
|
|
|
if( i != m_FreezeSegments.GetSize()-1 )
|
|
|
|
|
file.WriteString( "," );
|
|
|
|
|
}
|
|
|
|
|
file.WriteString( ";\n" );
|
|
|
|
|
|
|
|
|
|
file.WriteString( "#BPMS:" );
|
|
|
|
|
for( i=0; i<m_BPMSegments.GetSize(); i++ )
|
|
|
|
|
{
|
|
|
|
|
BPMSegment &bs = m_BPMSegments[i];
|
|
|
|
|
|
|
|
|
|
file.WriteString( ssprintf("%f=%f", bs.m_fStartBeat, bs.m_fBPM) );
|
|
|
|
|
if( i != m_BPMSegments.GetSize()-1 )
|
|
|
|
|
file.WriteString( "," );
|
|
|
|
|
}
|
|
|
|
|
file.WriteString( ";\n" );
|
|
|
|
|
|
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
|
|
//
|
2002-05-19 01:59:48 +00:00
|
|
|
// Save all Notess for this file
|
2002-04-16 17:31:00 +00:00
|
|
|
//
|
2002-05-19 01:59:48 +00:00
|
|
|
for( i=0; i<m_arrayNotes.GetSize(); i++ )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
m_arrayNotes[i].SaveToSMDir( m_sSongDir );
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
2002-02-11 04:46:31 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-27 08:23:27 +00:00
|
|
|
Grade Song::GetGradeForDifficultyClass( NotesType nt, DifficultyClass dc )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
CArray<Notes*, Notes*> arrayNotess;
|
2002-05-27 08:23:27 +00:00
|
|
|
this->GetNotesThatMatch( nt, arrayNotess );
|
2002-05-19 01:59:48 +00:00
|
|
|
SortNotesArrayByDifficultyClass( arrayNotess );
|
2002-02-11 04:46:31 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
for( int i=0; i<arrayNotess.GetSize(); i++ )
|
2002-04-16 17:31:00 +00:00
|
|
|
{
|
2002-05-19 01:59:48 +00:00
|
|
|
Notes* pNotes = arrayNotess[i];
|
|
|
|
|
if( pNotes->m_DifficultyClass == dc )
|
|
|
|
|
return pNotes->m_TopGrade;
|
2002-04-16 17:31:00 +00:00
|
|
|
}
|
|
|
|
|
return GRADE_NO_DATA;
|
|
|
|
|
}
|
2002-01-16 10:01:32 +00:00
|
|
|
|
2002-05-19 01:59:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-02-11 04:46:31 +00:00
|
|
|
/////////////////////////////////////
|
|
|
|
|
// Sorting
|
|
|
|
|
/////////////////////////////////////
|
2002-01-16 10:01:32 +00:00
|
|
|
|
|
|
|
|
int CompareSongPointersByTitle(const void *arg1, const void *arg2)
|
|
|
|
|
{
|
|
|
|
|
Song* pSong1 = *(Song**)arg1;
|
|
|
|
|
Song* pSong2 = *(Song**)arg2;
|
|
|
|
|
|
2002-04-28 20:42:32 +00:00
|
|
|
CString sTitle1 = pSong1->GetMainTitle();
|
|
|
|
|
CString sTitle2 = pSong2->GetMainTitle();
|
2002-01-16 10:01:32 +00:00
|
|
|
|
|
|
|
|
CString sFilePath1 = pSong1->GetSongFilePath(); // this is unique among songs
|
|
|
|
|
CString sFilePath2 = pSong2->GetSongFilePath();
|
|
|
|
|
|
|
|
|
|
CString sCompareString1 = sTitle1 + sFilePath1;
|
|
|
|
|
CString sCompareString2 = sTitle2 + sFilePath2;
|
|
|
|
|
|
2002-03-30 20:00:13 +00:00
|
|
|
return CompareCStringsAsc( (void*)&sCompareString1, (void*)&sCompareString2 );
|
2002-01-16 10:01:32 +00:00
|
|
|
}
|
|
|
|
|
|
2002-02-11 04:46:31 +00:00
|
|
|
void SortSongPointerArrayByTitle( CArray<Song*, Song*> &arraySongPointers )
|
2002-01-16 10:01:32 +00:00
|
|
|
{
|
|
|
|
|
qsort( arraySongPointers.GetData(), arraySongPointers.GetSize(), sizeof(Song*), CompareSongPointersByTitle );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CompareSongPointersByBPM(const void *arg1, const void *arg2)
|
|
|
|
|
{
|
|
|
|
|
Song* pSong1 = *(Song**)arg1;
|
|
|
|
|
Song* pSong2 = *(Song**)arg2;
|
|
|
|
|
|
|
|
|
|
float fMinBPM1, fMaxBPM1, fMinBPM2, fMaxBPM2;
|
|
|
|
|
pSong1->GetMinMaxBPM( fMinBPM1, fMaxBPM1 );
|
|
|
|
|
pSong2->GetMinMaxBPM( fMinBPM2, fMaxBPM2 );
|
|
|
|
|
|
|
|
|
|
CString sFilePath1 = pSong1->GetSongFilePath(); // this is unique among songs
|
|
|
|
|
CString sFilePath2 = pSong2->GetSongFilePath();
|
|
|
|
|
|
|
|
|
|
if( fMaxBPM1 < fMaxBPM2 )
|
|
|
|
|
return -1;
|
|
|
|
|
else if( fMaxBPM1 == fMaxBPM2 )
|
2002-03-30 20:00:13 +00:00
|
|
|
return CompareCStringsAsc( (void*)&sFilePath1, (void*)&sFilePath2 );
|
2002-01-16 10:01:32 +00:00
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-11 04:46:31 +00:00
|
|
|
void SortSongPointerArrayByBPM( CArray<Song*, Song*> &arraySongPointers )
|
2002-01-16 10:01:32 +00:00
|
|
|
{
|
|
|
|
|
qsort( arraySongPointers.GetData(), arraySongPointers.GetSize(), sizeof(Song*), CompareSongPointersByBPM );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int CompareSongPointersByArtist(const void *arg1, const void *arg2)
|
|
|
|
|
{
|
|
|
|
|
Song* pSong1 = *(Song**)arg1;
|
|
|
|
|
Song* pSong2 = *(Song**)arg2;
|
|
|
|
|
|
|
|
|
|
CString sArtist1 = pSong1->GetArtist();
|
|
|
|
|
CString sArtist2 = pSong2->GetArtist();
|
|
|
|
|
|
2002-02-24 01:43:11 +00:00
|
|
|
if( sArtist1 < sArtist2 )
|
|
|
|
|
return -1;
|
|
|
|
|
else if( sArtist1 == sArtist2 )
|
|
|
|
|
return CompareSongPointersByTitle( arg1, arg2 );
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
2002-01-16 10:01:32 +00:00
|
|
|
}
|
|
|
|
|
|
2002-02-11 04:46:31 +00:00
|
|
|
void SortSongPointerArrayByArtist( CArray<Song*, Song*> &arraySongPointers )
|
2002-01-16 10:01:32 +00:00
|
|
|
{
|
|
|
|
|
qsort( arraySongPointers.GetData(), arraySongPointers.GetSize(), sizeof(Song*), CompareSongPointersByArtist );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CompareSongPointersByGroup(const void *arg1, const void *arg2)
|
|
|
|
|
{
|
|
|
|
|
Song* pSong1 = *(Song**)arg1;
|
|
|
|
|
Song* pSong2 = *(Song**)arg2;
|
|
|
|
|
|
|
|
|
|
CString sGroup1 = pSong1->GetGroupName();
|
|
|
|
|
CString sGroup2 = pSong2->GetGroupName();
|
|
|
|
|
|
2002-02-24 01:43:11 +00:00
|
|
|
if( sGroup1 < sGroup2 )
|
|
|
|
|
return -1;
|
|
|
|
|
else if( sGroup1 == sGroup2 )
|
|
|
|
|
return CompareSongPointersByTitle( arg1, arg2 );
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
2002-01-16 10:01:32 +00:00
|
|
|
}
|
|
|
|
|
|
2002-02-11 04:46:31 +00:00
|
|
|
void SortSongPointerArrayByGroup( CArray<Song*, Song*> &arraySongPointers )
|
2002-01-16 10:01:32 +00:00
|
|
|
{
|
|
|
|
|
qsort( arraySongPointers.GetData(), arraySongPointers.GetSize(), sizeof(Song*), CompareSongPointersByGroup );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CompareSongPointersByMostPlayed(const void *arg1, const void *arg2)
|
|
|
|
|
{
|
|
|
|
|
Song* pSong1 = *(Song**)arg1;
|
|
|
|
|
Song* pSong2 = *(Song**)arg2;
|
|
|
|
|
|
2002-02-02 05:11:12 +00:00
|
|
|
int iNumTimesPlayed1 = pSong1->GetNumTimesPlayed();
|
|
|
|
|
int iNumTimesPlayed2 = pSong2->GetNumTimesPlayed();
|
2002-01-16 10:01:32 +00:00
|
|
|
|
2002-02-24 01:43:11 +00:00
|
|
|
if( iNumTimesPlayed1 < iNumTimesPlayed2 )
|
2002-01-16 10:01:32 +00:00
|
|
|
return -1;
|
|
|
|
|
else if( iNumTimesPlayed1 == iNumTimesPlayed2 )
|
2002-02-24 01:43:11 +00:00
|
|
|
return CompareSongPointersByTitle( arg1, arg2 );
|
2002-01-16 10:01:32 +00:00
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-11 04:46:31 +00:00
|
|
|
void SortSongPointerArrayByMostPlayed( CArray<Song*, Song*> &arraySongPointers )
|
2002-01-16 10:01:32 +00:00
|
|
|
{
|
|
|
|
|
qsort( arraySongPointers.GetData(), arraySongPointers.GetSize(), sizeof(Song*), CompareSongPointersByMostPlayed );
|
|
|
|
|
}
|
2002-04-16 17:31:00 +00:00
|
|
|
|