2020-07-23 20:32:26 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundSource.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"
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"
2021-06-23 20:08:21 -04:00
# include "MetasoundEngineArchetypes.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"
2021-07-28 17:12:57 -04:00
# include "MetasoundFrontendInjectReceiveNodes.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-12-10 20:37:31 -05:00
# include "MetasoundOutputFormatInterfaces.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-12-10 20:37:31 -05:00
# include "MetasoundSourceInterface.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"
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
2021-07-28 17:12:57 -04:00
{
2022-01-11 13:52:09 -05:00
using FFormatOutputVertexKeyMap = TMap < EMetasoundSourceAudioFormat , TArray < Metasound : : FVertexName > > ;
const FFormatOutputVertexKeyMap & GetFormatOutputVertexKeys ( )
{
auto CreateVertexKeyMap = [ ] ( )
{
using namespace Metasound : : Frontend ;
return FFormatOutputVertexKeyMap
{
{
EMetasoundSourceAudioFormat : : Mono ,
{
OutputFormatMonoInterface : : Outputs : : MonoOut
}
} ,
{
EMetasoundSourceAudioFormat : : Stereo ,
{
OutputFormatStereoInterface : : Outputs : : LeftOut ,
OutputFormatStereoInterface : : Outputs : : RightOut ,
}
}
} ;
} ;
static const FFormatOutputVertexKeyMap Map = CreateVertexKeyMap ( ) ;
return Map ;
}
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 ;
}
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
{
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
}
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-02-24 23:28:20 -05:00
Metasound : : 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
{
2021-06-08 10:52:31 -04:00
using namespace Metasound ;
2021-11-22 15:55:50 -05:00
using namespace Metasound : : Engine ;
2021-06-08 10:52:31 -04:00
using namespace Metasound : : Frontend ;
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
{
2021-06-08 10:52:31 -04:00
ConvertFromPreset ( ) ;
2021-06-23 20:08:21 -04:00
bool bDidModifyDocument = false ;
2020-12-14 15:48:27 -04:00
switch ( OutputFormat )
{
case EMetasoundSourceAudioFormat : : Mono :
2021-06-08 10:52:31 -04:00
{
2021-11-22 15:55:50 -05:00
bDidModifyDocument = FModifyRootGraphInterfaces (
2021-12-10 20:37:31 -05:00
{ OutputFormatStereoInterface : : GetVersion ( ) } ,
{ OutputFormatMonoInterface : : GetVersion ( ) }
2021-11-22 15:55:50 -05:00
) . Transform ( GetDocumentHandle ( ) ) ;
2021-06-08 10:52:31 -04:00
}
break ;
2020-12-14 15:48:27 -04:00
2021-06-08 10:52:31 -04:00
case EMetasoundSourceAudioFormat : : Stereo :
{
2021-11-22 15:55:50 -05:00
bDidModifyDocument = FModifyRootGraphInterfaces (
2021-12-10 20:37:31 -05:00
{ OutputFormatMonoInterface : : GetVersion ( ) } ,
{ OutputFormatStereoInterface : : GetVersion ( ) }
2021-11-22 15:55:50 -05:00
) . Transform ( GetDocumentHandle ( ) ) ;
2021-06-08 10:52:31 -04:00
}
break ;
default :
{
static_assert ( static_cast < int32 > ( EMetasoundSourceAudioFormat : : COUNT ) = = 2 , " Possible missing format switch case coverage. " ) ;
}
break ;
}
2021-06-23 20:08:21 -04:00
if ( bDidModifyDocument )
2021-06-08 10:52:31 -04:00
{
2021-11-22 15:55:50 -05:00
ConformObjectDataToInterfaces ( ) ;
2021-08-18 15:16:57 -04:00
// Use the editor form of register to ensure other editors'
// MetaSounds are auto-updated if they are referencing this graph.
if ( Graph )
{
Graph - > RegisterGraphWithFrontend ( ) ;
}
2021-06-23 20:08:21 -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
{
2021-12-10 20:37:31 -05:00
using namespace Metasound : : Frontend ;
if ( IsInterfaceDeclared ( OutputFormatMonoInterface : : GetVersion ( ) ) )
2021-08-18 15:16:57 -04:00
{
if ( OutputFormat ! = EMetasoundSourceAudioFormat : : Mono | | NumChannels ! = 1 )
{
OutputFormat = EMetasoundSourceAudioFormat : : Mono ;
NumChannels = 1 ;
return true ;
}
}
2021-12-10 20:37:31 -05:00
if ( IsInterfaceDeclared ( OutputFormatStereoInterface : : GetVersion ( ) ) )
2021-08-18 15:16:57 -04:00
{
if ( OutputFormat ! = EMetasoundSourceAudioFormat : : Stereo | | NumChannels ! = 2 )
{
OutputFormat = EMetasoundSourceAudioFormat : : Stereo ;
NumChannels = 2 ;
return true ;
}
}
return false ;
}
2021-07-27 15:36:03 -04:00
void UMetaSoundSource : : BeginDestroy ( )
{
UnregisterGraphWithFrontend ( ) ;
Super : : BeginDestroy ( ) ;
}
void UMetaSoundSource : : PreSave ( FObjectPreSaveContext InSaveContext )
{
Super : : PreSave ( InSaveContext ) ;
2021-08-31 16:07:45 -04:00
Metasound : : PreSaveAsset ( * this , InSaveContext ) ;
2021-07-27 15:36:03 -04:00
}
void UMetaSoundSource : : Serialize ( FArchive & InArchive )
{
Super : : Serialize ( InArchive ) ;
Metasound : : SerializeToArchive ( * this , InArchive ) ;
}
2021-08-18 15:16:57 -04:00
void UMetaSoundSource : : SetReferencedAssetClassKeys ( TSet < Metasound : : Frontend : : FNodeRegistryKey > & & InKeys )
{
ReferencedAssetClassKeys = MoveTemp ( InKeys ) ;
}
2021-11-07 23:43:01 -05:00
TSet < FSoftObjectPath > & UMetaSoundSource : : GetReferencedAssetClassCache ( )
{
return ReferenceAssetClassCache ;
}
const TSet < FSoftObjectPath > & UMetaSoundSource : : GetReferencedAssetClassCache ( ) const
2021-08-18 15:16:57 -04:00
{
return ReferenceAssetClassCache ;
}
2021-06-08 10:52:31 -04:00
# if WITH_EDITORONLY_DATA
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-02-25 15:48:47 -05:00
void UMetaSoundSource : : PostLoad ( )
{
Super : : PostLoad ( ) ;
Duration = GetDuration ( ) ;
bLooping = IsLooping ( ) ;
}
2021-06-16 11:21:13 -04:00
void UMetaSoundSource : : SetRegistryAssetClassInfo ( const Metasound : : Frontend : : FNodeClassInfo & InNodeInfo )
{
Metasound : : SetMetaSoundRegistryAssetClassInfo ( * this , InNodeInfo ) ;
}
2021-06-08 10:52:31 -04:00
# endif // WITH_EDITORONLY_DATA
2021-08-30 14:08:45 -04:00
void UMetaSoundSource : : InitParameters ( TArray < FAudioParameter > & InParametersToInit , FName InFeatureName )
{
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-03-10 22:07:08 -05:00
const TArray < FMetasoundFrontendClassInput > & TransmittableInputs = RuntimeData . TransmittableInputs ;
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-03-10 22:07:08 -05:00
auto Sanitize = [ & TransmittableInputs ] ( FAudioParameter & Parameter ) - > bool
2022-02-25 09:59:46 -05:00
{
2022-03-10 22:07:08 -05:00
auto FindInput = [ & Parameter ] ( const FMetasoundFrontendClassInput & Input )
2022-02-25 09:59:46 -05:00
{
2022-03-10 22:07:08 -05:00
if ( Parameter . ParamName = = Input . Name )
2022-02-25 09:59:46 -05:00
{
2022-03-10 22:07:08 -05:00
return Parameter . TypeName . IsNone ( ) | | Parameter . TypeName = = Input . TypeName ;
2022-02-25 09:59:46 -05:00
}
2022-03-10 22:07:08 -05:00
return false ;
} ;
const FMetasoundFrontendClassInput * Input = TransmittableInputs . FindByPredicate ( FindInput ) ;
if ( ! Input )
2022-02-25 09:59:46 -05:00
{
return false ;
}
2021-08-30 14:08:45 -04:00
switch ( Parameter . ParamType )
{
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
} ;
auto ConstructProxies = [ this , FeatureName = InFeatureName ] ( FAudioParameter & OutParamToInit )
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
const Audio : : FProxyDataInitParams ProxyInitParams { FeatureName } ;
switch ( OutParamToInit . ParamType )
{
case EAudioParameterType : : Object :
{
FDataTypeRegistryInfo DataTypeInfo ;
if ( IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( OutParamToInit . ObjectParam , DataTypeInfo ) )
{
Audio : : IProxyDataPtr ProxyPtr = IDataTypeRegistry : : Get ( ) . CreateProxyFromUObject ( DataTypeInfo . DataTypeName , OutParamToInit . ObjectParam ) ;
OutParamToInit . ObjectProxies . Emplace ( MoveTemp ( ProxyPtr ) ) ;
// Null out param as it is no longer needed (nor desired to be accessed once passed to the Audio Thread)
OutParamToInit . ObjectParam = nullptr ;
}
}
break ;
case EAudioParameterType : : ObjectArray :
{
for ( TObjectPtr < UObject > & Object : OutParamToInit . ArrayObjectParam )
{
FDataTypeRegistryInfo DataTypeInfo ;
if ( IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( Object , DataTypeInfo ) )
{
Audio : : IProxyDataPtr ProxyPtr = IDataTypeRegistry : : Get ( ) . CreateProxyFromUObject ( DataTypeInfo . DataTypeName , Object ) ;
OutParamToInit . ObjectProxies . Emplace ( MoveTemp ( ProxyPtr ) ) ;
}
}
// 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 ;
}
} ;
2021-11-18 14:37:34 -05:00
TMap < FName , FName > InputNameTypeMap ;
Algo : : Transform ( GetDocumentChecked ( ) . RootGraph . Interface . Inputs , InputNameTypeMap , [ ] ( const FMetasoundFrontendClassInput & Input )
{
return TPair < FName , FName > ( Input . Name , Input . TypeName ) ;
} ) ;
2022-02-25 09:59:46 -05:00
for ( int32 i = InParametersToInit . Num ( ) - 1 ; i > = 0 ; - - i )
2021-08-30 14:08:45 -04:00
{
2022-03-10 22:07:08 -05:00
FAudioParameter & Parameter = InParametersToInit [ 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
{
2022-02-25 09:59:46 -05:00
if ( IsParameterValid ( Parameter , InputNameTypeMap ) )
{
ConstructProxies ( Parameter ) ;
}
else
{
2022-03-10 22:07:08 -05:00
# if !NO_LOGGING
2022-03-04 04:08:58 -05:00
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to set invalid parameter '%s' in asset '%s': Either does not exist or is unsupported type " ) , * Parameter . ParamName . ToString ( ) , * AssetName ) ;
# endif // !NO_LOGGING
2022-03-10 22:07:08 -05:00
constexpr bool bAllowShrinking = false ;
InParametersToInit . RemoveAtSwap ( i , 1 , bAllowShrinking ) ;
}
2021-11-18 14:37:34 -05:00
}
else
{
2022-02-25 09:59:46 -05:00
constexpr bool bAllowShrinking = false ;
InParametersToInit . RemoveAtSwap ( i , 1 , bAllowShrinking ) ;
2022-03-04 04:08:58 -05:00
# if !NO_LOGGING
2022-03-10 22:07:08 -05:00
UE_LOG ( LogMetaSound , Error , 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
{
2021-06-16 11:21:13 -04:00
return { GetDocumentChecked ( ) . RootGraph , * GetPathName ( ) } ;
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
}
2021-04-02 02:09:50 -04:00
ISoundGeneratorPtr UMetaSoundSource : : CreateSoundGenerator ( const FSoundGeneratorInitParams & InParams )
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 ;
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 ) ;
2020-07-23 20:32:26 -04:00
2022-03-10 22:07:08 -05:00
TSharedPtr < const IGraph , ESPMode : : ThreadSafe > MetasoundGraph = GetRuntimeData ( ) . Graph ;
2021-07-28 17:12:57 -04:00
if ( ! MetasoundGraph . IsValid ( ) )
2020-11-17 17:52:08 -04:00
{
2021-01-22 03:05:22 -04:00
return ISoundGeneratorPtr ( nullptr ) ;
}
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 ;
2021-09-13 14:14:37 -04:00
FMetasoundGeneratorInitParams InitParams =
2021-02-10 21:43:31 -04:00
{
2021-03-23 22:43:04 -04:00
InSettings ,
2022-05-10 16:51:39 -04:00
MoveTemp ( BuilderSettings ) ,
2021-09-16 14:46:43 -04:00
MetasoundGraph ,
2021-03-23 22:43:04 -04:00
Environment ,
GetName ( ) ,
2021-12-10 20:37:31 -05:00
GetAudioOutputVertexKeys ( )
2021-03-23 22:43:04 -04:00
} ;
2020-07-23 20:32:26 -04:00
2021-03-23 22:43:04 -04:00
return ISoundGeneratorPtr ( new FMetasoundGenerator ( MoveTemp ( InitParams ) ) ) ;
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.
TArray < FMetasoundFrontendClassInput > TransmittableInputs = GetTransmittableClassInputs ( ) ;
for ( const FMetasoundFrontendClassInput & Input : TransmittableInputs )
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 :
{
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 ;
2022-03-10 22:07:08 -05:00
ensure ( Input . DefaultLiteral . TryGet ( 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
{
TMap < FName , FName > InputNameTypeMap ;
Algo : : Transform ( GetDocumentChecked ( ) . RootGraph . Interface . Inputs , InputNameTypeMap , [ ] ( const FMetasoundFrontendClassInput & Input )
{
return TPair < FName , FName > ( Input . Name , Input . TypeName ) ;
} ) ;
return IsParameterValid ( InParameter , InputNameTypeMap ) ;
}
bool UMetaSoundSource : : IsParameterValid ( const FAudioParameter & InParameter , const TMap < FName , FName > & InInputNameTypeMap ) 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 ;
}
2021-11-18 14:37:34 -05:00
const FName * TypeName = InInputNameTypeMap . Find ( InParameter . ParamName ) ;
if ( ! 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 )
{
case EAudioParameterType : : Boolean :
2021-08-30 14:08:45 -04:00
{
2021-11-18 14:37:34 -05:00
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsBoolParsable ;
}
break ;
case EAudioParameterType : : BooleanArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsBoolArrayParsable ;
}
break ;
case EAudioParameterType : : Float :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsFloatParsable ;
}
break ;
case EAudioParameterType : : FloatArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsFloatArrayParsable ;
}
break ;
case EAudioParameterType : : Integer :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsIntParsable ;
}
break ;
case EAudioParameterType : : IntegerArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsIntArrayParsable ;
}
break ;
case EAudioParameterType : : Object :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( InParameter . ObjectParam , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsProxyParsable ;
bIsValid & = DataTypeInfo . DataTypeName = = * TypeName ;
}
break ;
case EAudioParameterType : : ObjectArray :
{
bIsValid = true ;
2022-03-01 21:34:04 -05:00
const FName ElementTypeName = CreateElementTypeNameFromArrayTypeName ( * TypeName ) ;
2021-11-18 14:37:34 -05:00
for ( UObject * Object : InParameter . ArrayObjectParam )
2021-08-30 14:08:45 -04:00
{
2021-11-18 14:37:34 -05:00
FDataTypeRegistryInfo DataTypeInfo ;
2022-03-01 21:34:04 -05:00
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( Object , DataTypeInfo ) ;
2021-11-18 14:37:34 -05:00
bIsValid & = DataTypeInfo . bIsProxyParsable ;
2022-03-01 21:34:04 -05:00
bIsValid & = DataTypeInfo . DataTypeName = = ElementTypeName ;
2021-08-30 14:08:45 -04:00
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 ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsStringParsable ;
}
break ;
case EAudioParameterType : : StringArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsStringArrayParsable ;
}
break ;
case EAudioParameterType : : NoneArray :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
bIsValid & = DataTypeInfo . bIsDefaultArrayParsable ;
}
case EAudioParameterType : : None :
default :
{
FDataTypeRegistryInfo DataTypeInfo ;
bIsValid = IDataTypeRegistry : : Get ( ) . GetDataTypeInfo ( * TypeName , DataTypeInfo ) ;
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 ( ) ) ;
}
2021-08-30 14:08:45 -04:00
TUniquePtr < Audio : : IParameterTransmitter > UMetaSoundSource : : CreateParameterTransmitter ( Audio : : FParameterTransmitterInitParams & & InParams ) const
{
2022-03-23 15:56:20 -04:00
METASOUND_LLM_SCOPE ;
2021-08-30 14:08:45 -04:00
Metasound : : FMetaSoundParameterTransmitter : : FInitParams InitParams ( GetOperatorSettings ( InParams . SampleRate ) , InParams . InstanceID ) ;
2021-01-22 03:05:22 -04:00
2021-06-08 10:52:31 -04:00
for ( const FSendInfoAndVertexName & InfoAndName : FMetasoundAssetBase : : GetSendInfos ( InParams . InstanceID ) )
2021-01-22 03:05:22 -04:00
{
InitParams . Infos . Add ( InfoAndName . SendInfo ) ;
}
2021-08-30 14:08:45 -04:00
TUniquePtr < Audio : : IParameterTransmitter > NewTransmitter = MakeUnique < Metasound : : FMetaSoundParameterTransmitter > ( InitParams ) ;
2022-03-10 22:07:08 -05:00
NewTransmitter - > SetParameters ( MoveTemp ( InParams . DefaultParams ) ) ;
2021-08-30 14:08:45 -04:00
return NewTransmitter ;
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 ;
}
2021-09-13 14:14:37 -04:00
const TArray < Metasound : : FVertexName > & UMetaSoundSource : : GetAudioOutputVertexKeys ( ) const
2021-07-28 17:12:57 -04:00
{
2022-01-11 13:52:09 -05:00
using namespace Metasound : : SourcePrivate ;
2021-07-28 17:12:57 -04:00
2021-09-13 14:14:37 -04:00
if ( const TArray < Metasound : : FVertexName > * ArrayKeys = GetFormatOutputVertexKeys ( ) . Find ( OutputFormat ) )
2021-07-28 17:12:57 -04:00
{
return * ArrayKeys ;
}
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 ;
}
}
2021-12-10 20:37:31 -05:00
# undef LOCTEXT_NAMESPACE // MetaSound