458 lines
17 KiB
C++
458 lines
17 KiB
C++
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2024.
|
|
|
|
#pragma once
|
|
|
|
#include "Containers/Map.h"
|
|
#include "Runtime/Launch/Resources/Version.h"
|
|
#include "Sound/SoundAttenuation.h"
|
|
#include "AudioDevice.h"
|
|
#include "FMODStudioModule.h"
|
|
#include "FMODUtils.h"
|
|
#include "FMODAudioComponent.generated.h"
|
|
|
|
// Event property
|
|
UENUM()
|
|
namespace EFMODEventProperty
|
|
{
|
|
enum Type
|
|
{
|
|
/* Priority to set on low-level channels created by this event instance (-1 to 256). */
|
|
ChannelPriority,
|
|
/** Schedule delay to synchronized playback for multiple tracks in DSP clocks, or -1 for default. */
|
|
ScheduleDelay,
|
|
/** Schedule look-ahead on the timeline in DSP clocks, or -1 for default. */
|
|
ScheduleLookahead,
|
|
/** Override the event's 3D minimum distance, or -1 for default. */
|
|
MinimumDistance,
|
|
/** Override the event's 3D maximum distance, or -1 for default. */
|
|
MaximumDistance,
|
|
/** Number of options */
|
|
Count
|
|
};
|
|
}
|
|
|
|
|
|
/** Used to store callback info from FMOD thread to our event */
|
|
struct FTimelineMarkerProperties
|
|
{
|
|
FString Name;
|
|
int32 Position;
|
|
FTimelineMarkerProperties()
|
|
: Position(0)
|
|
{}
|
|
};
|
|
|
|
/** Used to store callback info from FMOD thread to our event */
|
|
struct FTimelineBeatProperties
|
|
{
|
|
int32 Bar;
|
|
int32 Beat;
|
|
int32 Position;
|
|
float Tempo;
|
|
int32 TimeSignatureUpper;
|
|
int32 TimeSignatureLower;
|
|
FTimelineBeatProperties()
|
|
: Bar(0)
|
|
, Beat(0)
|
|
, Position(0)
|
|
, Tempo(0.0f)
|
|
, TimeSignatureUpper(0)
|
|
, TimeSignatureLower(0)
|
|
{}
|
|
};
|
|
|
|
USTRUCT(BlueprintType)
|
|
struct FFMODAttenuationDetails
|
|
{
|
|
GENERATED_USTRUCT_BODY()
|
|
/** Should we use Attenuation set in Studio or be able to modify in Editor. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FMOD|Attenuation")
|
|
uint32 bOverrideAttenuation : 1;
|
|
/** Override the event's 3D minimum distance. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FMOD|Attenuation",
|
|
meta = (ClampMin = "0.0", UIMin = "0.0", EditCondition = "bOverrideAttenuation"))
|
|
float MinimumDistance;
|
|
/** Override the event's 3D maximum distance. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FMOD|Attenuation",
|
|
meta = (ClampMin = "0.0", UIMin = "0.0", EditCondition = "bOverrideAttenuation"))
|
|
float MaximumDistance;
|
|
|
|
FFMODAttenuationDetails()
|
|
: bOverrideAttenuation(false)
|
|
, MinimumDistance(1.0f)
|
|
, MaximumDistance(10.0f)
|
|
{}
|
|
};
|
|
|
|
USTRUCT(BlueprintType)
|
|
struct FFMODOcclusionDetails
|
|
{
|
|
GENERATED_USTRUCT_BODY()
|
|
/** Enable Occlusion Settings. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FMOD|Occlusion")
|
|
bool bEnableOcclusion;
|
|
/* Which trace channel to use for audio occlusion checks. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FMOD|Occlusion", meta = (EditCondition = "bEnableOcclusion"))
|
|
TEnumAsByte<enum ECollisionChannel> OcclusionTraceChannel;
|
|
/** Whether or not to enable complex geometry occlusion checks. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="FMOD|Occlusion", meta=(EditCondition = "bEnableOcclusion"))
|
|
bool bUseComplexCollisionForOcclusion;
|
|
|
|
FFMODOcclusionDetails()
|
|
: bEnableOcclusion(false)
|
|
, OcclusionTraceChannel(ECC_Visibility)
|
|
, bUseComplexCollisionForOcclusion(false)
|
|
{}
|
|
};
|
|
|
|
/** called when an event stops, either because it played to completion or because a Stop() call turned it off early */
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnEventStopped);
|
|
/** called when a sound stops */
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnSoundStopped);
|
|
/** called when we reach a named marker on the timeline */
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnTimelineMarker, FString, Name, int32, Position);
|
|
/** called when we reach a beat on the timeline */
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(
|
|
FOnTimelineBeat, int32, Bar, int32, Beat, int32, Position, float, Tempo, int32, TimeSignatureUpper, int32, TimeSignatureLower);
|
|
|
|
namespace FMOD
|
|
{
|
|
class DSP;
|
|
class Sound;
|
|
namespace Studio
|
|
{
|
|
class EventDescription;
|
|
class EventInstance;
|
|
}
|
|
}
|
|
|
|
struct FMOD_STUDIO_TIMELINE_MARKER_PROPERTIES;
|
|
struct FMOD_STUDIO_TIMELINE_BEAT_PROPERTIES;
|
|
|
|
/**
|
|
* Plays FMOD Studio events.
|
|
*/
|
|
UCLASS(Blueprintable, ClassGroup = (Audio, Common), hidecategories = (Object, ActorComponent, Physics, Rendering, Mobility, LOD),
|
|
ShowCategories = Trigger, meta = (BlueprintSpawnableComponent))
|
|
class FMODSTUDIO_API UFMODAudioComponent : public USceneComponent
|
|
{
|
|
GENERATED_UCLASS_BODY()
|
|
|
|
friend struct FFMODEventControlExecutionToken;
|
|
friend struct FPlayingToken;
|
|
friend FMOD_RESULT F_CALLBACK UFMODAudioComponent_EventCallback(FMOD_STUDIO_EVENT_CALLBACK_TYPE type, FMOD_STUDIO_EVENTINSTANCE *event, void *parameters);
|
|
|
|
public:
|
|
/** The event asset to use for this sound. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FMODAudio)
|
|
UFMODEvent* Event;
|
|
|
|
/** Event parameter cache. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, SimpleDisplay, Category = FMODAudio)
|
|
TMap<FName, float> ParameterCache;
|
|
|
|
/** Sound name used for programmer sound. Will look up the name in any loaded audio table. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FMODAudio)
|
|
FString ProgrammerSoundName;
|
|
|
|
/** Enable timeline callbacks for this sound, so that OnTimelineMarker and OnTimelineBeat can be used. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FMODAudio)
|
|
uint32 bEnableTimelineCallbacks : 1;
|
|
|
|
/** Auto destroy this component on completion. */
|
|
UPROPERTY()
|
|
uint32 bAutoDestroy : 1;
|
|
|
|
/** Stop sound when owner is destroyed. */
|
|
UPROPERTY()
|
|
uint32 bStopWhenOwnerDestroyed : 1;
|
|
|
|
/** Whether we apply gain and low-pass based on audio zones. */
|
|
uint32 bApplyAmbientVolumes : 1;
|
|
|
|
/** Whether we apply gain and low-pass based on occlusion onto a parameter. */
|
|
uint32 bApplyOcclusionParameter:1;
|
|
|
|
/** Called when an event stops, either because it played to completion or because a Stop() call turned it off early. */
|
|
UPROPERTY(BlueprintAssignable)
|
|
FOnEventStopped OnEventStopped;
|
|
|
|
/** Called when a sound stops. */
|
|
UPROPERTY(BlueprintAssignable)
|
|
FOnSoundStopped OnSoundStopped;
|
|
|
|
/** Called when we reach a named marker (if bEnableTimelineCallbacks is true). */
|
|
UPROPERTY(BlueprintAssignable)
|
|
FOnTimelineMarker OnTimelineMarker;
|
|
|
|
/** Called when we reach a beat of a tempo (if bEnableTimelineCallbacks is true). */
|
|
UPROPERTY(BlueprintAssignable)
|
|
FOnTimelineBeat OnTimelineBeat;
|
|
|
|
/** New Event to be used by the FMODAudioComponent. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void SetEvent(UFMODEvent *NewEvent);
|
|
|
|
/** Start a sound playing on an audio component. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void Play();
|
|
|
|
/** Stop an audio component playing its sound cue, issue any delegates if needed. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void Stop();
|
|
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void Release();
|
|
|
|
/** Allow an event to continue past a sustain point. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void KeyOff();
|
|
|
|
/** Return true if this component is currently playing an event. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
bool IsPlaying();
|
|
|
|
/** Sets the volume level. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void SetVolume(float volume);
|
|
|
|
/** Sets the pitch multiplier. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void SetPitch(float pitch);
|
|
|
|
/** Pause/Unpause an audio component. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void SetPaused(bool paused);
|
|
|
|
/** Get the paused state of the audio component. Returns false if internal getPaused query fails. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
bool GetPaused();
|
|
|
|
/** Set a parameter of the Event. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void SetParameter(FName Name, float Value);
|
|
|
|
/** Will be deprecated in FMOD 2.01, use `GetParameterValue(FName, float, float)` instead.
|
|
* Get parameter value from the Event.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
float GetParameter(FName Name);
|
|
|
|
/** Get parameter value from the Event.
|
|
* @param Name - Name of parameter
|
|
* @param UserValue - Parameter value as set from the public API.
|
|
* @param FinalValue - Final combined parameter value.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void GetParameterValue(FName Name, float &UserValue, float &FinalValue);
|
|
|
|
/** Set a property of the Event. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void SetProperty(EFMODEventProperty::Type Property, float Value);
|
|
|
|
/** Get a property of the Event. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
float GetProperty(EFMODEventProperty::Type Property);
|
|
|
|
/** Get the event length in milliseconds. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
int32 GetLength() const;
|
|
|
|
/** Set the timeline position in milliseconds. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void SetTimelinePosition(int32 Time);
|
|
|
|
/** Get the timeline position in milliseconds. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
int32 GetTimelinePosition();
|
|
|
|
/** Set the sound name to use for programmer sound. Will look up the name in any loaded audio table. */
|
|
UFUNCTION(BlueprintCallable, Category = "Audio|FMOD|Components")
|
|
void SetProgrammerSoundName(FString Value);
|
|
|
|
/** Set a programmer sound to use for this audio component. Lifetime of sound must exceed that of the audio component. */
|
|
void SetProgrammerSound(FMOD::Sound *Sound);
|
|
|
|
/** FMOD Custom Attenuation Details. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FMODAudio)
|
|
struct FFMODAttenuationDetails AttenuationDetails;
|
|
|
|
/** FMOD Custom Occlusion Details. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FMODAudio)
|
|
struct FFMODOcclusionDetails OcclusionDetails;
|
|
|
|
/** Actual Studio instance handle. */
|
|
FMOD::Studio::EventInstance *StudioInstance;
|
|
|
|
// Begin UObject interface.
|
|
#if WITH_EDITOR
|
|
virtual void PostEditChangeProperty(FPropertyChangedEvent &e) override;
|
|
#endif // WITH_EDITOR
|
|
virtual void PostLoad() override;
|
|
// End UObject interface.
|
|
|
|
// Begin USceneComponent Interface
|
|
virtual void Activate(bool bReset = false) override;
|
|
virtual void Deactivate() override;
|
|
/** Called when a component is registered, after Scene is set, but before CreateRenderState_Concurrent or OnCreatePhysicsState are called. */
|
|
virtual void OnRegister() override;
|
|
/** Called when a component is unregistered. Called after DestroyRenderState_Concurrent and OnDestroyPhysicsState are called. */
|
|
virtual void OnUnregister() override;
|
|
// End USceneComponent Interface
|
|
|
|
// Begin ActorComponent interface.
|
|
/** Overridable native event for when play begins for this actor. */
|
|
virtual void BeginPlay() override;
|
|
/** Overridable function called whenever this actor is being removed from a level. */
|
|
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
|
/** Function called every frame on this ActorComponent. Only executes if the component is registered, and also PrimaryComponentTick.bCanEverTick must be set to true. */
|
|
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
|
// End ActorComponent interface.
|
|
|
|
protected:
|
|
// Begin UObject interface.
|
|
virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
|
|
// End UObject interface.
|
|
|
|
// Begin USceneComponent Interface
|
|
virtual FString GetDetailedInfoInternal() const override;
|
|
// End USceneComponent Interface
|
|
|
|
private:
|
|
bool bDefaultParameterValuesCached;
|
|
|
|
enum PauseContext
|
|
{
|
|
Explicit,
|
|
Implicit
|
|
};
|
|
|
|
/** Used for pausing from sequencer. */
|
|
bool bImplicitlyPaused = false;
|
|
|
|
/** Used for pausing from a direct call to pause. */
|
|
bool bExplicitlyPaused = false;
|
|
|
|
/** Stored properties to apply next time we create an instance. */
|
|
float StoredProperties[EFMODEventProperty::Count];
|
|
|
|
/** Internal play function which can play events in the editor. */
|
|
void PlayInternal(EFMODSystemContext::Type Context, bool bReset = false);
|
|
|
|
/** Pause the audio component from a sequencer call. */
|
|
void PauseInternal(PauseContext Pauser);
|
|
|
|
/** Resume the audio component from a sequencer call. */
|
|
void ResumeInternal(PauseContext Pauser);
|
|
|
|
/** Cache default event parameter values. */
|
|
void CacheDefaultParameterValues();
|
|
|
|
/** Check that only player driven parameters are added to the cache. */
|
|
void UpdateCachedParameterValues();
|
|
|
|
/** Update gain and low-pass based on interior volumes. */
|
|
void UpdateInteriorVolumes();
|
|
|
|
/** Update attenuation if we have it set. */
|
|
void UpdateAttenuation();
|
|
|
|
/** Apply Volume and LPF into event. */
|
|
void ApplyVolumeLPF();
|
|
|
|
/** Timeline Marker callback. */
|
|
void EventCallbackAddMarker(struct FMOD_STUDIO_TIMELINE_MARKER_PROPERTIES *props);
|
|
|
|
/** Timeline Beat callback. */
|
|
void EventCallbackAddBeat(struct FMOD_STUDIO_TIMELINE_BEAT_PROPERTIES *props);
|
|
|
|
/** Programmer Sound Create callback. */
|
|
void EventCallbackCreateProgrammerSound(struct FMOD_STUDIO_PROGRAMMER_SOUND_PROPERTIES *props);
|
|
|
|
/** Programmer Sound Destroy callback. */
|
|
void EventCallbackDestroyProgrammerSound(struct FMOD_STUDIO_PROGRAMMER_SOUND_PROPERTIES *props);
|
|
|
|
/** Called when the event has finished stopping. */
|
|
void OnPlaybackCompleted();
|
|
|
|
void EventCallbackSoundStopped();
|
|
bool TriggerSoundStoppedDelegate;
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
void UpdateSpriteTexture();
|
|
#endif
|
|
|
|
#if WITH_EDITOR
|
|
/** Function assigned to the FMODStudioModule PreShutdown delegate to clean up before the Studio System is released. */
|
|
void Shutdown();
|
|
#endif
|
|
|
|
/** Release any cached parameters then the Studio Instance. */
|
|
void ReleaseEventCache();
|
|
|
|
/** Release the Studio Instance. */
|
|
void ReleaseEventInstance();
|
|
|
|
/** Check if a parameter is game controlled or automated to determine if it should be cached. */
|
|
bool ShouldCacheParameter(const FMOD_STUDIO_PARAMETER_DESCRIPTION& ParameterDescription);
|
|
|
|
/** Return a cached reference to the current IFMODStudioModule.*/
|
|
IFMODStudioModule& GetStudioModule()
|
|
{
|
|
if (Module == nullptr)
|
|
{
|
|
Module = &IFMODStudioModule::Get();
|
|
}
|
|
return *Module;
|
|
}
|
|
/** Stored reference to the current IFMODStudioModule. */
|
|
IFMODStudioModule* Module;
|
|
|
|
// Settings for ambient volume effects.
|
|
/** Timer used for volumes fading in and out. Used for automating volume and/or LPF with Ambient Zones. */
|
|
double InteriorLastUpdateTime;
|
|
/** Previous interior volume value. Used for automating volume and/or LPF with Ambient Zones. */
|
|
float SourceInteriorVolume;
|
|
/** Previous interior LPF value. Used for automating volume and/or LPF with Ambient Zones. */
|
|
float SourceInteriorLPF;
|
|
/** Current interior volume value. Used for automating volume and/or LPF with Ambient Zones. */
|
|
float CurrentInteriorVolume;
|
|
/** Current interior LPF value. Used for automating volume and/or LPF with Ambient Zones. */
|
|
float CurrentInteriorLPF;
|
|
/** Calculated Ambient volume level for that frame. Used for automating volume and/or LPF with Ambient Zones. */
|
|
float AmbientVolume;
|
|
/** Calculated Ambient LPF level for that frame. Used for automating volume and/or LPF with Ambient Zones. */
|
|
float AmbientLPF;
|
|
/** Previously set Volume value. Used for automating volume and/or LPF with Ambient Zones. */
|
|
float LastVolume;
|
|
/** Previously set LPF value. Used for automating volume and/or LPF with Ambient Zones. */
|
|
float LastLPF;
|
|
/** Was the object occluded in the previous frame. */
|
|
bool wasOccluded;
|
|
/** Stored ID of the Occlusion parameter of the Event (if applicable). */
|
|
FMOD_STUDIO_PARAMETER_ID OcclusionID;
|
|
/** Stored ID of the Volume parameter of the Event (if applicable). */
|
|
FMOD_STUDIO_PARAMETER_ID AmbientVolumeID;
|
|
/** Stored ID of the LPF parameter of the Event (if applicable). */
|
|
FMOD_STUDIO_PARAMETER_ID AmbientLPFID;
|
|
|
|
// Tempo and marker callbacks.
|
|
/** A scope lock used specifically for callbacks. */
|
|
FCriticalSection CallbackLock;
|
|
/** Stores the Timeline Markers as they are triggered. */
|
|
TArray<FTimelineMarkerProperties> CallbackMarkerQueue;
|
|
/** Stores the Timeline Beats as they are triggered. */
|
|
TArray<FTimelineBeatProperties> CallbackBeatQueue;
|
|
|
|
/** Direct assignment of programmer sound from other C++ code. */
|
|
FMOD::Sound *ProgrammerSound;
|
|
bool NeedDestroyProgrammerSoundCallback;
|
|
/** The length of the current Event in milliseconds. */
|
|
int32 EventLength;
|
|
|
|
/** To prevent restarting by delayed state restore from sequencer. */
|
|
bool bPlayEnded;
|
|
|
|
FVector Velocity;
|
|
FVector LastLocation;
|
|
}; |