// Copyright Epic Games, Inc. All Rights Reserved. #include "MetasoundFacade.h" #include "MetasoundNodeRegistrationMacro.h" #include "MetasoundExecutableOperator.h" #include "MetasoundPrimitives.h" #include "MetasoundStandardNodesNames.h" #include "MetasoundAudioBuffer.h" #include "Internationalization/Text.h" #include "MetasoundParamHelper.h" #define LOCTEXT_NAMESPACE "MetasoundStandardNodes_ClampNode" namespace Metasound { namespace ClampVertexNames { METASOUND_PARAM(InputValue, "In", "Input value to clamp."); METASOUND_PARAM(InputMinValue, "Min", "The min value to clamp."); METASOUND_PARAM(InputMaxValue, "Max", "The max value to clamp."); METASOUND_PARAM(OutputValue, "Value", "The clamped value."); } namespace MetasoundClampNodePrivate { FNodeClassMetadata CreateNodeClassMetadata(const FName& InDataTypeName, const FName& InOperatorName, const FText& InDisplayName, const FText& InDescription, const FVertexInterface& InDefaultInterface) { FNodeClassMetadata Metadata { FNodeClassName { "Clamp", InOperatorName, InDataTypeName }, 1, // Major Version 0, // Minor Version InDisplayName, InDescription, PluginAuthor, PluginNodeMissingPrompt, InDefaultInterface, { METASOUND_LOCTEXT("ClampCategory", "Math") }, { METASOUND_LOCTEXT("ClampKeyword", "Clamp") }, FNodeDisplayStyle() }; return Metadata; } template struct TClamp { bool bIsSupported = false; }; template<> struct TClamp { static void GetClamped(int32 InValue, int32 InMin, int32 InMax, int32& OutClamped) { OutClamped = FMath::Clamp(InValue, InMin, InMax); } static TDataReadReference CreateInValue(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputValue), InParams.OperatorSettings); } static TDataReadReference CreateInMin(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputMinValue), InParams.OperatorSettings); } static TDataReadReference CreateInMax(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputMaxValue), InParams.OperatorSettings); } }; template<> struct TClamp { static void GetClamped(float InValue, float InMin, float InMax, float& OutClamped) { OutClamped = FMath::Clamp(InValue, InMin, InMax); } static TDataReadReference CreateInValue(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputValue), InParams.OperatorSettings); } static TDataReadReference CreateInMin(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputMinValue), InParams.OperatorSettings); } static TDataReadReference CreateInMax(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputMaxValue), InParams.OperatorSettings); } }; template<> struct TClamp { static void GetClamped(const FAudioBuffer& InValue, const FAudioBuffer& InMin, const FAudioBuffer& InMax, FAudioBuffer& OutClamped) { float* OutClampedBufferPtr = OutClamped.GetData(); const float* InBufferPtr = InValue.GetData(); const float* MinBufferPtr = InMin.GetData(); const float* MaxBufferPtr = InMax.GetData(); int32 NumSamples = InValue.Num(); for (int32 i = 0; i < NumSamples; ++i) { OutClampedBufferPtr[i] = FMath::Clamp(InBufferPtr[i], MinBufferPtr[i], MaxBufferPtr[i]); } } static TDataReadReference CreateInValue(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputValue), InParams.OperatorSettings); } static TDataReadReference CreateInMin(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputMinValue), InParams.OperatorSettings); } static TDataReadReference CreateInMax(const FBuildOperatorParams& InParams) { using namespace ClampVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; return InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputMaxValue), InParams.OperatorSettings); } }; } template class TClampNodeOperator : public TExecutableOperator> { public: static const FVertexInterface& GetDefaultInterface() { using namespace ClampVertexNames; using namespace MetasoundClampNodePrivate; static const FVertexInterface DefaultInterface( FInputVertexInterface( TInputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(InputValue)), TInputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(InputMinValue)), TInputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(InputMaxValue)) ), FOutputVertexInterface( TOutputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(OutputValue)) ) ); return DefaultInterface; } static const FNodeClassMetadata& GetNodeInfo() { auto CreateNodeClassMetadata = []() -> FNodeClassMetadata { const FName DataTypeName = GetMetasoundDataTypeName(); const FName OperatorName = "Clamp"; const FText NodeDisplayName = METASOUND_LOCTEXT_FORMAT("ClampDisplayNamePattern", "Clamp ({0})", GetMetasoundDataTypeDisplayText()); const FText NodeDescription = METASOUND_LOCTEXT("ClampDesc", "Returns the clamped value of the input within the given value range."); const FVertexInterface NodeInterface = GetDefaultInterface(); return MetasoundClampNodePrivate::CreateNodeClassMetadata(DataTypeName, OperatorName, NodeDisplayName, NodeDescription, NodeInterface); }; static const FNodeClassMetadata Metadata = CreateNodeClassMetadata(); return Metadata; } static TUniquePtr CreateOperator(const FBuildOperatorParams& InParams, FBuildResults& OutResults) { using namespace ClampVertexNames; using namespace MetasoundClampNodePrivate; TDataReadReference InputValue = TClamp::CreateInValue(InParams); TDataReadReference InputMinValue = TClamp::CreateInMin(InParams); TDataReadReference InputMaxValue = TClamp::CreateInMax(InParams); return MakeUnique>(InParams.OperatorSettings, InputValue, InputMinValue, InputMaxValue); } TClampNodeOperator(const FOperatorSettings& InSettings, const TDataReadReference& InInputValue, const TDataReadReference& InInputMinValue, const TDataReadReference& InInputMaxValue) : InputValue(InInputValue) , InputMinValue(InInputMinValue) , InputMaxValue(InInputMaxValue) , OutputValue(TDataWriteReferenceFactory::CreateAny(InSettings)) { GetClamped(); } virtual ~TClampNodeOperator() = default; virtual void BindInputs(FInputVertexInterfaceData& InOutVertexData) override { using namespace ClampVertexNames; InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InputValue), InputValue); InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InputMinValue), InputMinValue); InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InputMaxValue), InputMaxValue); } virtual void BindOutputs(FOutputVertexInterfaceData& InOutVertexData) override { using namespace ClampVertexNames; InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(OutputValue), OutputValue); } void GetClamped() { using namespace MetasoundClampNodePrivate; TClamp::GetClamped(*InputValue, *InputMinValue, *InputMaxValue, *OutputValue); } void Reset(const IOperator::FResetParams& InParams) { GetClamped(); } void Execute() { GetClamped(); } private: TDataReadReference InputValue; TDataReadReference InputMinValue; TDataReadReference InputMaxValue; TDataWriteReference OutputValue; }; /** TClampNode * * Returns the clamped value of the input in the specified range. */ template using TClampNode = TNodeFacade>; using FClampNodeInt32 = TClampNode; METASOUND_REGISTER_NODE(FClampNodeInt32) using FClampNodeFloat = TClampNode; METASOUND_REGISTER_NODE(FClampNodeFloat) using FClampNodeAudio = TClampNode; METASOUND_REGISTER_NODE(FClampNodeAudio) } #undef LOCTEXT_NAMESPACE //MetaSoundStandardNodes_ClampNode