UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Dsp.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"
7#include "HAL/Platform.h"
8#include "HAL/UnrealMemory.h"
9#include "Logging/LogMacros.h"
10#include "Math/UnrealMath.h"
11#include "Misc/ScopeLock.h"
15#include "Templates/IsSigned.h"
16
17// Macros which can be enabled to cause DSP sample checking
18#if 0
19#define CHECK_SAMPLE(VALUE)
20#define CHECK_SAMPLE2(VALUE)
21#else
22#define CHECK_SAMPLE(VALUE) Audio::CheckSample(VALUE)
23#define CHECK_SAMPLE2(VALUE) Audio::CheckSample(VALUE)
24#endif
25
26namespace Audio
27{
28 // Utility to check for sample clipping. Put breakpoint in conditional to find
29 // DSP code that's not behaving correctly
30 inline void CheckSample(float InSample, float Threshold = 0.001f)
31 {
32 if (InSample > Threshold || InSample < -Threshold)
33 {
34 UE_LOG(LogSignalProcessing, Log, TEXT("SampleValue Was %.2f"), InSample);
35 }
36 }
37
38 // Clamps floats to 0 if they are in sub-normal range
39 UE_DEPRECATED(5.5, "Audio code relies on denormals flush to zero floating point mode from now on. Please use FScopedFTZFloatMode instead of this API")
40 inline float UnderflowClamp(const float InValue)
41 {
42 if (InValue > -FLT_MIN && InValue < FLT_MIN)
43 {
44 return 0.0f;
45 }
46 return InValue;
47 }
48
49 // Function converts linear scale volume to decibels
50 inline float ConvertToDecibels(const float InLinear, const float InFloor = UE_SMALL_NUMBER)
51 {
52 return 20.0f * FMath::LogX(10.0f, FMath::Max(InLinear, InFloor));
53 }
54
55 // Function converts decibel to linear scale
56 inline float ConvertToLinear(const float InDecibels)
57 {
58 return FMath::Pow(10.0f, InDecibels / 20.0f);
59 }
60
61 // Given a velocity value [0,127], return the linear gain
62 inline float GetGainFromVelocity(const float InVelocity)
63 {
64 if (InVelocity == 0.0f)
65 {
66 return 0.0f;
67 }
68 return (InVelocity * InVelocity) / (127.0f * 127.0f);
69 }
70
71 // Low precision, high performance approximation of sine using parabolic polynomial approx
72 // Valid on interval [-PI, PI]
73 inline float FastSin(const float X)
74 {
75 return (4.0f * X) / UE_PI * (1.0f - FMath::Abs(X) / UE_PI);
76 }
77
78 // Slightly higher precision, high performance approximation of sine using parabolic polynomial approx
79 inline float FastSin2(const float X)
80 {
81 float X2 = FastSin(X);
82 X2 = 0.225f * (X2* FMath::Abs(X2) - X2) + X2;
83 return X2;
84 }
85
86 // Valid on interval [-PI, PI]
87 // Sine approximation using Bhaskara I technique discovered in 7th century.
88 // https://en.wikipedia.org/wiki/Bh%C4%81skara_I
89 inline float FastSin3(const float X)
90 {
91 const float AbsX = FMath::Abs(X);
92 const float Numerator = 16.0f * X * (UE_PI - AbsX);
93 const float Denominator = 5.0f * UE_PI * UE_PI - 4.0f * AbsX * (UE_PI - AbsX);
94 return Numerator / Denominator;
95 }
96
126 {
127 public:
129 {
130 LastPhasePerSample = -1;
131 LastPhase = InStartingPhaseRadians;
132 QuadDxVec = VectorZeroFloat();
133 QuadDyVec = VectorZeroFloat();
134 }
135
145 void GenerateBuffer(float SampleRate, float ClampedFrequency, float* Buffer, int32 BufferSampleCount)
146 {
147 // Regenerate our vector rotation components if our changes.
148 const float PhasePerSample = (ClampedFrequency * (2 * UE_PI)) / (SampleRate);
149 if (LastPhasePerSample != PhasePerSample)
150 {
151 float QuadDx = FMath::Cos(PhasePerSample * 4);
152 float QuadDy = FMath::Sin(PhasePerSample * 4);
153
154 QuadDxVec = VectorLoadFloat1(&QuadDx);
155 QuadDyVec = VectorLoadFloat1(&QuadDy);
156
157 LastPhasePerSample = PhasePerSample;
158 }
159
160 float* Write = Buffer;
161
162 // The rotation matrix drifts, so we resync every so often
163 while (BufferSampleCount)
164 {
165 // The concept here is that cos/sin are points on a unit circle,
166 // so an oscilator is just a rotation of that point.
167 //
168 // To avoid drift, we resync off of an accurate sin/cos every evaluation
169 // then do a 2d rotation in the actual loop.
170 //
171 // we store 4 points at once to use SIMD, so each rotation is actually
172 // 4x the phase delta.
173 //
174 alignas(16) float PhaseSource[4];
175 PhaseSource[0] = LastPhase + 0 * PhasePerSample;
176 PhaseSource[1] = LastPhase + 1 * PhasePerSample;
177 PhaseSource[2] = LastPhase + 2 * PhasePerSample;
178 PhaseSource[3] = LastPhase + 3 * PhasePerSample;
179
181 VectorRegister4Float XVector, YVector;
182
183 // We need an accurate representation of the delta
184 // vectors since we are integrating it
185 VectorSinCos(&YVector, &XVector, &PhaseVec);
186
187 // Copy to local (the compiler actually didn't do this!)
190
192 if (BlockSampleCount > 480)
193 BlockSampleCount = 480;
194
195 // Unrolling this didn't seem to really help perf wise.
197 while (Block4)
198 {
199 VectorStore(YVector, Write);
200
201 // 2D rotation matrix.
204
205 XVector = NewX;
206 YVector = NewY;
207
208 Write += 4;
209 Block4--;
210 }
211
212 constexpr int32 SIMD_MASK = 0x00000003;
214 {
215 // We've actually already calculated the next quad - it's in YVector
216 alignas(16) float YFloats[4];
217 VectorStore(YVector, YFloats);
218
220 for (int32 i = 0; i < Remn; i++)
221 {
222 Write[i] = YFloats[i];
223 }
224 }
225
226 // Advance phase, range reduce, and store.
228 PhaseInRadians -= FMath::FloorToFloat(PhaseInRadians / (2 * UE_PI)) * (2 * UE_PI);
229 LastPhase = PhaseInRadians;
230
232 } // end while BufferSampleCount
233 } // end GenerateBuffer
234
235 private:
236 VectorRegister4Float QuadDxVec, QuadDyVec;
237 float LastPhasePerSample;
238 float LastPhase;
239 }; // end FSinOsc2DRotation
240
241 // Fast tanh based on pade approximation
242 inline float FastTanh(float X)
243 {
244 if (X < -3) return -1.0f;
245 if (X > 3) return 1.0f;
246 const float InputSquared = X*X;
247 return X*(27.0f + InputSquared) / (27.0f + 9.0f * InputSquared);
248 }
249
250 // Based on sin parabolic approximation
251 inline float FastTan(float X)
252 {
253 const float Num = X * (1.0f - FMath::Abs(X) / UE_PI);
254 const float Den = (X + 0.5f * UE_PI) * (1.0f - FMath::Abs(X + 0.5f * UE_PI) / UE_PI);
255 return Num / Den;
256 }
257
258 // Gets polar value from unipolar
259 inline float GetBipolar(const float X)
260 {
261 return 2.0f * X - 1.0f;
262 }
263
264 // Converts bipolar value to unipolar
265 inline float GetUnipolar(const float X)
266 {
267 return 0.5f * X + 0.5f;
268 }
269
270 // Converts in place a buffer into Unipolar (0..1)
271 // This is a Vector op version of the GetUnipolar function. (0.5f * X + 0.5f).
273 {
274 // Make sure buffers are aligned and we can do a whole number of loops.
275 check(NumSamples % 4 == 0);
276
278
279 // Process buffer 1 vector (4 floats) at a time.
280 for(int32 i = NumSamples / 4; i; --i, InAlignedBuffer += 4)
281 {
283 V = VectorMultiply(V, Half);
284 V = VectorAdd(V, Half);
286 }
287 }
288
289 // Using midi tuning standard, compute frequency in hz from midi value
290 inline float GetFrequencyFromMidi(const float InMidiNote)
291 {
292 return 440.0f * FMath::Pow(2.0f, (InMidiNote - 69.0f) / 12.0f);
293 }
294
295 // Returns the log frequency of the input value. Maps linear domain and range values to log output (good for linear slider controlling frequency)
296 inline float GetLogFrequencyClamped(const float InValue, const FVector2D& Domain, const FVector2D& Range)
297 {
298 // Check if equal as well as less than to avoid round error in case where at edges.
299 if (InValue <= Domain.X)
300 {
301 return UE_REAL_TO_FLOAT(Range.X);
302 }
303
304 if (InValue >= Domain.Y)
305 {
306 return UE_REAL_TO_FLOAT(Range.Y);
307 }
308
309 //Handle edge case of NaN
310 if (FMath::IsNaN(InValue))
311 {
312 return UE_REAL_TO_FLOAT(Range.X);
313 }
314
315 const FVector2D RangeLog(FMath::Max(FMath::Loge(Range.X), UE_SMALL_NUMBER), FMath::Min(FMath::Loge(Range.Y), UE_BIG_NUMBER));
317 return FMath::Exp(FreqLinear);
318 }
319
320 // Returns the linear frequency of the input value. Maps log domain and range values to linear output (good for linear slider representation/visualization of log frequency). Reverse of GetLogFrequencyClamped.
321 inline float GetLinearFrequencyClamped(const float InFrequencyValue, const FVector2D& Domain, const FVector2D& Range)
322 {
323 // Check if equal as well as less than to avoid round error in case where at edges.
324 if (InFrequencyValue <= Range.X)
325 {
326 return UE_REAL_TO_FLOAT(Domain.X);
327 }
328
329 if (InFrequencyValue >= Range.Y)
330 {
331 return UE_REAL_TO_FLOAT(Domain.Y);
332 }
333
334 //Handle edge case of NaN
335 if (FMath::IsNaN(InFrequencyValue))
336 {
337 return UE_REAL_TO_FLOAT(Domain.X);
338 }
339
340 const FVector2D RangeLog(FMath::Max(FMath::Loge(Range.X), UE_SMALL_NUMBER), FMath::Min(FMath::Loge(Range.Y), UE_BIG_NUMBER));
343 }
344
345 // Using midi tuning standard, compute midi from frequency in hz
346 inline float GetMidiFromFrequency(const float InFrequency)
347 {
348 return 69.0f + 12.0f * FMath::LogX(2.0f, InFrequency / 440.0f);
349 }
350
351 // Return a pitch scale factor based on the difference between a base midi note and a target midi note. Useful for samplers.
353 {
354 const float BaseFrequency = GetFrequencyFromMidi(FMath::Clamp((float)BaseMidiNote, 0.0f, 127.0f));
355 const float TargetFrequency = 440.0f * FMath::Pow(2.0f, ((float)TargetMidiNote - 69.0f) / 12.0f);
356 const float PitchScale = TargetFrequency / BaseFrequency;
357 return PitchScale;
358 }
359
360 // Returns the frequency multiplier to scale a base frequency given the input semitones
361 inline float GetFrequencyMultiplier(const float InPitchSemitones)
362 {
363 if (InPitchSemitones == 0.0f)
364 {
365 return 1.0f;
366
367 }
368 return FMath::Pow(2.0f, InPitchSemitones / 12.0f);
369 }
370
371 // Returns the number of semitones relative to a base frequency given the input frequency multiplier
372 inline float GetSemitones(const float InMultiplier)
373 {
374 if (InMultiplier <= 0.0f)
375 {
376 return 12.0f * FMath::Log2(UE_SMALL_NUMBER);
377 }
378 return 12.0f * FMath::Log2(InMultiplier);
379 }
380
381 // Calculates equal power stereo pan using sinusoidal-panning law and cheap approximation for sin
382 // InLinear pan is [-1.0, 1.0] so it can be modulated by a bipolar LFO
383 inline void GetStereoPan(const float InLinearPan, float& OutLeft, float& OutRight)
384 {
385 const float LeftPhase = 0.5f * UE_PI * (0.5f * (InLinearPan + 1.0f) + 1.0f);
386 const float RightPhase = 0.25f * UE_PI * (InLinearPan + 1.0f);
387 OutLeft = FMath::Clamp(FastSin(LeftPhase), 0.0f, 1.0f);
388 OutRight = FMath::Clamp(FastSin(RightPhase), 0.0f, 1.0f);
389 }
390
391 // Encodes a stereo Left/Right signal into a stereo Mid/Side signal
392 inline void EncodeMidSide(float& LeftChannel, float& RightChannel)
393 {
394 const float Temp = (LeftChannel - RightChannel);
395 //Output
397 RightChannel = Temp;
398 }
399
400 // Encodes a stereo Left/Right signal into a stereo Mid/Side signal
406
407
408 // Decodes a stereo Mid/Side signal into a stereo Left/Right signal
409 inline void DecodeMidSide(float& MidChannel, float& SideChannel)
410 {
411 const float Temp = (MidChannel - SideChannel) * 0.5f;
412 //Output
413 MidChannel = (MidChannel + SideChannel) * 0.5f;
414 SideChannel = Temp;
415 }
416
417 // Decodes a stereo Mid/Side signal into a stereo Left/Right signal
423
424 // Helper function to get bandwidth from Q
425 inline float GetBandwidthFromQ(const float InQ)
426 {
427 // make sure Q is not 0.0f, clamp to slightly positive
428 const float Q = FMath::Max(UE_KINDA_SMALL_NUMBER, InQ);
429 const float Arg = 0.5f * ((1.0f / Q) + FMath::Sqrt(1.0f / (Q*Q) + 4.0f));
430 const float OutBandwidth = 2.0f * FMath::LogX(2.0f, Arg);
431 return OutBandwidth;
432 }
433
434 // Helper function get Q from bandwidth
435 inline float GetQFromBandwidth(const float InBandwidth)
436 {
437 const float InBandwidthClamped = FMath::Max(UE_KINDA_SMALL_NUMBER, InBandwidth);
438 const float Temp = FMath::Pow(2.0f, InBandwidthClamped);
439 const float OutQ = FMath::Sqrt(Temp) / (Temp - 1.0f);
440 return OutQ;
441 }
442
443 // Given three values, determine peak location and value of quadratic fitted to the data.
444 //
445 // @param InValues - An array of 3 values with the maximum value located in InValues[1].
446 // @param OutPeakLoc - The peak location relative to InValues[1].
447 // @param OutPeakValue - The value of the peak at the peak location.
448 //
449 // @returns True if a peak was found, false if the values do not represent a peak.
450 inline bool QuadraticPeakInterpolation(const float InValues[3], float& OutPeakLoc, float& OutPeakValue)
451 {
452 float Denom = InValues[0] - 2.f * InValues[1] + InValues[2];
453
454 if (Denom >= 0.f)
455 {
456 // This is not a peak.
457 return false;
458 }
459
460 float Tmp = InValues[0] - InValues[2];
461
462 OutPeakLoc = 0.5f * Tmp / Denom;
463
464 if ((OutPeakLoc > 0.5f) || (OutPeakLoc < -0.5f))
465 {
466 // This is not a peak.
467 return false;
468 }
469
470 OutPeakValue = InValues[1] - 0.25f * Tmp * OutPeakLoc;
471
472 return true;
473 }
474
475 // Polynomial interpolation using lagrange polynomials.
476 // https://en.wikipedia.org/wiki/Lagrange_polynomial
477 inline float LagrangianInterpolation(const TArray<FVector2D> Points, const float Alpha)
478 {
479 float Lagrangian = 1.0f;
480 float Output = 0.0f;
481
482 const int32 NumPoints = Points.Num();
483 for (int32 i = 0; i < NumPoints; ++i)
484 {
485 Lagrangian = 1.0f;
486 for (int32 j = 0; j < NumPoints; ++j)
487 {
488 if (i != j)
489 {
490 float Denom = UE_REAL_TO_FLOAT(Points[i].X - Points[j].X);
491 if (FMath::Abs(Denom) < UE_SMALL_NUMBER)
492 {
494 }
495 Lagrangian *= (Alpha - UE_REAL_TO_FLOAT(Points[j].X)) / Denom;
496 }
497 }
498 Output += Lagrangian * UE_REAL_TO_FLOAT(Points[i].Y);
499 }
500 return Output;
501 }
502
503 // Simple exponential easing class. Useful for cheaply and smoothly interpolating parameters.
505 {
506 public:
508 : CurrentValue(InInitValue)
509 , Threshold(InThreshold)
510 , TargetValue(InInitValue)
511 , EaseFactor(InEaseFactor)
512 , OneMinusEase(1.0f - InEaseFactor)
513 , EaseTimesTarget(EaseFactor * InInitValue)
514 {
515 }
516
517 void Init(float InInitValue, float InEaseFactor = 0.001f)
518 {
519 CurrentValue = InInitValue;
520 TargetValue = InInitValue;
521 EaseFactor = InEaseFactor;
522
523 OneMinusEase = 1.0f - EaseFactor;
524 EaseTimesTarget = TargetValue * EaseFactor;
525 }
526
527 bool IsDone() const
528 {
529 return FMath::Abs(TargetValue - CurrentValue) < Threshold;
530 }
531
533 {
534 if (IsDone())
535 {
536 return CurrentValue;
537 }
538
539 // Micro-optimization,
540 // But since GetNextValue(NumTicksToJumpAhead) does this work in a tight loop (non-vectorizable), might as well
541 /*
542 return CurrentValue = CurrentValue + (TargetValue - CurrentValue) * EaseFactor;
543 = CurrentValue + EaseFactor*TargetValue - EaseFactor*CurrentValue
544 = (CurrentValue - EaseFactor*CurrentValue) + EaseFactor*TargetValue
545 = (1 - EaseFactor)*CurrentValue + EaseFactor*TargetValue
546 */
547 return CurrentValue = OneMinusEase * CurrentValue + EaseTimesTarget;
548 }
549
550 // same as GetValue(), but overloaded to jump forward by NumTicksToJumpAhead timesteps
551 // (before getting the value)
553 {
554 while (NumTicksToJumpAhead && !IsDone())
555 {
556 CurrentValue = OneMinusEase * CurrentValue + EaseTimesTarget;
558 }
559
560 return CurrentValue;
561 }
562
563 float PeekCurrentValue() const
564 {
565 return CurrentValue;
566 }
567
568 void SetEaseFactor(const float InEaseFactor)
569 {
570 EaseFactor = InEaseFactor;
571 OneMinusEase = 1.0f - EaseFactor;
572 }
573
574 void operator=(const float& InValue)
575 {
577 }
578
579 void SetValue(const float InValue, const bool bIsInit = false)
580 {
581 TargetValue = InValue;
582 EaseTimesTarget = EaseFactor * TargetValue;
583 if (bIsInit)
584 {
585 CurrentValue = TargetValue;
586 }
587 }
588
589 // This is a method for getting the factor to use for a given tau and sample rate.
590 // Tau here is defined as the time it takes the interpolator to be within 1/e of it's destination.
591 static float GetFactorForTau(float InTau, float InSampleRate)
592 {
593 return 1.0f - FMath::Exp(-1.0f / (InTau * InSampleRate));
594 }
595
596 private:
597
598 // Current value of the exponential ease
599 float CurrentValue;
600
601 // Threshold to use to evaluate if the ease is done
602 float Threshold;
603
604 // Target value
605 float TargetValue;
606
607 // Percentage to move toward target value from current value each tick
608 float EaseFactor;
609
610 // 1.0f - EaseFactor
611 float OneMinusEase;
612
613 // EaseFactor * TargetValue
614 float EaseTimesTarget;
615 };
616
617 // Simple easing function used to help interpolate params
619 {
620 public:
622 : StartValue(0.0f)
623 , CurrentValue(0.0f)
624 , DeltaValue(0.0f)
625 , SampleRate(44100.0f)
626 , DurationTicks(0)
627 , DefaultDurationTicks(0)
628 , CurrentTick(0)
629 , bIsInit(true)
630 {
631 }
632
634 {
635 }
636
637 bool IsDone() const
638 {
639 return CurrentTick >= DurationTicks;
640 }
641
642 void Init(float InSampleRate)
643 {
644 SampleRate = InSampleRate;
645 bIsInit = true;
646 }
647
648 void SetValueRange(const float Start, const float End, const float InTimeSec)
649 {
650 StartValue = Start;
651 CurrentValue = Start;
653 }
654
656 {
657 if (IsDone())
658 {
659 return CurrentValue;
660 }
661
662 CurrentValue = DeltaValue * (float)CurrentTick / (float)DurationTicks + StartValue;
663
664 ++CurrentTick;
665 return CurrentValue;
666 }
667
668 // same as GetValue(), but overloaded to increment Current Tick by NumTicksToJumpAhead
669 // (before getting the value)
671 {
672 if (IsDone())
673 {
674 return CurrentValue;
675 }
676
677 CurrentTick = FMath::Min(CurrentTick + NumTicksToJumpAhead, DurationTicks);
678 CurrentValue = DeltaValue * (float)CurrentTick / (float)DurationTicks + StartValue;
679
680 return CurrentValue;
681 }
682
683 float PeekCurrentValue() const
684 {
685 return CurrentValue;
686 }
687
688 // Updates the target value without changing the duration or tick data.
689 // Sets the state as if the new value was the target value all along
690 void SetValueInterrupt(const float InValue)
691 {
692 if (IsDone())
693 {
694 CurrentValue = InValue;
695 }
696 else
697 {
698 DurationTicks = DurationTicks - CurrentTick;
699 CurrentTick = 0;
700 DeltaValue = InValue - CurrentValue;
701 StartValue = CurrentValue;
702 }
703 }
704
705 void SetValue(const float InValue, float InTimeSec = 0.0f)
706 {
707 if (bIsInit)
708 {
709 bIsInit = false;
710 DurationTicks = 0;
711 }
712 else
713 {
714 DurationTicks = (int32)(SampleRate * InTimeSec);
715 }
716 CurrentTick = 0;
717
718 if (DurationTicks == 0)
719 {
720 CurrentValue = InValue;
721 }
722 else
723 {
724 DeltaValue = InValue - CurrentValue;
725 StartValue = CurrentValue;
726 }
727 }
728
729 private:
730 float StartValue;
731 float CurrentValue;
732 float DeltaValue;
733 float SampleRate;
734 int32 DurationTicks;
735 int32 DefaultDurationTicks;
736 int32 CurrentTick;
737 bool bIsInit;
738 };
739
740 // Simple parameter object which uses critical section to write to and read from data
741 template<typename T>
743 {
744 public:
746 : bChanged(false)
747 {}
748
749 // Sets the params
750 void SetParams(const T& InParams)
751 {
753 bChanged = true;
755 }
756
757 // Returns a copy of the params safely if they've changed since last time this was called
759 {
761 if (bChanged)
762 {
763 bChanged = false;
765 return true;
766 }
767 return false;
768 }
769
775
779 };
780
781 template <typename SampleType>
826
832 template <typename SampleType, size_t Alignment = 16>
834 {
835 private:
836
838 uint32 Capacity;
839 FThreadSafeCounter ReadCounter;
840 FThreadSafeCounter WriteCounter;
841
842 public:
844 {
845 SetCapacity(0);
846 }
847
852
854 {
855 InternalBuffer = InOther.InternalBuffer;
856 Capacity = InOther.Capacity;
857 ReadCounter.Set(InOther.ReadCounter.GetValue());
858 WriteCounter.Set(InOther.WriteCounter.GetValue());
859
860 return *this;
861 }
862
863
868
870 {
872 }
873
874 void Empty()
875 {
876 ReadCounter.Set(0);
877 WriteCounter.Set(0);
878 InternalBuffer.Empty();
879 }
880
882 {
883 checkf(InCapacity < (uint32)TNumericLimits<int32>::Max(), TEXT("Max capacity for this buffer is 2,147,483,647 samples. Otherwise our index arithmetic will not work."));
884 Capacity = InCapacity + 1;
885 ReadCounter.Set(0);
886 WriteCounter.Set(0);
887 InternalBuffer.Reset();
888 InternalBuffer.AddZeroed(Capacity);
889 }
890
897 {
898 if (Capacity <= InMinimumCapacity)
899 {
901
902 checkf(NewCapacity < (uint32)TNumericLimits<int32>::Max(), TEXT("Max capacity overflow. Requested %d. Maximum allowed %d"), NewCapacity, TNumericLimits<int32>::Max());
903
904 uint32 NumToAdd = NewCapacity - Capacity;
905 InternalBuffer.AddZeroed(NumToAdd);
906 Capacity = NewCapacity;
907 }
908
910 {
911 ReadCounter.Set(0);
912 WriteCounter.Set(0);
913 }
914 }
915
918 {
919 return Push(InBuffer.GetData(), InBuffer.Num());
920 }
921
922 // Pushes some amount of samples into this circular buffer.
923 // Returns the amount of samples written.
924 // This can only be used for trivially copyable types.
925 int32 Push(const SampleType* InBuffer, uint32 NumSamples)
926 {
927 SampleType* DestBuffer = InternalBuffer.GetData();
928 const uint32 ReadIndex = ReadCounter.GetValue();
929 const uint32 WriteIndex = WriteCounter.GetValue();
930
931 int32 NumToCopy = FMath::Min<int32>(NumSamples, Remainder());
932 const int32 NumToWrite = FMath::Min<int32>(NumToCopy, Capacity - WriteIndex);
933
934 FMemory::Memcpy(&DestBuffer[WriteIndex], InBuffer, NumToWrite * sizeof(SampleType));
935 FMemory::Memcpy(&DestBuffer[0], &InBuffer[NumToWrite], (NumToCopy - NumToWrite) * sizeof(SampleType));
936
937 WriteCounter.Set((WriteIndex + NumToCopy) % Capacity);
938
939 return NumToCopy;
940 }
941
942 // Pushes some amount of zeros into the circular buffer.
943 // Useful when acting as a blocked, mono/interleaved delay line
945 {
946 SampleType* DestBuffer = InternalBuffer.GetData();
947 const uint32 ReadIndex = ReadCounter.GetValue();
948 const uint32 WriteIndex = WriteCounter.GetValue();
949
950 int32 NumToZeroEnd = FMath::Min<int32>(NumSamplesOfZeros, Remainder());
951 const int32 NumToZeroBegin = FMath::Min<int32>(NumToZeroEnd, Capacity - WriteIndex);
952
953 FMemory::Memzero(&DestBuffer[WriteIndex], NumToZeroBegin * sizeof(SampleType));
954 FMemory::Memzero(&DestBuffer[0], (NumToZeroEnd - NumToZeroBegin) * sizeof(SampleType));
955
956 WriteCounter.Set((WriteIndex + NumToZeroEnd) % Capacity);
957
958 return NumToZeroEnd;
959 }
960
961 // Push a single sample onto this buffer.
962 // Returns false if the buffer is full.
963 bool Push(const SampleType& InElement)
964 {
965 if (Remainder() == 0)
966 {
967 return false;
968 }
969 else
970 {
971 SampleType* DestBuffer = InternalBuffer.GetData();
972 const uint32 ReadIndex = ReadCounter.GetValue();
973 const uint32 WriteIndex = WriteCounter.GetValue();
974
975 DestBuffer[WriteIndex] = InElement;
976
977 WriteCounter.Set((WriteIndex + 1) % Capacity);
978 return true;
979 }
980 }
981
982 bool Push(SampleType && InElement)
983 {
984 if (Remainder() == 0)
985 {
986 return false;
987 }
988 else
989 {
990 SampleType* DestBuffer = InternalBuffer.GetData();
991 const uint32 ReadIndex = ReadCounter.GetValue();
992 const uint32 WriteIndex = WriteCounter.GetValue();
993
994 DestBuffer[WriteIndex] = MoveTemp(InElement);
995
996 WriteCounter.Set((WriteIndex + 1) % Capacity);
997 return true;
998 }
999 }
1000
1001 // Same as Pop(), but does not increment the read counter.
1002 int32 Peek(SampleType* OutBuffer, uint32 NumSamples) const
1003 {
1004 const SampleType* SrcBuffer = InternalBuffer.GetData();
1005 const uint32 ReadIndex = ReadCounter.GetValue();
1006 const uint32 WriteIndex = WriteCounter.GetValue();
1007
1008 int32 NumToCopy = FMath::Min<int32>(NumSamples, Num());
1009
1010 const int32 NumRead = FMath::Min<int32>(NumToCopy, Capacity - ReadIndex);
1011 FMemory::Memcpy(OutBuffer, &SrcBuffer[ReadIndex], NumRead * sizeof(SampleType));
1012
1013 FMemory::Memcpy(&OutBuffer[NumRead], &SrcBuffer[0], (NumToCopy - NumRead) * sizeof(SampleType));
1014
1015 check(NumSamples < ((uint32)TNumericLimits<int32>::Max()));
1016
1017 return NumToCopy;
1018 }
1019
1020 // same Peek(), but provides a (possibly) disjointed view of the memory in-place
1021 // Push calls while the returned view is being accessed is undefined behavior
1023 {
1024 const SampleType* SrcBuffer = InternalBuffer.GetData();
1025 const uint32 ReadIndex = ReadCounter.GetValue();
1026 const uint32 WriteIndex = WriteCounter.GetValue();
1027
1028 int32 NumToView = FMath::Min<int32>(NumSamples, Num());
1029 const int32 NumRead = FMath::Min<int32>(NumToView, Capacity - ReadIndex);
1030 check(NumSamples < ((uint32)TNumericLimits<int32>::Max()));
1031
1033 TArrayView<const SampleType>(SrcBuffer + ReadIndex, NumRead)
1035 );
1036 }
1037
1038 // Peeks a single element.
1039 // returns false if the element is empty.
1040 bool Peek(SampleType& OutElement) const
1041 {
1042 if (Num() == 0)
1043 {
1044 return false;
1045 }
1046 else
1047 {
1048 SampleType* SrcBuffer = InternalBuffer.GetData();
1049 const uint32 ReadIndex = ReadCounter.GetValue();
1050
1051 OutElement = SrcBuffer[ReadIndex];
1052
1053 return true;
1054 }
1055 }
1056
1057 // Pops some amount of samples into this circular buffer.
1058 // Returns the amount of samples read.
1059 int32 Pop(SampleType* OutBuffer, uint32 NumSamples)
1060 {
1061 int32 NumSamplesRead = Peek(OutBuffer, NumSamples);
1062 check(NumSamples < ((uint32)TNumericLimits<int32>::Max()));
1063
1064 ReadCounter.Set((ReadCounter.GetValue() + NumSamplesRead) % Capacity);
1065
1066 return NumSamplesRead;
1067 }
1068
1069 // Same as Pop(), but provides a (possibly) disjinted view of memory in-place
1070 // Push calls while the returned view is being accessed is undefined behavior
1072 {
1073 check(NumSamples < ((uint32)TNumericLimits<int32>::Max()));
1074
1076 const int32 NumSamplesRead = View.Num();
1077 ReadCounter.Set((ReadCounter.GetValue() + NumSamplesRead) % Capacity);
1078
1079 return View;
1080 }
1081
1082 // Pops some amount of samples into this circular buffer.
1083 // Returns the amount of samples read.
1084 int32 Pop(uint32 NumSamples)
1085 {
1086 check(NumSamples < ((uint32)TNumericLimits<int32>::Max()));
1087
1088 int32 NumSamplesRead = FMath::Min<int32>(NumSamples, Num());
1089
1090 ReadCounter.Set((ReadCounter.GetValue() + NumSamplesRead) % Capacity);
1091
1092 return NumSamplesRead;
1093 }
1094
1095 // Pops a single element.
1096 // Will assert if the buffer is empty. Please check Num() > 0 before calling.
1097 SampleType Pop()
1098 {
1099 // Calling this when the buffer is empty is considered a fatal error.
1100 check(Num() > 0);
1101
1102 SampleType* SrcBuffer = InternalBuffer.GetData();
1103 const uint32 ReadIndex = ReadCounter.GetValue();
1104
1105 SampleType PoppedValue = MoveTempIfPossible(InternalBuffer[ReadIndex]);
1106 ReadCounter.Set((ReadCounter.GetValue() + 1) % Capacity);
1107 return PoppedValue;
1108 }
1109
1110 // When called, seeks the read or write cursor to only retain either the NumSamples latest data
1111 // (if bRetainOldestSamples is false) or the NumSamples oldest data (if bRetainOldestSamples is true)
1112 // in the buffer. Cannot be used to increase the capacity of this buffer.
1113 void SetNum(uint32 NumSamples, bool bRetainOldestSamples = false)
1114 {
1115 check(NumSamples < Capacity);
1116
1118 {
1119 WriteCounter.Set((ReadCounter.GetValue() + NumSamples) % Capacity);
1120 }
1121 else
1122 {
1123 int64 ReadCounterNum = ((int32)WriteCounter.GetValue()) - ((int32) NumSamples);
1124 if (ReadCounterNum < 0)
1125 {
1126 ReadCounterNum = Capacity + ReadCounterNum;
1127 }
1128
1129 ReadCounter.Set(ReadCounterNum);
1130 }
1131 }
1132
1133 // Get number of samples that can be popped off of the buffer.
1134 uint32 Num() const
1135 {
1136 const int32 ReadIndex = ReadCounter.GetValue();
1137 const int32 WriteIndex = WriteCounter.GetValue();
1138
1139 if (WriteIndex >= ReadIndex)
1140 {
1141 return WriteIndex - ReadIndex;
1142 }
1143 else
1144 {
1145 return Capacity - ReadIndex + WriteIndex;
1146 }
1147 }
1148
1149 // Get the current capacity of the buffer
1151 {
1152 return Capacity;
1153 }
1154
1155 // Get number of samples that can be pushed onto the buffer before it is full.
1157 {
1158 return Capacity - Num() - 1;
1159 }
1160 };
1161
1165 template <int Base, int Exp>
1167 {
1168 static_assert(Exp >= 0, "TGetPower only supports positive exponents.");
1169 static const int64 Value = Base * TGetPower<Base, Exp - 1>::Value;
1170 };
1171
1172 template <int Base>
1173 struct TGetPower<Base, 0>
1174 {
1175 static const int64 Value = 1;
1176 };
1177
1182 template <typename SampleType, uint32 Q = (sizeof(SampleType) * 8 - 1)>
1184 {
1185 SampleType Sample;
1186
1187 template <typename SampleTypeToCheck>
1188 static void CheckValidityOfSampleType()
1189 {
1191 static_assert(bIsTypeValid, "Invalid sample type! TSampleRef only supports float or integer values.");
1192 }
1193
1194 template <typename SampleTypeToCheck, uint32 QToCheck>
1195 static void CheckValidityOfQ()
1196 {
1197 // If this is a fixed-precision value, our Q offset must be less than how many bits we have.
1199 static_assert(bIsTypeValid, "Invalid value for Q! TSampleRef only supports float or int types. For int types, Q must be smaller than the number of bits in the int type.");
1200 }
1201
1202 // This is the number used to convert from float to our fixed precision value.
1203 static constexpr float QFactor = TGetPower<2, Q>::Value - 1;
1204
1205 // for fixed precision types, the max and min values that we can represent are calculated here:
1206 static constexpr float MaxValue = TGetPower<2, (sizeof(SampleType) * 8 - Q)>::Value;
1207 static constexpr float MinValue = !!TIsSigned<SampleType>::Value ? (-1.0f * MaxValue) : 0.0f;
1208
1209 public:
1210
1211 TSample(SampleType& InSample)
1212 : Sample(InSample)
1213 {
1216 }
1217
1218 template<typename ReturnType = float>
1219 ReturnType AsFloat() const
1220 {
1221 static_assert(TIsFloatingPoint<ReturnType>::Value, "Return type for AsFloat() must be a floating point type.");
1222
1224 {
1225 return static_cast<ReturnType>(Sample);
1226 }
1228 {
1229 // Cast from fixed to float.
1230 return static_cast<ReturnType>(Sample) / QFactor;
1231 }
1232 else
1233 {
1234 checkNoEntry();
1235 return static_cast<ReturnType>(Sample);
1236 }
1237 }
1238
1239 template<typename ReturnType, uint32 ReturnQ = (sizeof(SampleType) * 8 - 1)>
1241 {
1242 static_assert(TIsIntegral<ReturnType>::Value, "This function must be called with an integer type as ReturnType.");
1244
1246 {
1247 if (Q > ReturnQ)
1248 {
1249 return Sample << (Q - ReturnQ);
1250 }
1251 else if (Q < ReturnQ)
1252 {
1253 return Sample >> (ReturnQ - Q);
1254 }
1255 else
1256 {
1257 return Sample;
1258 }
1259 }
1261 {
1262 static constexpr float ReturnQFactor = TGetPower<2, ReturnQ>::Value - 1;
1263 return (ReturnType)(Sample * ReturnQFactor);
1264 }
1265 }
1266
1267 template <typename OtherSampleType>
1269 {
1271
1272 if constexpr (std::is_same_v<SampleType, OtherSampleType>)
1273 {
1274 Sample = InSample;
1275 return *this;
1276 }
1278 {
1279 // Cast from Q15 to float.
1280 Sample = ((SampleType)InSample) / QFactor;
1281 return *this;
1282 }
1284 {
1285 // cast from float to Q15.
1286 Sample = static_cast<SampleType>(InSample * QFactor);
1287 return *this;
1288 }
1289 else
1290 {
1291 checkNoEntry();
1292 return *this;
1293 }
1294 }
1295
1296 template <typename OtherSampleType>
1298 {
1300
1301 // Float case:
1303 {
1305 {
1306 // float * float.
1307 return LHS.Sample * RHS;
1308 }
1310 {
1311 // float * Q.
1312 SampleType FloatRHS = ((SampleType)RHS) / QFactor;
1313 return LHS.Sample * FloatRHS;
1314 }
1315 else
1316 {
1317 checkNoEntry();
1318 return LHS.Sample;
1319 }
1320
1321 }
1322 // Q Case
1324 {
1326 {
1327 // fixed * float.
1328 OtherSampleType FloatLHS = ((OtherSampleType)LHS.Sample) / QFactor;
1329 OtherSampleType Result = FMath::Clamp(FloatLHS * RHS, MinValue, MaxValue);
1330 return static_cast<SampleType>(Result * QFactor);
1331 }
1333 {
1334 // Q * Q.
1335 float FloatLHS = ((float)LHS.Sample) / QFactor;
1336 float FloatRHS = ((float)RHS) / QFactor;
1337 float Result = FMath::Clamp(FloatLHS * FloatRHS, MinValue, MaxValue);
1338 return static_cast<OtherSampleType>(Result * QFactor);
1339 }
1340 else
1341 {
1342 checkNoEntry();
1343 return LHS.Sample;
1344 }
1345 }
1346 else
1347 {
1348 checkNoEntry();
1349 return LHS.Sample;
1350 }
1351 }
1352 };
1353
1354
1370 template <typename SampleType, uint32 Q = (sizeof(SampleType) * 8 - 1)>
1372 {
1373 SampleType& Sample;
1374
1375 template <typename SampleTypeToCheck>
1376 static void CheckValidityOfSampleType()
1377 {
1379 static_assert(bIsTypeValid, "Invalid sample type! TSampleRef only supports float or integer values.");
1380 }
1381
1382 template <typename SampleTypeToCheck, uint32 QToCheck>
1383 static void CheckValidityOfQ()
1384 {
1385 // If this is a fixed-precision value, our Q offset must be less than how many bits we have.
1387 static_assert(bIsTypeValid, "Invalid value for Q! TSampleRef only supports float or int types. For int types, Q must be smaller than the number of bits in the int type.");
1388 }
1389
1390 // This is the number used to convert from float to our fixed precision value.
1391 static constexpr float QFactor = TGetPower<2, Q>::Value - 1;
1392
1393 // for fixed precision types, the max and min values that we can represent are calculated here:
1394 static constexpr float MaxValue = TGetPower<2, (sizeof(SampleType) * 8 - Q)>::Value;
1395 static constexpr float MinValue = !!TIsSigned<SampleType>::Value ? (-1.0f * MaxValue) : 0.0f;
1396
1397 public:
1398
1405
1406 template<typename ReturnType = float>
1407 ReturnType AsFloat() const
1408 {
1409 static_assert(TIsFloatingPoint<ReturnType>::Value, "Return type for AsFloat() must be a floating point type.");
1410
1412 {
1413 return static_cast<ReturnType>(Sample);
1414 }
1416 {
1417 // Cast from fixed to float.
1418 return static_cast<ReturnType>(Sample) / QFactor;
1419 }
1420 else
1421 {
1422 checkNoEntry();
1423 return static_cast<ReturnType>(Sample);
1424 }
1425 }
1426
1427 template<typename ReturnType, uint32 ReturnQ = (sizeof(SampleType) * 8 - 1)>
1429 {
1430 static_assert(TIsIntegral<ReturnType>::Value, "This function must be called with an integer type as ReturnType.");
1431
1433
1435 {
1436 if (Q > ReturnQ)
1437 {
1438 return Sample << (Q - ReturnQ);
1439 }
1440 else if (Q < ReturnQ)
1441 {
1442 return Sample >> (ReturnQ - Q);
1443 }
1444 else
1445 {
1446 return Sample;
1447 }
1448 }
1450 {
1451 static constexpr SampleType ReturnQFactor = TGetPower<2, ReturnQ>::Value - 1;
1452 return (ReturnType) (Sample * ReturnQFactor);
1453 }
1454 }
1455
1456 template <typename OtherSampleType>
1458 {
1460
1461 if constexpr (std::is_same_v<SampleType, OtherSampleType>)
1462 {
1463 Sample = InSample;
1464 return *this;
1465 }
1467 {
1468 // Cast from fixed to float.
1469 Sample = ((SampleType)InSample) / QFactor;
1470 return *this;
1471 }
1473 {
1474 // cast from float to fixed.
1475 Sample = (SampleType)(InSample * QFactor);
1476 return *this;
1477 }
1478 else
1479 {
1480 checkNoEntry();
1481 return *this;
1482 }
1483 }
1484
1485 template <typename OtherSampleType>
1486 friend SampleType operator *(const TSampleRef<SampleType>& LHS, const OtherSampleType& RHS)
1487 {
1489
1490 // Float case:
1492 {
1494 {
1495 // float * float.
1496 return LHS.Sample * RHS;
1497 }
1499 {
1500 // float * fixed.
1501 SampleType FloatRHS = ((SampleType)RHS) / QFactor;
1502 return LHS.Sample * FloatRHS;
1503 }
1504 else
1505 {
1506 checkNoEntry();
1507 return LHS.Sample;
1508 }
1509
1510 }
1511 // Fixed Precision Case
1513 {
1515 {
1516 // fixed * float.
1517 OtherSampleType FloatLHS = ((OtherSampleType)LHS.Sample) / QFactor;
1518 OtherSampleType Result = FMath::Clamp(FloatLHS * RHS, MinValue, MaxValue);
1519 return static_cast<SampleType>(Result * QFactor);
1520 }
1522 {
1523 // fixed * fixed.
1524 float FloatLHS = ((float)LHS.Sample) / QFactor;
1525 float FloatRHS = ((float)RHS) / QFactor;
1526 float Result = FMath::Clamp(FloatLHS * FloatRHS, MinValue, MaxValue);
1527
1528 return static_cast<SampleType>(Result * QFactor);
1529 }
1530 else
1531 {
1532 checkNoEntry();
1533 return LHS.Sample;
1534 }
1535 }
1536 else
1537 {
1538 checkNoEntry();
1539 return LHS.Sample;
1540 }
1541 }
1542 };
1543}
1544
#define check(expr)
Definition AssertionMacros.h:314
#define checkNoEntry()
Definition AssertionMacros.h:316
#define ensure( InExpression)
Definition AssertionMacros.h:464
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
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
return true
Definition ExternalRpcRegistry.cpp:601
#define X(Name, Desc)
Definition FormatStringSan.h:47
#define UE_REAL_TO_FLOAT(argument)
Definition LargeWorldCoordinates.h:30
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
@ Num
Definition MetalRHIPrivate.h:234
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
FORCEINLINE VectorRegister4Float VectorSubtract(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:731
FORCEINLINE void VectorSinCos(VectorRegister4Float *RESTRICT VSinAngles, VectorRegister4Float *RESTRICT VCosAngles, const VectorRegister4Float *RESTRICT VAngles)
Definition UnrealMathFPU.h:2109
FORCEINLINE VectorRegister4Float VectorSetFloat1(float F)
Definition UnrealMathFPU.h:518
FORCEINLINE VectorRegister4Float VectorMultiply(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:758
FORCEINLINE VectorRegister4Float VectorLoadFloat1(const float *Ptr)
Definition UnrealMathFPU.h:468
FORCEINLINE void VectorStore(const VectorRegister4Float &Vec, float *Dst)
Definition UnrealMathFPU.h:566
FORCEINLINE VectorRegister4Float VectorAdd(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:704
FORCEINLINE VectorRegister4Float VectorZeroFloat(void)
Definition UnrealMathFPU.h:331
FORCEINLINE VectorRegister4Float VectorLoad(const float *Ptr)
Definition UnrealMathFPU.h:394
#define UE_PI
Definition UnrealMathUtility.h:129
#define UE_BIG_NUMBER
Definition UnrealMathUtility.h:132
#define UE_SMALL_NUMBER
Definition UnrealMathUtility.h:130
#define UE_KINDA_SMALL_NUMBER
Definition UnrealMathUtility.h:131
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTempIfPossible(T &&Obj) noexcept
Definition UnrealTemplate.h:538
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
FRWLock Lock
Definition UnversionedPropertySerialization.cpp:921
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Dsp.h:505
bool IsDone() const
Definition Dsp.h:527
void SetEaseFactor(const float InEaseFactor)
Definition Dsp.h:568
float GetNextValue(uint32 NumTicksToJumpAhead)
Definition Dsp.h:552
void operator=(const float &InValue)
Definition Dsp.h:574
FExponentialEase(float InInitValue=0.0f, float InEaseFactor=0.001f, float InThreshold=UE_KINDA_SMALL_NUMBER)
Definition Dsp.h:507
static float GetFactorForTau(float InTau, float InSampleRate)
Definition Dsp.h:591
void SetValue(const float InValue, const bool bIsInit=false)
Definition Dsp.h:579
void Init(float InInitValue, float InEaseFactor=0.001f)
Definition Dsp.h:517
float GetNextValue()
Definition Dsp.h:532
float PeekCurrentValue() const
Definition Dsp.h:563
Definition Dsp.h:619
float GetNextValue(int32 NumTicksToJumpAhead)
Definition Dsp.h:670
void Init(float InSampleRate)
Definition Dsp.h:642
void SetValueInterrupt(const float InValue)
Definition Dsp.h:690
float GetNextValue()
Definition Dsp.h:655
FLinearEase()
Definition Dsp.h:621
bool IsDone() const
Definition Dsp.h:637
~FLinearEase()
Definition Dsp.h:633
void SetValue(const float InValue, float InTimeSec=0.0f)
Definition Dsp.h:705
float PeekCurrentValue() const
Definition Dsp.h:683
void SetValueRange(const float Start, const float End, const float InTimeSec)
Definition Dsp.h:648
Definition Dsp.h:126
void GenerateBuffer(float SampleRate, float ClampedFrequency, float *Buffer, int32 BufferSampleCount)
Definition Dsp.h:145
FSinOsc2DRotation(float InStartingPhaseRadians=0.f)
Definition Dsp.h:128
Definition Dsp.h:834
int32 Peek(SampleType *OutBuffer, uint32 NumSamples) const
Definition Dsp.h:1002
TCircularAudioBuffer()
Definition Dsp.h:843
SampleType Pop()
Definition Dsp.h:1097
int32 Push(TArrayView< const SampleType > InBuffer)
Definition Dsp.h:917
bool Push(const SampleType &InElement)
Definition Dsp.h:963
TCircularAudioBuffer(uint32 InCapacity)
Definition Dsp.h:864
DisjointedArrayView< const SampleType > PopInPlace(uint32 NumSamples)
Definition Dsp.h:1071
bool Push(SampleType &&InElement)
Definition Dsp.h:982
void SetCapacity(uint32 InCapacity)
Definition Dsp.h:881
int32 Push(const SampleType *InBuffer, uint32 NumSamples)
Definition Dsp.h:925
uint32 Remainder() const
Definition Dsp.h:1156
TCircularAudioBuffer & operator=(const TCircularAudioBuffer< SampleType, Alignment > &InOther)
Definition Dsp.h:853
void Reserve(uint32 InMinimumCapacity, bool bRetainExistingSamples)
Definition Dsp.h:896
uint32 GetCapacity() const
Definition Dsp.h:1150
DisjointedArrayView< const SampleType > PeekInPlace(uint32 NumSamples) const
Definition Dsp.h:1022
uint32 Num() const
Definition Dsp.h:1134
void Empty()
Definition Dsp.h:874
int32 Pop(SampleType *OutBuffer, uint32 NumSamples)
Definition Dsp.h:1059
void SetNum(uint32 NumSamples, bool bRetainOldestSamples=false)
Definition Dsp.h:1113
TCircularAudioBuffer(const TCircularAudioBuffer< SampleType, Alignment > &InOther)
Definition Dsp.h:848
int32 PushZeros(uint32 NumSamplesOfZeros)
Definition Dsp.h:944
bool Peek(SampleType &OutElement) const
Definition Dsp.h:1040
void Reset(uint32 InCapacity=0)
Definition Dsp.h:869
int32 Pop(uint32 NumSamples)
Definition Dsp.h:1084
Definition Dsp.h:743
T CurrentParams
Definition Dsp.h:777
void SetParams(const T &InParams)
Definition Dsp.h:750
bool GetParams(T *OutParamsCopy)
Definition Dsp.h:758
void CopyParams(T &OutParamsCopy) const
Definition Dsp.h:770
bool bChanged
Definition Dsp.h:776
TParams()
Definition Dsp.h:745
FCriticalSection CritSect
Definition Dsp.h:778
Definition Dsp.h:1372
TSampleRef(SampleType &InSample)
Definition Dsp.h:1399
ReturnType AsFixedPrecisionInt()
Definition Dsp.h:1428
friend SampleType operator*(const TSampleRef< SampleType > &LHS, const OtherSampleType &RHS)
Definition Dsp.h:1486
TSampleRef< SampleType, Q > & operator=(const OtherSampleType InSample)
Definition Dsp.h:1457
ReturnType AsFloat() const
Definition Dsp.h:1407
Definition Dsp.h:1184
ReturnType AsFixedPrecisionInt()
Definition Dsp.h:1240
ReturnType AsFloat() const
Definition Dsp.h:1219
friend TSample< SampleType, Q > operator*(const TSample< SampleType, Q > &LHS, const OtherSampleType &RHS)
Definition Dsp.h:1297
TSample< SampleType, Q > & operator=(const OtherSampleType InSample)
Definition Dsp.h:1268
TSample(SampleType &InSample)
Definition Dsp.h:1211
Definition ScopeLock.h:141
Definition ThreadSafeCounter.h:14
int32 GetValue() const
Definition ThreadSafeCounter.h:120
int32 Set(int32 Value)
Definition ThreadSafeCounter.h:99
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_REWRITE SizeType Num() const
Definition Array.h:1144
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_NODEBUG UE_FORCEINLINE_HINT ElementType * GetData() UE_LIFETIMEBOUND
Definition Array.h:1027
SizeType AddZeroed()
Definition Array.h:2755
void Empty(SizeType Slack=0)
Definition Array.h:2273
NO_LOGGING.
Definition AudioMixerPlatformAndroid.cpp:53
void CheckSample(float InSample, float Threshold=0.001f)
Definition Dsp.h:30
float GetGainFromVelocity(const float InVelocity)
Definition Dsp.h:62
float FastSin2(const float X)
Definition Dsp.h:79
float ConvertToDecibels(const float InLinear, const float InFloor=UE_SMALL_NUMBER)
Definition Dsp.h:50
float UnderflowClamp(const float InValue)
Definition Dsp.h:40
float FastSin(const float X)
Definition Dsp.h:73
void ConvertBipolarBufferToUnipolar(float *InAlignedBuffer, int32 NumSamples)
Definition Dsp.h:272
float LagrangianInterpolation(const TArray< FVector2D > Points, const float Alpha)
Definition Dsp.h:477
float GetBandwidthFromQ(const float InQ)
Definition Dsp.h:425
float FastTanh(float X)
Definition Dsp.h:242
float FastTan(float X)
Definition Dsp.h:251
float FastSin3(const float X)
Definition Dsp.h:89
TArray< float, FAudioBufferAlignedAllocator > FAlignedFloatBuffer
Definition AlignedBuffer.h:22
float GetSemitones(const float InMultiplier)
Definition Dsp.h:372
float GetUnipolar(const float X)
Definition Dsp.h:265
float GetLogFrequencyClamped(const float InValue, const FVector2D &Domain, const FVector2D &Range)
Definition Dsp.h:296
float GetFrequencyFromMidi(const float InMidiNote)
Definition Dsp.h:290
bool QuadraticPeakInterpolation(const float InValues[3], float &OutPeakLoc, float &OutPeakValue)
Definition Dsp.h:450
void GetStereoPan(const float InLinearPan, float &OutLeft, float &OutRight)
Definition Dsp.h:383
float ConvertToLinear(const float InDecibels)
Definition Dsp.h:56
float GetMidiFromFrequency(const float InFrequency)
Definition Dsp.h:346
float GetPitchScaleFromMIDINote(int32 BaseMidiNote, int32 TargetMidiNote)
Definition Dsp.h:352
float GetQFromBandwidth(const float InBandwidth)
Definition Dsp.h:435
void EncodeMidSide(const FAlignedFloatBuffer &InLeftChannel, const FAlignedFloatBuffer &InRightChannel, FAlignedFloatBuffer &OutMidChannel, FAlignedFloatBuffer &OutSideChannel)
Definition Dsp.cpp:9
float GetLinearFrequencyClamped(const float InFrequencyValue, const FVector2D &Domain, const FVector2D &Range)
Definition Dsp.h:321
float GetBipolar(const float X)
Definition Dsp.h:259
void DecodeMidSide(const FAlignedFloatBuffer &InMidChannel, const FAlignedFloatBuffer &InSideChannel, FAlignedFloatBuffer &OutLeftChannel, FAlignedFloatBuffer &OutRightChannel)
Definition Dsp.cpp:37
float GetFrequencyMultiplier(const float InPitchSemitones)
Definition Dsp.h:361
@ false
Definition radaudio_common.h:23
Definition Dsp.h:783
TArrayView< SampleType > SecondBuffer
Definition Dsp.h:823
DisjointedArrayView(TArrayView< SampleType > &&InFirstBuffer, TArrayView< SampleType > &&InSecondBuffer)
Definition Dsp.h:784
DisjointedArrayView< OtherSampleType > SplitOtherToMatch(OtherSampleType *Other, int32 InNum) const
Definition Dsp.h:790
int32 Num() const
Definition Dsp.h:819
int32 FirstNum() const
Definition Dsp.h:817
int32 CopyIntoBuffer(SampleType *InDestination, int32 InNumSamples)
Definition Dsp.h:801
int32 SecondNum() const
Definition Dsp.h:818
TArrayView< SampleType > FirstBuffer
Definition Dsp.h:822
Definition Dsp.h:1167
static const int64 Value
Definition Dsp.h:1169
static UE_FORCEINLINE_HINT auto GetMappedRangeValueUnclamped(const UE::Math::TVector2< T > &InputRange, const UE::Math::TVector2< T > &OutputRange, const T2 Value)
Definition UnrealMathUtility.h:1086
static constexpr UE_FORCEINLINE_HINT T Clamp(const T X, const T MinValue, const T MaxValue)
Definition UnrealMathUtility.h:592
static float Log2(float Value)
Definition UnrealMathUtility.h:722
static UE_FORCEINLINE_HINT void * Memzero(void *Dest, SIZE_T Count)
Definition UnrealMemory.h:131
static UE_FORCEINLINE_HINT void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:160
Definition IsFloatingPoint.h:12
Definition IsIntegral.h:12
Definition IsSigned.h:12
Definition NumericLimits.h:41
double FReal
Definition Vector2D.h:42
T Y
Definition Vector2D.h:52
T X
Definition Vector2D.h:49
Definition UnrealMathFPU.h:20