149 lines
3.5 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|