2020-07-23 20:32:26 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundSource.h"
2023-03-07 17:01:52 -05:00
# include "Algo/Find.h"
2021-11-18 14:37:34 -05:00
# include "Algo/Transform.h"
2022-05-02 18:59:38 -04:00
# include "AssetRegistry/AssetRegistryModule.h"
2022-01-11 13:52:09 -05:00
# include "AudioDeviceManager.h"
2021-12-10 20:37:31 -05:00
# include "IAudioParameterInterfaceRegistry.h"
2023-03-07 17:01:52 -05:00
# include "Interfaces/MetasoundOutputFormatInterfaces.h"
2022-08-19 12:14:31 -04:00
# include "Interfaces/MetasoundFrontendSourceInterface.h"
2020-07-23 20:32:26 -04:00
# include "Internationalization/Text.h"
# include "MetasoundAssetBase.h"
2022-08-10 14:18:10 -04:00
# include "MetasoundAssetManager.h"
2020-12-14 15:48:27 -04:00
# include "MetasoundAudioFormats.h"
2023-03-07 17:01:52 -05:00
# include "MetasoundBuilderSubsystem.h"
2023-06-14 17:01:59 -04:00
# include "MetasoundDynamicOperatorTransactor.h"
2022-10-13 17:38:11 -04:00
# include "MetasoundEngineAsset.h"
2020-11-17 17:52:08 -04:00
# include "MetasoundEngineEnvironment.h"
2021-06-08 10:52:31 -04:00
# include "MetasoundEnvironment.h"
2021-01-22 03:05:22 -04:00
# include "MetasoundFrontendController.h"
2021-08-30 14:08:45 -04:00
# include "MetasoundFrontendDataTypeRegistry.h"
2023-03-07 17:01:52 -05:00
# include "MetasoundFrontendDocumentBuilder.h"
2021-01-22 03:05:22 -04:00
# include "MetasoundFrontendQuery.h"
# include "MetasoundFrontendQuerySteps.h"
2021-05-28 16:17:48 -04:00
# include "MetasoundFrontendTransform.h"
2020-07-23 20:32:26 -04:00
# include "MetasoundGenerator.h"
2020-12-14 15:48:27 -04:00
# include "MetasoundLog.h"
2022-05-10 16:51:39 -04:00
# include "MetasoundOperatorBuilderSettings.h"
2021-02-16 01:26:50 -04:00
# include "MetasoundOperatorSettings.h"
2021-08-30 14:08:45 -04:00
# include "MetasoundParameterTransmitter.h"
2020-07-23 20:32:26 -04:00
# include "MetasoundPrimitives.h"
2021-01-22 03:05:22 -04:00
# include "MetasoundReceiveNode.h"
2022-03-01 21:25:04 -05:00
# include "MetasoundSettings.h"
2021-08-11 15:22:01 -04:00
# include "MetasoundTrace.h"
2021-01-27 15:54:01 -04:00
# include "MetasoundTrigger.h"
2021-06-08 10:52:31 -04:00
# include "MetasoundUObjectRegistry.h"
# include "UObject/ObjectSaveContext.h"
2023-03-07 17:01:52 -05:00
# include "UObject/ScriptInterface.h"
2020-07-23 20:32:26 -04:00
2022-09-28 01:06:15 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(MetasoundSource)
2020-07-23 20:32:26 -04:00
# if WITH_EDITORONLY_DATA
# include "EdGraph/EdGraph.h"
# endif // WITH_EDITORONLY_DATA
2021-12-10 20:37:31 -05:00
# define LOCTEXT_NAMESPACE "MetaSound"
2021-04-02 02:09:50 -04:00
2022-01-11 13:52:09 -05:00
namespace Metasound
2021-07-28 17:12:57 -04:00
{
2022-01-11 13:52:09 -05:00
namespace SourcePrivate
2023-07-20 14:02:15 -04:00
{
2022-08-10 14:18:10 -04:00
Frontend : : FMetaSoundAssetRegistrationOptions GetInitRegistrationOptions ( )
{
Frontend : : FMetaSoundAssetRegistrationOptions RegOptions ;
RegOptions . bForceReregister = false ;
if ( const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) )
{
RegOptions . bAutoUpdateLogWarningOnDroppedConnection = Settings - > bAutoUpdateLogWarningOnDroppedConnection ;
}
return RegOptions ;
}
2023-04-05 17:38:47 -04:00
class FParameterRouter
{
2023-04-06 18:47:28 -04:00
struct FQueueState
{
TWeakPtr < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > DataChannel ;
bool bWriterAvailable = true ;
} ;
2023-04-05 17:38:47 -04:00
public :
using FAudioDeviceIDAndInstanceID = TTuple < Audio : : DeviceID , uint64 > ;
2023-04-06 18:47:28 -04:00
TSharedPtr < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > FindOrCreateDataChannelForReader ( Audio : : DeviceID InDeviceID , uint64 InstanceID )
2023-04-05 17:38:47 -04:00
{
2023-04-06 18:47:28 -04:00
constexpr bool bIsForWriter = false ;
return FindOrCreateDataChannel ( InDeviceID , InstanceID , bIsForWriter ) ;
}
2023-04-05 17:38:47 -04:00
2023-04-06 18:47:28 -04:00
TSharedPtr < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > FindOrCreateDataChannelForWriter ( Audio : : DeviceID InDeviceID , uint64 InstanceID )
{
constexpr bool bIsForWriter = true ;
return FindOrCreateDataChannel ( InDeviceID , InstanceID , bIsForWriter ) ;
2023-04-05 17:38:47 -04:00
}
private :
2023-04-06 18:47:28 -04:00
TSharedPtr < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > FindOrCreateDataChannel ( Audio : : DeviceID InDeviceID , uint64 InstanceID , bool bIsForWriter )
{
FScopeLock Lock ( & DataChannelMapCS ) ;
FAudioDeviceIDAndInstanceID Key = { InDeviceID , InstanceID } ;
const bool bIsForReader = ! bIsForWriter ;
if ( FQueueState * State = DataChannels . Find ( Key ) )
{
// Allow multiple readers to be returned because FMetaSoundGenerators are recreated when they come out of virtualization.
// Only allow a single writer to be returned because FMetaSoundParameterTransmitters are only created once
const bool bIsAvailable = bIsForReader | | ( State - > bWriterAvailable & & bIsForWriter ) ;
if ( bIsAvailable )
{
TSharedPtr < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > Channel = State - > DataChannel . Pin ( ) ;
if ( Channel . IsValid ( ) )
{
if ( bIsForWriter )
{
State - > bWriterAvailable = false ;
}
return Channel ;
}
}
}
TSharedPtr < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > NewChannel = MakeShared < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > ( ) ;
FQueueState NewState ;
NewState . DataChannel = NewChannel ;
if ( bIsForWriter )
{
NewState . bWriterAvailable = false ;
}
DataChannels . Add ( Key , NewState ) ;
return NewChannel ;
}
2023-04-05 17:38:47 -04:00
FCriticalSection DataChannelMapCS ;
2023-04-06 18:47:28 -04:00
TSortedMap < FAudioDeviceIDAndInstanceID , FQueueState > DataChannels ;
2023-04-05 17:38:47 -04:00
} ;
2022-01-11 13:52:09 -05:00
} // namespace SourcePrivate
} // namespace Metasound
2021-04-02 02:09:50 -04:00
2021-02-19 18:30:53 -04:00
2021-04-02 02:09:50 -04:00
UMetaSoundSource : : UMetaSoundSource ( const FObjectInitializer & ObjectInitializer )
2020-07-23 20:32:26 -04:00
: Super ( ObjectInitializer )
2021-06-08 10:52:31 -04:00
, FMetasoundAssetBase ( )
2020-07-23 20:32:26 -04:00
{
2022-11-17 16:36:26 -05:00
bProcedural = true ;
2021-01-11 14:18:46 -04:00
bRequiresStopFade = true ;
2020-07-23 20:32:26 -04:00
NumChannels = 1 ;
2022-02-25 15:48:47 -05:00
2021-04-02 02:09:50 -04:00
// todo: ensure that we have a method so that the audio engine can be authoritative over the sample rate the UMetaSoundSource runs at.
2021-02-16 01:26:50 -04:00
SampleRate = 48000.f ;
2020-07-23 20:32:26 -04:00
}
2023-05-10 20:28:39 -04:00
const UClass & UMetaSoundSource : : GetBaseMetaSoundUClass ( ) const
{
return * UMetaSoundSource : : StaticClass ( ) ;
}
const FMetasoundFrontendDocument & UMetaSoundSource : : GetDocument ( ) const
{
return RootMetasoundDocument ;
}
2020-12-14 15:48:27 -04:00
# if WITH_EDITOR
2021-04-02 02:09:50 -04:00
void UMetaSoundSource : : PostEditUndo ( )
2021-03-02 21:39:09 -04:00
{
Super : : PostEditUndo ( ) ;
2022-10-13 17:38:11 -04:00
Metasound : : FMetaSoundEngineAssetHelper : : PostEditUndo ( * this ) ;
2021-03-02 21:39:09 -04:00
}
2021-07-28 16:21:39 -04:00
void UMetaSoundSource : : PostDuplicate ( EDuplicateMode : : Type InDuplicateMode )
{
Super : : PostDuplicate ( InDuplicateMode ) ;
2021-11-22 15:55:50 -05:00
// Guid is reset as asset may share implementation from
// asset duplicated from but should not be registered as such.
if ( InDuplicateMode = = EDuplicateMode : : Normal )
{
2022-03-10 21:19:13 -05:00
AssetClassID = FGuid : : NewGuid ( ) ;
Metasound : : Frontend : : FRenameRootGraphClass : : Generate ( GetDocumentHandle ( ) , AssetClassID ) ;
2021-11-22 15:55:50 -05:00
}
2021-07-28 16:21:39 -04:00
}
2021-04-02 02:09:50 -04:00
void UMetaSoundSource : : PostEditChangeProperty ( FPropertyChangedEvent & InEvent )
2020-12-14 15:48:27 -04:00
{
Super : : PostEditChangeProperty ( InEvent ) ;
2021-06-08 10:52:31 -04:00
if ( InEvent . GetPropertyName ( ) = = GET_MEMBER_NAME_CHECKED ( UMetaSoundSource , OutputFormat ) )
2020-12-14 15:48:27 -04:00
{
2022-08-15 10:49:30 -04:00
PostEditChangeOutputFormat ( ) ;
}
}
2021-06-08 10:52:31 -04:00
2022-08-15 10:49:30 -04:00
void UMetaSoundSource : : PostEditChangeOutputFormat ( )
{
using namespace Metasound : : Frontend ;
2023-08-02 14:35:48 -04:00
EMetaSoundBuilderResult Result = EMetaSoundBuilderResult : : Failed ;
{
const UMetaSoundBuilderSubsystem & BuilderSubsystem = UMetaSoundBuilderSubsystem : : GetConstChecked ( ) ;
2023-08-09 16:45:21 -04:00
2023-08-02 14:35:48 -04:00
UMetaSoundSourceBuilder * SourceBuilder = BuilderSubsystem . AttachSourceBuilderToAsset ( this ) ;
2023-08-09 16:45:21 -04:00
check ( SourceBuilder ) ;
2023-08-02 14:35:48 -04:00
SourceBuilder - > SetFormat ( OutputFormat , Result ) ;
2023-08-09 16:45:21 -04:00
2023-08-02 14:35:48 -04:00
// TODO: Once builders are notified of controller changes and can be safely persistent, this
// can be removed so builders can be shared and not have to be created for each change output
// format mutation transaction.
BuilderSubsystem . DetachBuilderFromAsset ( GetDocument ( ) . RootGraph . Metadata . GetClassName ( ) ) ;
}
2023-03-07 17:01:52 -05:00
if ( Result = = EMetaSoundBuilderResult : : Succeeded )
2022-08-15 10:49:30 -04:00
{
// Update the data in this UMetaSoundSource to reflect what is in the metasound document.
ConformObjectDataToInterfaces ( ) ;
// Use the editor form of register to ensure other editors'
// MetaSounds are auto-updated if they are referencing this graph.
if ( Graph )
2021-06-08 10:52:31 -04:00
{
2022-08-15 10:49:30 -04:00
Graph - > RegisterGraphWithFrontend ( ) ;
2020-12-14 15:48:27 -04:00
}
2022-08-15 10:49:30 -04:00
MarkMetasoundDocumentDirty ( ) ;
2020-12-14 15:48:27 -04:00
}
}
2021-06-08 10:52:31 -04:00
# endif // WITH_EDITOR
2020-12-14 15:48:27 -04:00
2021-11-22 15:55:50 -05:00
bool UMetaSoundSource : : ConformObjectDataToInterfaces ( )
2021-08-18 15:16:57 -04:00
{
2023-03-07 17:01:52 -05:00
using namespace Metasound : : Engine ;
using namespace Metasound : : Frontend ;
2021-12-10 20:37:31 -05:00
2022-08-15 10:49:30 -04:00
bool bDidAlterObjectData = false ;
// Update the OutputFormat and NumChannels to match the audio format interface
// on the root document.
2023-03-07 17:01:52 -05:00
const FOutputAudioFormatInfoMap & FormatInfo = GetOutputAudioFormatInfo ( ) ;
for ( const FOutputAudioFormatInfoPair & Pair : FormatInfo )
2021-08-18 15:16:57 -04:00
{
2022-08-15 10:49:30 -04:00
if ( RootMetasoundDocument . Interfaces . Contains ( Pair . Value . InterfaceVersion ) )
2021-08-18 15:16:57 -04:00
{
2022-08-15 10:49:30 -04:00
if ( ( OutputFormat ! = Pair . Key ) | | ( NumChannels ! = Pair . Value . OutputVertexChannelOrder . Num ( ) ) )
{
OutputFormat = Pair . Key ;
NumChannels = Pair . Value . OutputVertexChannelOrder . Num ( ) ;
bDidAlterObjectData = true ;
}
break ;
2021-08-18 15:16:57 -04:00
}
}
2022-08-15 10:49:30 -04:00
return bDidAlterObjectData ;
2021-08-18 15:16:57 -04:00
}
2021-07-27 15:36:03 -04:00
void UMetaSoundSource : : BeginDestroy ( )
{
UnregisterGraphWithFrontend ( ) ;
Super : : BeginDestroy ( ) ;
}
void UMetaSoundSource : : PreSave ( FObjectPreSaveContext InSaveContext )
{
Super : : PreSave ( InSaveContext ) ;
2022-10-13 17:38:11 -04:00
Metasound : : FMetaSoundEngineAssetHelper : : PreSaveAsset ( * this , InSaveContext ) ;
2021-07-27 15:36:03 -04:00
}
void UMetaSoundSource : : Serialize ( FArchive & InArchive )
{
Super : : Serialize ( InArchive ) ;
2022-10-13 17:38:11 -04:00
Metasound : : FMetaSoundEngineAssetHelper : : SerializeToArchive ( * this , InArchive ) ;
2021-07-27 15:36:03 -04:00
}
2022-10-13 17:38:11 -04:00
# if WITH_EDITOR
void UMetaSoundSource : : SetReferencedAssetClasses ( TSet < Metasound : : Frontend : : IMetaSoundAssetManager : : FAssetInfo > & & InAssetClasses )
2021-08-18 15:16:57 -04:00
{
2022-10-13 17:38:11 -04:00
Metasound : : FMetaSoundEngineAssetHelper : : SetReferencedAssetClasses ( * this , MoveTemp ( InAssetClasses ) ) ;
}
# endif // WITH_EDITOR
TArray < FMetasoundAssetBase * > UMetaSoundSource : : GetReferencedAssets ( )
{
return Metasound : : FMetaSoundEngineAssetHelper : : GetReferencedAssets ( * this ) ;
2021-08-18 15:16:57 -04:00
}
2022-10-13 17:38:11 -04:00
const TSet < FSoftObjectPath > & UMetaSoundSource : : GetAsyncReferencedAssetClassPaths ( ) const
2021-11-07 23:43:01 -05:00
{
return ReferenceAssetClassCache ;
}
2022-10-13 17:38:11 -04:00
void UMetaSoundSource : : OnAsyncReferencedAssetsLoaded ( const TArray < FMetasoundAssetBase * > & InAsyncReferences )
2021-08-18 15:16:57 -04:00
{
2022-10-13 17:38:11 -04:00
Metasound : : FMetaSoundEngineAssetHelper : : OnAsyncReferencedAssetsLoaded ( * this , InAsyncReferences ) ;
2021-08-18 15:16:57 -04:00
}
2021-06-08 10:52:31 -04:00
# if WITH_EDITORONLY_DATA
2022-10-13 17:38:11 -04:00
2021-06-08 10:52:31 -04:00
UEdGraph * UMetaSoundSource : : GetGraph ( )
{
return Graph ;
}
const UEdGraph * UMetaSoundSource : : GetGraph ( ) const
{
return Graph ;
}
UEdGraph & UMetaSoundSource : : GetGraphChecked ( )
{
check ( Graph ) ;
return * Graph ;
}
const UEdGraph & UMetaSoundSource : : GetGraphChecked ( ) const
{
check ( Graph ) ;
return * Graph ;
}
FText UMetaSoundSource : : GetDisplayName ( ) const
{
FString TypeName = UMetaSoundSource : : StaticClass ( ) - > GetName ( ) ;
return FMetasoundAssetBase : : GetDisplayName ( MoveTemp ( TypeName ) ) ;
}
2021-06-16 11:21:13 -04:00
2022-10-13 17:38:11 -04:00
void UMetaSoundSource : : SetRegistryAssetClassInfo ( const Metasound : : Frontend : : FNodeClassInfo & InNodeInfo )
{
Metasound : : FMetaSoundEngineAssetHelper : : SetMetaSoundRegistryAssetClassInfo ( * this , InNodeInfo ) ;
}
# endif // WITH_EDITORONLY_DATA
2022-02-25 15:48:47 -05:00
void UMetaSoundSource : : PostLoad ( )
{
Super : : PostLoad ( ) ;
2022-10-13 17:38:11 -04:00
Metasound : : FMetaSoundEngineAssetHelper : : PostLoad ( * this ) ;
2022-02-25 15:48:47 -05:00
Duration = GetDuration ( ) ;
bLooping = IsLooping ( ) ;
}
2022-09-28 22:19:31 -04:00
void UMetaSoundSource : : InitParameters ( TArray < FAudioParameter > & ParametersToInit , FName InFeatureName )
2021-08-30 14:08:45 -04:00
{
2022-08-10 14:18:10 -04:00
using namespace Metasound : : SourcePrivate ;
2022-03-23 15:56:20 -04:00
METASOUND_LLM_SCOPE ;
2022-08-10 14:18:10 -04:00
// Have to call register vs a simple get as the source may have yet to start playing/has not been registered
2022-03-10 22:07:08 -05:00
// via InitResources. If it has, this call is fast and returns the already cached RuntimeData.
2022-08-10 14:18:10 -04:00
RegisterGraphWithFrontend ( GetInitRegistrationOptions ( ) ) ;
const FRuntimeData & RuntimeData = GetRuntimeData ( ) ;
2022-08-18 13:55:13 -04:00
2023-07-20 14:02:15 -04:00
TMap < FName , const FMetasoundFrontendVertex * > PublicInputMap ;
2022-08-18 13:55:13 -04:00
{
2023-07-20 14:02:15 -04:00
const TArray < FMetasoundFrontendClassInput > & PublicInputs = RuntimeData . PublicInputs ;
Algo : : Transform ( PublicInputs , PublicInputMap , [ ] ( const FMetasoundFrontendClassInput & Input )
2023-07-24 19:35:46 -04:00
{
return TPair < FName , const FMetasoundFrontendVertex * > ( Input . Name , & Input ) ;
} ) ;
2023-07-20 14:02:15 -04:00
}
2022-03-10 22:07:08 -05:00
2022-02-25 09:59:46 -05:00
// Removes values that are not explicitly defined by the ParamType and returns
// whether or not the parameter is a valid input and should be included.
2022-08-18 13:55:13 -04:00
auto Sanitize = [ & PublicInputMap ] ( FAudioParameter & Parameter ) - > bool
2022-02-25 09:59:46 -05:00
{
2023-07-20 14:02:15 -04:00
const FMetasoundFrontendVertex * Input = PublicInputMap . FindRef ( Parameter . ParamName ) ;
2022-03-10 22:07:08 -05:00
if ( ! Input )
2022-02-25 09:59:46 -05:00
{
return false ;
}
2022-08-18 13:55:13 -04:00
const bool bIsMatchingType = Parameter . TypeName . IsNone ( ) | | ( Parameter . TypeName = = Input - > TypeName ) ;
if ( ! bIsMatchingType )
{
return false ;
}
2021-08-30 14:08:45 -04:00
switch ( Parameter . ParamType )
{
2023-01-17 18:39:44 -05:00
case EAudioParameterType : : Trigger :
{
Parameter = FAudioParameter ( Parameter . ParamName , EAudioParameterType : : Trigger ) ;
}
break ;
2021-08-30 14:08:45 -04:00
case EAudioParameterType : : Boolean :
{
Parameter = FAudioParameter ( Parameter . ParamName , Parameter . BoolParam ) ;
}
break ;
case EAudioParameterType : : BooleanArray :
{
TArray < bool > TempArray = Parameter . ArrayBoolParam ;
Parameter = FAudioParameter ( Parameter . ParamName , MoveTemp ( TempArray ) ) ;
}
break ;
case EAudioParameterType : : Float :
{
Parameter = FAudioParameter ( Parameter . ParamName , Parameter . FloatParam ) ;
}
break ;
case EAudioParameterType : : FloatArray :
{
TArray < float > TempArray = Parameter . ArrayFloatParam ;
Parameter = FAudioParameter ( Parameter . ParamName , MoveTemp ( TempArray ) ) ;
}
break ;
case EAudioParameterType : : Integer :
{
Parameter = FAudioParameter ( Parameter . ParamName , Parameter . IntParam ) ;
}
break ;
case EAudioParameterType : : IntegerArray :
{
TArray < int32 > TempArray = Parameter . ArrayIntParam ;
Parameter = FAudioParameter ( Parameter . ParamName , MoveTemp ( TempArray ) ) ;
}
break ;
case EAudioParameterType : : Object :
{
Parameter = FAudioParameter ( Parameter . ParamName , Parameter . ObjectParam ) ;
}
break ;
case EAudioParameterType : : ObjectArray :
{
TArray < UObject * > TempArray = Parameter . ArrayObjectParam ;
Parameter = FAudioParameter ( Parameter . ParamName , MoveTemp ( TempArray ) ) ;
}
break ;
case EAudioParameterType : : String :
{
Parameter = FAudioParameter ( Parameter . ParamName , Parameter . StringParam ) ;
}
break ;
case EAudioParameterType : : StringArray :
{
TArray < FString > TempArray = Parameter . ArrayStringParam ;
Parameter = FAudioParameter ( Parameter . ParamName , MoveTemp ( TempArray ) ) ;
}
break ;
case EAudioParameterType : : None :
default :
break ;
}
2022-02-25 09:59:46 -05:00
return true ;
2021-08-30 14:08:45 -04:00
} ;
2023-07-20 14:02:15 -04:00
auto ConstructProxies = [ this ] ( FAudioParameter & OutParamToInit , FName VertexTypeName )
2021-08-30 14:08:45 -04:00
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
switch ( OutParamToInit . ParamType )
{
case EAudioParameterType : : Object :
{
2023-07-20 14:02:15 -04:00
TSharedPtr < Audio : : IProxyData > ProxyPtr = IDataTypeRegistry : : Get ( ) . CreateProxyFromUObject ( VertexTypeName , OutParamToInit . ObjectParam ) ;
OutParamToInit . ObjectProxies . Emplace ( MoveTemp ( ProxyPtr ) ) ;
2021-08-30 14:08:45 -04:00
2023-07-20 14:02:15 -04:00
// Null out param as it is no longer needed (nor desired to be accessed once passed to the Audio Thread)
OutParamToInit . ObjectParam = nullptr ;
2021-08-30 14:08:45 -04:00
}
break ;
case EAudioParameterType : : ObjectArray :
{
2023-07-24 19:35:46 -04:00
const FName ElementTypeName = CreateElementTypeNameFromArrayTypeName ( VertexTypeName ) ;
2021-08-30 14:08:45 -04:00
for ( TObjectPtr < UObject > & Object : OutParamToInit . ArrayObjectParam )
{
2023-07-24 19:35:46 -04:00
TSharedPtr < Audio : : IProxyData > ProxyPtr = IDataTypeRegistry : : Get ( ) . CreateProxyFromUObject ( ElementTypeName , Object ) ;
2023-07-20 14:02:15 -04:00
OutParamToInit . ObjectProxies . Emplace ( MoveTemp ( ProxyPtr ) ) ;
2021-08-30 14:08:45 -04:00
}
// Reset param array as it is no longer needed (nor desired to be accessed once passed to the Audio Thread).
// All object manipulation hereafter should be done via proxies
OutParamToInit . ArrayObjectParam . Reset ( ) ;
}
break ;
default :
break ;
}
} ;
2022-09-28 22:19:31 -04:00
for ( int32 i = ParametersToInit . Num ( ) - 1 ; i > = 0 ; - - i )
2021-08-30 14:08:45 -04:00
{
2022-09-28 22:19:31 -04:00
FAudioParameter & Parameter = ParametersToInit [ i ] ;
2022-03-04 04:08:58 -05:00
# if !NO_LOGGING
// For logging in case of failure
2022-03-10 22:07:08 -05:00
const FString AssetName = GetName ( ) ;
2022-03-04 04:08:58 -05:00
# endif // !NO_LOGGING
2022-02-25 09:59:46 -05:00
if ( Sanitize ( Parameter ) )
2021-11-18 14:37:34 -05:00
{
2023-07-20 14:02:15 -04:00
const FMetasoundFrontendVertex * Vertex = PublicInputMap . FindRef ( Parameter . ParamName ) ;
if ( IsParameterValid ( Parameter , Vertex ) )
2022-02-25 09:59:46 -05:00
{
2023-07-20 14:02:15 -04:00
ConstructProxies ( Parameter , Vertex - > TypeName ) ;
2022-02-25 09:59:46 -05:00
}
else
{
2022-03-10 22:07:08 -05:00
# if !NO_LOGGING
2022-09-21 15:42:38 -04:00
if ( : : Metasound : : MetaSoundParameterEnableWarningOnIgnoredParameterCVar )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to set invalid parameter '%s' in asset '%s': Either does not exist or is unsupported type " ) , * Parameter . ParamName . ToString ( ) , * AssetName ) ;
}
2022-03-04 04:08:58 -05:00
# endif // !NO_LOGGING
2022-03-10 22:07:08 -05:00
constexpr bool bAllowShrinking = false ;
2022-09-28 22:19:31 -04:00
ParametersToInit . RemoveAtSwap ( i , 1 , bAllowShrinking ) ;
2022-03-10 22:07:08 -05:00
}
2021-11-18 14:37:34 -05:00
}
else
{
2022-02-25 09:59:46 -05:00
constexpr bool bAllowShrinking = false ;
2022-09-28 22:19:31 -04:00
ParametersToInit . RemoveAtSwap ( i , 1 , bAllowShrinking ) ;
2022-09-21 15:42:38 -04:00
2022-03-04 04:08:58 -05:00
# if !NO_LOGGING
2022-09-21 15:42:38 -04:00
if ( : : Metasound : : MetaSoundParameterEnableWarningOnIgnoredParameterCVar )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to set parameter '%s' in asset '%s': No name specified, no transmittable input found, or type mismatch. " ) , * Parameter . ParamName . ToString ( ) , * AssetName ) ;
}
2022-03-04 04:08:58 -05:00
# endif // !NO_LOGGING
2021-11-18 14:37:34 -05:00
}
2021-08-30 14:08:45 -04:00
}
}
2021-08-18 15:16:57 -04:00
void UMetaSoundSource : : InitResources ( )
{
2021-08-30 14:08:45 -04:00
using namespace Metasound : : Frontend ;
2022-08-10 14:18:10 -04:00
using namespace Metasound : : SourcePrivate ;
2022-03-23 15:56:20 -04:00
METASOUND_LLM_SCOPE ;
2021-08-30 14:08:45 -04:00
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundSource : : InitResources ) ;
2021-08-18 15:16:57 -04:00
2022-08-10 14:18:10 -04:00
RegisterGraphWithFrontend ( GetInitRegistrationOptions ( ) ) ;
2021-08-18 15:16:57 -04:00
}
2021-06-16 11:21:13 -04:00
Metasound : : Frontend : : FNodeClassInfo UMetaSoundSource : : GetAssetClassInfo ( ) const
2021-06-08 10:52:31 -04:00
{
2022-09-12 19:52:49 -04:00
return { GetDocumentChecked ( ) . RootGraph , FSoftObjectPath ( this ) } ;
2021-06-08 10:52:31 -04:00
}
2020-12-14 15:48:27 -04:00
2021-04-02 02:09:50 -04:00
bool UMetaSoundSource : : IsPlayable ( ) const
2020-07-23 20:32:26 -04:00
{
// todo: cache off whether this metasound is buildable to an operator.
return true ;
}
2021-04-02 02:09:50 -04:00
bool UMetaSoundSource : : SupportsSubtitles ( ) const
2020-07-23 20:32:26 -04:00
{
return Super : : SupportsSubtitles ( ) ;
}
2022-01-18 18:05:56 -05:00
float UMetaSoundSource : : GetDuration ( ) const
2020-07-23 20:32:26 -04:00
{
2022-04-25 19:12:43 -04:00
// This is an unfortunate function required by logic in determining what sounds can be potentially
// culled (in this case prematurally). MetaSound OneShots are stopped either by internally logic that
// triggers OnFinished, or if an external system requests the sound to be stopped. Setting the duration
// as a "close to" maximum length without being considered looping avoids the MetaSound from being
// culled inappropriately.
return IsOneShot ( ) ? INDEFINITELY_LOOPING_DURATION - 1.0f : INDEFINITELY_LOOPING_DURATION ;
2020-07-23 20:32:26 -04:00
}
2021-12-10 20:37:31 -05:00
bool UMetaSoundSource : : ImplementsParameterInterface ( Audio : : FParameterInterfacePtr InInterface ) const
2021-11-22 15:55:50 -05:00
{
2021-12-10 20:37:31 -05:00
const FMetasoundFrontendVersion Version { InInterface - > GetName ( ) , { InInterface - > GetVersion ( ) . Major , InInterface - > GetVersion ( ) . Minor } } ;
return GetDocumentChecked ( ) . Interfaces . Contains ( Version ) ;
2021-11-22 15:55:50 -05:00
}
2022-08-18 13:55:13 -04:00
ISoundGeneratorPtr UMetaSoundSource : : CreateSoundGenerator ( const FSoundGeneratorInitParams & InParams , TArray < FAudioParameter > & & InDefaultParameters )
2020-07-23 20:32:26 -04:00
{
2020-11-17 17:52:08 -04:00
using namespace Metasound ;
2021-05-10 19:52:56 -04:00
using namespace Metasound : : Frontend ;
2021-06-23 20:08:21 -04:00
using namespace Metasound : : Engine ;
2023-04-05 17:38:47 -04:00
using namespace Metasound : : SourcePrivate ;
2020-11-17 17:52:08 -04:00
2022-03-23 15:56:20 -04:00
METASOUND_LLM_SCOPE ;
2021-08-18 15:16:57 -04:00
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundSource : : CreateSoundGenerator ) ;
2021-08-11 15:22:01 -04:00
2020-07-23 20:32:26 -04:00
SampleRate = InParams . SampleRate ;
2021-02-16 01:26:50 -04:00
FOperatorSettings InSettings = GetOperatorSettings ( static_cast < FSampleRate > ( SampleRate ) ) ;
2021-07-28 17:12:57 -04:00
FMetasoundEnvironment Environment = CreateEnvironment ( InParams ) ;
2023-04-05 17:38:47 -04:00
FParameterRouter & Router = GetParameterRouter ( ) ;
2023-04-06 18:47:28 -04:00
TSharedPtr < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > DataChannel = Router . FindOrCreateDataChannelForReader ( InParams . AudioDeviceID , InParams . InstanceID ) ;
2020-07-23 20:32:26 -04:00
2022-05-10 16:51:39 -04:00
FOperatorBuilderSettings BuilderSettings = FOperatorBuilderSettings : : GetDefaultSettings ( ) ;
// Graph analyzer currently only enabled for preview sounds (but can theoretically be supported for all sounds)
BuilderSettings . bPopulateInternalDataReferences = InParams . bIsPreviewSound ;
2023-04-05 17:38:47 -04:00
constexpr bool bBuildSynchronous = false ;
2020-07-23 20:32:26 -04:00
2023-07-18 16:24:42 -04:00
const bool bIsDynamic = DynamicTransactor . IsValid ( ) ;
TSharedPtr < FMetasoundGenerator > Generator ;
if ( bIsDynamic )
{
// In order to ensure synchronization and avoid race conditions the current state
// of the graph is copied and transform queue created here. This ensures that:
//
// 1. Modifications to the underlying FGraph in the FDynamicOperatorTransactor can continue
// while the generator is being constructed on an async task. If this were not ensured,
// a race condition would be introduced wherein the FGraph could be manipulated while the
// graph is being read while building the generator.
//
// 2. The state of the FGraph and TransformQueue are synchronized so that any additional
// changes applied to the FDynamicOperatorTransactor will be placed in the TransformQueue.
// The dynamic operator & generator will then consume these transforms after it has finished
// being built.
2023-08-02 12:05:30 -04:00
BuilderSettings . bEnableOperatorRebind = true ;
2023-07-18 16:24:42 -04:00
FMetasoundDynamicGraphGeneratorInitParams InitParams
{
{
InSettings ,
MoveTemp ( BuilderSettings ) ,
MakeShared < FGraph > ( DynamicTransactor - > GetGraph ( ) ) , // Make a copy of the graph.
Environment ,
GetName ( ) ,
GetOutputAudioChannelOrder ( ) ,
MoveTemp ( InDefaultParameters ) ,
bBuildSynchronous ,
DataChannel
} ,
DynamicTransactor - > CreateTransformQueue ( InSettings , Environment ) // Create transaction queue
} ;
TSharedPtr < FMetasoundDynamicGraphGenerator > DynamicGenerator = MakeShared < FMetasoundDynamicGraphGenerator > ( InSettings ) ;
DynamicGenerator - > Init ( MoveTemp ( InitParams ) ) ;
Generator = MoveTemp ( DynamicGenerator ) ;
}
else
{
TSharedPtr < const IGraph , ESPMode : : ThreadSafe > MetasoundGraph = GetRuntimeData ( ) . Graph ;
if ( ! MetasoundGraph . IsValid ( ) )
{
return ISoundGeneratorPtr ( nullptr ) ;
}
FMetasoundGeneratorInitParams InitParams
{
InSettings ,
MoveTemp ( BuilderSettings ) ,
MetasoundGraph ,
Environment ,
GetName ( ) ,
GetOutputAudioChannelOrder ( ) ,
MoveTemp ( InDefaultParameters ) ,
bBuildSynchronous ,
DataChannel
} ;
Generator = MakeShared < FMetasoundConstGraphGenerator > ( MoveTemp ( InitParams ) ) ;
}
if ( Generator . IsValid ( ) )
{
TrackGenerator ( InParams . AudioComponentId , Generator ) ;
}
2022-12-13 18:25:01 -05:00
return ISoundGeneratorPtr ( Generator ) ;
}
void UMetaSoundSource : : OnEndGenerate ( ISoundGeneratorPtr Generator )
{
using namespace Metasound ;
ForgetGenerator ( Generator ) ;
2020-07-23 20:32:26 -04:00
}
2021-11-18 19:26:47 -05:00
bool UMetaSoundSource : : GetAllDefaultParameters ( TArray < FAudioParameter > & OutParameters ) const
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
using namespace Metasound : : Engine ;
2022-03-10 22:07:08 -05:00
// TODO: Make this use the cached runtime data's input copy. This call can become expensive if called repeatedly.
2022-08-18 13:55:13 -04:00
TArray < FMetasoundFrontendClassInput > PublicInputs = GetPublicClassInputs ( ) ;
for ( const FMetasoundFrontendClassInput & Input : PublicInputs )
2022-02-15 11:30:22 -05:00
{
2021-11-18 19:26:47 -05:00
FAudioParameter Params ;
2022-03-10 22:07:08 -05:00
Params . ParamName = Input . Name ;
Params . TypeName = Input . TypeName ;
2022-02-15 11:30:22 -05:00
2022-03-10 22:07:08 -05:00
switch ( Input . DefaultLiteral . GetType ( ) )
2021-11-18 19:26:47 -05:00
{
2022-02-15 11:30:22 -05:00
case EMetasoundFrontendLiteralType : : Boolean :
{
2023-01-17 18:39:44 -05:00
static const FName TriggerName = " Trigger " ;
if ( Params . TypeName = = TriggerName )
{
Params . ParamType = EAudioParameterType : : Trigger ;
}
else
{
Params . ParamType = EAudioParameterType : : Boolean ;
}
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Params . BoolParam ) ) ;
2022-02-15 11:30:22 -05:00
}
2021-11-18 19:26:47 -05:00
break ;
2022-02-15 11:30:22 -05:00
case EMetasoundFrontendLiteralType : : BooleanArray :
{
Params . ParamType = EAudioParameterType : : BooleanArray ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Params . ArrayBoolParam ) ) ;
2022-02-15 11:30:22 -05:00
}
2021-11-18 19:26:47 -05:00
break ;
2022-02-15 11:30:22 -05:00
case EMetasoundFrontendLiteralType : : Integer :
{
Params . ParamType = EAudioParameterType : : Integer ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Params . IntParam ) ) ;
2022-02-15 11:30:22 -05:00
}
2021-11-18 19:26:47 -05:00
break ;
2022-02-15 11:30:22 -05:00
case EMetasoundFrontendLiteralType : : IntegerArray :
{
Params . ParamType = EAudioParameterType : : IntegerArray ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Params . ArrayIntParam ) ) ;
2022-02-15 11:30:22 -05:00
}
2021-11-18 19:26:47 -05:00
break ;
2022-02-15 11:30:22 -05:00
case EMetasoundFrontendLiteralType : : Float :
{
Params . ParamType = EAudioParameterType : : Float ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Params . FloatParam ) ) ;
2022-02-15 11:30:22 -05:00
}
2021-11-18 19:26:47 -05:00
break ;
2022-02-15 11:30:22 -05:00
case EMetasoundFrontendLiteralType : : FloatArray :
{
Params . ParamType = EAudioParameterType : : FloatArray ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Params . ArrayFloatParam ) ) ;
2022-02-15 11:30:22 -05:00
}
break ;
case EMetasoundFrontendLiteralType : : String :
{
Params . ParamType = EAudioParameterType : : String ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Params . StringParam ) ) ;
2022-02-15 11:30:22 -05:00
}
break ;
case EMetasoundFrontendLiteralType : : StringArray :
{
Params . ParamType = EAudioParameterType : : StringArray ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Params . ArrayStringParam ) ) ;
2022-02-15 11:30:22 -05:00
}
break ;
case EMetasoundFrontendLiteralType : : UObject :
{
Params . ParamType = EAudioParameterType : : Object ;
UObject * Object = nullptr ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( Object ) ) ;
2022-02-15 11:30:22 -05:00
Params . ObjectParam = Object ;
}
break ;
case EMetasoundFrontendLiteralType : : UObjectArray :
{
Params . ParamType = EAudioParameterType : : ObjectArray ;
2023-04-18 22:39:29 -04:00
ensure ( Input . DefaultLiteral . TryGet ( MutableView ( Params . ArrayObjectParam ) ) ) ;
2022-02-15 11:30:22 -05:00
}
break ;
default :
2021-11-18 19:26:47 -05:00
break ;
}
if ( Params . ParamType ! = EAudioParameterType : : None )
{
OutParameters . Add ( Params ) ;
}
}
return true ;
}
2021-08-30 14:08:45 -04:00
bool UMetaSoundSource : : IsParameterValid ( const FAudioParameter & InParameter ) const
2021-11-18 14:37:34 -05:00
{
2023-07-20 14:02:15 -04:00
const TArray < FMetasoundFrontendClassInput > & Inputs = GetDocumentChecked ( ) . RootGraph . Interface . Inputs ;
const FMetasoundFrontendVertex * Vertex = Algo : : FindByPredicate ( Inputs , [ & InParameter ] ( const FMetasoundFrontendClassInput & Input )
2021-11-18 14:37:34 -05:00
{
2023-07-20 14:02:15 -04:00
return Input . Name = = InParameter . ParamName ;
2021-11-18 14:37:34 -05:00
} ) ;
2023-07-20 14:02:15 -04:00
return IsParameterValid ( InParameter , Vertex ) ;
2021-11-18 14:37:34 -05:00
}
2023-07-20 14:02:15 -04:00
bool UMetaSoundSource : : IsParameterValid ( const FAudioParameter & InParameter , const FMetasoundFrontendVertex * InVertex ) const
2021-01-22 03:05:22 -04:00
{
2021-08-30 14:08:45 -04:00
using namespace Metasound ;
using namespace Metasound : : Frontend ;
2022-03-10 22:07:08 -05:00
if ( InParameter . ParamName . IsNone ( ) )
{
return false ;
}
2023-07-20 14:02:15 -04:00
if ( ! InVertex )
{
return false ;
}
const FName & TypeName = InVertex - > TypeName ;
if ( ! InParameter . TypeName . IsNone ( ) & & InParameter . TypeName ! = TypeName )
2021-08-30 14:08:45 -04:00
{
2021-11-18 14:37:34 -05:00
return false ;
}
2021-08-30 14:08:45 -04:00
2021-11-18 14:37:34 -05:00
bool bIsValid = false ;
switch ( InParameter . ParamType )
{
2023-01-17 18:39:44 -05:00
case EAudioParameterType : : Trigger :
2021-11-18 14:37:34 -05:00
case EAudioParameterType : : Boolean :
2021-08-30 14:08:45 -04:00
{
2021-11-18 14:37:34 -05:00
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsBoolParsable ;
}
break ;
case EAudioParameterType : : BooleanArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsBoolArrayParsable ;
}
break ;
case EAudioParameterType : : Float :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsFloatParsable ;
}
break ;
case EAudioParameterType : : FloatArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsFloatArrayParsable ;
}
break ;
case EAudioParameterType : : Integer :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsIntParsable ;
}
break ;
case EAudioParameterType : : IntegerArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsIntArrayParsable ;
}
break ;
case EAudioParameterType : : Object :
{
2023-07-20 14:02:15 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . IsValidUObjectForDataType ( TypeName , InParameter . ObjectParam ) ;
2021-11-18 14:37:34 -05:00
}
break ;
case EAudioParameterType : : ObjectArray :
{
bIsValid = true ;
2022-08-18 13:55:13 -04:00
const FName ElementTypeName = CreateElementTypeNameFromArrayTypeName ( TypeName ) ;
2023-07-20 14:02:15 -04:00
for ( const UObject * Object : InParameter . ArrayObjectParam )
2021-08-30 14:08:45 -04:00
{
2023-07-26 16:02:00 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . IsValidUObjectForDataType ( ElementTypeName , Object ) ;
2021-11-18 14:37:34 -05:00
if ( ! bIsValid )
2021-08-30 14:08:45 -04:00
{
2021-11-18 14:37:34 -05:00
break ;
2021-08-30 14:08:45 -04:00
}
}
}
2021-11-18 14:37:34 -05:00
break ;
case EAudioParameterType : : String :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsStringParsable ;
}
break ;
case EAudioParameterType : : StringArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsStringArrayParsable ;
}
break ;
case EAudioParameterType : : NoneArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsDefaultArrayParsable ;
}
case EAudioParameterType : : None :
default :
{
FDataTypeRegistryInfo DataTypeInfo ;
2022-08-18 13:55:13 -04:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( TypeName , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsDefaultParsable ;
}
break ;
}
2021-08-30 14:08:45 -04:00
return bIsValid ;
}
2022-01-18 18:05:56 -05:00
bool UMetaSoundSource : : IsLooping ( ) const
2022-01-13 17:34:30 -05:00
{
return ! IsOneShot ( ) ;
}
2022-01-18 18:05:56 -05:00
bool UMetaSoundSource : : IsOneShot ( ) const
2021-12-15 23:11:10 -05:00
{
using namespace Metasound : : Frontend ;
// If the metasound source implements the one-shot interface, then it's a one-shot metasound
return IsInterfaceDeclared ( SourceOneShotInterface : : GetVersion ( ) ) ;
}
2022-09-28 22:19:31 -04:00
TSharedPtr < Audio : : IParameterTransmitter > UMetaSoundSource : : CreateParameterTransmitter ( Audio : : FParameterTransmitterInitParams & & InParams ) const
2021-08-30 14:08:45 -04:00
{
2023-04-05 17:38:47 -04:00
using namespace Metasound ;
using namespace Metasound : : SourcePrivate ;
2022-03-23 15:56:20 -04:00
METASOUND_LLM_SCOPE ;
2023-04-05 17:38:47 -04:00
const FRuntimeData & RuntimeData = GetRuntimeData ( ) ;
2021-01-22 03:05:22 -04:00
2023-04-05 17:38:47 -04:00
TArray < FName > ValidParameters ;
Algo : : Transform ( RuntimeData . TransmittableInputs , ValidParameters , [ ] ( const FMetasoundFrontendClassInput & InputVertex ) { return InputVertex . Name ; } ) ;
FParameterRouter & Router = GetParameterRouter ( ) ;
2023-04-06 18:47:28 -04:00
TSharedPtr < TSpscQueue < FMetaSoundParameterTransmitter : : FParameter > > DataChannel = Router . FindOrCreateDataChannelForWriter ( InParams . AudioDeviceID , InParams . InstanceID ) ;
2023-04-05 17:38:47 -04:00
Metasound : : FMetaSoundParameterTransmitter : : FInitParams InitParams ( GetOperatorSettings ( InParams . SampleRate ) , InParams . InstanceID , MoveTemp ( InParams . DefaultParams ) , MoveTemp ( ValidParameters ) , DataChannel ) ;
InitParams . DebugMetaSoundName = GetFName ( ) ;
2021-01-22 03:05:22 -04:00
2022-09-28 22:19:31 -04:00
return MakeShared < Metasound : : FMetaSoundParameterTransmitter > ( MoveTemp ( InitParams ) ) ;
2021-01-22 03:05:22 -04:00
}
2021-04-02 02:09:50 -04:00
Metasound : : FOperatorSettings UMetaSoundSource : : GetOperatorSettings ( Metasound : : FSampleRate InSampleRate ) const
2021-01-22 03:05:22 -04:00
{
2022-05-10 16:51:39 -04:00
const float BlockRate = Metasound : : Frontend : : GetDefaultBlockRate ( ) ;
2021-01-22 03:05:22 -04:00
return Metasound : : FOperatorSettings ( InSampleRate , BlockRate ) ;
}
2021-07-28 17:12:57 -04:00
Metasound : : FMetasoundEnvironment UMetaSoundSource : : CreateEnvironment ( ) const
{
using namespace Metasound ;
2021-12-10 20:37:31 -05:00
using namespace Metasound : : Frontend ;
2021-07-28 17:12:57 -04:00
2022-02-07 18:00:45 -05:00
FMetasoundEnvironment Environment ;
2021-12-10 20:37:31 -05:00
Environment . SetValue < uint32 > ( SourceInterface : : Environment : : SoundUniqueID , GetUniqueID ( ) ) ;
2021-07-28 17:12:57 -04:00
return Environment ;
}
Metasound : : FMetasoundEnvironment UMetaSoundSource : : CreateEnvironment ( const FSoundGeneratorInitParams & InParams ) const
{
using namespace Metasound ;
using namespace Metasound : : Engine ;
2021-12-10 20:37:31 -05:00
using namespace Metasound : : Frontend ;
2021-07-28 17:12:57 -04:00
FMetasoundEnvironment Environment = CreateEnvironment ( ) ;
2021-12-10 20:37:31 -05:00
Environment . SetValue < bool > ( SourceInterface : : Environment : : IsPreview , InParams . bIsPreviewSound ) ;
Environment . SetValue < uint64 > ( SourceInterface : : Environment : : TransmitterID , InParams . InstanceID ) ;
2022-02-07 18:00:45 -05:00
Environment . SetValue < Audio : : FDeviceId > ( SourceInterface : : Environment : : DeviceID , InParams . AudioDeviceID ) ;
2022-06-29 15:04:47 -04:00
Environment . SetValue < int32 > ( SourceInterface : : Environment : : AudioMixerNumOutputFrames , InParams . AudioMixerNumOutputFrames ) ;
2021-12-10 20:37:31 -05:00
2021-08-09 15:13:40 -04:00
# if WITH_METASOUND_DEBUG_ENVIRONMENT
2021-12-10 20:37:31 -05:00
Environment . SetValue < FString > ( SourceInterface : : Environment : : GraphName , GetFullName ( ) ) ;
2021-08-09 15:13:40 -04:00
# endif // WITH_METASOUND_DEBUG_ENVIRONMENT
2021-07-28 17:12:57 -04:00
return Environment ;
}
2021-08-30 14:08:45 -04:00
Metasound : : FMetasoundEnvironment UMetaSoundSource : : CreateEnvironment ( const Audio : : FParameterTransmitterInitParams & InParams ) const
2021-07-28 17:12:57 -04:00
{
using namespace Metasound ;
using namespace Metasound : : Engine ;
2021-12-10 20:37:31 -05:00
using namespace Metasound : : Frontend ;
2021-07-28 17:12:57 -04:00
FMetasoundEnvironment Environment = CreateEnvironment ( ) ;
2021-12-10 20:37:31 -05:00
Environment . SetValue < uint64 > ( SourceInterface : : Environment : : TransmitterID , InParams . InstanceID ) ;
2021-07-28 17:12:57 -04:00
return Environment ;
}
2022-08-15 10:49:30 -04:00
const TArray < Metasound : : FVertexName > & UMetaSoundSource : : GetOutputAudioChannelOrder ( ) const
2021-07-28 17:12:57 -04:00
{
2023-03-07 17:01:52 -05:00
using namespace Metasound : : Engine ;
using namespace Metasound : : Frontend ;
2021-07-28 17:12:57 -04:00
2023-03-07 17:01:52 -05:00
if ( const FOutputAudioFormatInfo * FormatInfo = GetOutputAudioFormatInfo ( ) . Find ( OutputFormat ) )
2021-07-28 17:12:57 -04:00
{
2022-08-15 10:49:30 -04:00
return FormatInfo - > OutputVertexChannelOrder ;
2021-07-28 17:12:57 -04:00
}
else
{
// Unhandled audio format. Need to update audio output format vertex key map.
checkNoEntry ( ) ;
2021-09-13 14:14:37 -04:00
static const TArray < Metasound : : FVertexName > Empty ;
2021-07-28 17:12:57 -04:00
return Empty ;
}
}
2022-12-13 18:25:01 -05:00
void UMetaSoundSource : : TrackGenerator ( uint64 Id , TSharedPtr < Metasound : : FMetasoundGenerator > Generator )
{
FScopeLock GeneratorMapLock ( & GeneratorMapCriticalSection ) ;
Generators . Add ( Id , Generator ) ;
OnGeneratorInstanceCreated . Broadcast ( Id , Generator ) ;
}
void UMetaSoundSource : : ForgetGenerator ( ISoundGeneratorPtr Generator )
{
using namespace Metasound ;
FMetasoundGenerator * AsMetasoundGenerator = static_cast < FMetasoundGenerator * > ( Generator . Get ( ) ) ;
FScopeLock GeneratorMapLock ( & GeneratorMapCriticalSection ) ;
for ( auto It = Generators . begin ( ) ; It ! = Generators . end ( ) ; + + It )
{
if ( ( * It ) . Value . HasSameObject ( AsMetasoundGenerator ) )
{
OnGeneratorInstanceDestroyed . Broadcast ( ( * It ) . Key , StaticCastSharedPtr < Metasound : : FMetasoundGenerator > ( Generator ) ) ;
Generators . Remove ( ( * It ) . Key ) ;
return ;
}
}
}
TWeakPtr < Metasound : : FMetasoundGenerator > UMetaSoundSource : : GetGeneratorForAudioComponent ( uint64 ComponentId ) const
{
using namespace Metasound ;
FScopeLock GeneratorMapLock ( & GeneratorMapCriticalSection ) ;
const TWeakPtr < FMetasoundGenerator > * Result = Generators . Find ( ComponentId ) ;
if ( ! Result )
{
return TWeakPtr < FMetasoundGenerator > ( nullptr ) ;
}
return * Result ;
}
2023-04-05 17:38:47 -04:00
Metasound : : SourcePrivate : : FParameterRouter & UMetaSoundSource : : GetParameterRouter ( )
{
using namespace Metasound : : SourcePrivate ;
static FParameterRouter Router ;
return Router ;
}
2023-08-09 16:45:21 -04:00
TSharedPtr < Metasound : : DynamicGraph : : FDynamicOperatorTransactor > UMetaSoundSource : : SetDynamicGeneratorEnabled ( bool bInIsEnabled )
2023-06-14 17:01:59 -04:00
{
using namespace Metasound ;
using namespace Metasound : : DynamicGraph ;
2023-08-09 16:45:21 -04:00
if ( bInIsEnabled )
2023-06-14 17:01:59 -04:00
{
2023-08-09 16:45:21 -04:00
if ( ! DynamicTransactor . IsValid ( ) )
2023-06-14 17:01:59 -04:00
{
2023-08-09 16:45:21 -04:00
TSharedPtr < FGraph > CurrentGraph = GetRuntimeData ( ) . Graph ;
if ( CurrentGraph . IsValid ( ) )
{
DynamicTransactor = MakeShared < FDynamicOperatorTransactor > ( * CurrentGraph ) ;
}
else
{
DynamicTransactor = MakeShared < FDynamicOperatorTransactor > ( ) ;
}
2023-06-14 17:01:59 -04:00
}
}
else
{
DynamicTransactor . Reset ( ) ;
}
return DynamicTransactor ;
}
TSharedPtr < Metasound : : DynamicGraph : : FDynamicOperatorTransactor > UMetaSoundSource : : GetDynamicGeneratorTransactor ( ) const
{
return DynamicTransactor ;
}
2023-04-05 17:38:47 -04:00
2021-12-10 20:37:31 -05:00
# undef LOCTEXT_NAMESPACE // MetaSound