You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#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]
260 lines
9.5 KiB
C++
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
|
|
|