UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
EnvelopeFollower.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Containers/Array.h"
6#include "DSP/AlignedBuffer.h"
8#include "DSP/Dsp.h"
9#include "HAL/Platform.h"
10
11namespace Audio
12{
13 // Different modes for the envelope follower
14 namespace EPeakMode
15 {
23 }
24
25
28 {
29 // see https://en.wikipedia.org/wiki/RC_time_constant
30 // Time constants indicate how quickly the envelope follower responds to changes in input
31 static constexpr float AnalogTimeConstant = 1.00239343f;
32 static constexpr float DigitalTimeConstant = 4.60517019f;
33
34 public:
43
47
49 inline bool GetAnalog() const { return bIsAnalog; }
50
52 inline float GetAttackTimeSamples() const { return AttackTimeSamples; }
53
55 inline float GetReleaseTimeSamples() const { return ReleaseTimeSamples; }
56
58 inline float GetAttackTimeMsec() const { return AttackTimeMsec; }
59
61 inline float GetReleaseTimeMsec() const { return ReleaseTimeMsec; }
62
64 inline float GetSampleRate() const { return SampleRate; }
65
66 protected:
67
69
70 private:
71
72 float SampleRate;
73 float AttackTimeSamples;
74 float AttackTimeMsec;
75 float ReleaseTimeSamples;
76 float ReleaseTimeMsec;
77 bool bIsAnalog;
78 };
79
80
83 {
84 public:
94
101
108 SIGNALPROCESSING_API void ProcessAudio(const float* InBuffer, int32 InNumFrames, float* OutBuffer);
109
112
115
117
118 private:
119 int32 NumChannels;
120 TArray<float> PriorEnvelopeValues;
121 };
122
125 {
126 static constexpr int32 DefaultHistoryCapacity = 16384;
127
128 public:
129
137
140
143
145
152 SIGNALPROCESSING_API void ProcessAudio(const float* InBuffer, int32 InNumFrames, float* OutBuffer);
153
154 private:
155 float SampleRate;
156 int32 NumChannels;
157 int32 WindowTimeFrames;
158 int32 WindowTimeSamples;
159 float NormFactor;
160
161 TArray<float> ChannelValues;
162 TCircularAudioBuffer<float> HistorySquared;
163 FAlignedFloatBuffer SquaredHistoryBuffer;
164 FAlignedFloatBuffer SquaredInputBuffer;
165 };
166
169 {
170 public:
178
181
184
186
193 SIGNALPROCESSING_API void ProcessAudio(const float* InBuffer, int32 InNumFrames, float* OutBuffer);
194
195 private:
196 float SampleRate;
197 int32 NumChannels;
198 float Alpha;
199 float Beta;
200
201 TArray<float> ChannelValues;
202 };
203
221
226 {
227 public:
230
233
236
239
242
245
248
250 SIGNALPROCESSING_API bool GetAnalog() const;
251
254
257
260
263
266
269
276 SIGNALPROCESSING_API void ProcessAudio(const float* InBuffer, int32 InNumFrames, float* OutBuffer);
277
284
287
290
291 private:
292 void ProcessWorkBuffer(const float* InBuffer, int32 InNumFrames);
293
294 FAlignedFloatBuffer WorkBuffer;
295 FMeanSquaredIIR MeanSquaredProcessor;
296 FAttackReleaseSmoother Smoother;
297
298 int32 NumChannels;
299 EPeakMode::Type EnvMode;
300 };
301
317
323 {
324
325 public:
326
329 : FAttackRelease(InParams.SampleRate, InParams.AttackTimeMsec, InParams.ReleaseTimeMsec, InParams.bIsAnalog)
330 , Value(0.f)
331 , Mode(InParams.Mode)
332 , AnalysisValue(0.f)
333 , AnalysisWindowMsec(5.f)
334 {
335 SetAnalysisWindow(InParams.AnalysisWindowMsec);
336 }
337
342
345 {
346 SetSampleRate(InParams.SampleRate);
347 SetAttackTime(InParams.AttackTimeMsec);
348 SetReleaseTime(InParams.ReleaseTimeMsec);
349 SetMode(InParams.Mode);
350 SetAnalog(InParams.bIsAnalog);
351 SetAnalysisWindow(InParams.AnalysisWindowMsec);
352 }
353
354 /* Sets the input analysis mode of the envelope follower */
356 {
357 Mode = InMode;
358 }
359
362 {
363 if (ensure(InAnalysisWindowMsec > 0.f))
364 {
365 AnalysisWindowMsec = InAnalysisWindowMsec;
366 InitMeanSquaredCoefficients(AnalysisWindowMsec, GetSampleRate());
367 }
368 }
369
371 inline float ProcessSample(float InSample)
372 {
373 float NormSample = NormalizeSample(InSample);
374
375 float Diff = Value - NormSample;
376 if (Diff <= 0.f)
377 {
378 Value = (GetAttackTimeSamples() * Diff) + NormSample;
379 }
380 else
381 {
382 Value = (GetReleaseTimeSamples() * Diff) + NormSample;
383 }
384
385 return Value;
386 }
387
388 inline void ProcessBuffer(const float* InSamples, const int32 InNumSamples, float* OutSamples)
389 {
391
392 NormalizeSamples(InSamples, InNumSamples, OutSamples);
393
394 for (int32 SampleIndex = 0; SampleIndex < InNumSamples; ++SampleIndex)
395 {
396 float NormSample = OutSamples[SampleIndex];
397 float Diff = Value - NormSample;
398 if (Diff <= 0.f)
399 {
400 Value = (GetAttackTimeSamples() * Diff) + NormSample;
401 }
402 else
403 {
404 Value = (GetReleaseTimeSamples() * Diff) + NormSample;
405 }
406 OutSamples[SampleIndex] = Value;
407 }
408 }
409
410 void Reset()
411 {
412 Value = 0.f;
413 }
414
416 inline float GetValue() const
417 {
418 return Value;
419 }
420
421 private:
422 inline float NormalizeSample(float InSample)
423 {
424 switch (Mode)
425 {
426 case EPeakMode::Peak:
427 return FMath::Abs(InSample);
428
430
431 {
433 AnalysisValue = AnalysisFilterBeta * SampleSquared + AnalysisFilterAlpha * AnalysisValue;
434 return AnalysisValue;
435 }
436
438
439 {
441 AnalysisValue = AnalysisFilterBeta * SampleSquared + AnalysisFilterAlpha * AnalysisValue;
442 return FMath::Sqrt(AnalysisValue);
443 }
444
445 default:
446 {
447 checkNoEntry();
448 }
449 }
450
451 return InSample;
452 }
453
454 inline void NormalizeSamples(const float* InSamples, const int32 InNumSamples, float* OutSamples)
455 {
458 switch (Mode)
459 {
460 case EPeakMode::Peak:
461 ArrayAbs(In, Out);
462 return;
463
465 {
466 ArraySquare(In, Out);
467 for (int32 SampleIndex = 0; SampleIndex < InNumSamples; ++SampleIndex)
468 {
469 AnalysisValue = AnalysisFilterBeta * OutSamples[SampleIndex] + AnalysisFilterAlpha * AnalysisValue;
470 OutSamples[SampleIndex] = AnalysisValue;
471 }
472 return;
473 }
474
476
477 {
478 ArraySquare(In, Out);
479 for (int32 SampleIndex = 0; SampleIndex < InNumSamples; ++SampleIndex)
480 {
481 AnalysisValue = AnalysisFilterBeta * OutSamples[SampleIndex] + AnalysisFilterAlpha * AnalysisValue;
482 OutSamples[SampleIndex] = AnalysisValue;
483 }
484 ArraySqrtInPlace(Out);
485 return;
486 }
487
488 default:
489 {
490 checkNoEntry();
491 }
492 }
493 }
494
495 void InitMeanSquaredCoefficients(float InWinMsec, float InSampleRate)
496 {
497 if (ensure((InSampleRate > 0.f) && (InWinMsec > 0.f)))
498 {
499 AnalysisFilterAlpha = FMath::Exp(-1000.f / (InSampleRate * InWinMsec));
500 AnalysisFilterBeta = 1.f - AnalysisFilterAlpha;
501 }
502 }
503
504 float Value = 0.f;
506 float AnalysisValue = 0.f;
507 float AnalysisWindowMsec = 10.f;
508 float AnalysisFilterAlpha = 0.f;
509 float AnalysisFilterBeta = 1.f;
510 };
511}
#define check(expr)
Definition AssertionMacros.h:314
#define checkNoEntry()
Definition AssertionMacros.h:316
#define ensure( InExpression)
Definition AssertionMacros.h:464
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
void Init()
Definition LockFreeList.h:4
Definition EnvelopeFollower.h:83
SIGNALPROCESSING_API void ProcessAudio(const float *InBuffer, int32 InNumFrames)
Definition EnvelopeFollower.cpp:95
SIGNALPROCESSING_API void SetNumChannels(int32 InNumChannels)
Definition EnvelopeFollower.cpp:144
SIGNALPROCESSING_API const TArray< float > & GetEnvelopeValues() const
Definition EnvelopeFollower.cpp:140
SIGNALPROCESSING_API void Reset()
Definition EnvelopeFollower.cpp:157
Definition EnvelopeFollower.h:28
SIGNALPROCESSING_API void SetAnalog(bool bInIsAnalog)
Definition EnvelopeFollower.cpp:53
float GetReleaseTimeMsec() const
Definition EnvelopeFollower.h:61
float GetAttackTimeSamples() const
Definition EnvelopeFollower.h:52
float GetSampleRate() const
Definition EnvelopeFollower.h:64
SIGNALPROCESSING_API void SetReleaseTime(float InReleaseTimeMsec)
Definition EnvelopeFollower.cpp:74
float GetReleaseTimeSamples() const
Definition EnvelopeFollower.h:55
float GetAttackTimeMsec() const
Definition EnvelopeFollower.h:58
SIGNALPROCESSING_API void SetAttackTime(float InAttackTimeMsec)
Definition EnvelopeFollower.cpp:60
SIGNALPROCESSING_API void SetSampleRate(float InSampleRate)
Definition EnvelopeFollower.cpp:43
bool GetAnalog() const
Definition EnvelopeFollower.h:49
Definition EnvelopeFollower.h:226
SIGNALPROCESSING_API void SetReleaseTime(float InReleaseTimeMsec)
Definition EnvelopeFollower.cpp:423
SIGNALPROCESSING_API void SetMode(EPeakMode::Type InMode)
Definition EnvelopeFollower.cpp:429
SIGNALPROCESSING_API bool GetAnalog() const
Definition EnvelopeFollower.cpp:383
SIGNALPROCESSING_API float GetSampleRate() const
Definition EnvelopeFollower.cpp:368
SIGNALPROCESSING_API void SetAttackTime(float InAttackTimeMsec)
Definition EnvelopeFollower.cpp:417
SIGNALPROCESSING_API void SetAnalog(bool bInIsAnalog)
Definition EnvelopeFollower.cpp:411
SIGNALPROCESSING_API float GetAttackTimeMsec() const
Definition EnvelopeFollower.cpp:373
SIGNALPROCESSING_API EPeakMode::Type GetMode() const
Definition EnvelopeFollower.cpp:388
SIGNALPROCESSING_API const TArray< float > & GetEnvelopeValues() const
Definition EnvelopeFollower.cpp:483
SIGNALPROCESSING_API int32 GetNumChannels() const
Definition EnvelopeFollower.cpp:363
SIGNALPROCESSING_API float GetReleaseTimeMsec() const
Definition EnvelopeFollower.cpp:378
SIGNALPROCESSING_API FEnvelopeFollower()
Definition EnvelopeFollower.cpp:341
SIGNALPROCESSING_API void SetNumChannels(int32 InNumChannels)
Definition EnvelopeFollower.cpp:393
SIGNALPROCESSING_API void ProcessAudio(const float *InBuffer, int32 InNumFrames, float *OutBuffer)
Definition EnvelopeFollower.cpp:435
SIGNALPROCESSING_API void Reset()
Definition EnvelopeFollower.cpp:404
Definition EnvelopeFollower.h:323
void Reset()
Definition EnvelopeFollower.h:410
float ProcessSample(float InSample)
Definition EnvelopeFollower.h:371
void SetMode(EPeakMode::Type InMode)
Definition EnvelopeFollower.h:355
void Init(const FInlineEnvelopeFollowerInitParams &InParams)
Definition EnvelopeFollower.h:344
FInlineEnvelopeFollower(const FInlineEnvelopeFollowerInitParams &InParams)
Definition EnvelopeFollower.h:328
void ProcessBuffer(const float *InSamples, const int32 InNumSamples, float *OutSamples)
Definition EnvelopeFollower.h:388
void SetAnalysisWindow(float InAnalysisWindowMsec)
Definition EnvelopeFollower.h:361
float GetValue() const
Definition EnvelopeFollower.h:416
FInlineEnvelopeFollower()
Definition EnvelopeFollower.h:338
Definition EnvelopeFollower.h:125
SIGNALPROCESSING_API void Reset()
Definition EnvelopeFollower.cpp:197
SIGNALPROCESSING_API void SetNumChannels(int32 InNumChannels)
Definition EnvelopeFollower.cpp:213
SIGNALPROCESSING_API void SetWindowSize(float InWindowTimeMsec)
Definition EnvelopeFollower.cpp:185
SIGNALPROCESSING_API void ProcessAudio(const float *InBuffer, int32 InNumFrames, float *OutBuffer)
Definition EnvelopeFollower.cpp:222
Definition EnvelopeFollower.h:169
SIGNALPROCESSING_API void SetWindowSize(float InWindowTimeMsec)
Definition EnvelopeFollower.cpp:279
SIGNALPROCESSING_API void ProcessAudio(const float *InBuffer, int32 InNumFrames, float *OutBuffer)
Definition EnvelopeFollower.cpp:314
SIGNALPROCESSING_API void Reset()
Definition EnvelopeFollower.cpp:304
SIGNALPROCESSING_API void SetNumChannels(int32 InNumChannels)
Definition EnvelopeFollower.cpp:291
Definition Dsp.h:834
Definition ArrayView.h:139
Definition Array.h:670
Type
Definition EnvelopeFollower.h:17
@ RootMeanSquared
Definition EnvelopeFollower.h:19
@ Count
Definition EnvelopeFollower.h:21
@ Peak
Definition EnvelopeFollower.h:20
@ MeanSquared
Definition EnvelopeFollower.h:18
NO_LOGGING.
Definition AudioMixerPlatformAndroid.cpp:53
void ArraySquare(TArrayView< const float > InValues, TArrayView< float > OutValues)
Definition FloatArrayMath.cpp:1449
void ArraySqrtInPlace(TArrayView< float > InValues)
Definition FloatArrayMath.cpp:1528
void ArrayAbs(TArrayView< const float > InBuffer, TArrayView< float > OutBuffer)
Definition FloatArrayMath.cpp:551
Definition EnvelopeFollower.h:205
bool bIsAnalog
Definition EnvelopeFollower.h:217
EPeakMode::Type Mode
Definition EnvelopeFollower.h:215
float SampleRate
Definition EnvelopeFollower.h:207
float AttackTimeMsec
Definition EnvelopeFollower.h:211
float ReleaseTimeMsec
Definition EnvelopeFollower.h:213
int32 NumChannels
Definition EnvelopeFollower.h:209
float AnalysisWindowMsec
Definition EnvelopeFollower.h:219
Definition EnvelopeFollower.h:303
EPeakMode::Type Mode
Definition EnvelopeFollower.h:311
float AnalysisWindowMsec
Definition EnvelopeFollower.h:315
float ReleaseTimeMsec
Definition EnvelopeFollower.h:309
bool bIsAnalog
Definition EnvelopeFollower.h:313
float AttackTimeMsec
Definition EnvelopeFollower.h:307
float SampleRate
Definition EnvelopeFollower.h:305