Files
UnrealEngine/Engine/Source/Runtime/SignalProcessing/Private/WaveShaper.cpp
2025-05-18 13:04:45 +08:00

149 lines
3.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DSP/WaveShaper.h"
#include "DSP/Dsp.h"
namespace Audio
{
FWaveShaper::FWaveShaper()
: Amount(1.0f)
, OutputGain(1.0f)
, Bias(0.f)
, Type(EWaveShaperType::ATan)
, OneOverAtanAmount(1.f / (FMath::Atan(Amount)))
, OneOverTanhAmount(1.f / Audio::FastTanh(Amount))
{
}
FWaveShaper::~FWaveShaper()
{
}
void FWaveShaper::Init(const float InSampleRate)
{
}
void FWaveShaper::SetAmount(const float InAmount)
{
Amount = FMath::Max(InAmount, 1.f);
OneOverAtanAmount = 1.f / FMath::Atan(Amount);
OneOverTanhAmount = 1.f / Audio::FastTanh(Amount);
}
void FWaveShaper::SetBias(const float InBias)
{
Bias = FMath::Clamp(InBias, -1.f, 1.f);
}
void FWaveShaper::SetOutputGainDb(const float InGainDb)
{
OutputGain = Audio::ConvertToLinear(InGainDb);
}
void FWaveShaper::SetOutputGainLinear(const float InGainLinear)
{
OutputGain = InGainLinear;
}
void FWaveShaper::SetType(const EWaveShaperType InType)
{
Type = InType;
}
void FWaveShaper::ProcessAudio(const float InSample, float& OutSample)
{
OutSample = OutputGain * FMath::Atan((InSample + Bias) * Amount) * OneOverAtanAmount;
}
void FWaveShaper::ProcessAudioBuffer(const float* InBuffer, float* OutBuffer, int32 NumFrames)
{
switch (Type)
{
case EWaveShaperType::ATan:
ProcessATan(InBuffer, OutBuffer, NumFrames);
break;
case EWaveShaperType::Cubic:
ProcessCubic(InBuffer, OutBuffer, NumFrames);
break;
case EWaveShaperType::Sin:
ProcessSin(InBuffer, OutBuffer, NumFrames);
break;
case EWaveShaperType::HardClip:
ProcessHardClip(InBuffer, OutBuffer, NumFrames);
break;
case EWaveShaperType::Tanh:
default:
ProcessTanh(InBuffer, OutBuffer, NumFrames);
break;
}
}
void FWaveShaper::ProcessHardClip(const float* InBuffer, float* OutBuffer, int32 NumSamples)
{
for (int32 Sample = 0; Sample < NumSamples; Sample++)
{
OutBuffer[Sample] = OutputGain * FMath::Clamp(Amount * (InBuffer[Sample] + Bias), -1.f, 1.f);
}
}
void FWaveShaper::ProcessATan(const float* InBuffer, float* OutBuffer, int32 NumSamples)
{
for (int32 Sample = 0; Sample < NumSamples; Sample++)
{
OutBuffer[Sample] = OutputGain * FMath::Atan((InBuffer[Sample] + Bias) * Amount) * OneOverAtanAmount;
}
}
void FWaveShaper::ProcessCubic(const float* InBuffer, float* OutBuffer, int32 NumSamples)
{
static const float CubicMax = 2.f / 3.f;
static const float OneThird = 1.f / 3.f;
float InSampleCopy = 0.f;
for (int32 Sample = 0; Sample < NumSamples; Sample++)
{
InSampleCopy = (InBuffer[Sample] + Bias) * Amount;
if (FMath::Abs(InSampleCopy) > 1.f)
{
OutBuffer[Sample] = FMath::Sign(InSampleCopy) * CubicMax;
}
else
{
OutBuffer[Sample] = InSampleCopy - (InSampleCopy * InSampleCopy * InSampleCopy * OneThird);
}
OutBuffer[Sample] *= OutputGain;
}
}
void FWaveShaper::ProcessSin(const float* InBuffer, float* OutBuffer, int32 NumSamples)
{
float InSampleCopy = 0.f;
for (int32 Sample = 0; Sample < NumSamples; Sample++)
{
InSampleCopy = (InBuffer[Sample] + Bias) * Amount;
if (FMath::Abs(InSampleCopy) > HALF_PI)
{
OutBuffer[Sample] = FMath::Sign(InSampleCopy);
}
else
{
OutBuffer[Sample] = Audio::FastSin3(InSampleCopy);
}
OutBuffer[Sample] *= OutputGain;
}
}
void FWaveShaper::ProcessTanh(const float* InBuffer, float* OutBuffer, int32 NumSamples)
{
for (int32 Sample = 0; Sample < NumSamples; Sample++)
{
OutBuffer[Sample] = OutputGain * Audio::FastTanh((InBuffer[Sample] + Bias) * Amount) * OneOverTanhAmount;
}
}
}