UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SoundWaveScrubber.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "DSP/AlignedBuffer.h"
6#include "DSP/GrainEnvelope.h"
8#include "Sound/SoundBase.h"
10#include "Sound/SoundWave.h"
13
14#include "SoundWaveScrubber.generated.h"
15
16#define UE_API AUDIOMIXER_API
17
18namespace Audio
19{
20
21// Class manages the runtime generation of scrubbed audio from a reference sound wave
22// It does this using a simple granulation technique of overlapping grains using a Hanning window.
24{
25public:
28
29 // Initialize the sound wave scrubber
31
32 // Sets whether or not to scrub the audio file. If false, then the output of the scrubber will be silence.
34
35 // Sets if the scrubber should scrub while playhead is stationary (after it hits it's target playhead)
37
38 // Sets the scrubbing location in seconds
40
41 // Sets the grain duration range in seconds (clamped in range of of 0.01 to 0.5 seconds)
42 // The grain duration used during grain spawn is based the scrubbing speed. Sloweer the speed, the longer the grain.
44
45 // Renders the audio from the sound wave scrubber into the output audio buffer.
47
48private:
49
50 // ----------------
51 // General state and/or settings
52 float AudioMixerSampleRate = 0.0f;
53 float SourceFileSampleRate = 0.0f;
54 float SourceFileDurationSeconds = 0.0f;
55 int32 NumChannels = 0;
56
57 // How much audio to decode per decode block
58 static constexpr float DecodedAudioSizeInSeconds = 1.0f;
59
60 // The current target playhead time in seconds
61 // The scrubber will interpolate to this if the current playhead time is less than a given threshold,
62 // otherwise the scrubber will "jump" to the playhead time.
63 float TargetPlayheadTimeSeconds = 0.0f;
64
65 // How long we've been stationary
66 float TimeSincePlayheadHasNotChanged = 0.0f;
67
68 // Interpolated playhead time
69 FDynamicParameter CurrentPlayheadTimeSeconds;
70
71 // ----------------
72 // Data for managing the decoded audio
73 struct FDecodedDataChunk
74 {
75 // The start frame of the decoded audio chunk
76 int32 FrameStart = INDEX_NONE;
77
78 // The actual decoded audio.
79 // Size is NumFrames * NumChannels * AudioMixerSampleRate (after SRC)
81
82 // Count of the number of grains actively using this chunk
83 int32 NumGrainsUsingChunk = 0;
84 };
85 // Place to store decoded chunks. We need 2 chunks for actively playing grains plus a free chunk.
86 TArray<FDecodedDataChunk> DecodedChunks;
87
88 // Sound wave proxy to safely query and use the referenced sound wave asset
89 FSoundWaveProxyPtr SoundWaveProxyPtr;
90 // Sound wave proxy reader is a decoder we can use to decode audio into chunks
91 TUniquePtr<FSoundWaveProxyReader> SoundWaveProxyReaderPtr;
92 // Simple SRC interface. Decoded audio is SRC'd to match the audio mixer sample rate
94
95 // Function utility to decode audio from the current sate to the given decoded data chunk
96 void DecodeToDataChunk(FDecodedDataChunk& InOutDataChunk, float InDecoderSeekTimeSeconds);
97
98 // This retrieves decoded data for the given read frame index.
99 // Returns INDEX_NONE if no decoded data was available for the given read index
100 int32 GetDecodedDataChunkIndexForCurrentReadIndex(int32 InReadFrameIndex);
101
102 // This function will decode the audio and cache it.
103 // Returns the index for the decoded chunk
104 int32 DecodeDataChunkIndexForCurrentReadIndex(int32 InReadFrameIndex);
105
106 // ----------------
107 // Data for granulation
108 // Envelope shared across grains
109 Audio::Grain::FEnvelope GrainEnvelope;
110
111 // The grain duration in frames
112 FVector2D TargetGrainDurationRange;
113 FVector2D GrainDurationRange;
114 float GrainDurationSeconds = 0.0f;
115
116 // Grain duration as computed by scrub velocity based on the grain duration ranges
117 int32 CurrentGrainDurationFrames = 0;
118 int32 CurrentHalfGrainDurationFrames = 0;
119
120 // Utility data useful for debugging the scrubber.
121 // The grain count is a running tally of the numebr of grains rendered
122 int32 GrainCount = 0;
123 // This should never go above 2
124 int32 NumActiveGrains = 0;
125
126 // Active grain data for a single grain
127 struct FGrain
128 {
129 // The number of frames this grain has rendered
130 // If this is larger than GrainDurationFrames it's an inactive grain
131 // this is used to look up the grain envelope to find the amplitude of the grain per frame
132 int32 CurrentRenderedFramesCount = INDEX_NONE;
133
134 // Index into the decoded data array
135 int32 DecodedDataChunkIndex = 0;
136
137 // The current read frame of the grain
138 int32 CurrentReadFrame = INDEX_NONE;
139
140 // The duration of this grain. Set when the grain spawns.
141 int32 GrainDurationFrames = 0;
142 };
143 // The grain data used to render the granular audio
144 TArray<FGrain> ActiveGrains;
145
146 // This is a frame count until we need to spawn another grain
147 int32 NumFramesTillNextGrainSpawn = 0;
148
149 // Spawns a new grain at the value of the current playhead
150 FGrain SpawnGrain();
151
152 // Makes sure the grain is referencing valid decoded data
153 void UpdateGrainDecodeData(FGrain& InGrain);
154
155 // Renders the grain, mixing it into the output buffer. Returns the frame index that is half
157
158 // Used for setting user parameters
159 FCriticalSection CritSect;
160
161 // Whether or not we're actively scrubbing audio playback.
162 bool bIsScrubbing = false;
163 bool bIsScrubbingDueToBeingStationary = true;
164
165 // Whether or not we scrub while the playhead doesn't move
166 bool bIsScrubbingWhileStationary = true;
167
168 // Whether or not we have an error with the decoder
169 bool bHasErrorWithDecoder = false;
170};
171
172
174{
175public:
177
178 // ~ISoundGenerator Begin
179 UE_API virtual int32 OnGenerateAudio(float* OutAudio, int32 NumSamples) override;
181 UE_API virtual bool IsFinished() const override;
182 // ~ISoundGenerator End
183
184 // Sets whether or not to scrub the audio file. If false, then the output of the scrubber will be silence.
186
187 // Sets if the scrubber should scrub while playhead is stationary (after it hits it's target playhead)
189
190 // Sets the scrubbing location in seconds
192
193 // Sets the grain duration range in seconds (clamped in range of of 0.01 to 0.5 seconds)
194 // The grain duration used during grain spawn is based the scrubbing speed. Sloweer the speed, the longer the grain.
196
197private:
198 int32 NumChannels = 0;
199 FSoundWaveScrubber SoundWaveScrubber;
200
201};
202
203}
204
205
206UCLASS(MinimalAPI)
208{
210public:
211
212 // ~USoundBase
213 virtual ISoundGeneratorPtr CreateSoundGenerator(const FSoundGeneratorInitParams& InParams) override;
214 // ~USoundBase
215
216 ISoundGeneratorPtr GetSoundGenerator() { return SoundWaveScrubber; }
217
218 // Sets the sound wave to scrub
219 UFUNCTION(BlueprintCallable, Category = "Scrubbing")
220 AUDIOMIXER_API void SetSoundWave(USoundWave* InSoundWave);
221
222 // Sets the scrub time in seconds
223 UFUNCTION(BlueprintCallable, Category = "Scrubbing")
224 AUDIOMIXER_API void SetPlayheadTime(float InPlayheadTimeSeconds);
225
226 // Returns the current playhead time
227 UFUNCTION(BlueprintCallable, Category = "Scrubbing")
228 float GetPlayheadTime() const { return PlayheadTimeSeconds; }
229
230 // Sets the scrub grain duration range.
231 UFUNCTION(BlueprintCallable, Category = "Scrubbing")
232 AUDIOMIXER_API void SetGrainDurationRange(const FVector2D& InGrainDurationRangeSeconds);
233
234 // Sets if the scrubber is actively scrubbing or not
235 UFUNCTION(BlueprintCallable, Category = "Scrubbing")
236 AUDIOMIXER_API void SetIsScrubbing(bool bInIsScrubbing);
237
238 // Sets if the scrubber should scrub while playhead is stationary (after it hits it's target playhead)
239 UFUNCTION(BlueprintCallable, Category = "Scrubbing")
240 AUDIOMIXER_API void SetIsScrubbingWhileStationary(bool bInScrubWhileStationary);
241
242private:
243 float PlayheadTimeSeconds = 0.0f;
244 FVector2D GrainDurationRange = { 0.4f, 0.05f };
245
246 bool bIsScrubbing = false;
247 bool bScrubWhileStationary = true;
248 float StationaryTimeSeconds = 0.1f;
249
250 ISoundGeneratorPtr SoundWaveScrubber;
251
253 TObjectPtr<USoundWave> SoundWaveToScrub;
254
255};
256
257#undef UE_API
@ INDEX_NONE
Definition CoreMiscDefines.h:150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::FPlatformRecursiveMutex FCriticalSection
Definition CriticalSection.h:53
void Init()
Definition LockFreeList.h:4
#define UPROPERTY(...)
UObject definition macros.
Definition ObjectMacros.h:744
#define UFUNCTION(...)
Definition ObjectMacros.h:745
#define GENERATED_UCLASS_BODY(...)
Definition ObjectMacros.h:768
#define UCLASS(...)
Definition ObjectMacros.h:776
#define UE_API
Definition SColorGradingComponentViewer.h:12
Definition SoundWaveScrubber.h:174
UE_API void SetIsScrubbing(bool bInIsScrubbing)
Definition SoundWaveScrubber.cpp:463
virtual UE_API int32 OnGenerateAudio(float *OutAudio, int32 NumSamples) override
Definition SoundWaveScrubber.cpp:483
UE_API void SetIsScrubbingWhileStationary(bool bInScrubWhileStationary)
Definition SoundWaveScrubber.cpp:468
virtual UE_API bool IsFinished() const override
Definition SoundWaveScrubber.cpp:495
virtual UE_API int32 GetDesiredNumSamplesToRenderPerCallback() const override
Definition SoundWaveScrubber.cpp:490
UE_API void SetPlayheadTime(float InPlayheadTimeSeconds)
Definition SoundWaveScrubber.cpp:473
UE_API void SetGrainDurationRange(const FVector2D &InGrainDurationRange)
Definition SoundWaveScrubber.cpp:478
Definition SoundWaveScrubber.h:24
UE_API int32 RenderAudio(TArrayView< float > &OutAudio)
Definition SoundWaveScrubber.cpp:217
UE_API ~FSoundWaveScrubber()
Definition SoundWaveScrubber.cpp:20
UE_API void SetIsScrubbing(bool bInIsScrubbing)
Definition SoundWaveScrubber.cpp:188
UE_API FSoundWaveScrubber()
Definition SoundWaveScrubber.cpp:11
UE_API void SetPlayheadTime(float InPlayheadTimeSeconds)
Definition SoundWaveScrubber.cpp:198
UE_API void SetGrainDurationRange(const FVector2D &InGrainDurationRange)
Definition SoundWaveScrubber.cpp:205
UE_API void SetIsScrubbingWhileStationary(bool bInIsScrubWhileStationary)
Definition SoundWaveScrubber.cpp:193
Definition AudioDynamicParameter.h:10
Definition SoundGenerator.h:31
Definition ArrayView.h:139
Definition UniquePtr.h:107
Definition SoundWaveScrubber.h:208
ISoundGeneratorPtr GetSoundGenerator()
Definition SoundWaveScrubber.h:216
Definition SoundWave.h:417
NO_LOGGING.
Definition AudioMixerPlatformAndroid.cpp:53
Definition SoundGenerator.h:17
Definition ObjectPtr.h:488