// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "DSP/BufferVectorOperations.h" namespace Audio { /** Sum all values in an array. */ SIGNALPROCESSING_API void ArraySum(TArrayView InValues, float& OutSum); /** Sums two buffers together and places the result in the resulting buffer. */ SIGNALPROCESSING_API void ArraySum(TArrayView InFloatBuffer1, TArrayView InFloatBuffer2, TArrayView OutputBuffer); /** Cumulative sum of array. * * InView contains data to be cumulatively summed. * OutData contains sum and is same size as InView. */ SIGNALPROCESSING_API void ArrayCumulativeSum(TArrayView InView, TArray& OutData); /** Mean of array. Equivalent to Sum(InView) / InView.Num() * * InView contains data to be analyzed. * OutMean contains the result. */ SIGNALPROCESSING_API void ArrayMean(TArrayView InView, float& OutMean); /** Mean Squared of array. Equivalent to Sum(InView * InView) / InView.Num() * * InArray contains data to be analyzed. * OutMean contains the result. */ SIGNALPROCESSING_API void ArrayMeanSquared(TArrayView InView, float& OutMean); /** Takes an audio buffer and returns the magnitude across that buffer. */ SIGNALPROCESSING_API float ArrayGetMagnitude(TArrayView Buffer); /** Takes an audio buffer and gets the average amplitude across that buffer. */ SIGNALPROCESSING_API float ArrayGetAverageValue(TArrayView Buffer); /** Takes an audio buffer and gets the average absolute amplitude across that buffer. */ SIGNALPROCESSING_API float ArrayGetAverageAbsValue(TArrayView Buffer); /** Mean filter of array. * * Note: Uses standard biased mean estimator of Sum(x) / Count(x). * Note: At array boundaries, this algorithm truncates windows where no valid array data exists. Values calculated with truncated windows have corresponding increased variances. * * InView contains data to be filtered. * WindowSize determines the number of samples from InView analyzed to produce a value in OutData. * WindowOrigin describes the offset from the windows first sample to the index of OutData. For example, if WindowOrigin = WindowSize/4, then OutData[i] = Mean(InView[i - Window/4 : i + 3 * Window / 4]). * OutData contains the produceds data. */ SIGNALPROCESSING_API void ArrayMeanFilter(TArrayView InView, int32 WindowSize, int32 WindowOrigin, TArray& OutData); /** Max filter of array. * * Note: At array boundaries, this algorithm truncates windows where no valid array data exists. * * InView contains data to be filtered. * WindowSize determines the number of samples from InView analyzed to produce a value in OutData. * WindowOrigin describes the offset from the windows first sample to the index of OutData. For example, if WindowOrigin = WindowSize/4, then OutData[i] = Max(InView[i - Window/4 : i + 3 * Window / 4]). * OutData contains the produceds data. */ SIGNALPROCESSING_API void ArrayMaxFilter(TArrayView InView, int32 WindowSize, int32 WindowOrigin, TArray& OutData); /** Computes the EuclideanNorm of the InView. Same as calculating the energy in window. */ SIGNALPROCESSING_API void ArrayGetEuclideanNorm(TArrayView InView, float& OutEuclideanNorm); /** Absolute value of array elements */ SIGNALPROCESSING_API void ArrayAbs(TArrayView InBuffer, TArrayView OutBuffer); /** Absolute value of array elements in place. * * InBuffer contains the data to be manipulated. */ SIGNALPROCESSING_API void ArrayAbsInPlace(TArrayView InBuffer); /** Clamp minimum value of array in place. * * InView contains data to be clamped. * InMin contains the minimum value allowable in InView. */ SIGNALPROCESSING_API void ArrayClampMinInPlace(TArrayView InView, float InMin); /** Clamp maximum value of array in place. * * InView contains data to be clamped. * InMax contains the maximum value allowable in InView. */ SIGNALPROCESSING_API void ArrayClampMaxInPlace(TArrayView InView, float InMax); /** Clamp values in an array. * * InView is a view of a float array to be clamped. * InMin is the minimum value allowable in the array. * InMax is the maximum value allowable in the array. */ SIGNALPROCESSING_API void ArrayClampInPlace(TArrayView InView, float InMin, float InMax); /** Scale an array so the minimum is 0 and the maximum is 1 * * InView is the view of a float array with the input data. * OutArray is an array which will hold the normalized data. */ SIGNALPROCESSING_API void ArrayMinMaxNormalize(TArrayView InView, TArray& OutArray); /** Element-wise Max */ SIGNALPROCESSING_API void ArrayMax(const TArrayView& InView1, const TArrayView& InView2, const TArrayView& OutView); /** Returns the largest value of an array irrespective of sign (ex. {-3, 2, 1} would return 3). * InView is a view of a float array to get the largest absolute value from. */ SIGNALPROCESSING_API float ArrayMaxAbsValue(const TArrayView InView); /** Multiply the second buffer by the first buffer. */ SIGNALPROCESSING_API void ArrayMultiply(TArrayView InFloatBufferA, TArrayView InFloatBufferB, TArrayView OutBuffer); /** Multiply the second buffer in place by the first buffer. */ SIGNALPROCESSING_API void ArrayMultiplyInPlace(TArrayView InFloatBuffer, TArrayView BufferToMultiply); /** Multiplies two complex valued arrays element-wise. * This assumes elements are in interleaved format [real_0, imag_0, ..., real_N, imag_N] * Stores result in InValues2 */ SIGNALPROCESSING_API void ArrayComplexMultiplyInPlace(TArrayView InValues1, TArrayView InValues2); /** Multiplies two complex valued arrays element-wise. * This assumes elements are in interleaved format [real_0, imag_0, ..., real_N, imag_N] * Adds result to OutArray */ SIGNALPROCESSING_API void ArrayComplexMultiplyAdd(TArrayView InValues1, TArrayView InValues2, TArrayView OutArray); /** Multiplies the input float buffer with the given value. */ SIGNALPROCESSING_API void ArrayMultiplyByConstant(TArrayView InFloatBuffer, float InValue, TArrayView OutFloatBuffer); /** Similar to ArrayMultiplyByConstant, but performs the multiply in place. */ SIGNALPROCESSING_API void ArrayMultiplyByConstantInPlace(TArrayView InOutBuffer, float InGain); /** Add arrays element-wise in place. InAccumulateValues[i] += InValues[i] * * InValues is the array to add. * InAccumulateValues is the array which holds the sum. */ SIGNALPROCESSING_API void ArrayAddInPlace(TArrayView InValues, TArrayView InAccumulateValues); /** Adds a constant to a buffer (useful for DC offset removal) */ SIGNALPROCESSING_API void ArrayAddConstantInplace(TArrayView InOutBuffer, float InConstant); /** Multiply Add arrays element-wise in place. InAccumulateValues[i] += InMultiplier * InValues[i] * * @param InValues - The array to add. * @param InMultiplier - The value to multiply against InValues * @param InAccumulateValues - The array which holds the sum. */ SIGNALPROCESSING_API void ArrayMultiplyAddInPlace(TArrayView InValues, float InMultiplier, TArrayView InAccumulateValues); /** Linearly Interpolate Add arrays element-wise in place. InAccumulateValues[i] += ((1 - alpha) * InStartMultiplier + alpha * InEndMultipler) * InValues[i] * Interpolation is performed over the length of the array. * * @param InValues - The array to add. * @param InStartMultiplier - The beginning value to multiply against InValues * @param InEndMultiplier - The ending value to multiply against InValues * @param InAccumulateValues - The array which holds the sum. */ SIGNALPROCESSING_API void ArrayLerpAddInPlace(TArrayView InValues, float InStartMultiplier, float InEndMultiplier, TArrayView InAccumulateValues); /** Subract arrays element-wise. OutArray = InMinuend - InSubtrahend * * InMinuend is the array of data to be subtracted from. * InSubtrahend is the array of data to subtract. * OutBuffer is the array which holds the result. */ SIGNALPROCESSING_API void ArraySubtract(TArrayView InMinuend, TArrayView InSubtrahend, TArrayView OutBuffer); /* Performs element-wise in-place subtraction placing the result in the subtrahend. InOutSubtrahend = InMinuend - InOutSubtrahend */ SIGNALPROCESSING_API void ArraySubtractInPlace1(TArrayView InMinuend, TArrayView InOutSubtrahend); /* Performs element-wise in-place subtraction placing the result in the minuend. InOutMinuend = InOutMinuend - InSubtrahend */ SIGNALPROCESSING_API void ArraySubtractInPlace2(TArrayView InOutMinuend, TArrayView InSubtrahend); /** Subtract value from each element in InValues */ SIGNALPROCESSING_API void ArraySubtractByConstantInPlace(TArrayView InValues, float InSubtrahend); /* Square values */ SIGNALPROCESSING_API void ArraySquare(TArrayView InValues, TArrayView OutValues); /** Square values in place. */ SIGNALPROCESSING_API void ArraySquareInPlace(TArrayView InValues); /** Take Square Root of values in place. */ SIGNALPROCESSING_API void ArraySqrtInPlace(TArrayView InValues); /** Perform complex conjugate of array. Assumes complex numbers are interlaves [real_0, imag_0, real_1, image_1, ..., real_N, imag_N]. */ SIGNALPROCESSING_API void ArrayComplexConjugate(TArrayView InValues, TArrayView OutValues); SIGNALPROCESSING_API void ArrayComplexConjugateInPlace(TArrayView InValues); /** Convert magnitude values to decibel values in place. db = 20 * log10(val) */ SIGNALPROCESSING_API void ArrayMagnitudeToDecibelInPlace(TArrayView InValues, float InMinimumDb); /** Convert power values to decibel values in place. db = 10 * log10(val) */ SIGNALPROCESSING_API void ArrayPowerToDecibelInPlace(TArrayView InValues, float InMinimumDb); /** Compute power of complex data. Out[i] = Complex[2 * i] * Complex[2 * i] + Complex[2 * i + 1] * Complex[2 * i + 1] */ SIGNALPROCESSING_API void ArrayComplexToPower(TArrayView InComplexSamples, TArrayView OutPowerSamples); /** Compute power of complex data. Out[i] = Real[i] * Real[i] + Imaginary[i] * Imaginary[i] */ SIGNALPROCESSING_API void ArrayComplexToPower(TArrayView InRealSamples, TArrayView InImaginarySamples, TArrayView OutPowerSamples); /* Sets a values to zero if value is denormal. Denormal numbers significantly slow down floating point operations. */ 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") SIGNALPROCESSING_API void ArrayUnderflowClamp(TArrayView InOutBuffer); /* Clamps the values in a buffer between a min and max value.*/ SIGNALPROCESSING_API void ArrayRangeClamp(TArrayView InOutBuffer, float InMinValue, float InMaxValue); /** Sets a constant to a buffer (useful for DC offset application) */ SIGNALPROCESSING_API void ArraySetToConstantInplace(TArrayView InOutBuffer, float InConstant); /* Performs an element-wise weighted sum OutputBuffer = (InBuffer1 x InGain1) + (InBuffer2 x InGain2) */ SIGNALPROCESSING_API void ArrayWeightedSum(TArrayView InBuffer1, float InGain1, TArrayView InBuffer2, float InGain2, TArrayView OutBuffer); /* Performs an element-wise weighted sum OutputBuffer = (InBuffer1 x InGain1) + InBuffer2 */ SIGNALPROCESSING_API void ArrayWeightedSum(TArrayView InBuffer1, float InGain1, TArrayView InBuffer2, TArrayView OutBuffer); /* Takes a float buffer and quickly interpolates it's gain from StartValue to EndValue. */ /* This operation completely ignores channel counts, so avoid using this function on buffers that are not mono, stereo or quad */ /* if the buffer needs to fade all channels uniformly. */ SIGNALPROCESSING_API void ArrayFade(TArrayView InOutBuffer, const float StartValue, const float EndValue); SIGNALPROCESSING_API void ArrayFade(TArrayView InBuffer, const float InStartValue, const float InEndValue, TArrayView OutBuffer); /** Takes buffer InFloatBuffer, optionally multiplies it by Gain, and adds it to BufferToSumTo. */ SIGNALPROCESSING_API void ArrayMixIn(TArrayView InFloatBuffer, TArrayView BufferToSumTo, const float Gain); SIGNALPROCESSING_API void ArrayMixIn(TArrayView InFloatBuffer, TArrayView BufferToSumTo); /** Takes buffer InPcm16Buffer, converts it to float and optionally multiplies it by Gain, and adds it to BufferToSumTo. */ SIGNALPROCESSING_API void ArrayMixIn(TArrayView InPcm16Buffer, TArrayView BufferToSumTo, const float Gain = 1.0f); /** This version of ArrayMixIn will fade from StartGain to EndGain. */ SIGNALPROCESSING_API void ArrayMixIn(TArrayView InFloatBuffer, TArrayView BufferToSumTo, const float StartGain, const float EndGain); SIGNALPROCESSING_API void ArrayFloatToPcm16(TArrayView InView, TArrayView OutView); SIGNALPROCESSING_API void ArrayPcm16ToFloat(TArrayView InView, TArrayView OutView); /** Converts float PCM data to 24 bit integer PCM data */ SIGNALPROCESSING_API void ArrayFloatToPcm24(TArrayView InView, TArrayView OutView); /** Copies 24 bits of a 32 bit integer (assumes data has been clamped to 24-bits) */ SIGNALPROCESSING_API void AssignPcm24Value(int8* OutPtr, const int32 InValue, const bool bIsOutputLittleEndian); /** Converts float PCM data to 32 bit integer PCM data */ SIGNALPROCESSING_API void ArrayFloatToPcm32(TArrayView InView, TArrayView OutView); /** Converts float PCM data to double PCM data */ SIGNALPROCESSING_API void ArrayFloatToPcmDouble(TArrayView InView, TArrayView OutView); /** Interleaves samples from an array of input buffers */ SIGNALPROCESSING_API void ArrayInterleave(const TArray& InBuffers, FAlignedFloatBuffer& OutBuffer); /** Interleaves samples from an array of input buffers */ SIGNALPROCESSING_API void ArrayInterleave(const float* const* RESTRICT InBuffers, float* RESTRICT OutBuffer, const int32 InFrames, const int32 InChannels); /** Interleaves samples from an array of input buffers */ SIGNALPROCESSING_API void ArrayDeinterleave(const FAlignedFloatBuffer& InBuffer, TArray& OutBuffers, const int32 InChannels); /** Interleaves samples from an array of input buffers */ SIGNALPROCESSING_API void ArrayDeinterleave(const TArrayView InView, TArray& OutBuffers, const int32 InChannels); /** Interleaves samples from an array of input buffers */ SIGNALPROCESSING_API void ArrayDeinterleave(const float* RESTRICT InBuffer, float* const* RESTRICT OutBuffers, const int32 InFrames, const int32 InChannels); /** Interpolates a Mono audio buffer. */ SIGNALPROCESSING_API void ArrayInterpolate(const float* RESTRICT InBuffer, float* RESTRICT OutBuffer, const int32 NumInSamples, const int32 NumOutSamples); /** Vectorized 16-bit integer byte swapping. */ SIGNALPROCESSING_API void ArrayInt16SwapBytes(TArrayView InView); /** Vectorized 24-bit integer byte swapping. */ SIGNALPROCESSING_API void ArrayInt24SwapBytes(TArrayView InView); /** Vectorized 32-bit integer byte swapping. */ SIGNALPROCESSING_API void ArrayInt32SwapBytes(TArrayView InView); /** Vectorized 32-bit float byte swapping. */ SIGNALPROCESSING_API void ArrayFloatSwapBytes(TArrayView InView); /** Vectorized 64-bit float byte swapping. */ SIGNALPROCESSING_API void ArrayDoubleSwapBytes(TArrayView InView); /** Returns true if host has little endian byte ordering */ UE_DEPRECATED(5.5, "Big Endian platforms are no longer supported.") SIGNALPROCESSING_API constexpr bool IsHostLittleEndian() { #if PLATFORM_LITTLE_ENDIAN return true; #else return false; #endif // PLATFORM_LITTLE_ENDIAN } /** All Pass Filter with a long delay. */ SIGNALPROCESSING_API void ArrayAPFLongDelayProcess(const float* InSamples, const float* InDelaySamples, const int32 InNum, float* OutSamples, float* OutDelaySamples, const float Gain); /** Fractional delay using linear interpolation. */ SIGNALPROCESSING_API void ArrayLerpFractionalDelay(const float* InSamples, const float* InDelays, const float* DelayData, const int* IntegerDelays, int* UpperDelayPos, int* LowerDelayPos, const int32 InNum, float* OutSamples, const float MaxDelay); /** Perform complex conjugate as well as scale. */ SIGNALPROCESSING_API void ArrayScaledComplexConjugate(const float* RESTRICT InValues, const int32 Num, float* RESTRICT OutValues, const float Scale); /** FContiguousSparse2DKernelTransform * * FContiguousSparse2DKernelTransform applies a matrix transformation to an input array. * [OutArray] = [[Kernal]][InView] * * It provides some optimization by exploit the contiguous and sparse qualities of the kernel rows, * which allows it to skip multiplications with the number zero. * * It works with non-sparse and non-contiguous kernels as well, but will be more computationally * expensive than a naive implementation. Also, only takes advantage of sparse contiguous rows, not columns. */ class FContiguousSparse2DKernelTransform { struct FRow { int32 StartIndex = 0; TArray OffsetValues; }; public: FContiguousSparse2DKernelTransform(const FContiguousSparse2DKernelTransform& ) = delete; FContiguousSparse2DKernelTransform(const FContiguousSparse2DKernelTransform&& ) = delete; FContiguousSparse2DKernelTransform& operator=(const FContiguousSparse2DKernelTransform& ) = delete; /** * NumInElements sets the expected number of input array elements as well as the number of elements in a row. * NumOutElements sets the number of output array elements as well as the number or rows. */ SIGNALPROCESSING_API FContiguousSparse2DKernelTransform(const int32 NumInElements, const int32 NumOutElements); SIGNALPROCESSING_API virtual ~FContiguousSparse2DKernelTransform(); /** Returns the required size of the input array */ SIGNALPROCESSING_API int32 GetNumInElements() const; /** Returns the size of the output array */ SIGNALPROCESSING_API int32 GetNumOutElements() const; /** Set the kernel values for an individual row. * * RowIndex determines which row is being set. * StartIndex denotes the offset into the row where the OffsetValues will be inserted. * OffsetValues contains the contiguous chunk of values which represent all the nonzero elements in the row. */ SIGNALPROCESSING_API void SetRow(const int32 RowIndex, const int32 StartIndex, TArrayView OffsetValues); /** Transforms the input array given the kernel. * * InView is the array to be transformed. It must have `NumInElements` number of elements. * OutArray is the transformed array. It will have `NumOutElements` number of elements. */ SIGNALPROCESSING_API void TransformArray(TArrayView InView, TArray& OutArray) const; /** Transforms the input array given the kernel. * * InView is the array to be transformed. It must have `NumInElements` number of elements. * OutArray is the transformed array. It will have `NumOutElements` number of elements. */ SIGNALPROCESSING_API void TransformArray(TArrayView InView, FAlignedFloatBuffer& OutArray) const; /** Transforms the input array given the kernel. * * InArray is the array to be transformed. It must have `NumInElements` number of elements. * OutArray is the transformed array. It must be allocated to hold at least NumOutElements. */ SIGNALPROCESSING_API void TransformArray(const float* InArray, float* OutArray) const; private: int32 NumIn; int32 NumOut; TArray Kernel; }; }