UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
PassiveFilter.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5// HEADER_UNIT_SKIP - Bad includes! Audio is not available in this module
6
7#include "CoreMinimal.h"
8#include "DSP/AudioFFT.h"
9#include "DSP/FFTAlgorithm.h"
10#include "Async/ParallelFor.h"
11#include "Audio.h"
12
13namespace Audio
14{
15
17 {
18 enum class EClass
19 {
22 };
23
24 enum class EType
25 {
26 Lowpass,
28 };
29
32
35 float UnitGain;
36
39
50 };
51
52 static float EvaluateChebyshevPolynomial(float FrequencyRatio, int32 Order)
53 {
55 {
56 return 1.0f;
57 }
58
59 switch (Order)
60 {
61 case 0:
62 {
63 return 1.0f;
64 }
65 case 1:
66 {
67 return FrequencyRatio;
68 }
69 case 2:
70 {
71 return 2.0f * FrequencyRatio * FrequencyRatio - 1.0f;
72 }
73 default:
74 {
75 // Rather than recursing,
76 // we perform an iterative chebyshev polynomial evaluation,
77 // since we are likely deep in the stack already:
78 float Temp0 = 2.0f * FrequencyRatio * FrequencyRatio - 1.0f;
79 float Temp1 = FrequencyRatio;
80
81 // Start at an order of 2:
82 float Result = Temp0;
83
85 {
86 Result = (2.0f * FrequencyRatio * Temp0) - Temp1;
87 Temp1 = Temp0;
88 Temp0 = Result;
89 }
90
91 return Result;
92 }
93 break;
94 }
95 }
96
97 static float GetGainForFrequency(float NormalizedFreq, const FPassiveFilterParams& InParams)
98 {
99 const float FrequencyRatio = (InParams.Type == FPassiveFilterParams::EType::Lowpass) ? (NormalizedFreq / InParams.NormalizedCutoffFrequency) : (InParams.NormalizedCutoffFrequency / NormalizedFreq);
100
101 switch (InParams.Class)
102 {
104 {
105 const float ChebyshevPolynomial = EvaluateChebyshevPolynomial(FrequencyRatio, InParams.Order);
106 return InParams.UnitGain / (FMath::Sqrt(1.0f + ChebyshevPolynomial * ChebyshevPolynomial));
107 break;
108 }
109 default:
111 {
112 const float Denominator = FMath::Sqrt((1 + FMath::Pow(FrequencyRatio, InParams.Order * 2.0f)));
113 return InParams.UnitGain / Denominator;
114 break;
115 }
116 }
117 }
118
122 static void Filter(TArrayView<float>& Signal, const FPassiveFilterParams& InParams)
123 {
124 if (!FMath::IsPowerOfTwo(Signal.Num()))
125 {
126 UE_LOG(LogAudio, Error, TEXT("Error in Filter: if using TArrayView<float>, Signal's length should be power of 2."));
127 return;
128 }
129
130 FFFTSettings FFTSettings;
131 FFTSettings.Log2Size = CeilLog2(Signal.Num());
132 FFTSettings.bArrays128BitAligned = true;
133
135 if (!FFT.IsValid())
136 {
137 UE_LOG(LogAudio, Error, TEXT("Failed to create an FFT Algorithm with log2size %d"), FFTSettings.Log2Size);
138 return;
139 }
140
141 float MaxVal = Signal[0];
142 float MinVal = Signal[0];
143
144 if (InParams.bScaleByOffset)
145 {
146 // First, find the max and min range:
147 for (int32 Index = 0; Index < Signal.Num(); ++Index)
148 {
149 const float Value = Signal[Index];
150 if (MaxVal < Value)
151 {
152 MaxVal = Value;
153 }
154 else if (Value < MinVal)
155 {
156 MinVal = Value;
157 }
158 }
159
160 // Map to [-1.0f, 1.0f];
161 float Scale = 1.0f / ((MaxVal - MinVal) * 2.0f);
162 float Offset = MinVal - 1.0f;
163
164 for (int32 Index = 0; Index < Signal.Num(); ++Index)
165 {
166
167 Signal[Index] = (Signal[Index] - Offset) * Scale;
168 }
169 }
170
171 // Perform FFT on data:
173 TimeData.AddZeroed(FFT->NumInputFloats());
174 FMemory::Memcpy(TimeData.GetData(), Signal.GetData(), Signal.Num() * sizeof(float));
175
177 ComplexSpectrum.AddUninitialized(FFT->NumOutputFloats());
178
179 FFT->ForwardRealToComplex(TimeData.GetData(), ComplexSpectrum.GetData());
180
181 const float NumBins = FFT->NumOutputFloats() / 2;
182
183 if (InParams.bRemoveDC)
184 {
185 ComplexSpectrum[0] = 0.f;
186 ComplexSpectrum[1] = 0.f;
187 }
188
189 // Apply filter in parallel:
190 ParallelFor(NumBins, [&](int32 Index)
191 {
192 float NormalizedFreq = ((float)Index) / (NumBins - 1);
193 float Gain = GetGainForFrequency(NormalizedFreq, InParams);
194
195 ComplexSpectrum[2 * Index] *= Gain;
196 ComplexSpectrum[2 * Index + 1] *= Gain;
197 });
198
199 // Inverse FFT back into the signal:
200 FFT->InverseComplexToReal(ComplexSpectrum.GetData(), TimeData.GetData());
201
202 FMemory::Memcpy(Signal.GetData(), TimeData.GetData(), Signal.Num() * sizeof(float));
203
204 // If we're scaling, map back to it's original range:
205 if (InParams.bScaleByOffset)
206 {
207 // Map back to original values:
208 float Scale = ((MaxVal - MinVal) * 2.0f);
209 float Offset = -1.0f * (MinVal - 1.0f);
210
211 for (int32 Index = 0; Index < Signal.Num(); ++Index)
212 {
213
214 Signal[Index] = (Signal[Index] - Offset) * Scale;
215 }
216 }
217 }
218
222 static void Filter(TArray<float>& Signal, const FPassiveFilterParams& InParams)
223 {
224 if (FMath::IsPowerOfTwo(Signal.Num()))
225 {
228 }
229 else
230 {
231 const int32 OriginalLength = Signal.Num();
232 const int32 NumZerosRequired = FMath::RoundUpToPowerOfTwo(OriginalLength) - OriginalLength;
236 Signal.SetNum(OriginalLength);
237 }
238 }
239}
void ParallelFor(int32 Num, TFunctionRef< void(int32)> Body, bool bForceSingleThread, bool bPumpRenderingThread=false)
Definition ParallelFor.h:481
#define TEXT(x)
Definition Platform.h:1272
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
return true
Definition ExternalRpcRegistry.cpp:601
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
uint32 Offset
Definition VulkanMemory.cpp:4033
static SIGNALPROCESSING_API TUniquePtr< IFFTAlgorithm > NewFFTAlgorithm(const FFFTSettings &InSettings, const FName &InAlgorithmFactoryName=AnyAlgorithmFactory)
Definition FFTAlgorithm.cpp:133
Definition ArrayView.h:139
UE_FORCEINLINE_HINT constexpr ElementType * GetData() const
Definition ArrayView.h:295
UE_FORCEINLINE_HINT constexpr SizeType Num() const
Definition ArrayView.h:380
Definition Array.h:670
UE_FORCEINLINE_HINT SizeType AddUninitialized()
Definition Array.h:1664
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
SizeType AddZeroed()
Definition Array.h:2755
Definition UniquePtr.h:107
bool IsValid() const
Definition UniquePtr.h:280
NO_LOGGING.
Definition AudioMixerPlatformAndroid.cpp:53
TArray< float, FAudioBufferAlignedAllocator > FAlignedFloatBuffer
Definition AlignedBuffer.h:22
int32 CeilLog2(int32 InNum)
Definition AudioFFT.cpp:238
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
const int32 Order[8][8]
Definition VorbisAudioInfo.cpp:47
@ false
Definition radaudio_common.h:23
U16 Index
Definition radfft.cpp:71
Definition PassiveFilter.h:17
int32 Order
Definition PassiveFilter.h:33
FPassiveFilterParams()
Definition PassiveFilter.h:40
EType Type
Definition PassiveFilter.h:31
float UnitGain
Definition PassiveFilter.h:35
bool bScaleByOffset
Definition PassiveFilter.h:38
EClass Class
Definition PassiveFilter.h:30
float NormalizedCutoffFrequency
Definition PassiveFilter.h:34
EClass
Definition PassiveFilter.h:19
EType
Definition PassiveFilter.h:25
bool bRemoveDC
Definition PassiveFilter.h:37
static UE_FORCEINLINE_HINT bool IsNearlyEqual(float A, float B, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:388
static constexpr UE_FORCEINLINE_HINT bool IsPowerOfTwo(T Value)
Definition UnrealMathUtility.h:519
static UE_FORCEINLINE_HINT void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:160