// Copyright Epic Games, Inc. All Rights Reserved. #include "MetasoundCatCastingNode.h" #include "MetasoundChannelAgnosticType.h" #include "MetasoundExecutableOperator.h" #include "MetasoundFacade.h" #include "MetasoundNodeRegistrationMacro.h" #include "MetasoundVertex.h" #include "TypeFamily/ChannelTypeFamily.h" #define LOCTEXT_NAMESPACE "MetasoundStandardNodes_CatCastingNode" namespace Metasound { class FChannelAgnosticType; struct FBuildOperatorParams; class FNodeFacade; namespace CatCastingPrivate { METASOUND_PARAM(InputFromCat, "Input", "CAT to Cast"); METASOUND_PARAM(OutputToCat, "Output", "CAT Result"); class FCatCastingOperatorData final : public TOperatorData { public: // The OperatorDataTypeName is used when downcasting an IOperatorData to ensure // that the downcast is valid. static const FLazyName OperatorDataTypeName; explicit FCatCastingOperatorData(const FName& InToTypeName, Audio::EChannelTranscodeMethod InTranscodeMethod, Audio::EChannelMapMonoUpmixMethod InMixMethod) : ToTypeName(InToTypeName) , TranscodeMethod(InTranscodeMethod) , MixMethod(InMixMethod) {} const FName& GetToType() const { return ToTypeName; } Audio::EChannelMapMonoUpmixMethod GetMixMethod() const { return MixMethod; } Audio::EChannelTranscodeMethod GetTranscodeMethod() const { return TranscodeMethod; } private: FName ToTypeName; Audio::EChannelTranscodeMethod TranscodeMethod; Audio::EChannelMapMonoUpmixMethod MixMethod; }; // Linkage. const FLazyName FCatCastingOperatorData::OperatorDataTypeName = TEXT("FCatCastingOperatorData"); } class FCatCastingOperator final : public TExecutableOperator { public: FCatCastingOperator(const FBuildOperatorParams& InParams, FChannelAgnosticTypeReadRef&& InInputCat, const CatCastingPrivate::FCatCastingOperatorData& InData, const FName InConcreteName) : InputFrom(MoveTemp(InInputCat)) , ToFormatName(InConcreteName) , OutputCastResult(FChannelAgnosticTypeWriteRef::CreateNew(InParams.OperatorSettings, InConcreteName)) , Settings(InParams.OperatorSettings) , TranscodeMethod(InData.GetTranscodeMethod()) , MixMethod(InData.GetMixMethod()) {} virtual ~FCatCastingOperator() override = default; static const FVertexInterface& GetDefaultInterface() { using namespace CatCastingPrivate; auto CreateDefaultInterface = []()-> FVertexInterface { // inputs FInputVertexInterface InputInterface; InputInterface.Add(TInputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(InputFromCat))); // outputs FOutputVertexInterface OutputInterface; OutputInterface.Add(TOutputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(OutputToCat))); return FVertexInterface(InputInterface, OutputInterface); }; // end lambda: CreateDefaultInterface() static const FVertexInterface DefaultInterface = CreateDefaultInterface(); return DefaultInterface; } static TUniquePtr CreateOperator(const FBuildOperatorParams& InParams, FBuildResults& OutResults) { using namespace CatCastingPrivate; const FCatCastingOperatorData* CatTestingConfigData = CastOperatorData(InParams.Node.GetOperatorData().Get()); if (!CatTestingConfigData) { return MakeUnique(); } const FName CastToName = CatTestingConfigData->GetToType(); const FInputVertexInterfaceData& InputData = InParams.InputData; const Audio::FChannelTypeFamily* ConcreteToType = Audio::GetChannelRegistry().FindConcreteChannel(CastToName); TDataReadReference InputCat = InputData.GetOrCreateDefaultDataReadReference( METASOUND_GET_PARAM_NAME(InputFromCat), InParams.OperatorSettings); // Make sure the cast is to something sane, otherwise use the inputs type... const FName CastToNameSane = ConcreteToType ? ConcreteToType->GetName() : InputCat->GetTypeName(); return MakeUnique( InParams, MoveTemp(InputCat), *CatTestingConfigData, CastToNameSane ); } virtual void BindInputs(FInputVertexInterfaceData& InOutVertexData) override { using namespace CatCastingPrivate; InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InputFromCat) , InputFrom); } virtual void BindOutputs(FOutputVertexInterfaceData& InOutVertexData) override { using namespace CatCastingPrivate; InOutVertexData.BindWriteVertex(METASOUND_GET_PARAM_NAME(OutputToCat),OutputCastResult); // Create transcoder Transcoder = InputFrom->GetType().GetTranscoder( { .ToType = OutputCastResult->GetType(), .TranscodeMethod = TranscodeMethod, .MixMethod = MixMethod, } ); } void Reset(const FResetParams& InParams) { Execute(); } void Execute() { if (Transcoder) { using namespace CatCastingPrivate; using namespace Audio; TStackArrayOfPointers Src = MakeMultiMonoPointersFromView(InputFrom->GetRawMultiMono(), Settings.GetNumFramesPerBlock(), InputFrom->NumChannels()); TStackArrayOfPointers Dst = MakeMultiMonoPointersFromView(OutputCastResult->GetRawMultiMono(), Settings.GetNumFramesPerBlock(), OutputCastResult->NumChannels()); Transcoder(Src, Dst, Settings.GetNumFramesPerBlock()); } } static FNodeClassMetadata GetNodeInfo() { using namespace CatCastingPrivate; return FNodeClassMetadata { FNodeClassName{ "Experimental", "CatCastingOperator", "" }, 1, // Major version 0, // Minor version METASOUND_LOCTEXT("CatCastingNodeName", "CAT Casting Node"), METASOUND_LOCTEXT("CatCastingNodeNameDescription", "A Node that allows Casting to CATs"), TEXT("UE"), // Author METASOUND_LOCTEXT("ExampleConfigurablePromptIfMissing", "Enable the MetaSoundExperimental Plugin"), // Prompt if missing GetDefaultInterface(), {} }; } private: using FTranscoder = Audio::FChannelTypeFamily::FTranscoder; FChannelAgnosticTypeReadRef InputFrom; FName ToFormatName; FChannelAgnosticTypeWriteRef OutputCastResult; FOperatorSettings Settings; FTranscoder Transcoder; Audio::EChannelTranscodeMethod TranscodeMethod; Audio::EChannelMapMonoUpmixMethod MixMethod; }; // class FCatCastingOperator using FCatCastingNode = TNodeFacade; // register node config. METASOUND_REGISTER_NODE_AND_CONFIGURATION(FCatCastingNode, FMetaSoundCatCastingNodeConfiguration); } // namespace Metasound TArray UMetasoundCatCastingOptionsHelper::GetCastingOptions() { const TArray AllFormats = Audio::GetChannelRegistry().GetAllChannelFormats(); TArray FormatsOptions; Algo::Transform(AllFormats, FormatsOptions, [](const Audio::FChannelTypeFamily* i) -> FPropertyTextFName { return {.ValueString = i->GetName(), .DisplayName = FText::FromString(i->GetFriendlyName()) }; }); return FormatsOptions; } TInstancedStruct FMetaSoundCatCastingNodeConfiguration::OverrideDefaultInterface( const FMetasoundFrontendClass& InNodeClass) const { return TInstancedStruct::Make(FMetasoundFrontendClassInterface::GenerateClassInterface(Metasound::FCatCastingOperator::GetDefaultInterface())); } TSharedPtr FMetaSoundCatCastingNodeConfiguration::GetOperatorData() const { return MakeShared( ToType, static_cast(TranscodeMethod), static_cast(MixMethod) ); } #undef LOCTEXT_NAMESPACE //