2023-10-13 17:49:56 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
#include "MetasoundOperatorCacheSubsystem.h"
|
|
|
|
|
|
|
|
|
|
#include "AudioMixerDevice.h"
|
|
|
|
|
#include "MetasoundGenerator.h"
|
|
|
|
|
#include "MetasoundGeneratorModule.h"
|
|
|
|
|
#include "MetasoundOperatorCache.h"
|
|
|
|
|
#include "Modules/ModuleManager.h"
|
|
|
|
|
#include "Misc/Optional.h"
|
|
|
|
|
|
|
|
|
|
static TOptional<Metasound::FMetasoundGeneratorInitParams> CreateInitParams(UMetaSoundSource* InMetaSound, const FSoundGeneratorInitParams& InParams)
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
using namespace Metasound::Engine;
|
|
|
|
|
using namespace Metasound::SourcePrivate;
|
|
|
|
|
|
2023-10-31 18:35:37 -04:00
|
|
|
// InMetaSound was null
|
2023-10-13 17:49:56 -04:00
|
|
|
if (!ensure(InMetaSound))
|
|
|
|
|
{
|
2023-10-31 18:35:37 -04:00
|
|
|
return {};
|
2023-10-13 17:49:56 -04:00
|
|
|
}
|
2023-10-31 18:35:37 -04:00
|
|
|
// we cannot precache dynamic metasounds
|
|
|
|
|
if (!ensure(!InMetaSound->IsDynamic()))
|
2023-10-13 17:49:56 -04:00
|
|
|
{
|
2023-10-31 18:35:37 -04:00
|
|
|
return {};
|
2023-10-13 17:49:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FOperatorSettings InSettings = InMetaSound->GetOperatorSettings(static_cast<FSampleRate>(InParams.SampleRate));
|
|
|
|
|
FMetasoundEnvironment Environment = InMetaSound->CreateEnvironment(InParams);
|
|
|
|
|
|
|
|
|
|
FOperatorBuilderSettings BuilderSettings = FOperatorBuilderSettings::GetDefaultSettings();
|
|
|
|
|
// Graph analyzer currently only enabled for preview sounds (but can theoretically be supported for all sounds)
|
|
|
|
|
BuilderSettings.bPopulateInternalDataReferences = InParams.bIsPreviewSound;
|
|
|
|
|
|
|
|
|
|
return FMetasoundGeneratorInitParams
|
|
|
|
|
{
|
|
|
|
|
InSettings,
|
|
|
|
|
MoveTemp(BuilderSettings),
|
|
|
|
|
{}, // Graph, retrieved from the FrontEnd Registry in FOperatorPool::BuildAndAddOperator()
|
|
|
|
|
Environment,
|
|
|
|
|
InMetaSound->GetName(),
|
|
|
|
|
InMetaSound->GetOutputAudioChannelOrder(),
|
|
|
|
|
{}, // DefaultParameters
|
|
|
|
|
true, // bBuildSynchronous
|
|
|
|
|
{} // DataChannel
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UMetaSoundCacheSubsystem::ShouldCreateSubsystem(UObject* Outer) const
|
|
|
|
|
{
|
|
|
|
|
return !IsRunningDedicatedServer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UMetaSoundCacheSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
|
|
|
|
{
|
|
|
|
|
using namespace Audio;
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
|
|
|
|
|
const FMixerDevice* MixerDevice = GetMixerDevice();
|
|
|
|
|
|
2023-10-13 19:20:20 -04:00
|
|
|
if (ensure(MixerDevice))
|
2023-10-13 17:49:56 -04:00
|
|
|
{
|
2023-10-13 19:20:20 -04:00
|
|
|
BuildParams.AudioDeviceID = GetAudioDeviceHandle().GetDeviceID();
|
|
|
|
|
BuildParams.SampleRate = MixerDevice->GetSampleRate();
|
|
|
|
|
BuildParams.AudioMixerNumOutputFrames = MixerDevice->GetNumOutputFrames();
|
|
|
|
|
BuildParams.NumChannels = MixerDevice->GetNumDeviceChannels();
|
|
|
|
|
BuildParams.NumFramesPerCallback = 0;
|
|
|
|
|
BuildParams.InstanceID = 0;
|
2023-10-13 17:49:56 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UMetaSoundCacheSubsystem::Update()
|
|
|
|
|
{
|
|
|
|
|
#if METASOUND_OPERATORCACHEPROFILER_ENABLED
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
if (TSharedPtr<FOperatorPool> OperatorPool = FModuleManager::GetModuleChecked<IMetasoundGeneratorModule>("MetasoundGenerator").GetOperatorPool())
|
|
|
|
|
{
|
|
|
|
|
OperatorPool->UpdateHitRateTracker();
|
|
|
|
|
}
|
|
|
|
|
#endif // #if METASOUND_OPERATORCACHEPROFILER_ENABLED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UMetaSoundCacheSubsystem::PrecacheMetaSound(UMetaSoundSource* InMetaSound, int32 InNumInstances)
|
|
|
|
|
{
|
|
|
|
|
using namespace Audio;
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FOperatorPool> OperatorPool;
|
|
|
|
|
IMetasoundGeneratorModule* Module = FModuleManager::GetModulePtr<IMetasoundGeneratorModule>("MetasoundGenerator");
|
2023-10-31 18:35:37 -04:00
|
|
|
if (!ensure(Module))
|
2023-10-13 17:49:56 -04:00
|
|
|
{
|
2023-10-31 18:35:37 -04:00
|
|
|
return;
|
2023-10-13 17:49:56 -04:00
|
|
|
}
|
|
|
|
|
|
2023-10-31 18:35:37 -04:00
|
|
|
OperatorPool = Module->GetOperatorPool();
|
2023-10-13 17:49:56 -04:00
|
|
|
const FMixerDevice* MixerDevice = GetMixerDevice();
|
|
|
|
|
|
2024-02-08 18:23:13 -05:00
|
|
|
if (!ensure(MixerDevice && OperatorPool))
|
2023-10-13 17:49:56 -04:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-08 18:23:13 -05:00
|
|
|
if (!InMetaSound)
|
2023-10-13 17:49:56 -04:00
|
|
|
{
|
2024-02-08 18:23:13 -05:00
|
|
|
UE_LOG(LogMetaSound, Error, TEXT("PrecacheMetaSound called without being provided a MetaSound, ignoring request"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (InNumInstances < 1)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogMetaSound, Error, TEXT("PrecacheMetaSound called with invaled NumInstances %i, ignoring request"), InNumInstances);
|
2023-10-13 17:49:56 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InMetaSound->InitResources();
|
2023-10-13 19:20:20 -04:00
|
|
|
BuildParams.GraphName = InMetaSound->GetOwningAssetName();
|
2023-10-13 17:49:56 -04:00
|
|
|
|
|
|
|
|
if (InMetaSound->IsDynamic())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-13 19:20:20 -04:00
|
|
|
TOptional<FMetasoundGeneratorInitParams> InitParams = CreateInitParams(InMetaSound, BuildParams);
|
2023-10-13 17:49:56 -04:00
|
|
|
if (!InitParams.IsSet())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TUniquePtr<FOperatorBuildData> Data = MakeUnique<FOperatorBuildData>(
|
|
|
|
|
MoveTemp(InitParams.GetValue())
|
2023-12-15 13:21:12 -05:00
|
|
|
, InMetaSound->GetGraphRegistryKey()
|
2023-10-31 18:35:37 -04:00
|
|
|
, InMetaSound->AssetClassID
|
2023-10-13 17:49:56 -04:00
|
|
|
, InNumInstances
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
OperatorPool->BuildAndAddOperator(MoveTemp(Data));
|
2023-10-31 18:35:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UMetaSoundCacheSubsystem::TouchOrPrecacheMetaSound(UMetaSoundSource* InMetaSound, int32 InNumInstances)
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FOperatorPool> OperatorPool;
|
|
|
|
|
IMetasoundGeneratorModule* Module = FModuleManager::GetModulePtr<IMetasoundGeneratorModule>("MetasoundGenerator");
|
|
|
|
|
if (!ensure(Module))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OperatorPool = Module->GetOperatorPool();
|
|
|
|
|
if (!ensure(OperatorPool))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get the number of instances already in the cache
|
|
|
|
|
const int32 NumInCache = OperatorPool->GetNumCachedOperatorsWithAssetClassID(InMetaSound->AssetClassID);
|
|
|
|
|
|
|
|
|
|
// move pre-existing to the top of the cache
|
|
|
|
|
OperatorPool->TouchOperatorsViaAssetClassID(InMetaSound->AssetClassID, FMath::Min(NumInCache, InNumInstances));
|
|
|
|
|
|
|
|
|
|
// build the difference (InNumInstances - existing)
|
|
|
|
|
const int32 NumToBuild = InNumInstances - NumInCache;
|
|
|
|
|
if (NumToBuild > 0)
|
|
|
|
|
{
|
|
|
|
|
PrecacheMetaSound(InMetaSound, NumToBuild);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UMetaSoundCacheSubsystem::RemoveCachedOperatorsForMetaSound(UMetaSoundSource* InMetaSound)
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
|
2024-03-06 16:03:57 -05:00
|
|
|
if (!InMetaSound)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogMetaSound, Warning, TEXT("Remove Cached Operators called without being provided a MetaSound, ignoring request"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-31 18:35:37 -04:00
|
|
|
IMetasoundGeneratorModule* Module = FModuleManager::GetModulePtr<IMetasoundGeneratorModule>("MetasoundGenerator");
|
|
|
|
|
if (!ensure(Module))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TSharedPtr<FOperatorPool> OperatorPool = Module->GetOperatorPool())
|
|
|
|
|
{
|
|
|
|
|
OperatorPool->RemoveOperatorsWithAssetClassID(InMetaSound->AssetClassID);
|
|
|
|
|
}
|
2023-10-13 17:49:56 -04:00
|
|
|
}
|