diff --git a/Engine/source/T3D/assets/SoundAsset.cpp b/Engine/source/T3D/assets/SoundAsset.cpp index dd6ab9a0a..3f3a3bf25 100644 --- a/Engine/source/T3D/assets/SoundAsset.cpp +++ b/Engine/source/T3D/assets/SoundAsset.cpp @@ -44,6 +44,10 @@ #include "sfx/sfxSource.h" #endif +#ifndef _SFXPROFILE_H_ +#include "sfx/sfxProfile.h" +#endif // !_SFXPROFILE_H_ + // Debug Profiling. #include "platform/profiler.h" #include "sfx/sfxTypes.h" @@ -119,8 +123,28 @@ const String SoundAsset::mErrCodeStrings[] = SoundAsset::SoundAsset() : AssetBase() { - mSoundFile = StringTable->EmptyString(); - mSoundPath = StringTable->EmptyString(); + dMemset(mPlaylist.mSlots.mReplayMode, 0, sizeof(mPlaylist.mSlots.mReplayMode)); + dMemset(mPlaylist.mSlots.mTransitionIn, 0, sizeof(mPlaylist.mSlots.mTransitionIn)); + dMemset(mPlaylist.mSlots.mRepeatCount, 0, sizeof(mPlaylist.mSlots.mRepeatCount)); + dMemset(mPlaylist.mSlots.mState, 0, sizeof(mPlaylist.mSlots.mState)); + dMemset(mPlaylist.mSlots.mTrack, 0, sizeof(mPlaylist.mSlots.mTrack)); + dMemset(mPlaylist.mSlots.mStateMode, 0, sizeof(mPlaylist.mSlots.mStateMode)); + + for (U32 i = 0; i < SFXPlayList::NUM_SLOTS; i++) + { + mSoundFile[i] = StringTable->EmptyString(); + mSoundPath[i] = StringTable->EmptyString(); + + mPlaylist.mSlots.mTransitionOut[i] = SFXPlayList::TRANSITION_Wait; + mPlaylist.mSlots.mVolumeScale.mValue[i] = 1.f; + mPlaylist.mSlots.mPitchScale.mValue[i] = 1.f; + mPlaylist.mSlots.mFadeTimeIn.mValue[i] = -1.f; // Don't touch by default. + mPlaylist.mSlots.mFadeTimeOut.mValue[i] = -1.f; // Don't touch by default. + mPlaylist.mSlots.mMinDistance.mValue[i] = -1.f; // Don't touch by default. + mPlaylist.mSlots.mMaxDistance.mValue[i] = -1.f; // Don't touch by default. + + } + mSubtitleString = StringTable->EmptyString(); mLoadedState = AssetErrCode::NotLoaded; @@ -143,6 +167,14 @@ SoundAsset::SoundAsset() mProfileDesc.mPriority = 1.0f; mProfileDesc.mSourceGroup = NULL; + mIsPlaylist = false; + + mPlaylist.mNumSlotsToPlay = SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; + mPlaylist.mRandomMode = SFXPlayList::RANDOM_NotRandom; + mPlaylist.mTrace = false; + mPlaylist.mLoopMode = SFXPlayList::LOOP_All; + mPlaylist.mActiveSlots = 12; + } //----------------------------------------------------------------------------- @@ -158,9 +190,79 @@ void SoundAsset::initPersistFields() docsURL; // Call parent. Parent::initPersistFields(); + addArray("slots", SFXPlayList::SFXPlaylistSettings::NUM_SLOTS); + addProtectedField("soundFile", TypeAssetLooseFilePath, Offset(mSoundFile, SoundAsset), + &_setSoundFile, &_getSoundFile, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, "Path to the sound file."); - addProtectedField("soundFile", TypeAssetLooseFilePath, Offset(mSoundFile, SoundAsset), - &setSoundFile, &getSoundFile, "Path to the sound file."); + addField("replay", TYPEID< SFXPlayList::EReplayMode >(), Offset(mPlaylist.mSlots.mReplayMode, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Behavior when an already playing sound is encountered on this slot from a previous cycle.\n" + "Each slot can have an arbitrary number of sounds playing on it from previous cycles. This field determines " + "how SFXController will handle these sources."); + addField("transitionIn", TYPEID< SFXPlayList::ETransitionMode >(), Offset(mPlaylist.mSlots.mTransitionIn, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Behavior when moving into this slot.\n" + "After the delayIn time has expired (if any), this slot determines what the controller " + "will do before actually playing the slot."); + addField("transitionOut", TYPEID< SFXPlayList::ETransitionMode >(), Offset(mPlaylist.mSlots.mTransitionOut, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Behavior when moving out of this slot.\n" + "After the #detailTimeOut has expired (if any), this slot determines what the controller " + "will do before moving on to the next slot."); + addField("delayTimeIn", TypeF32, Offset(mPlaylist.mSlots.mDelayTimeIn.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Seconds to wait after moving into slot before #transitionIn."); + addField("delayTimeInVariance", TypePoint2F, Offset(mPlaylist.mSlots.mDelayTimeIn.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Bounds on randomization of #delayTimeIn.\n\n" + "@ref SFXPlayList_randomization\n"); + addField("delayTimeOut", TypeF32, Offset(mPlaylist.mSlots.mDelayTimeOut.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Seconds to wait before moving out of slot after #transitionOut."); + addField("delayTimeOutVariance", TypePoint2F, Offset(mPlaylist.mSlots.mDelayTimeOut.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Bounds on randomization of #delayTimeOut.\n\n" + "@ref SFXPlayList_randomization\n"); + addField("fadeTimeIn", TypeF32, Offset(mPlaylist.mSlots.mFadeTimeIn.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Seconds to fade sound in (-1 to use the track's own fadeInTime.)\n" + "@see SFXDescription::fadeTimeIn"); + addField("fadeTimeInVariance", TypePoint2F, Offset(mPlaylist.mSlots.mFadeTimeIn.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Bounds on randomization of #fadeInTime.\n\n" + "@ref SFXPlayList_randomization\n"); + addField("fadeTimeOut", TypeF32, Offset(mPlaylist.mSlots.mFadeTimeOut.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Seconds to fade sound out (-1 to use the track's own fadeOutTime.)\n" + "@see SFXDescription::fadeTimeOut"); + addField("fadeTimeOutVariance", TypePoint2F, Offset(mPlaylist.mSlots.mFadeTimeOut.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Bounds on randomization of #fadeOutTime\n\n" + "@ref SFXPlayList_randomization\n"); + addField("referenceDistance", TypeF32, Offset(mPlaylist.mSlots.mMinDistance.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "@c referenceDistance to set for 3D sounds in this slot (<1 to use @c referenceDistance of track's own description).\n" + "@see SFXDescription::referenceDistance"); + addField("referenceDistanceVariance", TypePoint2F, Offset(mPlaylist.mSlots.mMinDistance.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Bounds on randomization of #referenceDistance.\n\n" + "@ref SFXPlayList_randomization\n"); + addField("maxDistance", TypeF32, Offset(mPlaylist.mSlots.mMaxDistance.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "@c maxDistance to apply to 3D sounds in this slot (<1 to use @c maxDistance of track's own description).\n" + "@see SFXDescription::maxDistance"); + addField("maxDistanceVariance", TypePoint2F, Offset(mPlaylist.mSlots.mMaxDistance.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Bounds on randomization of #maxDistance.\n\n" + "@ref SFXPlayList_randomization\n"); + addField("volumeScale", TypeF32, Offset(mPlaylist.mSlots.mVolumeScale.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Scale factor to apply to volume of sounds played on this list slot.\n" + "This value will scale the actual volume level set on the track assigned to the slot, i.e. a value of 0.5 will " + "cause the track to play at half-volume."); + addField("volumeScaleVariance", TypePoint2F, Offset(mPlaylist.mSlots.mVolumeScale.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Bounds on randomization of #volumeScale.\n\n" + "@ref SFXPlayList_randomization\n"); + addField("pitchScale", TypeF32, Offset(mPlaylist.mSlots.mPitchScale.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Scale factor to apply to pitch of sounds played on this list slot.\n" + "This value will scale the actual pitch set on the track assigned to the slot, i.e. a value of 0.5 will " + "cause the track to play at half its assigned speed."); + addField("pitchScaleVariance", TypePoint2F, Offset(mPlaylist.mSlots.mPitchScale.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Bounds on randomization of #pitchScale.\n\n" + "@ref SFXPlayList_randomization\n"); + addField("repeatCount", TypeS32, Offset(mPlaylist.mSlots.mRepeatCount, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Number of times to loop this slot."); + addField("state", TypeSFXStateName, Offset(mPlaylist.mSlots.mState, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "State that must be active for this slot to play.\n\n" + "@ref SFXPlayList_states"); + addField("stateMode", TYPEID< SFXPlayList::EStateMode >(), Offset(mPlaylist.mSlots.mStateMode, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS, + "Behavior when assigned state is deactivated while slot is playing.\n\n" + "@ref SFXPlayList_states"); + endArray("slots"); addField("pitchAdjust", TypeF32, Offset(mProfileDesc.mPitch, SoundAsset), "Adjustment of the pitch value 1 is default."); addField("volumeAdjust", TypeF32, Offset(mProfileDesc.mVolume, SoundAsset), "Adjustment to the volume."); @@ -170,16 +272,33 @@ void SoundAsset::initPersistFields() addField("isStreaming", TypeBool, Offset(mProfileDesc.mIsStreaming, SoundAsset), "Use streaming."); //....why? addField("useHardware", TypeBool, Offset(mProfileDesc.mUseHardware, SoundAsset), "Use hardware mixing for this sound."); - addField("minDistance", TypeF32, Offset(mProfileDesc.mMinDistance, SoundAsset), "Minimum distance for sound."); - // more like it. - addField("maxDistance", TypeF32, Offset(mProfileDesc.mMaxDistance, SoundAsset), "Max distance for sound."); - addField("coneInsideAngle", TypeS32, Offset(mProfileDesc.mConeInsideAngle, SoundAsset), "Cone inside angle."); - addField("coneOutsideAngle", TypeS32, Offset(mProfileDesc.mConeOutsideAngle, SoundAsset), "Cone outside angle."); - addField("coneOutsideVolume", TypeF32, Offset(mProfileDesc.mConeOutsideVolume, SoundAsset), "Cone outside volume."); - addField("rolloffFactor", TypeF32, Offset(mProfileDesc.mRolloffFactor, SoundAsset), "Rolloff factor."); - addField("scatterDistance", TypePoint3F, Offset(mProfileDesc.mScatterDistance, SoundAsset), "Randomization to the spacial position of the sound."); addField("sourceGroup", TypeSFXSourceName, Offset(mProfileDesc.mSourceGroup, SoundAsset), "Group that sources playing with this description should be put into."); + addField("preload", TypeBool, Offset(mPreload, SoundAsset), "Whether to preload sound data when the profile is added to system."); + addGroup("Fading"); + addField("fadeInTime", TypeF32, Offset(mProfileDesc.mFadeInTime, SoundAsset), "Number of seconds to gradually fade in volume from zero when playback starts."); + addField("fadeOutTime", TypeF32, Offset(mProfileDesc.mFadeOutTime, SoundAsset), "Number of seconds to gradually fade out volume down to zero when playback is stopped or paused."); + addField("fadeInEase", TypeEaseF, Offset(mProfileDesc.mFadeInEase, SoundAsset), "Easing curve for fade-in transition."); + addField("fadeOutEase", TypeEaseF, Offset(mProfileDesc.mFadeOutEase, SoundAsset), "Easing curve for fade-out transition."); + addField("fadeLoops", TypeBool, Offset(mProfileDesc.mFadeLoops, SoundAsset), "Fade each cycle of a loop in and/or out; otherwise only fade-in first cycle."); + endGroup("Fading"); + + addGroup("3D"); + addField("minDistance", TypeF32, Offset(mProfileDesc.mMinDistance, SoundAsset), "Minimum distance for sound."); + addField("maxDistance", TypeF32, Offset(mProfileDesc.mMaxDistance, SoundAsset), "Max distance for sound."); + addField("coneInsideAngle", TypeS32, Offset(mProfileDesc.mConeInsideAngle, SoundAsset), "Cone inside angle."); + addField("coneOutsideAngle", TypeS32, Offset(mProfileDesc.mConeOutsideAngle, SoundAsset), "Cone outside angle."); + addField("coneOutsideVolume", TypeF32, Offset(mProfileDesc.mConeOutsideVolume, SoundAsset), "Cone outside volume."); + addField("rolloffFactor", TypeF32, Offset(mProfileDesc.mRolloffFactor, SoundAsset), "Rolloff factor."); + addField("scatterDistance", TypePoint3F, Offset(mProfileDesc.mScatterDistance, SoundAsset), "Randomization to the spacial position of the sound."); + endGroup("3D"); + + addGroup("Playlist settings"); + addField("random", TYPEID< SFXPlayList::ERandomMode >(), Offset(mPlaylist.mRandomMode, SoundAsset), "Slot playback order randomization pattern."); + addField("loopMode", TYPEID< SFXPlayList::ELoopMode >(), Offset(mPlaylist.mLoopMode, SoundAsset), "Behavior when description has looping enabled."); + addField("numSlotsToPlay", TypeS32, Offset(mPlaylist.mNumSlotsToPlay, SoundAsset), "Number of slots to play."); + addField("trace", TypeBool, Offset(mPlaylist.mTrace, SoundAsset), "Enable/disable execution tracing for this playlist (local only)."); + endGroup("Playlist settings"); } //------------------------------------------------------------------------------ @@ -193,67 +312,153 @@ void SoundAsset::copyTo(SimObject* object) void SoundAsset::initializeAsset(void) { Parent::initializeAsset(); + for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++) + { + if (i == 0 && mSoundFile[i] == StringTable->EmptyString()) + return; - if (mSoundFile == StringTable->EmptyString()) - return; + if (mSoundFile[i] == StringTable->EmptyString()) + break; - mSoundPath = getOwned() ? expandAssetFilePath(mSoundFile) : mSoundPath; + mSoundPath[i] = getOwned() ? expandAssetFilePath(mSoundFile[i]) : mSoundPath[i]; + } + + //loadSound(slotCount); + //mSoundPath = getOwned() ? expandAssetFilePath(mSoundFile) : mSoundPath; //loadSound(); } void SoundAsset::_onResourceChanged(const Torque::Path &path) { - if (path != Torque::Path(mSoundPath)) - return; + for (U32 i = 0; i < SFXPlayList::NUM_SLOTS; i++) + { + if (path != Torque::Path(mSoundPath[i])) + return; + } refreshAsset(); + //loadSound(slotCount); //loadSound(); } void SoundAsset::onAssetRefresh(void) { - if (mSoundFile == StringTable->EmptyString()) - return; + for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++) + { + if (i == 0 && mSoundFile[i] == StringTable->EmptyString()) + return; + if (mSoundFile[i] == StringTable->EmptyString()) + break; + + mSoundPath[i] = getOwned() ? expandAssetFilePath(mSoundFile[i]) : mSoundPath[i]; + } + + //loadSound(slotCount); //Update - mSoundPath = getOwned() ? expandAssetFilePath(mSoundFile) : mSoundPath; + //mSoundPath = getOwned() ? expandAssetFilePath(mSoundFile) : mSoundPath; //loadSound(); } bool SoundAsset::loadSound() { if (mLoadedState == AssetErrCode::Ok) return true; - if (mSoundPath) + + // find out how many active slots we have. + U32 numSlots = 0; + for (U32 i = 0; i < SFXPlayList::SFXPlaylistSettings::NUM_SLOTS; i++) { - if (!Torque::FS::IsFile(mSoundPath)) - { - Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile); - mLoadedState = BadFileReference; - mSFXProfile.setDescription(NULL); - mSFXProfile.setSoundFileName(StringTable->insert(StringTable->EmptyString())); - mSFXProfile.setPreload(false); + if (i == 0 && mSoundPath[i] == StringTable->EmptyString()) return false; - } - else - {// = new SFXProfile(mProfileDesc, mSoundFile, mPreload); - if (mProfileDesc.mSourceGroup == NULL) - mProfileDesc.mSourceGroup = dynamic_cast(Sim::findObject("AudioChannelMaster")); - mSFXProfile.setDescription(&mProfileDesc); - mSFXProfile.setSoundFileName(mSoundPath); - mSFXProfile.setPreload(mPreload); - //give it a nudge to preload if required - mSFXProfile.getBuffer(); - } + if (mSoundPath[i] == StringTable->EmptyString()) + break; + numSlots++; } + + + if (numSlots > 1) + { + mIsPlaylist = true; + + for (U32 i = 0; i < numSlots; i++) + { + if (mSoundPath[i]) + { + if (!Torque::FS::IsFile(mSoundPath[i])) + { + Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[i]); + mLoadedState = BadFileReference; + mSFXProfile[i].setDescription(NULL); + mSFXProfile[i].setSoundFileName(StringTable->insert(StringTable->EmptyString())); + mSFXProfile[i].setPreload(false); + return false; + } + else + {// = new SFXProfile(mProfileDesc, mSoundFile, mPreload); + if (mProfileDesc.mSourceGroup == NULL) + mProfileDesc.mSourceGroup = dynamic_cast(Sim::findObject("AudioChannelMaster")); + SFXProfile* trackProfile = new SFXProfile(); + trackProfile->setDescription(&mProfileDesc); + trackProfile->setSoundFileName(mSoundPath[i]); + trackProfile->setPreload(mPreload); + trackProfile->getBuffer(); + + mSFXProfile[i] = *trackProfile; + + mPlaylist.mSlots.mTrack[i] = trackProfile; + + } + } + } + + mPlaylist.setDescription(&mProfileDesc); + } + else + { + if (mSoundPath[0]) + { + if (!Torque::FS::IsFile(mSoundPath[0])) + { + Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile[0]); + mLoadedState = BadFileReference; + mSFXProfile[0].setDescription(NULL); + mSFXProfile[0].setSoundFileName(StringTable->insert(StringTable->EmptyString())); + mSFXProfile[0].setPreload(false); + return false; + } + else + {// = new SFXProfile(mProfileDesc, mSoundFile, mPreload); + if (mProfileDesc.mSourceGroup == NULL) + mProfileDesc.mSourceGroup = dynamic_cast(Sim::findObject("AudioChannelMaster")); + mSFXProfile[0].setDescription(&mProfileDesc); + mSFXProfile[0].setSoundFileName(mSoundPath[0]); + mSFXProfile[0].setPreload(mPreload); + + //give it a nudge to preload if required + mSFXProfile[0].getBuffer(); + } + + } + } + mChangeSignal.trigger(); mLoadedState = Ok; return true; } -void SoundAsset::setSoundFile(const char* pSoundFile) +StringTableEntry SoundAsset::getSoundFile(const char* pSoundFile, const U32 slotId) +{ + for (U32 i = 0; i < 12; i++) + { + if(mSoundFile[i] == pSoundFile) + return mSoundFile[i]; + } +} + +void SoundAsset::setSoundFile(const char* pSoundFile, const U32 slotId) { // Sanity! AssertFatal(pSoundFile != NULL, "Cannot use a NULL sound file."); @@ -261,12 +466,12 @@ void SoundAsset::setSoundFile(const char* pSoundFile) // Fetch sound file. pSoundFile = StringTable->insert(pSoundFile, true); - // Ignore no change, - if (pSoundFile == mSoundFile) + //Ignore no change, + if (pSoundFile == mSoundFile[slotId]) return; // Update. - mSoundFile = getOwned() ? expandAssetFilePath(pSoundFile) : pSoundFile; + mSoundFile[slotId] = getOwned() ? expandAssetFilePath(pSoundFile) : pSoundFile; // Refresh the asset. refreshAsset(); @@ -353,11 +558,11 @@ DefineEngineMethod(SoundAsset, playSound, S32, (Point3F position), (Point3F::Zer "Plays the sound for this asset.\n" "@return (sound plays).\n") { - if (object->getSfxProfile()) + if (object->getSFXTrack()) { MatrixF transform; transform.setPosition(position); - SFXSource* source = SFX->playOnce(object->getSfxProfile(), &transform, NULL, -1); + SFXSource* source = SFX->playOnce(object->getSFXTrack(), &transform, NULL, -1); if(source) return source->getId(); else diff --git a/Engine/source/T3D/assets/SoundAsset.h b/Engine/source/T3D/assets/SoundAsset.h index 63f81194a..ccd10627b 100644 --- a/Engine/source/T3D/assets/SoundAsset.h +++ b/Engine/source/T3D/assets/SoundAsset.h @@ -55,6 +55,11 @@ #include "sfx/sfxDescription.h" #endif // !_SFXDESCRIPTION_H_ + +#ifndef _SFXTRACK_H_ +#include "sfx/sfxTrack.h" +#endif + #ifndef _SFXPROFILE_H_ #include "sfx/sfxProfile.h" #endif // !_SFXPROFILE_H_ @@ -63,8 +68,17 @@ #include "core/resourceManager.h" #endif +#ifndef _SFXPLAYLIST_H_ +#include "sfx/sfxPlayList.h" +#endif + +#ifndef _SFXTYPES_H_ +#include "sfx/sfxTypes.h" +#endif + #include "assetMacroHelpers.h" class SFXResource; +class SFXPlayList; //----------------------------------------------------------------------------- class SoundAsset : public AssetBase @@ -73,13 +87,17 @@ class SoundAsset : public AssetBase typedef AssetPtr ConcreteAssetPtr; protected: - StringTableEntry mSoundFile; - StringTableEntry mSoundPath; - SFXProfile mSFXProfile; + StringTableEntry mSoundFile[12]; + StringTableEntry mSoundPath[12]; + SFXProfile mSFXProfile[12]; + SFXDescription mProfileDesc; + SFXPlayList mPlaylist; // subtitles StringTableEntry mSubtitleString; bool mPreload; + bool mIsPlaylist; + //SFXPlayList::SlotData mSlots; /*These will be needed in the refactor! Resource mSoundResource; @@ -132,17 +150,20 @@ public: virtual void copyTo(SimObject* object); //SFXResource* getSound() { return mSoundResource; } - Resource getSoundResource() { loadSound(); return mSFXProfile.getResource(); } + Resource getSoundResource(const U32 slotId = 0) { loadSound(); return mSFXProfile[slotId].getResource(); } /// Declare Console Object. DECLARE_CONOBJECT(SoundAsset); - void setSoundFile(const char* pSoundFile); + void setSoundFile(const char* pSoundFile, const U32 slotId = 0); bool loadSound(); - inline StringTableEntry getSoundFile(void) const { return mSoundFile; }; - inline StringTableEntry getSoundPath(void) const { return mSoundPath; }; - SFXProfile* getSfxProfile() { return &mSFXProfile; } + StringTableEntry getSoundFile(const char* pSoundFile, const U32 slotId = 0); + inline StringTableEntry getSoundPath(const U32 slotId = 0) const { return mSoundPath[slotId]; }; + SFXProfile* getSfxProfile(const U32 slotId = 0) { return &mSFXProfile[slotId]; } + SFXPlayList* getSfxPlaylist() { return &mPlaylist; } + SFXTrack* getSFXTrack() { return mIsPlaylist ? dynamic_cast(&mPlaylist) : dynamic_cast(&mSFXProfile[0]); } SFXDescription* getSfxDescription() { return &mProfileDesc; } + bool isPlaylist(){ return mIsPlaylist; } bool isLoop() { return mProfileDesc.mIsLooping; } bool is3D() { return mProfileDesc.mIs3D; } @@ -156,8 +177,8 @@ protected: void _onResourceChanged(const Torque::Path & path); virtual void onAssetRefresh(void); - static bool setSoundFile(void *obj, const char *index, const char *data) { static_cast(obj)->setSoundFile(data); return false; } - static const char* getSoundFile(void* obj, const char* data) { return static_cast(obj)->getSoundFile(); } + static bool _setSoundFile(void *obj, const char *index, const char *data) { static_cast(obj)->setSoundFile(data, index ? dAtoi(index) : 0); return false; } + static const char* _getSoundFile(void* obj, const char* data) { return static_cast(obj)->getSoundFile(data); } }; DefineConsoleType(TypeSoundAssetPtr, SoundAsset) @@ -175,7 +196,7 @@ DefineConsoleType(TypeSoundAssetId, String) StringTableEntry m##name##Name; \ StringTableEntry m##name##AssetId;\ AssetPtr m##name##Asset = NULL;\ - SFXProfile* m##name##Profile = NULL;\ + SFXTrack* m##name##Profile = NULL;\ SFXDescription* m##name##Desc = NULL;\ SimObjectId m##name##SFXId = 0;\ public: \ @@ -268,11 +289,12 @@ public: \ {\ return m##name;\ }\ - SFXProfile* get##name##Profile()\ + SFXTrack* get##name##Profile()\ {\ if (get##name() != StringTable->EmptyString() && m##name##Asset.notNull()){\ - m##name##Profile = m##name##Asset->getSfxProfile();\ - return m##name##Profile;}\ + m##name##Profile = m##name##Asset->getSFXTrack(); \ + return m##name##Profile;\ + }\ return NULL;\ }\ SFXDescription* get##name##Description()\ @@ -308,9 +330,9 @@ public: \ {\ if(stream->writeFlag(Sim::findObject(m##name##Name)))\ {\ - SFXTrack* sndTrack;\ - Sim::findObject(m##name##Name, sndTrack);\ + SFXTrack* sndTrack = get##name##Profile();\ stream->writeRangedU32(SimObjectId(sndTrack->getId()), DataBlockObjectIdFirst, DataBlockObjectIdLast);\ + sfxWrite(stream, sndTrack);\ }\ else\ {\ @@ -330,7 +352,10 @@ public: \ {\ if(stream->readFlag())\ {\ + String errorStr;\ m##name##SFXId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );\ + sfxReadAndResolve(stream, &m##name##Profile, errorStr);\ + Con::errorf("%s", errorStr.c_str());\ }\ else\ {\ @@ -359,7 +384,7 @@ public: \ StringTableEntry m##name##Name[max]; \ StringTableEntry m##name##AssetId[max];\ AssetPtr m##name##Asset[max];\ - SFXProfile* m##name##Profile[max];\ + SFXTrack* m##name##Profile[max];\ SimObjectId m##name##SFXId[max];\ public: \ const StringTableEntry get##name##File(const U32& index) const { return m##name##Name[index]; }\ @@ -461,10 +486,10 @@ public: \ return ResourceManager::get().load( "" );\ return m##name[id];\ }\ - SFXProfile* get##name##Profile(const U32& id)\ + SFXTrack* get##name##Profile(const U32& id)\ {\ - if (get##name(id) != StringTable->EmptyString() && m##name##Asset[id].notNull())\ - return m##name##Asset[id]->getSfxProfile();\ + if (m##name##Asset[id].notNull())\ + return m##name##Asset[id]->getSFXTrack(); \ return NULL;\ }\ bool is##name##Valid(const U32& id) {return (get##name(id) != StringTable->EmptyString() && m##name##Asset[id] && m##name##Asset[id]->getStatus() == AssetBase::Ok); } @@ -518,9 +543,12 @@ if (m##name##AssetId[index] != StringTable->EmptyString())\ {\ if(stream->writeFlag(Sim::findObject(m##name##Name[index])))\ {\ - SFXTrack* sndTrack;\ - Sim::findObject(m##name##Name[index], sndTrack);\ - stream->writeRangedU32(SimObjectId(sndTrack->getId()), DataBlockObjectIdFirst, DataBlockObjectIdLast);\ + SFXTrack* sndTrack = get##name##Profile(index);\ + if(stream->writeFlag(sndTrack != nullptr))\ + {\ + stream->writeRangedU32(SimObjectId(sndTrack->getId()), DataBlockObjectIdFirst, DataBlockObjectIdLast);\ + sfxWrite(stream, sndTrack);\ + }\ }\ else\ {\ @@ -540,7 +568,12 @@ if (m##name##AssetId[index] != StringTable->EmptyString())\ {\ if(stream->readFlag())\ {\ - m##name##SFXId[index] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );\ + String errorStr;\ + if(stream->readFlag())\ + {\ + m##name##SFXId[index] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );\ + sfxReadAndResolve(stream, &m##name##Profile[index], errorStr);\ + }\ }\ else\ {\ diff --git a/Engine/source/T3D/fx/explosion.cpp b/Engine/source/T3D/fx/explosion.cpp index d9cfc1367..d4d621cdf 100644 --- a/Engine/source/T3D/fx/explosion.cpp +++ b/Engine/source/T3D/fx/explosion.cpp @@ -1403,7 +1403,7 @@ bool Explosion::explode() resetWorldBox(); } - SFXProfile* sound_prof = mDataBlock->getSoundProfile(); + SFXProfile* sound_prof = static_cast(mDataBlock->getSoundProfile()); if (sound_prof) { soundProfile_clone = sound_prof->cloneAndPerformSubstitutions(ss_object, ss_index); diff --git a/Engine/source/T3D/fx/splash.cpp b/Engine/source/T3D/fx/splash.cpp index 3b8c6da24..07c3a52f3 100644 --- a/Engine/source/T3D/fx/splash.cpp +++ b/Engine/source/T3D/fx/splash.cpp @@ -686,7 +686,7 @@ void Splash::spawnExplosion() /// could just play the explosion one, but explosion could be weapon specific, /// splash sound could be liquid specific. food for thought. - SFXProfile* sound_prof = mDataBlock->getSoundProfile(); + SFXTrack* sound_prof = mDataBlock->getSoundProfile(); if (sound_prof) { SFX->playOnce(sound_prof, &getTransform()); diff --git a/Engine/source/T3D/gameBase/gameConnectionEvents.cpp b/Engine/source/T3D/gameBase/gameConnectionEvents.cpp index 184d504bf..a24a80c87 100644 --- a/Engine/source/T3D/gameBase/gameConnectionEvents.cpp +++ b/Engine/source/T3D/gameBase/gameConnectionEvents.cpp @@ -387,9 +387,9 @@ void SimSoundAssetEvent::process(NetConnection* con) { if (mAsset->is3D()) - SFX->playOnce(mAsset->getSfxProfile(), &mTransform); + SFX->playOnce(mAsset->getSFXTrack(), &mTransform); else - SFX->playOnce(mAsset->getSfxProfile()); + SFX->playOnce(mAsset->getSFXTrack()); } diff --git a/Engine/source/T3D/sfx/sfxEmitter.cpp b/Engine/source/T3D/sfx/sfxEmitter.cpp index 2ff998eec..961e3efb1 100644 --- a/Engine/source/T3D/sfx/sfxEmitter.cpp +++ b/Engine/source/T3D/sfx/sfxEmitter.cpp @@ -106,8 +106,7 @@ SFXEmitter::SFXEmitter() mDescription.mFadeInTime = -1.f; mDescription.mFadeOutTime = -1.f; mInstanceDescription = &mDescription; - mLocalProfile.mFilename = StringTable->EmptyString(); - mLocalProfile._registerSignals(); + mLocalProfile = NULL; INIT_ASSET(Sound); @@ -119,7 +118,9 @@ SFXEmitter::SFXEmitter() SFXEmitter::~SFXEmitter() { - mLocalProfile.onRemove(); + if(mLocalProfile != NULL) + mLocalProfile->onRemove(); + SFX_DELETE( mSource ); } @@ -653,7 +654,7 @@ void SFXEmitter::_update() SFXStatus prevState = mSource ? mSource->getStatus() : SFXStatusNull; // are we overriding the asset properties? - bool useTrackDescriptionOnly = (mUseTrackDescriptionOnly && mSoundAsset.notNull() && mSoundAsset->getSfxProfile()); + bool useTrackDescriptionOnly = (mUseTrackDescriptionOnly && mSoundAsset.notNull() && getSoundProfile()); if (mSoundAsset.notNull()) { @@ -662,12 +663,12 @@ void SFXEmitter::_update() else mInstanceDescription = &mDescription; - mLocalProfile = *mSoundAsset->getSfxProfile(); - } - // Make sure all the settings are valid. - mInstanceDescription->validate(); - mLocalProfile.setDescription(mInstanceDescription); + mLocalProfile = getSoundProfile(); + // Make sure all the settings are valid. + mInstanceDescription->validate(); + mLocalProfile->setDescription(mInstanceDescription); + } const MatrixF& transform = getTransform(); const VectorF& velocity = getVelocity(); @@ -676,12 +677,12 @@ void SFXEmitter::_update() if( mDirty.test( Track | Is3D | IsLooping | IsStreaming | TrackOnly ) ) { SFX_DELETE( mSource ); - if (mLocalProfile.getSoundFileName().isNotEmpty()) + if (getSoundProfile()) { - mSource = SFX->createSource(&mLocalProfile, &transform, &velocity); + mSource = SFX->createSource(mLocalProfile, &transform, &velocity); if (!mSource) Con::errorf("SFXEmitter::_update() - failed to create sound for track %i (%s)", - mSoundAsset->getSfxProfile()->getId(), mSoundAsset->getSfxProfile()->getName()); + getSoundProfile()->getId(), getSoundProfile()->getName()); // If we're supposed to play when the emitter is // added to the scene then also restart playback @@ -1043,8 +1044,8 @@ SFXStatus SFXEmitter::_getPlaybackStatus() const bool SFXEmitter::is3D() const { - if( mSoundAsset.notNull() && mSoundAsset->getSfxProfile() != NULL ) - return mSoundAsset->getSfxProfile()->getDescription()->mIs3D; + if( mSoundAsset.notNull() ) + return mSoundAsset->getSfxDescription()->mIs3D; else return mInstanceDescription->mIs3D; } @@ -1080,8 +1081,8 @@ void SFXEmitter::setScale( const VectorF &scale ) { F32 maxDistance; - if( mUseTrackDescriptionOnly && mSoundAsset.notNull() && mSoundAsset->getSfxProfile()) - maxDistance = mSoundAsset->getSfxProfile()->getDescription()->mMaxDistance; + if( mUseTrackDescriptionOnly && mSoundAsset.notNull() && getSoundProfile()) + maxDistance = mSoundAsset->getSfxDescription()->mMaxDistance; else { // Use the average of the three coords. diff --git a/Engine/source/T3D/sfx/sfxEmitter.h b/Engine/source/T3D/sfx/sfxEmitter.h index 134b6828c..103a92faf 100644 --- a/Engine/source/T3D/sfx/sfxEmitter.h +++ b/Engine/source/T3D/sfx/sfxEmitter.h @@ -116,7 +116,7 @@ class SFXEmitter : public SceneObject /// A local profile object used to coax the /// sound system to play a custom sound. - SFXProfile mLocalProfile; + SFXTrack* mLocalProfile; /// The description used by the local profile. SFXDescription mDescription; diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index c130b57b4..e6656fb15 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -2303,7 +2303,7 @@ void ShapeBase::updateAudioState(SoundThread& st) // if asset is valid, play if (st.asset->isAssetValid() ) { - st.sound = SFX->createSource( st.asset->getSfxProfile() , &getTransform() ); + st.sound = SFX->createSource( st.asset->getSFXTrack() , &getTransform() ); if ( st.sound ) st.sound->play(); } diff --git a/Engine/source/T3D/shapeImage.cpp b/Engine/source/T3D/shapeImage.cpp index c71c6f938..9ecddfc21 100644 --- a/Engine/source/T3D/shapeImage.cpp +++ b/Engine/source/T3D/shapeImage.cpp @@ -2785,7 +2785,7 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState, bool force) // Delete any loooping sounds that were in the previous state. // this is the crazy bit =/ needs to know prev state in order to stop sounds. // lastState does not return an id for the prev state so we keep track of it. - if (lastState->sound && lastState->sound->getSfxProfile()->getDescription()->mIsLooping) + if (lastState->sound && lastState->sound->getSFXTrack()->getDescription()->mIsLooping) { for (Vector::iterator i = image.mSoundSources.begin(); i != image.mSoundSources.end(); i++) SFX_DELETE((*i)); @@ -2799,7 +2799,7 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState, bool force) if (stateData.sound) { const Point3F& velocity = getVelocity(); - image.addSoundSource(SFX->createSource(stateData.sound->getSfxProfile(), &getRenderTransform(), &velocity)); + image.addSoundSource(SFX->createSource(stateData.sound->getSFXTrack(), &getRenderTransform(), &velocity)); } if (stateData.soundTrack) { diff --git a/Engine/source/sfx/sfxController.cpp b/Engine/source/sfx/sfxController.cpp index 0de38ad39..2e1c71b7f 100644 --- a/Engine/source/sfx/sfxController.cpp +++ b/Engine/source/sfx/sfxController.cpp @@ -167,7 +167,7 @@ void SFXController::_compileList( SFXPlayList* playList ) // If there's no track in this slot, ignore it. - if( !playList->getTrackProfile(slotIndex)) + if( !playList->getSlots().mTrack[slotIndex]) continue; // If this is a looped slot and the list is not set to loop @@ -394,7 +394,13 @@ bool SFXController::_execInsn() case OP_Play: { SFXPlayList* playList = getPlayList(); - SFXTrack* track = playList->getTrackProfile(insn.mSlotIndex); + if (playList == NULL) + { + endUpdate = true; + break; + } + + SFXTrack* track = playList->getSlots().mTrack[insn.mSlotIndex]; // Handle existing sources playing on this slot and find // whether we need to start a new source. @@ -817,6 +823,9 @@ void SFXController::_update() SFXPlayList* playList = getPlayList(); + if (!playList) + Parent::stop(); + // Check all sources against the current state setup and // take appropriate actions. diff --git a/Engine/source/sfx/sfxPlayList.cpp b/Engine/source/sfx/sfxPlayList.cpp index 4cc6a56e3..b763e4a14 100644 --- a/Engine/source/sfx/sfxPlayList.cpp +++ b/Engine/source/sfx/sfxPlayList.cpp @@ -23,6 +23,7 @@ #include "sfx/sfxPlayList.h" #include "sfx/sfxState.h" #include "sfx/sfxTypes.h" +#include "sfx/sfxDescription.h" #include "core/stream/bitStream.h" #include "math/mRandom.h" #include "math/mathTypes.h" @@ -218,10 +219,23 @@ SFXPlayList::SFXPlayList() : mRandomMode( RANDOM_NotRandom ), mLoopMode( LOOP_All ), mTrace( false ), - mNumSlotsToPlay( NUM_SLOTS ) + mNumSlotsToPlay( NUM_SLOTS ), + mActiveSlots(12) { - for (U32 i=0;iisTempClone()) + { + delete mDescription; + mDescription = 0; + } } //----------------------------------------------------------------------------- @@ -250,10 +264,10 @@ void SFXPlayList::initPersistFields() addArray( "slots", NUM_SLOTS ); - INITPERSISTFIELD_SOUNDASSET_ARRAY( Track, NUM_SLOTS, SFXPlayList, + addField("track", TypeSFXTrackName, Offset(mSlots.mTrack, SFXPlayList), NUM_SLOTS, "Track to play in this slot.\n" "This must be set for the slot to be considered for playback. Other settings for a slot " - "will not take effect except this field is set." ); + "will not take effect except this field is set."); addField( "replay", TYPEID< EReplayMode >(), Offset( mSlots.mReplayMode, SFXPlayList ), NUM_SLOTS, "Behavior when an already playing sound is encountered on this slot from a previous cycle.\n" "Each slot can have an arbitrary number of sounds playing on it from previous cycles. This field determines " @@ -340,32 +354,64 @@ void SFXPlayList::initPersistFields() //----------------------------------------------------------------------------- +U32 SFXPlayList::getNumSlots() +{ + U32 trackCount = 0; + for (U32 i = 0; i < NUM_SLOTS; i++) + { + if (mSlots.mTrack[i] == NULL) + { + return i; + } + trackCount++; + } + + return trackCount; +} + +bool SFXPlayList::isLooping() const +{ + // pretty useless in playlist, looping handled differently. + return false; +} + +bool SFXPlayList::onAdd() +{ + if (!Parent::onAdd()) + return false; + + mActiveSlots = getNumSlots(); + + validate(); + + return true; +} + +void SFXPlayList::onRemove() +{ + Parent::onRemove(); +} + bool SFXPlayList::preload( bool server, String& errorStr ) { if( !Parent::preload( server, errorStr ) ) return false; + + mActiveSlots = getNumSlots(); validate(); // Resolve SFXTracks and SFXStates on client. - + if( !server ) { - for( U32 i = 0; i < NUM_SLOTS; ++ i ) + for( U32 i = 0; i < mActiveSlots; ++ i ) { - StringTableEntry track = getTrack(i); - if (track != StringTable->EmptyString()) - { - _setTrack(getTrack(i), i); - if (!getTrackProfile(i)) - { - Con::errorf("SFXPlayList::Preload() - unable to find sfxProfile for asset %s", mTrackAssetId[i]); + if (!sfxResolve(&mSlots.mTrack[i], errorStr)) return false; - } - if (!sfxResolve(&mSlots.mState[i], errorStr)) + if (!sfxResolve(&mSlots.mState[i], errorStr)) return false; - } } } @@ -382,55 +428,57 @@ void SFXPlayList::packData( BitStream* stream ) stream->writeInt( mLoopMode, NUM_LOOP_MODE_BITS ); stream->writeInt( mNumSlotsToPlay, NUM_SLOTS_TO_PLAY_BITS ); - #define FOR_EACH_SLOT \ - for( U32 i = 0; i < NUM_SLOTS; ++ i ) - - FOR_EACH_SLOT stream->writeInt( mSlots.mReplayMode[ i ], NUM_REPLAY_MODE_BITS ); - FOR_EACH_SLOT stream->writeInt( mSlots.mTransitionIn[ i ], NUM_TRANSITION_MODE_BITS ); - FOR_EACH_SLOT stream->writeInt( mSlots.mTransitionOut[ i ], NUM_TRANSITION_MODE_BITS ); - FOR_EACH_SLOT stream->writeInt( mSlots.mStateMode[ i ], NUM_STATE_MODE_BITS ); - - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mFadeTimeIn.mValue[ i ] != -1 )) - stream->write( mSlots.mFadeTimeIn.mValue[ i ] ); - FOR_EACH_SLOT if (stream->writeFlag( mSlots.mFadeTimeIn.mVariance[ i ][ 0 ] > 0)) - stream->write(mSlots.mFadeTimeIn.mVariance[ i ][ 0 ] ); - FOR_EACH_SLOT if (stream->writeFlag( mSlots.mFadeTimeIn.mVariance[ i ][ 1 ] > 0)) - stream->write(mSlots.mFadeTimeIn.mVariance[ i ][ 1 ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mFadeTimeOut.mValue[ i ] != -1 )) - stream->write( mSlots.mFadeTimeOut.mValue[ i ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mFadeTimeOut.mVariance[i][0] > 0)) - stream->write(mSlots.mFadeTimeOut.mVariance[i][0]); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mFadeTimeOut.mVariance[i][1] > 0)) - stream->write(mSlots.mFadeTimeOut.mVariance[i][1]); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mDelayTimeIn.mValue[ i ] > 0)) - stream->write(mSlots.mDelayTimeIn.mValue[ i ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mDelayTimeIn.mVariance[ i ][ 0 ] > 0)) - stream->write(mSlots.mDelayTimeIn.mVariance[ i ][ 0 ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mDelayTimeIn.mVariance[ i ][ 1 ] > 0)) - stream->write(mSlots.mDelayTimeIn.mVariance[ i ][ 1 ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mDelayTimeOut.mValue[ i ] > 0)) - stream->write(mSlots.mDelayTimeOut.mValue[ i ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mDelayTimeOut.mVariance[ i ][ 0 ] > 0)) - stream->write(mSlots.mDelayTimeOut.mVariance[ i ][ 0 ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mDelayTimeOut.mVariance[ i ][ 1 ] > 0)) - stream->write(mSlots.mDelayTimeOut.mVariance[ i ][ 1 ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mVolumeScale.mValue[ i ] != 1)) - stream->write(mSlots.mVolumeScale.mValue[ i ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mVolumeScale.mVariance[ i ][ 0 ] > 0)) - stream->write(mSlots.mVolumeScale.mVariance[ i ][ 0 ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mVolumeScale.mVariance[ i ][ 1 ] > 0)) - stream->write(mSlots.mVolumeScale.mVariance[ i ][ 1 ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mPitchScale.mValue[ i ] != 1)) - stream->write(mSlots.mPitchScale.mValue[ i ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mPitchScale.mVariance[ i ][ 0 ] > 0)) - stream->write(mSlots.mPitchScale.mVariance[ i ][ 0 ] ); - FOR_EACH_SLOT if (stream->writeFlag(mSlots.mPitchScale.mVariance[ i ][ 1 ] > 0)) - stream->write(mSlots.mPitchScale.mVariance[ i ][ 1 ] ); - FOR_EACH_SLOT if (stream->writeFlag( mSlots.mRepeatCount[ i ] > 0)) - stream->write( mSlots.mRepeatCount[ i ] ); - - FOR_EACH_SLOT sfxWrite( stream, mSlots.mState[ i ] ); - FOR_EACH_SLOT PACKDATA_SOUNDASSET_ARRAY(Track, i); + stream->writeInt(mActiveSlots, 8); + + for (U32 i = 0; i < mActiveSlots; ++i) + { + stream->writeInt(mSlots.mReplayMode[i], NUM_REPLAY_MODE_BITS); + stream->writeInt(mSlots.mTransitionIn[i], NUM_TRANSITION_MODE_BITS); + stream->writeInt(mSlots.mTransitionOut[i], NUM_TRANSITION_MODE_BITS); + stream->writeInt(mSlots.mStateMode[i], NUM_STATE_MODE_BITS); + + if (stream->writeFlag(mSlots.mFadeTimeIn.mValue[i] != -1)) + stream->write(mSlots.mFadeTimeIn.mValue[i]); + if (stream->writeFlag(mSlots.mFadeTimeIn.mVariance[i][0] > 0)) + stream->write(mSlots.mFadeTimeIn.mVariance[i][0]); + if (stream->writeFlag(mSlots.mFadeTimeIn.mVariance[i][1] > 0)) + stream->write(mSlots.mFadeTimeIn.mVariance[i][1]); + if (stream->writeFlag(mSlots.mFadeTimeOut.mValue[i] != -1)) + stream->write(mSlots.mFadeTimeOut.mValue[i]); + if (stream->writeFlag(mSlots.mFadeTimeOut.mVariance[i][0] > 0)) + stream->write(mSlots.mFadeTimeOut.mVariance[i][0]); + if (stream->writeFlag(mSlots.mFadeTimeOut.mVariance[i][1] > 0)) + stream->write(mSlots.mFadeTimeOut.mVariance[i][1]); + if (stream->writeFlag(mSlots.mDelayTimeIn.mValue[i] > 0)) + stream->write(mSlots.mDelayTimeIn.mValue[i]); + if (stream->writeFlag(mSlots.mDelayTimeIn.mVariance[i][0] > 0)) + stream->write(mSlots.mDelayTimeIn.mVariance[i][0]); + if (stream->writeFlag(mSlots.mDelayTimeIn.mVariance[i][1] > 0)) + stream->write(mSlots.mDelayTimeIn.mVariance[i][1]); + if (stream->writeFlag(mSlots.mDelayTimeOut.mValue[i] > 0)) + stream->write(mSlots.mDelayTimeOut.mValue[i]); + if (stream->writeFlag(mSlots.mDelayTimeOut.mVariance[i][0] > 0)) + stream->write(mSlots.mDelayTimeOut.mVariance[i][0]); + if (stream->writeFlag(mSlots.mDelayTimeOut.mVariance[i][1] > 0)) + stream->write(mSlots.mDelayTimeOut.mVariance[i][1]); + if (stream->writeFlag(mSlots.mVolumeScale.mValue[i] != 1)) + stream->write(mSlots.mVolumeScale.mValue[i]); + if (stream->writeFlag(mSlots.mVolumeScale.mVariance[i][0] > 0)) + stream->write(mSlots.mVolumeScale.mVariance[i][0]); + if (stream->writeFlag(mSlots.mVolumeScale.mVariance[i][1] > 0)) + stream->write(mSlots.mVolumeScale.mVariance[i][1]); + if (stream->writeFlag(mSlots.mPitchScale.mValue[i] != 1)) + stream->write(mSlots.mPitchScale.mValue[i]); + if (stream->writeFlag(mSlots.mPitchScale.mVariance[i][0] > 0)) + stream->write(mSlots.mPitchScale.mVariance[i][0]); + if (stream->writeFlag(mSlots.mPitchScale.mVariance[i][1] > 0)) + stream->write(mSlots.mPitchScale.mVariance[i][1]); + if (stream->writeFlag(mSlots.mRepeatCount[i] > 0)) + stream->write(mSlots.mRepeatCount[i]); + + sfxWrite(stream, mSlots.mState[i]); + sfxWrite(stream, mSlots.mTrack[i]); + } } //----------------------------------------------------------------------------- @@ -442,36 +490,39 @@ void SFXPlayList::unpackData( BitStream* stream ) mRandomMode = ( ERandomMode ) stream->readInt( NUM_RANDOM_MODE_BITS ); mLoopMode = ( ELoopMode ) stream->readInt( NUM_LOOP_MODE_BITS ); mNumSlotsToPlay = stream->readInt( NUM_SLOTS_TO_PLAY_BITS ); - - FOR_EACH_SLOT mSlots.mReplayMode[ i ] = ( EReplayMode ) stream->readInt( NUM_REPLAY_MODE_BITS ); - FOR_EACH_SLOT mSlots.mTransitionIn[ i ] = ( ETransitionMode ) stream->readInt( NUM_TRANSITION_MODE_BITS ); - FOR_EACH_SLOT mSlots.mTransitionOut[ i ] = ( ETransitionMode ) stream->readInt( NUM_TRANSITION_MODE_BITS ); - FOR_EACH_SLOT mSlots.mStateMode[ i ] = ( EStateMode ) stream->readInt( NUM_STATE_MODE_BITS ); - - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mFadeTimeIn.mValue[ i ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mFadeTimeIn.mVariance[ i ][ 0 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mFadeTimeIn.mVariance[ i ][ 1 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mFadeTimeOut.mValue[ i ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mFadeTimeOut.mVariance[ i ][ 0 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mFadeTimeOut.mVariance[ i ][ 1 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mDelayTimeIn.mValue[ i ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mDelayTimeIn.mVariance[ i ][ 0 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mDelayTimeIn.mVariance[ i ][ 1 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mDelayTimeOut.mValue[ i ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mDelayTimeOut.mVariance[ i ][ 0 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mDelayTimeOut.mVariance[ i ][ 1 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mVolumeScale.mValue[ i ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mVolumeScale.mVariance[ i ][ 0 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mVolumeScale.mVariance[ i ][ 1 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mPitchScale.mValue[ i ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mPitchScale.mVariance[ i ][ 0 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mPitchScale.mVariance[ i ][ 1 ] );} - FOR_EACH_SLOT if(stream->readFlag()){ stream->read( &mSlots.mRepeatCount[ i ] );} - - FOR_EACH_SLOT sfxRead( stream, &mSlots.mState[ i ] ); - FOR_EACH_SLOT UNPACKDATA_SOUNDASSET_ARRAY(Track, i); - - #undef FOR_EACH_SLOT + + mActiveSlots = stream->readInt(8); + + for (U32 i = 0; i < mActiveSlots; ++i) + { + mSlots.mReplayMode[i] = (EReplayMode)stream->readInt(NUM_REPLAY_MODE_BITS); + mSlots.mTransitionIn[i] = (ETransitionMode)stream->readInt(NUM_TRANSITION_MODE_BITS); + mSlots.mTransitionOut[i] = (ETransitionMode)stream->readInt(NUM_TRANSITION_MODE_BITS); + mSlots.mStateMode[i] = (EStateMode)stream->readInt(NUM_STATE_MODE_BITS); + + if (stream->readFlag()) { stream->read(&mSlots.mFadeTimeIn.mValue[i]); } + if (stream->readFlag()) { stream->read(&mSlots.mFadeTimeIn.mVariance[i][0]); } + if (stream->readFlag()) { stream->read(&mSlots.mFadeTimeIn.mVariance[i][1]); } + if (stream->readFlag()) { stream->read(&mSlots.mFadeTimeOut.mValue[i]); } + if (stream->readFlag()) { stream->read(&mSlots.mFadeTimeOut.mVariance[i][0]); } + if (stream->readFlag()) { stream->read(&mSlots.mFadeTimeOut.mVariance[i][1]); } + if (stream->readFlag()) { stream->read(&mSlots.mDelayTimeIn.mValue[i]); } + if (stream->readFlag()) { stream->read(&mSlots.mDelayTimeIn.mVariance[i][0]); } + if (stream->readFlag()) { stream->read(&mSlots.mDelayTimeIn.mVariance[i][1]); } + if (stream->readFlag()) { stream->read(&mSlots.mDelayTimeOut.mValue[i]); } + if (stream->readFlag()) { stream->read(&mSlots.mDelayTimeOut.mVariance[i][0]); } + if (stream->readFlag()) { stream->read(&mSlots.mDelayTimeOut.mVariance[i][1]); } + if (stream->readFlag()) { stream->read(&mSlots.mVolumeScale.mValue[i]); } + if (stream->readFlag()) { stream->read(&mSlots.mVolumeScale.mVariance[i][0]); } + if (stream->readFlag()) { stream->read(&mSlots.mVolumeScale.mVariance[i][1]); } + if (stream->readFlag()) { stream->read(&mSlots.mPitchScale.mValue[i]); } + if (stream->readFlag()) { stream->read(&mSlots.mPitchScale.mVariance[i][0]); } + if (stream->readFlag()) { stream->read(&mSlots.mPitchScale.mVariance[i][1]); } + if (stream->readFlag()) { stream->read(&mSlots.mRepeatCount[i]); } + + sfxRead(stream, &mSlots.mState[i]); + sfxRead(stream, &mSlots.mTrack[i]); + } } //----------------------------------------------------------------------------- @@ -486,8 +537,8 @@ void SFXPlayList::inspectPostApply() void SFXPlayList::validate() { - if( mNumSlotsToPlay > NUM_SLOTS ) - mNumSlotsToPlay = NUM_SLOTS; + if( mNumSlotsToPlay > mActiveSlots ) + mNumSlotsToPlay = mActiveSlots; mSlots.mFadeTimeIn.validate(); mSlots.mFadeTimeOut.validate(); diff --git a/Engine/source/sfx/sfxPlayList.h b/Engine/source/sfx/sfxPlayList.h index 1043bf988..8fa0df89c 100644 --- a/Engine/source/sfx/sfxPlayList.h +++ b/Engine/source/sfx/sfxPlayList.h @@ -30,13 +30,8 @@ #include "sfx/sfxTrack.h" #endif -#ifndef SOUND_ASSET_H -#include "T3D/assets/SoundAsset.h" -#endif - - class SFXState; - +class SFXDescription; /// A playback list of SFXTracks. /// @@ -79,7 +74,7 @@ class SFXPlayList : public SFXTrack typedef SFXTrack Parent; - enum + enum SFXPlaylistSettings { /// Number of slots in a playlist. /// @@ -261,6 +256,9 @@ class SFXPlayList : public SFXTrack /// is playing. EStateMode mStateMode[ NUM_SLOTS ]; + /// Track to play in this slot. + SFXTrack* mTrack[NUM_SLOTS]; + SlotData() { dMemset( mReplayMode, 0, sizeof( mReplayMode ) ); @@ -268,6 +266,7 @@ class SFXPlayList : public SFXTrack dMemset( mTransitionOut, 0, sizeof( mTransitionOut ) ); dMemset( mRepeatCount, 0, sizeof( mRepeatCount ) ); dMemset( mState, 0, sizeof( mState ) ); + dMemset( mTrack, 0, sizeof( mTrack ) ); dMemset( mStateMode, 0, sizeof( mStateMode ) ); for( U32 i = 0; i < NUM_SLOTS; ++ i ) @@ -282,31 +281,33 @@ class SFXPlayList : public SFXTrack } } }; - DECLARE_SOUNDASSET_ARRAY(SFXPlayList, Track, NUM_SLOTS); - DECLARE_ASSET_ARRAY_SETGET(SFXPlayList, Track); - protected: - + public: + // moved to public for soundasset + /// Trace interpreter execution. This field is not networked. bool mTrace; - + /// Select slots at random. ERandomMode mRandomMode; - + /// Loop over slots in this list. ELoopMode mLoopMode; - + /// Number of slots to play from list. This can be used, for example, /// to create a list of tracks where only a single track is selected and /// played for each cycle. U32 mNumSlotsToPlay; - + /// Data for each of the playlist slots. SlotData mSlots; - - public: - + + U32 mActiveSlots; + SFXPlayList(); + + /// The destructor. + virtual ~SFXPlayList(); /// Make all settings conform to constraints. void validate(); @@ -324,7 +325,7 @@ class SFXPlayList : public SFXTrack ELoopMode getLoopMode() const { return mLoopMode; } /// Return the total number of slots in the list. - U32 getNumSlots() const { return NUM_SLOTS; } + U32 getNumSlots(); /// Return the slot data for this list. const SlotData& getSlots() const { return mSlots; } @@ -332,8 +333,13 @@ class SFXPlayList : public SFXTrack DECLARE_CONOBJECT( SFXPlayList ); DECLARE_CATEGORY( "SFX" ); DECLARE_DESCRIPTION( "A playback list of SFXProfiles or nested SFXPlayLists." ); - + + // SFXTrack. + virtual bool isLooping() const; + // SimDataBlock. + bool onAdd(); + void onRemove(); virtual bool preload( bool server, String& errorStr ); virtual void packData( BitStream* stream ); virtual void unpackData( BitStream* stream ); diff --git a/Engine/source/sfx/sfxSound.h b/Engine/source/sfx/sfxSound.h index 364f2ed59..7494e3846 100644 --- a/Engine/source/sfx/sfxSound.h +++ b/Engine/source/sfx/sfxSound.h @@ -143,7 +143,7 @@ class SFXSound : public SFXSource, bool isBlocked() const { return ( mVoice && mVoice->getStatus() == SFXStatusBlocked ); } /// Returns true if this is a continuously streaming source. - bool isStreaming() const { return mDescription->mIsStreaming; } + bool isStreaming() const { return mDescription ? mDescription->mIsStreaming : false; } /// Returns true if the source's associated data is ready for playback. bool isReady() const; diff --git a/Engine/source/sfx/sfxSource.cpp b/Engine/source/sfx/sfxSource.cpp index 51e09d795..4a1765c53 100644 --- a/Engine/source/sfx/sfxSource.cpp +++ b/Engine/source/sfx/sfxSource.cpp @@ -192,18 +192,18 @@ SFXSource::SFXSource() mSavedStatus( SFXStatusNull ), mStatusCallback( NULL ), mDescription( NULL ), - mVolume( 1.f ), - mPreFadeVolume( 1.f ), - mFadedVolume( 1.f ), - mModulativeVolume( 1.f ), - mPreAttenuatedVolume( 1.f ), - mAttenuatedVolume( 1.f ), + mVolume( 1.0f ), + mPreFadeVolume( 1.0f ), + mFadedVolume( 1.0f ), + mModulativeVolume( 1.0f ), + mPreAttenuatedVolume( 1.0f ), + mAttenuatedVolume( 1.0f ), mPriority( 0 ), - mModulativePriority( 1.f ), + mModulativePriority( 1.0f ), mEffectivePriority( 0 ), mPitch( 1.f ), - mModulativePitch( 1.f ), - mEffectivePitch( 1.f ), + mModulativePitch( 1.0f ), + mEffectivePitch( 1.0f ), mTransform( true ), mVelocity( 0, 0, 0 ), mMinDistance( 1 ), @@ -213,14 +213,14 @@ SFXSource::SFXSource() mConeOutsideVolume( 1 ), mDistToListener( 0.f ), mTransformScattered( false ), - mFadeInTime( 0.f ), - mFadeOutTime( 0.f ), - mFadeInPoint( -1.f ), - mFadeOutPoint( -1.f ), + mFadeInTime( 0.0f ), + mFadeOutTime( 0.0f ), + mFadeInPoint( -1.0f ), + mFadeOutPoint( -1.0f ), mFadeSegmentType( FadeSegmentNone ), mFadeSegmentEase( NULL ), - mFadeSegmentStartPoint( 0.f ), - mFadeSegmentEndPoint( 0.f ), + mFadeSegmentStartPoint( 0.0f ), + mFadeSegmentEndPoint( 0.0f ), mSavedFadeTime( -1.f ), mPlayStartTick( 0 ) { @@ -236,17 +236,17 @@ SFXSource::SFXSource( SFXTrack* track, SFXDescription* description ) mTrack( track ), mDescription( description ), mVolume( 1.f ), - mPreFadeVolume( 1.f ), - mFadedVolume( 1.f ), - mModulativeVolume( 1.f ), - mPreAttenuatedVolume( 1.f ), - mAttenuatedVolume( 1.f ), + mPreFadeVolume( 1.0f ), + mFadedVolume( 1.0f ), + mModulativeVolume( 1.0f ), + mPreAttenuatedVolume( 1.0f ), + mAttenuatedVolume( 1.0f ), mPriority( 0 ), - mModulativePriority( 1.f ), + mModulativePriority( 1.0f ), mEffectivePriority( 0 ), - mPitch( 1.f ), - mModulativePitch( 1.f ), - mEffectivePitch( 1.f ), + mPitch( 1.0f ), + mModulativePitch( 1.0f ), + mEffectivePitch( 1.0f ), mTransform( true ), mVelocity( 0, 0, 0 ), mMinDistance( 1 ), @@ -256,15 +256,15 @@ SFXSource::SFXSource( SFXTrack* track, SFXDescription* description ) mConeOutsideVolume( 1 ), mDistToListener( 0.f ), mTransformScattered( false ), - mFadeInTime( 0.f ), - mFadeOutTime( 0.f ), - mFadeInPoint( -1.f ), - mFadeOutPoint( -1.f ), + mFadeInTime( 0.0f ), + mFadeOutTime( 0.0f ), + mFadeInPoint( -1.0f ), + mFadeOutPoint( -1.0f ), mFadeSegmentType( FadeSegmentNone ), mFadeSegmentEase( NULL ), - mFadeSegmentStartPoint( 0.f ), - mFadeSegmentEndPoint( 0.f ), - mSavedFadeTime( -1.f ), + mFadeSegmentStartPoint( 0.0f ), + mFadeSegmentEndPoint( 0.0f ), + mSavedFadeTime( -1.0f ), mPlayStartTick( 0 ) { VECTOR_SET_ASSOCIATION( mParameters );