2023-03-07 17:01:52 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundBuilderSubsystem.h"
2023-03-09 17:56:53 -05:00
# include "Algo/Find.h"
2023-03-07 17:01:52 -05:00
# include "Algo/Transform.h"
# include "Components/AudioComponent.h"
2023-05-10 20:28:39 -04:00
# include "Engine/Engine.h"
2023-03-07 17:01:52 -05:00
# include "HAL/IConsoleManager.h"
# include "Interfaces/MetasoundOutputFormatInterfaces.h"
# include "Interfaces/MetasoundFrontendSourceInterface.h"
# include "Metasound.h"
2023-06-16 03:08:48 -04:00
# include "MetasoundAssetSubsystem.h"
2023-06-16 17:55:08 -04:00
# include "MetasoundDataReference.h"
# include "MetasoundDynamicOperatorTransactor.h"
# include "MetasoundFrontendDataTypeRegistry.h"
2023-03-07 17:01:52 -05:00
# include "MetasoundFrontendDocument.h"
2023-03-23 14:04:36 -04:00
# include "MetasoundFrontendRegistries.h"
2023-03-07 17:01:52 -05:00
# include "MetasoundFrontendSearchEngine.h"
# include "MetasoundFrontendTransform.h"
# include "MetasoundGeneratorHandle.h"
# include "MetasoundLog.h"
# include "MetasoundParameterTransmitter.h"
# include "MetasoundSource.h"
# include "MetasoundTrace.h"
# include "MetasoundUObjectRegistry.h"
2023-06-16 17:55:08 -04:00
# include "MetasoundVertex.h"
2023-03-07 17:01:52 -05:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(MetasoundBuilderSubsystem)
namespace Metasound : : Engine
{
namespace BuilderSubsystemPrivate
{
template < typename TLiteralType >
FMetasoundFrontendLiteral CreatePODMetaSoundLiteral ( const TLiteralType & Value , FName & OutDataType )
{
OutDataType = GetMetasoundDataTypeName < TLiteralType > ( ) ;
FMetasoundFrontendLiteral Literal ;
Literal . Set ( Value ) ;
return Literal ;
}
2023-03-09 17:56:53 -05:00
2023-06-16 17:55:08 -04:00
TUniquePtr < INode > CreateDynamicNodeFromFrontendLiteral ( const FName DataType , const FMetasoundFrontendLiteral & InLiteral )
{
using namespace Frontend ;
FLiteral ValueLiteral = InLiteral . ToLiteral ( DataType ) ;
// TODO: Node name "Literal" is always the same. Consolidate and deprecate providing unique node name to avoid unnecessary FName table bloat.
FLiteralNodeConstructorParams Params { " Literal " , FGuid : : NewGuid ( ) , MoveTemp ( ValueLiteral ) } ;
return IDataTypeRegistry : : Get ( ) . CreateLiteralNode ( DataType , MoveTemp ( Params ) ) ;
}
2023-03-09 17:56:53 -05:00
template < typename BuilderClass >
2023-06-22 14:43:52 -04:00
BuilderClass & CreateTransientBuilder ( FName BuilderName = { } )
2023-03-09 17:56:53 -05:00
{
const EObjectFlags NewObjectFlags = RF_Public | RF_Transient ;
UPackage * TransientPackage = GetTransientPackage ( ) ;
2023-06-22 14:43:52 -04:00
const FName ObjectName = MakeUniqueObjectName ( TransientPackage , BuilderClass : : StaticClass ( ) , BuilderName ) ;
2023-03-09 17:56:53 -05:00
TObjectPtr < BuilderClass > NewBuilder = NewObject < BuilderClass > ( TransientPackage , ObjectName , NewObjectFlags ) ;
check ( NewBuilder ) ;
2023-06-16 17:55:08 -04:00
NewBuilder - > InitFrontendBuilder ( ) ;
2023-03-09 17:56:53 -05:00
return * NewBuilder . Get ( ) ;
}
2023-03-07 17:01:52 -05:00
} // namespace BuilderSubsystemPrivate
} // namespace Metasound::Engine
2023-06-16 17:55:08 -04:00
2023-03-07 17:01:52 -05:00
FMetaSoundBuilderNodeOutputHandle UMetaSoundBuilderBase : : AddGraphInputNode ( FName Name , FName DataType , FMetasoundFrontendLiteral DefaultValue , EMetaSoundBuilderResult & OutResult , bool bIsConstructorInput )
{
FMetaSoundBuilderNodeOutputHandle NewHandle ;
const FMetasoundFrontendNode * Node = Builder . FindGraphInputNode ( Name ) ;
if ( Node )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " AddGraphInputNode Failed: Input Node already exists with name '%s'; returning handle to existing node which may or may not match requested DataType '%s' " ) , * Name . ToString ( ) , * DataType . ToString ( ) ) ;
}
else
{
2023-06-16 17:55:08 -04:00
FMetasoundFrontendClassInput Description ;
Description . Name = Name ;
Description . TypeName = DataType ;
Description . NodeID = FGuid : : NewGuid ( ) ;
Description . VertexID = FGuid : : NewGuid ( ) ;
Description . DefaultLiteral = static_cast < FMetasoundFrontendLiteral > ( DefaultValue ) ;
Description . AccessType = bIsConstructorInput ? EMetasoundFrontendVertexAccessType : : Value : EMetasoundFrontendVertexAccessType : : Reference ;
2023-03-07 17:01:52 -05:00
Node = Builder . AddGraphInput ( Description ) ;
}
if ( Node )
{
const TArray < FMetasoundFrontendVertex > & Outputs = Node - > Interface . Outputs ;
checkf ( ! Outputs . IsEmpty ( ) , TEXT ( " Node should be initialized and have one output. " ) ) ;
NewHandle . NodeID = Node - > GetID ( ) ;
NewHandle . VertexID = Outputs . Last ( ) . VertexID ;
}
OutResult = NewHandle . IsSet ( ) ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
return NewHandle ;
}
2023-05-30 14:46:00 -04:00
FMetaSoundBuilderNodeInputHandle UMetaSoundBuilderBase : : AddGraphOutputNode ( FName Name , FName DataType , FMetasoundFrontendLiteral DefaultValue , EMetaSoundBuilderResult & OutResult , bool bIsConstructorOutput )
2023-03-07 17:01:52 -05:00
{
FMetaSoundBuilderNodeInputHandle NewHandle ;
const FMetasoundFrontendNode * Node = Builder . FindGraphOutputNode ( Name ) ;
if ( Node )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " AddGraphOutputNode Failed: Output Node already exists with name '%s'; returning handle to existing node which may or may not match requested DataType '%s' " ) , * Name . ToString ( ) , * DataType . ToString ( ) ) ;
}
else
{
2023-06-16 17:55:08 -04:00
FMetasoundFrontendClassOutput Description ;
Description . Name = Name ;
Description . TypeName = DataType ;
Description . NodeID = FGuid : : NewGuid ( ) ;
Description . VertexID = FGuid : : NewGuid ( ) ;
Description . AccessType = bIsConstructorOutput ? EMetasoundFrontendVertexAccessType : : Value : EMetasoundFrontendVertexAccessType : : Reference ;
2023-03-07 17:01:52 -05:00
Node = Builder . AddGraphOutput ( Description ) ;
}
if ( Node )
{
const TArray < FMetasoundFrontendVertex > & Inputs = Node - > Interface . Inputs ;
checkf ( ! Inputs . IsEmpty ( ) , TEXT ( " Node should be initialized and have one input. " ) ) ;
const FGuid & VertexID = Inputs . Last ( ) . VertexID ;
if ( Builder . SetNodeInputDefault ( Node - > GetID ( ) , VertexID , DefaultValue ) )
{
NewHandle . NodeID = Node - > GetID ( ) ;
NewHandle . VertexID = VertexID ;
}
}
OutResult = NewHandle . IsSet ( ) ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
return NewHandle ;
}
void UMetaSoundBuilderBase : : AddInterface ( FName InterfaceName , EMetaSoundBuilderResult & OutResult )
{
const bool bInterfaceAdded = Builder . AddInterface ( InterfaceName ) ;
OutResult = bInterfaceAdded ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-05-03 18:06:20 -04:00
FMetaSoundNodeHandle UMetaSoundBuilderBase : : AddNode ( const TScriptInterface < IMetaSoundDocumentInterface > & NodeClass , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
using namespace Metasound ;
FMetaSoundNodeHandle NewHandle ;
if ( NodeClass )
{
if ( FMetasoundAssetBase * MetaSoundAsset = IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( NodeClass . GetObject ( ) ) )
{
MetaSoundAsset - > RegisterGraphWithFrontend ( ) ;
const IMetaSoundDocumentInterface * Interface = NodeClass . GetInterface ( ) ;
check ( Interface ) ;
const FMetasoundFrontendDocument & NodeClassDoc = Interface - > GetDocument ( ) ;
const FMetasoundFrontendGraphClass & NodeClassGraph = NodeClassDoc . RootGraph ;
2023-05-30 14:46:00 -04:00
2023-03-07 17:01:52 -05:00
if ( const FMetasoundFrontendNode * NewNode = Builder . AddGraphNode ( NodeClassGraph ) )
{
NewHandle . NodeID = NewNode - > GetID ( ) ;
}
}
}
OutResult = NewHandle . IsSet ( ) ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
return NewHandle ;
}
2023-06-16 17:55:08 -04:00
FMetaSoundNodeHandle UMetaSoundBuilderBase : : AddNodeByClassName ( const FMetasoundFrontendClassName & ClassName , int32 MajorVersion , EMetaSoundBuilderResult & OutResult )
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
FMetaSoundNodeHandle NewHandle ;
if ( const FMetasoundFrontendNode * NewNode = Builder . AddNodeByClassName ( ClassName , MajorVersion ) )
{
NewHandle . NodeID = NewNode - > GetID ( ) ;
}
OutResult = NewHandle . IsSet ( ) ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
return NewHandle ;
}
2023-03-07 17:01:52 -05:00
bool UMetaSoundBuilderBase : : ContainsNode ( const FMetaSoundNodeHandle & NodeHandle ) const
{
return Builder . ContainsNode ( NodeHandle . NodeID ) ;
}
bool UMetaSoundBuilderBase : : ContainsNodeInput ( const FMetaSoundBuilderNodeInputHandle & InputHandle ) const
{
return Builder . FindNodeInput ( InputHandle . NodeID , InputHandle . VertexID ) ! = nullptr ;
}
bool UMetaSoundBuilderBase : : ContainsNodeOutput ( const FMetaSoundBuilderNodeOutputHandle & OutputHandle ) const
{
return Builder . FindNodeOutput ( OutputHandle . NodeID , OutputHandle . VertexID ) ! = nullptr ;
}
2023-03-09 17:56:53 -05:00
void UMetaSoundBuilderBase : : ConnectNodes ( const FMetaSoundBuilderNodeOutputHandle & NodeOutputHandle , const FMetaSoundBuilderNodeInputHandle & NodeInputHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
2023-07-27 18:35:37 -04:00
using namespace Metasound : : Frontend ;
OutResult = EMetaSoundBuilderResult : : Failed ;
FMetasoundFrontendEdge NewEdge { NodeOutputHandle . NodeID , NodeOutputHandle . VertexID , NodeInputHandle . NodeID , NodeInputHandle . VertexID } ;
const EInvalidEdgeReason InvalidEdgeReason = Builder . IsValidEdge ( NewEdge ) ;
if ( InvalidEdgeReason = = Metasound : : Frontend : : EInvalidEdgeReason : : None )
2023-03-07 17:01:52 -05:00
{
2023-07-27 18:35:37 -04:00
# if !NO_LOGGING
const FMetasoundFrontendNode * OldOutputNode = nullptr ;
const FMetasoundFrontendVertex * OldOutputVertex = nullptr ;
if ( Builder . IsNodeInputConnected ( NodeInputHandle . NodeID , NodeInputHandle . VertexID ) )
{
OldOutputVertex = Builder . FindNodeOutputConnectedToNodeInput ( NodeInputHandle . NodeID , NodeInputHandle . VertexID , & OldOutputNode ) ;
}
# endif // !NO_LOGGING
const bool bRemovedEdge = Builder . RemoveEdgeToNodeInput ( NodeInputHandle . NodeID , NodeInputHandle . VertexID ) ;
Builder . AddEdge ( MoveTemp ( NewEdge ) ) ;
# if !NO_LOGGING
if ( bRemovedEdge )
{
checkf ( OldOutputNode , TEXT ( " MetaSound edge was removed from output but output node not found. " ) ) ;
checkf ( OldOutputVertex , TEXT ( " MetaSound edge was removed from output but output vertex not found. " ) ) ;
const FMetasoundFrontendNode * InputNode = Builder . FindNode ( NodeInputHandle . NodeID ) ;
checkf ( InputNode , TEXT ( " Edge was deemed valid but input parent node is missing " ) ) ;
const FMetasoundFrontendVertex * InputVertex = Builder . FindNodeInput ( NodeInputHandle . NodeID , NodeInputHandle . VertexID ) ;
checkf ( InputVertex , TEXT ( " Edge was deemed valid but input is missing " ) ) ;
const FMetasoundFrontendNode * OutputNode = Builder . FindNode ( NodeOutputHandle . NodeID ) ;
checkf ( OutputNode , TEXT ( " Edge was deemed valid but output parent node is missing " ) ) ;
const FMetasoundFrontendVertex * OutputVertex = Builder . FindNodeOutput ( NodeOutputHandle . NodeID , NodeOutputHandle . VertexID ) ;
checkf ( OutputVertex , TEXT ( " Edge was deemed valid but output is missing " ) ) ;
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Removed connection from node output '%s:%s' to node '%s:%s' in order to connect to node output '%s:%s' " ) ,
* OldOutputNode - > Name . ToString ( ) ,
* OldOutputVertex - > Name . ToString ( ) ,
* InputNode - > Name . ToString ( ) ,
* InputVertex - > Name . ToString ( ) ,
* OutputNode - > Name . ToString ( ) ,
* OutputVertex - > Name . ToString ( ) ) ;
}
# endif // !NO_LOGGING
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Builder '%s' 'ConnectNodes' failed: '%s' " ) , * GetName ( ) , * LexToString ( InvalidEdgeReason ) ) ;
}
2023-03-07 17:01:52 -05:00
}
2023-03-09 17:56:53 -05:00
void UMetaSoundBuilderBase : : ConnectNodesByInterfaceBindings ( const FMetaSoundNodeHandle & FromNodeHandle , const FMetaSoundNodeHandle & ToNodeHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
2023-03-09 17:56:53 -05:00
const bool bEdgesAdded = Builder . AddEdgesByNodeClassInterfaceBindings ( FromNodeHandle . NodeID , ToNodeHandle . NodeID ) ;
2023-03-07 17:01:52 -05:00
OutResult = bEdgesAdded ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
TArray < FMetaSoundBuilderNodeInputHandle > UMetaSoundBuilderBase : : ConnectNodeOutputsToMatchingGraphInterfaceOutputs ( const FMetaSoundNodeHandle & NodeHandle , EMetaSoundBuilderResult & OutResult )
{
TArray < const FMetasoundFrontendEdge * > NewEdges ;
const bool bEdgesAdded = Builder . AddEdgesFromMatchingInterfaceNodeOutputsToGraphOutputs ( NodeHandle . NodeID , NewEdges ) ;
OutResult = bEdgesAdded ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
TArray < FMetaSoundBuilderNodeInputHandle > ConnectedVertices ;
Algo : : Transform ( NewEdges , ConnectedVertices , [ this ] ( const FMetasoundFrontendEdge * NewEdge )
{
const FMetasoundFrontendVertex * Vertex = Builder . FindNodeInput ( NewEdge - > ToNodeID , NewEdge - > ToVertexID ) ;
checkf ( Vertex , TEXT ( " Edge connection reported success but vertex not found. " ) ) ;
2023-04-10 17:45:18 -04:00
return FMetaSoundBuilderNodeInputHandle ( NewEdge - > ToNodeID , Vertex - > VertexID ) ;
2023-03-07 17:01:52 -05:00
} ) ;
return ConnectedVertices ;
}
TArray < FMetaSoundBuilderNodeOutputHandle > UMetaSoundBuilderBase : : ConnectNodeInputsToMatchingGraphInterfaceInputs ( const FMetaSoundNodeHandle & NodeHandle , EMetaSoundBuilderResult & OutResult )
{
TArray < const FMetasoundFrontendEdge * > NewEdges ;
const bool bEdgesAdded = Builder . AddEdgesFromMatchingInterfaceNodeInputsToGraphInputs ( NodeHandle . NodeID , NewEdges ) ;
OutResult = bEdgesAdded ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
TArray < FMetaSoundBuilderNodeOutputHandle > ConnectedVertices ;
Algo : : Transform ( NewEdges , ConnectedVertices , [ this ] ( const FMetasoundFrontendEdge * NewEdge )
{
2023-06-26 15:40:12 -04:00
const FMetasoundFrontendVertex * Vertex = Builder . FindNodeOutput ( NewEdge - > FromNodeID , NewEdge - > FromVertexID ) ;
2023-03-07 17:01:52 -05:00
checkf ( Vertex , TEXT ( " Edge connection reported success but vertex not found. " ) ) ;
2023-04-10 17:45:18 -04:00
return FMetaSoundBuilderNodeOutputHandle ( NewEdge - > ToNodeID , Vertex - > VertexID ) ;
2023-03-07 17:01:52 -05:00
} ) ;
return ConnectedVertices ;
}
2023-03-09 17:56:53 -05:00
void UMetaSoundBuilderBase : : ConnectNodeOutputToGraphOutput ( FName GraphOutputName , const FMetaSoundBuilderNodeOutputHandle & NodeOutputHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
2023-07-27 18:35:37 -04:00
using namespace Metasound : : Frontend ;
2023-03-07 17:01:52 -05:00
OutResult = EMetaSoundBuilderResult : : Failed ;
if ( const FMetasoundFrontendNode * GraphOutputNode = Builder . FindGraphOutputNode ( GraphOutputName ) )
{
const FMetasoundFrontendVertex & InputVertex = GraphOutputNode - > Interface . Inputs . Last ( ) ;
2023-07-27 18:35:37 -04:00
FMetasoundFrontendEdge NewEdge { NodeOutputHandle . NodeID , NodeOutputHandle . VertexID , GraphOutputNode - > GetID ( ) , InputVertex . VertexID } ;
const EInvalidEdgeReason InvalidEdgeReason = Builder . IsValidEdge ( NewEdge ) ;
if ( InvalidEdgeReason = = EInvalidEdgeReason : : None )
2023-03-07 17:01:52 -05:00
{
2023-07-27 18:35:37 -04:00
Builder . RemoveEdgeToNodeInput ( GraphOutputNode - > GetID ( ) , InputVertex . VertexID ) ;
Builder . AddEdge ( MoveTemp ( NewEdge ) ) ;
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Builder '%s' 'ConnectNodeOutputToGraphOutput' failed: '%s' " ) , * GetName ( ) , * LexToString ( InvalidEdgeReason ) ) ;
}
2023-03-07 17:01:52 -05:00
}
}
2023-03-09 17:56:53 -05:00
void UMetaSoundBuilderBase : : ConnectNodeInputToGraphInput ( FName GraphInputName , const FMetaSoundBuilderNodeInputHandle & NodeInputHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
2023-07-27 18:35:37 -04:00
using namespace Metasound : : Frontend ;
2023-03-07 17:01:52 -05:00
2023-07-27 18:35:37 -04:00
OutResult = EMetaSoundBuilderResult : : Failed ;
if ( const FMetasoundFrontendNode * GraphInputNode = Builder . FindGraphInputNode ( GraphInputName ) )
2023-03-07 17:01:52 -05:00
{
2023-07-27 18:35:37 -04:00
const FMetasoundFrontendVertex & OutputVertex = GraphInputNode - > Interface . Outputs . Last ( ) ;
FMetasoundFrontendEdge NewEdge { GraphInputNode - > GetID ( ) , OutputVertex . VertexID , NodeInputHandle . NodeID , NodeInputHandle . VertexID } ;
const EInvalidEdgeReason InvalidEdgeReason = Builder . IsValidEdge ( NewEdge ) ;
if ( InvalidEdgeReason = = EInvalidEdgeReason : : None )
{
Builder . RemoveEdgeToNodeInput ( NodeInputHandle . NodeID , NodeInputHandle . VertexID ) ;
Builder . AddEdge ( MoveTemp ( NewEdge ) ) ;
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Builder '%s' 'ConnectNodeInputToGraphInput' failed: '%s' " ) , * GetName ( ) , * LexToString ( InvalidEdgeReason ) ) ;
}
}
2023-03-07 17:01:52 -05:00
}
2023-03-09 17:56:53 -05:00
void UMetaSoundBuilderBase : : DisconnectNodes ( const FMetaSoundBuilderNodeOutputHandle & NodeOutputHandle , const FMetaSoundBuilderNodeInputHandle & NodeInputHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
const bool bEdgeRemoved = Builder . RemoveEdge ( FMetasoundFrontendEdge
{
2023-03-09 17:56:53 -05:00
NodeOutputHandle . NodeID ,
NodeOutputHandle . VertexID ,
NodeInputHandle . NodeID ,
NodeInputHandle . VertexID ,
2023-03-07 17:01:52 -05:00
} ) ;
OutResult = bEdgeRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-03-09 17:56:53 -05:00
void UMetaSoundBuilderBase : : DisconnectNodeInput ( const FMetaSoundBuilderNodeInputHandle & NodeInputHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
2023-03-09 17:56:53 -05:00
const bool bEdgeRemoved = Builder . RemoveEdgeToNodeInput ( NodeInputHandle . NodeID , NodeInputHandle . VertexID ) ;
2023-03-07 17:01:52 -05:00
OutResult = bEdgeRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-03-09 17:56:53 -05:00
void UMetaSoundBuilderBase : : DisconnectNodeOutput ( const FMetaSoundBuilderNodeOutputHandle & NodeOutputHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
2023-03-09 17:56:53 -05:00
const bool bEdgeRemoved = Builder . RemoveEdgesFromNodeOutput ( NodeOutputHandle . NodeID , NodeOutputHandle . VertexID ) ;
2023-03-07 17:01:52 -05:00
OutResult = bEdgeRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-03-09 17:56:53 -05:00
void UMetaSoundBuilderBase : : DisconnectNodesByInterfaceBindings ( const FMetaSoundNodeHandle & FromNodeHandle , const FMetaSoundNodeHandle & ToNodeHandle , EMetaSoundBuilderResult & OutResult )
{
const bool bEdgesRemoved = Builder . RemoveEdgesByNodeClassInterfaceBindings ( FromNodeHandle . NodeID , ToNodeHandle . NodeID ) ;
OutResult = bEdgesRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-03-23 14:04:36 -04:00
FMetaSoundBuilderNodeInputHandle UMetaSoundBuilderBase : : FindNodeInputByName ( const FMetaSoundNodeHandle & NodeHandle , FName InputName , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
if ( const FMetasoundFrontendNode * Node = Builder . FindNode ( NodeHandle . NodeID ) )
{
const TArray < FMetasoundFrontendVertex > & InputVertices = Node - > Interface . Inputs ;
auto FindByNamePredicate = [ & InputName ] ( const FMetasoundFrontendVertex & Vertex ) { return Vertex . Name = = InputName ; } ;
if ( const FMetasoundFrontendVertex * Input = InputVertices . FindByPredicate ( FindByNamePredicate ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
2023-04-10 17:45:18 -04:00
return FMetaSoundBuilderNodeInputHandle ( Node - > GetID ( ) , Input - > VertexID ) ;
2023-03-07 17:01:52 -05:00
}
2023-03-23 14:04:36 -04:00
FString NodeClassName = TEXT ( " N/A " ) ;
if ( const FMetasoundFrontendClass * Class = Builder . FindDependency ( Node - > ClassID ) )
{
NodeClassName = Class - > Metadata . GetClassName ( ) . ToString ( ) ;
}
UE_LOG ( LogMetaSound , Display , TEXT ( " Builder '%s' failed to find node input '%s': Node class '%s' contains no such input " ) , * GetName ( ) , * InputName . ToString ( ) , * NodeClassName ) ;
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Builder '%s' failed to find node input '%s': Node with ID '%s' not found " ) , * GetName ( ) , * InputName . ToString ( ) , * NodeHandle . NodeID . ToString ( ) ) ;
2023-03-07 17:01:52 -05:00
}
2023-03-23 14:04:36 -04:00
2023-03-07 17:01:52 -05:00
OutResult = EMetaSoundBuilderResult : : Failed ;
return { } ;
}
2023-03-23 14:04:36 -04:00
TArray < FMetaSoundBuilderNodeInputHandle > UMetaSoundBuilderBase : : FindNodeInputs ( const FMetaSoundNodeHandle & NodeHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
return FindNodeInputsByDataType ( NodeHandle , OutResult , { } ) ;
}
2023-03-23 14:04:36 -04:00
TArray < FMetaSoundBuilderNodeInputHandle > UMetaSoundBuilderBase : : FindNodeInputsByDataType ( const FMetaSoundNodeHandle & NodeHandle , EMetaSoundBuilderResult & OutResult , FName DataType )
2023-03-07 17:01:52 -05:00
{
TArray < FMetaSoundBuilderNodeInputHandle > FoundVertices ;
if ( Builder . ContainsNode ( NodeHandle . NodeID ) )
{
TArray < const FMetasoundFrontendVertex * > Vertices = Builder . FindNodeInputs ( NodeHandle . NodeID , DataType ) ;
Algo : : Transform ( Vertices , FoundVertices , [ & NodeHandle ] ( const FMetasoundFrontendVertex * Vertex )
{
2023-04-10 17:45:18 -04:00
return FMetaSoundBuilderNodeInputHandle ( NodeHandle . NodeID , Vertex - > VertexID ) ;
2023-03-07 17:01:52 -05:00
} ) ;
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Failed to find node inputs by data type with builder '%s'. Node of with ID '%s' not found " ) , * GetName ( ) , * NodeHandle . NodeID . ToString ( ) ) ;
OutResult = EMetaSoundBuilderResult : : Failed ;
}
return FoundVertices ;
}
2023-03-23 14:04:36 -04:00
FMetaSoundBuilderNodeOutputHandle UMetaSoundBuilderBase : : FindNodeOutputByName ( const FMetaSoundNodeHandle & NodeHandle , FName OutputName , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
if ( const FMetasoundFrontendNode * Node = Builder . FindNode ( NodeHandle . NodeID ) )
{
const TArray < FMetasoundFrontendVertex > & OutputVertices = Node - > Interface . Outputs ;
auto FindByNamePredicate = [ & OutputName ] ( const FMetasoundFrontendVertex & Vertex ) { return Vertex . Name = = OutputName ; } ;
if ( const FMetasoundFrontendVertex * Output = OutputVertices . FindByPredicate ( FindByNamePredicate ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
2023-04-10 17:45:18 -04:00
return FMetaSoundBuilderNodeOutputHandle ( Node - > GetID ( ) , Output - > VertexID ) ;
2023-03-07 17:01:52 -05:00
}
2023-03-23 14:04:36 -04:00
FString NodeClassName = TEXT ( " N/A " ) ;
if ( const FMetasoundFrontendClass * Class = Builder . FindDependency ( Node - > ClassID ) )
{
NodeClassName = Class - > Metadata . GetClassName ( ) . ToString ( ) ;
}
UE_LOG ( LogMetaSound , Display , TEXT ( " Builder '%s' failed to find node output '%s': Node class '%s' contains no such output " ) , * GetName ( ) , * OutputName . ToString ( ) , * NodeClassName ) ;
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Builder '%s' failed to find node output '%s': Node with ID '%s' not found " ) , * GetName ( ) , * OutputName . ToString ( ) , * NodeHandle . NodeID . ToString ( ) ) ;
2023-03-07 17:01:52 -05:00
}
OutResult = EMetaSoundBuilderResult : : Failed ;
return { } ;
}
2023-03-23 14:04:36 -04:00
TArray < FMetaSoundBuilderNodeOutputHandle > UMetaSoundBuilderBase : : FindNodeOutputs ( const FMetaSoundNodeHandle & NodeHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
return FindNodeOutputsByDataType ( NodeHandle , OutResult , { } ) ;
}
2023-03-23 14:04:36 -04:00
TArray < FMetaSoundBuilderNodeOutputHandle > UMetaSoundBuilderBase : : FindNodeOutputsByDataType ( const FMetaSoundNodeHandle & NodeHandle , EMetaSoundBuilderResult & OutResult , FName DataType )
2023-03-07 17:01:52 -05:00
{
TArray < FMetaSoundBuilderNodeOutputHandle > FoundVertices ;
if ( Builder . ContainsNode ( NodeHandle . NodeID ) )
{
TArray < const FMetasoundFrontendVertex * > Vertices = Builder . FindNodeOutputs ( NodeHandle . NodeID , DataType ) ;
Algo : : Transform ( Vertices , FoundVertices , [ & NodeHandle ] ( const FMetasoundFrontendVertex * Vertex )
{
2023-04-10 17:45:18 -04:00
return FMetaSoundBuilderNodeOutputHandle ( NodeHandle . NodeID , Vertex - > VertexID ) ;
2023-03-07 17:01:52 -05:00
} ) ;
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Failed to find node outputs by data type with builder '%s'. Node of with ID '%s' not found " ) , * GetName ( ) , * NodeHandle . NodeID . ToString ( ) ) ;
OutResult = EMetaSoundBuilderResult : : Failed ;
}
return FoundVertices ;
}
2023-03-23 14:04:36 -04:00
TArray < FMetaSoundNodeHandle > UMetaSoundBuilderBase : : FindInterfaceInputNodes ( FName InterfaceName , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
TArray < FMetaSoundNodeHandle > NodeHandles ;
TArray < const FMetasoundFrontendNode * > Nodes ;
if ( Builder . FindInterfaceInputNodes ( InterfaceName , Nodes ) )
{
Algo : : Transform ( Nodes , NodeHandles , [ this ] ( const FMetasoundFrontendNode * Node )
{
check ( Node ) ;
return FMetaSoundNodeHandle { Node - > GetID ( ) } ;
} ) ;
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " '%s' interface not found on builder '%s'. No input nodes returned " ) , * InterfaceName . ToString ( ) , * GetName ( ) ) ;
OutResult = EMetaSoundBuilderResult : : Failed ;
}
return NodeHandles ;
}
2023-03-23 14:04:36 -04:00
TArray < FMetaSoundNodeHandle > UMetaSoundBuilderBase : : FindInterfaceOutputNodes ( FName InterfaceName , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
TArray < FMetaSoundNodeHandle > NodeHandles ;
TArray < const FMetasoundFrontendNode * > Nodes ;
if ( Builder . FindInterfaceOutputNodes ( InterfaceName , Nodes ) )
{
Algo : : Transform ( Nodes , NodeHandles , [ this ] ( const FMetasoundFrontendNode * Node )
{
check ( Node ) ;
return FMetaSoundNodeHandle { Node - > GetID ( ) } ;
} ) ;
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
OutResult = EMetaSoundBuilderResult : : Failed ;
}
return NodeHandles ;
}
2023-03-23 14:04:36 -04:00
FMetaSoundNodeHandle UMetaSoundBuilderBase : : FindGraphInputNode ( FName InputName , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
if ( const FMetasoundFrontendNode * GraphInputNode = Builder . FindGraphInputNode ( InputName ) )
{
2023-06-16 17:55:08 -04:00
OutResult = EMetaSoundBuilderResult : : Succeeded ;
2023-03-07 17:01:52 -05:00
return FMetaSoundNodeHandle { GraphInputNode - > GetID ( ) } ;
}
UE_LOG ( LogMetaSound , Display , TEXT ( " Failed to find graph input by name '%s' with builder '%s' " ) , * InputName . ToString ( ) , * GetName ( ) ) ;
OutResult = EMetaSoundBuilderResult : : Failed ;
return { } ;
}
2023-03-23 14:04:36 -04:00
FMetaSoundNodeHandle UMetaSoundBuilderBase : : FindGraphOutputNode ( FName OutputName , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
if ( const FMetasoundFrontendNode * GraphOutputNode = Builder . FindGraphOutputNode ( OutputName ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
return FMetaSoundNodeHandle { GraphOutputNode - > GetID ( ) } ;
}
UE_LOG ( LogMetaSound , Display , TEXT ( " Failed to find graph output by name '%s' with builder '%s' " ) , * OutputName . ToString ( ) , * GetName ( ) ) ;
OutResult = EMetaSoundBuilderResult : : Failed ;
return { } ;
}
2023-06-16 17:55:08 -04:00
UMetaSoundBuilderDocument * UMetaSoundBuilderBase : : CreateTransientDocumentObject ( ) const
2023-03-09 17:56:53 -05:00
{
2023-06-16 17:55:08 -04:00
UMetaSoundBuilderDocument * DocObject = NewObject < UMetaSoundBuilderDocument > ( ) ;
DocObject - > SetBaseMetaSoundUClass ( GetBuilderUClass ( ) ) ;
return DocObject ;
}
void UMetaSoundBuilderBase : : InitFrontendBuilder ( )
{
UMetaSoundBuilderDocument * DocObject = CreateTransientDocumentObject ( ) ;
Builder = FMetaSoundFrontendDocumentBuilder ( DocObject ) ;
2023-04-04 19:14:26 -04:00
Builder . InitDocument ( ) ;
}
2023-03-07 17:01:52 -05:00
void UMetaSoundBuilderBase : : InitNodeLocations ( )
{
Builder . InitNodeLocations ( ) ;
}
2023-06-16 03:08:48 -04:00
UObject * UMetaSoundBuilderBase : : GetReferencedPresetAsset ( ) const
{
using namespace Metasound : : Frontend ;
if ( ! IsPreset ( ) )
{
return nullptr ;
}
// Find the single external node which is the referenced preset asset,
// and find the asset with its registry key
auto FindExternalNode = [ this ] ( const FMetasoundFrontendNode & Node )
{
const FMetasoundFrontendClass * Class = Builder . FindDependency ( Node . ClassID ) ;
return Class - > Metadata . GetType ( ) = = EMetasoundFrontendClassType : : External ;
} ;
const FMetasoundFrontendNode * Node = Builder . GetDocument ( ) . RootGraph . Graph . Nodes . FindByPredicate ( FindExternalNode ) ;
if ( Node ! = nullptr )
{
const FMetasoundFrontendClass * NodeClass = Builder . FindDependency ( Node - > ClassID ) ;
const FNodeRegistryKey NodeClassRegistryKey = NodeRegistryKey : : CreateKey ( NodeClass - > Metadata ) ;
if ( FMetasoundAssetBase * Asset = IMetaSoundAssetManager : : GetChecked ( ) . TryLoadAssetFromKey ( NodeClassRegistryKey ) )
{
return Asset - > GetOwningAsset ( ) ;
}
}
return nullptr ;
}
2023-03-07 17:01:52 -05:00
bool UMetaSoundBuilderBase : : InterfaceIsDeclared ( FName InterfaceName ) const
{
return Builder . IsInterfaceDeclared ( InterfaceName ) ;
}
bool UMetaSoundBuilderBase : : NodesAreConnected ( const FMetaSoundBuilderNodeOutputHandle & OutputHandle , const FMetaSoundBuilderNodeInputHandle & InputHandle ) const
{
const FMetasoundFrontendEdge Edge = { OutputHandle . NodeID , OutputHandle . VertexID , InputHandle . NodeID , InputHandle . VertexID } ;
return Builder . ContainsEdge ( Edge ) ;
}
bool UMetaSoundBuilderBase : : NodeInputIsConnected ( const FMetaSoundBuilderNodeInputHandle & InputHandle ) const
{
return Builder . IsNodeInputConnected ( InputHandle . NodeID , InputHandle . VertexID ) ;
}
bool UMetaSoundBuilderBase : : NodeOutputIsConnected ( const FMetaSoundBuilderNodeOutputHandle & OutputHandle ) const
{
return Builder . IsNodeOutputConnected ( OutputHandle . NodeID , OutputHandle . VertexID ) ;
}
2023-05-30 14:39:48 -04:00
bool UMetaSoundBuilderBase : : IsPreset ( ) const
{
return Builder . IsPreset ( ) ;
}
void UMetaSoundBuilderBase : : ConvertFromPreset ( EMetaSoundBuilderResult & OutResult )
{
const bool bSuccess = Builder . ConvertFromPreset ( ) ;
OutResult = bSuccess ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-05-10 20:28:39 -04:00
void UMetaSoundBuilderBase : : RemoveGraphInput ( FName Name , EMetaSoundBuilderResult & OutResult )
{
const bool bRemoved = Builder . RemoveGraphInput ( Name ) ;
OutResult = bRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
void UMetaSoundBuilderBase : : RemoveGraphOutput ( FName Name , EMetaSoundBuilderResult & OutResult )
{
const bool bRemoved = Builder . RemoveGraphOutput ( Name ) ;
OutResult = bRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-03-07 17:01:52 -05:00
void UMetaSoundBuilderBase : : RemoveInterface ( FName InterfaceName , EMetaSoundBuilderResult & OutResult )
{
const bool bInterfaceRemoved = Builder . RemoveInterface ( InterfaceName ) ;
OutResult = bInterfaceRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
void UMetaSoundBuilderBase : : RemoveNode ( const FMetaSoundNodeHandle & NodeHandle , EMetaSoundBuilderResult & OutResult )
{
const bool bNodeRemoved = Builder . RemoveNode ( NodeHandle . NodeID ) ;
OutResult = bNodeRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-06-16 17:55:08 -04:00
void UMetaSoundBuilderBase : : RemoveNodeInputDefault ( const FMetaSoundBuilderNodeInputHandle & InputHandle , EMetaSoundBuilderResult & OutResult )
{
const bool bInputDefaultRemoved = Builder . RemoveNodeInputDefault ( InputHandle . NodeID , InputHandle . VertexID ) ;
OutResult = bInputDefaultRemoved ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-06-28 17:05:14 -04:00
void UMetaSoundBuilderBase : : RenameRootGraphClass ( const FMetasoundFrontendClassName & InName )
{
Builder . RenameRootGraphClass ( InName ) ;
}
2023-03-07 17:01:52 -05:00
# if WITH_EDITOR
2023-07-24 17:35:47 -04:00
void UMetaSoundBuilderBase : : ReloadCache ( )
{
Builder . ReloadCache ( ) ;
}
2023-03-07 17:01:52 -05:00
void UMetaSoundBuilderBase : : SetAuthor ( const FString & InAuthor )
{
Builder . SetAuthor ( InAuthor ) ;
}
# endif // WITH_EDITOR
2023-07-31 14:21:10 -04:00
void UMetaSoundBuilderBase : : SetGraphInputDefault ( FName InputName , const FMetasoundFrontendLiteral & Literal , EMetaSoundBuilderResult & OutResult )
{
const bool bInputDefaultSet = Builder . SetGraphInputDefault ( InputName , Literal ) ;
OutResult = bInputDefaultSet ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-03-07 17:01:52 -05:00
void UMetaSoundBuilderBase : : SetNodeInputDefault ( const FMetaSoundBuilderNodeInputHandle & InputHandle , const FMetasoundFrontendLiteral & Literal , EMetaSoundBuilderResult & OutResult )
{
const bool bInputDefaultSet = Builder . SetNodeInputDefault ( InputHandle . NodeID , InputHandle . VertexID , Literal ) ;
OutResult = bInputDefaultSet ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
2023-07-31 14:21:10 -04:00
# if WITH_EDITOR
void UMetaSoundBuilderBase : : SetNodeLocation ( const FMetaSoundNodeHandle & InNodeHandle , const FVector2D & InLocation , EMetaSoundBuilderResult & OutResult )
2023-05-30 14:39:48 -04:00
{
2023-07-31 14:21:10 -04:00
const bool bLocationSet = Builder . SetNodeLocation ( InNodeHandle . NodeID , InLocation ) ;
OutResult = bLocationSet ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
2023-05-30 14:39:48 -04:00
}
2023-07-31 14:21:10 -04:00
# endif // WITH_EDITOR
2023-05-30 14:39:48 -04:00
2023-03-23 14:04:36 -04:00
FMetaSoundNodeHandle UMetaSoundBuilderBase : : FindNodeInputParent ( const FMetaSoundBuilderNodeInputHandle & InputHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
if ( Builder . ContainsNode ( InputHandle . NodeID ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
return FMetaSoundNodeHandle { InputHandle . NodeID } ;
}
OutResult = EMetaSoundBuilderResult : : Failed ;
return { } ;
}
2023-03-23 14:04:36 -04:00
FMetaSoundNodeHandle UMetaSoundBuilderBase : : FindNodeOutputParent ( const FMetaSoundBuilderNodeOutputHandle & OutputHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
if ( Builder . ContainsNode ( OutputHandle . NodeID ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
return FMetaSoundNodeHandle { OutputHandle . NodeID } ;
}
OutResult = EMetaSoundBuilderResult : : Failed ;
return { } ;
}
2023-03-23 14:04:36 -04:00
FMetasoundFrontendVersion UMetaSoundBuilderBase : : FindNodeClassVersion ( const FMetaSoundNodeHandle & NodeHandle , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
if ( const FMetasoundFrontendNode * Node = Builder . FindNode ( NodeHandle . NodeID ) )
{
if ( const FMetasoundFrontendClass * Class = Builder . FindDependency ( Node - > ClassID ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
return FMetasoundFrontendVersion { Class - > Metadata . GetClassName ( ) . GetFullName ( ) , Class - > Metadata . GetVersion ( ) } ;
}
}
OutResult = EMetaSoundBuilderResult : : Failed ;
return FMetasoundFrontendVersion : : GetInvalid ( ) ;
}
2023-06-28 17:05:14 -04:00
FMetasoundFrontendClassName UMetaSoundBuilderBase : : GetRootGraphClassName ( ) const
{
return Builder . GetDocument ( ) . RootGraph . Metadata . GetClassName ( ) ;
}
2023-03-23 14:04:36 -04:00
void UMetaSoundBuilderBase : : GetNodeInputData ( const FMetaSoundBuilderNodeInputHandle & InputHandle , FName & Name , FName & DataType , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
if ( const FMetasoundFrontendVertex * Vertex = Builder . FindNodeInput ( InputHandle . NodeID , InputHandle . VertexID ) )
{
Name = Vertex - > Name ;
DataType = Vertex - > TypeName ;
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
Name = { } ;
DataType = { } ;
OutResult = EMetaSoundBuilderResult : : Failed ;
}
}
2023-06-16 17:55:08 -04:00
FMetasoundFrontendLiteral UMetaSoundBuilderBase : : GetNodeInputDefault ( const FMetaSoundBuilderNodeInputHandle & InputHandle , EMetaSoundBuilderResult & OutResult )
{
if ( const FMetasoundFrontendLiteral * Default = Builder . GetNodeInputDefault ( InputHandle . NodeID , InputHandle . VertexID ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
return * Default ;
}
OutResult = EMetaSoundBuilderResult : : Failed ;
return { } ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderBase : : GetNodeInputClassDefault ( const FMetaSoundBuilderNodeInputHandle & InputHandle , EMetaSoundBuilderResult & OutResult )
{
if ( const FMetasoundFrontendLiteral * Default = Builder . GetNodeInputClassDefault ( InputHandle . NodeID , InputHandle . VertexID ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
return * Default ;
}
OutResult = EMetaSoundBuilderResult : : Failed ;
return { } ;
}
2023-03-23 14:04:36 -04:00
void UMetaSoundBuilderBase : : GetNodeOutputData ( const FMetaSoundBuilderNodeOutputHandle & OutputHandle , FName & Name , FName & DataType , EMetaSoundBuilderResult & OutResult )
2023-03-07 17:01:52 -05:00
{
2023-03-23 14:04:36 -04:00
if ( const FMetasoundFrontendVertex * Vertex = Builder . FindNodeOutput ( OutputHandle . NodeID , OutputHandle . VertexID ) )
2023-03-07 17:01:52 -05:00
{
Name = Vertex - > Name ;
DataType = Vertex - > TypeName ;
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
Name = { } ;
DataType = { } ;
OutResult = EMetaSoundBuilderResult : : Failed ;
}
}
2023-05-30 14:39:48 -04:00
void UMetaSoundBuilderBase : : ConvertToPreset ( const TScriptInterface < IMetaSoundDocumentInterface > & ReferencedNodeClass , EMetaSoundBuilderResult & OutResult )
{
const IMetaSoundDocumentInterface * ReferencedInterface = ReferencedNodeClass . GetInterface ( ) ;
check ( ReferencedInterface ) ;
// Ensure the referenced node class isn't transient
if ( Cast < UMetaSoundBuilderDocument > ( ReferencedInterface ) )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Transient document builders cannot be referenced when converting builder '%s' to a preset. Build the referenced node class an asset first or use an existing asset instead " ) , * GetName ( ) ) ;
OutResult = EMetaSoundBuilderResult : : Failed ;
return ;
}
// Ensure the referenced node class is a matching object type
const UClass & BaseMetaSoundClass = ReferencedInterface - > GetBaseMetaSoundUClass ( ) ;
UObject * ReferencedObject = ReferencedNodeClass . GetObject ( ) ;
if ( ! ReferencedObject | | ( ReferencedObject & & ! ReferencedObject - > IsA ( & BaseMetaSoundClass ) ) )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " The referenced node type must match the base MetaSound class when converting builder '%s' to a preset (ex. source preset must reference another source) " ) , * GetName ( ) ) ;
OutResult = EMetaSoundBuilderResult : : Failed ;
return ;
}
// Ensure the referenced node is registered
if ( FMetasoundAssetBase * ReferencedMetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( ReferencedObject ) )
{
ReferencedMetaSoundAsset - > RegisterGraphWithFrontend ( ) ;
}
const FMetasoundFrontendDocument & ReferencedDocument = ReferencedInterface - > GetDocument ( ) ;
if ( Builder . ConvertToPreset ( ReferencedDocument ) )
{
OutResult = EMetaSoundBuilderResult : : Succeeded ;
}
else
{
OutResult = EMetaSoundBuilderResult : : Failed ;
}
}
2023-06-28 17:05:14 -04:00
void UMetaSoundBuilderBase : : UpdateDependencyClassNames ( const TMap < FMetasoundFrontendClassName , FMetasoundFrontendClassName > & OldToNewReferencedClassNames )
{
Builder . UpdateDependencyClassNames ( OldToNewReferencedClassNames ) ;
}
2023-03-23 14:04:36 -04:00
TScriptInterface < IMetaSoundDocumentInterface > UMetaSoundPatchBuilder : : Build ( UObject * Parent , const FMetaSoundBuilderOptions & InBuilderOptions ) const
2023-03-07 17:01:52 -05:00
{
2023-06-16 17:55:08 -04:00
return & BuildInternal < UMetaSoundPatch > ( Parent , InBuilderOptions ) ;
2023-03-07 17:01:52 -05:00
}
2023-04-06 16:32:00 -04:00
const UClass & UMetaSoundPatchBuilder : : GetBuilderUClass ( ) const
{
return * UMetaSoundPatch : : StaticClass ( ) ;
}
2023-06-16 17:55:08 -04:00
UMetaSoundBuilderBase & UMetaSoundBuilderSubsystem : : AttachBuilderToAssetChecked ( UObject & InObject ) const
2023-03-07 17:01:52 -05:00
{
2023-06-16 17:55:08 -04:00
const UClass * BaseClass = InObject . GetClass ( ) ;
if ( BaseClass = = UMetaSoundSource : : StaticClass ( ) )
{
UMetaSoundSourceBuilder * NewBuilder = AttachSourceBuilderToAsset ( CastChecked < UMetaSoundSource > ( & InObject ) ) ;
return * NewBuilder ;
}
else if ( BaseClass = = UMetaSoundPatch : : StaticClass ( ) )
{
UMetaSoundPatchBuilder * NewBuilder = AttachPatchBuilderToAsset ( CastChecked < UMetaSoundPatch > ( & InObject ) ) ;
return * NewBuilder ;
}
else
{
checkf ( false , TEXT ( " UClass '%s' is not a base MetaSound that supports attachment via the MetaSoundBuilderSubsystem " ) , * BaseClass - > GetFullName ( ) ) ;
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreateTransientBuilder < UMetaSoundPatchBuilder > ( ) ;
}
}
UMetaSoundPatchBuilder * UMetaSoundBuilderSubsystem : : AttachPatchBuilderToAsset ( UMetaSoundPatch * InPatch ) const
{
if ( InPatch )
{
return & AttachBuilderToAssetCheckedPrivate < UMetaSoundPatchBuilder > ( InPatch ) ;
}
return nullptr ;
}
UMetaSoundSourceBuilder * UMetaSoundBuilderSubsystem : : AttachSourceBuilderToAsset ( UMetaSoundSource * InSource ) const
{
if ( InSource )
{
UMetaSoundSourceBuilder & SourceBuilder = AttachBuilderToAssetCheckedPrivate < UMetaSoundSourceBuilder > ( InSource ) ;
SourceBuilder . AuditionSound = InSource ;
return & SourceBuilder ;
}
return nullptr ;
}
void UMetaSoundSourceBuilder : : Audition ( UObject * Parent , UAudioComponent * AudioComponent , FOnCreateAuditionGeneratorHandleDelegate CreateGenerator , bool bLiveUpdatesEnabled )
{
using namespace Metasound : : Engine ;
using namespace Metasound : : Engine : : BuilderSubsystemPrivate ;
2023-03-07 17:01:52 -05:00
using namespace Metasound : : Frontend ;
2023-03-23 14:04:36 -04:00
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundSourceBuilder : : Audition ) ;
2023-03-07 17:01:52 -05:00
if ( ! AudioComponent )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to audition MetaSoundBuilder '%s': No AudioComponent supplied " ) , * GetFullName ( ) ) ;
return ;
}
2023-06-16 17:55:08 -04:00
if ( ! bIsAttached )
2023-03-23 14:04:36 -04:00
{
2023-06-16 17:55:08 -04:00
FMetaSoundBuilderOptions BuilderOptions ;
BuilderOptions . bAddToRegistry = true ;
if ( AuditionSound . IsValid ( ) )
2023-03-07 17:01:52 -05:00
{
2023-06-16 17:55:08 -04:00
BuilderOptions . ExistingMetaSound = AuditionSound . Get ( ) ;
if ( USoundBase * Sound = AudioComponent - > GetSound ( ) )
2023-03-07 17:01:52 -05:00
{
2023-06-16 17:55:08 -04:00
if ( Sound ! = AuditionSound )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " MetaSoundBuilder '%s' supplied AudioComponent with unlinked sound '%s'. Stopping sound and replacing with builder's audition sound. " ) ,
* GetFullName ( ) ,
* Sound - > GetFullName ( ) ) ;
}
2023-03-07 17:01:52 -05:00
}
}
2023-06-16 17:55:08 -04:00
else
{
BuilderOptions . Name = MakeUniqueObjectName ( nullptr , UMetaSoundSource : : StaticClass ( ) , FName ( GetName ( ) + TEXT ( " _Audition " ) ) ) ;
}
AuditionSound = & BuildInternal < UMetaSoundSource > ( Parent , BuilderOptions ) ;
2023-03-23 14:04:36 -04:00
}
2023-03-07 17:01:52 -05:00
2023-06-16 17:55:08 -04:00
AudioComponent - > SetSound ( AuditionSound . Get ( ) ) ;
2023-07-24 19:49:03 -04:00
const bool bEnableDynamicGenerators = bLiveUpdatesEnabled ;
2023-06-16 17:55:08 -04:00
AuditionSound - > EnableDynamicGenerators ( bEnableDynamicGenerators ) ;
2023-03-07 17:01:52 -05:00
if ( CreateGenerator . IsBound ( ) )
{
UMetasoundGeneratorHandle * NewHandle = UMetasoundGeneratorHandle : : CreateMetaSoundGeneratorHandle ( AudioComponent ) ;
checkf ( NewHandle , TEXT ( " BindToGeneratorDelegate Failed when attempting to audition MetaSoundSource builder '%s' " ) , * GetName ( ) ) ;
CreateGenerator . Execute ( NewHandle ) ;
}
AudioComponent - > Play ( ) ;
}
2023-06-16 17:55:08 -04:00
bool UMetaSoundSourceBuilder : : ExecuteAuditionableTransaction ( FAuditionableTransaction Transaction ) const
{
using namespace Metasound : : Engine : : BuilderSubsystemPrivate ;
using namespace Metasound : : DynamicGraph ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundSourceBuilder : : ExecuteAuditionableTransaction ) ;
2023-07-24 19:49:03 -04:00
if ( AuditionSound . IsValid ( ) )
2023-06-16 17:55:08 -04:00
{
TSharedPtr < FDynamicOperatorTransactor > Transactor = AuditionSound - > GetDynamicGeneratorTransactor ( ) ;
if ( Transactor . IsValid ( ) )
{
return Transaction ( * Transactor ) ;
}
}
return false ;
}
2023-03-23 14:04:36 -04:00
TScriptInterface < IMetaSoundDocumentInterface > UMetaSoundSourceBuilder : : Build ( UObject * Parent , const FMetaSoundBuilderOptions & InBuilderOptions ) const
2023-03-07 17:01:52 -05:00
{
2023-06-16 17:55:08 -04:00
return & BuildInternal < UMetaSoundSource > ( Parent , InBuilderOptions ) ;
}
void UMetaSoundSourceBuilder : : InitFrontendBuilder ( )
{
using namespace Metasound : : Frontend ;
TSharedRef < FDocumentModifyDelegates > DocumentDelegates = MakeShared < FDocumentModifyDelegates > ( ) ;
InitDelegates ( * DocumentDelegates ) ;
UMetaSoundBuilderDocument * DocObject = CreateTransientDocumentObject ( ) ;
Builder = FMetaSoundFrontendDocumentBuilder ( DocObject , DocumentDelegates ) ;
Builder . InitDocument ( ) ;
2023-03-07 17:01:52 -05:00
}
const Metasound : : Engine : : FOutputAudioFormatInfoPair * UMetaSoundSourceBuilder : : FindOutputAudioFormatInfo ( ) const
{
using namespace Metasound : : Engine ;
const FOutputAudioFormatInfoMap & FormatInfo = GetOutputAudioFormatInfo ( ) ;
auto Predicate = [ this ] ( const FOutputAudioFormatInfoPair & Pair )
{
const FMetasoundFrontendDocument & Document = Builder . GetDocument ( ) ;
return Document . Interfaces . Contains ( Pair . Value . InterfaceVersion ) ;
} ;
return Algo : : FindByPredicate ( FormatInfo , Predicate ) ;
}
2023-04-06 16:32:00 -04:00
const UClass & UMetaSoundSourceBuilder : : GetBuilderUClass ( ) const
{
return * UMetaSoundSource : : StaticClass ( ) ;
}
2023-06-16 17:55:08 -04:00
bool UMetaSoundSourceBuilder : : GetLiveUpdatesEnabled ( ) const
{
using namespace Metasound : : Engine : : BuilderSubsystemPrivate ;
if ( ! AuditionSound . IsValid ( ) )
{
return false ;
}
return AuditionSound - > GetDynamicGeneratorTransactor ( ) . IsValid ( ) ;
}
void UMetaSoundSourceBuilder : : InitDelegates ( Metasound : : Frontend : : FDocumentModifyDelegates & OutDocumentDelegates ) const
{
OutDocumentDelegates . EdgeDelegates . OnEdgeAdded . AddUObject ( this , & UMetaSoundSourceBuilder : : OnEdgeAdded ) ;
OutDocumentDelegates . EdgeDelegates . OnRemovingEdge . AddUObject ( this , & UMetaSoundSourceBuilder : : OnRemovingEdge ) ;
OutDocumentDelegates . InterfaceDelegates . OnInputAdded . AddUObject ( this , & UMetaSoundSourceBuilder : : OnInputAdded ) ;
OutDocumentDelegates . InterfaceDelegates . OnOutputAdded . AddUObject ( this , & UMetaSoundSourceBuilder : : OnOutputAdded ) ;
OutDocumentDelegates . InterfaceDelegates . OnRemovingInput . AddUObject ( this , & UMetaSoundSourceBuilder : : OnRemovingInput ) ;
OutDocumentDelegates . InterfaceDelegates . OnRemovingOutput . AddUObject ( this , & UMetaSoundSourceBuilder : : OnRemovingOutput ) ;
OutDocumentDelegates . NodeDelegates . OnNodeAdded . AddUObject ( this , & UMetaSoundSourceBuilder : : OnNodeAdded ) ;
OutDocumentDelegates . NodeDelegates . OnNodeInputLiteralSet . AddUObject ( this , & UMetaSoundSourceBuilder : : OnNodeInputLiteralSet ) ;
OutDocumentDelegates . NodeDelegates . OnRemovingNode . AddUObject ( this , & UMetaSoundSourceBuilder : : OnRemovingNode ) ;
OutDocumentDelegates . NodeDelegates . OnRemovingNodeInputLiteral . AddUObject ( this , & UMetaSoundSourceBuilder : : OnRemovingNodeInputLiteral ) ;
}
void UMetaSoundSourceBuilder : : OnEdgeAdded ( int32 EdgeIndex ) const
{
using namespace Metasound : : DynamicGraph ;
const FMetasoundFrontendDocument & Doc = Builder . GetDocument ( ) ;
const FMetasoundFrontendEdge & NewEdge = Doc . RootGraph . Graph . Edges [ EdgeIndex ] ;
ExecuteAuditionableTransaction ( [ this , & NewEdge ] ( Metasound : : DynamicGraph : : FDynamicOperatorTransactor & Transactor )
{
const FMetaSoundFrontendDocumentBuilder & Builder = GetConstBuilder ( ) ;
const FMetasoundFrontendVertex * FromNodeOutput = Builder . FindNodeOutput ( NewEdge . FromNodeID , NewEdge . FromVertexID ) ;
const FMetasoundFrontendVertex * ToNodeInput = Builder . FindNodeInput ( NewEdge . ToNodeID , NewEdge . ToVertexID ) ;
if ( FromNodeOutput & & ToNodeInput )
{
Transactor . AddDataEdge ( NewEdge . FromNodeID , FromNodeOutput - > Name , NewEdge . ToNodeID , ToNodeInput - > Name ) ;
return true ;
}
return false ;
} ) ;
}
TOptional < Metasound : : FAnyDataReference > UMetaSoundSourceBuilder : : CreateDataReference ( const Metasound : : FOperatorSettings & InOperatorSettings , const Metasound : : FLiteral & InLiteral , Metasound : : EDataReferenceAccessType AccessType )
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
// TODO: move to TFunctionRef
const FName DataType = GetMetasoundDataTypeName < float > ( ) ;
return IDataTypeRegistry : : Get ( ) . CreateDataReference ( DataType , AccessType , InLiteral , InOperatorSettings ) ;
} ;
void UMetaSoundSourceBuilder : : OnInputAdded ( int32 InputIndex ) const
{
using namespace Metasound : : DynamicGraph ;
ExecuteAuditionableTransaction ( [ this , InputIndex ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
const FMetasoundFrontendDocument & Doc = Builder . GetDocument ( ) ;
const FMetasoundFrontendGraphClass & GraphClass = Doc . RootGraph ;
const FMetasoundFrontendClassInput & NewInput = GraphClass . Interface . Inputs [ InputIndex ] ;
const FLiteral NewInputLiteral = NewInput . DefaultLiteral . ToLiteral ( NewInput . TypeName ) ;
Transactor . AddInputDataDestination ( NewInput . NodeID , NewInput . Name , NewInputLiteral , & UMetaSoundSourceBuilder : : CreateDataReference ) ;
return true ;
} ) ;
}
void UMetaSoundSourceBuilder : : OnNodeAdded ( int32 NodeIndex ) const
{
using namespace Metasound : : DynamicGraph ;
ExecuteAuditionableTransaction ( [ this , NodeIndex ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
const FMetasoundFrontendDocument & Doc = Builder . GetDocument ( ) ;
const FMetasoundFrontendGraphClass & GraphClass = Doc . RootGraph ;
const FMetasoundFrontendNode & AddedNode = GraphClass . Graph . Nodes [ NodeIndex ] ;
const Metasound : : FNodeInitData InitData { AddedNode . Name , AddedNode . GetID ( ) } ;
const FMetasoundFrontendClass * NodeClass = Builder . FindDependency ( AddedNode . ClassID ) ;
checkf ( NodeClass , TEXT ( " Node successfully added to graph but document is missing associated dependency " ) ) ;
auto MatchesVertexNodeID = [ & InitData ] ( const FMetasoundFrontendClassVertex & Vertex ) { return Vertex . NodeID = = InitData . InstanceID ; } ;
switch ( NodeClass - > Metadata . GetType ( ) )
{
case EMetasoundFrontendClassType : : Input :
case EMetasoundFrontendClassType : : Output :
case EMetasoundFrontendClassType : : External :
{
const FNodeRegistryKey & ClassKey = NodeRegistryKey : : CreateKey ( NodeClass - > Metadata ) ;
FMetasoundFrontendRegistryContainer & Registry = * FMetasoundFrontendRegistryContainer : : Get ( ) ;
TUniquePtr < INode > NewNode = Registry . CreateNode ( ClassKey , InitData ) ;
Transactor . AddNode ( InitData . InstanceID , MoveTemp ( NewNode ) ) ;
return true ;
}
break ;
case EMetasoundFrontendClassType : : Graph :
case EMetasoundFrontendClassType : : Invalid :
case EMetasoundFrontendClassType : : Literal :
case EMetasoundFrontendClassType : : Template :
case EMetasoundFrontendClassType : : Variable :
case EMetasoundFrontendClassType : : VariableAccessor :
case EMetasoundFrontendClassType : : VariableDeferredAccessor :
case EMetasoundFrontendClassType : : VariableMutator :
default :
{
static_assert ( static_cast < int32 > ( EMetasoundFrontendClassType : : Invalid ) = = 10 , " Possible missing EMetasoundFrontendClassType case coverage " ) ;
UE_LOG ( LogMetaSound , Error , TEXT ( " Builder '%s' Audition Error: Addition of node was not propagated to active runtime graph: Runtime manipualtion of node ClassType unsupported. " ) , * GetName ( ) ) ;
return false ;
}
}
} ) ;
}
void UMetaSoundSourceBuilder : : OnNodeInputLiteralSet ( int32 NodeIndex , int32 VertexIndex , int32 LiteralIndex ) const
{
using namespace Metasound : : DynamicGraph ;
2023-07-28 16:20:02 -04:00
const FMetasoundFrontendGraphClass & GraphClass = Builder . GetDocument ( ) . RootGraph ;
const FMetasoundFrontendNode & Node = GraphClass . Graph . Nodes [ NodeIndex ] ;
const FMetasoundFrontendVertex & Input = Node . Interface . Inputs [ VertexIndex ] ;
// Only send the literal down if not connected, as the graph core layer will disconnect.
if ( ! Builder . IsNodeInputConnected ( Node . GetID ( ) , Input . VertexID ) )
2023-06-16 17:55:08 -04:00
{
2023-07-28 16:20:02 -04:00
ExecuteAuditionableTransaction ( [ this , & Node , & Input , & LiteralIndex ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound ;
using namespace Metasound : : Engine ;
2023-06-16 17:55:08 -04:00
2023-07-28 16:20:02 -04:00
const FMetasoundFrontendLiteral & InputDefault = Node . InputLiterals [ LiteralIndex ] . Value ;
TUniquePtr < INode > LiteralNode = BuilderSubsystemPrivate : : CreateDynamicNodeFromFrontendLiteral ( Input . TypeName , InputDefault ) ;
Transactor . SetValue ( Node . GetID ( ) , Input . Name , MoveTemp ( LiteralNode ) ) ;
return true ;
} ) ;
}
2023-06-16 17:55:08 -04:00
}
void UMetaSoundSourceBuilder : : OnOutputAdded ( int32 OutputIndex ) const
{
using namespace Metasound : : DynamicGraph ;
ExecuteAuditionableTransaction ( [ this , OutputIndex ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound : : Frontend ;
const FMetasoundFrontendDocument & Doc = Builder . GetDocument ( ) ;
const FMetasoundFrontendGraphClass & GraphClass = Doc . RootGraph ;
const FMetasoundFrontendClassOutput & NewOutput = GraphClass . Interface . Outputs [ OutputIndex ] ;
Transactor . AddOutputDataSource ( NewOutput . NodeID , NewOutput . Name ) ;
return true ;
} ) ;
}
void UMetaSoundSourceBuilder : : OnRemovingEdge ( int32 EdgeIndex ) const
{
using namespace Metasound : : DynamicGraph ;
const FMetasoundFrontendDocument & Doc = Builder . GetDocument ( ) ;
const FMetasoundFrontendEdge & EdgeBeingRemoved = Doc . RootGraph . Graph . Edges [ EdgeIndex ] ;
ExecuteAuditionableTransaction ( [ this , EdgeBeingRemoved ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound ;
using namespace Metasound : : Engine ;
const FMetaSoundFrontendDocumentBuilder & Builder = GetConstBuilder ( ) ;
const FMetasoundFrontendVertex * FromNodeOutput = Builder . FindNodeOutput ( EdgeBeingRemoved . FromNodeID , EdgeBeingRemoved . FromVertexID ) ;
const FMetasoundFrontendVertex * ToNodeInput = Builder . FindNodeInput ( EdgeBeingRemoved . ToNodeID , EdgeBeingRemoved . ToVertexID ) ;
if ( FromNodeOutput & & ToNodeInput )
{
const FMetasoundFrontendLiteral * InputDefault = Builder . GetNodeInputDefault ( EdgeBeingRemoved . ToNodeID , EdgeBeingRemoved . ToVertexID ) ;
if ( ! InputDefault )
{
InputDefault = Builder . GetNodeInputClassDefault ( EdgeBeingRemoved . ToNodeID , EdgeBeingRemoved . ToVertexID ) ;
}
if ( ensureAlwaysMsgf ( InputDefault , TEXT ( " Could not dynamically assign default literal upon removing edge: literal should be assigned by either the frontend document's input or the class definition " ) ) )
{
TUniquePtr < INode > LiteralNode = BuilderSubsystemPrivate : : CreateDynamicNodeFromFrontendLiteral ( ToNodeInput - > TypeName , * InputDefault ) ;
Transactor . RemoveDataEdge ( EdgeBeingRemoved . FromNodeID , FromNodeOutput - > Name , EdgeBeingRemoved . ToNodeID , ToNodeInput - > Name , MoveTemp ( LiteralNode ) ) ;
return true ;
}
}
return false ;
} ) ;
}
void UMetaSoundSourceBuilder : : OnRemovingInput ( int32 InputIndex ) const
{
using namespace Metasound : : DynamicGraph ;
ExecuteAuditionableTransaction ( [ this , InputIndex ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound : : Frontend ;
const FMetasoundFrontendDocument & Doc = Builder . GetDocument ( ) ;
const FMetasoundFrontendGraphClass & GraphClass = Doc . RootGraph ;
const FMetasoundFrontendClassInput & InputBeingRemoved = GraphClass . Interface . Inputs [ InputIndex ] ;
Transactor . RemoveInputDataDestination ( InputBeingRemoved . Name ) ;
return true ;
} ) ;
}
void UMetaSoundSourceBuilder : : OnRemovingNode ( int32 NodeIndex ) const
{
using namespace Metasound : : DynamicGraph ;
ExecuteAuditionableTransaction ( [ this , NodeIndex ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound : : Frontend ;
const FMetasoundFrontendDocument & Doc = Builder . GetDocument ( ) ;
const FMetasoundFrontendGraphClass & GraphClass = Doc . RootGraph ;
const FMetasoundFrontendNode & NodeBeingRemoved = GraphClass . Graph . Nodes [ NodeIndex ] ;
const FGuid & NodeID = NodeBeingRemoved . GetID ( ) ;
Transactor . RemoveNode ( NodeID ) ;
return true ;
} ) ;
}
void UMetaSoundSourceBuilder : : OnRemovingNodeInputLiteral ( int32 NodeIndex , int32 VertexIndex , int32 LiteralIndex ) const
{
using namespace Metasound : : DynamicGraph ;
ExecuteAuditionableTransaction ( [ this , & NodeIndex , & VertexIndex , & LiteralIndex ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound ;
using namespace Metasound : : Engine ;
using namespace Metasound : : Frontend ;
const TArray < FMetasoundFrontendNode > & Nodes = Builder . GetDocument ( ) . RootGraph . Graph . Nodes ;
const FMetasoundFrontendNode & Node = Nodes [ NodeIndex ] ;
const FMetasoundFrontendVertex & Input = Node . Interface . Inputs [ VertexIndex ] ;
const FMetasoundFrontendLiteral * InputDefault = Builder . GetNodeInputClassDefault ( Node . GetID ( ) , Input . VertexID ) ;
if ( ensureAlwaysMsgf ( InputDefault , TEXT ( " Could not dynamically assign default literal from class definition upon removing input literal: document's dependency entry invalid and has no default assigned " ) ) )
{
TUniquePtr < INode > LiteralNode = BuilderSubsystemPrivate : : CreateDynamicNodeFromFrontendLiteral ( Input . TypeName , * InputDefault ) ;
Transactor . SetValue ( Node . GetID ( ) , Input . Name , MoveTemp ( LiteralNode ) ) ;
return true ;
}
return false ;
} ) ;
}
void UMetaSoundSourceBuilder : : OnRemovingOutput ( int32 OutputIndex ) const
{
using namespace Metasound : : DynamicGraph ;
ExecuteAuditionableTransaction ( [ this , OutputIndex ] ( FDynamicOperatorTransactor & Transactor )
{
using namespace Metasound : : Frontend ;
const FMetasoundFrontendDocument & Doc = Builder . GetDocument ( ) ;
const FMetasoundFrontendGraphClass & GraphClass = Doc . RootGraph ;
const FMetasoundFrontendClassOutput & OutputBeingRemoved = GraphClass . Interface . Outputs [ OutputIndex ] ;
Transactor . RemoveOutputDataSource ( OutputBeingRemoved . Name ) ;
return true ;
} ) ;
}
2023-03-07 17:01:52 -05:00
void UMetaSoundSourceBuilder : : SetFormat ( EMetaSoundOutputAudioFormat OutputFormat , EMetaSoundBuilderResult & OutResult )
{
using namespace Metasound : : Engine ;
using namespace Metasound : : Frontend ;
// Convert to non-preset MetaSoundSource since interface data is being altered
Builder . ConvertFromPreset ( ) ;
const FOutputAudioFormatInfoMap & FormatMap = GetOutputAudioFormatInfo ( ) ;
// Determine which interfaces to add and remove from the document due to the
// output format being changed.
TArray < FMetasoundFrontendVersion > OutputFormatsToAdd ;
if ( const FOutputAudioFormatInfo * FormatInfo = FormatMap . Find ( OutputFormat ) )
{
OutputFormatsToAdd . Add ( FormatInfo - > InterfaceVersion ) ;
}
TArray < FMetasoundFrontendVersion > OutputFormatsToRemove ;
const FMetasoundFrontendDocument & Document = GetConstBuilder ( ) . GetDocument ( ) ;
for ( const FOutputAudioFormatInfoPair & Pair : FormatMap )
{
const FMetasoundFrontendVersion & FormatVersion = Pair . Value . InterfaceVersion ;
if ( Document . Interfaces . Contains ( FormatVersion ) )
{
if ( ! OutputFormatsToAdd . Contains ( FormatVersion ) )
{
OutputFormatsToRemove . Add ( FormatVersion ) ;
}
}
}
2023-05-10 20:28:39 -04:00
FModifyInterfaceOptions Options ( OutputFormatsToRemove , OutputFormatsToAdd ) ;
# if WITH_EDITORONLY_DATA
Options . bSetDefaultNodeLocations = true ;
# endif // WITH_EDITORONLY_DATA
const bool bSuccess = Builder . ModifyInterfaces ( MoveTemp ( Options ) ) ;
2023-03-07 17:01:52 -05:00
OutResult = bSuccess ? EMetaSoundBuilderResult : : Succeeded : EMetaSoundBuilderResult : : Failed ;
}
UMetaSoundPatchBuilder * UMetaSoundBuilderSubsystem : : CreatePatchBuilder ( FName BuilderName , EMetaSoundBuilderResult & OutResult )
{
2023-06-22 14:43:52 -04:00
OutResult = EMetaSoundBuilderResult : : Succeeded ;
return & Metasound : : Engine : : BuilderSubsystemPrivate : : CreateTransientBuilder < UMetaSoundPatchBuilder > ( BuilderName ) ;
2023-03-07 17:01:52 -05:00
}
UMetaSoundSourceBuilder * UMetaSoundBuilderSubsystem : : CreateSourceBuilder (
FName BuilderName ,
FMetaSoundBuilderNodeOutputHandle & OnPlayNodeOutput ,
FMetaSoundBuilderNodeInputHandle & OnFinishedNodeInput ,
TArray < FMetaSoundBuilderNodeInputHandle > & AudioOutNodeInputs ,
EMetaSoundBuilderResult & OutResult ,
EMetaSoundOutputAudioFormat OutputFormat ,
bool bIsOneShot )
{
using namespace Metasound : : Frontend ;
using namespace Metasound : : Engine : : BuilderSubsystemPrivate ;
OnPlayNodeOutput = { } ;
OnFinishedNodeInput = { } ;
AudioOutNodeInputs . Reset ( ) ;
2023-06-22 14:43:52 -04:00
UMetaSoundSourceBuilder & NewBuilder = CreateTransientBuilder < UMetaSoundSourceBuilder > ( BuilderName ) ;
2023-03-07 17:01:52 -05:00
2023-04-06 16:51:46 -04:00
OutResult = EMetaSoundBuilderResult : : Succeeded ;
if ( OutputFormat ! = EMetaSoundOutputAudioFormat : : Mono )
2023-04-05 17:01:55 -04:00
{
2023-04-06 16:51:46 -04:00
NewBuilder . SetFormat ( OutputFormat , OutResult ) ;
2023-03-07 17:01:52 -05:00
}
2023-04-05 17:01:55 -04:00
2023-04-06 16:51:46 -04:00
if ( OutResult = = EMetaSoundBuilderResult : : Succeeded )
2023-03-07 17:01:52 -05:00
{
TArray < FMetaSoundNodeHandle > AudioOutputNodes ;
2023-04-06 16:51:46 -04:00
if ( const Metasound : : Engine : : FOutputAudioFormatInfoPair * FormatInfo = NewBuilder . FindOutputAudioFormatInfo ( ) )
2023-03-07 17:01:52 -05:00
{
2023-03-09 17:56:53 -05:00
AudioOutputNodes = NewBuilder . FindInterfaceOutputNodes ( FormatInfo - > Value . InterfaceVersion . Name , OutResult ) ;
2023-03-07 17:01:52 -05:00
}
2023-04-06 16:51:46 -04:00
else
{
OutResult = EMetaSoundBuilderResult : : Failed ;
}
2023-03-07 17:01:52 -05:00
2023-04-06 16:51:46 -04:00
if ( OutResult = = EMetaSoundBuilderResult : : Succeeded )
2023-03-07 17:01:52 -05:00
{
Algo : : Transform ( AudioOutputNodes , AudioOutNodeInputs , [ & NewBuilder , & BuilderName ] ( const FMetaSoundNodeHandle & AudioOutputNode ) - > FMetaSoundBuilderNodeInputHandle
{
EMetaSoundBuilderResult Result ;
2023-03-09 17:56:53 -05:00
TArray < FMetaSoundBuilderNodeInputHandle > Inputs = NewBuilder . FindNodeInputs ( AudioOutputNode , Result ) ;
2023-03-07 17:01:52 -05:00
if ( ! Inputs . IsEmpty ( ) )
{
return Inputs . Last ( ) ;
}
UE_LOG ( LogMetaSound , Error , TEXT ( " Builder '%s' Creation Error: Failed to find expected audio output node input vertex. Returned vertices set may be incomplete. " ) , * BuilderName . ToString ( ) ) ;
return { } ;
} ) ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Builder '%s' Creation Error: Failed to find expected audio output format and/or associated output nodes. " ) , * BuilderName . ToString ( ) ) ;
return nullptr ;
}
}
else
{
2023-04-06 16:51:46 -04:00
UE_LOG ( LogMetaSound , Error , TEXT ( " Builder '%s' Creation Error: Failed to set output format when initializing. " ) , * BuilderName . ToString ( ) ) ;
2023-03-07 17:01:52 -05:00
return nullptr ;
}
{
2023-03-09 17:56:53 -05:00
FMetaSoundNodeHandle OnPlayNode = NewBuilder . FindGraphInputNode ( SourceInterface : : Inputs : : OnPlay , OutResult ) ;
2023-03-07 17:01:52 -05:00
if ( OutResult = = EMetaSoundBuilderResult : : Failed )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Builder '%s' Creation Error: Failed to add required interface '%s' when attempting to create MetaSound Source Builder " ) , * BuilderName . ToString ( ) , * SourceInterface : : GetVersion ( ) . ToString ( ) ) ;
return nullptr ;
}
2023-03-09 17:56:53 -05:00
TArray < FMetaSoundBuilderNodeOutputHandle > Outputs = NewBuilder . FindNodeOutputs ( OnPlayNode , OutResult ) ;
2023-03-07 17:01:52 -05:00
if ( OutResult = = EMetaSoundBuilderResult : : Failed )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Builder '%s' Creation Error: Failed to find output vertex for 'OnPlay' input node when attempting to create MetaSound Source Builder " ) , * BuilderName . ToString ( ) ) ;
return nullptr ;
}
check ( ! Outputs . IsEmpty ( ) ) ;
OnPlayNodeOutput = Outputs . Last ( ) ;
}
2023-04-06 16:51:46 -04:00
if ( bIsOneShot )
2023-03-07 17:01:52 -05:00
{
2023-04-06 16:51:46 -04:00
FMetaSoundNodeHandle OnFinishedNode = NewBuilder . FindGraphOutputNode ( SourceOneShotInterface : : Outputs : : OnFinished , OutResult ) ;
if ( OutResult = = EMetaSoundBuilderResult : : Failed )
2023-03-07 17:01:52 -05:00
{
2023-04-06 16:51:46 -04:00
UE_LOG ( LogMetaSound , Error , TEXT ( " Builder '%s' Creation Error: Failed to add '%s' interface; interface definition may not be registered. " ) , * BuilderName . ToString ( ) , * SourceOneShotInterface : : GetVersion ( ) . ToString ( ) ) ;
2023-03-07 17:01:52 -05:00
}
2023-04-06 16:51:46 -04:00
TArray < FMetaSoundBuilderNodeInputHandle > Inputs = NewBuilder . FindNodeInputs ( OnFinishedNode , OutResult ) ;
if ( OutResult = = EMetaSoundBuilderResult : : Failed )
2023-03-07 17:01:52 -05:00
{
2023-04-06 16:51:46 -04:00
UE_LOG ( LogMetaSound , Error , TEXT ( " Builder '%s' Creation Error: Failed to find input vertex for 'OnFinished' output node when attempting to create MetaSound Source Builder " ) , * BuilderName . ToString ( ) ) ;
return nullptr ;
2023-03-07 17:01:52 -05:00
}
2023-04-06 16:51:46 -04:00
check ( ! Inputs . IsEmpty ( ) ) ;
OnFinishedNodeInput = Inputs . Last ( ) ;
}
else
{
NewBuilder . RemoveInterface ( SourceOneShotInterface : : GetVersion ( ) . Name , OutResult ) ;
2023-03-07 17:01:52 -05:00
}
2023-03-09 17:56:53 -05:00
return & NewBuilder ;
2023-03-07 17:01:52 -05:00
}
2023-05-30 14:39:48 -04:00
UMetaSoundPatchBuilder * UMetaSoundBuilderSubsystem : : CreatePatchPresetBuilder ( FName BuilderName , const TScriptInterface < IMetaSoundDocumentInterface > & ReferencedNodeClass , EMetaSoundBuilderResult & OutResult )
{
2023-06-22 14:43:52 -04:00
UMetaSoundPatchBuilder & Builder = Metasound : : Engine : : BuilderSubsystemPrivate : : CreateTransientBuilder < UMetaSoundPatchBuilder > ( BuilderName ) ;
2023-05-30 14:39:48 -04:00
Builder . ConvertToPreset ( ReferencedNodeClass , OutResult ) ;
return & Builder ;
}
2023-06-16 03:08:48 -04:00
UMetaSoundBuilderBase & UMetaSoundBuilderSubsystem : : CreatePresetBuilder ( FName BuilderName , const TScriptInterface < IMetaSoundDocumentInterface > & ReferencedPatchClass , EMetaSoundBuilderResult & OutResult )
{
const UClass & Class = ReferencedPatchClass - > GetBaseMetaSoundUClass ( ) ;
if ( & Class = = UMetaSoundSource : : StaticClass ( ) )
{
return * CreateSourcePresetBuilder ( BuilderName , ReferencedPatchClass , OutResult ) ;
}
else if ( & Class = = UMetaSoundPatch : : StaticClass ( ) )
{
return * CreatePatchPresetBuilder ( BuilderName , ReferencedPatchClass , OutResult ) ;
}
else
{
checkf ( false , TEXT ( " UClass '%s' cannot be built to a MetaSound preset " ) , * Class . GetFullName ( ) ) ;
2023-06-22 14:43:52 -04:00
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreateTransientBuilder < UMetaSoundPatchBuilder > ( BuilderName ) ;
2023-06-16 03:08:48 -04:00
}
}
2023-05-30 14:39:48 -04:00
UMetaSoundSourceBuilder * UMetaSoundBuilderSubsystem : : CreateSourcePresetBuilder ( FName BuilderName , const TScriptInterface < IMetaSoundDocumentInterface > & ReferencedNodeClass , EMetaSoundBuilderResult & OutResult )
{
UMetaSoundSourceBuilder & Builder = Metasound : : Engine : : BuilderSubsystemPrivate : : CreateTransientBuilder < UMetaSoundSourceBuilder > ( ) ;
Builder . ConvertToPreset ( ReferencedNodeClass , OutResult ) ;
return & Builder ;
}
2023-05-10 20:28:39 -04:00
UMetaSoundBuilderSubsystem & UMetaSoundBuilderSubsystem : : GetChecked ( )
{
checkf ( GEngine , TEXT ( " Cannot access UMetaSoundBuilderSubsystem without engine loaded " ) ) ;
UMetaSoundBuilderSubsystem * BuilderSubsystem = GEngine - > GetEngineSubsystem < UMetaSoundBuilderSubsystem > ( ) ;
checkf ( BuilderSubsystem , TEXT ( " Failed to find initialized 'UMetaSoundBuilderSubsystem " ) ) ;
return * BuilderSubsystem ;
}
const UMetaSoundBuilderSubsystem & UMetaSoundBuilderSubsystem : : GetConstChecked ( )
{
checkf ( GEngine , TEXT ( " Cannot access UMetaSoundBuilderSubsystem without engine loaded " ) ) ;
UMetaSoundBuilderSubsystem * BuilderSubsystem = GEngine - > GetEngineSubsystem < UMetaSoundBuilderSubsystem > ( ) ;
checkf ( BuilderSubsystem , TEXT ( " Failed to find initialized 'UMetaSoundBuilderSubsystem " ) ) ;
return * BuilderSubsystem ;
}
2023-03-07 17:01:52 -05:00
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateBoolMetaSoundLiteral ( bool Value , FName & OutDataType )
{
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreatePODMetaSoundLiteral ( Value , OutDataType ) ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateBoolArrayMetaSoundLiteral ( const TArray < bool > & Value , FName & OutDataType )
{
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreatePODMetaSoundLiteral ( Value , OutDataType ) ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateFloatMetaSoundLiteral ( float Value , FName & OutDataType )
{
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreatePODMetaSoundLiteral ( Value , OutDataType ) ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateFloatArrayMetaSoundLiteral ( const TArray < float > & Value , FName & OutDataType )
{
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreatePODMetaSoundLiteral ( Value , OutDataType ) ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateIntMetaSoundLiteral ( int32 Value , FName & OutDataType )
{
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreatePODMetaSoundLiteral ( Value , OutDataType ) ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateIntArrayMetaSoundLiteral ( const TArray < int32 > & Value , FName & OutDataType )
{
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreatePODMetaSoundLiteral ( Value , OutDataType ) ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateStringMetaSoundLiteral ( const FString & Value , FName & OutDataType )
{
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreatePODMetaSoundLiteral ( Value , OutDataType ) ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateStringArrayMetaSoundLiteral ( const TArray < FString > & Value , FName & OutDataType )
{
return Metasound : : Engine : : BuilderSubsystemPrivate : : CreatePODMetaSoundLiteral ( Value , OutDataType ) ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateObjectMetaSoundLiteral ( UObject * Value )
{
FMetasoundFrontendLiteral Literal ;
Literal . Set ( Value ) ;
return Literal ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateObjectArrayMetaSoundLiteral ( const TArray < UObject * > & Value )
{
FMetasoundFrontendLiteral Literal ;
Literal . Set ( Value ) ;
return Literal ;
}
FMetasoundFrontendLiteral UMetaSoundBuilderSubsystem : : CreateMetaSoundLiteralFromParam ( const FAudioParameter & Param )
{
return FMetasoundFrontendLiteral { Param } ;
}
2023-06-16 17:55:08 -04:00
bool UMetaSoundBuilderSubsystem : : DetachBuilderFromAsset ( const FMetasoundFrontendClassName & InClassName )
{
return AssetBuilders . Remove ( InClassName . GetFullName ( ) ) > 0 ;
}
const Metasound : : Frontend : : FDocumentModifyDelegates * UMetaSoundBuilderSubsystem : : FindModifyDelegates ( const FMetasoundFrontendClassName & InClassName ) const
{
using namespace Metasound : : Frontend ;
TWeakObjectPtr < UMetaSoundBuilderBase > BuilderPtr = AssetBuilders . FindRef ( InClassName . GetFullName ( ) ) ;
if ( BuilderPtr . IsValid ( ) )
{
return & BuilderPtr - > GetConstBuilder ( ) . GetDocumentDelegates ( ) ;
}
return nullptr ;
}
2023-06-22 14:43:52 -04:00
UMetaSoundBuilderBase * UMetaSoundBuilderSubsystem : : FindBuilder ( FName BuilderName )
{
return NamedBuilders . FindRef ( BuilderName ) ;
}
2023-03-07 17:01:52 -05:00
UMetaSoundPatchBuilder * UMetaSoundBuilderSubsystem : : FindPatchBuilder ( FName BuilderName )
{
2023-06-22 14:43:52 -04:00
if ( UMetaSoundBuilderBase * Builder = FindBuilder ( BuilderName ) )
{
return Cast < UMetaSoundPatchBuilder > ( Builder ) ;
}
return nullptr ;
2023-03-07 17:01:52 -05:00
}
UMetaSoundSourceBuilder * UMetaSoundBuilderSubsystem : : FindSourceBuilder ( FName BuilderName )
{
2023-06-22 14:43:52 -04:00
if ( UMetaSoundBuilderBase * Builder = FindBuilder ( BuilderName ) )
{
return Cast < UMetaSoundSourceBuilder > ( Builder ) ;
}
return nullptr ;
2023-06-16 17:55:08 -04:00
}
void UMetaSoundBuilderSubsystem : : Initialize ( FSubsystemCollectionBase & Collection )
{
using namespace Metasound : : Frontend ;
IMetaSoundDocumentBuilderRegistry : : Set ( [ ] ( ) - > IMetaSoundDocumentBuilderRegistry &
{
check ( GEngine ) ;
UMetaSoundBuilderSubsystem * BuilderSubsystem = GEngine - > GetEngineSubsystem < UMetaSoundBuilderSubsystem > ( ) ;
check ( BuilderSubsystem ) ;
return static_cast < IMetaSoundDocumentBuilderRegistry & > ( * BuilderSubsystem ) ;
} ) ;
2023-03-07 17:01:52 -05:00
}
bool UMetaSoundBuilderSubsystem : : IsInterfaceRegistered ( FName InInterfaceName ) const
{
using namespace Metasound : : Frontend ;
FMetasoundFrontendInterface Interface ;
return ISearchEngine : : Get ( ) . FindInterfaceWithHighestVersion ( InInterfaceName , Interface ) ;
}
2023-07-24 17:35:47 -04:00
# if WITH_EDITOR
void UMetaSoundBuilderSubsystem : : PostBuilderAssetTransaction ( const FMetasoundFrontendClassName & InClassName )
{
TWeakObjectPtr < UMetaSoundBuilderBase > BuilderPtr = AssetBuilders . FindRef ( InClassName . GetFullName ( ) ) ;
if ( UMetaSoundBuilderBase * Builder = BuilderPtr . Get ( ) )
{
Builder - > ReloadCache ( ) ;
}
}
# endif // WITH_EDITOR
2023-06-22 14:43:52 -04:00
void UMetaSoundBuilderSubsystem : : RegisterBuilder ( FName BuilderName , UMetaSoundBuilderBase * Builder )
{
if ( Builder )
{
NamedBuilders . FindOrAdd ( BuilderName ) = Builder ;
}
}
2023-03-07 17:01:52 -05:00
void UMetaSoundBuilderSubsystem : : RegisterPatchBuilder ( FName BuilderName , UMetaSoundPatchBuilder * Builder )
{
2023-06-22 14:43:52 -04:00
if ( Builder )
{
NamedBuilders . FindOrAdd ( BuilderName ) = Builder ;
}
2023-03-07 17:01:52 -05:00
}
void UMetaSoundBuilderSubsystem : : RegisterSourceBuilder ( FName BuilderName , UMetaSoundSourceBuilder * Builder )
{
2023-06-22 14:43:52 -04:00
if ( Builder )
{
NamedBuilders . FindOrAdd ( BuilderName ) = Builder ;
}
}
bool UMetaSoundBuilderSubsystem : : UnregisterBuilder ( FName BuilderName )
{
return NamedBuilders . Remove ( BuilderName ) > 0 ;
2023-03-07 17:01:52 -05:00
}
bool UMetaSoundBuilderSubsystem : : UnregisterPatchBuilder ( FName BuilderName )
{
2023-06-22 14:43:52 -04:00
return NamedBuilders . Remove ( BuilderName ) > 0 ;
2023-03-07 17:01:52 -05:00
}
bool UMetaSoundBuilderSubsystem : : UnregisterSourceBuilder ( FName BuilderName )
{
2023-06-22 14:43:52 -04:00
return NamedBuilders . Remove ( BuilderName ) > 0 ;
2023-03-07 17:01:52 -05:00
}