// Copyright Epic Games, Inc. All Rights Reserved. /** Interface for Non Real-Time (NRT) Audio Analyzer UObjects. */ #pragma once #include "CoreMinimal.h" #include "IAudioAnalyzerNRTInterface.h" #include "AudioAnalyzerAsset.h" #include "Sound/SoundWave.h" #include "AudioAnalyzerNRT.generated.h" /** UAudioAnalyzerNRTSettings * * UAudioAnalyzerNRTSettings provides a way to store and reuse existing analyzer settings * across multiple analyzers. This class provides the interface and functionality to * automatically trigger reanalysis of audio across all analyzers associated with this * setting when when a UPROPERTY in this setting object is edited. * */ UCLASS(Abstract, EditInlineNew, BlueprintType, MinimalAPI) class UAudioAnalyzerNRTSettings : public UAudioAnalyzerAssetBase { GENERATED_BODY() public: #if WITH_EDITOR FAnalyzeAudioDelegate AnalyzeAudioDelegate; /** * Called when a UPROPERTY of this class is edited. Triggers * reanalysis of audio. * * This determines whether to trigger analysis by calling ShouldEventTriggerAnalysis(...) */ AUDIOANALYZER_API void PostEditChangeProperty (struct FPropertyChangedEvent & PropertyChangedEvent) override; /** * This returns true when the PropertyChangeEvent is due to update a setting property. * Override this method in order to customize this behavior. */ AUDIOANALYZER_API virtual bool ShouldEventTriggerAnalysis(struct FPropertyChangedEvent & PropertyChangeEvent); #endif }; /** UAudioAnalyzerNRT * * UAudioAnalyzerNRT applies an analyzer to a sound using specific settings, stores the * results and exposes them via blueprints. * * Subclasses of UAudioAnalyzerNRT must implement GetAnalyzerNRTFactoryName() to associate * the UAudioAnalyzerNRT with an IAudioAnalyzerNRTFactory implementation. * * To support blueprint access, subclasses can implement UFUNCTIONs to expose the data * returned by GetResult(). */ UCLASS(Abstract, EditInlineNew, BlueprintType, MinimalAPI) class UAudioAnalyzerNRT : public UAudioAnalyzerAssetBase { GENERATED_BODY() public: /** * ID to keep track of results. Useful for tracking most recent result when performing * asynchronous processing. */ typedef int32 FResultId; /** Thread safe shared point to result object. */ typedef TSharedPtr FResultSharedPtr; /** * The USoundWave which is analyzed. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=AudioAnalyzer, meta=(DisallowedClasses="/Script/MetasoundEngine.MetaSoundSource, /Script/Engine.SoundSourceBus")) TObjectPtr Sound; /** The duration of the analyzed audio in seconds. */ UPROPERTY(BlueprintReadOnly, Category=AudioAnalyzer) float DurationInSeconds; /** * Returns the result object generated by the associated IAudioAnalyzerNRTFactory. * The template argument must be the IAudioAnalyzerNRTResult subclass returned by * the associated IAudioAnalyzerNRTFactory. */ template TSharedPtr GetResult() { TSharedPtr ReturnedResult; { FScopeLock ResultLock(&ResultCriticalSection); ReturnedResult = StaticCastSharedPtr(Result); } return ReturnedResult; } /** * Returns the result object generated by the associated IAudioAnalyzerNRTFactory. * The template argument must be the IAudioAnalyzerNRTResult subclass returned by * the associated IAudioAnalyzerNRTFactory. */ template TSharedPtr GetResult() const { TSharedPtr ReturnedResult; { FScopeLock ResultLock(&ResultCriticalSection); ReturnedResult = StaticCastSharedPtr(Result); } return ReturnedResult; } /** * Implementations can override this method to create settings objects * specific for their analyzer. */ AUDIOANALYZER_API virtual TUniquePtr GetSettings(const float InSampleRate, const int32 InNumChannels) const; /** * Performs serialization of results. */ AUDIOANALYZER_API virtual void Serialize(FArchive& Ar) override; #if WITH_EDITOR AUDIOANALYZER_API void SetResult(FResultSharedPtr NewResult); /** This will only store the result if the passed InResultId matches the CurrentResultId. */ AUDIOANALYZER_API void SetResultIfLatest(FResultSharedPtr NewResult, FResultId InResultId); /** * Called before a UPROPERTY of this class is edited. This checks to see * if the UPROPERTY is a UAudioAnalyzerNRTSettings. If so, the previous settings' * AnalyzeAudioDelegate will be unbound from this object's AnalyzeAudio() */ AUDIOANALYZER_API void PreEditChange(FProperty* PropertyAboutToChange) override; /** * Called when a UPROPERTY of this class is edited. Triggering * reanalysis of audio when appropriate and binds new settings if the UPROPERTY * is a UAudioAnalyzerNRTSettings derived object. * * This determines whether to trigger analysis by calling ShouldEventTriggerAnalysis(...) */ AUDIOANALYZER_API void PostEditChangeProperty (struct FPropertyChangedEvent & PropertyChangedEvent) override; /** * Returns true when the PropertyChangeEvent is due to update SoundWave or Settings. */ AUDIOANALYZER_API virtual bool ShouldEventTriggerAnalysis(struct FPropertyChangedEvent & PropertyChangeEvent); /** Performs the analaysis of the audio */ UFUNCTION() AUDIOANALYZER_API void AnalyzeAudio(); #endif protected: #if WITH_EDITOR /** This sets the AnalyzeAudio callback to the delegate in settings. */ AUDIOANALYZER_API void SetSettingsDelegate(UAudioAnalyzerNRTSettings* InSettings); /** This removes the existing delegate handle from the current settings object */ AUDIOANALYZER_API void RemoveSettingsDelegate(UAudioAnalyzerNRTSettings* InSettings); #endif /* Subclasses must override this method in order to inform this object which AnalyzerNRTFactory to use for analysis */ AUDIOANALYZER_API virtual FName GetAnalyzerNRTFactoryName() const PURE_VIRTUAL(UAudioAnalyzerNRT::GetAnalyzerNRTFactoryName, return FName();); private: // Returns UAudioAnalyzerNRTSettings* if property points to a valid UAudioAnalyzerNRTSettings, otherwise returns nullptr. AUDIOANALYZER_API UAudioAnalyzerNRTSettings* GetSettingsFromProperty(FProperty* Property); TSharedPtr Result; // Critical section is mutable so it can still be locked within const methods. mutable FCriticalSection ResultCriticalSection; // Result id of the current result. TAtomic CurrentResultId; #if WITH_EDITOR TMap AnalyzeAudioDelegateHandles; #endif };