// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Async/AsyncWork.h" #include "AudioAnalyzerAsset.h" #include "AudioAnalyzerFacade.h" #include "AudioDefines.h" #include "CoreMinimal.h" #include "DSP/MultithreadedPatching.h" #include "IAudioAnalyzerInterface.h" #include "Sound/AudioBus.h" #include "AudioAnalyzer.generated.h" class UAudioAnalyzerSubsystem; /** UAudioAnalyzerSettings * * UAudioAnalyzerSettings provides a way to store and reuse existing analyzer settings * across multiple analyzers. * */ UCLASS(Abstract, EditInlineNew, BlueprintType, MinimalAPI) class UAudioAnalyzerSettings : public UAudioAnalyzerAssetBase { GENERATED_BODY() }; typedef TSharedPtr FAnalyzerResultSharedPtr; class FAudioAnalyzeTask : public FNonAbandonableTask { public: FAudioAnalyzeTask(TUniquePtr& InAnalyzerFacade, int32 InSampleRate, int32 InNumChannels); // Set in the task the current state of the analyzer controls void SetAnalyzerControls(TSharedPtr InControls); // Give the task the audio data to analyze void SetAudioBuffer(TArray&& InAudioData); // Move the audio buffer back out TArray&& GetAudioBuffer() { return MoveTemp(AudioData); } // Does the task work void DoWork(); FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(AudioAnalyzeTask, STATGROUP_ThreadPoolAsyncTasks); } // Get the results from the task TUniquePtr GetResults() { return MoveTemp(Results); } private: TUniquePtr AnalyzerFacade; int32 SampleRate = 0; int32 NumChannels = 0; TArray AudioData; TUniquePtr Results; TSharedPtr AnalyzerControls; }; /** UAudioAnalyzer * * UAudioAnalyzer performs analysis on an audio bus using specific settings and exposes the results via blueprints. * * Subclasses of UAudioAnalyzer must implement GetAnalyzerFactoryName() to associate * the UAudioAnalyzer asset with an IAudioAnalyzerFactory implementation. * * To support blueprint access, subclasses can implement UFUNCTIONs to expose the data * returned by GetResult(). */ UCLASS(Abstract, EditInlineNew, BlueprintType, MinimalAPI) class UAudioAnalyzer : public UObject { GENERATED_BODY() friend class UAudioAnalyzerSubsystem; 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 UAudioBus which is analyzed in real-time. */ UPROPERTY(Transient) TObjectPtr AudioBus; /** Starts analyzing audio from the given audio bus. Optionally override the audio bus desired to analyze. */ UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = AudioAnalyzer, meta = (WorldContext = "WorldContextObject")) AUDIOANALYZER_API void StartAnalyzing(const UObject* WorldContextObject, UAudioBus* AudioBusToAnalyze); /** Starts analyzing using the given world.*/ UE_DEPRECATED(5.4, "Use the StartAnalyzing method that uses Audio::FDeviceId.") AUDIOANALYZER_API void StartAnalyzing(UWorld* InWorld, UAudioBus* AudioBusToAnalyze); AUDIOANALYZER_API void StartAnalyzing(const Audio::FDeviceId InAudioDeviceId, UAudioBus* AudioBusToAnalyze); /** Stops analyzing audio. */ UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = AudioAnalyzer, meta = (WorldContext = "WorldContextObject")) AUDIOANALYZER_API void StopAnalyzing(const UObject* WorldContextObject = nullptr); /** * Implementations can override this method to create settings objects * specific for their analyzer. */ AUDIOANALYZER_API virtual TUniquePtr GetSettings(const int32 InSampleRate, const int32 InNumChannels) const; /** * Implementations can override this method to create controls objects * specific for their analyzer. */ AUDIOANALYZER_API virtual TSharedPtr GetAnalyzerControls() const; /** Function to broadcast results. */ virtual void BroadcastResults() {} //~ Begin UObject Interface. AUDIOANALYZER_API virtual void BeginDestroy() override; //~ End UObject interface private: /** Returns if this audio analyzer has enough audio queued up and is ready for analysis. */ AUDIOANALYZER_API bool IsReadyForAnalysis() const; /** Does the actual analysis and casts the results to the derived classes type. Returns true if there results to broadcast. */ AUDIOANALYZER_API bool DoAnalysis(); protected: template TUniquePtr GetResults() { return TUniquePtr(static_cast(ResultsInternal.Release())); } /* Subclasses must override this method in order to inform this object which AnalyzerFactory to use for analysis */ AUDIOANALYZER_API virtual FName GetAnalyzerFactoryName() const PURE_VIRTUAL(UAudioAnalyzer::GetAnalyzerFactoryName, return FName();); /** How many frames of audio to wait before analyzing the audio. */ int32 NumFramesPerBufferToAnalyze = 1024; private: // Returns UAudioAnalyzerSettings* if property points to a valid UAudioAnalyzerSettings, otherwise returns nullptr. AUDIOANALYZER_API UAudioAnalyzerSettings* GetSettingsFromProperty(FProperty* Property); // Audio analysis subsystem used with this audio analyzer UPROPERTY(Transient) TObjectPtr AudioAnalyzerSubsystem; // Output patch for retrieving audio from audio bus for analysis Audio::FPatchOutputStrongPtr PatchOutputStrongPtr; // Analysis task TSharedPtr> AnalysisTask; // The analyzer facade used for async tasks TUniquePtr AnalyzerFacade; // Cached results of previous analysis task. Can be invalid. TUniquePtr ResultsInternal; // The analyzer controls that can be modified real-time TSharedPtr AnalyzerControls; // Scratch buffer used for copying data from patch output and fed to analysis task TArray AnalysisBuffer; // The sample of the audio renderer int32 AudioMixerSampleRate = 0; // The number of channels for the audio bus int32 NumBusChannels = 0; // The analyzer factory to use Audio::IAnalyzerFactory* AnalyzerFactory = nullptr; };