#pragma once #include #include #include #include #include "MusicPattern.h" #include "RandGen.h" //#define TRACE_MUSIC #ifdef TRACE_MUSIC #define MTRACE TRACE #else #define MTRACE __noop #endif #define PATTERNSET_CHANGE_FADETIME 2.0 // Forward declarations struct ISystem; // Smart Pattern-Ptr typedef _smart_ptr TPatternInstancePtr; // Type of blending enum EBlendingType { EBlend_FadeOut, EBlend_ToEnd, EBlend_Stop }; // Info-Structure for automated fading struct SMusicPatternPlayInfo { SMusicPatternPlayInfo() { nLayer=MUSICLAYER_MAIN; pPatternInstance=NULL; eBlendType=EBlend_ToEnd; pRefCount=NULL; fPhase=1.0; fFadeTime=0.0; // use default fade time... bRefCountAdjusted=false; } ~SMusicPatternPlayInfo() { pPatternInstance=NULL; } TPatternInstancePtr pPatternInstance; int nLayer; EBlendingType eBlendType; int *pRefCount; // internal double fPhase; // phase for fading (0-1) double fFadeTime; // time in seconds to fade bool bRefCountAdjusted; }; ////////////////////////////////////////////////////////////////////////// // A couple of typedefs for various stl-containers ////////////////////////////////////////////////////////////////////////// typedef std::map > TPatternMap; typedef TPatternMap::iterator TPatternMapIt; typedef std::vector TStringVec; typedef TStringVec::iterator TStringVecIt; typedef std::vector TPatternPlayInfoVec; typedef TPatternPlayInfoVec::iterator TPatternPlayInfoVecIt; ////////////////////////////////////////////////////////////////////////// // Structure to collect/handle mood-events ////////////////////////////////////////////////////////////////////////// struct SMoodEventInfo { bool operator<(const SMoodEventInfo &b) const { if (stricmp(sMood.c_str(),b.sMood.c_str()) < 0) return true; return false; } string sMood;// name of mood float fTime; // time of consecutive event-occurance }; typedef std::set TMoodEventSet; typedef TMoodEventSet::iterator TMoodEventSetIt; ////////////////////////////////////////////////////////////////////////// // The MusicSystem itself ////////////////////////////////////////////////////////////////////////// class CMusicSystem : public IMusicSystem { protected: CRITICAL_SECTION m_CS; // system pointers ISystem *m_pSystem; ITimer *m_pTimer; ILog *m_pLog; ISoundSystem *m_pSoundSystem; // random generator CPseudoRandGen m_RandGen; // notification sink IMusicSystemSink *m_pSink; // current data (allocated externally) SMusicData *m_pDataPtr; bool m_bOwnMusicData; // sound-playback params float m_fMasterVolume; int m_nSampleRate; float m_fLatency; // bytes/sample in output stream int m_nBytesPerSample; // fmod stream data CS_STREAM *m_pStream; int m_nChannel; // states bool m_bDataLoaded; bool m_bPause; bool m_bPlaying; bool m_bBridging; // bridging in progress bool m_bCurrPatternIsBridge; bool m_bForcePatternChange; // change pattern asap (next fadepoint), do not play to the end (last fadepoint) // status SMusicSystemStatus m_Status; // all patterns TPatternMap m_mapPatterns; // current patterns TPatternInstancePtr m_pCurrPattern; TPatternInstancePtr m_pNextPattern; int m_nLayeredRhythmicPatterns; int m_nLayeredIncidentalPatterns; // temporary mix-buffer void *m_pMixBuffer; // array of currently playing patterns TPatternPlayInfoVec m_vecPlayingPatterns; // all themes (moods inside) TThemeMap m_mapThemes; // current theme/mood SMusicTheme *m_pThemeOverride; // overriding theme (eg. for vehicle) SMusicTheme *m_pCurrTheme; SMusicTheme *m_pNextTheme; // in case a theme change occured, this is the new theme... NULL otherwise SMusicMood *m_pCurrMood; SMusicMood *m_pNextMood; // mood event arrays TMoodEventSet m_setMoodEvents; // active mood events TMoodEventSet m_setFrameMoodEvents; // mood events arrived last frame // default mood //SMusicMood *m_pDefaultMood; float m_fDefaultMoodTime; // current time 'till default-mood-timeout string m_sDefaultMood; // override of theme-specific default-mood (set by SetDefaultMood); set to "" to use theme-specific // fading double m_fCurrCrossfadeTime; // logging TStringVec m_vecLog; bool m_bEnableEventProcessing; ICVar *m_pCVarDebugMusic; ICVar *m_pCVarMusicEnable; ICVar *m_pCVarMusicMaxSimultaniousPatterns; ICVar *m_pCVarMusicStreamedData; int m_musicEnable; protected: virtual ~CMusicSystem(); bool Init(); void Shutdown(); void FlushLog(); CMusicPattern* AddPattern(const char *pszName, const char *pszFilename); bool FlushPatterns(); bool StartPlaying(); bool StopPlaying(); SMusicMood* GetMood(SMusicTheme *pTheme, const char *pszMood); bool SetTheme(SMusicTheme *pNewTheme, bool bOverride); bool SetMood(SMusicMood *pNewMood); SMusicMood* GetDefaultMood(SMusicTheme *pTheme); void PushPatternToMixList(SMusicPatternPlayInfo &PlayInfo); void EnterDefaultMood(); void Silence(); void AdjustMixStreamsRefCount(int nSamples); void MixStreams(void *pBuffer, int nLength); bool FadeStream(SMusicPatternPlayInfo &PlayInfo, signed short *pBuffer, int nSamples); void FadeOutAllSecondaryLayers(double fFadeTime); CMusicPatternInstance* GetPatternInstance(const char *pszPattern); bool UpdateCurrentPatternSet(SMusicMood *pMood, int nSamples, bool bAllowChange); bool ChoosePatternSet(SMusicMood *pMood); CMusicPatternInstance* ChooseBridge(SMusicTheme *pCurrTheme, SMusicTheme *pNewTheme); CMusicPatternInstance* ChoosePattern(SMusicMood *pMood, int nLayer=MUSICLAYER_MAIN); signed char StreamingCallback(CS_STREAM *pStream, void *pBuffer, int nLength); //friend signed char __cdecl _StreamingCallback(CS_STREAM *pStream, void *pBuffer, int nLength, INT_PTR nParam); #ifndef CS_VERSION_372 #ifdef CS_VERSION_361 friend signed char F_CALLBACKAPI _StreamingCallback(CS_STREAM *pStream, void *pBuffer, int nLength, int nParam); #else friend signed char F_CALLBACKAPI _StreamingCallback(CS_STREAM *pStream, void *pBuffer, int nLength, INT_PTR nParam); #endif #else friend signed char F_CALLBACKAPI _StreamingCallback(CS_STREAM *pStream, void *pBuffer, int nLength, void * nParam); #endif friend class CMusicLoadSink; public: CMusicSystem(ISystem *pSystem); void Release(); ISystem* GetSystem() { return m_pSystem; } int GetBytesPerSample() { return m_nBytesPerSample; } IMusicSystemSink* SetSink(IMusicSystemSink *pSink); bool SetData(struct SMusicData *pMusicData,bool bNoRelease=false); void ReleaseData(); void Unload(); void Pause(bool bPause); void EnableEventProcessing(bool bEnable) { m_bEnableEventProcessing=bEnable; } bool ResetThemeOverride(); bool SetTheme(const char *pszTheme, bool bOverride=false); const char* GetTheme() { if (m_pCurrTheme) return m_pCurrTheme->sName.c_str(); return ""; } bool SetMood(const char *pszMood); bool SetDefaultMood(const char *pszMood); const char* GetMood() { if (m_pCurrMood) return m_pCurrMood->sName.c_str(); return ""; } IStringItVec* GetThemes(); IStringItVec* GetMoods(const char *pszTheme); bool AddMusicMoodEvent(const char *pszMood, float fTimeout); void Update(); SMusicSystemStatus* GetStatus(); // retrieve status of music-system... dont keep returning pointer ! //! compute memory-consumption void GetMemoryUsage(class ICrySizer* pSizer); bool LoadMusicDataFromLUA(IScriptSystem* pScriptSystem, const char *pszFilename); bool StreamOGG(); void LogMsg( const char *pszFormat, ... ); ////////////////////////////////////////////////////////////////////////// //! Load music data from XML. //! @param bAddAdata if true data from XML will be added to currently loaded music data. bool LoadFromXML( const char *sFilename,bool bAddData ); ////////////////////////////////////////////////////////////////////////// // Editing support. ////////////////////////////////////////////////////////////////////////// virtual void UpdateTheme( SMusicTheme *pTheme ); virtual void UpdateMood( SMusicMood *pMood ); virtual void UpdatePattern( SPatternDef *pPattern ); virtual void RenamePattern( const char *sOldName,const char *sNewName ); virtual void PlayPattern( const char *sPattern,bool bStopPrevious ); virtual void DeletePattern( const char *sPattern ); private: ////////////////////////////////////////////////////////////////////////// // Loading. ////////////////////////////////////////////////////////////////////////// void LoadPatternFromXML( XmlNodeRef node,SPatternDef *pPattern ); void LoadMoodFromXML( XmlNodeRef &node,SMusicMood *pMood ); void LoadThemeFromXML( XmlNodeRef &node,SMusicTheme *pTheme ); }; ////////////////////////////////////////////////////////////////////////// // String-vector-class to iterate data from other DLLs ////////////////////////////////////////////////////////////////////////// class CStringItVec : public IStringItVec { public: CStringItVec(TStringVec &Vec) { m_nRefCount=0; m_Vec=Vec; MoveFirst(); }; bool IsEnd() { return (m_itVec==m_Vec.end()); }; const char* Next() { return IsEnd() ? "" : (*m_itVec++).c_str(); }; void MoveFirst() { m_itVec = m_Vec.begin(); }; void AddRef() { m_nRefCount++; } void Release() { --m_nRefCount; if (m_nRefCount<=0) { delete this; } }; protected: int m_nRefCount; TStringVec m_Vec; TStringVecIt m_itVec; }; ////////////////////////////////////////////////////////////////////////// // SmartCriticalSection-class to make things easier ////////////////////////////////////////////////////////////////////////// class CSmartCriticalSection { private: CRITICAL_SECTION *m_pCS; public: CSmartCriticalSection(CRITICAL_SECTION &CS) { m_pCS=&CS; EnterCriticalSection(m_pCS); } ~CSmartCriticalSection() { LeaveCriticalSection(m_pCS); } };