From 4543aaec264ef048e8f78ff768d4520af07e3ccb Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Tue, 14 Feb 2023 18:54:25 -0600 Subject: [PATCH] audio gui control a gui element that plays a sound on loop, with minor configuration options and a logcal block for conditional plug in --- Engine/source/gui/shiny/guiAudioCtrl.cpp | 209 +++++++++++++++++++++++ Engine/source/gui/shiny/guiAudioCtrl.h | 102 +++++++++++ 2 files changed, 311 insertions(+) create mode 100644 Engine/source/gui/shiny/guiAudioCtrl.cpp create mode 100644 Engine/source/gui/shiny/guiAudioCtrl.h diff --git a/Engine/source/gui/shiny/guiAudioCtrl.cpp b/Engine/source/gui/shiny/guiAudioCtrl.cpp new file mode 100644 index 000000000..62678f045 --- /dev/null +++ b/Engine/source/gui/shiny/guiAudioCtrl.cpp @@ -0,0 +1,209 @@ +//----------------------------------------------------------------------------- +// 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 "gui/shiny/guiAudioCtrl.h" +#include "console/engineAPI.h" +#include "sfx/sfxSystem.h" +#include "sfx/sfxTrack.h" +#include "sfx/sfxSource.h" +#include "sfx/sfxTypes.h" + +#define TickMs 32 + +IMPLEMENT_CONOBJECT( GuiAudioCtrl ); + +ConsoleDocClass( GuiAudioCtrl, + "@brief Brief Description.\n\n" + "Audio PLayback.\n\n" + + "@ingroup GuiUtil\n"); + +GuiAudioCtrl::GuiAudioCtrl() +{ + INIT_ASSET(Sound); + mTickPeriodMS = 100; + mLastThink = 0; + mCurrTick = 0; + mPlayIf = ""; + mSoundPlaying = NULL; + + mUseTrackDescriptionOnly = false; + mDescription.mIs3D = false; + mDescription.mIsLooping = true; + mDescription.mIsStreaming = false; + mDescription.mFadeInTime = -1.f; + mDescription.mFadeOutTime = -1.f; + + mVolume = 1; + mPitch = 1; + mFadeInTime = -1; + mFadeOutTime = -1; + mSourceGroup = NULL; + setProcessTicks(); +} + +GuiAudioCtrl::~GuiAudioCtrl() +{ + if (mSoundPlaying) + mSoundPlaying->stop(); + SFX_DELETE(mSoundPlaying); +} + +bool GuiAudioCtrl::onWake() +{ + return Parent::onWake(); +} + +void GuiAudioCtrl::onSleep() +{ + if (mSoundPlaying) + mSoundPlaying->stop(); + SFX_DELETE(mSoundPlaying); + Parent::onSleep(); +} + +void GuiAudioCtrl::processTick() +{ + + if (mLastThink + mTickPeriodMS < mCurrTick) + { + mCurrTick = 0; + mLastThink = 0; + if (isSoundValid()) + { + _update(); + } + } + else + { + mCurrTick += TickMs; + } +} + +bool GuiAudioCtrl::testCondition() +{ + if (mPlayIf.isEmpty()) + return true; //we've got no tests to run so just do it + + //test the mapper plugged in condition line + String resVar = getIdString() + String(".result"); + Con::setBoolVariable(resVar.c_str(), false); + String command = resVar + "=" + mPlayIf + ";"; + Con::evaluatef(command.c_str()); + if (Con::getBoolVariable(resVar.c_str()) == 1) + { + return true; + } + return false; +} + +void GuiAudioCtrl::initPersistFields() +{ + addGroup("Sounds"); + INITPERSISTFIELD_SOUNDASSET(Sound, GuiAudioCtrl, "Looping SoundAsset to play while GuiAudioCtrl is active."); + addField("tickPeriodMS", TypeS32, Offset(mTickPeriodMS, GuiAudioCtrl), + "@brief Time in milliseconds between calls to onTick().\n\n" + "@see onTickTrigger()\n"); + addField("playIf", TypeCommand, Offset(mPlayIf, GuiAudioCtrl), "evaluation condition to trip playback (true/false)"); + addField("useTrackDescriptionOnly", TypeBool, Offset(mUseTrackDescriptionOnly, GuiAudioCtrl), + "If this is true, all fields except for #playOnAdd and #track are ignored on the emitter object.\n" + "This is useful to prevent fields in the #track's description from being overridden by emitter fields."); + addField("sourceGroup", TypeSFXSourceName, Offset(mSourceGroup, GuiAudioCtrl), + "The SFXSource to which to assign the sound of this emitter as a child.\n" + "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n" + "@see SFXDescription::sourceGroup"); + addField("volume", TypeF32, Offset(mVolume, GuiAudioCtrl), + "Volume level to apply to the sound.\n" + "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n" + "@see SFXDescription::volume"); + addField("pitch", TypeF32, Offset(mPitch, GuiAudioCtrl), + "Pitch shift to apply to the sound. Default is 1 = play at normal speed.\n" + "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n" + "@see SFXDescription::pitch"); + addField("fadeInTime", TypeF32, Offset(mFadeInTime, GuiAudioCtrl), + "Number of seconds to gradually fade in volume from zero when playback starts.\n" + "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n" + "@see SFXDescription::fadeInTime"); + addField("fadeOutTime", TypeF32, Offset(mFadeOutTime, GuiAudioCtrl), + "Number of seconds to gradually fade out volume down to zero when playback is stopped or paused.\n" + "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n" + "@see SFXDescription::fadeOutTime"); + endGroup("Sounds"); + + Parent::initPersistFields(); +} + +void GuiAudioCtrl::_update() +{ + if (isSoundValid()) + { + //mLocalProfile = *mSoundAsset->getSfxProfile(); + mDescription = *mSoundAsset->getSfxDescription(); + } + + // Make sure all the settings are valid. + mDescription.validate(); + + bool useTrackDescriptionOnly = (mUseTrackDescriptionOnly && getSoundProfile()); + + if (getSoundProfile()) + { + if (mSoundPlaying == NULL) + { + mSoundPlaying = SFX->createSource(getSoundProfile()); + } + } + + // The rest only applies if we have a source. + if (mSoundPlaying && !useTrackDescriptionOnly) + { + + // Set the volume irrespective of the profile. + if (mSourceGroup) + { + mSourceGroup->addObject(mSoundPlaying); + mSoundPlaying->setVolume(mSourceGroup->getVolume() * mVolume); + } + else + { + mSoundPlaying->setVolume(mVolume); + } + + mSoundPlaying->setPitch(mPitch); + mSoundPlaying->setFadeTimes(mFadeInTime, mFadeOutTime); + + } + + if (testCondition() && isActive() && isAwake()) + { + if (mSoundPlaying && !mSoundPlaying->isPlaying()) + { + mSoundPlaying->play(); + } + } + else + { + if (mSoundPlaying != NULL) + { + mSoundPlaying->stop(); + } + } +} diff --git a/Engine/source/gui/shiny/guiAudioCtrl.h b/Engine/source/gui/shiny/guiAudioCtrl.h new file mode 100644 index 000000000..906fd7bf9 --- /dev/null +++ b/Engine/source/gui/shiny/guiAudioCtrl.h @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#ifndef _GUIAUDIOCTRL_H_ +#define _GUIAUDIOCTRL_H_ + +#ifndef _GUITICKCTRL_H_ +#include "gui/shiny/guiTickCtrl.h" +#endif + +#ifndef SOUND_ASSET_H +#include "T3D/assets/SoundAsset.h" +#endif + +/// This Gui Control is designed to be subclassed to let people create controls +/// which want to receive update ticks at a constant interval. This class was +/// created to be the Parent class of a control which used a DynamicTexture +/// along with a VectorField to create warping effects much like the ones found +/// in visualization displays for iTunes or Winamp. Those displays are updated +/// at the framerate frequency. This works fine for those effects, however for +/// an application of the same type of effects for things like Gui transitions +/// the framerate-driven update frequency is not desirable because it does not +/// allow the developer to be able to have any idea of a consistent user-experience. +/// +/// Enter the ITickable interface. This lets the Gui control, in this case, update +/// the dynamic texture at a constant rate of once per tick, even though it gets +/// rendered every frame, thus creating a framerate-independent update frequency +/// so that the effects are at a consistent speed regardless of the specifics +/// of the system the user is on. This means that the screen-transitions will +/// occur in the same time on a machine getting 300fps in the Gui shell as a +/// machine which gets 150fps in the Gui shell. +/// @see ITickable +class GuiAudioCtrl : public GuiTickCtrl +{ + typedef GuiTickCtrl Parent; + +private: + +protected: + + // So this can be instantiated and not be a pure virtual class + void interpolateTick( F32 delta ) {}; + void processTick(); + void advanceTime( F32 timeDelta ) {}; + + S32 mTickPeriodMS; + U32 mLastThink; + U32 mCurrTick; + String mPlayIf; + SFXSource* mSoundPlaying; + /// Whether to leave sound setup exclusively to the assigned mTrack and not + /// override part of the track's description with emitter properties. + bool mUseTrackDescriptionOnly; + + /// The description and variant values used by the local profile. + SFXDescription mDescription; + SFXSource* mSourceGroup; + F32 mVolume; + F32 mPitch; + F32 mFadeInTime; + F32 mFadeOutTime; + + /// Called when the emitter state has been marked + /// dirty and the source needs to be updated. + void _update(); + +public: + DECLARE_SOUNDASSET(GuiAudioCtrl, Sound); + DECLARE_ASSET_SETGET(GuiAudioCtrl, Sound); + GuiAudioCtrl(); + ~GuiAudioCtrl(); + // GuiControl. + bool onWake(); + void onSleep(); + void setActive(bool value) {}; + bool testCondition(); + static void initPersistFields(); + DECLARE_CONOBJECT(GuiAudioCtrl); + DECLARE_CATEGORY( "Gui Other" ); +}; + + +#endif