2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-08-15 13:50:15 -04:00
# include "DSP/FloatArrayMath.h"
# include "CoreMinimal.h"
2022-04-19 20:25:11 -04:00
# include "Math/UnrealMathVectorConstants.h"
2022-04-04 13:09:43 -04:00
# include "SignalProcessingModule.h"
2022-07-20 21:52:27 -04:00
# include "ProfilingDebugging/CsvProfiler.h"
2024-08-29 13:00:59 -04:00
# include "DSP/Dsp.h"
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC && !UE_BUILD_SHIPPING
# include "HAL/IConsoleManager.h"
# endif
# if INTEL_ISPC
# include "FloatArrayMath.ispc.generated.h"
# endif
2022-07-21 21:41:49 -04:00
# if !defined(AUDIO_FLOAT_ARRAY_MATH_ISPC_ENABLED_DEFAULT)
# define AUDIO_FLOAT_ARRAY_MATH_ISPC_ENABLED_DEFAULT 1
# endif
// Support run-time toggling on supported platforms in non-shipping configurations
# if !INTEL_ISPC || UE_BUILD_SHIPPING
static constexpr bool bAudio_FloatArrayMath_ISPC_Enabled = INTEL_ISPC & & AUDIO_FLOAT_ARRAY_MATH_ISPC_ENABLED_DEFAULT ;
# else
static bool bAudio_FloatArrayMath_ISPC_Enabled = AUDIO_FLOAT_ARRAY_MATH_ISPC_ENABLED_DEFAULT ;
static FAutoConsoleVariableRef CVarAudioFloatArrayMathISPCEnabled ( TEXT ( " au.FloatArrayMath.ISPC " ) , bAudio_FloatArrayMath_ISPC_Enabled , TEXT ( " Whether to use ISPC optimizations in audio float array math operations " ) ) ;
2022-04-04 13:09:43 -04:00
# endif
2019-08-15 13:50:15 -04:00
2022-07-20 21:52:27 -04:00
CSV_DEFINE_CATEGORY ( Audio_Dsp , false ) ;
2019-08-15 13:50:15 -04:00
namespace Audio
{
2020-02-25 18:21:12 -05:00
namespace MathIntrinsics
{
const float Loge10 = FMath : : Loge ( 10.f ) ;
const int32 SimdMask = 0xFFFFFFFC ;
const int32 NotSimdMask = 0x00000003 ;
2023-11-01 12:25:28 -04:00
const int32 Simd8Mask = 0xFFFFFFF8 ;
const int32 NotSimd8Mask = 0x00000007 ;
const int32 Simd16Mask = 0xFFFFFFF0 ;
const int32 NotSimd16Mask = 0x0000000F ;
2020-02-26 18:55:39 -05:00
}
2020-02-25 18:21:12 -05:00
2020-02-26 18:55:39 -05:00
void ArraySum ( TArrayView < const float > InValues , float & OutSum )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySum ) ;
2020-02-26 18:55:39 -05:00
OutSum = 0.f ;
int32 Num = InValues . Num ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-02-26 18:55:39 -05:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArraySum ( InValues . GetData ( ) , OutSum , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
VectorRegister4Float Total = VectorSetFloat1 ( 0.f ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InValues [ i ] ) ;
Total = VectorAdd ( Total , VectorData ) ;
}
float Val [ 4 ] ;
VectorStore ( Total , Val ) ;
OutSum + = Val [ 0 ] + Val [ 1 ] + Val [ 2 ] + Val [ 3 ] ;
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutSum + = InValues [ i ] ;
}
}
2020-02-26 18:55:39 -05:00
}
}
2022-04-04 13:09:43 -04:00
void ArraySum ( TArrayView < const float > InFloatBuffer1 , TArrayView < const float > InFloatBuffer2 , TArrayView < float > OutputBuffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySum ) ;
2022-04-04 13:09:43 -04:00
checkf ( InFloatBuffer1 . Num ( ) = = InFloatBuffer2 . Num ( ) , TEXT ( " Input buffers must be equal length " ) ) ;
2020-02-26 18:55:39 -05:00
2022-04-04 13:09:43 -04:00
const int32 Num = InFloatBuffer1 . Num ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-02-26 18:55:39 -05:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArraySum2 ( InFloatBuffer1 . GetData ( ) , InFloatBuffer2 . GetData ( ) , OutputBuffer . GetData ( ) , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2020-02-26 18:55:39 -05:00
2022-04-04 13:09:43 -04:00
if ( NumToSimd )
2020-02-26 18:55:39 -05:00
{
2022-04-04 13:09:43 -04:00
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input1 = VectorLoad ( & InFloatBuffer1 [ i ] ) ;
VectorRegister4Float Input2 = VectorLoad ( & InFloatBuffer2 [ i ] ) ;
VectorRegister4Float Output = VectorAdd ( Input1 , Input2 ) ;
VectorStore ( Output , & OutputBuffer [ i ] ) ;
}
2020-02-26 18:55:39 -05:00
}
2022-04-04 13:09:43 -04:00
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutputBuffer [ i ] = InFloatBuffer1 [ i ] + InFloatBuffer2 [ i ] ;
}
}
2020-02-26 18:55:39 -05:00
}
2022-04-04 13:09:43 -04:00
}
2020-02-26 18:55:39 -05:00
2019-10-02 13:45:06 -04:00
void ArrayCumulativeSum ( TArrayView < const float > InView , TArray < float > & OutData )
2019-08-15 13:50:15 -04:00
{
// Initialize output data
2019-10-02 13:45:06 -04:00
int32 Num = InView . Num ( ) ;
2019-08-15 13:50:15 -04:00
OutData . Reset ( ) ;
OutData . AddUninitialized ( Num ) ;
if ( Num < 1 )
{
return ;
}
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayCumulativeSum ) ;
2019-08-15 13:50:15 -04:00
float * OutDataPtr = OutData . GetData ( ) ;
2019-10-02 13:45:06 -04:00
const float * InViewPtr = InView . GetData ( ) ;
2019-08-15 13:50:15 -04:00
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-08-15 13:50:15 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayCumulativeSum ( InViewPtr , OutDataPtr , Num ) ;
# endif
}
else
{
// Start summing
* OutDataPtr = * InViewPtr + + ;
for ( int32 i = 1 ; i < Num ; i + + )
{
float Temp = * OutDataPtr + + + * InViewPtr + + ;
* OutDataPtr = Temp ;
}
2019-08-15 13:50:15 -04:00
}
}
2019-10-31 12:19:40 -04:00
void ArrayMean ( TArrayView < const float > InView , float & OutMean )
{
OutMean = 0.f ;
const int32 Num = InView . Num ( ) ;
if ( Num < 1 )
{
return ;
}
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMean ) ;
2019-10-31 12:19:40 -04:00
const float * DataPtr = InView . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-10-31 12:19:40 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMean ( DataPtr , OutMean , Num ) ;
# endif
}
else
{
for ( int32 i = 0 ; i < Num ; i + + )
{
OutMean + = DataPtr [ i ] ;
}
OutMean / = static_cast < float > ( Num ) ;
2019-10-31 12:19:40 -04:00
}
}
2021-07-21 14:45:59 -04:00
void ArrayMeanSquared ( TArrayView < const float > InView , float & OutMean )
{
OutMean = 0.0f ;
const int32 Num = InView . Num ( ) ;
if ( Num < 1 )
{
return ;
}
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMeanSquared ) ;
2021-07-21 14:45:59 -04:00
const float * DataPtr = InView . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2021-07-21 14:45:59 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMeanSquared ( DataPtr , OutMean , Num ) ;
# endif
2021-07-21 14:45:59 -04:00
}
2022-04-04 13:09:43 -04:00
else
{
for ( int32 i = 0 ; i < Num ; i + + )
{
OutMean + = DataPtr [ i ] * DataPtr [ i ] ;
}
OutMean / = static_cast < float > ( Num ) ;
}
}
2021-07-21 14:45:59 -04:00
2022-04-04 13:09:43 -04:00
float ArrayGetMagnitude ( TArrayView < const float > Buffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayGetMagnitude ) ;
2022-04-04 13:09:43 -04:00
const int32 Num = Buffer . Num ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
return ispc : : ArrayGetMagnitude ( Buffer . GetData ( ) , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
float Sum = 0.0f ;
if ( NumToSimd )
{
VectorRegister4Float VectorSum = VectorZero ( ) ;
const float Exponent = 2.0f ;
VectorRegister4Float ExponentVector = VectorLoadFloat1 ( & Exponent ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input = VectorPow ( VectorLoad ( & Buffer [ i ] ) , ExponentVector ) ;
VectorSum = VectorAdd ( VectorSum , Input ) ;
}
float PartionedSums [ 4 ] ;
VectorStore ( VectorSum , PartionedSums ) ;
Sum + = PartionedSums [ 0 ] + PartionedSums [ 1 ] + PartionedSums [ 2 ] + PartionedSums [ 3 ] ;
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
Sum + = Buffer [ i ] * Buffer [ i ] ;
}
}
return FMath : : Sqrt ( Sum ) ;
}
}
float ArrayGetAverageValue ( TArrayView < const float > Buffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayGetAverageValue ) ;
2022-04-04 13:09:43 -04:00
const int32 Num = Buffer . Num ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
return ispc : : ArrayGetAverageValue ( Buffer . GetData ( ) , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
float Sum = 0.0f ;
if ( NumToSimd )
{
VectorRegister4Float VectorSum = VectorZero ( ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input = VectorLoad ( & Buffer [ i ] ) ;
VectorSum = VectorAdd ( VectorSum , Input ) ;
}
float PartionedSums [ 4 ] ;
VectorStore ( VectorSum , PartionedSums ) ;
Sum + = PartionedSums [ 0 ] + PartionedSums [ 1 ] + PartionedSums [ 2 ] + PartionedSums [ 3 ] ;
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
Sum + = Buffer [ i ] ;
}
}
return Sum / Num ;
}
}
float ArrayGetAverageAbsValue ( TArrayView < const float > Buffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayGetAverageAbsValue ) ;
2022-04-04 13:09:43 -04:00
const int32 Num = Buffer . Num ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
return ispc : : ArrayGetAverageAbsValue ( Buffer . GetData ( ) , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
float Sum = 0.0f ;
if ( NumToSimd )
{
VectorRegister4Float VectorSum = VectorZero ( ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input = VectorAbs ( VectorLoad ( & Buffer [ i ] ) ) ;
VectorSum = VectorAdd ( VectorSum , Input ) ;
}
float PartionedSums [ 4 ] ;
VectorStore ( VectorSum , PartionedSums ) ;
Sum + = PartionedSums [ 0 ] + PartionedSums [ 1 ] + PartionedSums [ 2 ] + PartionedSums [ 3 ] ;
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
Sum + = FMath : : Abs ( Buffer [ i ] ) ;
}
}
return Sum / Num ;
}
2021-07-21 14:45:59 -04:00
}
2019-10-02 13:45:06 -04:00
void ArrayMeanFilter ( TArrayView < const float > InView , int32 WindowSize , int32 WindowOrigin , TArray < float > & OutData )
2019-08-15 13:50:15 -04:00
{
// a quick but sinful implementation of a mean filter. encourages floating point rounding errors.
check ( WindowOrigin < WindowSize ) ;
check ( WindowOrigin > = 0 ) ;
check ( WindowSize > 0 ) ;
// Initialize output data
2019-10-02 13:45:06 -04:00
const int32 Num = InView . Num ( ) ;
2019-08-15 13:50:15 -04:00
OutData . Reset ( ) ;
OutData . AddUninitialized ( Num ) ;
if ( Num < 1 )
{
return ;
}
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMeanFilter ) ;
2019-08-15 13:50:15 -04:00
// Use cumulative sum to avoid multiple summations
2019-10-02 13:45:06 -04:00
// Instead of summing over InView[StartIndex:EndIndex], avoid all that
2019-08-15 13:50:15 -04:00
// calculation by taking difference of cumulative sum at those two points:
// cumsum(X[0:b]) - cumsum(X[0:a]) = sum(X[a:b])
TArray < float > SummedData ;
2019-10-02 13:45:06 -04:00
ArrayCumulativeSum ( InView , SummedData ) ;
2019-08-15 13:50:15 -04:00
const float LastSummedData = SummedData . Last ( ) ;
float * OutDataPtr = OutData . GetData ( ) ;
const float * SummedDataPtr = SummedData . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-08-15 13:50:15 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMeanFilter ( SummedDataPtr , WindowSize , WindowOrigin , OutDataPtr , LastSummedData , Num ) ;
# endif
2019-08-15 13:50:15 -04:00
}
else
{
2022-04-04 13:09:43 -04:00
const int32 LastIndexBeforeEndBoundaryCondition = FMath : : Max ( WindowOrigin + 1 , Num - WindowSize + WindowOrigin + 1 ) ;
const int32 StartOffset = - WindowOrigin - 1 ;
const int32 EndOffset = WindowSize - WindowOrigin - 1 ;
const int32 WindowTail = WindowSize - WindowOrigin ;
if ( ( WindowSize - WindowOrigin ) < Num )
2019-08-15 13:50:15 -04:00
{
2022-04-04 13:09:43 -04:00
// Handle boundary condition where analysis window precedes beginning of array.
for ( int32 i = 0 ; i < ( WindowOrigin + 1 ) ; i + + )
{
OutDataPtr [ i ] = SummedDataPtr [ i + EndOffset ] / FMath : : Max ( 1.f , static_cast < float > ( WindowTail + i ) ) ;
}
// No boundary conditions to handle here.
const float MeanDivisor = static_cast < float > ( WindowSize ) ;
for ( int32 i = WindowOrigin + 1 ; i < LastIndexBeforeEndBoundaryCondition ; i + + )
{
OutDataPtr [ i ] = ( SummedDataPtr [ i + EndOffset ] - SummedDataPtr [ i + StartOffset ] ) / MeanDivisor ;
}
}
else
{
// Handle boundary condition where window precedes beginning and goes past end of array
const float ArrayMean = LastSummedData / static_cast < float > ( Num ) ;
for ( int32 i = 0 ; i < LastIndexBeforeEndBoundaryCondition ; i + + )
{
OutDataPtr [ i ] = ArrayMean ;
}
}
// Handle boundary condition where analysis window goes past end of array.
for ( int32 i = LastIndexBeforeEndBoundaryCondition ; i < Num ; i + + )
{
OutDataPtr [ i ] = ( LastSummedData - SummedDataPtr [ i + StartOffset ] ) / static_cast < float > ( Num - i + WindowOrigin ) ;
2019-08-15 13:50:15 -04:00
}
}
}
2019-10-02 13:45:06 -04:00
void ArrayMaxFilter ( TArrayView < const float > InView , int32 WindowSize , int32 WindowOrigin , TArray < float > & OutData )
2019-08-15 13:50:15 -04:00
{
// A reasonable implementation of a max filter for the data we're interested in, though surely not the fastest.
check ( WindowOrigin < WindowSize ) ;
check ( WindowOrigin > = 0 ) ;
check ( WindowSize > 0 ) ;
int32 StartIndex = - WindowOrigin ;
int32 EndIndex = StartIndex + WindowSize ;
// Initialize output
2019-10-02 13:45:06 -04:00
int32 Num = InView . Num ( ) ;
2019-08-15 13:50:15 -04:00
OutData . Reset ( ) ;
OutData . AddUninitialized ( Num ) ;
if ( Num < 1 )
{
return ;
}
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMaxFilter ) ;
2019-08-15 13:50:15 -04:00
// Get max in first window
int32 ActualStartIndex = 0 ;
int32 ActualEndIndex = FMath : : Min ( EndIndex , Num ) ;
2019-10-02 13:45:06 -04:00
const float * InViewPtr = InView . GetData ( ) ;
2019-08-15 13:50:15 -04:00
float * OutDataPtr = OutData . GetData ( ) ;
int32 MaxIndex = 0 ;
2019-10-02 13:45:06 -04:00
float MaxValue = InView [ 0 ] ;
2019-08-15 13:50:15 -04:00
for ( int32 i = ActualStartIndex ; i < ActualEndIndex ; i + + )
{
2019-10-02 13:45:06 -04:00
if ( InViewPtr [ i ] > MaxValue )
2019-08-15 13:50:15 -04:00
{
2019-10-02 13:45:06 -04:00
MaxValue = InViewPtr [ i ] ;
2019-08-15 13:50:15 -04:00
MaxIndex = i ;
}
}
OutDataPtr [ 0 ] = MaxValue ;
StartIndex + + ;
EndIndex + + ;
// Get max in remaining windows
for ( int32 i = 1 ; i < Num ; i + + )
{
ActualStartIndex = FMath : : Max ( StartIndex , 0 ) ;
ActualEndIndex = FMath : : Min ( EndIndex , Num ) ;
if ( MaxIndex < StartIndex )
{
// We need to evaluate the entire window because the previous maximum value was not in this window.
MaxIndex = ActualStartIndex ;
2019-10-02 13:45:06 -04:00
MaxValue = InViewPtr [ MaxIndex ] ;
2019-08-15 13:50:15 -04:00
for ( int32 j = ActualStartIndex + 1 ; j < ActualEndIndex ; j + + )
{
2019-10-02 13:45:06 -04:00
if ( InViewPtr [ j ] > MaxValue )
2019-08-15 13:50:15 -04:00
{
MaxIndex = j ;
2019-10-02 13:45:06 -04:00
MaxValue = InViewPtr [ MaxIndex ] ;
2019-08-15 13:50:15 -04:00
}
}
}
else
{
// We only need to inspect the newest sample because the previous maximum value was in this window.
2019-10-02 13:45:06 -04:00
if ( InViewPtr [ ActualEndIndex - 1 ] > MaxValue )
2019-08-15 13:50:15 -04:00
{
MaxIndex = ActualEndIndex - 1 ;
2019-10-02 13:45:06 -04:00
MaxValue = InViewPtr [ MaxIndex ] ;
2019-08-15 13:50:15 -04:00
}
}
OutDataPtr [ i ] = MaxValue ;
StartIndex + + ;
EndIndex + + ;
}
}
2019-10-02 13:45:06 -04:00
void ArrayGetEuclideanNorm ( TArrayView < const float > InView , float & OutEuclideanNorm )
2019-08-15 13:50:15 -04:00
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayGetEuclideanNorm ) ;
2019-08-15 13:50:15 -04:00
// Initialize output.
OutEuclideanNorm = 0.0f ;
2019-10-02 13:45:06 -04:00
const int32 Num = InView . Num ( ) ;
const float * InViewData = InView . GetData ( ) ;
2019-08-15 13:50:15 -04:00
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayGetEuclideanNorm ( InViewData , OutEuclideanNorm , Num ) ;
# endif
}
else
{
// Sum it up.
for ( int32 i = 0 ; i < Num ; i + + )
{
OutEuclideanNorm + = InViewData [ i ] * InViewData [ i ] ;
}
OutEuclideanNorm = FMath : : Sqrt ( OutEuclideanNorm ) ;
}
2019-08-15 13:50:15 -04:00
}
2021-09-02 20:49:36 -04:00
void ArrayAbs ( TArrayView < const float > InBuffer , TArrayView < float > OutBuffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayAbs ) ;
2021-09-02 20:49:36 -04:00
const int32 Num = InBuffer . Num ( ) ;
check ( OutBuffer . Num ( ) = = Num ) ;
const float * InData = InBuffer . GetData ( ) ;
float * OutData = OutBuffer . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2021-09-02 20:49:36 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayAbs ( InData , OutData , Num ) ;
# endif
}
else
{
2022-08-08 18:37:54 -04:00
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
2022-04-04 13:09:43 -04:00
{
2022-08-08 18:37:54 -04:00
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input = VectorLoad ( & InData [ i ] ) ;
VectorStore ( VectorAbs ( Input ) , & OutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutData [ i ] = FMath : : Abs ( InData [ i ] ) ;
}
2022-04-04 13:09:43 -04:00
}
2021-09-02 20:49:36 -04:00
}
}
2019-10-31 12:19:40 -04:00
void ArrayAbsInPlace ( TArrayView < float > InView )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayAbsInPlace ) ;
2019-10-31 12:19:40 -04:00
const int32 Num = InView . Num ( ) ;
float * Data = InView . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-10-31 12:19:40 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayAbsInPlace ( Data , Num ) ;
# endif
}
else
{
2022-08-08 18:37:54 -04:00
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
2022-04-04 13:09:43 -04:00
{
2022-08-08 18:37:54 -04:00
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input = VectorLoad ( & Data [ i ] ) ;
VectorStore ( VectorAbs ( Input ) , & Data [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
Data [ i ] = FMath : : Abs ( Data [ i ] ) ;
}
2022-04-04 13:09:43 -04:00
}
2019-10-31 12:19:40 -04:00
}
}
void ArrayClampMinInPlace ( TArrayView < float > InView , float InMin )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayClampMinInPlace ) ;
2019-10-31 12:19:40 -04:00
const int32 Num = InView . Num ( ) ;
float * Data = InView . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-10-31 12:19:40 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayClampMinInPlace ( Data , InMin , Num ) ;
# endif
}
else
{
for ( int32 i = 0 ; i < Num ; i + + )
{
Data [ i ] = FMath : : Max ( InMin , Data [ i ] ) ;
}
2019-10-31 12:19:40 -04:00
}
}
void ArrayClampMaxInPlace ( TArrayView < float > InView , float InMax )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayClampMaxInPlace ) ;
2019-10-31 12:19:40 -04:00
const int32 Num = InView . Num ( ) ;
float * Data = InView . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-10-31 12:19:40 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayClampMaxInPlace ( Data , InMax , Num ) ;
# endif
}
else
{
for ( int32 i = 0 ; i < Num ; i + + )
{
Data [ i ] = FMath : : Min ( InMax , Data [ i ] ) ;
}
2019-10-31 12:19:40 -04:00
}
}
2019-10-02 13:45:06 -04:00
void ArrayClampInPlace ( TArrayView < float > InView , float InMin , float InMax )
2019-08-15 13:50:15 -04:00
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayClampInPlace ) ;
2019-10-02 13:45:06 -04:00
const int32 Num = InView . Num ( ) ;
float * Data = InView . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-08-15 13:50:15 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayClampInPlace ( Data , InMin , InMax , Num ) ;
# endif
}
else
{
for ( int32 i = 0 ; i < Num ; i + + )
{
Data [ i ] = FMath : : Clamp ( Data [ i ] , InMin , InMax ) ;
}
2019-08-15 13:50:15 -04:00
}
}
2019-09-03 18:19:36 -04:00
2019-10-31 12:19:40 -04:00
void ArrayMinMaxNormalize ( TArrayView < const float > InView , TArray < float > & OutArray )
{
const int32 Num = InView . Num ( ) ;
OutArray . Reset ( Num ) ;
if ( Num < 1 )
{
return ;
}
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMinMaxNormalize ) ;
2019-10-31 12:19:40 -04:00
OutArray . AddUninitialized ( Num ) ;
const float * InDataPtr = InView . GetData ( ) ;
float * OutDataPtr = OutArray . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-10-31 12:19:40 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMinMaxNormalize ( InDataPtr , OutDataPtr , Num ) ;
# endif
}
else
{
float MaxValue = InDataPtr [ 0 ] ;
float MinValue = InDataPtr [ 0 ] ;
// determine min and max
for ( int32 i = 1 ; i < Num ; i + + )
{
if ( InDataPtr [ i ] < MinValue )
{
MinValue = InDataPtr [ i ] ;
}
else if ( InDataPtr [ i ] > MaxValue )
{
MaxValue = InDataPtr [ i ] ;
}
}
// Normalize data by subtracting minimum value and dividing by range
float Scale = 1.f / FMath : : Max ( SMALL_NUMBER , MaxValue - MinValue ) ;
for ( int32 i = 0 ; i < Num ; i + + )
{
OutDataPtr [ i ] = ( InDataPtr [ i ] - MinValue ) * Scale ;
}
2019-10-31 12:19:40 -04:00
}
}
2022-04-19 20:25:11 -04:00
2023-09-22 10:18:37 -04:00
void ArrayMax ( const TArrayView < const float > & InView1 , const TArrayView < const float > & InView2 , const TArrayView < float > & OutView )
{
check ( InView1 . Num ( ) = = InView2 . Num ( ) ) ;
check ( InView1 . Num ( ) = = OutView . Num ( ) ) ;
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMax ) ;
const int32 Num = InView1 . Num ( ) ;
2024-08-29 13:00:59 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2023-09-22 10:18:37 -04:00
{
2024-08-29 13:00:59 -04:00
# if INTEL_ISPC
ispc : : ArrayMax ( InView1 . GetData ( ) , InView2 . GetData ( ) , OutView . GetData ( ) , Num ) ;
# endif
2023-09-22 10:18:37 -04:00
}
2024-08-29 13:00:59 -04:00
else
2023-09-22 10:18:37 -04:00
{
2024-08-29 13:00:59 -04:00
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
2023-09-22 10:18:37 -04:00
{
2024-08-29 13:00:59 -04:00
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input1 = VectorLoad ( & InView1 [ i ] ) ;
VectorRegister4Float Input2 = VectorLoad ( & InView2 [ i ] ) ;
VectorStore ( VectorMax ( Input1 , Input2 ) , & OutView [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutView [ i ] = FMath : : Max ( InView1 [ i ] , InView2 [ i ] ) ;
}
2023-09-22 10:18:37 -04:00
}
}
}
2022-04-26 15:15:19 -04:00
float ArrayMaxAbsValue ( const TArrayView < const float > InView )
2022-04-19 20:25:11 -04:00
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMaxAbsValue ) ;
2022-04-19 20:25:11 -04:00
const int32 Num = InView . Num ( ) ;
const float * Data = InView . GetData ( ) ;
2024-08-29 13:00:59 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2022-04-19 20:25:11 -04:00
{
2024-08-29 13:00:59 -04:00
# if INTEL_ISPC
return ispc : : ArrayMaxAbsValue ( Data , Num ) ;
# endif
}
else
{
float Max = 0.f ;
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2022-04-19 20:25:11 -04:00
2024-08-29 13:00:59 -04:00
VectorRegister4Float MaxVector = VectorSetFloat1 ( 0.f ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input1 = VectorLoad ( & Data [ i ] ) ;
MaxVector = VectorMax ( MaxVector , VectorAbs ( Input1 ) ) ;
}
AlignedFloat4 OutArray ( MaxVector ) ;
Max = FMath : : Max ( FMath : : Max ( OutArray [ 0 ] , OutArray [ 1 ] ) , FMath : : Max ( OutArray [ 2 ] , OutArray [ 3 ] ) ) ;
2022-04-19 20:25:11 -04:00
}
2024-08-29 13:00:59 -04:00
if ( NumNotToSimd )
2022-04-19 20:25:11 -04:00
{
2024-08-29 13:00:59 -04:00
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
Max = FMath : : Max ( FMath : : Abs ( Data [ i ] ) , Max ) ;
}
2022-04-19 20:25:11 -04:00
}
2024-08-29 13:00:59 -04:00
return Max ;
}
2022-04-19 20:25:11 -04:00
}
2019-10-31 12:19:40 -04:00
2024-04-17 13:53:00 -04:00
void ArrayMultiply ( TArrayView < const float > InFloatBufferA , TArrayView < const float > InFloatBufferB , TArrayView < float > OutBuffer )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMultiply ) ;
checkf ( ( InFloatBufferA . Num ( ) = = InFloatBufferB . Num ( ) ) & & ( InFloatBufferA . Num ( ) = = OutBuffer . Num ( ) ) , TEXT ( " Input buffers must be equal length " ) ) ;
const int32 Num = InFloatBufferA . Num ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayMultiply ( InFloatBufferA . GetData ( ) , InFloatBufferB . GetData ( ) , OutBuffer . GetData ( ) , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input1 = VectorLoad ( & InFloatBufferA [ i ] ) ;
VectorRegister4Float Input2 = VectorLoad ( & InFloatBufferB [ i ] ) ;
VectorRegister4Float Output = VectorMultiply ( Input1 , Input2 ) ;
VectorStore ( Output , & OutBuffer [ i ] ) ;
}
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutBuffer [ i ] = InFloatBufferA [ i ] * InFloatBufferB [ i ] ;
}
}
}
2022-04-04 13:09:43 -04:00
void ArrayMultiplyInPlace ( TArrayView < const float > InFloatBuffer , TArrayView < float > BufferToMultiply )
2020-02-26 18:55:39 -05:00
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMultiplyInPlace ) ;
2022-04-04 13:09:43 -04:00
checkf ( InFloatBuffer . Num ( ) = = BufferToMultiply . Num ( ) , TEXT ( " Input buffers must be equal length " ) ) ;
2020-04-22 14:10:08 -04:00
2022-04-04 13:09:43 -04:00
const int32 Num = BufferToMultiply . Num ( ) ;
2020-02-26 18:55:39 -05:00
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-02-26 18:55:39 -05:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMultiplyInPlace ( InFloatBuffer . GetData ( ) , BufferToMultiply . GetData ( ) , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input1 = VectorLoad ( & InFloatBuffer [ i ] ) ;
VectorRegister4Float Output = VectorLoad ( & BufferToMultiply [ i ] ) ;
Output = VectorMultiply ( Input1 , Output ) ;
VectorStore ( Output , & BufferToMultiply [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
BufferToMultiply [ i ] = InFloatBuffer [ i ] * BufferToMultiply [ i ] ;
}
}
2020-02-26 18:55:39 -05:00
}
}
2020-04-22 14:10:08 -04:00
void ArrayComplexMultiplyInPlace ( TArrayView < const float > InValues1 , TArrayView < float > InValues2 )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayComplexMultiplyInPlace ) ;
2020-04-22 14:10:08 -04:00
check ( InValues1 . Num ( ) = = InValues2 . Num ( ) ) ;
const int32 Num = InValues1 . Num ( ) ;
// Needs to be in interleaved format.
check ( ( Num % 2 ) = = 0 ) ;
const float * InData1 = InValues1 . GetData ( ) ;
float * InData2 = InValues2 . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-04-22 14:10:08 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayComplexMultiplyInPlace ( InData1 , InData2 , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
const VectorRegister4Float RealSignFlip = MakeVectorRegister ( - 1.f , 1.f , - 1.f , 1.f ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData1 = VectorLoad ( & InData1 [ i ] ) ;
VectorRegister4Float VectorData2 = VectorLoad ( & InData2 [ i ] ) ;
VectorRegister4Float VectorData1Real = VectorSwizzle ( VectorData1 , 0 , 0 , 2 , 2 ) ;
VectorRegister4Float VectorData1Imag = VectorSwizzle ( VectorData1 , 1 , 1 , 3 , 3 ) ;
VectorRegister4Float VectorData2Swizzle = VectorSwizzle ( VectorData2 , 1 , 0 , 3 , 2 ) ;
VectorRegister4Float Result = VectorMultiply ( VectorData1Imag , VectorData2Swizzle ) ;
Result = VectorMultiply ( Result , RealSignFlip ) ;
Result = VectorMultiplyAdd ( VectorData1Real , VectorData2 , Result ) ;
VectorStore ( Result , & InData2 [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + = 2 )
{
float Real = ( InData1 [ i ] * InData2 [ i ] ) - ( InData1 [ i + 1 ] * InData2 [ i + 1 ] ) ;
float Imag = ( InData1 [ i ] * InData2 [ i + 1 ] ) + ( InData1 [ i + 1 ] * InData2 [ i ] ) ;
InData2 [ i ] = Real ;
InData2 [ i + 1 ] = Imag ;
}
}
2020-04-22 14:10:08 -04:00
}
}
2024-08-29 13:00:59 -04:00
void ArrayComplexMultiplyAdd ( TArrayView < const float > InValues1 , TArrayView < const float > InValues2 , TArrayView < float > OutArray )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayComplexMultiplyAdd ) ;
check ( InValues1 . Num ( ) = = InValues2 . Num ( ) ) ;
check ( OutArray . Num ( ) = = InValues1 . Num ( ) ) ;
const int32 Num = InValues1 . Num ( ) ;
const float * InAData = InValues1 . GetData ( ) ;
const float * InBData = InValues2 . GetData ( ) ;
float * OutData = OutArray . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayComplexMultiplyAdd ( InAData , InBData , OutData , Num ) ;
# endif
}
else
{
const int32 NumSimd = Num & MathIntrinsics : : SimdMask ;
// Complex numbers are stored as [real_0, complex_0, real_1, complex_1, ... real_N, complex_N]
// So we final amount must be evenly divisble by 2.
check ( NumSimd % 2 = = 0 ) ;
const VectorRegister4Float SignFlip = MakeVectorRegisterFloat ( - 1.f , 1.f , - 1.f , 1.f ) ;
for ( int32 i = 0 ; i < NumSimd ; i + = 4 )
{
// Complex multiply add
// Nr = real component of Nth number
// Ni = imaginary component of Nth number
//
//
// The input is then
// A1r A1i A2r A2i
// B1r B1i B2r B2i
// VectorA = A1r A1i A2r A2i
VectorRegister4Float VectorInA = VectorLoad ( & InAData [ i ] ) ;
// Temp12 = A1i A1r A2i A2r
VectorRegister4Float Temp1 = VectorSwizzle ( VectorInA , 1 , 0 , 3 , 2 ) ;
// VectorB = B1r B1i B2r B2i
VectorRegister4Float VectorInB = VectorLoad ( & InBData [ i ] ) ;
// Temp2 = B1r B1r B2r B2r
VectorRegister4Float Temp2 = VectorSwizzle ( VectorInB , 0 , 0 , 2 , 2 ) ;
// Temp3 = B1i B1i B2i B2i
VectorRegister4Float Temp3 = VectorSwizzle ( VectorInB , 1 , 1 , 3 , 3 ) ;
// VectorA = A1rB1r, A1iB1r, A2rB2r, A2iB2r
VectorInA = VectorMultiply ( VectorInA , Temp2 ) ;
// Temp1 = A1iB1i, A1rB1i, A2iB2i, A2rb2i
Temp1 = VectorMultiply ( Temp1 , Temp3 ) ;
// Temp1 = -A1iB1i, A1rB1i, -A2iB2i, A2rb2i
// Temp1 = A1rB1r - A1iB1i, A1iB1r + A1rB1i, A2rB2r - A2iB2i, A2iB2r + A2rB2i
Temp1 = VectorMultiplyAdd ( Temp1 , SignFlip , VectorInA ) ;
// VectorOut = O1r + A1rB1r - A1iB1i, O1i + A1iB1r + A1rB1i, O2r + A2rB2r - A2iB2i, O2i + A2iB2r + A2rB2i
VectorRegister4Float VectorOut = VectorLoad ( & OutData [ i ] ) ;
VectorOut = VectorAdd ( Temp1 , VectorOut ) ;
VectorStore ( VectorOut , & OutData [ i ] ) ;
}
for ( int32 i = NumSimd ; i < Num ; i + = 2 )
{
// Real output
OutData [ i ] + = ( InAData [ i ] * InBData [ i ] ) - ( InAData [ i + 1 ] * InBData [ i + 1 ] ) ;
// Imaginary output
OutData [ i + 1 ] + = ( InAData [ i + 1 ] * InBData [ i ] ) + ( InAData [ i ] * InBData [ i + 1 ] ) ;
}
}
}
2022-04-04 13:09:43 -04:00
void ArrayMultiplyByConstant ( TArrayView < const float > InFloatBuffer , float InValue , TArrayView < float > OutFloatBuffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMultiplyByConstant ) ;
2022-04-04 13:09:43 -04:00
check ( InFloatBuffer . Num ( ) = = OutFloatBuffer . Num ( ) ) ;
2020-04-22 14:10:08 -04:00
2022-04-04 13:09:43 -04:00
const int32 Num = InFloatBuffer . Num ( ) ;
// Get ptrs to audio buffers to avoid bounds check in non-shipping builds
const float * InBufferPtr = InFloatBuffer . GetData ( ) ;
float * OutBufferPtr = OutFloatBuffer . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-04-22 14:10:08 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMultiplyByConstant ( InBufferPtr , InValue , OutBufferPtr , Num ) ;
# endif
}
else
{
// Can only SIMD on multiple of 4 buffers, we'll do normal multiples on last bit
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2020-04-22 14:10:08 -04:00
2022-04-04 13:09:43 -04:00
if ( NumToSimd )
2020-04-22 14:10:08 -04:00
{
2022-04-04 13:09:43 -04:00
// Load the single value we want to multiply all values by into a vector register
const VectorRegister4Float MultiplyValue = VectorLoadFloat1 ( & InValue ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
// Load the next 4 samples of the input buffer into a register
VectorRegister4Float InputBufferRegister = VectorLoad ( & InBufferPtr [ i ] ) ;
2020-04-22 14:10:08 -04:00
2022-04-04 13:09:43 -04:00
// Perform the multiply
VectorRegister4Float Temp = VectorMultiply ( InputBufferRegister , MultiplyValue ) ;
2020-04-22 14:10:08 -04:00
2022-04-04 13:09:43 -04:00
// Store results into the output buffer
VectorStore ( Temp , & OutBufferPtr [ i ] ) ;
}
}
2020-04-22 14:10:08 -04:00
2022-04-04 13:09:43 -04:00
if ( NumNotToSimd )
{
// Perform remaining non-simd values left over
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutBufferPtr [ i ] = InValue * InBufferPtr [ i ] ;
}
2020-04-22 14:10:08 -04:00
}
}
2022-04-04 13:09:43 -04:00
}
2020-04-22 14:10:08 -04:00
2022-04-04 13:09:43 -04:00
void ArrayMultiplyByConstantInPlace ( TArrayView < float > InOutBuffer , float InGain )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMultiplyByConstantInPlace ) ;
2022-04-04 13:09:43 -04:00
int32 Num = InOutBuffer . Num ( ) ;
float * InOutData = InOutBuffer . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-04-22 14:10:08 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMultiplyByConstantInPlace ( InOutData , Num , InGain ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2020-04-22 14:10:08 -04:00
2022-04-04 13:09:43 -04:00
const VectorRegister4Float Gain = VectorLoadFloat1 ( & InGain ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Output = VectorLoad ( & InOutData [ i ] ) ;
Output = VectorMultiply ( Output , Gain ) ;
VectorStore ( Output , & InOutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InOutData [ i ] * = InGain ;
}
}
2020-04-22 14:10:08 -04:00
}
}
2020-02-25 18:21:12 -05:00
void ArrayAddInPlace ( TArrayView < const float > InValues , TArrayView < float > InAccumulateValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayAddInPlace ) ;
2020-02-25 18:21:12 -05:00
check ( InValues . Num ( ) = = InAccumulateValues . Num ( ) ) ;
const int32 Num = InValues . Num ( ) ;
const float * InData = InValues . GetData ( ) ;
float * InAccumulateData = InAccumulateValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-09-12 13:49:12 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayAddInPlace ( InData , InAccumulateData , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InData [ i ] ) ;
VectorRegister4Float VectorAccumData = VectorLoad ( & InAccumulateData [ i ] ) ;
VectorRegister4Float VectorOut = VectorAdd ( VectorData , VectorAccumData ) ;
VectorStore ( VectorOut , & InAccumulateData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InAccumulateData [ i ] + = InData [ i ] ;
}
}
2020-02-25 18:21:12 -05:00
}
}
2022-04-04 13:09:43 -04:00
void ArrayAddConstantInplace ( TArrayView < float > InOutBuffer , float InConstant )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayAddConstantInplace ) ;
2022-04-04 13:09:43 -04:00
int32 Num = InOutBuffer . Num ( ) ;
float * InOutData = InOutBuffer . GetData ( ) ;
2020-02-25 18:21:12 -05:00
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-02-25 18:21:12 -05:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayAddConstantInplace ( InOutData , Num , InConstant ) ;
# endif
2020-02-25 18:21:12 -05:00
}
2022-04-04 13:09:43 -04:00
else
2020-02-25 18:21:12 -05:00
{
2022-04-04 13:09:43 -04:00
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2020-02-25 18:21:12 -05:00
2022-04-04 13:09:43 -04:00
const VectorRegister4Float Constant = VectorLoadFloat1 ( & InConstant ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Output = VectorLoad ( & InOutData [ i ] ) ;
Output = VectorAdd ( Output , Constant ) ;
VectorStore ( Output , & InOutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InOutData [ i ] + = InConstant ;
}
}
2020-02-25 18:21:12 -05:00
}
}
2020-10-22 19:19:16 -04:00
void ArrayMultiplyAddInPlace ( TArrayView < const float > InValues , float InMultiplier , TArrayView < float > InAccumulateValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMultiplyAddInPlace ) ;
2020-10-22 19:19:16 -04:00
check ( InValues . Num ( ) = = InAccumulateValues . Num ( ) ) ;
const int32 Num = InValues . Num ( ) ;
const float * InData = InValues . GetData ( ) ;
float * InAccumulateData = InAccumulateValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-10-22 19:19:16 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMultiplyAddInPlace ( InData , InMultiplier , InAccumulateData , Num ) ;
# endif
}
else
{
for ( int32 i = 0 ; i < Num ; i + + )
{
InAccumulateData [ i ] + = InData [ i ] * InMultiplier ;
}
2020-10-22 19:19:16 -04:00
}
}
void ArrayLerpAddInPlace ( TArrayView < const float > InValues , float InStartMultiplier , float InEndMultiplier , TArrayView < float > InAccumulateValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayLerpAddInPlace ) ;
2020-10-22 19:19:16 -04:00
check ( InValues . Num ( ) = = InAccumulateValues . Num ( ) ) ;
const int32 Num = InValues . Num ( ) ;
const float * InData = InValues . GetData ( ) ;
float * InAccumulateData = InAccumulateValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-10-22 19:19:16 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayLerpAddInPlace ( InData , InStartMultiplier , InEndMultiplier , InAccumulateData , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const float Delta = ( InEndMultiplier - InStartMultiplier ) / FMath : : Max ( 1.f , static_cast < float > ( Num - 1 ) ) ;
const float FourByDelta = 4.f * Delta ;
VectorRegister4Float VectorDelta = MakeVectorRegister ( FourByDelta , FourByDelta , FourByDelta , FourByDelta ) ;
VectorRegister4Float VectorMultiplier = MakeVectorRegister ( InStartMultiplier , InStartMultiplier + Delta , InStartMultiplier + 2.f * Delta , InStartMultiplier + 3.f * Delta ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InData [ i ] ) ;
VectorRegister4Float VectorAccumData = VectorLoad ( & InAccumulateData [ i ] ) ;
VectorRegister4Float VectorOut = VectorMultiplyAdd ( VectorData , VectorMultiplier , VectorAccumData ) ;
VectorMultiplier = VectorAdd ( VectorMultiplier , VectorDelta ) ;
VectorStore ( VectorOut , & InAccumulateData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
float Multiplier = InStartMultiplier + NumToSimd * Delta ;
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InAccumulateData [ i ] + = InData [ i ] * Multiplier ;
Multiplier + = Delta ;
}
}
2020-10-22 19:19:16 -04:00
}
}
2022-04-04 13:09:43 -04:00
/* Subtracts two buffers together element-wise. */
void ArraySubtract ( TArrayView < const float > InMinuend , TArrayView < const float > InSubtrahend , TArrayView < float > OutBuffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySubtract ) ;
2022-04-04 13:09:43 -04:00
const int32 Num = InMinuend . Num ( ) ;
2020-10-22 19:19:16 -04:00
2022-04-04 13:09:43 -04:00
checkf ( Num = = InSubtrahend . Num ( ) & & Num = = OutBuffer . Num ( ) , TEXT ( " InMinuend, InSubtrahend, and OutBuffer must have equal Num elements (%d vs %d vs %d) " ) , Num , InSubtrahend . Num ( ) , OutBuffer . Num ( ) ) ;
2020-10-22 19:19:16 -04:00
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-10-22 19:19:16 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArraySubtract ( InMinuend . GetData ( ) , InSubtrahend . GetData ( ) , OutBuffer . GetData ( ) , Num ) ;
# endif
2020-10-22 19:19:16 -04:00
}
2022-04-04 13:09:43 -04:00
else
2020-10-22 19:19:16 -04:00
{
2022-04-04 13:09:43 -04:00
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2020-10-22 19:19:16 -04:00
2022-04-04 13:09:43 -04:00
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input1 = VectorLoad ( & InMinuend [ i ] ) ;
VectorRegister4Float Input2 = VectorLoad ( & InSubtrahend [ i ] ) ;
VectorRegister4Float Output = VectorSubtract ( Input1 , Input2 ) ;
VectorStore ( Output , & OutBuffer [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutBuffer [ i ] = InMinuend [ i ] - InSubtrahend [ i ] ;
}
}
2020-10-22 19:19:16 -04:00
}
}
2022-04-04 13:09:43 -04:00
/* Performs element-wise in-place subtraction placing the result in the subtrahend. InOutSubtrahend = InMinuend - InOutSubtrahend */
void ArraySubtractInPlace1 ( TArrayView < const float > InMinuend , TArrayView < float > InOutSubtrahend )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySubtractInPlace1 ) ;
2022-04-04 13:09:43 -04:00
checkf ( InMinuend . Num ( ) = = InOutSubtrahend . Num ( ) , TEXT ( " Input buffers must be equal length " ) ) ;
const int32 Num = InMinuend . Num ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArraySubtractInPlace1 ( InMinuend . GetData ( ) , InOutSubtrahend . GetData ( ) , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input1 = VectorLoad ( & InMinuend [ i ] ) ;
VectorRegister4Float Input2 = VectorLoad ( & InOutSubtrahend [ i ] ) ;
VectorRegister4Float Output = VectorSubtract ( Input1 , Input2 ) ;
VectorStore ( Output , & InOutSubtrahend [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
InOutSubtrahend [ i ] = InMinuend [ i ] - InOutSubtrahend [ i ] ;
}
}
}
}
/* Performs element-wise in-place subtraction placing the result in the minuend. InOutMinuend = InOutMinuend - InSubtrahend */
void ArraySubtractInPlace2 ( TArrayView < float > InOutMinuend , TArrayView < const float > InSubtrahend )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySubtractInPlace2 ) ;
2022-04-04 13:09:43 -04:00
checkf ( InOutMinuend . Num ( ) = = InSubtrahend . Num ( ) , TEXT ( " Input buffers must be equal length " ) ) ;
const int32 Num = InOutMinuend . Num ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArraySubtractInPlace2 ( InOutMinuend . GetData ( ) , InSubtrahend . GetData ( ) , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input1 = VectorLoad ( & InOutMinuend [ i ] ) ;
VectorRegister4Float Input2 = VectorLoad ( & InSubtrahend [ i ] ) ;
VectorRegister4Float Output = VectorSubtract ( Input1 , Input2 ) ;
VectorStore ( Output , & InOutMinuend [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
InOutMinuend [ i ] = InOutMinuend [ i ] - InSubtrahend [ i ] ;
}
}
}
}
2020-02-25 18:21:12 -05:00
void ArraySubtractByConstantInPlace ( TArrayView < float > InValues , float InSubtrahend )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySubtractByConstantInPlace ) ;
2020-02-25 18:21:12 -05:00
const int32 Num = InValues . Num ( ) ;
2022-04-04 13:09:43 -04:00
float * InData = InValues . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-02-25 18:21:12 -05:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArraySubtractByConstantInPlace ( InData , InSubtrahend , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const VectorRegister4Float VectorSubtrahend = VectorSetFloat1 ( InSubtrahend ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InData [ i ] ) ;
VectorData = VectorSubtract ( VectorData , VectorSubtrahend ) ;
VectorStore ( VectorData , & InData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InData [ i ] - = InSubtrahend ;
}
}
2020-02-25 18:21:12 -05:00
}
}
2021-09-02 20:49:36 -04:00
void ArraySquare ( TArrayView < const float > InValues , TArrayView < float > OutValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySquare ) ;
2021-09-02 20:49:36 -04:00
check ( InValues . Num ( ) = = OutValues . Num ( ) ) ;
2022-04-04 13:09:43 -04:00
const int32 Num = InValues . Num ( ) ;
2021-09-02 20:49:36 -04:00
const float * InData = InValues . GetData ( ) ;
float * OutData = OutValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2021-09-02 20:49:36 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArraySquare ( InData , OutData , Num ) ;
# endif
2021-09-02 20:49:36 -04:00
}
2022-04-04 13:09:43 -04:00
else
2021-09-02 20:49:36 -04:00
{
2022-04-04 13:09:43 -04:00
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InData [ i ] ) ;
VectorData = VectorMultiply ( VectorData , VectorData ) ;
VectorStore ( VectorData , & OutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
OutData [ i ] = InData [ i ] * InData [ i ] ;
}
}
2021-09-02 20:49:36 -04:00
}
}
void ArraySquareInPlace ( TArrayView < float > InValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySquareInPlace ) ;
2022-04-04 13:09:43 -04:00
const int32 Num = InValues . Num ( ) ;
2021-09-02 20:49:36 -04:00
float * InData = InValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2021-09-02 20:49:36 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArraySquareInPlace ( InData , Num ) ;
# endif
2021-09-02 20:49:36 -04:00
}
2022-04-04 13:09:43 -04:00
else
2021-09-02 20:49:36 -04:00
{
2022-04-04 13:09:43 -04:00
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InData [ i ] ) ;
VectorData = VectorMultiply ( VectorData , VectorData ) ;
VectorStore ( VectorData , & InData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InData [ i ] = InData [ i ] * InData [ i ] ;
}
}
2021-09-02 20:49:36 -04:00
}
}
2020-04-13 13:56:37 -04:00
void ArraySqrtInPlace ( TArrayView < float > InValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySqrtInPlace ) ;
2020-04-13 13:56:37 -04:00
const int32 Num = InValues . Num ( ) ;
float * InValuesData = InValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-04-13 13:56:37 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArraySqrtInPlace ( InValuesData , Num ) ;
# endif
}
else
{
for ( int32 i = 0 ; i < Num ; i + + )
{
InValues [ i ] = FMath : : Sqrt ( InValues [ i ] ) ;
}
2020-04-13 13:56:37 -04:00
}
}
2020-04-22 14:10:08 -04:00
void ArrayComplexConjugate ( TArrayView < const float > InValues , TArrayView < float > OutValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayComplexConjugate ) ;
2020-04-22 14:10:08 -04:00
check ( OutValues . Num ( ) = = InValues . Num ( ) ) ;
check ( ( InValues . Num ( ) % 2 ) = = 0 ) ;
int32 Num = InValues . Num ( ) ;
const float * InData = InValues . GetData ( ) ;
float * OutData = OutValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-04-22 14:10:08 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayComplexConjugate ( InData , OutData , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const VectorRegister4Float ConjugateMult = MakeVectorRegister ( 1.f , - 1.f , 1.f , - 1.f ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InData [ i ] ) ;
VectorData = VectorMultiply ( VectorData , ConjugateMult ) ;
VectorStore ( VectorData , & OutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + = 2 )
{
OutData [ i ] = InData [ i ] ;
OutData [ i + 1 ] = - InData [ i + 1 ] ;
}
}
2020-04-22 14:10:08 -04:00
}
}
void ArrayComplexConjugateInPlace ( TArrayView < float > InValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayComplexConjugateInPlace ) ;
2020-04-22 14:10:08 -04:00
check ( ( InValues . Num ( ) % 2 ) = = 0 ) ;
int32 Num = InValues . Num ( ) ;
float * InData = InValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-04-22 14:10:08 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayComplexConjugateInPlace ( InData , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const VectorRegister4Float ConjugateMult = MakeVectorRegister ( 1.f , - 1.f , 1.f , - 1.f ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InData [ i ] ) ;
VectorData = VectorMultiply ( VectorData , ConjugateMult ) ;
VectorStore ( VectorData , & InData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
2022-11-11 05:53:55 -05:00
for ( int32 i = NumToSimd ; i < Num ; i + + )
2022-04-04 13:09:43 -04:00
{
2022-11-11 05:53:55 -05:00
if ( ( i % 2 ) = = 1 )
{
InData [ i ] * = - 1.f ;
}
2022-04-04 13:09:43 -04:00
}
}
2020-04-22 14:10:08 -04:00
}
}
2020-02-26 18:55:39 -05:00
void ArrayMagnitudeToDecibelInPlace ( TArrayView < float > InValues , float InMinimumDb )
2019-09-12 13:49:12 -04:00
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMagnitudeToDecibelInPlace ) ;
2020-02-25 18:21:12 -05:00
const int32 Num = InValues . Num ( ) ;
float * InValuesData = InValues . GetData ( ) ;
2020-02-26 18:55:39 -05:00
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-09-12 13:49:12 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayMagnitudeToDecibelInPlace ( InValuesData , InMinimumDb , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const float Scale = 20.f / MathIntrinsics : : Loge10 ;
const float Minimum = FMath : : Exp ( InMinimumDb * MathIntrinsics : : Loge10 / 20.f ) ;
const VectorRegister4Float VectorScale = VectorSetFloat1 ( Scale ) ;
const VectorRegister4Float VectorMinimum = VectorSetFloat1 ( Minimum ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InValuesData [ i ] ) ;
VectorData = VectorMax ( VectorData , VectorMinimum ) ;
VectorData = VectorLog ( VectorData ) ;
VectorData = VectorMultiply ( VectorData , VectorScale ) ;
VectorStore ( VectorData , & InValuesData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InValuesData [ i ] = FMath : : Max ( InValuesData [ i ] , Minimum ) ;
InValuesData [ i ] = 20.f * FMath : : Loge ( InValuesData [ i ] ) / MathIntrinsics : : Loge10 ;
}
}
2019-10-02 13:45:06 -04:00
}
}
2020-02-26 18:55:39 -05:00
void ArrayPowerToDecibelInPlace ( TArrayView < float > InValues , float InMinimumDb )
2020-02-25 18:21:12 -05:00
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayPowerToDecibelInPlace ) ;
2020-02-25 18:21:12 -05:00
const int32 Num = InValues . Num ( ) ;
float * InValuesData = InValues . GetData ( ) ;
2020-02-26 18:55:39 -05:00
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-02-25 18:21:12 -05:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayPowerToDecibelInPlace ( InValuesData , InMinimumDb , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const float Scale = 10.f / MathIntrinsics : : Loge10 ;
const float Minimum = FMath : : Exp ( InMinimumDb * MathIntrinsics : : Loge10 / 10.f ) ;
const VectorRegister4Float VectorMinimum = VectorSetFloat1 ( Minimum ) ;
const VectorRegister4Float VectorScale = VectorSetFloat1 ( Scale ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorData = VectorLoad ( & InValuesData [ i ] ) ;
VectorData = VectorMax ( VectorData , VectorMinimum ) ;
VectorData = VectorLog ( VectorData ) ;
VectorData = VectorMultiply ( VectorData , VectorScale ) ;
VectorStore ( VectorData , & InValuesData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InValuesData [ i ] = FMath : : Max ( InValuesData [ i ] , Minimum ) ;
InValuesData [ i ] = 10.f * FMath : : Loge ( InValuesData [ i ] ) / MathIntrinsics : : Loge10 ;
}
}
2020-02-25 18:21:12 -05:00
}
}
void ArrayComplexToPower ( TArrayView < const float > InComplexValues , TArrayView < float > OutPowerValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayComplexToPower ) ;
2020-02-25 18:21:12 -05:00
check ( ( InComplexValues . Num ( ) % 2 ) = = 0 ) ;
check ( InComplexValues . Num ( ) = = ( OutPowerValues . Num ( ) * 2 ) ) ;
const int32 NumOut = OutPowerValues . Num ( ) ;
const float * InComplexData = InComplexValues . GetData ( ) ;
float * OutPowerData = OutPowerValues . GetData ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-02-25 18:21:12 -05:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayComplexToPowerInterleaved ( InComplexData , OutPowerData , NumOut ) ;
# endif
}
else
{
const int32 NumToSimd = NumOut & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = NumOut & MathIntrinsics : : NotSimdMask ;
2020-02-25 18:21:12 -05:00
2022-04-04 13:09:43 -04:00
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VectorComplex1 = VectorLoad ( & InComplexData [ 2 * i ] ) ;
VectorRegister4Float VectorSquared1 = VectorMultiply ( VectorComplex1 , VectorComplex1 ) ;
2020-02-25 18:21:12 -05:00
2022-04-04 13:09:43 -04:00
VectorRegister4Float VectorComplex2 = VectorLoad ( & InComplexData [ ( 2 * i ) + 4 ] ) ;
VectorRegister4Float VectorSquared2 = VectorMultiply ( VectorComplex2 , VectorComplex2 ) ;
VectorRegister4Float VectorSquareReal = VectorShuffle ( VectorSquared1 , VectorSquared2 , 0 , 2 , 0 , 2 ) ;
VectorRegister4Float VectorSquareImag = VectorShuffle ( VectorSquared1 , VectorSquared2 , 1 , 3 , 1 , 3 ) ;
VectorRegister4Float VectorOut = VectorAdd ( VectorSquareReal , VectorSquareImag ) ;
VectorStore ( VectorOut , & OutPowerData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < NumOut ; i + + )
{
int32 ComplexPos = 2 * i ;
float RealValue = InComplexData [ ComplexPos ] ;
float ImagValue = InComplexData [ ComplexPos + 1 ] ;
OutPowerData [ i ] = ( RealValue * RealValue ) + ( ImagValue * ImagValue ) ;
}
}
2020-02-25 18:21:12 -05:00
}
}
2022-04-04 13:09:43 -04:00
void ArrayComplexToPower ( TArrayView < const float > InRealSamples , TArrayView < const float > InImaginarySamples , TArrayView < float > OutPowerSamples )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayComplexToPower ) ;
2022-04-04 13:09:43 -04:00
checkf ( InRealSamples . Num ( ) = = InImaginarySamples . Num ( ) , TEXT ( " Input buffers must have equal number of elements " ) ) ;
2020-02-25 18:21:12 -05:00
2022-04-04 13:09:43 -04:00
const int32 Num = InRealSamples . Num ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2020-02-25 18:21:12 -05:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : ArrayComplexToPower ( InRealSamples . GetData ( ) , InImaginarySamples . GetData ( ) , OutPowerSamples . GetData ( ) , Num ) ;
# endif
2020-02-25 18:21:12 -05:00
}
2022-04-04 13:09:43 -04:00
else
2020-02-25 18:21:12 -05:00
{
2022-04-04 13:09:43 -04:00
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2020-02-25 18:21:12 -05:00
2022-04-04 13:09:43 -04:00
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VInReal = VectorLoad ( & InRealSamples [ i ] ) ;
VectorRegister4Float VInRealSquared = VectorMultiply ( VInReal , VInReal ) ;
VectorRegister4Float VInImag = VectorLoad ( & InImaginarySamples [ i ] ) ;
VectorRegister4Float VOut = VectorMultiplyAdd ( VInImag , VInImag , VInRealSquared ) ;
VectorStore ( VOut , & OutPowerSamples [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
const float InRealSquared = InRealSamples [ i ] * InRealSamples [ i ] ;
const float InImagSquared = InImaginarySamples [ i ] * InImaginarySamples [ i ] ;
OutPowerSamples [ i ] = InRealSquared + InImagSquared ;
}
}
2020-02-25 18:21:12 -05:00
}
}
2022-04-04 13:09:43 -04:00
/* Sets a values to zero if value is denormal. Denormal numbers significantly slow down floating point operations. */
void ArrayUnderflowClamp ( TArrayView < float > InOutValues )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayUnderflowClamp ) ;
2022-04-04 13:09:43 -04:00
int32 Num = InOutValues . Num ( ) ;
float * InOutData = InOutValues . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayUnderflowClamp ( InOutData , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const VectorRegister4Float VFMIN = MakeVectorRegister ( FLT_MIN , FLT_MIN , FLT_MIN , FLT_MIN ) ;
const VectorRegister4Float VNFMIN = MakeVectorRegister ( - FLT_MIN , - FLT_MIN , - FLT_MIN , - FLT_MIN ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VInOut = VectorLoad ( & InOutData [ i ] ) ;
// Create mask of denormal numbers.
VectorRegister4Float Mask = VectorBitwiseAnd ( VectorCompareGT ( VInOut , VNFMIN ) , VectorCompareLT ( VInOut , VFMIN ) ) ;
// Choose between zero or original number based upon mask.
VInOut = VectorSelect ( Mask , GlobalVectorConstants : : FloatZero , VInOut ) ;
VectorStore ( VInOut , & InOutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
float InOut = InOutData [ i ] ;
// Create mask of denormal numbers.
const bool Mask = ( InOut > - FLT_MIN ) & & ( InOut < FLT_MIN ) ;
// Choose between zero or original number based upon mask.
InOut = Mask ? 0.0f : InOut ;
InOutData [ i ] = InOut ;
}
}
}
}
/* Clamps values in the buffer to be between InMinValue and InMaxValue */
void ArrayRangeClamp ( TArrayView < float > InOutBuffer , float InMinValue , float InMaxValue )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayRangeClamp ) ;
2022-04-04 13:09:43 -04:00
int32 Num = InOutBuffer . Num ( ) ;
float * InOutData = InOutBuffer . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayRangeClamp ( InOutData , Num , InMinValue , InMaxValue ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const VectorRegister4Float VMinVal = MakeVectorRegister ( InMinValue , InMinValue , InMinValue , InMinValue ) ;
const VectorRegister4Float VMaxVal = MakeVectorRegister ( InMaxValue , InMaxValue , InMaxValue , InMaxValue ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VInOut = VectorLoad ( & InOutData [ i ] ) ;
// Create masks to flag elements outside of range.
VectorRegister4Float MinMask = VectorCompareLT ( VInOut , VMinVal ) ;
VectorRegister4Float MaxMask = VectorCompareGT ( VInOut , VMaxVal ) ;
// Choose between range extremes or original number based on masks.
VInOut = VectorSelect ( MinMask , VMinVal , VInOut ) ;
VInOut = VectorSelect ( MaxMask , VMaxVal , VInOut ) ;
VectorStore ( VInOut , & InOutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InOutData [ i ] = FMath : : Clamp ( InOutData [ i ] , InMinValue , InMaxValue ) ;
}
}
}
}
void ArraySetToConstantInplace ( TArrayView < float > InOutBuffer , float InConstant )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArraySetToConstantInplace ) ;
2022-04-04 13:09:43 -04:00
int32 Num = InOutBuffer . Num ( ) ;
float * InOutData = InOutBuffer . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArraySetToConstantInplace ( InOutData , Num , InConstant ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const VectorRegister4Float Constant = VectorLoadFloat1 ( & InConstant ) ;
if ( NumToSimd )
{
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorStore ( Constant , & InOutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
InOutData [ i ] = InConstant ;
}
}
}
}
/* Performs an element-wise weighted sum OutputBuffer = (InBuffer1 x InGain1) + (InBuffer2 x InGain2) */
void ArrayWeightedSum ( TArrayView < const float > InBuffer1 , float InGain1 , TArrayView < const float > InBuffer2 , float InGain2 , TArrayView < float > OutBuffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayWeightedSum ) ;
2022-04-04 13:09:43 -04:00
checkf ( InBuffer1 . Num ( ) = = InBuffer2 . Num ( ) , TEXT ( " Buffers must be equal length " ) ) ;
int32 Num = InBuffer1 . Num ( ) ;
const float * InData1 = InBuffer1 . GetData ( ) ;
const float * InData2 = InBuffer2 . GetData ( ) ;
float * OutData = OutBuffer . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayWeightedSumTwoGain ( InData1 , InGain1 , InData2 , InGain2 , OutData , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
VectorRegister4Float Gain1Vector = VectorLoadFloat1 ( & InGain1 ) ;
VectorRegister4Float Gain2Vector = VectorLoadFloat1 ( & InGain2 ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
// InBuffer1 x InGain1
VectorRegister4Float Input1 = VectorLoad ( & InData1 [ i ] ) ;
// InBuffer2 x InGain2
VectorRegister4Float Input2 = VectorLoad ( & InData2 [ i ] ) ;
VectorRegister4Float Weighted2 = VectorMultiply ( Input2 , Gain2Vector ) ;
VectorRegister4Float Output = VectorMultiplyAdd ( Input1 , Gain1Vector , Weighted2 ) ;
VectorStore ( Output , & OutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
OutData [ i ] = ( InData1 [ i ] * InGain1 ) + ( InData2 [ i ] * InGain2 ) ;
}
}
}
}
/* Performs an element-wise weighted sum OutputBuffer = (InBuffer1 x InGain1) + InBuffer2 */
void ArrayWeightedSum ( TArrayView < const float > InBuffer1 , float InGain1 , TArrayView < const float > InBuffer2 , TArrayView < float > OutBuffer )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayWeightedSum ) ;
2022-04-04 13:09:43 -04:00
checkf ( InBuffer1 . Num ( ) = = InBuffer2 . Num ( ) & & InBuffer1 . Num ( ) = = OutBuffer . Num ( ) , TEXT ( " Buffers must be equal length " ) ) ;
int32 Num = InBuffer1 . Num ( ) ;
const float * InData1 = InBuffer1 . GetData ( ) ;
const float * InData2 = InBuffer2 . GetData ( ) ;
float * OutData = OutBuffer . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayWeightedSumOneGain ( InData1 , InGain1 , InData2 , OutData , Num ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
if ( NumToSimd )
{
VectorRegister4Float Gain1Vector = VectorLoadFloat1 ( & InGain1 ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
// InBuffer1 x InGain1
VectorRegister4Float Input1 = VectorLoad ( & InData1 [ i ] ) ;
VectorRegister4Float Input2 = VectorLoad ( & InData2 [ i ] ) ;
VectorRegister4Float Output = VectorMultiplyAdd ( Input1 , Gain1Vector , Input2 ) ;
VectorStore ( Output , & OutData [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
OutData [ i ] = ( InData1 [ i ] * InGain1 ) + InData2 [ i ] ;
}
}
}
}
void ArrayFade ( TArrayView < float > InOutBuffer , const float StartValue , const float EndValue )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayFade ) ;
2022-04-04 13:09:43 -04:00
int32 Num = InOutBuffer . Num ( ) ;
float * OutFloatBuffer = InOutBuffer . GetData ( ) ;
if ( FMath : : IsNearlyEqual ( StartValue , EndValue ) )
{
// No need to do anything if start and end values are both 0.0
if ( StartValue = = 0.0f )
{
FMemory : : Memset ( OutFloatBuffer , 0 , sizeof ( float ) * Num ) ;
}
else
{
ArrayMultiplyByConstantInPlace ( InOutBuffer , StartValue ) ;
}
}
else
{
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayFade ( OutFloatBuffer , Num , StartValue , EndValue ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2022-11-11 05:53:55 -05:00
const float DeltaValue = ( ( EndValue - StartValue ) / Num ) ;
2022-04-04 13:09:43 -04:00
if ( NumToSimd )
{
2022-11-11 05:53:55 -05:00
constexpr VectorRegister4Float VectorFour = MakeVectorRegisterFloatConstant ( 4.f , 4.f , 4.f , 4.f ) ;
VectorRegister4Float Accumulator = MakeVectorRegisterFloat ( 0.f , 1.f , 2.f , 3.f ) ;
2022-04-04 13:09:43 -04:00
VectorRegister4Float Delta = VectorLoadFloat1 ( & DeltaValue ) ;
2022-11-11 05:53:55 -05:00
VectorRegister4Float Start = VectorLoadFloat1 ( & StartValue ) ;
2022-04-04 13:09:43 -04:00
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Output = VectorLoad ( & OutFloatBuffer [ i ] ) ;
2022-11-11 05:53:55 -05:00
VectorRegister4Float Gain = VectorMultiplyAdd ( Accumulator , Delta , Start ) ;
2022-04-04 13:09:43 -04:00
Output = VectorMultiply ( Output , Gain ) ;
2022-11-11 05:53:55 -05:00
Accumulator = VectorAdd ( Accumulator , VectorFour ) ;
2022-04-04 13:09:43 -04:00
VectorStore ( Output , & OutFloatBuffer [ i ] ) ;
}
}
if ( NumNotToSimd )
{
2022-11-11 05:53:55 -05:00
float Gain = ( NumToSimd * DeltaValue ) + StartValue ;
2022-04-04 13:09:43 -04:00
// Do a fade from start to end
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutFloatBuffer [ i ] = OutFloatBuffer [ i ] * Gain ;
Gain + = DeltaValue ;
}
}
}
}
}
2024-03-05 14:25:25 -05:00
void ArrayFade ( TArrayView < const float > InBuffer , const float InStartValue , const float InEndValue , TArrayView < float > OutBuffer )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayFade ) ;
const int32 Num = InBuffer . Num ( ) ;
check ( Num < = OutBuffer . Num ( ) ) ;
const float * InFloatBuffer = InBuffer . GetData ( ) ;
float * OutFloatBuffer = OutBuffer . GetData ( ) ;
// case 1: no fade
if ( FMath : : IsNearlyEqual ( InStartValue , InEndValue ) )
{
if ( InStartValue = = 0.0f )
{
// No need to do anything if start and end values are both 0.0
FMemory : : Memset ( OutFloatBuffer , 0 , sizeof ( float ) * Num ) ;
}
else
{
// no fade, just scale the output
ArrayMultiplyByConstant ( InBuffer , InStartValue , OutBuffer ) ;
}
return ;
}
// case 2: fade w/ ISPC
# if INTEL_ISPC
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
ispc : : ArrayFade2 ( InFloatBuffer , Num , InStartValue , InEndValue , OutFloatBuffer ) ;
return ;
}
# endif
// case 3: fade w/ our vectorization abstraction
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const float DeltaValue = ( ( InEndValue - InStartValue ) / Num ) ;
if ( NumToSimd )
{
constexpr VectorRegister4Float VectorFour = MakeVectorRegisterFloatConstant ( 4.f , 4.f , 4.f , 4.f ) ;
VectorRegister4Float Accumulator = MakeVectorRegisterFloat ( 0.f , 1.f , 2.f , 3.f ) ;
VectorRegister4Float Delta = VectorLoadFloat1 ( & DeltaValue ) ;
VectorRegister4Float Start = VectorLoadFloat1 ( & InStartValue ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Gain = VectorMultiplyAdd ( Accumulator , Delta , Start ) ;
VectorRegister4Float Input = VectorLoad ( & InFloatBuffer [ i ] ) ;
VectorRegister4Float Output = VectorMultiply ( Input , Gain ) ;
Accumulator = VectorAdd ( Accumulator , VectorFour ) ;
VectorStore ( Output , & OutFloatBuffer [ i ] ) ;
}
}
if ( NumNotToSimd )
{
float Gain = ( NumToSimd * DeltaValue ) + InStartValue ;
// Do a fade from start to end
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
OutFloatBuffer [ i ] = InFloatBuffer [ i ] * Gain ;
Gain + = DeltaValue ;
}
}
}
2022-04-04 13:09:43 -04:00
void ArrayMixIn ( TArrayView < const float > InFloatBuffer , TArrayView < float > BufferToSumTo , const float Gain )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMixIn ) ;
2022-04-04 13:09:43 -04:00
checkf ( InFloatBuffer . Num ( ) = = BufferToSumTo . Num ( ) , TEXT ( " Buffers must be equal size " ) ) ;
int32 Num = InFloatBuffer . Num ( ) ;
const float * InData = InFloatBuffer . GetData ( ) ;
float * InOutData = BufferToSumTo . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayMixInWithGain ( InData , InOutData , Num , Gain ) ;
# endif
}
else
{
2023-10-12 08:21:50 -04:00
VectorRegister4Float GainVector = VectorLoadFloat1 ( & Gain ) ;
int32 i = 0 ;
2023-11-01 12:25:28 -04:00
const int32 SimdNum = Num & MathIntrinsics : : Simd16Mask ;
for ( ; i < SimdNum ; i + = 16 )
2023-10-10 12:10:28 -04:00
{
2023-11-01 12:25:28 -04:00
// manually unrolling the loop produces a bit faster code
VectorRegister4x4Float Input = VectorLoad16 ( & InData [ i ] ) ;
VectorRegister4x4Float Output = VectorLoad16 ( & InOutData [ i ] ) ;
2023-10-12 08:21:50 -04:00
Output . val [ 0 ] = VectorMultiplyAdd ( Input . val [ 0 ] , GainVector , Output . val [ 0 ] ) ;
Output . val [ 1 ] = VectorMultiplyAdd ( Input . val [ 1 ] , GainVector , Output . val [ 1 ] ) ;
Output . val [ 2 ] = VectorMultiplyAdd ( Input . val [ 2 ] , GainVector , Output . val [ 2 ] ) ;
Output . val [ 3 ] = VectorMultiplyAdd ( Input . val [ 3 ] , GainVector , Output . val [ 3 ] ) ;
2023-11-01 12:25:28 -04:00
VectorStore16 ( Output , & InOutData [ i ] ) ;
2023-10-10 12:47:41 -04:00
}
2023-10-12 08:21:50 -04:00
for ( ; i < Num ; + + i )
{
InOutData [ i ] + = InData [ i ] * Gain ;
2022-04-04 13:09:43 -04:00
}
}
}
void ArrayMixIn ( TArrayView < const float > InFloatBuffer , TArrayView < float > BufferToSumTo )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMixIn ) ;
2022-04-04 13:09:43 -04:00
checkf ( InFloatBuffer . Num ( ) = = BufferToSumTo . Num ( ) , TEXT ( " Buffers must be equal size " ) ) ;
int32 Num = InFloatBuffer . Num ( ) ;
const float * InData = InFloatBuffer . GetData ( ) ;
float * InOutData = BufferToSumTo . GetData ( ) ;
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayMixIn ( InData , InOutData , Num ) ;
# endif
}
else
{
2023-10-12 08:21:50 -04:00
int32 i = 0 ;
2023-11-01 12:25:28 -04:00
const int32 SimdNum = Num & MathIntrinsics : : Simd16Mask ;
for ( ; i < SimdNum ; i + = 16 )
2022-04-04 13:09:43 -04:00
{
2023-11-01 12:25:28 -04:00
// manually unrolling the loop produces a bit faster code
VectorRegister4x4Float Input = VectorLoad16 ( & InData [ i ] ) ;
VectorRegister4x4Float Output = VectorLoad16 ( & InOutData [ i ] ) ;
2023-10-12 08:21:50 -04:00
Output . val [ 0 ] = VectorAdd ( Input . val [ 0 ] , Output . val [ 0 ] ) ;
Output . val [ 1 ] = VectorAdd ( Input . val [ 1 ] , Output . val [ 1 ] ) ;
Output . val [ 2 ] = VectorAdd ( Input . val [ 2 ] , Output . val [ 2 ] ) ;
Output . val [ 3 ] = VectorAdd ( Input . val [ 3 ] , Output . val [ 3 ] ) ;
2023-11-01 12:25:28 -04:00
VectorStore16 ( Output , & InOutData [ i ] ) ;
2022-04-04 13:09:43 -04:00
}
2023-10-12 08:21:50 -04:00
for ( ; i < Num ; + + i )
{
InOutData [ i ] + = InData [ i ] ;
2022-04-04 13:09:43 -04:00
}
}
}
void ArrayMixIn ( TArrayView < const float > InFloatBuffer , TArrayView < float > BufferToSumTo , const float StartGain , const float EndGain )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMixIn ) ;
2022-04-04 13:09:43 -04:00
checkf ( InFloatBuffer . Num ( ) = = BufferToSumTo . Num ( ) , TEXT ( " Buffers must be equal size " ) ) ;
int32 Num = InFloatBuffer . Num ( ) ;
if ( FMath : : IsNearlyEqual ( StartGain , EndGain ) )
{
// No need to do anything if start and end values are both 0.0
if ( StartGain = = 0.0f )
{
return ;
}
else
{
ArrayMixIn ( InFloatBuffer , BufferToSumTo , StartGain ) ;
}
}
else
{
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayMixInWithDelta ( InFloatBuffer . GetData ( ) , BufferToSumTo . GetData ( ) , Num , StartGain , EndGain ) ;
# endif
}
else
{
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
2022-11-11 05:53:55 -05:00
const float DeltaValue = ( ( EndGain - StartGain ) / Num ) ;
2022-04-04 13:09:43 -04:00
if ( NumToSimd )
{
2022-11-11 05:53:55 -05:00
constexpr VectorRegister4Float VectorFour = MakeVectorRegisterFloatConstant ( 4.f , 4.f , 4.f , 4.f ) ;
VectorRegister4Float Accumulator = MakeVectorRegisterFloat ( 0.f , 1.f , 2.f , 3.f ) ;
2022-04-04 13:09:43 -04:00
2022-11-11 05:53:55 -05:00
VectorRegister4Float Start = VectorLoadFloat1 ( & StartGain ) ;
2022-04-04 13:09:43 -04:00
VectorRegister4Float Delta = VectorLoadFloat1 ( & DeltaValue ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float Input = VectorLoad ( & InFloatBuffer [ i ] ) ;
VectorRegister4Float Output = VectorLoad ( & BufferToSumTo [ i ] ) ;
2022-11-11 05:53:55 -05:00
VectorRegister4Float Gain = VectorMultiplyAdd ( Accumulator , Delta , Start ) ;
2022-04-04 13:09:43 -04:00
Output = VectorMultiplyAdd ( Input , Gain , Output ) ;
2022-11-11 05:53:55 -05:00
Accumulator = VectorAdd ( Accumulator , VectorFour ) ;
2022-04-04 13:09:43 -04:00
VectorStore ( Output , & BufferToSumTo [ i ] ) ;
}
}
if ( NumNotToSimd )
{
float Gain = ( NumToSimd * DeltaValue ) + StartGain ;
for ( int32 i = NumToSimd ; i < Num ; + + i )
{
BufferToSumTo [ i ] + = InFloatBuffer [ i ] * Gain ;
Gain + = DeltaValue ;
}
}
}
}
}
2023-05-18 18:51:24 -04:00
void ArrayMixIn ( TArrayView < const int16 > InPcm16Buffer , TArrayView < float > BufferToSumTo , const float Gain )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayMixIn ) ;
checkf ( InPcm16Buffer . Num ( ) = = BufferToSumTo . Num ( ) , TEXT ( " Buffers must be equal size " ) ) ;
const int32 Num = InPcm16Buffer . Num ( ) ;
const int32 NumToSimd = Num & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = Num & MathIntrinsics : : NotSimdMask ;
const int16 * InputPtr = InPcm16Buffer . GetData ( ) ;
float * OutPtr = BufferToSumTo . GetData ( ) ;
const float ConversionValue = Gain / static_cast < float > ( TNumericLimits < int16 > : : Max ( ) ) ;
if ( NumToSimd )
{
const VectorRegister4Float ConversionVector = VectorSetFloat1 ( ConversionValue ) ;
AlignedFloat4 FloatArray ( GlobalVectorConstants : : FloatZero ) ;
for ( int32 i = 0 ; i < NumToSimd ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
FloatArray [ 0 ] = ( float ) InputPtr [ i ] ;
FloatArray [ 1 ] = ( float ) InputPtr [ i + 1 ] ;
FloatArray [ 2 ] = ( float ) InputPtr [ i + 2 ] ;
FloatArray [ 3 ] = ( float ) InputPtr [ i + 3 ] ;
const VectorRegister4Float InVector = FloatArray . ToVectorRegister ( ) ;
const VectorRegister4Float OutData = VectorLoad ( & OutPtr [ i ] ) ;
const VectorRegister4Float ScaledVector = VectorMultiplyAdd ( InVector , ConversionVector , OutData ) ;
VectorStore ( ScaledVector , & OutPtr [ i ] ) ;
}
}
if ( NumNotToSimd )
{
for ( int32 i = NumToSimd ; i < Num ; i + + )
{
OutPtr [ i ] + = ( float ) InputPtr [ i ] * ConversionValue ;
}
}
}
2022-04-19 20:25:11 -04:00
void ArrayFloatToPcm16 ( TArrayView < const float > InView , TArrayView < int16 > OutView )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayFloatToPcm16 ) ;
2023-10-12 08:21:50 -04:00
check ( OutView . Num ( ) > = InView . Num ( ) ) ;
2022-04-19 20:25:11 -04:00
const int32 Num = InView . Num ( ) ;
const float * InputPtr = InView . GetData ( ) ;
int16 * OutPtr = OutView . GetData ( ) ;
2024-08-29 13:00:59 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayFloatToPcm16 ( InputPtr , OutPtr , Num ) ;
# endif
}
else
{
constexpr float ConversionValue = static_cast < float > ( TNumericLimits < int16 > : : Max ( ) ) ;
const VectorRegister4Float Multiplier = VectorSetFloat1 ( ConversionValue ) ;
int32 i = 0 ;
2023-10-12 08:21:50 -04:00
# if PLATFORM_ENABLE_VECTORINTRINSICS_NEON
2024-08-29 13:00:59 -04:00
const int32 SimdNum = Num & MathIntrinsics : : Simd8Mask ;
for ( ; i < SimdNum ; i + = 8 )
{
const float32x4x2_t InVector = vld1q_f32_x2 ( & InputPtr [ i ] ) ;
const VectorRegister4Float ScaledVector1 = VectorMultiply ( InVector . val [ 0 ] , Multiplier ) ;
const VectorRegister4Float ScaledVector2 = VectorMultiply ( InVector . val [ 1 ] , Multiplier ) ;
const VectorRegister4Int IntVector1 = VectorFloatToInt ( ScaledVector1 ) ;
const VectorRegister4Int IntVector2 = VectorFloatToInt ( ScaledVector2 ) ;
const int16x8_t Result = vmovn_high_s32 ( vmovn_u32 ( IntVector1 ) , IntVector2 ) ;
vst1q_s16 ( & OutPtr [ i ] , Result ) ;
}
2023-10-12 08:21:50 -04:00
# else
2024-08-29 13:00:59 -04:00
const int32 SimdNum = Num & MathIntrinsics : : SimdMask ;
for ( ; i < SimdNum ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
const VectorRegister4Float InVector = VectorLoad ( & InputPtr [ i ] ) ;
const VectorRegister4Float ScaledVector = VectorMultiply ( InVector , Multiplier ) ;
const VectorRegister4Int IntVector = VectorFloatToInt ( ScaledVector ) ;
2023-10-12 08:21:50 -04:00
2024-08-29 13:00:59 -04:00
const AlignedFloat4 ScaledFloatArray ( ScaledVector ) ;
2023-10-12 08:21:50 -04:00
2024-08-29 13:00:59 -04:00
OutPtr [ i + 0 ] = ( int16 ) ScaledFloatArray [ 0 ] ;
OutPtr [ i + 1 ] = ( int16 ) ScaledFloatArray [ 1 ] ;
OutPtr [ i + 2 ] = ( int16 ) ScaledFloatArray [ 2 ] ;
OutPtr [ i + 3 ] = ( int16 ) ScaledFloatArray [ 3 ] ;
}
2023-10-12 08:21:50 -04:00
# endif //~PLATFORM_ENABLE_VECTORINTRINSICS_NEON
2024-08-29 13:00:59 -04:00
for ( ; i < Num ; i + + )
{
OutPtr [ i ] = ( int16 ) ( InputPtr [ i ] * ConversionValue ) ;
}
2022-04-19 20:25:11 -04:00
}
}
void ArrayPcm16ToFloat ( TArrayView < const int16 > InView , TArrayView < float > OutView )
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayPcm16ToFloat ) ;
2023-10-12 08:21:50 -04:00
check ( OutView . Num ( ) > = InView . Num ( ) ) ;
2022-04-19 20:25:11 -04:00
const int32 Num = InView . Num ( ) ;
const int16 * InputPtr = InView . GetData ( ) ;
float * OutPtr = OutView . GetData ( ) ;
2024-08-29 13:00:59 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayPcm16ToFloat ( InputPtr , OutPtr , Num ) ;
# endif
}
else
{
constexpr float ConversionValue = 1.f / static_cast < float > ( TNumericLimits < int16 > : : Max ( ) ) ;
const VectorRegister4Float Multiplier = VectorSetFloat1 ( ConversionValue ) ;
2022-04-19 20:25:11 -04:00
2024-08-29 13:00:59 -04:00
int32 i = 0 ;
2023-10-12 08:21:50 -04:00
# if PLATFORM_ENABLE_VECTORINTRINSICS_NEON
2024-08-29 13:00:59 -04:00
const int32 SimdNum = Num & MathIntrinsics : : Simd8Mask ;
for ( ; i < SimdNum ; i + = 8 )
{
int16x8_t Data = vld1q_s16 ( & InputPtr [ i ] ) ;
int32x4_t VecA = vmovl_s16 ( vget_low_s16 ( Data ) ) ;
int32x4_t VecB = vmovl_high_s16 ( Data ) ;
float32x4x2_t FloatVec ;
FloatVec . val [ 0 ] = VectorMultiply ( vcvtq_f32_s32 ( VecA ) , Multiplier ) ;
FloatVec . val [ 1 ] = VectorMultiply ( vcvtq_f32_s32 ( VecB ) , Multiplier ) ;
vst1q_f32_x2 ( & OutPtr [ i ] , FloatVec ) ;
}
2023-10-12 08:21:50 -04:00
# else
2024-08-29 13:00:59 -04:00
AlignedFloat4 FloatArray ( GlobalVectorConstants : : FloatZero ) ;
const int32 SimdNum = Num & MathIntrinsics : : SimdMask ;
for ( ; i < SimdNum ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
FloatArray [ 0 ] = ( float ) InputPtr [ i ] ;
FloatArray [ 1 ] = ( float ) InputPtr [ i + 1 ] ;
FloatArray [ 2 ] = ( float ) InputPtr [ i + 2 ] ;
FloatArray [ 3 ] = ( float ) InputPtr [ i + 3 ] ;
2023-10-12 08:21:50 -04:00
2024-08-29 13:00:59 -04:00
const VectorRegister4Float InVector = FloatArray . ToVectorRegister ( ) ;
const VectorRegister4Float ScaledVector = VectorMultiply ( InVector , Multiplier ) ;
2023-10-12 08:21:50 -04:00
2024-08-29 13:00:59 -04:00
VectorStore ( ScaledVector , & OutPtr [ i ] ) ;
}
2023-10-12 08:21:50 -04:00
# endif //~PLATFORM_ENABLE_VECTORINTRINSICS_NEON
2024-08-29 13:00:59 -04:00
for ( ; i < Num ; i + + )
{
OutPtr [ i ] = ( float ) InputPtr [ i ] * ConversionValue ;
}
2022-04-19 20:25:11 -04:00
}
}
2022-05-04 18:00:13 -04:00
2024-04-07 17:02:03 -04:00
constexpr int CreateByteMask ( uint32 A , uint32 B , uint32 C , uint32 D )
{
return A | ( B < < 8 ) | ( C < < 16 ) | ( D < < 24 ) ;
}
void ArrayFloatToPcm24 ( TArrayView < const float > InView , TArrayView < int8 > OutView )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayFloatToPcm24 ) ;
const int32 Num = InView . Num ( ) ;
const float * InputPtr = InView . GetData ( ) ;
int8 * OutPtr = OutView . GetData ( ) ;
int32 InIndex = 0 ;
int32 OutIndex = 0 ;
constexpr int32 SizeofPCM24 = 3 ;
constexpr float ConversionValue = static_cast < float > ( 0x7fffff ) ;
constexpr int32 SimdIndexStride = ( 4 * SizeofPCM24 ) ;
check ( ( OutView . Num ( ) / SizeofPCM24 ) > = InView . Num ( ) ) ;
const VectorRegister4Float Multiplier = VectorSetFloat1 ( ConversionValue ) ;
// In the SIMD loop below, we overwrite an extra 4 bytes of zeros. The ZeroFillMargin
// is used to ensure we don't write off the end of the output array.
const int32 ZeroFillMargin = 2 ;
const int32 SimdNum = ( Num - ZeroFillMargin ) & MathIntrinsics : : SimdMask ;
2024-04-15 20:33:39 -04:00
// 0x80 designates zero fill for the _mm_shuffle_epi8 intrinsic for SSE
// Neon uses >= number of source bytes, which is 0x10 in this case so 0x80 works for both platforms
2024-04-07 17:02:03 -04:00
constexpr uint32 ZeroFill = 0x80 ;
// Here we convert from 4 32-bit ints to 4 24-bit ints using the mask register below.
// Notice that every 4th byte is skipped. This is the uneeded high byte of the 32-bit int.
2024-08-29 13:00:59 -04:00
VectorRegister4Int Mask = MakeVectorRegisterInt (
CreateByteMask ( 0 , 1 , 2 , 4 ) ,
CreateByteMask ( 5 , 6 , 8 , 9 ) ,
CreateByteMask ( 10 , 12 , 13 , 14 ) ,
CreateByteMask ( ZeroFill , ZeroFill , ZeroFill , ZeroFill ) ) ;
2024-04-07 17:02:03 -04:00
for ( ; InIndex < SimdNum ; InIndex + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
const VectorRegister4Float InVector = VectorLoad ( & InputPtr [ InIndex ] ) ;
const VectorRegister4Float ScaledVector = VectorMultiply ( InVector , Multiplier ) ;
const VectorRegister4Int IntVector = VectorFloatToInt ( ScaledVector ) ;
const VectorRegister4Int OutVector = VectorShuffleByte4 ( IntVector , Mask ) ;
VectorIntStore ( OutVector , & OutPtr [ OutIndex ] ) ;
OutIndex + = SimdIndexStride ;
}
for ( ; InIndex < Num ; InIndex + + )
{
2024-09-11 19:55:40 -04:00
// Cast to signed integer first because casting a negative float directly to an
// unsigned int is undefined behavior. Some compilers will assign zero. Others
// will implicily cast to signed int first and then to unsigned.
// https://en.cppreference.com/w/c/language/conversion
const int32 ConvertedValue = InputPtr [ InIndex ] * ConversionValue ;
const uint32 UnsignedValue = uint32 ( ConvertedValue ) ;
2024-08-29 13:00:59 -04:00
uint8 * UnsignedOutPtr = ( uint8 * ) & OutPtr [ OutIndex ] ;
2024-09-11 19:55:40 -04:00
UnsignedOutPtr [ 0 ] = UnsignedValue & 0xFF ;
UnsignedOutPtr [ 1 ] = UnsignedValue > > 8 & 0xFF ;
UnsignedOutPtr [ 2 ] = UnsignedValue > > 16 & 0xFF ;
2024-04-07 17:02:03 -04:00
OutIndex + = SizeofPCM24 ;
}
}
void ArrayFloatToPcm32 ( TArrayView < const float > InView , TArrayView < int32 > OutView )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayFloatToPcm32 ) ;
check ( OutView . Num ( ) > = InView . Num ( ) ) ;
const int32 Num = InView . Num ( ) ;
const float * InputPtr = InView . GetData ( ) ;
int32 * OutPtr = OutView . GetData ( ) ;
int32 Index = 0 ;
// Use double precision due to the limitations of
// single precision floats (e.g. values >= 2^24 get rounded)
constexpr double ConversionValue = static_cast < double > ( TNumericLimits < int32 > : : Max ( ) ) ;
const VectorRegister4Double Multiplier = VectorSetFloat1 ( ConversionValue ) ;
const int32 SimdNum = Num & MathIntrinsics : : SimdMask ;
for ( ; Index < SimdNum ; Index + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
const VectorRegister4Float InputVectorFloat = VectorLoad ( & InputPtr [ Index ] ) ;
const VectorRegister4Double InputVector = MakeVectorRegisterDouble ( InputVectorFloat ) ;
const VectorRegister4Double ScaledVector = VectorMultiply ( InputVector , Multiplier ) ;
const VectorRegister4Int OutVector = VectorDoubleToInt ( ScaledVector ) ;
VectorIntStore ( OutVector , & OutPtr [ Index ] ) ;
}
for ( ; Index < Num ; Index + + )
{
const double Value = InputPtr [ Index ] ;
OutPtr [ Index ] = static_cast < int32 > ( Value * ConversionValue ) ;
}
}
void ArrayFloatToPcmDouble ( TArrayView < const float > InView , TArrayView < double > OutView )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayFloatToPcmDouble ) ;
check ( OutView . Num ( ) > = InView . Num ( ) ) ;
const int32 Num = InView . Num ( ) ;
const float * InputPtr = InView . GetData ( ) ;
double * OutPtr = OutView . GetData ( ) ;
int32 Index = 0 ;
const int32 SimdNum = Num & MathIntrinsics : : SimdMask ;
for ( ; Index < SimdNum ; Index + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
const VectorRegister4Float InputVectorFloat = VectorLoad ( & InputPtr [ Index ] ) ;
const VectorRegister4Double OutVector = MakeVectorRegisterDouble ( InputVectorFloat ) ;
VectorStore ( OutVector , & OutPtr [ Index ] ) ;
}
for ( ; Index < Num ; + + Index )
{
OutPtr [ Index ] = ( double ) InputPtr [ Index ] ;
}
}
2022-05-04 18:00:13 -04:00
void ArrayInterleave ( const TArray < FAlignedFloatBuffer > & InBuffers , FAlignedFloatBuffer & OutBuffer )
{
if ( InBuffers . Num ( ) = = 0 )
{
return ;
}
const int32 NumChannels = InBuffers . Num ( ) ;
const int32 NumFrames = InBuffers [ 0 ] . Num ( ) ;
OutBuffer . SetNumUninitialized ( NumChannels * NumFrames ) ;
TArray < const float * > BufferPtrArray ;
BufferPtrArray . Reset ( NumChannels ) ;
for ( const FAlignedFloatBuffer & Buffer : InBuffers )
{
const float * BufferPtr = Buffer . GetData ( ) ;
BufferPtrArray . Add ( BufferPtr ) ;
}
const float * * InBufferPtr = BufferPtrArray . GetData ( ) ;
ArrayInterleave ( InBufferPtr , OutBuffer . GetData ( ) , NumFrames , NumChannels ) ;
}
2023-10-31 18:57:52 -04:00
void ArrayInterleave ( const float * const * RESTRICT InBuffers , float * RESTRICT OutBuffer , const int32 InFrames , const int32 InChannels )
2022-05-04 18:00:13 -04:00
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayInterleave ) ;
2022-05-04 18:00:13 -04:00
for ( int32 ChannelIdx = 0 ; ChannelIdx < InChannels ; ChannelIdx + + )
{
2023-10-31 18:57:52 -04:00
const float * InPtr = InBuffers [ ChannelIdx ] ;
float * OutPtr = & OutBuffer [ ChannelIdx ] ;
2022-05-04 18:00:13 -04:00
for ( int32 SampleIdx = 0 ; SampleIdx < InFrames ; SampleIdx + + )
{
2023-10-31 18:57:52 -04:00
* OutPtr = * InPtr + + ;
OutPtr + = InChannels ;
2022-05-04 18:00:13 -04:00
}
}
}
void ArrayDeinterleave ( const FAlignedFloatBuffer & InBuffer , TArray < FAlignedFloatBuffer > & OutBuffers , const int32 InChannels )
{
check ( InChannels > 0 ) ;
const int32 NumFrames = InBuffer . Num ( ) / InChannels ;
2024-04-07 17:02:03 -04:00
ArrayDeinterleave ( TArrayView < const float > ( InBuffer . GetData ( ) , NumFrames ) , OutBuffers , InChannels ) ;
}
void ArrayDeinterleave ( const TArrayView < const float > InView , TArray < FAlignedFloatBuffer > & OutBuffers , const int32 InChannels )
{
check ( InChannels > 0 ) ;
const int32 NumFrames = InView . Num ( ) ;
2022-05-04 18:00:13 -04:00
TArray < float * > BufferPtrArray ;
BufferPtrArray . Reset ( InChannels ) ;
OutBuffers . SetNum ( InChannels ) ;
for ( FAlignedFloatBuffer & Buffer : OutBuffers )
{
Buffer . SetNumUninitialized ( NumFrames ) ;
float * BufferPtr = Buffer . GetData ( ) ;
BufferPtrArray . Add ( BufferPtr ) ;
}
float * * OutBufferPtr = BufferPtrArray . GetData ( ) ;
2024-04-07 17:02:03 -04:00
ArrayDeinterleave ( InView . GetData ( ) , OutBufferPtr , NumFrames , InChannels ) ;
2022-05-04 18:00:13 -04:00
}
2023-10-31 18:57:52 -04:00
void ArrayDeinterleave ( const float * RESTRICT InBuffer , float * const * RESTRICT OutBuffers , const int32 InFrames , const int32 InChannels )
2022-05-04 18:00:13 -04:00
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayDeinterleave ) ;
2024-08-29 13:00:59 -04:00
for ( int32 ChannelIdx = 0 ; ChannelIdx < InChannels ; ChannelIdx + + )
2022-05-04 18:00:13 -04:00
{
2023-10-31 18:57:52 -04:00
const float * InPtr = & InBuffer [ ChannelIdx ] ;
float * OutPtr = OutBuffers [ ChannelIdx ] ;
2024-08-29 13:00:59 -04:00
for ( int32 SampleIdx = 0 ; SampleIdx < InFrames ; SampleIdx + + )
2022-05-04 18:00:13 -04:00
{
2023-10-31 18:57:52 -04:00
* OutPtr + + = * InPtr ;
InPtr + = InChannels ;
2022-05-04 18:00:13 -04:00
}
}
}
2022-04-19 20:25:11 -04:00
2023-09-12 19:28:17 -04:00
void ArrayInterpolate ( const float * InBuffer , float * OutBuffer , const int32 NumInSamples , const int32 NumOutSamples )
{
if ( NumOutSamples < = 0 | | NumInSamples < = 0 )
{
return ;
}
const float SampleStride = ( float ) NumInSamples / ( float ) NumOutSamples ;
const int32 NumToSimd = NumOutSamples & MathIntrinsics : : SimdMask ;
const int32 NumNotToSimd = NumOutSamples & MathIntrinsics : : NotSimdMask ;
2023-09-22 10:18:37 -04:00
if ( NumToSimd )
2023-09-12 19:28:17 -04:00
{
VectorRegister4Float Strides = VectorSet (
4.f * SampleStride ,
4.f * SampleStride ,
4.f * SampleStride ,
4.f * SampleStride
) ;
2023-09-22 10:18:37 -04:00
2023-09-12 19:28:17 -04:00
VectorRegister4Float Indeces = VectorSet (
0.f * SampleStride ,
1.f * SampleStride ,
2.f * SampleStride ,
3.f * SampleStride
) ;
2023-09-22 10:18:37 -04:00
2023-09-12 19:28:17 -04:00
for ( int32 OutputIndex = 0 ; OutputIndex < NumToSimd ; OutputIndex + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
alignas ( 16 ) int32 LeftIndecesRaw [ 4 ] ;
alignas ( 16 ) int32 RightIndecesRaw [ 4 ] ;
2023-09-22 10:18:37 -04:00
2023-09-12 19:28:17 -04:00
VectorRegister4Float LeftIndeces = VectorFloor ( Indeces ) ;
VectorRegister4Float Fractions = VectorSubtract ( Indeces , LeftIndeces ) ;
VectorRegister4Float InvFractions = VectorSubtract ( GlobalVectorConstants : : FloatOne , Fractions ) ;
VectorRegister4Int LeftIndecesInt = VectorFloatToInt ( LeftIndeces ) ;
// Lookup samples for interpolation
VectorIntStoreAligned ( LeftIndecesInt , LeftIndecesRaw ) ;
VectorIntStoreAligned ( VectorIntAdd ( LeftIndecesInt , GlobalVectorConstants : : IntOne ) , RightIndecesRaw ) ;
VectorRegister4Float LowerSamples = VectorSet (
InBuffer [ LeftIndecesRaw [ 0 ] ] ,
InBuffer [ LeftIndecesRaw [ 1 ] ] ,
InBuffer [ LeftIndecesRaw [ 2 ] ] ,
InBuffer [ LeftIndecesRaw [ 3 ] ]
) ;
VectorRegister4Float UpperSamples = VectorSet (
InBuffer [ RightIndecesRaw [ 0 ] ] ,
InBuffer [ RightIndecesRaw [ 1 ] ] ,
InBuffer [ RightIndecesRaw [ 2 ] ] ,
InBuffer [ RightIndecesRaw [ 3 ] ]
) ;
2023-09-22 10:18:37 -04:00
2023-09-12 19:28:17 -04:00
VectorRegister4Float VOut = VectorMultiplyAdd (
LowerSamples ,
Fractions ,
VectorMultiply ( UpperSamples , InvFractions ) ) ;
VectorStore ( VOut , & OutBuffer [ OutputIndex ] ) ;
Indeces = VectorAdd ( Indeces , Strides ) ;
}
}
2023-09-22 10:18:37 -04:00
if ( NumNotToSimd )
2023-09-12 19:28:17 -04:00
{
2023-09-22 10:18:37 -04:00
float SampleIndex = ( float ) ( NumToSimd ) * SampleStride ;
2023-09-12 19:28:17 -04:00
for ( int32 OutputIndex = NumToSimd ; OutputIndex < NumOutSamples ; OutputIndex + + )
2023-09-22 10:18:37 -04:00
{
const int32 LeftSample = FMath : : FloorToInt32 ( SampleIndex ) ;
int32 RightSample = FMath : : CeilToInt32 ( SampleIndex ) ;
const float Frac = SampleIndex - LeftSample ;
OutBuffer [ OutputIndex ] = ( Frac * InBuffer [ LeftSample ] ) + ( ( 1.f - Frac ) * InBuffer [ RightSample ] ) ;
SampleIndex + = SampleStride ;
}
2023-09-12 19:28:17 -04:00
}
}
2024-04-07 17:02:03 -04:00
void ArrayInt16SwapBytes ( TArrayView < int16 > InView )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayInt16SwapBytes ) ;
const int32 Num = InView . Num ( ) ;
int16 * InputPtr = InView . GetData ( ) ;
int32 Index = 0 ;
const int32 SimdNum = Num & MathIntrinsics : : Simd8Mask ;
constexpr int32 NumInt16PerVectorRegister = sizeof ( VectorRegister4Int ) / sizeof ( int16 ) ;
const VectorRegister4Int LeftMask = VectorIntSet1 ( 0x00ff00ff ) ;
const VectorRegister4Int RightMask = VectorIntSet1 ( 0xff00ff00 ) ;
for ( ; Index < SimdNum ; Index + = NumInt16PerVectorRegister )
{
VectorRegister4Int InputVector = VectorIntLoad ( & InputPtr [ Index ] ) ;
const VectorRegister4Int LeftVector = VectorShiftLeftImm ( VectorIntAnd ( InputVector , LeftMask ) , 8 ) ;
const VectorRegister4Int RightVector = VectorShiftRightImmLogical ( VectorIntAnd ( InputVector , RightMask ) , 8 ) ;
InputVector = VectorIntOr ( LeftVector , RightVector ) ;
VectorIntStore ( InputVector , & InputPtr [ Index ] ) ;
}
for ( ; Index < Num ; Index + + )
{
InputPtr [ Index ] = BYTESWAP_ORDER16 ( InputPtr [ Index ] ) ;
}
}
void ArrayInt24SwapBytes ( TArrayView < int8 > InView )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayInt24SwapBytes ) ;
const int32 NumBytes = InView . Num ( ) ;
int8 * InputPtr = InView . GetData ( ) ;
int32 Index = 0 ;
constexpr int32 SizeofPCM24 = 3 ;
// We can fit 5 PCM24 samples into a vector register with one byte left over
constexpr int32 NumPCM24PerVectorRegister = sizeof ( VectorRegister4Int ) / SizeofPCM24 ;
constexpr int32 SimdIndexStride = ( NumPCM24PerVectorRegister * SizeofPCM24 ) ;
const int32 MaxSimdBytes = NumBytes - sizeof ( VectorRegister4Int ) ;
VectorRegister4Int Mask = MakeVectorRegisterInt (
CreateByteMask ( 2 , 1 , 0 , 5 ) ,
CreateByteMask ( 4 , 3 , 8 , 7 ) ,
CreateByteMask ( 6 , 11 , 10 , 9 ) ,
CreateByteMask ( 14 , 13 , 12 , 15 ) ) ;
for ( ; Index < MaxSimdBytes ; Index + = SimdIndexStride )
{
const VectorRegister4Int InputVector = VectorIntLoad ( & InputPtr [ Index ] ) ;
const VectorRegister4Int OutVector = VectorShuffleByte4 ( InputVector , Mask ) ;
VectorIntStore ( OutVector , & InputPtr [ Index ] ) ;
}
for ( ; Index < NumBytes ; Index + = SizeofPCM24 )
{
int8 TempValue = InputPtr [ Index ] ;
InputPtr [ Index ] = InputPtr [ Index + 2 ] ;
InputPtr [ Index + 2 ] = TempValue ;
}
}
void ArrayInt32SwapBytes ( TArrayView < int32 > InView )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayInt32SwapBytes ) ;
const int32 Num = InView . Num ( ) ;
int32 * InputPtr = InView . GetData ( ) ;
int32 Index = 0 ;
const int32 SimdNum = Num & MathIntrinsics : : SimdMask ;
constexpr int32 NumInt32PerVectorRegister = sizeof ( VectorRegister4Int ) / sizeof ( int32 ) ;
VectorRegister4Int Mask = MakeVectorRegisterInt (
CreateByteMask ( 3 , 2 , 1 , 0 ) ,
CreateByteMask ( 7 , 6 , 5 , 4 ) ,
CreateByteMask ( 11 , 10 , 9 , 8 ) ,
CreateByteMask ( 15 , 14 , 13 , 12 ) ) ;
for ( ; Index < SimdNum ; Index + = NumInt32PerVectorRegister )
{
const VectorRegister4Int InputVector = VectorIntLoad ( & InputPtr [ Index ] ) ;
// Byte shuffle is approximately 2x faster than mask and shift method in this case
const VectorRegister4Int OutVector = VectorShuffleByte4 ( InputVector , Mask ) ;
VectorIntStore ( OutVector , & InputPtr [ Index ] ) ;
}
for ( ; Index < Num ; Index + + )
{
InputPtr [ Index ] = BYTESWAP_ORDER32 ( InputPtr [ Index ] ) ;
}
}
void ArrayFloatSwapBytes ( TArrayView < float > InView )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayFloatSwapBytes ) ;
ArrayInt32SwapBytes ( TArrayView < int32 > ( ( int32 * ) InView . GetData ( ) , InView . Num ( ) ) ) ;
}
void ArrayDoubleSwapBytes ( TArrayView < double > InView )
{
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , ArrayDoubleSwapBytes ) ;
const int32 Num = InView . Num ( ) ;
double * InputPtr = InView . GetData ( ) ;
int32 Index = 0 ;
const int32 SimdNum = Num & MathIntrinsics : : SimdMask ;
constexpr int32 NumDoublePerVectorRegister = sizeof ( VectorRegister4Double ) / sizeof ( double ) ;
VectorRegister4Int Mask = MakeVectorRegisterInt (
CreateByteMask ( 7 , 6 , 5 , 4 ) ,
CreateByteMask ( 3 , 2 , 1 , 0 ) ,
CreateByteMask ( 15 , 14 , 13 , 12 ) ,
CreateByteMask ( 11 , 10 , 9 , 8 ) ) ;
for ( ; Index < SimdNum ; Index + = NumDoublePerVectorRegister )
{
const VectorRegister4Double InputVector = VectorLoad ( & InputPtr [ Index ] ) ;
const VectorRegister4Int OutVectorXY = VectorShuffleByte4 ( VectorCastDoubleToInt ( InputVector . XY ) , Mask ) ;
const VectorRegister4Int OutVectorZW = VectorShuffleByte4 ( VectorCastDoubleToInt ( InputVector . ZW ) , Mask ) ;
const VectorRegister4Double OutVector ( VectorCastIntToDouble ( OutVectorXY ) , VectorCastIntToDouble ( OutVectorZW ) ) ;
VectorStore ( OutVector , & InputPtr [ Index ] ) ;
}
for ( ; Index < Num ; Index + + )
{
InputPtr [ Index ] = BYTESWAP_ORDERD ( InputPtr [ Index ] ) ;
}
}
2024-08-29 13:00:59 -04:00
void ArrayAPFLongDelayProcess ( const float * InSamples , const float * InDelaySamples , const int32 InNum , float * OutSamples , float * OutDelaySamples , const float Gain )
{
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayAPFLongDelayProcess ( InSamples ,
InDelaySamples ,
InNum ,
OutSamples ,
OutDelaySamples ,
Gain ) ;
# endif
}
else
{
// Calculate new delay line samples. "w[n] = x[n] + gw[n - d]"
int32 NumToSIMD = InNum - ( InNum % AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER ) ;
VectorRegister4Float VG = MakeVectorRegisterFloat ( Gain , Gain , Gain , Gain ) ;
VectorRegister4Float VNG = MakeVectorRegisterFloat ( - Gain , - Gain , - Gain , - Gain ) ;
for ( int32 i = 0 ; i < InNum ; i + = AUDIO_NUM_FLOATS_PER_VECTOR_REGISTER )
{
VectorRegister4Float VInDelay = VectorLoadAligned ( & InDelaySamples [ i ] ) ;
VectorRegister4Float VInSamples = VectorLoadAligned ( & InSamples [ i ] ) ;
// w[n] = x[n] + G * w[n - D]
VectorRegister4Float VOutDelay = VectorMultiplyAdd ( VInDelay , VG , VInSamples ) ;
VectorStoreAligned ( VOutDelay , & OutDelaySamples [ i ] ) ;
// y[n] = -G * w[n] + w[n - D]
VectorRegister4Float VOut = VectorMultiplyAdd ( VOutDelay , VNG , VInDelay ) ;
VectorStoreAligned ( VOut , & OutSamples [ i ] ) ;
}
// Calculate allpass for remaining samples that we couldn't SIMD
for ( int32 i = NumToSIMD ; i < InNum ; i + + )
{
OutDelaySamples [ i ] = InDelaySamples [ i ] * Gain + InSamples [ i ] ;
OutSamples [ i ] = OutDelaySamples [ i ] * - Gain + InDelaySamples [ i ] ;
}
}
}
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 )
{
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayLerpFractionalDelay ( InSamples ,
InDelays ,
DelayData ,
IntegerDelays ,
InNum ,
OutSamples ,
MaxDelay ) ;
# endif
}
else
{
const VectorRegister4Float VMaxDelay = MakeVectorRegister ( MaxDelay , MaxDelay , MaxDelay , MaxDelay ) ;
for ( int32 i = 0 ; i < InNum ; i + = 4 )
{
VectorRegister4Float VFractionalDelays = VectorLoad ( & InDelays [ i ] ) ;
// Ensure fractional delays are positive
VFractionalDelays = VectorMax ( VFractionalDelays , GlobalVectorConstants : : FloatZero ) ;
VFractionalDelays = VectorMin ( VFractionalDelays , VMaxDelay ) ;
// Separate integer from fraction
VectorRegister4Float VFloorDelays = VectorFloor ( VFractionalDelays ) ;
// Determine linear weights
VectorRegister4Float VUpperCoefficients = VectorSubtract ( VFractionalDelays , VFloorDelays ) ;
VectorRegister4Float VLowerCoefficients = VectorSubtract ( GlobalVectorConstants : : FloatOne , VUpperCoefficients ) ;
// Make integer locations relative to block
VectorRegister4Int VIntegerDelays = VectorFloatToInt ( VFloorDelays ) ;
VectorRegister4Int VIntegerDelayOffset = VectorIntLoadAligned ( & IntegerDelays [ i ] ) ;
VIntegerDelays = VectorIntSubtract ( VIntegerDelayOffset , VIntegerDelays ) ;
// Lookup samples for interpolation
VectorIntStoreAligned ( VIntegerDelays , UpperDelayPos ) ;
VectorIntStoreAligned ( VectorIntAdd ( VIntegerDelays , GlobalVectorConstants : : IntOne ) , LowerDelayPos ) ;
VectorRegister4Float VLowerSamples = MakeVectorRegister (
DelayData [ LowerDelayPos [ 0 ] ] ,
DelayData [ LowerDelayPos [ 1 ] ] ,
DelayData [ LowerDelayPos [ 2 ] ] ,
DelayData [ LowerDelayPos [ 3 ] ]
) ;
VectorRegister4Float VUpperSamples = MakeVectorRegister (
DelayData [ UpperDelayPos [ 0 ] ] ,
DelayData [ UpperDelayPos [ 1 ] ] ,
DelayData [ UpperDelayPos [ 2 ] ] ,
DelayData [ UpperDelayPos [ 3 ] ]
) ;
// Interpolate samples
VectorRegister4Float VOut = VectorMultiplyAdd (
VLowerSamples ,
VLowerCoefficients ,
VectorMultiply ( VUpperSamples , VUpperCoefficients ) ) ;
VectorStore ( VOut , & OutSamples [ i ] ) ;
}
}
}
void ArrayScaledComplexConjugate ( const float * RESTRICT InValues , const int32 Num , float * RESTRICT OutValues , const float Scale )
{
if ( bAudio_FloatArrayMath_ISPC_Enabled )
{
# if INTEL_ISPC
ispc : : ArrayScaledComplexConjugate ( InValues ,
Num ,
OutValues ,
Scale ) ;
# endif
}
else
{
// Use mask to quickly find out number of values that can be SIMD'd
const int32 SIMD_MASK = 0xFFFFFFFC ;
const int32 NumToSimd = SIMD_MASK & Num ;
// Complex values in a vector are [real_1, imag_1, real_2, imag_2].
// By multipling this value, we flip the sign of the imaginary components, which
// is the equivalent of a complex conjugate.
const VectorRegister4Float SignFlipImag = MakeVectorRegisterFloat ( Scale , - Scale , Scale , - Scale ) ;
// Perform operation using SIMD
for ( int32 i = 0 ; i < NumToSimd ; i + = 4 )
{
VectorRegister4Float Value = VectorLoad ( & InValues [ i ] ) ;
Value = VectorMultiply ( SignFlipImag , Value ) ;
VectorStore ( Value , & OutValues [ i ] ) ;
}
// Perform operation where SIMD not possible.
for ( int32 i = NumToSimd ; i < Num ; i + = 2 )
{
OutValues [ i ] = Scale * InValues [ i ] ;
OutValues [ i + 1 ] = - Scale * InValues [ i + 1 ] ;
}
}
}
2019-09-03 18:19:36 -04:00
FContiguousSparse2DKernelTransform : : FContiguousSparse2DKernelTransform ( const int32 NumInElements , const int32 NumOutElements )
: NumIn ( NumInElements )
, NumOut ( NumOutElements )
{
check ( NumIn > = 0 ) ;
check ( NumOut > = 0 )
FRow EmptyRow ;
EmptyRow . StartIndex = 0 ;
2020-03-16 13:22:27 -04:00
// Fill up the kernel with empty rows
2019-09-03 18:19:36 -04:00
Kernel . Init ( EmptyRow , NumOut ) ;
}
2020-03-16 13:22:27 -04:00
FContiguousSparse2DKernelTransform : : ~ FContiguousSparse2DKernelTransform ( )
{
}
2019-09-03 18:19:36 -04:00
int32 FContiguousSparse2DKernelTransform : : GetNumInElements ( ) const
{
return NumIn ;
}
int32 FContiguousSparse2DKernelTransform : : GetNumOutElements ( ) const
{
return NumOut ;
}
void FContiguousSparse2DKernelTransform : : SetRow ( const int32 RowIndex , const int32 StartIndex , TArrayView < const float > OffsetValues )
{
check ( ( StartIndex + OffsetValues . Num ( ) ) < = NumIn ) ;
// Copy row data internally
Kernel [ RowIndex ] . StartIndex = StartIndex ;
Kernel [ RowIndex ] . OffsetValues = TArray < float > ( OffsetValues . GetData ( ) , OffsetValues . Num ( ) ) ;
}
2019-10-02 13:45:06 -04:00
void FContiguousSparse2DKernelTransform : : TransformArray ( TArrayView < const float > InView , TArray < float > & OutArray ) const
2019-09-03 18:19:36 -04:00
{
2019-10-02 13:45:06 -04:00
check ( InView . Num ( ) = = NumIn ) ;
2019-09-03 18:19:36 -04:00
// Resize output
OutArray . Reset ( NumOut ) ;
if ( NumOut > 0 )
{
OutArray . AddUninitialized ( NumOut ) ;
}
2019-10-02 13:45:06 -04:00
TransformArray ( InView . GetData ( ) , OutArray . GetData ( ) ) ;
2019-09-03 18:19:36 -04:00
}
2021-05-04 16:05:46 -04:00
void FContiguousSparse2DKernelTransform : : TransformArray ( TArrayView < const float > InView , FAlignedFloatBuffer & OutArray ) const
2019-09-03 18:19:36 -04:00
{
2019-10-02 13:45:06 -04:00
check ( InView . Num ( ) = = NumIn ) ;
2019-09-03 18:19:36 -04:00
// Resize output
OutArray . Reset ( NumOut ) ;
if ( NumOut > 0 )
{
OutArray . AddUninitialized ( NumOut ) ;
}
2019-10-02 13:45:06 -04:00
TransformArray ( InView . GetData ( ) , OutArray . GetData ( ) ) ;
2019-09-03 18:19:36 -04:00
}
void FContiguousSparse2DKernelTransform : : TransformArray ( const float * InArray , float * OutArray ) const
{
2022-07-20 21:52:27 -04:00
CSV_SCOPED_TIMING_STAT ( Audio_Dsp , TransformArray ) ;
2019-09-03 18:19:36 -04:00
check ( nullptr ! = InArray ) ;
check ( nullptr ! = OutArray ) ;
// Initialize output
FMemory : : Memset ( OutArray , 0 , sizeof ( float ) * NumOut ) ;
// Apply kernel one row at a time
const FRow * KernelData = Kernel . GetData ( ) ;
for ( int32 RowIndex = 0 ; RowIndex < Kernel . Num ( ) ; RowIndex + + )
{
const FRow & Row = KernelData [ RowIndex ] ;
// Get offset pointer into input array.
const float * OffsetInData = & InArray [ Row . StartIndex ] ;
// Get offset pointer of row.
const float * RowValuePtr = Row . OffsetValues . GetData ( ) ;
// dot prod 'em.
int32 NumToMult = Row . OffsetValues . Num ( ) ;
2022-04-04 13:09:43 -04:00
if ( bAudio_FloatArrayMath_ISPC_Enabled )
2019-09-03 18:19:36 -04:00
{
2022-04-04 13:09:43 -04:00
# if INTEL_ISPC
ispc : : TransformArrayRow ( OffsetInData , RowValuePtr , OutArray , RowIndex , NumToMult ) ;
# endif
}
else
{
for ( int32 i = 0 ; i < NumToMult ; i + + )
{
OutArray [ RowIndex ] + = OffsetInData [ i ] * RowValuePtr [ i ] ;
}
2019-09-03 18:19:36 -04:00
}
}
}
2019-08-15 13:50:15 -04:00
}