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

  1. // Fill out your copyright notice in the Description page of Project Settings.
  2. #pragma once
  3. #include "Components/ActorComponent.h"
  4. #include "AudioDecompress.h"
  5. // Workers, to have an Async Decompress worker
  6. #include "Runtime/Core/Public/Async/AsyncWork.h"
  7. #include "AudioDecompressWorker.h"
  8. #include "SoundVisComponent.generated.h"
  9. USTRUCT(BlueprintType, Blueprintable)
  10. struct FSoundVisData
  11. {
  12. GENERATED_USTRUCT_BODY()
  13. UPROPERTY(BlueprintReadOnly, Category = "eXiSoundVis | Sounds")
  14. class USoundWave* SoundWaveRef;
  15. TSharedPtr<uint8> PCMData;
  16. ~FSoundVisData()
  17. {
  18. SoundWaveRef = nullptr;
  19. PCMData.Reset();
  20. }
  21. };
  22. // Delegate that passes FSoundVisData
  23. DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FFileLoadCompleted, USoundWave*, SoundWaveRef);
  24. // Delegate used by the Worker
  25. DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWorkerFinished, USoundWave*, SoundWaveRef);
  26. // Delegate that passes FrequencyValues
  27. DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FFrequencySpectrumCalculated, const TArray<float>&, OutFrequencies);
  28. UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), meta=(DisplayName = "SoundVisComponent") )
  29. class EXISOUNDVIS_API USoundVisComponent : public UActorComponent
  30. {
  31. GENERATED_BODY()
  32. /// VARIABLES ///
  33. private:
  34. // Reference to the SoundWave we are decompressing
  35. USoundWave* CompressedSoundWaveRef;
  36. /// Blueprint Exposed Variables
  37. public:
  38. // Audio Component to Play our Audio with
  39. UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Sound Player")
  40. class UAudioComponent* AudioComponent;
  41. // TimerHandle for the SoundPlayer, that only exists to check how long a Sound is running
  42. UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Frequency Spectrum")
  43. FTimerHandle SoundPlayerTimer;
  44. UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Sound Player")
  45. bool bSoundPlaying;
  46. UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Sound Player")
  47. bool bSoundPaused;
  48. UPROPERTY(BlueprintReadOnly, Category = "SoundVis | Sound Player")
  49. bool bSoundPausedByBackgroundWindow = false;
  50. UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "SoundVis | Sound Player")
  51. bool bPauseWhenWindowInBackground = true;
  52. UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "SoundVis | Sound Player")
  53. bool bNormalizeOutputToDb = false;
  54. /// Delegates
  55. // Blueprint Delegate that gets Broadcasted when the File is loaded completely
  56. UPROPERTY(BlueprintAssignable)
  57. FFileLoadCompleted OnFileLoadCompleted;
  58. // Blueprint Delegate that gets Broadcasted each time the Frequency Spectrum is calculated
  59. UPROPERTY(BlueprintAssignable)
  60. FFrequencySpectrumCalculated OnFrequencySpectrumCalculated;
  61. /// Debug
  62. UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "SoundVis | Debugging")
  63. bool bShowLogDebug;
  64. UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "SoundVis | Debugging")
  65. bool bShowWarningDebug;
  66. UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "SoundVis | Debugging")
  67. bool bShowErrorDebug;
  68. private:
  69. // The CurrentSoundData is only valid if the AudioPlayer is paused or running!
  70. USoundWave* CurrentSoundData;
  71. // The CurrentSegmentLength is only valid if the AudioPlayer is pause or running
  72. float CurrentSegmentLength;
  73. // Timer and Delegate for the DecompressWorker
  74. FTimerHandle AudioDecompressTimer;
  75. // Timer and Delegate for the auto calculation of the spectrum
  76. FTimerHandle FrequencySpectrumTimer;
  77. FTimerDelegate FrequencySpectrumTimerDelegate;
  78. /// FUNCTIONS ///
  79. public:
  80. /// De-/Constructors
  81. // Sets default values for this component's properties
  82. USoundVisComponent();
  83. // Cleans up stuff
  84. ~USoundVisComponent();
  85. /// Overrides
  86. // Tick called each frame
  87. virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
  88. /// Functions to load Data from the HardDrive
  89. // Function to load a sound file from the HD
  90. bool LoadSoundFileFromHD(const FString& InFilePath);
  91. // Function to fill in the RawFile sound data into the USoundWave object
  92. bool FillSoundWaveInfo(class USoundWave* InSoundWave, TArray<uint8>* InRawFile);
  93. /// Function to decompress the compressed Data that comes with the .ogg file
  94. bool GetPCMDataFromFile(class USoundWave* InSoundWave);
  95. /// Function to calculate the frequency spectrum
  96. void CalculateFrequencySpectrum(USoundWave* InSoundWaveRef, const float InStartTime, const float InDuration, TArray<float>& OutFrequencies);
  97. /// Helper Functions
  98. // Function used to get a better value for the FFT. Uses Hann Window
  99. float GetFFTInValue(const int16 InSampleValue, const int16 InSampleIndex, const int16 InSampleCount);
  100. // Function to Start a new DecompressTask
  101. void InitNewDecompressTask(USoundWave* InSoundWaveRef);
  102. // DEBUG Test function to check if Task can call stuff in here
  103. void Notify_SoundDecompressed();
  104. void Notify_FailedToDecompress();
  105. // Function that is looped to handle the calculation of the FrequencySpectrum
  106. UFUNCTION()
  107. void HandleFrequencySpectrumCalculation();
  108. /// Blueprint Versions of the File Data Functions
  109. /**
  110. * Will load a file (currently .ogg) from your Hard-Drive and save it in a USoundWave variable
  111. *
  112. * @param InFilePath Absolute path to the File. E.g.: "C:/Sounds/File.ogg"
  113. *
  114. */
  115. UFUNCTION(BlueprintCallable, meta = (DisplayName = "Load Sound File"), Category = "SoundVis | SoundFile")
  116. bool BP_LoadSoundFileFromHD(const FString InFilePath);
  117. /**
  118. * Will get an Array of Names of the Found SoundFiles
  119. *
  120. * @param InDirectoryPath Path to the Directory in which the Files are (absolute/relative)
  121. * @param bInAbsolutePath Tells if the DirectoryPath is absolute (C:/..) or relative to the GameDirectory
  122. * @param InFileExtension This is the Extension the Function should look for. For the Plugin it should be .ogg
  123. * @param OutSoundFileNamesWithPath The Array of found SoundFileNames (full Path/Name.Extension)
  124. * @param OutSoundFileNamesWithoutPath The Array of found SoundFileNames (only Name.Extension)
  125. *
  126. */
  127. UFUNCTION(BlueprintCallable, meta = (DisplayName = "Load Sound File Names"), Category = "SoundVis | SoundFile")
  128. void BP_LoadAllSoundFileNamesFromHD(bool& bLoaded, const FString InDirectoryPath, const bool bInAbsolutePath, const FString InFileExtension, TArray<FString>& OutSoundFileNamesWithPath, TArray<FString>& OutSoundFileNamesWithoutPath);
  129. /**
  130. * Will call the CalculateFrequencySpectrum function from BP Side
  131. *
  132. * @param InSoundWave SoundWave that gets analyzed
  133. * @param InStartTime The StartPoint of the TimeWindow we want to analyze
  134. * @param InDuration The length of the TimeWindow we want to analyze
  135. * @param OutFrequencies Array of float values for x Frequencies from 0 to 22000
  136. *
  137. */
  138. UFUNCTION(BlueprintCallable, meta = (DisplayName = "Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
  139. void BP_CalculateFrequencySpectrum(USoundWave* InSoundWaveRef, const float InStartTime, const float InDuration, TArray<float>& OutFrequencies);
  140. /**
  141. * Will play the passed USoundWave and also start calculating the FrequencySpectrum (loops over the InSegmentLength sized parts)
  142. *
  143. * @param InSoundWaveRef SoundWave that gets started and analyzed
  144. * @param InSegmentLength Length of the SoundWave segment that should get analyzed
  145. *
  146. */
  147. UFUNCTION(BlueprintCallable, meta = (DisplayName = "Start Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
  148. void BP_StartCalculatingFrequencySpectrum(USoundWave* InSoundWaveRef, const float InSegmentLength);
  149. /**
  150. * If playing, pauses the current playing USoundWave and FrequencySpectrum calculation
  151. *
  152. */
  153. UFUNCTION(BlueprintCallable, meta = (DisplayName = "Pause Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
  154. void BP_PauseCalculatingFrequencySpectrum();
  155. /**
  156. * If playing or paused, stops the current USoundWave and FrequencySpectrum calculation
  157. */
  158. UFUNCTION(BlueprintCallable, meta = (DisplayName = "Stop Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
  159. void BP_StopCalculatingFrequencySpectrum();
  160. /**
  161. * If paused, resumes the current USoundWave and FrequencySpectrum calculation
  162. *
  163. */
  164. UFUNCTION(BlueprintCallable, meta = (DisplayName = "Resume Calculate Freq Spectrum"), Category = "SoundVis | Frequency Spectrum")
  165. void BP_ResumeCalculatingFrequencySpectrum();
  166. /// Sound Player Information
  167. /**
  168. * Returns if the Player is currently playing or not
  169. *
  170. * @return True if playing
  171. */
  172. UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Player Playing"), Category = "SoundVis | SoundPlayer")
  173. bool IsPlayerPlaying();
  174. /**
  175. * Returns if the Player is currently paused or not
  176. *
  177. * @return True if paused
  178. */
  179. UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Player Paused"), Category = "SoundVis | SoundPlayer")
  180. bool IsPlayerPaused();
  181. /**
  182. * Return the current PlayBack Time of the Sound Player Timer
  183. *
  184. * @return Current PlayBack Time
  185. */
  186. UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Current Playback Time"), Category = "SoundVis | SoundPlayer")
  187. float GetCurrentPlayBackTime();
  188. /// Frequency Data Functions
  189. /**
  190. * 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
  191. *
  192. * @param InSoundWave SoundWave to get specific data from (SampleRate)
  193. * @param InFrequencies Array of float values for different frequencies from 0 to 22000. Can be get by using the "BP_CalculateFrequencySpectrum" function
  194. * @param InWantedFrequency The Frequency of which you want the value of
  195. * @param OutFrequencyValue Float value of the requested frequency
  196. *
  197. */
  198. UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Freq Value"), Category = "SoundVis | Frequency Values")
  199. static void BP_GetSpecificFrequencyValue(USoundWave* InSoundWave, TArray<float> InFrequencies, int32 InWantedFrequency, float& OutFrequencyValue);
  200. /**
  201. * This function will return the average value for SubBass (20 to 60hz)
  202. *
  203. * @param InSoundWave SoundWave to get specific data from (SampleRate)
  204. * @param InFrequencies Array of float values for different frequencies from 0 to 22000. Can be get by using the "BP_CalculateFrequencySpectrum" function
  205. * @param OutAverageSubBass Average value of the frequencies from 20 to 60
  206. *
  207. */
  208. UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Average Subbass Value"), Category = "SoundVis | Frequency Values")
  209. static void BP_GetAverageSubBassValue(USoundWave* InSoundWave, TArray<float> InFrequencies, float& OutAverageSubBass);
  210. /**
  211. * This function will return the average value for Bass (60 to 250hz)
  212. *
  213. * @param InSoundWave SoundWave to get specific data from (SampleRate)
  214. * @param InFrequencies Array of float values for different frequencies from 0 to 22000. Can be get by using the "BP_CalculateFrequencySpectrum" function
  215. * @param OutAverageBass Average value of the frequencies from 60 to 250
  216. *
  217. */
  218. UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Average Bass Value"), Category = "SoundVis | Frequency Values")
  219. static void BP_GetAverageBassValue(USoundWave* InSoundWave, TArray<float> InFrequencies, float& OutAverageBass);
  220. /**
  221. * This function will return the average value for a given frequency interval e.g.: 20 to 60 (SubBass)
  222. *
  223. * @param InSoundWave SoundWave to get specific data from (SampleRate)
  224. * @param InFrequencies Array of float values for different frequencies from 0 to 22000. Can be get by using the "BP_CalculateFrequencySpectrum" function
  225. * @param InStartFrequency Start Frequency of the Frequency interval
  226. * @param InEndFrequency End Frequency of the Frequency interval
  227. * @param OutAverageFrequency Average value of the requested frequency interval
  228. *
  229. */
  230. UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Average Freq Value In Range"), Category = "SoundVis | Frequency Values")
  231. static void BP_GetAverageFrequencyValueInRange(USoundWave* InSoundWave, TArray<float> InFrequencies, int32 InStartFrequence, int32 InEndFrequence, float& OutAverageFrequency);
  232. };