2020-07-17 16:43:42 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "MetasoundAssetBase.h"
|
|
|
|
|
|
2020-12-14 15:48:27 -04:00
|
|
|
#include "Algo/AnyOf.h"
|
2022-08-18 13:55:13 -04:00
|
|
|
#include "Algo/Copy.h"
|
2022-03-01 16:31:55 -05:00
|
|
|
#include "Algo/ForEach.h"
|
2021-06-16 11:21:13 -04:00
|
|
|
#include "Algo/Transform.h"
|
2021-09-16 14:46:43 -04:00
|
|
|
#include "Containers/Set.h"
|
2020-07-21 14:34:07 -04:00
|
|
|
#include "HAL/FileManager.h"
|
2022-11-03 14:18:47 -04:00
|
|
|
#include "HAL/IConsoleManager.h"
|
2021-11-22 15:55:50 -05:00
|
|
|
#include "IAudioParameterTransmitter.h"
|
2022-08-19 12:14:31 -04:00
|
|
|
#include "Interfaces/MetasoundFrontendInterface.h"
|
2023-03-13 17:23:05 -04:00
|
|
|
#include "Interfaces/MetasoundFrontendInterfaceRegistry.h"
|
2021-06-08 10:52:31 -04:00
|
|
|
#include "Internationalization/Text.h"
|
2020-07-17 16:43:42 -04:00
|
|
|
#include "IStructSerializerBackend.h"
|
2021-07-27 15:36:03 -04:00
|
|
|
#include "Logging/LogMacros.h"
|
2021-11-07 23:43:01 -05:00
|
|
|
#include "MetasoundAssetManager.h"
|
2021-01-13 10:48:59 -04:00
|
|
|
#include "MetasoundFrontendController.h"
|
2021-07-12 16:13:03 -04:00
|
|
|
#include "MetasoundFrontendDocument.h"
|
2023-03-07 17:01:52 -05:00
|
|
|
#include "MetasoundFrontendDocumentBuilder.h"
|
2023-06-20 13:12:39 -04:00
|
|
|
#include "MetasoundFrontendDocumentIdGenerator.h"
|
2022-08-19 12:14:31 -04:00
|
|
|
#include "MetasoundFrontendDocumentVersioning.h"
|
2021-06-08 10:52:31 -04:00
|
|
|
#include "MetasoundFrontendGraph.h"
|
2022-08-10 14:18:10 -04:00
|
|
|
#include "MetasoundFrontendNodeTemplateRegistry.h"
|
2021-08-18 15:16:57 -04:00
|
|
|
#include "MetasoundFrontendRegistries.h"
|
2021-06-08 10:52:31 -04:00
|
|
|
#include "MetasoundFrontendSearchEngine.h"
|
2021-01-13 10:48:59 -04:00
|
|
|
#include "MetasoundFrontendTransform.h"
|
2020-12-14 15:48:27 -04:00
|
|
|
#include "MetasoundJsonBackend.h"
|
2021-01-13 10:48:59 -04:00
|
|
|
#include "MetasoundLog.h"
|
2023-03-07 17:01:52 -05:00
|
|
|
#include "MetasoundParameterPack.h"
|
2021-08-30 14:08:45 -04:00
|
|
|
#include "MetasoundParameterTransmitter.h"
|
2021-08-11 15:22:01 -04:00
|
|
|
#include "MetasoundTrace.h"
|
2021-09-13 14:14:37 -04:00
|
|
|
#include "MetasoundVertex.h"
|
2022-08-16 16:19:43 -04:00
|
|
|
#include "NodeTemplates/MetasoundFrontendDocumentTemplatePreprocessor.h"
|
2020-07-17 16:43:42 -04:00
|
|
|
#include "StructSerializer.h"
|
2022-08-10 14:18:10 -04:00
|
|
|
#include "Templates/SharedPointer.h"
|
2021-06-16 11:21:13 -04:00
|
|
|
#include "UObject/MetaData.h"
|
2020-07-17 16:43:42 -04:00
|
|
|
|
2021-06-08 10:52:31 -04:00
|
|
|
#define LOCTEXT_NAMESPACE "MetaSound"
|
|
|
|
|
|
2021-06-16 11:21:13 -04:00
|
|
|
namespace Metasound
|
|
|
|
|
{
|
2022-05-10 16:51:39 -04:00
|
|
|
namespace Frontend
|
2021-07-27 15:36:03 -04:00
|
|
|
{
|
2022-05-10 16:51:39 -04:00
|
|
|
namespace AssetBasePrivate
|
2021-07-27 15:36:03 -04:00
|
|
|
{
|
2022-05-10 16:51:39 -04:00
|
|
|
static float BlockRate = 100.f;
|
2021-07-27 15:36:03 -04:00
|
|
|
|
2022-05-10 16:51:39 -04:00
|
|
|
void DepthFirstTraversal(const FMetasoundAssetBase& InInitAsset, TFunctionRef<TSet<const FMetasoundAssetBase*>(const FMetasoundAssetBase&)> InVisitFunction)
|
2021-07-27 15:36:03 -04:00
|
|
|
{
|
2022-05-10 16:51:39 -04:00
|
|
|
// Non recursive depth first traversal.
|
|
|
|
|
TArray<const FMetasoundAssetBase*> Stack({ &InInitAsset });
|
|
|
|
|
TSet<const FMetasoundAssetBase*> Visited;
|
2021-07-27 15:36:03 -04:00
|
|
|
|
2022-05-10 16:51:39 -04:00
|
|
|
while (!Stack.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
const FMetasoundAssetBase* CurrentNode = Stack.Pop();
|
|
|
|
|
if (!Visited.Contains(CurrentNode))
|
|
|
|
|
{
|
|
|
|
|
TArray<const FMetasoundAssetBase*> Children = InVisitFunction(*CurrentNode).Array();
|
|
|
|
|
Stack.Append(Children);
|
|
|
|
|
|
|
|
|
|
Visited.Add(CurrentNode);
|
|
|
|
|
}
|
2021-07-27 15:36:03 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-10-10 15:44:28 -04:00
|
|
|
|
|
|
|
|
// Remove all inputs from the provided array of public inputs which are of non-transmittable data types.
|
|
|
|
|
TArray<FMetasoundFrontendClassInput> GetTransmittableInputsFromPublicInputs(const TArray<FMetasoundFrontendClassInput>& InPublicInputs)
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
|
|
|
|
TArray<FMetasoundFrontendClassInput> TransmittableInputs;
|
|
|
|
|
|
|
|
|
|
IDataTypeRegistry& Registry = IDataTypeRegistry::Get();
|
|
|
|
|
Algo::TransformIf(InPublicInputs, TransmittableInputs,
|
|
|
|
|
[&Registry](const FMetasoundFrontendClassInput& Input)
|
|
|
|
|
{
|
|
|
|
|
if (Input.AccessType != EMetasoundFrontendVertexAccessType::Reference)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FDataTypeRegistryInfo Info;
|
|
|
|
|
if (!Registry.GetDataTypeInfo(Input.TypeName, Info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Info.bIsTransmittable)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}, [](const FMetasoundFrontendClassInput& Input) { return Input; }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return TransmittableInputs;
|
|
|
|
|
}
|
2022-10-13 17:38:11 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// Registers node by copying document. Updates to document require re-registration.
|
|
|
|
|
class FNodeRegistryEntry : public INodeRegistryEntry
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FNodeRegistryEntry(const FString& InName, TSharedPtr<FMetasoundFrontendDocument> InPreprocessedDoc, const FSoftObjectPath& InAssetPath)
|
|
|
|
|
: Name(InName)
|
|
|
|
|
, PreprocessedDoc(InPreprocessedDoc)
|
|
|
|
|
{
|
|
|
|
|
// Copy FrontendClass to preserve original document.
|
|
|
|
|
FrontendClass = PreprocessedDoc->RootGraph;
|
|
|
|
|
FrontendClass.Metadata.SetType(EMetasoundFrontendClassType::External);
|
|
|
|
|
|
|
|
|
|
ClassInfo = FNodeClassInfo(PreprocessedDoc->RootGraph, InAssetPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ~FNodeRegistryEntry() = default;
|
|
|
|
|
|
|
|
|
|
virtual const FNodeClassInfo& GetClassInfo() const override
|
|
|
|
|
{
|
|
|
|
|
return ClassInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual TUniquePtr<INode> CreateNode(const FNodeInitData&) const override
|
|
|
|
|
{
|
|
|
|
|
static const TSet<FName> ReferencedGraphTransmissibleInputNames; // Empty as referenced graphs do not support transmission
|
|
|
|
|
return FFrontendGraphBuilder().CreateGraph(*PreprocessedDoc, ReferencedGraphTransmissibleInputNames, Name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual TUniquePtr<INode> CreateNode(FDefaultLiteralNodeConstructorParams&&) const override { return nullptr; }
|
|
|
|
|
virtual TUniquePtr<INode> CreateNode(FDefaultNamedVertexNodeConstructorParams&&) const override { return nullptr; }
|
|
|
|
|
virtual TUniquePtr<INode> CreateNode(FDefaultNamedVertexWithLiteralNodeConstructorParams&&) const override { return nullptr; }
|
|
|
|
|
|
|
|
|
|
virtual const FMetasoundFrontendClass& GetFrontendClass() const override
|
|
|
|
|
{
|
|
|
|
|
return FrontendClass;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual TUniquePtr<INodeRegistryEntry> Clone() const override
|
|
|
|
|
{
|
|
|
|
|
return MakeUnique<FNodeRegistryEntry>(Name, PreprocessedDoc, ClassInfo.AssetPath);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 14:51:42 -04:00
|
|
|
virtual TSet<FMetasoundFrontendVersion>* GetImplementedInterfaces() const override
|
|
|
|
|
{
|
|
|
|
|
return &PreprocessedDoc->Interfaces;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-13 17:38:11 -04:00
|
|
|
virtual bool IsNative() const override
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
FString Name;
|
|
|
|
|
TSharedPtr<FMetasoundFrontendDocument> PreprocessedDoc;
|
|
|
|
|
FMetasoundFrontendClass FrontendClass;
|
|
|
|
|
FNodeClassInfo ClassInfo;
|
|
|
|
|
};
|
2022-05-10 16:51:39 -04:00
|
|
|
} // namespace AssetBasePrivate
|
|
|
|
|
|
|
|
|
|
FAutoConsoleVariableRef CVarMetaSoundBlockRate(
|
|
|
|
|
TEXT("au.MetaSound.BlockRate"),
|
|
|
|
|
AssetBasePrivate::BlockRate,
|
|
|
|
|
TEXT("Sets block rate (blocks per second) of MetaSounds.\n")
|
|
|
|
|
TEXT("Default: 100.0f, Min: 1.0f, Max: 1000.0f"),
|
|
|
|
|
ECVF_Default);
|
|
|
|
|
|
|
|
|
|
float GetDefaultBlockRate()
|
|
|
|
|
{
|
|
|
|
|
return FMath::Clamp(AssetBasePrivate::BlockRate, 1.0f, 1000.0f);
|
2021-07-27 15:36:03 -04:00
|
|
|
}
|
2022-05-10 16:51:39 -04:00
|
|
|
} // namespace Frontend
|
2021-06-16 11:21:13 -04:00
|
|
|
} // namespace Metasound
|
|
|
|
|
|
2020-07-23 16:39:56 -04:00
|
|
|
const FString FMetasoundAssetBase::FileExtension(TEXT(".metasound"));
|
|
|
|
|
|
2021-11-07 23:43:01 -05:00
|
|
|
void FMetasoundAssetBase::RegisterGraphWithFrontend(Metasound::Frontend::FMetaSoundAssetRegistrationOptions InRegistrationOptions)
|
2020-07-23 16:39:56 -04:00
|
|
|
{
|
2021-06-08 10:52:31 -04:00
|
|
|
using namespace Metasound;
|
|
|
|
|
using namespace Metasound::Frontend;
|
2020-07-23 16:39:56 -04:00
|
|
|
|
2021-08-11 15:22:01 -04:00
|
|
|
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE(MetaSoundAssetBase::RegisterGraphWithFrontend);
|
2021-08-18 15:16:57 -04:00
|
|
|
if (!InRegistrationOptions.bForceReregister)
|
2021-06-08 10:52:31 -04:00
|
|
|
{
|
2021-08-18 15:16:57 -04:00
|
|
|
if (IsRegistered())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-07 23:43:01 -05:00
|
|
|
|
2022-10-13 17:38:11 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
if (InRegistrationOptions.bRebuildReferencedAssetClasses)
|
2021-08-18 15:16:57 -04:00
|
|
|
{
|
2022-10-13 17:38:11 -04:00
|
|
|
RebuildReferencedAssetClasses();
|
2021-08-18 15:16:57 -04:00
|
|
|
}
|
2022-10-13 17:38:11 -04:00
|
|
|
#endif
|
2021-08-18 15:16:57 -04:00
|
|
|
|
|
|
|
|
if (InRegistrationOptions.bRegisterDependencies)
|
|
|
|
|
{
|
2022-10-13 17:38:11 -04:00
|
|
|
RegisterAssetDependencies(InRegistrationOptions);
|
2021-08-18 15:16:57 -04:00
|
|
|
}
|
2022-10-13 17:38:11 -04:00
|
|
|
IMetaSoundAssetManager::GetChecked().AddOrUpdateAsset(*GetOwningAsset());
|
2021-08-18 15:16:57 -04:00
|
|
|
|
|
|
|
|
// Auto update must be done after all referenced asset classes are registered
|
|
|
|
|
if (InRegistrationOptions.bAutoUpdate)
|
|
|
|
|
{
|
2022-10-13 17:38:11 -04:00
|
|
|
const bool bDidUpdate = AutoUpdate(InRegistrationOptions.bAutoUpdateLogWarningOnDroppedConnection);
|
2022-02-10 18:36:26 -05:00
|
|
|
#if WITH_EDITOR
|
2022-10-13 17:38:11 -04:00
|
|
|
if (bDidUpdate || InRegistrationOptions.bForceViewSynchronization)
|
2022-02-02 02:19:16 -05:00
|
|
|
{
|
2022-09-22 15:02:24 -04:00
|
|
|
GetModifyContext().SetForceRefreshViews();
|
2022-02-02 02:19:16 -05:00
|
|
|
}
|
2022-02-10 18:36:26 -05:00
|
|
|
#endif // WITH_EDITOR
|
2022-02-02 02:19:16 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-02-10 18:36:26 -05:00
|
|
|
#if WITH_EDITOR
|
2022-02-02 02:19:16 -05:00
|
|
|
if (InRegistrationOptions.bForceViewSynchronization)
|
2022-01-18 18:06:06 -05:00
|
|
|
{
|
2022-09-22 15:02:24 -04:00
|
|
|
GetModifyContext().SetForceRefreshViews();
|
2021-11-18 14:37:34 -05:00
|
|
|
}
|
2022-02-10 18:36:26 -05:00
|
|
|
#endif // WITH_EDITOR
|
2021-06-08 10:52:31 -04:00
|
|
|
}
|
|
|
|
|
|
2022-02-10 18:36:26 -05:00
|
|
|
#if WITH_EDITOR
|
2022-01-20 19:19:55 -05:00
|
|
|
// Must be completed after auto-update to ensure all non-transient referenced dependency data is up-to-date (ex.
|
|
|
|
|
// class version), which is required for most accurately caching current registry metadata.
|
2022-01-26 18:11:52 -05:00
|
|
|
CacheRegistryMetadata();
|
2022-02-10 18:36:26 -05:00
|
|
|
#endif // WITH_EDITOR
|
2022-01-20 19:19:55 -05:00
|
|
|
|
2021-08-18 15:16:57 -04:00
|
|
|
FString AssetName;
|
|
|
|
|
const UObject* OwningAsset = GetOwningAsset();
|
|
|
|
|
if (ensure(OwningAsset))
|
|
|
|
|
{
|
|
|
|
|
AssetName = OwningAsset->GetName();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-13 17:38:11 -04:00
|
|
|
TSharedPtr<FMetasoundFrontendDocument> PreprocessedDocument = PreprocessDocument();
|
2022-10-10 15:44:28 -04:00
|
|
|
CacheRuntimeData(*PreprocessedDocument);
|
2022-10-13 17:38:11 -04:00
|
|
|
FNodeClassInfo AssetClassInfo = GetAssetClassInfo();
|
2022-08-10 14:18:10 -04:00
|
|
|
|
2022-10-13 17:38:11 -04:00
|
|
|
TUniquePtr<INodeRegistryEntry> RegistryEntry = MakeUnique<AssetBasePrivate::FNodeRegistryEntry>(AssetName, PreprocessedDocument, AssetClassInfo.AssetPath);
|
|
|
|
|
|
|
|
|
|
UnregisterGraphWithFrontend();
|
2022-08-10 14:18:10 -04:00
|
|
|
RegistryKey = FMetasoundFrontendRegistryContainer::Get()->RegisterNode(MoveTemp(RegistryEntry));
|
2021-06-16 11:21:13 -04:00
|
|
|
|
2022-04-25 16:59:41 -04:00
|
|
|
if (NodeRegistryKey::IsValid(RegistryKey) && FMetasoundFrontendRegistryContainer::Get()->IsNodeRegistered(RegistryKey))
|
2021-06-16 11:21:13 -04:00
|
|
|
{
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
2022-10-13 17:38:11 -04:00
|
|
|
UpdateAssetRegistry();
|
2021-06-16 11:21:13 -04:00
|
|
|
#endif // WITH_EDITORONLY_DATA
|
|
|
|
|
}
|
|
|
|
|
else
|
2021-06-08 10:52:31 -04:00
|
|
|
{
|
2021-08-18 15:16:57 -04:00
|
|
|
FString ClassName;
|
|
|
|
|
if (OwningAsset)
|
|
|
|
|
{
|
|
|
|
|
if (UClass* Class = OwningAsset->GetClass())
|
|
|
|
|
{
|
|
|
|
|
ClassName = Class->GetName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
UE_LOG(LogMetaSound, Error, TEXT("Registration failed for MetaSound node class '%s' of UObject class '%s'"), *AssetName, *ClassName);
|
2021-06-08 10:52:31 -04:00
|
|
|
}
|
2020-07-23 16:39:56 -04:00
|
|
|
}
|
|
|
|
|
|
2021-07-27 15:36:03 -04:00
|
|
|
void FMetasoundAssetBase::UnregisterGraphWithFrontend()
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
2021-08-11 15:22:01 -04:00
|
|
|
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE(MetaSoundAssetBase::UnregisterGraphWithFrontend);
|
2021-07-27 15:36:03 -04:00
|
|
|
|
|
|
|
|
if (!NodeRegistryKey::IsValid(RegistryKey))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const UObject* OwningAsset = GetOwningAsset();
|
|
|
|
|
if (!ensureAlways(OwningAsset))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ensureAlways(FMetasoundFrontendRegistryContainer::Get()->UnregisterNode(RegistryKey));
|
|
|
|
|
RegistryKey = FNodeRegistryKey();
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-13 10:48:59 -04:00
|
|
|
void FMetasoundAssetBase::SetMetadata(FMetasoundFrontendClassMetadata& InMetadata)
|
2020-07-17 16:43:42 -04:00
|
|
|
{
|
2021-01-13 10:48:59 -04:00
|
|
|
FMetasoundFrontendDocument& Doc = GetDocumentChecked();
|
|
|
|
|
Doc.RootGraph.Metadata = InMetadata;
|
|
|
|
|
|
2021-07-27 15:36:03 -04:00
|
|
|
if (Doc.RootGraph.Metadata.GetType() != EMetasoundFrontendClassType::Graph)
|
2021-01-13 10:48:59 -04:00
|
|
|
{
|
2021-04-02 03:03:27 -04:00
|
|
|
UE_LOG(LogMetaSound, Display, TEXT("Forcing class type to EMetasoundFrontendClassType::Graph on root graph metadata"));
|
2021-07-27 15:36:03 -04:00
|
|
|
Doc.RootGraph.Metadata.SetType(EMetasoundFrontendClassType::Graph);
|
2021-01-13 10:48:59 -04:00
|
|
|
}
|
2020-07-17 16:43:42 -04:00
|
|
|
}
|
|
|
|
|
|
2021-11-22 15:55:50 -05:00
|
|
|
bool FMetasoundAssetBase::GetDeclaredInterfaces(TArray<const Metasound::Frontend::IInterfaceRegistryEntry*>& OutInterfaces) const
|
2021-07-28 17:12:57 -04:00
|
|
|
{
|
2023-03-07 17:01:52 -05:00
|
|
|
return FMetaSoundFrontendDocumentBuilder::FindDeclaredInterfaces(GetDocumentChecked(), OutInterfaces);
|
2021-11-22 15:55:50 -05:00
|
|
|
}
|
|
|
|
|
|
2021-12-10 20:37:31 -05:00
|
|
|
bool FMetasoundAssetBase::IsInterfaceDeclared(const FMetasoundFrontendVersion& InVersion) const
|
2021-11-22 15:55:50 -05:00
|
|
|
{
|
2021-12-10 20:37:31 -05:00
|
|
|
return GetDocumentChecked().Interfaces.Contains(InVersion);
|
2021-07-28 17:12:57 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-08 10:52:31 -04:00
|
|
|
void FMetasoundAssetBase::SetDocument(const FMetasoundFrontendDocument& InDocument)
|
2020-12-14 15:48:27 -04:00
|
|
|
{
|
2021-01-13 10:48:59 -04:00
|
|
|
FMetasoundFrontendDocument& Document = GetDocumentChecked();
|
2020-07-23 20:32:26 -04:00
|
|
|
Document = InDocument;
|
2021-06-23 20:08:21 -04:00
|
|
|
MarkMetasoundDocumentDirty();
|
2020-07-23 20:32:26 -04:00
|
|
|
}
|
|
|
|
|
|
2021-11-22 15:55:50 -05:00
|
|
|
void FMetasoundAssetBase::AddDefaultInterfaces()
|
2020-07-23 20:32:26 -04:00
|
|
|
{
|
2021-11-22 15:55:50 -05:00
|
|
|
using namespace Metasound::Frontend;
|
2021-02-01 15:59:27 -04:00
|
|
|
|
2021-11-22 15:55:50 -05:00
|
|
|
UObject* OwningAsset = GetOwningAsset();
|
|
|
|
|
check(OwningAsset);
|
2021-06-23 20:08:21 -04:00
|
|
|
|
2021-11-22 15:55:50 -05:00
|
|
|
UClass* AssetClass = OwningAsset->GetClass();
|
|
|
|
|
check(AssetClass);
|
2023-04-04 19:14:26 -04:00
|
|
|
const FTopLevelAssetPath& ClassPath = AssetClass->GetClassPathName();
|
2021-11-22 15:55:50 -05:00
|
|
|
|
2023-04-04 19:14:26 -04:00
|
|
|
TArray<FMetasoundFrontendVersion> InitVersions = ISearchEngine::Get().FindUClassDefaultInterfaceVersions(ClassPath);
|
|
|
|
|
FModifyRootGraphInterfaces({ }, InitVersions).Transform(GetDocumentChecked());
|
2021-06-23 20:08:21 -04:00
|
|
|
}
|
|
|
|
|
|
2023-03-07 17:01:52 -05:00
|
|
|
void FMetasoundAssetBase::SetDocument(FMetasoundFrontendDocument&& InDocument)
|
|
|
|
|
{
|
|
|
|
|
FMetasoundFrontendDocument& Document = GetDocumentChecked();
|
|
|
|
|
Document = MoveTemp(InDocument);
|
|
|
|
|
MarkMetasoundDocumentDirty();
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 15:16:57 -04:00
|
|
|
bool FMetasoundAssetBase::VersionAsset()
|
2021-06-23 20:08:21 -04:00
|
|
|
{
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
using namespace Metasound::Frontend;
|
2021-08-11 15:22:01 -04:00
|
|
|
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE(MetaSoundAssetBase::VersionAsset);
|
2023-06-20 13:12:39 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
const bool bIsDeterministic = MetaSoundEnableDeterministicIDGenerationInEditorCVar != 0 && !IsRunningCookCommandlet();
|
|
|
|
|
FDocumentIDGenerator::FScopeDeterminism DeterminismScope(bIsDeterministic);
|
2023-07-24 12:45:51 -04:00
|
|
|
#else
|
|
|
|
|
const bool bIsDeterministic = MetaSoundEnableRuntimeDeterministicIDGeneration != 0 && !IsRunningCookCommandlet();
|
|
|
|
|
FDocumentIDGenerator::FScopeDeterminism DeterminismScope(bIsDeterministic);
|
2023-06-20 13:12:39 -04:00
|
|
|
#endif // WITH_EDITOR
|
2021-06-23 20:08:21 -04:00
|
|
|
|
|
|
|
|
FName AssetName;
|
|
|
|
|
FString AssetPath;
|
|
|
|
|
if (const UObject* OwningAsset = GetOwningAsset())
|
|
|
|
|
{
|
|
|
|
|
AssetName = FName(OwningAsset->GetName());
|
|
|
|
|
AssetPath = OwningAsset->GetPathName();
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 17:01:52 -05:00
|
|
|
FMetasoundFrontendDocument* Doc = GetDocumentAccessPtr().Get();
|
2021-11-22 15:55:50 -05:00
|
|
|
if (!ensure(Doc))
|
2021-06-23 20:08:21 -04:00
|
|
|
{
|
2021-11-22 15:55:50 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-10 20:37:31 -05:00
|
|
|
bool bDidEdit = Doc->VersionInterfaces();
|
2021-11-22 15:55:50 -05:00
|
|
|
|
|
|
|
|
// Version Document Model
|
2021-12-10 20:37:31 -05:00
|
|
|
FDocumentHandle DocHandle = GetDocumentHandle();
|
2021-11-22 15:55:50 -05:00
|
|
|
{
|
|
|
|
|
bDidEdit |= FVersionDocument(AssetName, AssetPath).Transform(DocHandle);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-16 19:59:03 -05:00
|
|
|
// Version Interfaces. Has to be re-run until no pass reports an update in case
|
|
|
|
|
// versions fork (ex. an interface splits into two newly named interfaces).
|
2021-11-22 15:55:50 -05:00
|
|
|
{
|
|
|
|
|
bool bInterfaceUpdated = false;
|
2021-12-16 19:59:03 -05:00
|
|
|
bool bPassUpdated = true;
|
|
|
|
|
while (bPassUpdated)
|
2021-08-18 15:16:57 -04:00
|
|
|
{
|
2021-12-16 19:59:03 -05:00
|
|
|
bPassUpdated = false;
|
|
|
|
|
|
|
|
|
|
const TArray<FMetasoundFrontendVersion> Versions = Doc->Interfaces.Array();
|
|
|
|
|
for (const FMetasoundFrontendVersion& Version : Versions)
|
|
|
|
|
{
|
2023-04-28 16:43:19 -04:00
|
|
|
bPassUpdated |= FUpdateRootGraphInterface(Version, GetOwningAssetName()).Transform(DocHandle);
|
2021-12-16 19:59:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bInterfaceUpdated |= bPassUpdated;
|
2021-08-18 15:16:57 -04:00
|
|
|
}
|
2021-12-16 19:59:03 -05:00
|
|
|
|
2021-11-22 15:55:50 -05:00
|
|
|
if (bInterfaceUpdated)
|
|
|
|
|
{
|
|
|
|
|
ConformObjectDataToInterfaces();
|
|
|
|
|
}
|
|
|
|
|
bDidEdit |= bInterfaceUpdated;
|
2021-06-23 20:08:21 -04:00
|
|
|
}
|
|
|
|
|
|
2021-07-27 15:36:03 -04:00
|
|
|
return bDidEdit;
|
2021-02-01 15:59:27 -04:00
|
|
|
}
|
|
|
|
|
|
2022-02-10 18:36:26 -05:00
|
|
|
#if WITH_EDITOR
|
2022-01-26 18:11:52 -05:00
|
|
|
void FMetasoundAssetBase::CacheRegistryMetadata()
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
2023-03-07 17:01:52 -05:00
|
|
|
FMetasoundFrontendDocument* Document = GetDocumentAccessPtr().Get();
|
2022-01-26 18:11:52 -05:00
|
|
|
if (!ensure(Document))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using FNameDataTypePair = TPair<FName, FName>;
|
|
|
|
|
const TSet<FMetasoundFrontendVersion>& InterfaceVersions = Document->Interfaces;
|
|
|
|
|
FMetasoundFrontendClassInterface& RootGraphClassInterface = Document->RootGraph.Interface;
|
|
|
|
|
|
|
|
|
|
// 1. Gather inputs/outputs managed by interfaces
|
|
|
|
|
TMap<FNameDataTypePair, FMetasoundFrontendClassInput*> Inputs;
|
|
|
|
|
for (FMetasoundFrontendClassInput& Input : RootGraphClassInterface.Inputs)
|
|
|
|
|
{
|
|
|
|
|
FNameDataTypePair NameDataTypePair = FNameDataTypePair(Input.Name, Input.TypeName);
|
|
|
|
|
Inputs.Add(MoveTemp(NameDataTypePair), &Input);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TMap<FNameDataTypePair, FMetasoundFrontendClassOutput*> Outputs;
|
|
|
|
|
for (FMetasoundFrontendClassOutput& Output : RootGraphClassInterface.Outputs)
|
|
|
|
|
{
|
|
|
|
|
FNameDataTypePair NameDataTypePair = FNameDataTypePair(Output.Name, Output.TypeName);
|
|
|
|
|
Outputs.Add(MoveTemp(NameDataTypePair), &Output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. Copy metadata for inputs/outputs managed by interfaces, removing them from maps generated
|
2022-03-01 16:31:55 -05:00
|
|
|
auto CacheInterfaceMetadata = [](const FMetasoundFrontendVertexMetadata & InRegistryMetadata, FMetasoundFrontendVertexMetadata& OutMetadata)
|
|
|
|
|
{
|
|
|
|
|
const int32 CachedSortOrderIndex = OutMetadata.SortOrderIndex;
|
|
|
|
|
OutMetadata = InRegistryMetadata;
|
|
|
|
|
OutMetadata.SortOrderIndex = CachedSortOrderIndex;
|
|
|
|
|
};
|
|
|
|
|
|
2022-01-26 18:11:52 -05:00
|
|
|
for (const FMetasoundFrontendVersion& Version : InterfaceVersions)
|
|
|
|
|
{
|
|
|
|
|
const FInterfaceRegistryKey InterfaceKey = GetInterfaceRegistryKey(Version);
|
|
|
|
|
const IInterfaceRegistryEntry* Entry = IInterfaceRegistry::Get().FindInterfaceRegistryEntry(InterfaceKey);
|
|
|
|
|
if (ensure(Entry))
|
|
|
|
|
{
|
|
|
|
|
for (const FMetasoundFrontendClassInput& InterfaceInput : Entry->GetInterface().Inputs)
|
|
|
|
|
{
|
|
|
|
|
const FNameDataTypePair NameDataTypePair = FNameDataTypePair(InterfaceInput.Name, InterfaceInput.TypeName);
|
|
|
|
|
if (FMetasoundFrontendClassInput* Input = Inputs.FindRef(NameDataTypePair))
|
|
|
|
|
{
|
2022-03-01 16:31:55 -05:00
|
|
|
CacheInterfaceMetadata(InterfaceInput.Metadata, Input->Metadata);
|
2022-01-26 18:11:52 -05:00
|
|
|
Inputs.Remove(NameDataTypePair);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const FMetasoundFrontendClassOutput& InterfaceOutput : Entry->GetInterface().Outputs)
|
|
|
|
|
{
|
|
|
|
|
const FNameDataTypePair NameDataTypePair = FNameDataTypePair(InterfaceOutput.Name, InterfaceOutput.TypeName);
|
|
|
|
|
if (FMetasoundFrontendClassOutput* Output = Outputs.FindRef(NameDataTypePair))
|
|
|
|
|
{
|
2022-03-01 16:31:55 -05:00
|
|
|
CacheInterfaceMetadata(InterfaceOutput.Metadata, Output->Metadata);
|
2022-01-26 18:11:52 -05:00
|
|
|
Outputs.Remove(NameDataTypePair);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. Iterate remaining inputs/outputs not managed by interfaces and set to serialize text
|
|
|
|
|
// (in case they were orphaned by an interface no longer being implemented).
|
|
|
|
|
for (TPair<FNameDataTypePair, FMetasoundFrontendClassInput*>& Pair : Inputs)
|
|
|
|
|
{
|
|
|
|
|
Pair.Value->Metadata.SetSerializeText(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (TPair<FNameDataTypePair, FMetasoundFrontendClassOutput*>& Pair : Outputs)
|
|
|
|
|
{
|
|
|
|
|
Pair.Value->Metadata.SetSerializeText(true);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-01 16:31:55 -05:00
|
|
|
// 4. Refresh style as order of members could've changed
|
|
|
|
|
{
|
|
|
|
|
FMetasoundFrontendInterfaceStyle InputStyle;
|
|
|
|
|
Algo::ForEach(RootGraphClassInterface.Inputs, [&InputStyle](const FMetasoundFrontendClassInput& Input)
|
|
|
|
|
{
|
|
|
|
|
InputStyle.DefaultSortOrder.Add(Input.Metadata.SortOrderIndex);
|
|
|
|
|
});
|
|
|
|
|
RootGraphClassInterface.SetInputStyle(InputStyle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
FMetasoundFrontendInterfaceStyle OutputStyle;
|
|
|
|
|
Algo::ForEach(RootGraphClassInterface.Outputs, [&OutputStyle](const FMetasoundFrontendClassOutput& Output)
|
|
|
|
|
{
|
|
|
|
|
OutputStyle.DefaultSortOrder.Add(Output.Metadata.SortOrderIndex);
|
|
|
|
|
});
|
|
|
|
|
RootGraphClassInterface.SetOutputStyle(OutputStyle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. Cache registry data on document dependencies
|
2022-01-27 01:31:46 -05:00
|
|
|
for (FMetasoundFrontendClass& Dependency : Document->Dependencies)
|
2022-01-26 18:11:52 -05:00
|
|
|
{
|
2022-01-27 01:31:46 -05:00
|
|
|
if (!FMetasoundFrontendClass::CacheGraphDependencyMetadataFromRegistry(Dependency))
|
2022-01-26 18:11:52 -05:00
|
|
|
{
|
|
|
|
|
UE_LOG(LogMetaSound, Warning,
|
|
|
|
|
TEXT("'%s' failed to cache dependency registry data: Registry missing class with key '%s'"),
|
|
|
|
|
*GetOwningAssetName(),
|
2022-01-27 01:31:46 -05:00
|
|
|
*Dependency.Metadata.GetClassName().ToString());
|
2022-01-26 18:11:52 -05:00
|
|
|
UE_LOG(LogMetaSound, Warning,
|
|
|
|
|
TEXT("Asset '%s' may fail to build runtime graph unless re-registered after dependency with given key is loaded."),
|
|
|
|
|
*GetOwningAssetName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-22 15:02:24 -04:00
|
|
|
FMetasoundFrontendDocumentModifyContext& FMetasoundAssetBase::GetModifyContext()
|
2021-11-18 14:37:34 -05:00
|
|
|
{
|
2022-09-22 15:02:24 -04:00
|
|
|
return GetDocumentChecked().Metadata.ModifyContext;
|
2021-11-18 14:37:34 -05:00
|
|
|
}
|
|
|
|
|
|
2022-09-22 15:02:24 -04:00
|
|
|
const FMetasoundFrontendDocumentModifyContext& FMetasoundAssetBase::GetModifyContext() const
|
2021-11-22 15:55:50 -05:00
|
|
|
{
|
2022-09-22 15:02:24 -04:00
|
|
|
return GetDocumentChecked().Metadata.ModifyContext;
|
2021-11-18 14:37:34 -05:00
|
|
|
}
|
2022-02-10 18:36:26 -05:00
|
|
|
#endif // WITH_EDITOR
|
2021-11-18 14:37:34 -05:00
|
|
|
|
2023-06-23 14:53:34 -04:00
|
|
|
TSharedPtr<Metasound::FGraph, ESPMode::ThreadSafe> FMetasoundAssetBase::BuildMetasoundDocument(const FMetasoundFrontendDocument& InPreprocessedDoc, const TSet<FName>& InTransmittableInputNames) const
|
2021-06-08 10:52:31 -04:00
|
|
|
{
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
2021-08-11 15:22:01 -04:00
|
|
|
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE(MetaSoundAssetBase::BuildMetasoundDocument);
|
|
|
|
|
|
2022-03-04 04:25:00 -05:00
|
|
|
// Create graph which can spawn instances.
|
2022-10-10 15:44:28 -04:00
|
|
|
TUniquePtr<FFrontendGraph> FrontendGraph = FFrontendGraphBuilder::CreateGraph(InPreprocessedDoc, InTransmittableInputNames, GetOwningAssetName());
|
|
|
|
|
if (!FrontendGraph.IsValid())
|
2022-03-04 04:25:00 -05:00
|
|
|
{
|
|
|
|
|
UE_LOG(LogMetaSound, Error, TEXT("Failed to build MetaSound graph in asset '%s'"), *GetOwningAssetName());
|
|
|
|
|
}
|
2021-06-08 10:52:31 -04:00
|
|
|
|
2023-06-23 14:53:34 -04:00
|
|
|
TSharedPtr<Metasound::FGraph, ESPMode::ThreadSafe> SharedGraph(FrontendGraph.Release());
|
2021-09-16 14:46:43 -04:00
|
|
|
|
|
|
|
|
return SharedGraph;
|
2021-06-08 10:52:31 -04:00
|
|
|
}
|
|
|
|
|
|
2021-08-18 15:16:57 -04:00
|
|
|
bool FMetasoundAssetBase::IsRegistered() const
|
2021-07-27 15:36:03 -04:00
|
|
|
{
|
2021-08-18 15:16:57 -04:00
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
|
|
|
|
if (!NodeRegistryKey::IsValid(RegistryKey))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FMetasoundFrontendRegistryContainer::Get()->IsNodeRegistered(RegistryKey);
|
2021-07-27 15:36:03 -04:00
|
|
|
}
|
|
|
|
|
|
2021-11-18 14:37:34 -05:00
|
|
|
bool FMetasoundAssetBase::IsReferencedAsset(const FMetasoundAssetBase& InAsset) const
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
|
|
|
|
bool bIsReferenced = false;
|
2022-05-10 16:51:39 -04:00
|
|
|
AssetBasePrivate::DepthFirstTraversal(*this, [&](const FMetasoundAssetBase& ChildAsset)
|
2021-11-18 14:37:34 -05:00
|
|
|
{
|
|
|
|
|
TSet<const FMetasoundAssetBase*> Children;
|
|
|
|
|
if (&ChildAsset == &InAsset)
|
|
|
|
|
{
|
|
|
|
|
bIsReferenced = true;
|
|
|
|
|
return Children;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<FMetasoundAssetBase*> ChildRefs;
|
|
|
|
|
ensureAlways(IMetaSoundAssetManager::GetChecked().TryLoadReferencedAssets(ChildAsset, ChildRefs));
|
|
|
|
|
Algo::Transform(ChildRefs, Children, [](FMetasoundAssetBase* Child) { return Child; });
|
|
|
|
|
return Children;
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return bIsReferenced;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 15:16:57 -04:00
|
|
|
bool FMetasoundAssetBase::AddingReferenceCausesLoop(const FSoftObjectPath& InReferencePath) const
|
2021-07-27 15:36:03 -04:00
|
|
|
{
|
2021-11-07 23:43:01 -05:00
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
2021-08-18 15:16:57 -04:00
|
|
|
const FMetasoundAssetBase* ReferenceAsset = IMetaSoundAssetManager::GetChecked().TryLoadAsset(InReferencePath);
|
2021-07-27 15:36:03 -04:00
|
|
|
if (!ensureAlways(ReferenceAsset))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool bCausesLoop = false;
|
|
|
|
|
const FMetasoundAssetBase* Parent = this;
|
2022-05-10 16:51:39 -04:00
|
|
|
AssetBasePrivate::DepthFirstTraversal(*ReferenceAsset, [&](const FMetasoundAssetBase& ChildAsset)
|
2021-07-27 15:36:03 -04:00
|
|
|
{
|
|
|
|
|
TSet<const FMetasoundAssetBase*> Children;
|
|
|
|
|
if (Parent == &ChildAsset)
|
|
|
|
|
{
|
|
|
|
|
bCausesLoop = true;
|
|
|
|
|
return Children;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-07 23:43:01 -05:00
|
|
|
TArray<FMetasoundAssetBase*> ChildRefs;
|
2021-11-18 14:37:34 -05:00
|
|
|
ensureAlways(IMetaSoundAssetManager::GetChecked().TryLoadReferencedAssets(ChildAsset, ChildRefs));
|
|
|
|
|
Algo::Transform(ChildRefs, Children, [] (FMetasoundAssetBase* Child) { return Child; });
|
2021-07-27 15:36:03 -04:00
|
|
|
return Children;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return bCausesLoop;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 11:21:13 -04:00
|
|
|
void FMetasoundAssetBase::ConvertFromPreset()
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
FGraphHandle GraphHandle = GetRootGraphHandle();
|
2022-02-10 15:07:39 -05:00
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
2021-06-16 11:21:13 -04:00
|
|
|
FMetasoundFrontendGraphStyle Style = GraphHandle->GetGraphStyle();
|
|
|
|
|
Style.bIsGraphEditable = true;
|
|
|
|
|
GraphHandle->SetGraphStyle(Style);
|
2022-02-10 15:07:39 -05:00
|
|
|
#endif // WITH_EDITOR
|
2021-07-27 15:36:03 -04:00
|
|
|
|
2022-02-09 12:52:07 -05:00
|
|
|
FMetasoundFrontendGraphClassPresetOptions PresetOptions = GraphHandle->GetGraphPresetOptions();
|
|
|
|
|
PresetOptions.bIsPreset = false;
|
|
|
|
|
GraphHandle->SetGraphPresetOptions(PresetOptions);
|
2021-06-16 11:21:13 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-08 10:52:31 -04:00
|
|
|
TArray<FMetasoundAssetBase::FSendInfoAndVertexName> FMetasoundAssetBase::GetSendInfos(uint64 InInstanceID) const
|
|
|
|
|
{
|
2021-07-28 17:12:57 -04:00
|
|
|
using namespace Metasound;
|
2021-06-08 10:52:31 -04:00
|
|
|
using namespace Metasound::Frontend;
|
2021-08-30 14:08:45 -04:00
|
|
|
using FSendInfo = FMetaSoundParameterTransmitter::FSendInfo;
|
2021-06-08 10:52:31 -04:00
|
|
|
|
2021-09-16 14:46:43 -04:00
|
|
|
check(IsInGameThread() || IsInAudioThread());
|
|
|
|
|
|
|
|
|
|
const FRuntimeData& RuntimeData = GetRuntimeData();
|
2022-03-10 22:07:08 -05:00
|
|
|
checkf(CurrentCachedRuntimeDataChangeID == RuntimeData.ChangeID, TEXT("Asset must have up-to-date cached RuntimeData prior to calling GetSendInfos"));
|
2021-09-16 14:46:43 -04:00
|
|
|
|
2021-06-08 10:52:31 -04:00
|
|
|
TArray<FSendInfoAndVertexName> SendInfos;
|
|
|
|
|
|
2021-09-16 14:46:43 -04:00
|
|
|
for (const FMetasoundFrontendClassInput& Vertex : RuntimeData.TransmittableInputs)
|
2021-06-08 10:52:31 -04:00
|
|
|
{
|
2021-09-16 14:46:43 -04:00
|
|
|
FSendInfoAndVertexName Info;
|
2021-06-08 10:52:31 -04:00
|
|
|
|
2023-04-05 17:38:47 -04:00
|
|
|
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
2021-09-16 14:46:43 -04:00
|
|
|
Info.SendInfo.Address = FMetaSoundParameterTransmitter::CreateSendAddressFromInstanceID(InInstanceID, Vertex.Name, Vertex.TypeName);
|
2023-04-05 17:38:47 -04:00
|
|
|
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
2021-09-16 14:46:43 -04:00
|
|
|
Info.SendInfo.ParameterName = Vertex.Name;
|
|
|
|
|
Info.SendInfo.TypeName = Vertex.TypeName;
|
|
|
|
|
Info.VertexName = Vertex.Name;
|
2021-06-08 10:52:31 -04:00
|
|
|
|
2021-09-16 14:46:43 -04:00
|
|
|
SendInfos.Add(Info);
|
|
|
|
|
|
2021-06-08 10:52:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SendInfos;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-10 18:36:26 -05:00
|
|
|
#if WITH_EDITOR
|
2021-06-08 10:52:31 -04:00
|
|
|
FText FMetasoundAssetBase::GetDisplayName(FString&& InTypeName) const
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
|
|
|
|
FConstGraphHandle GraphHandle = GetRootGraphHandle();
|
|
|
|
|
const bool bIsPreset = !GraphHandle->GetGraphStyle().bIsGraphEditable;
|
|
|
|
|
|
|
|
|
|
if (!bIsPreset)
|
|
|
|
|
{
|
|
|
|
|
return FText::FromString(MoveTemp(InTypeName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FText::Format(LOCTEXT("PresetDisplayNameFormat", "{0} (Preset)"), FText::FromString(MoveTemp(InTypeName)));
|
|
|
|
|
}
|
2022-02-10 18:36:26 -05:00
|
|
|
#endif // WITH_EDITOR
|
2021-06-08 10:52:31 -04:00
|
|
|
|
2021-02-01 15:59:27 -04:00
|
|
|
bool FMetasoundAssetBase::MarkMetasoundDocumentDirty() const
|
|
|
|
|
{
|
|
|
|
|
if (const UObject* OwningAsset = GetOwningAsset())
|
|
|
|
|
{
|
|
|
|
|
return ensure(OwningAsset->MarkPackageDirty());
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2020-07-23 20:32:26 -04:00
|
|
|
}
|
|
|
|
|
|
2021-01-13 10:48:59 -04:00
|
|
|
Metasound::Frontend::FDocumentHandle FMetasoundAssetBase::GetDocumentHandle()
|
|
|
|
|
{
|
2023-03-07 17:01:52 -05:00
|
|
|
return Metasound::Frontend::IDocumentController::CreateDocumentHandle(GetDocumentAccessPtr());
|
2021-01-13 10:48:59 -04:00
|
|
|
}
|
2020-07-17 16:43:42 -04:00
|
|
|
|
2021-01-13 19:18:22 -04:00
|
|
|
Metasound::Frontend::FConstDocumentHandle FMetasoundAssetBase::GetDocumentHandle() const
|
|
|
|
|
{
|
2023-03-07 17:01:52 -05:00
|
|
|
return Metasound::Frontend::IDocumentController::CreateDocumentHandle(GetDocumentConstAccessPtr());
|
2021-01-13 19:18:22 -04:00
|
|
|
}
|
|
|
|
|
|
2020-12-14 15:48:27 -04:00
|
|
|
Metasound::Frontend::FGraphHandle FMetasoundAssetBase::GetRootGraphHandle()
|
2020-07-17 16:43:42 -04:00
|
|
|
{
|
2021-01-13 10:48:59 -04:00
|
|
|
return GetDocumentHandle()->GetRootGraph();
|
2020-07-17 16:43:42 -04:00
|
|
|
}
|
|
|
|
|
|
2021-01-13 19:18:22 -04:00
|
|
|
Metasound::Frontend::FConstGraphHandle FMetasoundAssetBase::GetRootGraphHandle() const
|
|
|
|
|
{
|
|
|
|
|
return GetDocumentHandle()->GetRootGraph();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-05 12:47:19 -04:00
|
|
|
bool FMetasoundAssetBase::ImportFromJSON(const FString& InJSON)
|
2020-07-23 16:39:56 -04:00
|
|
|
{
|
2021-08-11 15:22:01 -04:00
|
|
|
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE(MetaSoundAssetBase::ImportFromJSON);
|
|
|
|
|
|
2023-03-07 17:01:52 -05:00
|
|
|
FMetasoundFrontendDocument* Document = GetDocumentAccessPtr().Get();
|
2021-07-12 16:13:03 -04:00
|
|
|
if (ensure(nullptr != Document))
|
2020-12-14 15:48:27 -04:00
|
|
|
{
|
2021-02-01 15:59:27 -04:00
|
|
|
bool bSuccess = Metasound::Frontend::ImportJSONToMetasound(InJSON, *Document);
|
|
|
|
|
|
|
|
|
|
if (bSuccess)
|
|
|
|
|
{
|
|
|
|
|
ensure(MarkMetasoundDocumentDirty());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bSuccess;
|
2020-12-14 15:48:27 -04:00
|
|
|
}
|
|
|
|
|
return false;
|
2020-07-23 16:39:56 -04:00
|
|
|
}
|
|
|
|
|
|
2020-08-05 12:47:19 -04:00
|
|
|
bool FMetasoundAssetBase::ImportFromJSONAsset(const FString& InAbsolutePath)
|
2020-07-17 16:43:42 -04:00
|
|
|
{
|
2021-08-11 15:22:01 -04:00
|
|
|
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE(MetaSoundAssetBase::ImportFromJSONAsset);
|
|
|
|
|
|
2023-03-07 17:01:52 -05:00
|
|
|
Metasound::Frontend::FDocumentAccessPtr DocumentPtr = GetDocumentAccessPtr();
|
2021-07-12 16:13:03 -04:00
|
|
|
if (FMetasoundFrontendDocument* Document = DocumentPtr.Get())
|
2020-12-14 15:48:27 -04:00
|
|
|
{
|
2021-02-01 15:59:27 -04:00
|
|
|
bool bSuccess = Metasound::Frontend::ImportJSONAssetToMetasound(InAbsolutePath, *Document);
|
|
|
|
|
|
|
|
|
|
if (bSuccess)
|
|
|
|
|
{
|
|
|
|
|
ensure(MarkMetasoundDocumentDirty());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bSuccess;
|
2020-12-14 15:48:27 -04:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-13 10:48:59 -04:00
|
|
|
FMetasoundFrontendDocument& FMetasoundAssetBase::GetDocumentChecked()
|
2020-12-14 15:48:27 -04:00
|
|
|
{
|
2023-03-07 17:01:52 -05:00
|
|
|
FMetasoundFrontendDocument* Document = GetDocumentAccessPtr().Get();
|
2021-07-12 16:13:03 -04:00
|
|
|
check(nullptr != Document);
|
|
|
|
|
return *Document;
|
2020-12-14 15:48:27 -04:00
|
|
|
}
|
|
|
|
|
|
2021-01-13 10:48:59 -04:00
|
|
|
const FMetasoundFrontendDocument& FMetasoundAssetBase::GetDocumentChecked() const
|
2020-12-14 15:48:27 -04:00
|
|
|
{
|
2023-03-07 17:01:52 -05:00
|
|
|
const FMetasoundFrontendDocument* Document = GetDocumentConstAccessPtr().Get();
|
2020-12-14 15:48:27 -04:00
|
|
|
|
2021-07-12 16:13:03 -04:00
|
|
|
check(nullptr != Document);
|
|
|
|
|
return *Document;
|
2020-08-05 12:47:19 -04:00
|
|
|
}
|
2021-07-28 17:12:57 -04:00
|
|
|
|
2023-03-23 14:04:36 -04:00
|
|
|
const Metasound::Frontend::FNodeRegistryKey& FMetasoundAssetBase::GetRegistryKey() const
|
|
|
|
|
{
|
|
|
|
|
return RegistryKey;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-28 17:12:57 -04:00
|
|
|
FString FMetasoundAssetBase::GetOwningAssetName() const
|
|
|
|
|
{
|
|
|
|
|
if (const UObject* OwningAsset = GetOwningAsset())
|
|
|
|
|
{
|
2022-01-27 00:45:28 -05:00
|
|
|
return OwningAsset->GetPathName();
|
2021-07-28 17:12:57 -04:00
|
|
|
}
|
|
|
|
|
return FString();
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-18 13:55:13 -04:00
|
|
|
TArray<FMetasoundFrontendClassInput> FMetasoundAssetBase::GetPublicClassInputs() const
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
|
|
|
|
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE(FMetasoundAssetBase::GetPublicClassInputs);
|
|
|
|
|
|
2021-11-22 15:55:50 -05:00
|
|
|
auto GetInputName = [](const FMetasoundFrontendClassInput& InInput) { return InInput.Name; };
|
2021-09-16 14:46:43 -04:00
|
|
|
|
2022-08-18 13:55:13 -04:00
|
|
|
// Inputs which are controlled by an interface are private.
|
2021-11-22 15:55:50 -05:00
|
|
|
TArray<const IInterfaceRegistryEntry*> Interfaces;
|
2022-08-18 13:55:13 -04:00
|
|
|
TSet<FVertexName> PrivateInputs;
|
2023-03-07 17:01:52 -05:00
|
|
|
FMetaSoundFrontendDocumentBuilder::FindDeclaredInterfaces(GetDocumentChecked(), Interfaces);
|
2021-11-22 15:55:50 -05:00
|
|
|
for (const IInterfaceRegistryEntry* InterfaceEntry : Interfaces)
|
2021-09-16 14:46:43 -04:00
|
|
|
{
|
2021-11-22 15:55:50 -05:00
|
|
|
if (InterfaceEntry)
|
2021-09-16 14:46:43 -04:00
|
|
|
{
|
2021-11-22 15:55:50 -05:00
|
|
|
if (InterfaceEntry->GetRouterName() != Audio::IParameterTransmitter::RouterName)
|
2021-09-16 14:46:43 -04:00
|
|
|
{
|
2021-11-22 15:55:50 -05:00
|
|
|
const FMetasoundFrontendInterface& Interface = InterfaceEntry->GetInterface();
|
2022-08-18 13:55:13 -04:00
|
|
|
Algo::Transform(Interface.Inputs, PrivateInputs, GetInputName);
|
2021-09-16 14:46:43 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-18 13:55:13 -04:00
|
|
|
auto IsPublic = [&PrivateInputs](const FMetasoundFrontendClassVertex& InVertex)
|
|
|
|
|
{
|
|
|
|
|
return !PrivateInputs.Contains(InVertex.Name);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const FMetasoundFrontendDocument& Doc = GetDocumentChecked();
|
|
|
|
|
TArray<FMetasoundFrontendClassInput> PublicInputs;
|
|
|
|
|
|
|
|
|
|
Algo::CopyIf(Doc.RootGraph.Interface.Inputs, PublicInputs, IsPublic);
|
|
|
|
|
|
2022-12-15 17:03:02 -05:00
|
|
|
// Add the parameter pack input that ALL Metasounds have
|
|
|
|
|
PublicInputs.Add(UMetasoundParameterPack::GetClassInput());
|
|
|
|
|
|
2022-08-18 13:55:13 -04:00
|
|
|
return PublicInputs;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-13 17:38:11 -04:00
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
void FMetasoundAssetBase::RebuildReferencedAssetClasses()
|
2022-01-21 15:40:14 -05:00
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
2022-10-13 17:38:11 -04:00
|
|
|
IMetaSoundAssetManager& AssetManager = IMetaSoundAssetManager::GetChecked();
|
|
|
|
|
|
|
|
|
|
AssetManager.AddAssetReferences(*this);
|
|
|
|
|
TSet<IMetaSoundAssetManager::FAssetInfo> ReferencedAssetClasses = AssetManager.GetReferencedAssetClasses(*this);
|
|
|
|
|
SetReferencedAssetClasses(MoveTemp(ReferencedAssetClasses));
|
|
|
|
|
}
|
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
void FMetasoundAssetBase::RegisterAssetDependencies(const Metasound::Frontend::FMetaSoundAssetRegistrationOptions& InRegistrationOptions)
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
|
|
|
|
IMetaSoundAssetManager& AssetManager = IMetaSoundAssetManager::GetChecked();
|
|
|
|
|
TArray<FMetasoundAssetBase*> References = GetReferencedAssets();
|
|
|
|
|
for (FMetasoundAssetBase* Reference : References)
|
|
|
|
|
{
|
|
|
|
|
if (InRegistrationOptions.bForceReregister || !Reference->IsRegistered())
|
|
|
|
|
{
|
|
|
|
|
// TODO: Check for infinite recursion and error if so
|
|
|
|
|
AssetManager.AddOrUpdateAsset(*(Reference->GetOwningAsset()));
|
|
|
|
|
Reference->RegisterGraphWithFrontend(InRegistrationOptions);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FMetasoundAssetBase::AutoUpdate(bool bInLogWarningsOnDroppedConnection)
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
2023-06-20 13:12:39 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
const bool bIsDeterministic = MetaSoundEnableDeterministicIDGenerationInEditorCVar != 0 && !IsRunningCookCommandlet();
|
|
|
|
|
FDocumentIDGenerator::FScopeDeterminism DeterminismScope(bIsDeterministic);
|
2023-07-24 12:45:51 -04:00
|
|
|
#else
|
|
|
|
|
const bool bIsDeterministic = MetaSoundEnableRuntimeDeterministicIDGeneration != 0 && !IsRunningCookCommandlet();
|
|
|
|
|
FDocumentIDGenerator::FScopeDeterminism DeterminismScope(bIsDeterministic);
|
2023-06-20 13:12:39 -04:00
|
|
|
#endif // WITH_EDITOR
|
2022-10-13 17:38:11 -04:00
|
|
|
|
|
|
|
|
FString OwningAssetName = GetOwningAssetName();
|
|
|
|
|
const bool bAutoUpdated = FAutoUpdateRootGraph(MoveTemp(OwningAssetName), bInLogWarningsOnDroppedConnection).Transform(GetDocumentHandle());
|
|
|
|
|
return bAutoUpdated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
|
void FMetasoundAssetBase::UpdateAssetRegistry()
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound;
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
|
|
|
|
FNodeClassInfo AssetClassInfo = GetAssetClassInfo();
|
|
|
|
|
// Refresh Asset Registry Info if successfully registered with Frontend
|
|
|
|
|
const FMetasoundFrontendGraphClass& DocumentClassGraph = GetDocumentHandle()->GetRootGraphClass();
|
|
|
|
|
const FMetasoundFrontendClassMetadata& DocumentClassMetadata = DocumentClassGraph.Metadata;
|
|
|
|
|
AssetClassInfo.AssetClassID = FGuid(DocumentClassMetadata.GetClassName().Name.ToString());
|
|
|
|
|
FNodeClassName ClassName = DocumentClassMetadata.GetClassName().ToNodeClassName();
|
|
|
|
|
FMetasoundFrontendClass GraphClass;
|
|
|
|
|
|
|
|
|
|
AssetClassInfo.Version = DocumentClassMetadata.GetVersion();
|
|
|
|
|
|
|
|
|
|
AssetClassInfo.InputTypes.Reset();
|
|
|
|
|
Algo::Transform(GraphClass.Interface.Inputs, AssetClassInfo.InputTypes, [] (const FMetasoundFrontendClassInput& Input) { return Input.TypeName; });
|
|
|
|
|
|
|
|
|
|
AssetClassInfo.OutputTypes.Reset();
|
|
|
|
|
Algo::Transform(GraphClass.Interface.Outputs, AssetClassInfo.OutputTypes, [](const FMetasoundFrontendClassOutput& Output) { return Output.TypeName; });
|
|
|
|
|
|
|
|
|
|
SetRegistryAssetClassInfo(MoveTemp(AssetClassInfo));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FMetasoundFrontendDocument> FMetasoundAssetBase::PreprocessDocument()
|
|
|
|
|
{
|
|
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FMetasoundFrontendDocument> PreprocessedDocument = MakeShared<FMetasoundFrontendDocument>(GetDocumentChecked());
|
|
|
|
|
FDocumentTemplatePreprocessTransform TemplatePreprocessor;
|
|
|
|
|
TemplatePreprocessor.Transform(*PreprocessedDocument);
|
|
|
|
|
return PreprocessedDocument;
|
2022-01-21 15:40:14 -05:00
|
|
|
}
|
|
|
|
|
|
2022-08-16 16:19:43 -04:00
|
|
|
const FMetasoundAssetBase::FRuntimeData& FMetasoundAssetBase::CacheRuntimeData(const FMetasoundFrontendDocument& InPreprocessedDoc)
|
2021-09-16 14:46:43 -04:00
|
|
|
{
|
2022-10-10 15:44:28 -04:00
|
|
|
using namespace Metasound::Frontend;
|
|
|
|
|
|
2022-03-10 22:07:08 -05:00
|
|
|
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE(MetaSoundAssetBase::CacheRuntimeData);
|
|
|
|
|
|
2022-10-10 15:44:28 -04:00
|
|
|
CurrentCachedRuntimeDataChangeID = FGuid::NewGuid();
|
|
|
|
|
CachedRuntimeData.ChangeID = CurrentCachedRuntimeDataChangeID;
|
|
|
|
|
|
|
|
|
|
TArray<FMetasoundFrontendClassInput> PublicInputs = GetPublicClassInputs();
|
|
|
|
|
TArray<FMetasoundFrontendClassInput> TransmittableInputs = AssetBasePrivate::GetTransmittableInputsFromPublicInputs(PublicInputs);
|
|
|
|
|
|
|
|
|
|
TSet<FName> TransmittableInputNames;
|
|
|
|
|
Algo::Transform(TransmittableInputs, TransmittableInputNames, [](const FMetasoundFrontendClassInput& Input) { return Input.Name; });
|
2023-06-23 14:53:34 -04:00
|
|
|
TSharedPtr<Metasound::FGraph, ESPMode::ThreadSafe> Graph = BuildMetasoundDocument(InPreprocessedDoc, TransmittableInputNames);
|
2022-10-10 15:44:28 -04:00
|
|
|
|
|
|
|
|
CachedRuntimeData =
|
2021-09-16 14:46:43 -04:00
|
|
|
{
|
2022-10-10 15:44:28 -04:00
|
|
|
CurrentCachedRuntimeDataChangeID,
|
|
|
|
|
MoveTemp(PublicInputs),
|
|
|
|
|
MoveTemp(TransmittableInputs),
|
|
|
|
|
MoveTemp(Graph)
|
|
|
|
|
};
|
2021-09-16 14:46:43 -04:00
|
|
|
|
|
|
|
|
return CachedRuntimeData;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 22:07:08 -05:00
|
|
|
const FMetasoundAssetBase::FRuntimeData& FMetasoundAssetBase::GetRuntimeData() const
|
|
|
|
|
{
|
|
|
|
|
ensureMsgf(CurrentCachedRuntimeDataChangeID == CachedRuntimeData.ChangeID, TEXT("Accessing out-of-date runtime data: MetaSound asset '%s'."), *GetOwningAssetName());
|
|
|
|
|
|
|
|
|
|
return CachedRuntimeData;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-08 10:52:31 -04:00
|
|
|
#undef LOCTEXT_NAMESPACE // "MetaSound"
|