Files
UnrealEngineUWP/Engine/Plugins/Runtime/Metasound/Source/MetasoundStandardNodes/Private/MetasoundTriggerOnThresholdNode.cpp
helen yang bb284960b2 Compile out FText from MetaSound Nodes in non editor builds
#rb rob.gay
#preflight 62057365a155a4cddac5bf1d
#jira UE-142194

#ROBOMERGE-AUTHOR: helen.yang
#ROBOMERGE-SOURCE: CL 18945030 in //UE5/Release-5.0/... via CL 18945230 via CL 18946167
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v917-18934589)

[CL 18946312 by helen yang in ue5-main branch]
2022-02-10 18:36:47 -05:00

260 lines
9.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MetasoundTriggerOnThresholdNode.h"
#include "MetasoundAudioBuffer.h"
#include "MetasoundEnumRegistrationMacro.h"
#include "MetasoundExecutableOperator.h"
#include "MetasoundFacade.h"
#include "MetasoundNodeRegistrationMacro.h"
#include "MetasoundDataTypeRegistrationMacro.h"
#include "MetasoundOperatorSettings.h"
#include "MetasoundPrimitives.h"
#include "MetasoundStandardNodesNames.h"
#include "MetasoundTrigger.h"
#include "MetasoundVertex.h"
#include "MetasoundStandardNodesCategories.h"
#define LOCTEXT_NAMESPACE "MetasoundStandardNodes_ThresholdNode"
namespace Metasound
{
enum class EBufferTriggerType
{
RisingEdge,
FallingEdge,
AbsThreshold,
};
DECLARE_METASOUND_ENUM(EBufferTriggerType, EBufferTriggerType::RisingEdge, METASOUNDSTANDARDNODES_API,
FEnumBufferTriggerType, FEnumBufferTriggerTypeInfo, FBufferTriggerTypeReadRef, FEnumBufferTriggerTypeWriteRef);
DEFINE_METASOUND_ENUM_BEGIN(EBufferTriggerType, FEnumBufferTriggerType, "BufferTriggerType")
DEFINE_METASOUND_ENUM_ENTRY(EBufferTriggerType::RisingEdge, "RisingEdgeDescription", "Rising Edge", "RisingEdgeDescriptionTT", ""),
DEFINE_METASOUND_ENUM_ENTRY(EBufferTriggerType::FallingEdge, "FallingEdgeDescription", "Falling Edge", "FallingEdgeDescriptionTT", ""),
DEFINE_METASOUND_ENUM_ENTRY(EBufferTriggerType::AbsThreshold, "AbsThresholdDescription", "Abs Threshold", "AbsThresholdDescriptionTT", "")
DEFINE_METASOUND_ENUM_END()
class FTriggerOnThresholdOperator : public IOperator
{
public:
static constexpr float DefaultThreshold = 0.85f;
static TUniquePtr<IOperator> CreateOperator(const FCreateOperatorParams& InParams, FBuildErrorArray& OutErrors);
static const FNodeClassMetadata& GetNodeInfo();
static FVertexInterface DeclareVertexInterface();
FTriggerOnThresholdOperator(const FOperatorSettings& InSettings, FAudioBufferReadRef InBuffer, FFloatReadRef InThreshold);
virtual FDataReferenceCollection GetInputs() const override;
virtual FDataReferenceCollection GetOutputs() const override;
protected:
FAudioBufferReadRef In;
FFloatReadRef Threshold;
FTriggerWriteRef Out;
bool bTriggered = false;
float LastSample = 0.f;
static constexpr const TCHAR* OutPinName = TEXT("Out");
static constexpr const TCHAR* InPinName = TEXT("In");
static constexpr const TCHAR* ThresholdPinName = TEXT("Threshold");
static constexpr const TCHAR* TriggerType = TEXT("Type");
};
// Mac Clang requires linkage on constexpr
constexpr float FTriggerOnThresholdOperator::DefaultThreshold;
struct FTriggerOnThresholdOperator_EdgeCommon : public FTriggerOnThresholdOperator
{
using FTriggerOnThresholdOperator::FTriggerOnThresholdOperator;
template<typename PREDICATE>
void Generate(const PREDICATE& ValueTester)
{
Out->AdvanceBlock();
const float* InputBuffer = In->GetData();
const int32 NumFrames = In->Num();
const float ThreshValue = *Threshold;
float Previous = LastSample;
for (int32 i = 0; i < NumFrames; ++i)
{
const float Current = *InputBuffer;
// If Previous didn't trigger but current value does... fire!
if (!ValueTester(Previous, ThreshValue) && ValueTester(Current,ThreshValue))
{
Out->TriggerFrame(i);
}
Previous = Current;
++InputBuffer;
}
// Remember the last sample for next frame.
LastSample = Previous;
}
};
struct FTriggerOnThresholdOperator_RisingEdge final : public FTriggerOnThresholdOperator_EdgeCommon
{
using FTriggerOnThresholdOperator_EdgeCommon::FTriggerOnThresholdOperator_EdgeCommon;
void Execute()
{
Generate(TGreater<float>{});
}
static void ExecuteFunction(IOperator* InOperator) { static_cast<FTriggerOnThresholdOperator_RisingEdge*>(InOperator)->Execute(); }
FExecuteFunction GetExecuteFunction() override { return &FTriggerOnThresholdOperator_RisingEdge::ExecuteFunction; }
};
struct FTriggerOnThresholdOperator_FallingEdge final : public FTriggerOnThresholdOperator_EdgeCommon
{
using FTriggerOnThresholdOperator_EdgeCommon::FTriggerOnThresholdOperator_EdgeCommon;
static void ExecuteFunction(IOperator* InOperator) { static_cast<FTriggerOnThresholdOperator_FallingEdge*>(InOperator)->Execute(); }
FExecuteFunction GetExecuteFunction() override { return &FTriggerOnThresholdOperator_FallingEdge::ExecuteFunction; }
void Execute()
{
Generate(TLess<float>{});
}
};
struct FTriggerOnThresholdOperator_AbsThreshold final : public FTriggerOnThresholdOperator
{
using FTriggerOnThresholdOperator::FTriggerOnThresholdOperator;
static void ExecuteFunction(IOperator* InOperator) { static_cast<FTriggerOnThresholdOperator_AbsThreshold*>(InOperator)->Execute(); }
FExecuteFunction GetExecuteFunction() override { return &FTriggerOnThresholdOperator_AbsThreshold::ExecuteFunction; }
void Execute()
{
Out->AdvanceBlock();
const float* InputBuffer = In->GetData();
const int32 NumFrames = In->Num();
const float ThresholdSqr = *Threshold * *Threshold;
for (int32 i = 0; i < NumFrames; ++i)
{
const float Current = *InputBuffer;
const float CurrentSqr = Current * Current;
if (CurrentSqr > ThresholdSqr && !bTriggered)
{
bTriggered = true;
Out->TriggerFrame(i);
}
else if (CurrentSqr < ThresholdSqr && bTriggered)
{
bTriggered = false;
}
++InputBuffer;
}
}
};
FTriggerOnThresholdOperator::FTriggerOnThresholdOperator(const FOperatorSettings& InSettings, FAudioBufferReadRef InBuffer, FFloatReadRef InThreshold)
: In(InBuffer)
, Threshold(InThreshold)
, Out(FTriggerWriteRef::CreateNew(InSettings))
{}
FDataReferenceCollection FTriggerOnThresholdOperator::GetInputs() const
{
FDataReferenceCollection InputDataReferences;
InputDataReferences.AddDataReadReference(ThresholdPinName, FFloatReadRef(Threshold));
InputDataReferences.AddDataReadReference(InPinName, FAudioBufferReadRef(In));
return InputDataReferences;
}
FDataReferenceCollection FTriggerOnThresholdOperator::GetOutputs() const
{
FDataReferenceCollection OutputDataReferences;
OutputDataReferences.AddDataReadReference(OutPinName, FTriggerWriteRef(Out));
return OutputDataReferences;
}
FVertexInterface FTriggerOnThresholdOperator::DeclareVertexInterface()
{
static const FVertexInterface Interface(
FInputVertexInterface(
TInputDataVertexModel<FAudioBuffer>(InPinName, METASOUND_LOCTEXT("BufferInDescription", "Input")),
TInputDataVertexModel<float>(ThresholdPinName, METASOUND_LOCTEXT("ThresholdDescription", "Trigger Threshold"), DefaultThreshold),
TInputDataVertexModel<FEnumBufferTriggerType>(TriggerType, METASOUND_LOCTEXT("ThresholdDescription", "Trigger Threshold"))
),
FOutputVertexInterface(
TOutputDataVertexModel<FTrigger>(OutPinName, METASOUND_LOCTEXT("TriggerOutDescription", "Output"))
)
);
return Interface;
}
const FNodeClassMetadata& FTriggerOnThresholdOperator::GetNodeInfo()
{
auto InitNodeInfo = []() -> FNodeClassMetadata
{
FNodeClassMetadata Info;
Info.ClassName = {StandardNodes::Namespace, TEXT("TriggerOnThreshold"), StandardNodes::AudioVariant};
Info.MajorVersion = 1;
Info.MinorVersion = 0;
Info.DisplayName = METASOUND_LOCTEXT("Metasound_TriggerOnThresholdNodeDisplayName", "Trigger On Threshold");
Info.Description = METASOUND_LOCTEXT("Metasound_TriggerOnThresholdNodeDescription", "Trigger based on a audio buffer input");
Info.Author = PluginAuthor;
Info.PromptIfMissing = PluginNodeMissingPrompt;
Info.DefaultInterface = DeclareVertexInterface();
Info.CategoryHierarchy.Emplace(NodeCategories::Trigger);
return Info;
};
static const FNodeClassMetadata Info = InitNodeInfo();
return Info;
}
FTriggerOnThresholdNode::FTriggerOnThresholdNode(const FNodeInitData& InInitData)
: FTriggerOnThresholdNode(InInitData.InstanceName, InInitData.InstanceID, FTriggerOnThresholdOperator::DefaultThreshold)
{
}
FTriggerOnThresholdNode::FTriggerOnThresholdNode(const FVertexName& InName, const FGuid& InInstanceID, float InDefaultThreshold)
: FNodeFacade(InName, InInstanceID, TFacadeOperatorClass<FTriggerOnThresholdOperator>())
, DefaultThreshold(InDefaultThreshold)
{
}
TUniquePtr<IOperator> FTriggerOnThresholdOperator::CreateOperator(const FCreateOperatorParams& InParams, FBuildErrorArray& OutErrors)
{
const FTriggerOnThresholdNode& Node = static_cast<const FTriggerOnThresholdNode&>(InParams.Node);
const FDataReferenceCollection& InputCol = InParams.InputDataReferences;
const FOperatorSettings& Settings = InParams.OperatorSettings;
const FInputVertexInterface& InputInterface = DeclareVertexInterface().GetInputInterface();
// Static property pin, only used for factory.
FBufferTriggerTypeReadRef Type = InputCol.GetDataReadReferenceOrConstruct<FEnumBufferTriggerType>(TriggerType);
FAudioBufferReadRef InputBuffer = InputCol.GetDataReadReferenceOrConstruct<FAudioBuffer>(InPinName, Settings);
FFloatReadRef Threshold = InputCol.GetDataReadReferenceOrConstructWithVertexDefault<float>(InputInterface, ThresholdPinName, Settings);
switch (*Type)
{
default:
case EBufferTriggerType::RisingEdge:
return MakeUnique<FTriggerOnThresholdOperator_RisingEdge>(InParams.OperatorSettings, InputBuffer, Threshold);
case EBufferTriggerType::FallingEdge:
return MakeUnique<FTriggerOnThresholdOperator_FallingEdge>(InParams.OperatorSettings, InputBuffer, Threshold);
case EBufferTriggerType::AbsThreshold:
return MakeUnique<FTriggerOnThresholdOperator_AbsThreshold>(InParams.OperatorSettings, InputBuffer, Threshold);
}
checkNoEntry();
return nullptr;
}
METASOUND_REGISTER_NODE(FTriggerOnThresholdNode);
}
#undef LOCTEXT_NAMESPACE //MetasoundStandardNodes