123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- //-----------------------------------------------------------------------------
- // 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/sfxParameter.h"
- #include "console/consoleTypes.h"
- #include "console/simBase.h"
- #include "console/engineAPI.h"
- #include "console/simSet.h"
- #include "math/mMathFn.h"
- #include "math/mathTypes.h"
- #include "math/mathIO.h"
- #include "core/stream/bitStream.h"
- #include "platform/typetraits.h"
- IMPLEMENT_CONOBJECT( SFXParameter );
- ConsoleDocClass( SFXParameter,
- "@brief A sound channel value that can be bound to multiple sound sources.\n\n"
-
- "Parameters are special objects that isolate a specific property that sound sources can have and allows to bind "
- "this isolated instance to multiple sound sources such that when the value of the parameter changes, all sources "
- "bound to the parameter will have their respective property changed.\n\n"
-
- "Parameters are identified and referenced by their #internalName. This means that the SFXDescription::parameters and "
- "SFXTrack::parameters fields should contain the #internalNames of the SFXParameter objects which should be attached to "
- "the SFXSources when they are created. No two SFXParameters should have the same #internalName.\n\n"
-
- "All SFXParameter instances are automatically made children of the SFXParameterGroup.\n\n"
-
- "@note To simply control the volume and/or pitch levels of a group of sounds, it is easier and more efficient to use "
- "a sound source group rather than SFXParameters (see @ref SFXSource_hierarchies). Simply create a SFXSource object representing the group, assign "
- "SFXDescription::sourceGroup of the sounds appropriately, and then set the volume and/or pitch level of the group to "
- "modulate the respective properties of all children.\n\n"
-
- "@section SFXParameter_updates Parameter Updates\n"
-
- "Parameters are periodically allowed to update their own values. This makes it possible to attach custom logic to a parameter "
- "and have individual parameters synchronize their values autonomously. Use the onUpdate() callback to attach "
- "script code to a parameter update.\n\n"
-
- "@tsexample\n"
- "new SFXParameter( EngineRPMLevel )\n"
- "{\n"
- " // Set the name by which this parameter is identified.\n"
- " internalName = \"EngineRPMLevel\";\n"
- "\n"
- " // Let this parameter control the pitch of attached sources to simulate engine RPM ramping up and down.\n"
- " channel = \"Pitch\";\n"
- "\n"
- " // Start out with unmodified pitch.\n"
- " defaultValue = 1;\n"
- "\n"
- " // Add a texture description of what this parameter does.\n"
- " description = \"Engine RPM Level\";\n"
- "};\n"
- "\n"
- "// Create a description that automatically attaches the engine RPM parameter.\n"
- "singleton SFXDescription( EngineRPMSound : AudioLoop2D )\n"
- "{\n"
- " parameters[ 0 ] = \"EngineRPMLevel\";\n"
- "};\n"
- "\n"
- "// Create sound sources for the engine.\n"
- "sfxCreateSource( EngineRPMSound, \"art/sound/engine/enginePrimary\" );\n"
- "sfxCreateSource( EngineRPMSound, \"art/sound/engine/engineSecondary\" );\n"
- "\n"
- "// Setting the parameter value will now affect the pitch level of both sound sources.\n"
- "EngineRPMLevel.value = 0.5;\n"
- "EngineRPMLevel.value = 1.5;\n"
- "@endtsexample\n\n"
-
- "@ref SFX_interactive\n\n"
- "@ingroup SFX"
- );
- IMPLEMENT_CALLBACK( SFXParameter, onUpdate, void, (), (),
- "Called when the sound system triggers an update on the parameter.\n"
- "This occurs periodically during system operation." );
- //-----------------------------------------------------------------------------
- SFXParameter::SFXParameter()
- : mValue( 1.f ),
- mRange( 0.f, 1.f ),
- mChannel( SFXChannelVolume ),
- mDefaultValue( 1.f )
- {
- }
- //-----------------------------------------------------------------------------
- SFXParameter::~SFXParameter()
- {
- }
- //-----------------------------------------------------------------------------
- void SFXParameter::initPersistFields()
- {
- addGroup( "Sound" );
-
- addProtectedField( "value", TypeF32, Offset( mValue, SFXParameter ),
- &SFXParameter::_setValue, &defaultProtectedGetFn,
- "Current value of the audio parameter.\n"
- "All attached sources are notified when this value changes." );
- addProtectedField( "range", TypePoint2F, Offset( mRange, SFXParameter ),
- &SFXParameter::_setRange, &defaultProtectedGetFn,
- "Permitted range for #value.\n"
- "Minimum and maximum allowed value for the parameter. Both inclusive.\n\n"
- "For all but the User0-3 channels, this property is automatically set up by SFXParameter." );
- addProtectedField( "channel", TYPEID< SFXChannel >(), Offset( mChannel, SFXParameter ),
- &SFXParameter::_setChannel, &defaultProtectedGetFn,
- "Channel that the parameter controls.\n"
- "This controls which property of the sources it is attached to the parameter controls." );
- addProtectedField( "defaultValue", TypeF32, Offset( mDefaultValue, SFXParameter ),
- &SFXParameter::_setDefaultValue, &defaultProtectedGetFn,
- "Value to which the parameter is initially set.\n"
- "When the parameter is first added to the system, #value will be set to #defaultValue." );
- addField( "description", TypeRealString,Offset( mDescription, SFXParameter ),
- "Textual description of the parameter.\n"
- "Primarily for use in the Audio Parameters dialog of the editor to allow for easier identification "
- "of parameters." );
-
- endGroup( "Sound" );
-
- Parent::initPersistFields();
- }
- //-----------------------------------------------------------------------------
- bool SFXParameter::_setValue( void *object, const char *index, const char *data )
- {
- reinterpret_cast< SFXParameter* >( object )->setValue( dAtof( data ) );
- return false;
- }
- //-----------------------------------------------------------------------------
- bool SFXParameter::_setRange( void *object, const char *index, const char *data )
- {
- Point2F range = EngineUnmarshallData< Point2F >()( data );
- reinterpret_cast< SFXParameter* >( object )->setRange( range );
- return false;
- }
- //-----------------------------------------------------------------------------
- bool SFXParameter::_setChannel( void *object, const char *index, const char *data )
- {
- SFXChannel channel = EngineUnmarshallData< SFXChannel >()( data );
- reinterpret_cast< SFXParameter* >( object )->setChannel( channel );
- return false;
- }
- //-----------------------------------------------------------------------------
- bool SFXParameter::_setDefaultValue( void *object, const char *index, const char *data )
- {
- reinterpret_cast< SFXParameter* >( object )->setDefaultValue( dAtof( data ) );
- return false;
- }
- //-----------------------------------------------------------------------------
- bool SFXParameter::onAdd()
- {
- if( !Parent::onAdd() )
- return false;
-
- mValue = mDefaultValue;
-
- // Make sure the parameter has a name.
-
- if( !getInternalName() || !getInternalName()[ 0 ] )
- {
- Con::errorf( "SFXParameter::onAdd - %i (%s): parameter object does not have a name", getId(), getName() );
- return false;
- }
-
- // Make sure the parameter has a unique name.
-
- if( find( getInternalName() ) )
- {
- Con::errorf( "SFXParameter::onAdd - %i (%s): a parameter called '%s' already exists", getId(), getName(), getInternalName() );
- return false;
- }
-
- // Add us to the SFXParameter group.
-
- Sim::getSFXParameterGroup()->addObject( this );
-
- return true;
- }
- //-----------------------------------------------------------------------------
- void SFXParameter::onRemove()
- {
- mEventSignal.trigger( this, SFXParameterEvent_Deleted );
- Parent::onRemove();
- }
- //-----------------------------------------------------------------------------
- void SFXParameter::update()
- {
- onUpdate_callback();
- }
- //-----------------------------------------------------------------------------
- void SFXParameter::reset()
- {
- setValue( mDefaultValue );
- }
- //-----------------------------------------------------------------------------
- void SFXParameter::setValue( F32 value )
- {
- if( value == mValue )
- return;
-
- mValue = mClampF( value, mRange.x, mRange.y );
- mEventSignal.trigger( this, SFXParameterEvent_ValueChanged );
- }
- //-----------------------------------------------------------------------------
- void SFXParameter::setDefaultValue( F32 value )
- {
- mDefaultValue = mClampF( value, mRange.x, mRange.y );
- }
- //-----------------------------------------------------------------------------
- void SFXParameter::setRange( const Point2F& range )
- {
- if( range == mRange )
- return;
-
- mRange = range;
-
- F32 value = mClampF( mValue, mRange.x, mRange.y );
- if( value != mValue )
- setValue( value );
-
- mDefaultValue = mClampF( mDefaultValue, mRange.x, mRange.y );
- }
- //-----------------------------------------------------------------------------
- void SFXParameter::setChannel( SFXChannel channel )
- {
- if( mChannel == channel )
- return;
-
- mChannel = channel;
-
- F32 value = mValue;
- switch( channel )
- {
- case SFXChannelVolume:
- case SFXChannelConeOutsideVolume:
- setRange( 0.f, 1.0f );
- break;
-
- case SFXChannelConeInsideAngle:
- case SFXChannelConeOutsideAngle:
- setRange( 0.f, 360.f );
- break;
-
- case SFXChannelPitch:
- case SFXChannelMinDistance:
- case SFXChannelMaxDistance:
- case SFXChannelCursor:
- setRange( 0.f, TypeTraits< F32 >::MAX );
- break;
-
- case SFXChannelStatus:
- setRange( F32( SFXStatusPlaying ), F32( SFXStatusStopped ) );
- break;
-
- default:
- setRange( TypeTraits< F32 >::MIN, TypeTraits< F32 >::MAX );
- break;
- }
-
- // If the range setting did not result in the value already
- // being changed, fire a value-change signal now so that sources
- // can catch on to the new semantics. Unfortunately, we can't
- // do something about the old semantic's value having been
- // changed by us.
-
- if( mValue == value )
- mEventSignal.trigger( this, SFXParameterEvent_ValueChanged );
- }
- //-----------------------------------------------------------------------------
- SFXParameter* SFXParameter::find( StringTableEntry name )
- {
- return dynamic_cast< SFXParameter* >(
- Sim::getSFXParameterGroup()->findObjectByInternalName( name )
- );
- }
- //=============================================================================
- // Console Methods.
- //=============================================================================
- // MARK: ---- Console Methods ----
- //-----------------------------------------------------------------------------
- DefineEngineMethod( SFXParameter, getParameterName, String, (),,
- "Get the name of the parameter.\n"
- "@return The paramete name." )
- {
- return object->getInternalName();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( SFXParameter, reset, void, (),,
- "Reset the parameter's value to its default.\n"
- "@see SFXParameter::defaultValue\n" )
- {
- object->reset();
- }
|