Files
UnrealEngineUWP/Engine/Source/Runtime/SignalProcessing/Public/DSP/LinkwitzRileyBandSplitter.h
phil popp 0171af0f69 Fix for multiband compressor crash on mac due to unaligned buffers
#rnx
#rb Miles.Flanagan
#jira UE-144203
#lockdown Nick.Whiting
#preflight 621ea171257fd6e09935365b


#ROBOMERGE-AUTHOR: phil.popp
#ROBOMERGE-SOURCE: CL 19210416 via CL 19210667 via CL 19211976 via CL 19212039 via CL 19212177
#ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v921-19075845)

[CL 19224186 by phil popp in ue5-main branch]
2022-03-02 13:13:42 -05:00

114 lines
2.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "DSP/Filter.h"
#include "DSP/VariablePoleFilter.h"
#include "DSP/BufferVectorOperations.h"
#define MAX_BUFFER_SIZE 8192 // 8 channels * 1024 samples
namespace Audio
{
struct FLinkwitzRileyBandFilter
{
TArray<FVariablePoleFilter> Filters;
FVariablePoleFilter& operator[](int32 InIndex) { return Filters[InIndex]; }
};
struct FMultibandBuffer
{
Audio::FAlignedFloatBuffer Buffer;
int32 NumBands = 0;
int32 NumSamples = 0;
FMultibandBuffer() = default;
FMultibandBuffer(int32 InBands, int32 InSamples)
: NumBands(InBands)
, NumSamples(InSamples)
{
Buffer.SetNumZeroed(InBands * InSamples);
}
void Init(int32 InBands, int32 InSamples)
{
NumBands = InBands;
NumSamples = InSamples;
Buffer.SetNumZeroed(InBands * InSamples);
}
void SetBands(int32 InBands)
{
NumBands = InBands;
Reset();
}
void SetSamples(int32 InSamples)
{
NumSamples = InSamples;
Reset();
}
// Zero buffers
void Reset()
{
Buffer.Reset(NumSamples * NumBands);
Buffer.AddZeroed(NumSamples * NumBands);
}
float* operator[](int32 BandIndex) { return &Buffer[BandIndex * NumSamples]; }
};
/*
* Helper for Multi-Band processing to generate Linwitz-Riley filtered outputs from input
* https://en.wikipedia.org/wiki/Linkwitz%E2%80%93Riley_filter
*/
class SIGNALPROCESSING_API FLinkwitzRileyBandSplitter
{
public:
struct FCrossoverBandwidthPair
{
float Frequency = 0.f;
float Bandwidth = 0.f;
};
FLinkwitzRileyBandSplitter() {};
// initalize filters
void Init(const int32 InChannels,
const float InSampleRate,
const EFilterOrder FilterOrder,
const bool bInPhaseCompensate,
const TArray<float>& InCrossovers); // Always InBands - 1 Crossovers
void ProcessAudioFrame(const float* InBuffer, FMultibandBuffer& OutBuffer);
void ProcessAudioBuffer(const float* InBuffer, FMultibandBuffer& OutBuffer, const int32 NumFrames);
void SetCrossovers(const TArray<float>& InCrossoverFrequencies);
private:
EFilterOrder FilterOrder = EFilterOrder::FourPole;
int32 NumBands = 1;
int32 NumChannels = 2;
float SampleRate = 48000.f;
TArray<float> SharedBuffer;
TArray<float> BandWorkBuffer;
FAlignedFloatBuffer SharedAlignedBuffer;
FAlignedFloatBuffer BandAlignedBuffer;
TArray<FLinkwitzRileyBandFilter> BandFilters;
TArray<FCrossoverBandwidthPair> Crossovers;
void CopyToBuffer(float* Destination, const float* Origin, const int32 NumSamples);
void InvertBuffer(float* Buffer, const int32 NumSamples);
float GetQ(EFilterOrder InFilterOrder);
};
}