2021-11-22 15:55:50 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundInterface.h"
2021-12-10 20:37:31 -05:00
# include "Algo/Transform.h"
# include "AudioParameterControllerInterface.h"
# include "IAudioParameterInterfaceRegistry.h"
2021-11-22 15:55:50 -05:00
# include "IAudioParameterTransmitter.h"
2021-12-10 20:37:31 -05:00
# include "MetasoundEngineArchetypes.h"
# include "MetasoundFrontendDataTypeRegistry.h"
# include "MetasoundFrontendDocument.h"
# include "MetasoundFrontendTransform.h"
# include "MetasoundLog.h"
# include "MetasoundOutputFormatInterfaces.h"
# include "MetasoundParameterTransmitter.h"
# include "MetasoundSource.h"
# include "MetasoundSourceInterface.h"
# include "MetasoundUObjectRegistry.h"
# include "Templates/SharedPointer.h"
# include "Templates/UniquePtr.h"
# include "UObject/Class.h"
# include "UObject/NoExportTypes.h"
2021-11-22 15:55:50 -05:00
namespace Metasound
{
namespace Engine
{
2021-12-10 20:37:31 -05:00
struct FInterfaceRegistryOptions
2021-11-22 15:55:50 -05:00
{
2021-12-10 20:37:31 -05:00
bool bIsDefault = false ;
2021-12-15 23:11:10 -05:00
bool bEditorCanAddOrRemove = true ;
2021-12-10 20:37:31 -05:00
FName InputSystemName ;
FName UClassName ;
} ;
2021-11-22 15:55:50 -05:00
2021-12-10 20:37:31 -05:00
// Entry for registered interface.
class FInterfaceRegistryEntry : public Frontend : : IInterfaceRegistryEntry
{
public :
FInterfaceRegistryEntry (
const FMetasoundFrontendInterface & InInterface ,
TUniquePtr < Frontend : : IDocumentTransform > & & InUpdateTransform ,
FInterfaceRegistryOptions & & InOptions
)
: Interface ( InInterface )
, UpdateTransform ( MoveTemp ( InUpdateTransform ) )
, Options ( MoveTemp ( InOptions ) )
2021-11-22 15:55:50 -05:00
{
2021-12-10 20:37:31 -05:00
}
2021-12-15 23:11:10 -05:00
virtual bool EditorCanAddOrRemove ( ) const override
{
return Options . bEditorCanAddOrRemove ;
}
2021-12-10 20:37:31 -05:00
virtual bool UClassIsSupported ( FName InUClassName ) const override
{
if ( Options . UClassName . IsNone ( ) )
2021-11-22 15:55:50 -05:00
{
2021-12-10 20:37:31 -05:00
return true ;
2021-12-01 15:59:03 -05:00
}
2021-12-10 20:37:31 -05:00
// TODO: Support child asset class types.
return Options . UClassName = = InUClassName ;
}
virtual bool IsDefault ( ) const override
{
return Options . bIsDefault ;
}
virtual FName GetRouterName ( ) const override
{
return Options . InputSystemName ;
}
virtual const FMetasoundFrontendInterface & GetInterface ( ) const override
{
return Interface ;
}
virtual bool UpdateRootGraphInterface ( Frontend : : FDocumentHandle InDocument ) const override
{
if ( UpdateTransform . IsValid ( ) )
{
return UpdateTransform - > Transform ( InDocument ) ;
}
return false ;
}
private :
FMetasoundFrontendInterface Interface ;
TUniquePtr < Frontend : : IDocumentTransform > UpdateTransform ;
FInterfaceRegistryOptions Options ;
} ;
template < typename UClassType >
2021-12-15 23:11:10 -05:00
void RegisterInterface ( const FMetasoundFrontendInterface & InInterface , TUniquePtr < Frontend : : IDocumentTransform > & & InUpdateTransform , bool bInIsDefault , bool bEditorCanAddOrRemove , FName InRouterName )
2021-12-10 20:37:31 -05:00
{
using namespace Frontend ;
FInterfaceRegistryOptions Options
{
bInIsDefault ,
2021-12-15 23:11:10 -05:00
bEditorCanAddOrRemove ,
2021-12-10 20:37:31 -05:00
InRouterName ,
UClassType : : StaticClass ( ) - > GetFName ( )
2021-12-01 15:59:03 -05:00
} ;
2021-12-10 20:37:31 -05:00
IMetasoundUObjectRegistry : : Get ( ) . RegisterUClassInterface ( MakeUnique < TMetasoundUObjectRegistryEntry < UClassType > > ( InInterface . Version ) ) ;
IInterfaceRegistry : : Get ( ) . RegisterInterface ( MakeUnique < FInterfaceRegistryEntry > ( InInterface , MoveTemp ( InUpdateTransform ) , MoveTemp ( Options ) ) ) ;
}
2021-12-15 23:11:10 -05:00
void RegisterInterface ( Audio : : FParameterInterfacePtr Interface , TUniquePtr < Frontend : : IDocumentTransform > & & InUpdateTransform , bool bInIsDefault , bool bEditorCanAddOrRemove , FName InRouterName )
2021-12-10 20:37:31 -05:00
{
using namespace Frontend ;
auto ResolveMemberDataType = [ ] ( FName DataType , EAudioParameterType ParamType )
{
if ( ! DataType . IsNone ( ) )
{
const bool bIsRegisteredType = Frontend : : IDataTypeRegistry : : Get ( ) . IsRegistered ( DataType ) ;
if ( ensureAlwaysMsgf ( bIsRegisteredType , TEXT ( " Attempting to register Interface member with unregistered DataType '%s'. " ) , * DataType . ToString ( ) ) )
{
return DataType ;
}
}
return ConvertParameterToDataType ( ParamType ) ;
} ;
FMetasoundFrontendInterface FrontendInterface ;
FrontendInterface . Version = { Interface - > GetName ( ) , FMetasoundFrontendVersionNumber { Interface - > GetVersion ( ) . Major , Interface - > GetVersion ( ) . Minor } } ;
Algo : : Transform ( Interface - > GetInputs ( ) , FrontendInterface . Inputs , [ & ] ( const Audio : : FParameterInterface : : FInput & Input )
{
FMetasoundFrontendClassInput ClassInput ;
ClassInput . Name = Input . InitValue . ParamName ;
ClassInput . DefaultLiteral = FMetasoundFrontendLiteral ( Input . InitValue ) ;
ClassInput . TypeName = ResolveMemberDataType ( Input . DataType , Input . InitValue . ParamType ) ;
ClassInput . Metadata . DisplayName = Input . DisplayName ;
ClassInput . Metadata . Description = Input . Description ;
ClassInput . VertexID = FGuid : : NewGuid ( ) ;
return ClassInput ;
} ) ;
Algo : : Transform ( Interface - > GetOutputs ( ) , FrontendInterface . Outputs , [ & ] ( const Audio : : FParameterInterface : : FOutput & Output )
{
FMetasoundFrontendClassOutput ClassOutput ;
ClassOutput . Name = Output . ParamName ;
ClassOutput . TypeName = ResolveMemberDataType ( Output . DataType , Output . ParamType ) ;
ClassOutput . Metadata . DisplayName = Output . DisplayName ;
ClassOutput . Metadata . Description = Output . Description ;
ClassOutput . VertexID = FGuid : : NewGuid ( ) ;
return ClassOutput ;
} ) ;
Algo : : Transform ( Interface - > GetEnvironment ( ) , FrontendInterface . Environment , [ & ] ( const Audio : : FParameterInterface : : FEnvironmentVariable & Environment )
{
FMetasoundFrontendClassEnvironmentVariable EnvironmentVariable ;
EnvironmentVariable . Name = Environment . ParamName ;
// Disabled as it isn't used to infer type when getting/setting at a lower level.
// TODO: Either remove type info for environment variables all together or enforce type.
// EnvironmentVariable.TypeName = ResolveMemberDataType(Environment.DataType, Environment.ParamType);
EnvironmentVariable . Metadata . DisplayName = Environment . DisplayName ;
EnvironmentVariable . Metadata . Description = Environment . Description ;
return EnvironmentVariable ;
} ) ;
const UClass * SourceClass = UMetaSoundSource : : StaticClass ( ) ;
check ( SourceClass ) ;
const bool bInterfaceSupportsSource = SourceClass - > IsChildOf ( & Interface - > GetType ( ) ) ;
if ( ensureAlwaysMsgf ( bInterfaceSupportsSource , TEXT ( " Interfaces defined using Audio::FParameterInterface currently only supported by UMetaSoundSource asset type. " ) ) )
{
2021-12-15 23:11:10 -05:00
RegisterInterface < UMetaSoundSource > ( FrontendInterface , MoveTemp ( InUpdateTransform ) , bInIsDefault , bEditorCanAddOrRemove , InRouterName ) ;
2021-12-10 20:37:31 -05:00
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Interface '%s' registered for asset type '%s'. " ) , * Interface - > GetName ( ) . ToString ( ) , * SourceClass - > GetName ( ) ) ;
}
}
void RegisterInterfaces ( )
{
using namespace Frontend ;
// Register Default Internal Interfaces (Not managed directly by end-user & added by default when creating new MetaSound assets).
{
constexpr bool bIsDefault = true ;
2021-12-15 23:11:10 -05:00
constexpr bool bEditorCanAddOrRemove = false ;
RegisterInterface < UMetaSound > ( MetasoundV1_0 : : GetInterface ( ) , nullptr , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
2021-12-10 20:37:31 -05:00
2021-12-15 23:11:10 -05:00
RegisterInterface ( SourceInterface : : CreateInterface ( * UMetaSoundSource : : StaticClass ( ) ) , MakeUnique < SourceInterface : : FUpdateInterface > ( ) , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
RegisterInterface ( OutputFormatMonoInterface : : CreateInterface ( * UMetaSoundSource : : StaticClass ( ) ) , nullptr , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
2021-12-10 20:37:31 -05:00
}
// Register Non-Default Internal Interfaces (Not managed directly by end-user & not added by default when creating new MetaSound assets).
{
constexpr bool bIsDefault = false ;
2021-12-15 23:11:10 -05:00
constexpr bool bEditorCanAddOrRemove = false ;
// Added for upgrading old metasounds
RegisterInterface ( SourceInterfaceV1_0 : : CreateInterface ( * UMetaSoundSource : : StaticClass ( ) ) , nullptr , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
2021-12-10 20:37:31 -05:00
// Set default interface with unset version to use base UMetaSound class implementation (legacy requirement for 5.0 alpha).
2021-12-15 23:11:10 -05:00
RegisterInterface < UMetaSound > ( FMetasoundFrontendInterface ( ) , nullptr , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
2021-12-10 20:37:31 -05:00
2021-12-15 23:11:10 -05:00
RegisterInterface < UMetaSoundSource > ( MetasoundOutputFormatStereoV1_0 : : GetInterface ( ) , nullptr , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
RegisterInterface < UMetaSoundSource > ( MetasoundOutputFormatStereoV1_1 : : GetInterface ( ) , MakeUnique < MetasoundOutputFormatStereoV1_1 : : FUpdateInterface > ( ) , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
RegisterInterface < UMetaSoundSource > ( MetasoundOutputFormatStereoV1_2 : : GetInterface ( ) , MakeUnique < MetasoundOutputFormatStereoV1_2 : : FUpdateInterface > ( ) , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
2021-12-10 20:37:31 -05:00
2021-12-15 23:11:10 -05:00
RegisterInterface < UMetaSoundSource > ( MetasoundOutputFormatMonoV1_0 : : GetInterface ( ) , nullptr , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
RegisterInterface < UMetaSoundSource > ( MetasoundOutputFormatMonoV1_1 : : GetInterface ( ) , MakeUnique < MetasoundOutputFormatMonoV1_1 : : FUpdateInterface > ( ) , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
RegisterInterface < UMetaSoundSource > ( MetasoundOutputFormatMonoV1_2 : : GetInterface ( ) , MakeUnique < MetasoundOutputFormatMonoV1_2 : : FUpdateInterface > ( ) , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
2021-12-10 20:37:31 -05:00
2021-12-15 23:11:10 -05:00
RegisterInterface ( OutputFormatStereoInterface : : CreateInterface ( * UMetaSoundSource : : StaticClass ( ) ) , nullptr , bIsDefault , bEditorCanAddOrRemove , IDataReference : : RouterName ) ;
RegisterInterface ( SourceOneShotInterface : : CreateInterface ( * UMetaSoundSource : : StaticClass ( ) ) , nullptr , bIsDefault , true , IDataReference : : RouterName ) ;
2021-12-10 20:37:31 -05:00
}
// Register External Interfaces (Interfaces defined externally & can be managed directly by end-user).
auto RegisterExternalInterface = [ ] ( Audio : : FParameterInterfacePtr Interface )
{
// Currently, no externally defined interfaces can be added as default for protection against undesired
2021-12-15 23:11:10 -05:00
// interfaces automatically being added when creating a new MetaSound asset through the editor. Also,
// all parameter interfaces are enabled in the editor for addition/removal.
2021-12-10 20:37:31 -05:00
constexpr bool bIsDefault = false ;
2021-12-15 23:11:10 -05:00
constexpr bool bEditorCanAddOrRemove = true ;
2021-12-10 20:37:31 -05:00
TUniquePtr < Frontend : : IDocumentTransform > NullTransform ;
2021-12-15 23:11:10 -05:00
RegisterInterface ( Interface , MoveTemp ( NullTransform ) , bIsDefault , bEditorCanAddOrRemove , Audio : : IParameterTransmitter : : RouterName ) ;
2021-12-10 20:37:31 -05:00
} ;
Audio : : IAudioParameterInterfaceRegistry : : Get ( ) . IterateInterfaces ( RegisterExternalInterface ) ;
Audio : : IAudioParameterInterfaceRegistry : : Get ( ) . OnRegistration ( MoveTemp ( RegisterExternalInterface ) ) ;
2021-11-22 15:55:50 -05:00
}
} // namespace Engine
} // namespace Metasound