A modded EditSaber for making beat saber maps.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

307 lines
12 KiB

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Components/ActorComponent.h"
#include "AudioDecompress.h"
// Workers, to have an Async Decompress worker
#include "Runtime/Core/Public/Async/AsyncWork.h"
#include "AudioDecompressWorker.h"
#include "SoundVisComponent.generated.h"
USTRUCT(BlueprintType, Blueprintable)
struct FSoundVisData
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly, Category = "eXiSoundVis | Sounds")
class USoundWave* SoundWaveRef;
TSharedPtr<uint8> PCMData;
~FSoundVisData()
{
SoundWaveRef = nullptr;
PCMData.Reset();
}
};
// Delegate that passes FSoundVisData
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FFileLoadCompleted, USoundWave*, SoundWaveRef);
// Delegate used by the Worker
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWorkerFinished, USoundWave*, SoundWaveRef);
// Delegate that passes FrequencyValues
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FFrequencySpectrumCalculated, const TArray<float>&, OutFrequencies);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), meta=(DisplayName = "SoundVisComponent") )
class EXISOUNDVIS_API USoundVisComponent : public UActorComponent
{
GENERATED_BODY()
/// VARIABLES ///
private:
// Reference to the SoundWave we are decompressing
USoundWave* CompressedSoundWaveRef;
/// Blueprint Exposed Variables
public:
// Audio Component to Play our Audio with
UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Sound Player")
class UAudioComponent* AudioComponent;
// TimerHandle for the SoundPlayer, that only exists to check how long a Sound is running
UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Frequency Spectrum")
FTimerHandle SoundPlayerTimer;
UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Sound Player")
bool bSoundPlaying;
UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Sound Player")
bool bSoundPaused;
UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Sound Player")
bool bSoundPausedByBackgroundWindow = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "SoundVis | Sound Player")
bool bPauseWhenWindowInBackground = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "SoundVis | Sound Player")
bool bNormalizeOutputToDb = false;
/// Delegates
// Blueprint Delegate that gets Broadcasted when the File is loaded completely
UPROPERTY(BlueprintAssignable)
FFileLoadCompleted OnFileLoadCompleted;
// Blueprint Delegate that gets Broadcasted each time the Frequency Spectrum is calculated
UPROPERTY(BlueprintAssignable)
FFrequencySpectrumCalculated OnFrequencySpectrumCalculated;
/// Debug
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "SoundVis | Debugging")
bool bShowLogDebug;
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "SoundVis | Debugging")
bool bShowWarningDebug;
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "SoundVis | Debugging")
bool bShowErrorDebug;
private:
// The CurrentSoundData is only valid if the AudioPlayer is paused or running!
USoundWave* CurrentSoundData;
// The CurrentSegmentLength is only valid if the AudioPlayer is pause or running
float CurrentSegmentLength;
// Timer and Delegate for the DecompressWorker
FTimerHandle AudioDecompressTimer;
// Timer and Delegate for the auto calculation of the spectrum
FTimerHandle FrequencySpectrumTimer;
FTimerDelegate FrequencySpectrumTimerDelegate;
/// FUNCTIONS ///
public:
/// De-/Constructors
// Sets default values for this component's properties
USoundVisComponent();
// Cleans up stuff
~USoundVisComponent();
/// Overrides
// Tick called each frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
/// Functions to load Data from the HardDrive
// Function to load a sound file from the HD
bool LoadSoundFileFromHD(const FString& InFilePath);
// Function to fill in the RawFile sound data into the USoundWave object
bool FillSoundWaveInfo(class USoundWave* InSoundWave, TArray<uint8>* InRawFile);
/// Function to decompress the compressed Data that comes with the .ogg file
bool GetPCMDataFromFile(class USoundWave* InSoundWave);
/// Function to calculate the frequency spectrum
void CalculateFrequencySpectrum(USoundWave* InSoundWaveRef, const float InStartTime, const float InDuration, TArray<float>& OutFrequencies);
/// Helper Functions
// Function used to get a better value for the FFT. Uses Hann Window
float GetFFTInValue(const int16 InSampleValue, const int16 InSampleIndex, const int16 InSampleCount);
// Function to Start a new DecompressTask
void InitNewDecompressTask(USoundWave* InSoundWaveRef);
// DEBUG Test function to check if Task can call stuff in here
void Notify_SoundDecompressed();
void Notify_FailedToDecompress();
// Function that is looped to handle the calculation of the FrequencySpectrum
UFUNCTION()
void HandleFrequencySpectrumCalculation();
/// Blueprint Versions of the File Data Functions
/**
* Will load a file (currently .ogg) from your Hard-Drive and save it in a USoundWave variable
*
* @param InFilePath Absolute path to the File. E.g.: "C:/Sounds/File.ogg"
*
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Load Sound File"), Category = "SoundVis | SoundFile")
bool BP_LoadSoundFileFromHD(const FString InFilePath);
/**
* Will get an Array of Names of the Found SoundFiles
*
* @param InDirectoryPath Path to the Directory in which the Files are (absolute/relative)
* @param bInAbsolutePath Tells if the DirectoryPath is absolute (C:/..) or relative to the GameDirectory
* @param InFileExtension This is the Extension the Function should look for. For the Plugin it should be .ogg
* @param OutSoundFileNamesWithPath The Array of found SoundFileNames (full Path/Name.Extension)
* @param OutSoundFileNamesWithoutPath The Array of found SoundFileNames (only Name.Extension)
*
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Load Sound File Names"), Category = "SoundVis | SoundFile")
void BP_LoadAllSoundFileNamesFromHD(bool& bLoaded, const FString InDirectoryPath, const bool bInAbsolutePath, const FString InFileExtension, TArray<FString>& OutSoundFileNamesWithPath, TArray<FString>& OutSoundFileNamesWithoutPath);
/**
* Will call the CalculateFrequencySpectrum function from BP Side
*
* @param InSoundWave SoundWave that gets analyzed
* @param InStartTime The StartPoint of the TimeWindow we want to analyze
* @param InDuration The length of the TimeWindow we want to analyze
* @param OutFrequencies Array of float values for x Frequencies from 0 to 22000
*
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
void BP_CalculateFrequencySpectrum(USoundWave* InSoundWaveRef, const float InStartTime, const float InDuration, TArray<float>& OutFrequencies);
/**
* Will play the passed USoundWave and also start calculating the FrequencySpectrum (loops over the InSegmentLength sized parts)
*
* @param InSoundWaveRef SoundWave that gets started and analyzed
* @param InSegmentLength Length of the SoundWave segment that should get analyzed
*
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Start Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
void BP_StartCalculatingFrequencySpectrum(USoundWave* InSoundWaveRef, const float InSegmentLength);
/**
* If playing, pauses the current playing USoundWave and FrequencySpectrum calculation
*
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Pause Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
void BP_PauseCalculatingFrequencySpectrum();
/**
* If playing or paused, stops the current USoundWave and FrequencySpectrum calculation
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Stop Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
void BP_StopCalculatingFrequencySpectrum();
/**
* If paused, resumes the current USoundWave and FrequencySpectrum calculation
*
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Resume Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
void BP_ResumeCalculatingFrequencySpectrum();
/// Sound Player Information
/**
* Returns if the Player is currently playing or not
*
* @return True if playing
*/
UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Player Playing"), Category = "SoundVis | SoundPlayer")
bool IsPlayerPlaying();
/**
* Returns if the Player is currently paused or not
*
* @return True if paused
*/
UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Player Paused"), Category = "SoundVis | SoundPlayer")
bool IsPlayerPaused();
/**
* Return the current PlayBack Time of the Sound Player Timer
*
* @return Current PlayBack Time
*/
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Current Playback Time"), Category = "SoundVis | SoundPlayer")
float GetCurrentPlayBackTime();
/// Frequency Data Functions
/**
* This function will return the value of a specific frequency. It's needs a Frequency Array from the "BP_CalculateFrequencySpectrum" function and the matching SoundWave
*
* @param InSoundWave SoundWave to get specific data from (SampleRate)
* @param InFrequencies Array of float values for different frequencies from 0 to 22000. Can be get by using the "BP_CalculateFrequencySpectrum" function
* @param InWantedFrequency The Frequency of which you want the value of
* @param OutFrequencyValue Float value of the requested frequency
*
*/
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Freq Value"), Category = "SoundVis | Frequency Values")
static void BP_GetSpecificFrequencyValue(USoundWave* InSoundWave, TArray<float> InFrequencies, int32 InWantedFrequency, float& OutFrequencyValue);
/**
* This function will return the average value for SubBass (20 to 60hz)
*
* @param InSoundWave SoundWave to get specific data from (SampleRate)
* @param InFrequencies Array of float values for different frequencies from 0 to 22000. Can be get by using the "BP_CalculateFrequencySpectrum" function
* @param OutAverageSubBass Average value of the frequencies from 20 to 60
*
*/
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Average Subbass Value"), Category = "SoundVis | Frequency Values")
static void BP_GetAverageSubBassValue(USoundWave* InSoundWave, TArray<float> InFrequencies, float& OutAverageSubBass);
/**
* This function will return the average value for Bass (60 to 250hz)
*
* @param InSoundWave SoundWave to get specific data from (SampleRate)
* @param InFrequencies Array of float values for different frequencies from 0 to 22000. Can be get by using the "BP_CalculateFrequencySpectrum" function
* @param OutAverageBass Average value of the frequencies from 60 to 250
*
*/
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Average Bass Value"), Category = "SoundVis | Frequency Values")
static void BP_GetAverageBassValue(USoundWave* InSoundWave, TArray<float> InFrequencies, float& OutAverageBass);
/**
* This function will return the average value for a given frequency interval e.g.: 20 to 60 (SubBass)
*
* @param InSoundWave SoundWave to get specific data from (SampleRate)
* @param InFrequencies Array of float values for different frequencies from 0 to 22000. Can be get by using the "BP_CalculateFrequencySpectrum" function
* @param InStartFrequency Start Frequency of the Frequency interval
* @param InEndFrequency End Frequency of the Frequency interval
* @param OutAverageFrequency Average value of the requested frequency interval
*
*/
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Average Freq Value In Range"), Category = "SoundVis | Frequency Values")
static void BP_GetAverageFrequencyValueInRange(USoundWave* InSoundWave, TArray<float> InFrequencies, int32 InStartFrequence, int32 InEndFrequence, float& OutAverageFrequency);
};