mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
* GroundWork -Reverted SFXPlaylist since it is going to be made from an asset now instead. -Added extra options to soundAssets description. -SFXPlaylist may need an onAdd function * Update sfxController.cpp * SFXPlaylist data -Added sfxPlaylist init persist fields for the slots to sound asset -Added logic to fil sfxPlaylist if more than 1 slot is filled * Update SoundAsset.cpp to stop git ci complaining, assetImporter........ * Update SoundAsset.h * sfxPlaylist -Fix: incomplete type error -Added onAdd and onRemove to playlist -SoundAsset getProfile define now returns playlist if the asset is a playlist. * Update SoundAsset.h -updated asset array to return playlist or profile depending on what the asset is * SFXPlaylist working -SFXPlaylist works AudioChannelDefault gets its volume set to 0 for some reason and was throwing off making sfxPlaylist inaudible. Still an exception when closing if using a playlist trips on line 355 of sfxSound * Update sfxSound.h * setSoundFile index null fix * Update SoundAsset.h * Update SoundAsset.h * netstream safety in case of a null asset assignment * Update sfxController.cpp added safeties around a null playlist trying to play. * Update with Az's asset err code changes --------- Co-authored-by: AzaezelX <quillus@hotmail.com>
550 lines
28 KiB
C++
550 lines
28 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// 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, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// 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. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#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"
|
|
|
|
|
|
IMPLEMENT_CO_DATABLOCK_V1( SFXPlayList );
|
|
|
|
|
|
ConsoleDocClass( SFXPlayList,
|
|
"@brief A datablock describing a playback pattern of sounds.\n\n"
|
|
|
|
"Playlists allow to define intricate playback patterns of invidual tracks and thus allow the sound system to be "
|
|
"easily used for playing multiple sounds in single operations.\n\n"
|
|
|
|
"As playlists are %SFXTracks, they can thus be used anywhere in the engine where sound data can be assigned.\n\n"
|
|
|
|
"Each playlist can hold a maximum of 16 tracks. Longer playlists may be constructed by cascading lists, i.e. "
|
|
"by creating a playlist that references other playlists.\n\n"
|
|
|
|
"Processing of a single playlist slot progresses in a fixed set of steps that are invariably "
|
|
"iterated through for each slot (except the slot is assigned a state and its state is deactivated; in "
|
|
"this case, the controller will exit out of the slot directly):\n\n"
|
|
|
|
"<ol>\n"
|
|
"<li><b>delayIn:</b><p>Waits a set amount of time before processing the slot. This is 0 by default and "
|
|
"is determined by the #delayTimeIn (seconds to wait) and #delayTimeInVariance (bounds on randomization) "
|
|
"properties.</p></li>\n"
|
|
"<li><b>#transitionIn:</b><p>Decides what to do @b before playing the slot. Defaults to @c None which makes "
|
|
"this stage a no-operation. Alternatively, the slot can be configured to wait for playback of other "
|
|
"slots to finish (@c Wait and @c WaitAll) or to stop playback of other slots (@c Stop and @c StopAll). "
|
|
"Note that @c Wait and @c Stop always refer to the source that was last started by the list.</p></li>\n"
|
|
"<li><b>play:</b><p><p>Finally, the #track attached to the slot is played. However, this will only @b start "
|
|
"playback of the track and then immediately move on to the next stage. It will @b not wait for the "
|
|
"track to finish playing. Note also that depending on the @c replay setting for the slot, this "
|
|
"stage may pick up a source that is already playing on the slot rather than starting a new one.</p> "
|
|
"<p>Several slot properties (fade times, min/max distance, and volume/pitch scale) are used in this stage.</p></li>\n"
|
|
"<li><b>delayOut:</b><p>Waits a set amount of time before transitioning out of the slot. This works the "
|
|
"same as @c delayIn and is set to 0 by default (i.e. no delay).</p></li>\n"
|
|
"<li><b>#transitionOut:</b><p>Decides what to do @b after playing the slot. This works like #transitionIn.</p></li>\n"
|
|
"</ol>\n\n"
|
|
|
|
"This is a key difference to playlists in normal music players where upon reaching a certain slot, the slot "
|
|
"will immediately play and the player then wait for playback to finish before moving on to the next slot.\n\n"
|
|
|
|
"@note Be aware that time limits set on slot delays are soft limits. The sound system updates sound sources in discrete "
|
|
"(and equally system update frequency dependent) intervals which thus determines the granularity at which "
|
|
"time-outs can be handled.\n\n"
|
|
|
|
"@section SFXPlayList_randomization Value Randomization\n\n"
|
|
|
|
"For greater variety, many of the values for individual slots may be given a randomization limit that will "
|
|
"trigger a dynamic variance of the specified base value.\n\n"
|
|
|
|
"Any given field @c xyz that may be randomized has a corresponding field @c xyzVariance which is a two-dimensional "
|
|
"vector. The first number specifies the greatest value that may be subtracted from the given base value (i.e. the @c xyz field) "
|
|
"whereas the second number specifies the greatest value that may be added to the base value. Between these two limits, "
|
|
"a random number is generated.\n\n"
|
|
|
|
"The default variance settings of \"0 0\" will thus not allow to add or subtract anything from the base value and "
|
|
"effectively disable randomization.\n\n"
|
|
|
|
"Randomization is re-evaluated on each cycle through a list.\n\n"
|
|
|
|
"@section SFXPlayList_states Playlists and States\n\n"
|
|
|
|
"A unique aspect of playlists is that they allow their playback to be tied to the changing set of active sound states. "
|
|
"This feature enables playlists to basically connect to an extensible state machine that can be leveraged by the game "
|
|
"code to signal a multitude of different gameplay states with the audio system then automatically reacting to state "
|
|
"transitions.\n\n"
|
|
|
|
"Playlists react to states in three ways:\n"
|
|
|
|
"- Before a controller starts processing a slot it checks whether the slot is assigned a #state. If this is the "
|
|
"case, the controller checks whether the particular state is active. If it is not, the entire slot is skipped. "
|
|
"If it is, the controller goes on to process the slot.\n"
|
|
"- If a controller is in one of the delay stages for a slot that has a #state assigned and the state is deactivated, "
|
|
"the controller will stop the delay and skip any of the remaining processing stages for the slot.\n"
|
|
"- Once the play stage has been processed for a slot that has a #state assigned, the slot's #stateMode will determine "
|
|
"what happens with the playing sound source if the slot's state is deactivated while the sound is still playing.\n"
|
|
"\n"
|
|
|
|
"A simple example of how to make use of states in combination with playlists would be to set up a playlist for background "
|
|
"music that reacts to the mood of the current gameplay situation. For example, during combat, tenser music could play than "
|
|
"during normal exploration. To set this up, different %SFXStates would represent different moods in the game and the "
|
|
"background music playlist would have one slot set up for each such mood. By making use of volume fades and the "
|
|
"@c PauseWhenDeactivated #stateMode, smooth transitions between the various audio tracks can be produced.\n\n"
|
|
|
|
"@tsexample\n"
|
|
"// Create a play list from two SFXProfiles.\n"
|
|
"%playList = new SFXPlayList()\n"
|
|
"{\n"
|
|
" // Use a looped description so the list playback will loop.\n"
|
|
" description = AudioMusicLoop2D;\n"
|
|
"\n"
|
|
" track[ 0 ] = Profile1;\n"
|
|
" track[ 1 ] = Profile2;\n"
|
|
"};\n"
|
|
"\n"
|
|
"// Play the list.\n"
|
|
"sfxPlayOnce( %playList );\n"
|
|
"@endtsexample\n\n"
|
|
|
|
"@ref SFX_interactive\n\n"
|
|
|
|
"@ingroup SFX"
|
|
);
|
|
|
|
|
|
ImplementEnumType( SFXPlayListLoopMode,
|
|
"Playlist behavior when description is set to loop.\n\n"
|
|
"@see SFXDescription::isLooping\n\n"
|
|
"@see SFXPlayList::loopMode\n\n"
|
|
"@ingroup SFX" )
|
|
{ SFXPlayList::LOOP_All, "All",
|
|
"Loop over all slots, i.e. jump from last to first slot after all slots have played." },
|
|
{ SFXPlayList::LOOP_Single, "Single",
|
|
"Loop infinitely over the current slot. Only useful in combination with either states or manual playlist control." },
|
|
EndImplementEnumType;
|
|
|
|
ImplementEnumType( SFXPlayListRandomMode,
|
|
"Randomization pattern to apply to playlist slot playback order.\n\n"
|
|
"@see SFXPlayList::random\n\n"
|
|
"@ingroup SFX" )
|
|
{ SFXPlayList::RANDOM_NotRandom, "NotRandom",
|
|
"Play slots in sequential order. No randomization." },
|
|
{ SFXPlayList::RANDOM_StrictRandom, "StrictRandom",
|
|
"Play a strictly random selection of slots.\n\n"
|
|
"In this mode, a set of numSlotsToPlay random numbers between 0 and numSlotsToPlay-1 (inclusive), i.e. in the range of valid slot indices, is "
|
|
"generated and playlist slots are played back in the order of this list. This allows the same slot to occur multiple times in a list and, "
|
|
"consequentially, allows for other slots to not appear at all in a given slot ordering." },
|
|
{ SFXPlayList::RANDOM_OrderedRandom, "OrderedRandom",
|
|
"Play all slots in the list in a random order.\n\n"
|
|
"In this mode, the @c numSlotsToPlay slots from the list with valid tracks assigned are put into a random order and played. This guarantees "
|
|
"that each slots is played exactly once albeit at a random position in the total ordering." },
|
|
EndImplementEnumType;
|
|
|
|
ImplementEnumType( SFXPlayListTransitionMode,
|
|
"Playlist behavior when transitioning in and out of invididual slots.\n\n"
|
|
"Transition behaviors apply when the playback controller starts processing a playlist slot and when it ends processing a slot. Using transition "
|
|
"behaviors, playback can be synchronized.\n\n"
|
|
"@see SFXPlayList::transitionIn\n\n"
|
|
"@see SFXPlayList::transitionOut\n\n"
|
|
"@ingroup SFX" )
|
|
{ SFXPlayList::TRANSITION_None, "None",
|
|
"No transition. Immediately move on to processing the slot or immediately move on to the next slot." },
|
|
{ SFXPlayList::TRANSITION_Wait, "Wait",
|
|
"Wait for the sound source spawned last by this playlist to finish playing. Then proceed." },
|
|
{ SFXPlayList::TRANSITION_WaitAll, "WaitAll",
|
|
"Wait for all sound sources currently spawned by the playlist to finish playing. Then proceed." },
|
|
{ SFXPlayList::TRANSITION_Stop, "Stop",
|
|
"Stop the sound source spawned last by this playlist. Then proceed." },
|
|
{ SFXPlayList::TRANSITION_StopAll, "StopAll",
|
|
"Stop all sound sources spawned by the playlist. Then proceed." },
|
|
EndImplementEnumType;
|
|
|
|
ImplementEnumType( SFXPlayListReplayMode,
|
|
"Behavior when hitting the play stage of a slot that is still playing from a previous cycle.\n\n"
|
|
"@see SFXPlayList::replay\n\n"
|
|
"@ingroup SFX" )
|
|
{ SFXPlayList::REPLAY_IgnorePlaying, "IgnorePlaying",
|
|
"Ignore any sources that may already be playing on the slot and just create a new source." },
|
|
{ SFXPlayList::REPLAY_RestartPlaying, "RestartPlaying",
|
|
"Restart all sources that was last created for the slot." },
|
|
{ SFXPlayList::REPLAY_KeepPlaying, "KeepPlaying",
|
|
"Keep playing the current source(s) as if the source started last on the slot was created in this cycle. For this, "
|
|
"the sources associated with the slot are brought to the top of the play stack." },
|
|
{ SFXPlayList::REPLAY_StartNew, "StartNew",
|
|
"Stop all sources currently playing on the slot and then create a new source." },
|
|
{ SFXPlayList::REPLAY_SkipIfPlaying, "SkipIfPlaying",
|
|
"If there are sources already playing on the slot, skip the play stage." },
|
|
EndImplementEnumType;
|
|
|
|
ImplementEnumType( SFXPlayListStateMode,
|
|
"Reaction behavior when a state is changed incompatibly on a slot that has already started playing.\n\n"
|
|
"@see SFXPlayList::stateMode\n\n"
|
|
"@ingroup SFX" )
|
|
{ SFXPlayList::STATE_StopInactive, "StopWhenDeactivated",
|
|
"Stop the sources playing on the slot when a state changes to a setting that is incompatible with "
|
|
"the slot's state setting." },
|
|
{ SFXPlayList::STATE_PauseInactive, "PauseWhenDeactivated",
|
|
"Pause all sources playing on the slot when a state changes to a setting that is incompatible with the "
|
|
"slot's state setting.\n\n"
|
|
"When the slot's state is reactivated again, the sources will resume playback." },
|
|
{ SFXPlayList::STATE_IgnoreInactive, "IgnoreWhenDeactivated",
|
|
"Ignore when a state changes to a setting incompatible with the slot's state setting and just keep "
|
|
"playing sources attached to the slot." },
|
|
EndImplementEnumType;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SFXPlayList::SFXPlayList()
|
|
: mRandomMode( RANDOM_NotRandom ),
|
|
mLoopMode( LOOP_All ),
|
|
mTrace( false ),
|
|
mNumSlotsToPlay( NUM_SLOTS ),
|
|
mActiveSlots(12)
|
|
{
|
|
}
|
|
|
|
SFXPlayList::~SFXPlayList()
|
|
{
|
|
if (!isTempClone())
|
|
return;
|
|
|
|
// cleanup after a temp-clone
|
|
|
|
if (mDescription && mDescription->isTempClone())
|
|
{
|
|
delete mDescription;
|
|
mDescription = 0;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXPlayList::initPersistFields()
|
|
{
|
|
docsURL;
|
|
addGroup( "Sound" );
|
|
|
|
addField( "random", TYPEID< ERandomMode >(), Offset( mRandomMode, SFXPlayList ),
|
|
"Slot playback order randomization pattern.\n"
|
|
"By setting this field to something other than \"NotRandom\" to order in which slots of the "
|
|
"playlist are processed can be changed from sequential to a random pattern. This allows to "
|
|
"to create more varied playback patterns.\n"
|
|
"Defaults to \"NotRandom\"." );
|
|
addField( "loopMode", TYPEID< ELoopMode >(), Offset( mLoopMode, SFXPlayList ),
|
|
"Behavior when description has looping enabled.\n"
|
|
"The loop mode determines whether the list will loop over a single slot or loop over "
|
|
"all the entire list of slots being played.\n\n"
|
|
"@see SFXDescription::isLooping" );
|
|
addField( "numSlotsToPlay", TypeS32, Offset( mNumSlotsToPlay, SFXPlayList ),
|
|
"Number of slots to play.\n"
|
|
"Up to a maximum of 16, this field determines the number of slots that are taken from the "
|
|
"list for playback. Only slots that have a valid #track assigned will be considered for "
|
|
"this." );
|
|
|
|
addArray( "slots", NUM_SLOTS );
|
|
|
|
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.");
|
|
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 "
|
|
"how SFXController will handle these sources." );
|
|
addField( "transitionIn", TYPEID< ETransitionMode >(), Offset( mSlots.mTransitionIn, SFXPlayList ), 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< ETransitionMode >(), Offset( mSlots.mTransitionOut, SFXPlayList ), 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( mSlots.mDelayTimeIn.mValue, SFXPlayList ), NUM_SLOTS,
|
|
"Seconds to wait after moving into slot before #transitionIn." );
|
|
addField( "delayTimeInVariance", TypePoint2F, Offset( mSlots.mDelayTimeIn.mVariance, SFXPlayList ), NUM_SLOTS,
|
|
"Bounds on randomization of #delayTimeIn.\n\n"
|
|
"@ref SFXPlayList_randomization\n" );
|
|
addField( "delayTimeOut", TypeF32, Offset( mSlots.mDelayTimeOut.mValue, SFXPlayList ), NUM_SLOTS,
|
|
"Seconds to wait before moving out of slot after #transitionOut." );
|
|
addField( "delayTimeOutVariance", TypePoint2F, Offset( mSlots.mDelayTimeOut.mVariance, SFXPlayList ), NUM_SLOTS,
|
|
"Bounds on randomization of #delayTimeOut.\n\n"
|
|
"@ref SFXPlayList_randomization\n" );
|
|
addField( "fadeTimeIn", TypeF32, Offset( mSlots.mFadeTimeIn.mValue, SFXPlayList ), NUM_SLOTS,
|
|
"Seconds to fade sound in (-1 to use the track's own fadeInTime.)\n"
|
|
"@see SFXDescription::fadeTimeIn" );
|
|
addField( "fadeTimeInVariance", TypePoint2F, Offset( mSlots.mFadeTimeIn.mVariance, SFXPlayList ), NUM_SLOTS,
|
|
"Bounds on randomization of #fadeInTime.\n\n"
|
|
"@ref SFXPlayList_randomization\n" );
|
|
addField( "fadeTimeOut", TypeF32, Offset( mSlots.mFadeTimeOut.mValue, SFXPlayList ), NUM_SLOTS,
|
|
"Seconds to fade sound out (-1 to use the track's own fadeOutTime.)\n"
|
|
"@see SFXDescription::fadeTimeOut" );
|
|
addField( "fadeTimeOutVariance", TypePoint2F, Offset( mSlots.mFadeTimeOut.mVariance, SFXPlayList ), NUM_SLOTS,
|
|
"Bounds on randomization of #fadeOutTime\n\n"
|
|
"@ref SFXPlayList_randomization\n" );
|
|
addField( "referenceDistance", TypeF32, Offset( mSlots.mMinDistance.mValue, SFXPlayList ), 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( mSlots.mMinDistance.mVariance, SFXPlayList ), NUM_SLOTS,
|
|
"Bounds on randomization of #referenceDistance.\n\n"
|
|
"@ref SFXPlayList_randomization\n" );
|
|
addField( "maxDistance", TypeF32, Offset( mSlots.mMaxDistance.mValue, SFXPlayList ), 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( mSlots.mMaxDistance.mVariance, SFXPlayList ), NUM_SLOTS,
|
|
"Bounds on randomization of #maxDistance.\n\n"
|
|
"@ref SFXPlayList_randomization\n" );
|
|
addField( "volumeScale", TypeF32, Offset( mSlots.mVolumeScale.mValue, SFXPlayList ), 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( mSlots.mVolumeScale.mVariance, SFXPlayList ), NUM_SLOTS,
|
|
"Bounds on randomization of #volumeScale.\n\n"
|
|
"@ref SFXPlayList_randomization\n" );
|
|
addField( "pitchScale", TypeF32, Offset( mSlots.mPitchScale.mValue, SFXPlayList ), 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( mSlots.mPitchScale.mVariance, SFXPlayList ), NUM_SLOTS,
|
|
"Bounds on randomization of #pitchScale.\n\n"
|
|
"@ref SFXPlayList_randomization\n" );
|
|
addField( "repeatCount", TypeS32, Offset( mSlots.mRepeatCount, SFXPlayList ), NUM_SLOTS,
|
|
"Number of times to loop this slot." );
|
|
addField( "state", TypeSFXStateName, Offset( mSlots.mState, SFXPlayList ), NUM_SLOTS,
|
|
"State that must be active for this slot to play.\n\n"
|
|
"@ref SFXPlayList_states" );
|
|
addField( "stateMode", TYPEID< EStateMode >(), Offset( mSlots.mStateMode, SFXPlayList ), NUM_SLOTS,
|
|
"Behavior when assigned state is deactivated while slot is playing.\n\n"
|
|
"@ref SFXPlayList_states" );
|
|
|
|
endArray( "slots" );
|
|
|
|
endGroup( "Sound" );
|
|
|
|
addGroup( "Debug" );
|
|
|
|
addField( "trace", TypeBool, Offset( mTrace, SFXPlayList ),
|
|
"Enable/disable execution tracing for this playlist (local only).\n"
|
|
"If this is true, SFXControllers attached to the list will automatically run in trace mode." );
|
|
|
|
endGroup( "Debug" );
|
|
|
|
Parent::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 < mActiveSlots; ++ i )
|
|
{
|
|
if (!sfxResolve(&mSlots.mTrack[i], errorStr))
|
|
return false;
|
|
|
|
if (!sfxResolve(&mSlots.mState[i], errorStr))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXPlayList::packData( BitStream* stream )
|
|
{
|
|
Parent::packData( stream );
|
|
|
|
stream->writeInt( mRandomMode, NUM_RANDOM_MODE_BITS );
|
|
stream->writeInt( mLoopMode, NUM_LOOP_MODE_BITS );
|
|
stream->writeInt( mNumSlotsToPlay, NUM_SLOTS_TO_PLAY_BITS );
|
|
|
|
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]);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXPlayList::unpackData( BitStream* stream )
|
|
{
|
|
Parent::unpackData( 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 );
|
|
|
|
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]);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXPlayList::inspectPostApply()
|
|
{
|
|
Parent::inspectPostApply();
|
|
validate();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SFXPlayList::validate()
|
|
{
|
|
if( mNumSlotsToPlay > mActiveSlots )
|
|
mNumSlotsToPlay = mActiveSlots;
|
|
|
|
mSlots.mFadeTimeIn.validate();
|
|
mSlots.mFadeTimeOut.validate();
|
|
mSlots.mDelayTimeIn.validate();
|
|
mSlots.mDelayTimeOut.validate();
|
|
mSlots.mVolumeScale.validate();
|
|
mSlots.mPitchScale.validate();
|
|
}
|