Files
UnrealEngine/Engine/Plugins/Runtime/Metasound/Source/MetasoundStandardNodes/Private/MetasoundWaveShaperNode.cpp
2025-05-18 13:04:45 +08:00

196 lines
7.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DSP/WaveShaper.h"
#include "Internationalization/Text.h"
#include "MetasoundEnumRegistrationMacro.h"
#include "MetasoundExecutableOperator.h"
#include "MetasoundNodeRegistrationMacro.h"
#include "MetasoundDataTypeRegistrationMacro.h"
#include "MetasoundParamHelper.h"
#include "MetasoundPrimitives.h"
#include "MetasoundStandardNodesCategories.h"
#include "MetasoundStandardNodesNames.h"
#include "MetasoundAudioBuffer.h"
#define LOCTEXT_NAMESPACE "MetasoundStandardNodes_WaveShaperNode"
namespace Metasound
{
namespace WaveShaperNode
{
METASOUND_PARAM(InAudioInput, "In", "Audio input.");
METASOUND_PARAM(InWaveShapeAmount, "Amount", "The amount of wave shaping to apply.");
METASOUND_PARAM(InWaveShapeBias, "Bias", "DC offset to apply before wave shaping.");
METASOUND_PARAM(InOutputGain, "OutputGain", "The amount of gain to apply after processing.");
METASOUND_PARAM(InType, "Type", "Algorithm to use to process the audio.");
METASOUND_PARAM(OutAudio, "Out", "Audio output.");
}
using namespace WaveShaperNode;
DECLARE_METASOUND_ENUM(Audio::EWaveShaperType, Audio::EWaveShaperType::ATan, METASOUNDSTANDARDNODES_API, FEnumEWaveShaperType, FEnumWaveShaperTypeInfo, FEnumWaveShaperReadRef, FEnumWaveShaperWriteRef);
DEFINE_METASOUND_ENUM_BEGIN(Audio::EWaveShaperType, FEnumEWaveShaperType, "WaveShaperType")
DEFINE_METASOUND_ENUM_ENTRY(Audio::EWaveShaperType::Sin, "SinDescription", "Sine", "SinTT", "Sine WaveShaper"),
DEFINE_METASOUND_ENUM_ENTRY(Audio::EWaveShaperType::ATan, "ATanDescription", "Inverse Tangent", "ATanTT", "Inverse Tangent WaveShaper"),
DEFINE_METASOUND_ENUM_ENTRY(Audio::EWaveShaperType::Tanh, "TanHDescription", "Hyperbolic Tangent", "TanHTT", "Hyperbolic Tangent WaveShaper"),
DEFINE_METASOUND_ENUM_ENTRY(Audio::EWaveShaperType::Cubic, "CubicDescription", "Cubic Polynomial", "CubicTT", "Cubic Polynomial WaveShaper"),
DEFINE_METASOUND_ENUM_ENTRY(Audio::EWaveShaperType::HardClip, "HarClipDescription", "Hard Clip", "HardClipTT", "Hard Clipper")
DEFINE_METASOUND_ENUM_END()
class FWaveShaperOperator : public TExecutableOperator<FWaveShaperOperator>
{
public:
static const FNodeClassMetadata& GetNodeInfo();
static const FVertexInterface& GetVertexInterface();
static TUniquePtr<IOperator> CreateOperator(const FBuildOperatorParams& InParams, FBuildResults& OutResults);
FWaveShaperOperator(const FOperatorSettings& InSettings,
const FAudioBufferReadRef& InAudioInput,
const FFloatReadRef& InWaveShapeAmount,
const FFloatReadRef& InBias,
const FFloatReadRef& InOutputGain,
const FEnumWaveShaperReadRef& InType);
virtual void BindInputs(FInputVertexInterfaceData& InOutVertexData) override;
virtual void BindOutputs(FOutputVertexInterfaceData& InOutVertexData) override;
void Execute();
void Reset(const IOperator::FResetParams& InParams);
private:
// The input audio buffer
FAudioBufferReadRef AudioInput;
// The amount that the wave is shaped
FFloatReadRef Amount;
// DC offset to apply before gain
FFloatReadRef Bias;
// The amount of gain
FFloatReadRef OutputGain;
// What algorithm to use
FEnumWaveShaperReadRef Type;
// The audio output
FAudioBufferWriteRef AudioOutput;
// The internal WaveShaper
Audio::FWaveShaper WaveShaper;
};
FWaveShaperOperator::FWaveShaperOperator(const FOperatorSettings& InSettings,
const FAudioBufferReadRef& InAudioInput,
const FFloatReadRef& InAmount,
const FFloatReadRef& InBias,
const FFloatReadRef& InOutputGain,
const FEnumWaveShaperReadRef& InType)
: AudioInput(InAudioInput)
, Amount(InAmount)
, Bias(InBias)
, OutputGain(InOutputGain)
, Type(InType)
, AudioOutput(FAudioBufferWriteRef::CreateNew(InSettings))
{
WaveShaper.Init(InSettings.GetSampleRate());
}
void FWaveShaperOperator::BindInputs(FInputVertexInterfaceData& InOutVertexData)
{
InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InAudioInput), AudioInput);
InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InWaveShapeAmount), Amount);
InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InWaveShapeBias), Bias);
InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InOutputGain), OutputGain);
InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InType), Type);
}
void FWaveShaperOperator::BindOutputs(FOutputVertexInterfaceData& InOutVertexData)
{
InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(OutAudio), AudioOutput);
}
void FWaveShaperOperator::Execute()
{
const float* InputAudio = AudioInput->GetData();
float* OutputAudio = AudioOutput->GetData();
int32 NumFrames = AudioInput->Num();
WaveShaper.SetAmount(*Amount);
WaveShaper.SetBias(*Bias);
WaveShaper.SetOutputGainLinear(*OutputGain);
WaveShaper.SetType(*Type);
WaveShaper.ProcessAudioBuffer(InputAudio, OutputAudio, NumFrames);
}
void FWaveShaperOperator::Reset(const IOperator::FResetParams& InParams)
{
AudioOutput->Zero();
WaveShaper.Init(InParams.OperatorSettings.GetSampleRate());
}
const FVertexInterface& FWaveShaperOperator::GetVertexInterface()
{
static const FVertexInterface Interface(
FInputVertexInterface(
TInputDataVertex<FAudioBuffer>(METASOUND_GET_PARAM_NAME_AND_METADATA(InAudioInput)),
TInputDataVertex<float>(METASOUND_GET_PARAM_NAME_AND_METADATA(InWaveShapeAmount), 1.0f),
TInputDataVertex<float>(METASOUND_GET_PARAM_NAME_AND_METADATA(InWaveShapeBias), 0.0f),
TInputDataVertex<float>(METASOUND_GET_PARAM_NAME_AND_METADATA(InOutputGain), 1.0f),
TInputDataVertex<FEnumEWaveShaperType>(METASOUND_GET_PARAM_NAME_AND_METADATA(InType), (int32)Audio::EWaveShaperType::Sin)
),
FOutputVertexInterface(
TOutputDataVertex<FAudioBuffer>(METASOUND_GET_PARAM_NAME_AND_METADATA(OutAudio))
)
);
return Interface;
}
const FNodeClassMetadata& FWaveShaperOperator::GetNodeInfo()
{
auto InitNodeInfo = []() -> FNodeClassMetadata
{
FNodeClassMetadata Info;
Info.ClassName = { StandardNodes::Namespace, TEXT("WaveShaper"), StandardNodes::AudioVariant };
Info.MajorVersion = 1;
Info.MinorVersion = 0;
Info.DisplayName = METASOUND_LOCTEXT("Metasound_WaveShaperDisplayName", "WaveShaper");
Info.Description = METASOUND_LOCTEXT("Metasound_WaveShaperNodeDescription", "Applies non-linear shaping to the audio input.");
Info.Author = PluginAuthor;
Info.CategoryHierarchy = { NodeCategories::Filters };
Info.PromptIfMissing = PluginNodeMissingPrompt;
Info.DefaultInterface = GetVertexInterface();
return Info;
};
static const FNodeClassMetadata Info = InitNodeInfo();
return Info;
}
TUniquePtr<IOperator> FWaveShaperOperator::CreateOperator(const FBuildOperatorParams& InParams, FBuildResults& OutResults)
{
const FInputVertexInterfaceData& InputData = InParams.InputData;
FAudioBufferReadRef AudioIn = InputData.GetOrCreateDefaultDataReadReference<FAudioBuffer>(METASOUND_GET_PARAM_NAME(InAudioInput), InParams.OperatorSettings);
FFloatReadRef InAmount = InputData.GetOrCreateDefaultDataReadReference<float>(METASOUND_GET_PARAM_NAME(InWaveShapeAmount), InParams.OperatorSettings);
FFloatReadRef InBias = InputData.GetOrCreateDefaultDataReadReference<float>(METASOUND_GET_PARAM_NAME(InWaveShapeBias), InParams.OperatorSettings);
FFloatReadRef OutGain = InputData.GetOrCreateDefaultDataReadReference<float>(METASOUND_GET_PARAM_NAME(InOutputGain), InParams.OperatorSettings);
FEnumWaveShaperReadRef InType = InputData.GetOrCreateDefaultDataReadReference<FEnumEWaveShaperType>(METASOUND_GET_PARAM_NAME(InType), InParams.OperatorSettings);
return MakeUnique<FWaveShaperOperator>(InParams.OperatorSettings, AudioIn, InAmount, InBias, OutGain, InType);
}
using FWaveShaperNode = TNodeFacade<FWaveShaperOperator>;
METASOUND_REGISTER_NODE(FWaveShaperNode)
}
#undef LOCTEXT_NAMESPACE