2022-12-15 17:03:02 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundGeneratorHandle.h"
# include "MetasoundGenerator.h"
# include "MetasoundSource.h"
2023-04-04 12:40:45 -04:00
# include "MetasoundTrace.h"
2023-09-14 11:16:32 -04:00
# include "Analysis/MetasoundFrontendAnalyzerFactory.h"
2023-05-10 08:29:22 -04:00
# include "Analysis/MetasoundFrontendAnalyzerRegistry.h"
2023-09-14 11:16:32 -04:00
# include "Async/Async.h"
2023-05-10 08:29:22 -04:00
# include "Components/AudioComponent.h"
2022-12-15 17:03:02 -05:00
2023-09-14 11:16:32 -04:00
namespace Metasound
{
TMap < FName , FMetasoundGeneratorHandle : : FPassthroughAnalyzerInfo > FMetasoundGeneratorHandle : : PassthroughAnalyzers { } ;
FMetasoundGeneratorHandle : : FMetasoundGeneratorHandle ( FPrivateToken ,
TWeakObjectPtr < UAudioComponent > & & InAudioComponent )
: AudioComponent ( MoveTemp ( InAudioComponent ) )
, AudioComponentId ( AudioComponent . IsValid ( ) ? AudioComponent - > GetAudioComponentID ( ) : INDEX_NONE )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : FMetasoundGeneratorHandle ) ;
if ( ! AudioComponent . IsValid ( ) )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Created a FMetaSoundGeneratorHandle with an invalid UAudioComponent. " ) ) ;
return ;
}
if ( AudioComponent - > bCanPlayMultipleInstances )
{
UE_LOG (
LogMetaSound ,
Warning ,
TEXT ( " Created a FMetaSoundGeneratorHandle for a UAudioComponent that is allowed to play multiple instances. This may not work as expected. " ) )
}
}
TSharedPtr < FMetasoundGeneratorHandle > FMetasoundGeneratorHandle : : Create (
TWeakObjectPtr < UAudioComponent > & & InAudioComponent )
{
TSharedRef < FMetasoundGeneratorHandle > Handle = MakeShared < FMetasoundGeneratorHandle > (
FPrivateToken { } ,
MoveTemp ( InAudioComponent ) ) ;
if ( Handle - > IsValid ( ) )
{
const TWeakObjectPtr < UMetaSoundSource > Source = Handle - > GetMetaSoundSource ( ) ;
if ( ! Source . IsValid ( ) )
{
2024-07-16 16:58:09 -04:00
UE_LOG ( LogMetaSound , Error , TEXT ( " FMetaSoundGeneratorHandle missing source: %s. " ) , * Handle - > ToString ( ) ) ;
2023-09-14 11:16:32 -04:00
return nullptr ;
}
const uint64 AudioComponentId = Handle - > GetAudioComponentId ( ) ;
TWeakPtr < FMetasoundGenerator > GeneratorForComponent = Source - > GetGeneratorForAudioComponent ( AudioComponentId ) ;
// If we have a generator already, set it.
if ( GeneratorForComponent . IsValid ( ) )
{
Handle - > SetGenerator ( MoveTemp ( GeneratorForComponent ) ) ;
}
// Listen for the source creating a new generator
Handle - > GeneratorCreatedDelegateHandle = Source - > OnGeneratorInstanceCreated . AddSP (
Handle ,
& FMetasoundGeneratorHandle : : HandleGeneratorCreated ) ;
// Listen for the generator being destroyed
Handle - > GeneratorDestroyedDelegateHandle = Source - > OnGeneratorInstanceDestroyed . AddSP (
Handle ,
& FMetasoundGeneratorHandle : : HandleGeneratorDestroyed ) ;
return Handle ;
}
return nullptr ;
}
2024-04-11 02:17:22 -04:00
// Remove these PRAGMAs when cleaning up the deprecated OnGeneratorIOUpdated.
// The curly brace line was throwing errors for usage of the deprecated member, presumably it was doing something to tear it down and complaining about it.
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2023-09-14 11:16:32 -04:00
FMetasoundGeneratorHandle : : ~ FMetasoundGeneratorHandle ( )
{
check ( IsInGameThread ( ) ) ;
// unsubscribe from source events
{
const TWeakObjectPtr < UMetaSoundSource > Source = GetMetaSoundSource ( ) ;
if ( Source . IsValid ( ) )
{
Source - > OnGeneratorInstanceCreated . Remove ( GeneratorCreatedDelegateHandle ) ;
Source - > OnGeneratorInstanceDestroyed . Remove ( GeneratorDestroyedDelegateHandle ) ;
}
}
// unset the generator and clean up
SetGenerator ( nullptr ) ;
}
2024-04-11 02:17:22 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2023-09-14 11:16:32 -04:00
bool FMetasoundGeneratorHandle : : IsValid ( ) const
{
return AudioComponent . IsValid ( ) ;
}
uint64 FMetasoundGeneratorHandle : : GetAudioComponentId ( ) const
{
return AudioComponentId ;
}
TSharedPtr < FMetasoundGenerator > FMetasoundGeneratorHandle : : GetGenerator ( ) const
{
return Generator . Pin ( ) ;
}
void FMetasoundGeneratorHandle : : UpdateParameters ( const UMetasoundParameterPack & ParameterPack )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : UpdateParameters ) ;
// Update the latest state
LatestParameterState = ParameterPack . GetCopyOfParameterStorage ( ) ;
// Try to send to the generator
SendParametersToGenerator ( ) ;
}
bool FMetasoundGeneratorHandle : : WatchOutput (
const FName OutputName ,
const FOnMetasoundOutputValueChanged & OnOutputValueChanged ,
const FName AnalyzerName ,
const FName AnalyzerOutputName )
{
2023-10-25 00:54:11 -04:00
return WatchOutputInternal ( OutputName , FWatchOutputUnifiedDelegate ( OnOutputValueChanged ) , AnalyzerName , AnalyzerOutputName ) ;
}
2023-09-14 11:16:32 -04:00
2023-10-25 00:54:11 -04:00
bool FMetasoundGeneratorHandle : : WatchOutput (
const FName OutputName ,
const FOnMetasoundOutputValueChangedNative & OnOutputValueChanged ,
const FName AnalyzerName ,
const FName AnalyzerOutputName )
{
return WatchOutputInternal ( OutputName , FWatchOutputUnifiedDelegate ( OnOutputValueChanged ) , AnalyzerName , AnalyzerOutputName ) ;
2023-09-14 11:16:32 -04:00
}
2024-02-27 19:26:07 -05:00
bool FMetasoundGeneratorHandle : : UnwatchOutput (
FName OutputName ,
const FOnMetasoundOutputValueChanged & OnOutputValueChanged ,
FName AnalyzerName ,
FName AnalyzerOutputName )
{
return UnwatchOutputInternal ( OutputName , FWatchOutputUnifiedDelegate ( OnOutputValueChanged ) , AnalyzerName , AnalyzerOutputName ) ;
}
bool FMetasoundGeneratorHandle : : UnwatchOutput (
FName OutputName ,
const FOnMetasoundOutputValueChangedNative & OnOutputValueChanged ,
FName AnalyzerName ,
FName AnalyzerOutputName )
{
return UnwatchOutputInternal ( OutputName , FWatchOutputUnifiedDelegate ( OnOutputValueChanged ) , AnalyzerName , AnalyzerOutputName ) ;
}
bool FMetasoundGeneratorHandle : : UnwatchOutput (
FName OutputName ,
const FDelegateHandle & OnOutputValueChanged ,
FName AnalyzerName ,
FName AnalyzerOutputName )
{
return UnwatchOutputInternal ( OutputName , FWatchOutputUnifiedDelegate ( OnOutputValueChanged ) , AnalyzerName , AnalyzerOutputName ) ;
}
2023-09-14 11:16:32 -04:00
void FMetasoundGeneratorHandle : : RegisterPassthroughAnalyzerForType (
const FName TypeName ,
const FName AnalyzerName ,
const FName OutputName )
{
check ( ! PassthroughAnalyzers . Contains ( TypeName ) ) ;
PassthroughAnalyzers . Add ( TypeName , { AnalyzerName , OutputName } ) ;
}
void FMetasoundGeneratorHandle : : EnableRuntimeRenderTiming ( bool Enable )
{
bRuntimeRenderTimingShouldBeEnabled = Enable ;
if ( const TSharedPtr < FMetasoundGenerator > PinnedGenerator = Generator . Pin ( ) )
{
PinnedGenerator - > EnableRuntimeRenderTiming ( bRuntimeRenderTimingShouldBeEnabled ) ;
}
}
double FMetasoundGeneratorHandle : : GetCPUCoreUtilization ( ) const
{
if ( const TSharedPtr < FMetasoundGenerator > PinnedGenerator = Generator . Pin ( ) )
{
return PinnedGenerator - > GetCPUCoreUtilization ( ) ;
}
return 0 ;
}
2024-07-16 16:58:09 -04:00
FString FMetasoundGeneratorHandle : : ToString ( ) const
{
if ( ! IsValid ( ) )
{
return FString : : Printf ( TEXT ( " Invalid Handle " ) ) ;
}
check ( AudioComponent . IsValid ( ) ) ;
return FString : : Printf ( TEXT ( " %s [Id:%d] with owner %s " ) , * GetNameSafe ( AudioComponent . Get ( ) ) , AudioComponentId , * GetNameSafe ( AudioComponent - > GetOwner ( ) ) ) ;
}
2023-09-14 11:16:32 -04:00
void FMetasoundGeneratorHandle : : SetGenerator ( TWeakPtr < FMetasoundGenerator > & & InGenerator )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : SetGenerator ) ;
check ( IsInGameThread ( ) ) ;
// early out if the incoming generator is null and the current generator is null
if ( ! Generator . IsValid ( ) & & ! InGenerator . IsValid ( ) )
{
return ;
}
if ( const TSharedPtr < FMetasoundGenerator > PinnedGenerator = Generator . Pin ( ) )
{
// skip the below logic if we are setting the same generator
if ( InGenerator . HasSameObject ( PinnedGenerator . Get ( ) ) )
{
return ;
}
// clean up if we had another generator
UnregisterGeneratorEvents ( ) ;
}
// set the cached generator
Generator = MoveTemp ( InGenerator ) ;
// Notify the generator has changed
if ( OnGeneratorSet . IsBound ( ) )
{
OnGeneratorSet . Execute ( TWeakPtr < FMetasoundGenerator > ( Generator ) ) ;
}
// We're setting a new generator, so do the setup stuff
if ( const TSharedPtr < FMetasoundGenerator > PinnedGenerator = Generator . Pin ( ) )
{
// Subscribe to generator events
RegisterGeneratorEvents ( ) ;
// Update params on the generator
SendParametersToGenerator ( ) ;
// Attach any output watchers we might have
FixUpOutputWatchers ( ) ;
// Enable render timing if appropriate
PinnedGenerator - > EnableRuntimeRenderTiming ( bRuntimeRenderTimingShouldBeEnabled ) ;
}
}
void FMetasoundGeneratorHandle : : RegisterGeneratorEvents ( )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : RegisterGeneratorEvents ) ;
check ( IsInGameThread ( ) ) ;
if ( const TSharedPtr < FMetasoundGenerator > PinnedGenerator = Generator . Pin ( ) )
{
// Output watchers
GeneratorOutputChangedDelegateHandle = PinnedGenerator - > OnOutputChanged . AddSP (
AsShared ( ) ,
& FMetasoundGeneratorHandle : : HandleOutputChanged ) ;
// Graph updated
{
FOnSetGraph : : FDelegate GraphSetDelegate ;
GraphSetDelegate . BindSP ( AsShared ( ) , & FMetasoundGeneratorHandle : : HandleGeneratorGraphSet ) ;
GeneratorGraphSetDelegateHandle = PinnedGenerator - > AddGraphSetCallback ( MoveTemp ( GraphSetDelegate ) ) ;
}
// Vertex interface updated (Live Update support)
2024-04-11 02:17:22 -04:00
GeneratorVertexInterfaceChangedDelegateHandle = PinnedGenerator - > OnVertexInterfaceDataUpdatedWithChanges . AddSP (
2023-09-14 11:16:32 -04:00
AsShared ( ) ,
& FMetasoundGeneratorHandle : : HandleGeneratorVertexInterfaceChanged ) ;
}
}
void FMetasoundGeneratorHandle : : UnregisterGeneratorEvents ( ) const
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : UnregisterGeneratorEvents ) ;
check ( IsInGameThread ( ) ) ;
if ( const TSharedPtr < FMetasoundGenerator > PinnedGenerator = Generator . Pin ( ) )
{
PinnedGenerator - > OnOutputChanged . Remove ( GeneratorOutputChangedDelegateHandle ) ;
PinnedGenerator - > RemoveGraphSetCallback ( GeneratorGraphSetDelegateHandle ) ;
2024-04-11 02:17:22 -04:00
PinnedGenerator - > OnVertexInterfaceDataUpdatedWithChanges . Remove ( GeneratorVertexInterfaceChangedDelegateHandle ) ;
2023-09-14 11:16:32 -04:00
}
}
TWeakObjectPtr < UMetaSoundSource > FMetasoundGeneratorHandle : : GetMetaSoundSource ( ) const
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : GetMetaSoundSource ) ;
check ( IsInGameThread ( ) ) ; // UAudioComponent::GetSound() isn't thread-safe.
if ( ! IsValid ( ) )
{
return nullptr ;
}
return Cast < UMetaSoundSource > ( AudioComponent - > GetSound ( ) ) ;
}
void FMetasoundGeneratorHandle : : SendParametersToGenerator ( ) const
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : SendParametersToGenerator ) ;
if ( ! LatestParameterState . IsValid ( ) )
{
return ;
}
// If we have a generator, enqueue the updated parameter state
if ( const TSharedPtr < FMetasoundGenerator > PinnedGenerator = Generator . Pin ( ) )
{
PinnedGenerator - > QueueParameterPack ( LatestParameterState ) ;
}
}
2023-10-25 00:54:11 -04:00
bool FMetasoundGeneratorHandle : : WatchOutputInternal (
const FName OutputName ,
const FWatchOutputUnifiedDelegate & OnOutputValueChanged ,
const FName AnalyzerName ,
const FName AnalyzerOutputName )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : WatchOutputInternal ) ;
check ( IsInGameThread ( ) ) ;
if ( ! IsValid ( ) )
{
return false ;
}
2024-02-27 19:26:07 -05:00
Frontend : : FAnalyzerAddress AnalyzerAddress ;
if ( ! TryCreateAnalyzerAddress ( OutputName , AnalyzerName , AnalyzerOutputName , AnalyzerAddress ) )
{
return false ;
}
// Create the watcher
CreateOutputWatcher ( AnalyzerAddress , OnOutputValueChanged ) ;
// Update the generator's analyzers if necessary
FixUpOutputWatchers ( ) ;
return true ;
}
bool FMetasoundGeneratorHandle : : UnwatchOutputInternal (
const FName OutputName ,
const FWatchOutputUnifiedDelegate & OnOutputValueChanged ,
const FName AnalyzerName ,
const FName AnalyzerOutputName )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : UnwatchOutputInternal ) ;
check ( IsInGameThread ( ) ) ;
if ( ! IsValid ( ) )
{
return false ;
}
Frontend : : FAnalyzerAddress AnalyzerAddress ;
if ( ! TryCreateAnalyzerAddress ( OutputName , AnalyzerName , AnalyzerOutputName , AnalyzerAddress ) )
{
return false ;
}
// Remove the watcher
RemoveOutputWatcher ( AnalyzerAddress , OnOutputValueChanged ) ;
// Update the generator's analyzers if necessary
FixUpOutputWatchers ( ) ;
return true ;
}
2024-05-09 15:58:51 -04:00
void FMetasoundGeneratorHandle : : UpdateOutputWatchersInternal ( )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : UpdateOutputWatchersInternal ) ;
check ( IsInGameThread ( ) ) ;
// Clear the flag *before* we drain the queue, so we don't leave any output updates behind.
OutputWatcherUpdateScheduled . clear ( ) ;
int32 NumDequeued = 0 ;
while ( TOptional < FOutputPayload > ChangedOutput = ChangedOutputs . Dequeue ( ) )
{
const FOutputWatcherKey WatcherKey
{
ChangedOutput - > OutputName ,
ChangedOutput - > AnalyzerName ,
ChangedOutput - > OutputValue . Name
} ;
if ( const FOutputWatcher * Watcher = OutputWatchers . Find ( WatcherKey ) )
{
Watcher - > OnOutputValueChanged . Broadcast ( ChangedOutput - > OutputName , ChangedOutput - > OutputValue ) ;
}
+ + NumDequeued ;
}
ChangedOutputsQueueCount . store ( FMath : : Max ( 0 , ChangedOutputsQueueCount . load ( ) - NumDequeued ) ) ;
}
2024-02-27 19:26:07 -05:00
bool FMetasoundGeneratorHandle : : TryCreateAnalyzerAddress (
const FName OutputName ,
const FName AnalyzerName ,
const FName AnalyzerOutputName ,
Frontend : : FAnalyzerAddress & OutAnalyzerAddress )
{
2023-10-25 00:54:11 -04:00
// Make the analyzer address.
Frontend : : FAnalyzerAddress AnalyzerAddress ;
AnalyzerAddress . InstanceID = GetAudioComponentId ( ) ;
AnalyzerAddress . OutputName = OutputName ;
AnalyzerAddress . AnalyzerName = AnalyzerName ;
AnalyzerAddress . AnalyzerMemberName = AnalyzerOutputName ;
AnalyzerAddress . AnalyzerInstanceID = FGuid : : NewGuid ( ) ;
// Find the output node and get the data type/node id from that
{
const TWeakObjectPtr < UMetaSoundSource > Source = GetMetaSoundSource ( ) ;
if ( ! Source . IsValid ( ) )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Couldn't find the MetaSound Source " ) ) ;
return false ;
}
// Find the node id and type name
const FMetasoundFrontendClassOutput * OutputPtr =
Source - > GetConstDocument ( ) . RootGraph . Interface . Outputs . FindByPredicate (
[ & AnalyzerAddress ] ( const FMetasoundFrontendClassOutput & Output )
{
return Output . Name = = AnalyzerAddress . OutputName ;
} ) ;
if ( nullptr = = OutputPtr )
{
return false ;
}
AnalyzerAddress . NodeID = OutputPtr - > NodeID ;
AnalyzerAddress . DataType = OutputPtr - > TypeName ;
}
// If no analyzer name was provided, try to find a passthrough analyzer
if ( AnalyzerAddress . AnalyzerName . IsNone ( ) )
{
if ( ! PassthroughAnalyzers . Contains ( AnalyzerAddress . DataType ) )
{
return false ;
}
AnalyzerAddress . AnalyzerName = PassthroughAnalyzers [ AnalyzerAddress . DataType ] . AnalyzerName ;
AnalyzerAddress . AnalyzerMemberName = PassthroughAnalyzers [ AnalyzerAddress . DataType ] . OutputName ;
}
// Check to see if the analyzer exists
{
using namespace Metasound : : Frontend ;
const IVertexAnalyzerFactory * Factory =
IVertexAnalyzerRegistry : : Get ( ) . FindAnalyzerFactory ( AnalyzerAddress . AnalyzerName ) ;
if ( nullptr = = Factory )
{
return false ;
}
}
2024-02-27 19:26:07 -05:00
OutAnalyzerAddress = AnalyzerAddress ;
2023-10-25 00:54:11 -04:00
return true ;
}
2023-09-14 11:16:32 -04:00
void FMetasoundGeneratorHandle : : FixUpOutputWatchers ( )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : FixUpOutputWatchers ) ;
check ( IsInGameThread ( ) ) ;
if ( ! IsValid ( ) )
{
return ;
}
if ( const TSharedPtr < FMetasoundGenerator > PinnedGenerator = Generator . Pin ( ) )
{
// For each watcher, make sure the generator has a corresponding analyzer
// (will fail gracefully on duplicates or non-existent outputs)
2024-02-27 19:26:07 -05:00
// we can also remove any analyzer that has no further bindings
2023-10-03 12:04:46 -04:00
for ( const auto & Watcher : OutputWatchers )
2023-09-14 11:16:32 -04:00
{
2024-02-27 19:26:07 -05:00
if ( Watcher . Value . OnOutputValueChanged . IsBound ( ) )
{
PinnedGenerator - > AddOutputVertexAnalyzer ( Watcher . Value . AnalyzerAddress ) ;
}
else
{
PinnedGenerator - > RemoveOutputVertexAnalyzer ( Watcher . Value . AnalyzerAddress ) ;
}
2023-09-14 11:16:32 -04:00
}
}
}
2024-02-27 19:26:07 -05:00
2023-09-14 11:16:32 -04:00
void FMetasoundGeneratorHandle : : CreateOutputWatcher (
const Frontend : : FAnalyzerAddress & AnalyzerAddress ,
2023-10-25 00:54:11 -04:00
const FWatchOutputUnifiedDelegate & OnOutputValueChanged )
2023-09-14 11:16:32 -04:00
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : CreateOutputWatcher ) ;
check ( IsInGameThread ( ) ) ; // modifying watchers isn't thread-safe
// If we already have a watcher for this output, just add the delegate to that one
2023-10-03 12:04:46 -04:00
const FOutputWatcherKey WatcherKey
{
AnalyzerAddress . OutputName ,
AnalyzerAddress . AnalyzerName ,
AnalyzerAddress . AnalyzerMemberName
} ;
if ( FOutputWatcher * Watcher = OutputWatchers . Find ( WatcherKey ) )
2023-09-14 11:16:32 -04:00
{
2023-10-25 00:54:11 -04:00
Watcher - > OnOutputValueChanged . Add ( OnOutputValueChanged ) ;
2023-09-14 11:16:32 -04:00
}
// Otherwise add a new watcher
else
{
2023-10-03 12:04:46 -04:00
OutputWatchers . Emplace ( WatcherKey , { AnalyzerAddress , OnOutputValueChanged } ) ;
2023-09-14 11:16:32 -04:00
}
}
2024-02-27 19:26:07 -05:00
void FMetasoundGeneratorHandle : : RemoveOutputWatcher (
const Frontend : : FAnalyzerAddress & AnalyzerAddress ,
const FWatchOutputUnifiedDelegate & OnOutputValueChanged )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : RemoveOutputWatcher ) ;
check ( IsInGameThread ( ) ) ; // modifying watchers isn't thread-safe
// Watcher must exist in order to be removed
const FOutputWatcherKey WatcherKey
{
AnalyzerAddress . OutputName ,
AnalyzerAddress . AnalyzerName ,
AnalyzerAddress . AnalyzerMemberName
} ;
if ( FOutputWatcher * Watcher = OutputWatchers . Find ( WatcherKey ) )
{
Watcher - > OnOutputValueChanged . Remove ( OnOutputValueChanged ) ;
}
}
2023-09-14 11:16:32 -04:00
void FMetasoundGeneratorHandle : : HandleGeneratorCreated (
const uint64 InAudioComponentId ,
TSharedPtr < FMetasoundGenerator > InGenerator )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : HandleGeneratorCreated ) ;
check ( InAudioComponentId ! = INDEX_NONE ) ;
if ( InAudioComponentId = = GetAudioComponentId ( ) )
{
// Set the generator on the game thread. We grab a weak pointer in case this gets destroyed while we wait.
2024-05-14 20:54:45 -04:00
ExecuteOnGameThread ( UE_SOURCE_LOCATION , [ WeakThis = AsWeak ( ) , WeakGenerator = InGenerator . ToWeakPtr ( ) ] ( )
2023-09-14 11:16:32 -04:00
{
if ( const TSharedPtr < FMetasoundGeneratorHandle > PinnedThis = WeakThis . Pin ( ) )
{
PinnedThis - > SetGenerator ( TWeakPtr < FMetasoundGenerator > ( WeakGenerator ) ) ;
}
} ) ;
}
}
void FMetasoundGeneratorHandle : : HandleGeneratorDestroyed (
const uint64 InAudioComponentId ,
TSharedPtr < FMetasoundGenerator > )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : HandleGeneratorDestroyed ) ;
check ( InAudioComponentId ! = INDEX_NONE ) ;
if ( InAudioComponentId = = GetAudioComponentId ( ) )
{
// Unset the generator on the game thread. We grab a weak pointer in case this gets destroyed while we wait.
2024-05-14 20:54:45 -04:00
ExecuteOnGameThread ( UE_SOURCE_LOCATION , [ WeakThis = AsWeak ( ) ] ( )
2023-09-14 11:16:32 -04:00
{
if ( const TSharedPtr < FMetasoundGeneratorHandle > PinnedThis = WeakThis . Pin ( ) )
{
PinnedThis - > SetGenerator ( nullptr ) ;
}
} ) ;
}
}
void FMetasoundGeneratorHandle : : HandleGeneratorGraphSet ( )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : HandleGeneratorGraphSet ) ;
// Defer to the game thread. We grab a weak pointer in case this gets destroyed while we wait.
2024-05-14 20:54:45 -04:00
ExecuteOnGameThread ( UE_SOURCE_LOCATION , [ WeakThis = AsWeak ( ) ] ( )
2023-09-14 11:16:32 -04:00
{
if ( const TSharedPtr < FMetasoundGeneratorHandle > PinnedThis = WeakThis . Pin ( ) )
{
PinnedThis - > SendParametersToGenerator ( ) ;
PinnedThis - > FixUpOutputWatchers ( ) ;
if ( PinnedThis - > OnGraphUpdated . IsBound ( ) )
{
PinnedThis - > OnGraphUpdated . Execute ( ) ;
}
}
} ) ;
}
2024-04-11 02:17:22 -04:00
void FMetasoundGeneratorHandle : : HandleGeneratorVertexInterfaceChanged ( const TArray < FVertexInterfaceChange > & VertexInterfaceChanges )
2023-09-14 11:16:32 -04:00
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : HandleGeneratorVertexInterfaceChanged ) ;
// Defer to the game thread. We grab a weak pointer in case this gets destroyed while we wait.
2024-05-14 20:54:45 -04:00
ExecuteOnGameThread ( UE_SOURCE_LOCATION , [ WeakThis = AsWeak ( ) , VertexInterfaceChanges ] ( )
2023-09-14 11:16:32 -04:00
{
if ( const TSharedPtr < FMetasoundGeneratorHandle > PinnedThis = WeakThis . Pin ( ) )
{
PinnedThis - > SendParametersToGenerator ( ) ;
PinnedThis - > FixUpOutputWatchers ( ) ;
2023-10-20 15:29:38 -04:00
2024-04-11 02:17:22 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2023-10-20 15:29:38 -04:00
if ( PinnedThis - > OnGeneratorIOUpdated . IsBound ( ) )
{
PinnedThis - > OnGeneratorIOUpdated . Execute ( ) ;
}
2024-04-11 02:17:22 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
if ( PinnedThis - > OnGeneratorIOUpdatedWithChanges . IsBound ( ) )
{
PinnedThis - > OnGeneratorIOUpdatedWithChanges . Execute ( VertexInterfaceChanges ) ;
}
2023-09-14 11:16:32 -04:00
}
} ) ;
}
void FMetasoundGeneratorHandle : : HandleOutputChanged (
FName AnalyzerName ,
FName OutputName ,
FName AnalyzerOutputName ,
TSharedPtr < IOutputStorage > OutputData )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetasoundGeneratorHandle : : HandleOutputChanged ) ;
2023-09-15 08:01:14 -04:00
if ( ChangedOutputsQueueCount > = ChangedOutputsQueueMax )
{
// Log only once per handle
if ( ChangedOutputsQueueShouldLogIfFull . load ( ) )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " UMetasoundGeneratorHandle output queue is full. " ) ) ;
ChangedOutputsQueueShouldLogIfFull . store ( false ) ;
}
return ;
}
2023-09-14 11:16:32 -04:00
ChangedOutputs . Enqueue ( AnalyzerName , OutputName , AnalyzerOutputName , OutputData ) ;
2023-09-15 08:01:14 -04:00
ChangedOutputsQueueCount . fetch_add ( 1 ) ;
2024-05-09 15:58:51 -04:00
// Drain the queue on the game thread, but don't bother if it's already been scheduled
if ( ! OutputWatcherUpdateScheduled . test_and_set ( ) )
{
// Defer to the game thread. We grab a weak pointer in case this gets destroyed while we wait.
2024-05-14 20:54:45 -04:00
ExecuteOnGameThread ( UE_SOURCE_LOCATION , [ WeakThis = AsWeak ( ) ] ( )
2024-05-09 15:58:51 -04:00
{
if ( const TSharedPtr < FMetasoundGeneratorHandle > PinnedThis = WeakThis . Pin ( ) )
{
PinnedThis - > UpdateOutputWatchersInternal ( ) ;
}
} ) ;
}
2023-09-14 11:16:32 -04:00
}
}
2023-04-05 17:42:36 -04:00
2022-12-15 17:03:02 -05:00
UMetasoundGeneratorHandle * UMetasoundGeneratorHandle : : CreateMetaSoundGeneratorHandle ( UAudioComponent * OnComponent )
{
2023-04-05 17:42:36 -04:00
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetasoundGeneratorHandle : : CreateMetaSoundGeneratorHandle ) ;
2022-12-15 17:03:02 -05:00
if ( ! OnComponent )
{
return nullptr ;
}
2023-09-14 11:16:32 -04:00
UMetasoundGeneratorHandle * Handle = NewObject < UMetasoundGeneratorHandle > ( ) ;
return Handle - > InitGeneratorHandle ( OnComponent ) ? Handle : nullptr ;
2022-12-15 17:03:02 -05:00
}
2023-04-05 17:42:36 -04:00
void UMetasoundGeneratorHandle : : BeginDestroy ( )
{
Super : : BeginDestroy ( ) ;
2023-05-03 13:43:51 -04:00
2023-09-14 11:16:32 -04:00
GeneratorHandle . Reset ( ) ;
2023-04-05 17:42:36 -04:00
}
bool UMetasoundGeneratorHandle : : IsValid ( ) const
{
2023-09-14 11:16:32 -04:00
return GeneratorHandle . IsValid ( ) & & GeneratorHandle - > IsValid ( ) ;
2023-04-05 17:42:36 -04:00
}
uint64 UMetasoundGeneratorHandle : : GetAudioComponentId ( ) const
{
2023-09-14 11:16:32 -04:00
return IsValid ( ) ? GeneratorHandle - > GetAudioComponentId ( ) : INDEX_NONE ;
2022-12-15 17:03:02 -05:00
}
bool UMetasoundGeneratorHandle : : ApplyParameterPack ( UMetasoundParameterPack * Pack )
{
2023-04-05 17:42:36 -04:00
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetasoundGeneratorHandle : : ApplyParameterPack ) ;
2023-09-14 11:16:32 -04:00
if ( nullptr = = Pack )
2022-12-15 17:03:02 -05:00
{
return false ;
}
2023-09-14 11:16:32 -04:00
if ( IsValid ( ) )
2022-12-15 17:03:02 -05:00
{
2023-09-14 11:16:32 -04:00
GeneratorHandle - > UpdateParameters ( * Pack ) ;
return true ;
2022-12-15 17:03:02 -05:00
}
2023-09-14 11:16:32 -04:00
return false ;
2022-12-15 17:03:02 -05:00
}
2023-09-14 11:16:32 -04:00
TSharedPtr < Metasound : : FMetasoundGenerator > UMetasoundGeneratorHandle : : GetGenerator ( ) const
2023-03-20 17:38:24 -04:00
{
2023-09-14 11:16:32 -04:00
return IsValid ( ) ? GeneratorHandle - > GetGenerator ( ) : nullptr ;
2023-03-20 17:38:24 -04:00
}
2023-09-14 11:16:32 -04:00
FDelegateHandle UMetasoundGeneratorHandle : : AddGraphSetCallback ( FOnSetGraph : : FDelegate & & Delegate )
2023-04-03 23:30:36 -04:00
{
2023-09-14 11:16:32 -04:00
return OnGeneratorsGraphChanged . Add ( MoveTemp ( Delegate ) ) ;
2023-04-03 23:30:36 -04:00
}
bool UMetasoundGeneratorHandle : : RemoveGraphSetCallback ( const FDelegateHandle & Handle )
{
return OnGeneratorsGraphChanged . Remove ( Handle ) ;
}
2024-05-29 11:58:19 -04:00
bool UMetasoundGeneratorHandle : : TryCreateAnalyzerAddress ( const FName OutputName , const FName AnalyzerName , const FName AnalyzerOutputName , Metasound : : Frontend : : FAnalyzerAddress & OutAnalyzerAddress )
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetasoundGeneratorHandle : : WatchOutput ) ;
if ( ! IsValid ( ) )
{
return false ;
}
return GeneratorHandle - > TryCreateAnalyzerAddress ( OutputName , AnalyzerName , AnalyzerOutputName , OutAnalyzerAddress ) ;
}
2023-04-05 17:42:36 -04:00
bool UMetasoundGeneratorHandle : : WatchOutput (
2023-09-14 11:16:32 -04:00
const FName OutputName ,
2023-04-05 17:42:36 -04:00
const FOnMetasoundOutputValueChanged & OnOutputValueChanged ,
2023-09-14 11:16:32 -04:00
const FName AnalyzerName ,
const FName AnalyzerOutputName )
2023-10-25 00:54:11 -04:00
{
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetasoundGeneratorHandle : : WatchOutput ) ;
if ( ! IsValid ( ) )
{
return false ;
}
return GeneratorHandle - > WatchOutput ( OutputName , OnOutputValueChanged , AnalyzerName , AnalyzerOutputName ) ;
}
bool UMetasoundGeneratorHandle : : WatchOutput (
const FName OutputName ,
const FOnMetasoundOutputValueChangedNative & OnOutputValueChanged ,
const FName AnalyzerName ,
const FName AnalyzerOutputName )
2023-04-03 23:30:36 -04:00
{
2023-04-05 17:42:36 -04:00
METASOUND_LLM_SCOPE ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetasoundGeneratorHandle : : WatchOutput ) ;
if ( ! IsValid ( ) )
{
return false ;
}
2023-09-14 11:16:32 -04:00
return GeneratorHandle - > WatchOutput ( OutputName , OnOutputValueChanged , AnalyzerName , AnalyzerOutputName ) ;
2023-04-05 17:42:36 -04:00
}
2023-09-14 11:16:32 -04:00
void UMetasoundGeneratorHandle : : RegisterPassthroughAnalyzerForType (
const FName TypeName ,
const FName AnalyzerName ,
const FName OutputName )
2023-08-24 08:28:12 -04:00
{
2023-09-14 11:16:32 -04:00
Metasound : : FMetasoundGeneratorHandle : : RegisterPassthroughAnalyzerForType ( TypeName , AnalyzerName , OutputName ) ;
2023-08-24 08:28:12 -04:00
}
2023-09-14 11:16:32 -04:00
void UMetasoundGeneratorHandle : : UpdateWatchers ( ) const
2023-04-05 17:42:36 -04:00
{
2024-05-09 15:58:51 -04:00
// Do nothing. No longer necessary.
2023-04-03 23:30:36 -04:00
}
2023-09-14 11:16:32 -04:00
void UMetasoundGeneratorHandle : : EnableRuntimeRenderTiming ( const bool Enable ) const
2022-12-15 17:03:02 -05:00
{
2023-09-14 11:16:32 -04:00
if ( IsValid ( ) )
2023-04-05 17:42:36 -04:00
{
2023-09-14 11:16:32 -04:00
GeneratorHandle - > EnableRuntimeRenderTiming ( Enable ) ;
2023-04-05 17:42:36 -04:00
}
2023-09-14 11:16:32 -04:00
}
double UMetasoundGeneratorHandle : : GetCPUCoreUtilization ( ) const
{
if ( IsValid ( ) )
2022-12-15 17:03:02 -05:00
{
2023-09-14 11:16:32 -04:00
return GeneratorHandle - > GetCPUCoreUtilization ( ) ;
}
return 0 ;
}
bool UMetasoundGeneratorHandle : : InitGeneratorHandle ( TWeakObjectPtr < UAudioComponent > & & AudioComponent )
{
GeneratorHandle = Metasound : : FMetasoundGeneratorHandle : : Create ( MoveTemp ( AudioComponent ) ) ;
if ( ! GeneratorHandle . IsValid ( ) )
{
return false ;
}
// Attach delegates
// NB: FMetasoundGeneratorHandle already executes these on the game thread,
// and its lifetime is tied to UMetasoundGeneratorHandle's lifetime,
// so we can guarantee the this pointer is valid when these get called.
GeneratorHandle - > OnGeneratorSet . BindLambda ( [ this ] ( TWeakPtr < Metasound : : FMetasoundGenerator > & & Generator )
{
if ( Generator . IsValid ( ) )
2022-12-15 17:03:02 -05:00
{
2023-03-20 17:38:24 -04:00
OnGeneratorHandleAttached . Broadcast ( ) ;
2022-12-15 17:03:02 -05:00
}
2023-09-14 11:16:32 -04:00
else
2023-03-20 17:38:24 -04:00
{
OnGeneratorHandleDetached . Broadcast ( ) ;
}
2023-09-14 11:16:32 -04:00
} ) ;
2023-05-16 15:30:22 -04:00
2023-09-14 11:16:32 -04:00
GeneratorHandle - > OnGraphUpdated . BindLambda ( [ this ] ( )
{
OnGeneratorsGraphChanged . Broadcast ( ) ;
} ) ;
2024-04-11 02:17:22 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2023-10-20 15:29:38 -04:00
GeneratorHandle - > OnGeneratorIOUpdated . BindLambda ( [ this ] ( )
{
OnIOUpdated . Broadcast ( ) ;
} ) ;
2024-04-11 02:17:22 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
GeneratorHandle - > OnGeneratorIOUpdatedWithChanges . BindLambda ( [ this ] ( const TArray < Metasound : : FVertexInterfaceChange > & VertexInterfaceChanges )
{
OnIOUpdatedWithChanges . Broadcast ( VertexInterfaceChanges ) ;
} ) ;
2023-10-20 15:29:38 -04:00
2023-09-14 11:16:32 -04:00
return true ;
2023-05-03 13:43:51 -04:00
}