it. Catalog writing (still for only one course) down to .381s; still too much time to be spending for one course on every load. I'd make catalog writing only happen if something has changed, but that would mean introducing some form of course caching, which I'd rather avoid ...
231 lines
8.8 KiB
C++
231 lines
8.8 KiB
C++
/* Song - Holds all music metadata and steps for one song. */
|
|
|
|
#ifndef SONG_H
|
|
#define SONG_H
|
|
|
|
#include "PlayerNumber.h"
|
|
#include "GameConstantsAndTypes.h"
|
|
#include "Grade.h"
|
|
#include "TimingData.h"
|
|
|
|
class Steps;
|
|
class StyleDef;
|
|
class NotesLoader;
|
|
class LyricsLoader;
|
|
class Profile;
|
|
class StepsID;
|
|
|
|
#define MAX_EDITS_PER_SONG_PER_PROFILE 5
|
|
#define MAX_EDITS_PER_SONG 5*NUM_PROFILE_SLOTS
|
|
|
|
extern const int FILE_CACHE_VERSION;
|
|
|
|
|
|
struct BackgroundChange
|
|
{
|
|
BackgroundChange() { m_fStartBeat=-1; m_fRate=1; m_bFadeLast=false; m_bRewindMovie=false; m_bLoop=true; };
|
|
BackgroundChange( float s, CString n, float r=1.f, bool f=false, bool m=false, bool l=true ) { m_fStartBeat=s; m_sBGName=n; m_fRate=r; m_bFadeLast=f; m_bRewindMovie=m; m_bLoop=l; };
|
|
float m_fStartBeat;
|
|
CString m_sBGName;
|
|
float m_fRate;
|
|
bool m_bFadeLast;
|
|
bool m_bRewindMovie;
|
|
bool m_bLoop;
|
|
};
|
|
|
|
void SortBackgroundChangesArray( vector<BackgroundChange> &arrayBackgroundChanges );
|
|
|
|
struct LyricSegment
|
|
{
|
|
float m_fStartTime;
|
|
CString m_sLyric;
|
|
RageColor m_Color;
|
|
};
|
|
|
|
|
|
class Song
|
|
{
|
|
CString m_sSongDir;
|
|
|
|
public:
|
|
/* Set when this song should be displayed in the music wheel: */
|
|
enum SelectionDisplay { SHOW_ALWAYS, /* all the time */
|
|
SHOW_ROULETTE, /* only when rouletting */
|
|
SHOW_NEVER } /* never (unless song hiding is turned off) */
|
|
m_SelectionDisplay;
|
|
|
|
Song();
|
|
~Song();
|
|
void Reset();
|
|
|
|
NotesLoader *MakeLoader( CString sDir ) const;
|
|
|
|
bool LoadFromSongDir( CString sDir );
|
|
void RevertFromDisk( bool bAllowNotesLoss=false );
|
|
|
|
void TidyUpData(); // call after loading to clean up invalid data
|
|
void ReCalculateRadarValuesAndLastBeat(); // called by TidyUpData, and after saving
|
|
void TranslateTitles(); // called by TidyUpData
|
|
|
|
void SaveToSMFile( CString sPath, bool bSavingCache );
|
|
void Save(); // saves SM and DWI
|
|
void SaveToCacheFile();
|
|
void SaveToDWIFile();
|
|
|
|
const CString &GetSongFilePath() const;
|
|
CString GetCacheFilePath() const;
|
|
|
|
void AddAutoGenNotes();
|
|
void AutoGen( StepsType ntTo, StepsType ntFrom ); // create Steps of type ntTo from Steps of type ntFrom
|
|
void RemoveAutoGenNotes();
|
|
|
|
/* Directory this song data came from: */
|
|
const CString &GetSongDir() const { return m_sSongDir; }
|
|
|
|
/* Filename associated with this file. This will always have
|
|
* an .SM extension. If we loaded an .SM, this will point to
|
|
* it, but if we loaded any other type, this will point to a
|
|
* generated .SM filename. */
|
|
CString m_sSongFileName;
|
|
|
|
CString m_sGroupName;
|
|
|
|
ProfileSlot m_LoadedFromProfile; // PROFILE_SLOT_INVALID if wasn't loaded from a profile
|
|
bool m_bIsSymLink;
|
|
|
|
CString m_sMainTitle, m_sSubTitle, m_sArtist;
|
|
CString m_sMainTitleTranslit, m_sSubTitleTranslit, m_sArtistTranslit;
|
|
|
|
/* If PREFSMAN->m_bShowNative is off, these are the same as GetTranslit* below.
|
|
* Otherwise, they return the main titles. */
|
|
CString GetDisplayMainTitle() const;
|
|
CString GetDisplaySubTitle() const;
|
|
CString GetDisplayArtist() const;
|
|
|
|
/* Returns the transliterated titles, if any; otherwise returns the main titles. */
|
|
CString GetTranslitMainTitle() const { return m_sMainTitleTranslit.size()? m_sMainTitleTranslit: m_sMainTitle; }
|
|
CString GetTranslitSubTitle() const { return m_sSubTitleTranslit.size()? m_sSubTitleTranslit: m_sSubTitle; }
|
|
CString GetTranslitArtist() const { return m_sArtistTranslit.size()? m_sArtistTranslit:m_sArtist; }
|
|
|
|
/* "title subtitle" */
|
|
CString GetFullDisplayTitle() const;
|
|
CString GetFullTranslitTitle() const;
|
|
|
|
/* This is read and saved, but never actually used. */
|
|
CString m_sCredit;
|
|
|
|
CString m_sMusicFile;
|
|
float m_fMusicLengthSeconds;
|
|
float m_fFirstBeat;
|
|
float m_fLastBeat;
|
|
float m_fMusicSampleStartSeconds;
|
|
float m_fMusicSampleLengthSeconds;
|
|
enum { DISPLAY_ACTUAL, DISPLAY_SPECIFIED, DISPLAY_RANDOM } m_DisplayBPMType;
|
|
float m_fSpecifiedBPMMin;
|
|
float m_fSpecifiedBPMMax; // if a range, then Min != Max
|
|
|
|
CString m_sBannerFile;
|
|
CString m_sLyricsFile;
|
|
CString m_sBackgroundFile;
|
|
CString m_sCDTitleFile;
|
|
|
|
CString GetMusicPath() const;
|
|
CString GetBannerPath() const;
|
|
CString GetLyricsPath() const;
|
|
CString GetBackgroundPath() const;
|
|
CString GetCDTitlePath() const;
|
|
|
|
/* For loading only: */
|
|
bool m_bHasMusic, m_bHasBanner;
|
|
|
|
bool HasMusic() const;
|
|
bool HasBanner() const;
|
|
bool HasBackground() const;
|
|
bool HasCDTitle() const;
|
|
bool HasMovieBackground() const;
|
|
bool HasBGChanges() const;
|
|
bool HasLyrics() const;
|
|
|
|
bool Matches(CString sGroup, CString sSong) const;
|
|
|
|
TimingData m_Timing;
|
|
vector<BackgroundChange> m_BackgroundChanges; // this must be sorted before gameplay
|
|
vector<BackgroundChange> m_ForegroundChanges; // this must be sorted before gameplay
|
|
vector<LyricSegment> m_LyricSegments; // this must be sorted before gameplay
|
|
|
|
void AddBPMSegment( const BPMSegment &seg ) { m_Timing.AddBPMSegment( seg ); }
|
|
void AddStopSegment( const StopSegment &seg ) { m_Timing.AddStopSegment( seg ); }
|
|
void AddBackgroundChange( BackgroundChange seg );
|
|
void AddForegroundChange( BackgroundChange seg );
|
|
void AddLyricSegment( LyricSegment seg );
|
|
|
|
void GetDisplayBpms( DisplayBpms &AddTo ) const;
|
|
CString GetBackgroundAtBeat( float fBeat ) const;
|
|
|
|
float GetBPMAtBeat( float fBeat ) const { return m_Timing.GetBPMAtBeat( fBeat ); }
|
|
void SetBPMAtBeat( float fBeat, float fBPM ) { m_Timing.SetBPMAtBeat( fBeat, fBPM ); }
|
|
BPMSegment& GetBPMSegmentAtBeat( float fBeat ) { return m_Timing.GetBPMSegmentAtBeat( fBeat ); }
|
|
void GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut ) const { m_Timing.GetBeatAndBPSFromElapsedTime( fElapsedTime, fBeatOut, fBPSOut, bFreezeOut ); }
|
|
float GetBeatFromElapsedTime( float fElapsedTime ) const { return m_Timing.GetBeatFromElapsedTime( fElapsedTime ); }
|
|
float GetElapsedTimeFromBeat( float fBeat ) const { return m_Timing.GetElapsedTimeFromBeat( fBeat ); }
|
|
bool HasSignificantBpmChangesOrStops() const;
|
|
|
|
bool SongCompleteForStyle( const StyleDef *st ) const;
|
|
bool HasStepsType( StepsType st ) const;
|
|
bool HasStepsTypeAndDifficulty( StepsType st, Difficulty dc ) const;
|
|
const vector<Steps*>& GetAllSteps( StepsType st=STEPS_TYPE_INVALID ) const { return st==STEPS_TYPE_INVALID? m_vpSteps:m_vpStepsByType[st]; }
|
|
void GetSteps( vector<Steps*>& arrayAddTo, StepsType st = STEPS_TYPE_INVALID, Difficulty dc = DIFFICULTY_INVALID, int iMeterLow = -1, int iMeterHigh = -1, const CString &sDescription = "", bool bIncludeAutoGen = true, int Max = -1 ) const;
|
|
Steps* GetStepsByDifficulty( StepsType st, Difficulty dc, bool bIncludeAutoGen = true ) const;
|
|
Steps* GetStepsByMeter( StepsType st, int iMeterLow, int iMeterHigh ) const;
|
|
Steps* GetStepsByDescription( StepsType st, CString sDescription ) const;
|
|
Steps* GetClosestNotes( StepsType st, Difficulty dc ) const;
|
|
bool IsEasy( StepsType st ) const;
|
|
bool HasEdits( StepsType st ) const;
|
|
SelectionDisplay GetDisplayed() const;
|
|
bool NormallyDisplayed() const { return GetDisplayed() == SHOW_ALWAYS; }
|
|
bool NeverDisplayed() const { return GetDisplayed() == SHOW_NEVER; }
|
|
bool RouletteDisplayed() const { return GetDisplayed() != SHOW_NEVER; }
|
|
|
|
void AddSteps( Steps* pSteps ); // we are responsible for deleting the memory pointed to by pSteps!
|
|
void RemoveSteps( const Steps* pSteps );
|
|
|
|
void FreeAllLoadedFromProfiles();
|
|
bool WasLoadedFromProfile() const { return m_LoadedFromProfile != PROFILE_SLOT_INVALID; }
|
|
int GetNumStepsLoadedFromProfile( ProfileSlot slot ) const;
|
|
bool IsEditAlreadyLoaded( Steps* pSteps ) const;
|
|
|
|
private:
|
|
void AdjustDuplicateSteps(); // part of TidyUpData
|
|
void DeleteDuplicateSteps( vector<Steps*> &vSteps );
|
|
|
|
vector<Steps*> m_vpSteps;
|
|
vector<Steps*> m_vpStepsByType[NUM_STEPS_TYPES];
|
|
};
|
|
|
|
#endif
|
|
|
|
/*
|
|
* (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.
|
|
*/
|