2020-09-08 14:13:51 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# pragma once
# include "DSP/Dsp.h"
# include "DSP/MultithreadedPatching.h"
2022-07-13 17:16:54 -04:00
# include "HAL/Platform.h"
2020-11-04 14:26:37 -04:00
# include "MetasoundAudioBuffer.h"
# include "MetasoundDataFactory.h"
# include "MetasoundDataReference.h"
2021-04-06 01:41:29 -04:00
# include "MetasoundExecutableOperator.h"
2020-11-04 14:26:37 -04:00
# include "MetasoundLiteral.h"
2021-08-30 14:08:45 -04:00
# include "MetasoundLog.h"
2020-11-04 14:26:37 -04:00
# include "MetasoundOperatorInterface.h"
# include "MetasoundOperatorSettings.h"
2021-04-06 01:41:29 -04:00
# include "MetasoundTrigger.h"
2020-11-04 14:26:37 -04:00
# include "Misc/Guid.h"
2021-10-12 21:21:22 -04:00
# include "Templates/TypeHash.h"
2020-11-04 14:26:37 -04:00
# include "UObject/NameTypes.h"
2020-09-08 14:13:51 -04:00
2021-07-21 15:46:42 -04:00
# include <atomic>
2020-09-08 14:13:51 -04:00
# include <type_traits>
/**
* METASOUND TRANSMISSION SYSTEM
2022-07-13 17:16:54 -04:00
* This allows for transmission of arbitrary data types using transmission addresses .
2020-09-08 14:13:51 -04:00
*
* Typical use case :
2021-03-05 20:06:54 -04:00
* TSenderPtr < float > FloatSender FDataTransmissionCenter : : Get ( ) . RegisterNewSender < float > ( ExampleAddress , InitSettings ) ;
2020-09-08 14:13:51 -04:00
* TReceiverPtr < float > FloatReceiver FDataTransmissionCenter : : Get ( ) . RegisterNewReceiver < float > ( ExampleAddress , InitSettings ) ;
*
* //...
* FloatSender - > Push ( 4.5f ) ;
*
* //... elsewhere on a different thread:
* float ReceivedFloat = FloatReceiver - > Pop ( ) ;
*
* In general , some performance considerations for this system :
2022-07-13 17:16:54 -04:00
* 1 ) Senders and receivers are meant to have long lifecycles , and requesting them from the FDataTransmissionCenter may be expensive if done every tick .
* 2 ) Most non - audio data types cannot be mixed , so multiple senders to the same address will cause only one of the senders to be effective .
* 3 ) while the overall system is thread safe , individual TSender and TReceiver objects should only be used by a single thread .
2020-09-08 14:13:51 -04:00
*/
namespace Metasound
{
2022-07-13 17:16:54 -04:00
//Forward declare
class FTransmissionAddress ;
uint32 GetTypeHash ( const Metasound : : FTransmissionAddress & ) ;
/** A FTranmissionAddress acts as a identifier for a data channel shared by
* one or more senders and or receivers .
*
* Different addressing schemes are supported by deriving a system specific
* address type from a FTransmissionAddress . This allows different systems
* to construct and store address information in their desired format while
* all utilizing the same system for transmission .
*/
class METASOUNDFRONTEND_API FTransmissionAddress
2020-09-08 14:13:51 -04:00
{
2021-10-12 21:21:22 -04:00
public :
2022-07-13 17:16:54 -04:00
FTransmissionAddress ( ) = default ;
virtual ~ FTransmissionAddress ( ) = default ;
/** Return the type of address.
*
* The AddressType must be unique per a subclass of FTransmissionAddress
* as it is used to determine the validity of a static_cast from FTransmissionAddress
* to the derived address type .
*/
virtual FName GetAddressType ( ) const = 0 ;
bool operator = = ( const FTransmissionAddress & InOther ) const ;
bool operator ! = ( const FTransmissionAddress & InOther ) const ;
/** Return the data type. */
virtual FName GetDataType ( ) const = 0 ;
/** Clone the address. */
virtual TUniquePtr < FTransmissionAddress > Clone ( ) const = 0 ;
/** Return a string representation of the address for debugging. */
virtual FString ToString ( ) const = 0 ;
private :
friend uint32 GetTypeHash ( const : : Metasound : : FTransmissionAddress & ) ;
template < typename DerivedAddressType >
friend const DerivedAddressType * CastAddressType ( const FTransmissionAddress & ) ;
template < typename DerivedAddressType >
struct THasStaticAddressType
{
private :
// SFINAE: If the static member `T::AddressType` exists, then this template is used.
template <
typename T ,
typename = typename std : : enable_if_t < ! std : : is_member_pointer_v < decltype ( & T : : AddressType ) > >
>
static std : : true_type CheckIfStaticMemberExists ( int32 ) ;
// SFINAE: If the static member `T::AddressType` does not exist, then this template is used.
template < typename >
static std : : false_type CheckIfStaticMemberExists ( . . . ) ;
public :
// True if the static member T::AddressType exists.
static constexpr bool Value = decltype ( CheckIfStaticMemberExists < DerivedAddressType > ( 0 ) ) : : value ;
} ;
/** Create a hash of the address. */
virtual uint32 GetHash ( ) const = 0 ;
/** Determine if the given address is equal to this address. */
virtual bool IsEqual ( const FTransmissionAddress & InOther ) const = 0 ;
} ;
/** Attempt to cast a FTransmissionAddress to a derived address type.
*
* This function uses the FTransmissionAddress : : GetAddressType ( ) method to
* determine whether the cast is legal . Each subclass of FTransmissionAddress
* * MUST * provide a unique address type to protect against invalid casts .
*/
template < typename DerivedAddressType >
const DerivedAddressType * CastAddressType ( const FTransmissionAddress & InOther )
{
// Helper struct to determine if the DerivedAddressType class has a `DerivedAddressType::AddressType` static member
// Static assert on invalid cast attempts
static_assert ( std : : is_base_of < FTransmissionAddress , DerivedAddressType > : : value , " The derived address type must be derived from FTransmissionAddress " ) ;
static_assert ( FTransmissionAddress : : THasStaticAddressType < DerivedAddressType > : : Value , " The derived address type must have a static member `AddressType` to perform casts " ) ;
// Check if AddressType is equal
if ( InOther . GetAddressType ( ) = = DerivedAddressType : : AddressType )
{
return static_cast < const DerivedAddressType * > ( & InOther ) ;
}
return nullptr ;
}
/** FSendAddress is used as a addressing system for MetaSound Send nodes, Recieve
* nodes and MetaSound script communication
*/
class METASOUNDFRONTEND_API FSendAddress : public FTransmissionAddress
{
public :
static const FLazyName AddressType ;
2021-10-12 21:21:22 -04:00
FSendAddress ( ) = default ;
2020-09-08 14:13:51 -04:00
2021-10-12 21:21:22 -04:00
// Create an address without a data type or instance ID
FSendAddress ( const FString & InChannelName ) ;
// Create an address with a channel name, data type and optionally an instance ID.
FSendAddress ( const FName & InChannelName , const FName & InDataType , uint64 InInstanceID = INDEX_NONE ) ;
2022-07-13 17:16:54 -04:00
virtual FName GetAddressType ( ) const override ;
virtual FName GetDataType ( ) const override ;
virtual TUniquePtr < FTransmissionAddress > Clone ( ) const override ;
virtual FString ToString ( ) const override ;
2020-09-08 14:13:51 -04:00
2022-07-13 17:16:54 -04:00
const FName & GetChannelName ( ) const ;
uint64 GetInstanceID ( ) const ;
2021-10-12 21:21:22 -04:00
private :
2022-07-13 17:16:54 -04:00
virtual uint32 GetHash ( ) const override ;
virtual bool IsEqual ( const FTransmissionAddress & InOther ) const override ;
2021-10-12 21:21:22 -04:00
FName ChannelName ;
FName DataType ;
// For instance-specific addresses, this uint64 is the instance of this metasound.
uint64 InstanceID = INDEX_NONE ;
2020-09-08 14:13:51 -04:00
} ;
2022-07-13 17:16:54 -04:00
FORCEINLINE uint32 GetTypeHash ( const Metasound : : FTransmissionAddress & InAddress )
{
return InAddress . GetHash ( ) ;
}
2020-09-08 14:13:51 -04:00
// Base class that defines shared state and utilities for senders, receivers, and the shared channel state.
class METASOUNDFRONTEND_API IDataTransmissionBase
{
public :
IDataTransmissionBase ( ) = delete ;
IDataTransmissionBase ( FName InDataType )
: DataType ( InDataType )
{
}
virtual ~ IDataTransmissionBase ( ) = default ;
template < typename TSenderImplementation >
bool CheckType ( ) const
{
FName DestinationTypeName = TSenderImplementation : : GetDataTypeName ( ) ;
return ensureAlwaysMsgf ( DataType = = DestinationTypeName , TEXT ( " Tried to downcast type %s to %s! " ) , * DataType . ToString ( ) , * DestinationTypeName . ToString ( ) ) ;
}
template < typename TSenderImplementation >
const TSenderImplementation & GetAs ( ) const
{
check ( CheckType < TSenderImplementation > ( ) ) ;
return static_cast < TSenderImplementation & > ( * this ) ;
}
template < typename TSenderImplementation >
TSenderImplementation & GetAs ( )
{
check ( CheckType < TSenderImplementation > ( ) ) ;
return static_cast < TSenderImplementation & > ( * this ) ;
}
FName GetDataType ( ) const
{
return DataType ;
}
protected :
// The data type for this sender.
FName DataType ;
} ;
class IDataChannel ;
// This is a handle to something that will retrieve a datatype.
// Intentionally opaque- to use, one will need to call IReceiver::GetAs<TReceiver<YourDataType>>().
class METASOUNDFRONTEND_API IReceiver : public IDataTransmissionBase
{
public :
2021-03-05 20:06:54 -04:00
IReceiver ( TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > InDataChannel , FName DataType )
2020-09-08 14:13:51 -04:00
: IDataTransmissionBase ( DataType )
, DataChannel ( InDataChannel )
{ }
virtual ~ IReceiver ( ) ;
protected :
2021-03-05 20:06:54 -04:00
TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > DataChannel ;
2020-09-08 14:13:51 -04:00
} ;
// This is a handle to something that will retrieve a datatype.
// Intentionally opaque- to use, one will need to call ISender::GetAs<TSender<YourDataType>>().
class METASOUNDFRONTEND_API ISender : public IDataTransmissionBase
{
public :
2021-03-05 20:06:54 -04:00
ISender ( TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > InDataChannel , FName DataType )
2020-09-08 14:13:51 -04:00
: IDataTransmissionBase ( DataType )
, DataChannel ( InDataChannel )
{ }
virtual ~ ISender ( ) ;
2021-03-23 17:55:31 -04:00
virtual int64 GetPayloadID ( ) const = 0 ;
2021-03-05 20:06:54 -04:00
// Constructs the value with a literal and pushes to data channel.
virtual bool PushLiteral ( const FLiteral & InLiteral ) = 0 ;
2020-09-08 14:13:51 -04:00
protected :
2021-03-05 20:06:54 -04:00
TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > DataChannel ;
2020-09-08 14:13:51 -04:00
} ;
struct FSenderInitParams
{
FOperatorSettings OperatorSettings ;
float DelayTimeInSeconds ;
} ;
struct FReceiverInitParams
{
FOperatorSettings OperatorSettings ;
} ;
// This contains an intermediary buffer for use between the send and receive nodes.
// Typically only used by ISender and IReceiver implementations.
2021-03-05 20:06:54 -04:00
class METASOUNDFRONTEND_API IDataChannel : public IDataTransmissionBase , public TSharedFromThis < IDataChannel , ESPMode : : ThreadSafe >
2020-09-08 14:13:51 -04:00
{
public :
virtual ~ IDataChannel ( ) = default ;
IDataChannel ( FName DataType )
: IDataTransmissionBase ( DataType )
{ }
TUniquePtr < IReceiver > NewReceiver ( const FReceiverInitParams & InitParams )
{
NumAliveReceivers . Increment ( ) ;
return ConstructNewReceiverImplementation ( InitParams ) ;
}
TUniquePtr < ISender > NewSender ( const FSenderInitParams & InitParams )
{
NumAliveSenders . Increment ( ) ;
return ConstructNewSenderImplementation ( InitParams ) ;
}
uint32 GetNumActiveReceivers ( ) const
{
return NumAliveReceivers . GetValue ( ) ;
}
uint32 GetNumActiveSenders ( ) const
{
return NumAliveSenders . GetValue ( ) ;
}
2021-07-21 15:46:42 -04:00
virtual int64 GetPayloadID ( ) const { return INDEX_NONE ; }
virtual int64 CreateNewPayloadID ( ) = 0 ;
2020-09-08 14:13:51 -04:00
virtual bool PushOpaque ( ISender & InSender ) { return true ; } ;
virtual void PopOpaque ( IReceiver & InReceiver ) { } ;
virtual bool IsEmpty ( ) const { return true ; } ;
virtual FName GetDataType ( ) { return FName ( ) ; } ;
2021-01-13 10:48:59 -04:00
virtual bool PushLiteral ( const FLiteral & InParam ) { return false ; }
2020-09-08 14:13:51 -04:00
protected :
virtual TUniquePtr < IReceiver > ConstructNewReceiverImplementation ( const FReceiverInitParams & InitParams ) { return nullptr ; } ;
virtual TUniquePtr < ISender > ConstructNewSenderImplementation ( const FSenderInitParams & InitParams ) { return nullptr ; } ;
private :
void OnSenderDestroyed ( )
{
check ( NumAliveSenders . GetValue ( ) > 0 ) ;
NumAliveSenders . Decrement ( ) ;
}
void OnReceiverDestroyed ( )
{
check ( NumAliveReceivers . GetValue ( ) > 0 ) ;
NumAliveReceivers . Decrement ( ) ;
}
friend class ISender ;
friend class IReceiver ;
FThreadSafeCounter NumAliveReceivers ;
FThreadSafeCounter NumAliveSenders ;
} ;
// Generic templates:
template < typename TDataType >
class TNonOperationalSender : public ISender
{
public :
bool Push ( const TDataType & InValue ) { return true ; }
} ;
template < typename TDataType >
class TNonOperationalReceiver : public IReceiver
{
public :
bool Pop ( TDataType & OutValue ) { return true ; }
} ;
template < typename TDataType >
class TNonOperationalDataChannel : public IDataChannel
{
public :
TNonOperationalDataChannel ( const FOperatorSettings & InOperatorSettings )
: IDataChannel ( FName ( ) )
2021-07-21 15:46:42 -04:00
, PayloadIDCounter ( 0 )
2020-09-08 14:13:51 -04:00
{ }
virtual bool PushOpaque ( ISender & InSender ) override
{
return true ;
}
virtual void PopOpaque ( IReceiver & InReceiver ) override
{
}
2021-07-21 15:46:42 -04:00
virtual int64 CreateNewPayloadID ( ) override
{
// Atomic return and post increment.
return PayloadIDCounter + + ;
}
2020-09-08 14:13:51 -04:00
virtual bool IsEmpty ( ) const override
{
return true ;
}
virtual FName GetDataType ( ) override
{
return GetDataTypeName ( ) ;
}
static FName GetDataTypeName ( )
{
2021-03-05 20:06:54 -04:00
return GetMetasoundDataTypeName < TDataType > ( ) ;
2020-09-08 14:13:51 -04:00
}
protected :
virtual TUniquePtr < IReceiver > ConstructNewReceiverImplementation ( const FReceiverInitParams & InitParams ) override
{
return TUniquePtr < IReceiver > ( ) ;
}
virtual TUniquePtr < ISender > ConstructNewSenderImplementation ( const FSenderInitParams & InitParams ) override
{
return TUniquePtr < ISender > ( ) ;
}
2021-07-21 15:46:42 -04:00
private :
std : : atomic < int64 > PayloadIDCounter ;
2020-09-08 14:13:51 -04:00
} ;
// Specializations for trivially copyable types:
template < typename TDataType >
class TSender : public ISender
{
static_assert ( std : : is_copy_constructible < TDataType > : : value , " The generic TDataChannel requires the DataType it is specialized with to be copy assignable. " ) ;
// This can be changed to change when we reallocate the internal buffer for this sender.
static constexpr float BufferResizeThreshold = 2.0f ;
2021-08-30 14:08:45 -04:00
bool bMessageDataTypeError = true ;
2020-09-08 14:13:51 -04:00
public :
bool Push ( const TDataType & InElement )
{
SenderBuffer . Push ( InElement ) ;
if ( SenderBuffer . Num ( ) > = NumElementsToDelayBy )
{
return PushToDataChannel ( ) ;
}
else
{
return true ;
}
}
2021-03-05 20:06:54 -04:00
bool PushLiteral ( const FLiteral & InLiteral ) override
{
if ( ! TLiteralTraits < TDataType > : : IsParsable ( InLiteral ) )
{
2021-08-30 14:08:45 -04:00
if ( bMessageDataTypeError )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to send data. Data type [TypeName:%s] cannot be parsed from literal [Literal:%s]. " ) , * GetMetasoundDataTypeString < TDataType > ( ) , * LexToString ( InLiteral ) ) ;
bMessageDataTypeError = false ;
}
2021-03-05 20:06:54 -04:00
return false ;
}
else
{
2021-04-06 01:41:29 -04:00
return TSender < TDataType > : : Push ( TDataTypeLiteralFactory < TDataType > : : CreateExplicitArgs ( Params . OperatorSettings , InLiteral ) ) ;
2021-03-05 20:06:54 -04:00
}
}
2020-09-08 14:13:51 -04:00
// Resets the delay for this specific sender. if this goes beyond the threshold set by BufferResizeThreshold, we reallocate.
bool SetDelay ( float InSeconds )
{
Params . DelayTimeInSeconds = InSeconds ;
2021-03-05 20:06:54 -04:00
SenderBuffer . SetCapacity ( 2 ) ;
2021-01-22 03:05:22 -04:00
return true ;
2020-09-08 14:13:51 -04:00
}
static FName GetDataTypeName ( )
{
2021-03-05 20:06:54 -04:00
return GetMetasoundDataTypeName < TDataType > ( ) ;
2020-09-08 14:13:51 -04:00
}
2021-03-05 20:06:54 -04:00
TSender ( const FSenderInitParams & InitParams , TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > InDataChannel )
2020-09-08 14:13:51 -04:00
: ISender ( InDataChannel , GetDataTypeName ( ) )
, Params ( InitParams )
{
2021-01-22 03:05:22 -04:00
SetDelay ( InitParams . DelayTimeInSeconds ) ;
2020-09-08 14:13:51 -04:00
}
2021-03-23 17:55:31 -04:00
int64 GetPayloadID ( ) const override
{
return PayloadID ;
}
2020-09-08 14:13:51 -04:00
TDataType RetrievePayload ( )
{
check ( Payload . IsValid ( ) ) ;
return MoveTempIfPossible ( * Payload ) ;
}
// Push from the SenderBuffer to the data channel.
bool PushToDataChannel ( )
{
2021-07-21 15:46:42 -04:00
PayloadID = DataChannel - > CreateNewPayloadID ( ) ;
2020-09-08 14:13:51 -04:00
if ( ! Payload . IsValid ( ) )
{
2021-03-23 17:55:31 -04:00
Payload = MakeUnique < TDataType > ( SenderBuffer . Pop ( ) ) ;
2020-09-08 14:13:51 -04:00
}
else
{
* Payload = SenderBuffer . Pop ( ) ;
}
return DataChannel - > PushOpaque ( * this ) ;
}
private :
// This buffer acts as a delay line for this sender specifically.
Audio : : TCircularAudioBuffer < TDataType > SenderBuffer ;
2021-03-23 17:55:31 -04:00
int64 PayloadID = 0 ;
2020-09-08 14:13:51 -04:00
// lazily initialized holder for payload, allocated on first call to Push.
// Placed on the heap so that we don't have to assume we know how to construct TDataType.
TUniquePtr < TDataType > Payload ;
FSenderInitParams Params ;
// The amount of pop operations before elements before this sender pushed appear.
2021-03-10 18:29:21 -04:00
uint32 NumElementsToDelayBy = 0 ;
2020-09-08 14:13:51 -04:00
} ;
template < typename TDataType >
class TReceiver : public IReceiver
{
static_assert ( std : : is_copy_constructible < TDataType > : : value , " The generic TDataChannel requires the DataType it is specialized with to be copy constructible. " ) ;
public :
bool CanPop ( ) const
{
2021-04-06 01:41:29 -04:00
if ( DataChannel - > GetPayloadID ( ) = = LastPayloadID )
{
return false ;
}
if ( DataChannel - > IsEmpty ( ) )
{
return false ;
}
return true ;
2020-09-08 14:13:51 -04:00
}
// Pop the latest value from the data channel.
bool Pop ( TDataType & OutValue )
{
DataChannel - > PopOpaque ( * this ) ;
check ( Payload . IsValid ( ) ) ;
OutValue = * Payload ;
return true ;
}
static FName GetDataTypeName ( )
{
2021-03-05 20:06:54 -04:00
return GetMetasoundDataTypeName < TDataType > ( ) ;
2020-09-08 14:13:51 -04:00
}
2021-03-05 20:06:54 -04:00
TReceiver ( const FReceiverInitParams & InitParams , TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > InDataChannel )
2020-09-08 14:13:51 -04:00
: IReceiver ( InDataChannel , GetDataTypeName ( ) )
, OperatorSettings ( InitParams . OperatorSettings )
{
}
2021-03-23 17:55:31 -04:00
void PushPayload ( int64 InPayloadID , const TDataType & InDataPayload )
2020-09-08 14:13:51 -04:00
{
2021-03-23 17:55:31 -04:00
// Attempting to send the same payload again, so ignore.
if ( InPayloadID = = LastPayloadID )
{
return ;
}
LastPayloadID = InPayloadID ;
2020-09-08 14:13:51 -04:00
if ( ! Payload . IsValid ( ) )
{
2021-03-23 17:55:31 -04:00
Payload = MakeUnique < TDataType > ( InDataPayload ) ;
2020-09-08 14:13:51 -04:00
}
else
{
* Payload = InDataPayload ;
}
}
private :
2021-03-23 17:55:31 -04:00
int64 LastPayloadID = INDEX_NONE ;
2020-09-08 14:13:51 -04:00
TUniquePtr < TDataType > Payload ;
FOperatorSettings OperatorSettings ;
} ;
// Generic templated implementation of IDataChannel that can use for any copyable type.
template < typename TDataType >
class TCopyableDataChannel : public IDataChannel
{
static_assert ( std : : is_copy_constructible < TDataType > : : value , " The generic TDataChannel requires the DataType it is specialized with to be copy constructible. " ) ;
public :
TCopyableDataChannel ( const FOperatorSettings & InOperatorSettings )
: IDataChannel ( GetDataTypeName ( ) )
, OperatorSettings ( InOperatorSettings )
2021-07-21 15:46:42 -04:00
, PayloadIDCounter ( 0 )
2020-09-08 14:13:51 -04:00
{ }
2021-03-23 17:55:31 -04:00
virtual int64 GetPayloadID ( ) const override
{
return PayloadID ;
}
2021-07-21 15:46:42 -04:00
virtual int64 CreateNewPayloadID ( ) override
{
// Atomic return and post increment.
return PayloadIDCounter + + ;
}
2020-09-08 14:13:51 -04:00
virtual bool PushOpaque ( ISender & InSender ) override
{
TSender < TDataType > & CastSender = InSender . GetAs < TSender < TDataType > > ( ) ;
{
2021-03-23 17:55:31 -04:00
FScopeLock ScopeLock ( & AtomicDataLock ) ;
PayloadID = InSender . GetPayloadID ( ) ;
if ( ! AtomicData . IsValid ( ) )
{
AtomicData = MakeUnique < TDataType > ( CastSender . RetrievePayload ( ) ) ;
}
else
{
* AtomicData = CastSender . RetrievePayload ( ) ;
}
2020-09-08 14:13:51 -04:00
}
return true ;
}
virtual void PopOpaque ( IReceiver & InReceiver ) override
{
TReceiver < TDataType > & CastReceiver = InReceiver . GetAs < TReceiver < TDataType > > ( ) ;
FScopeLock ScopeLock ( & AtomicDataLock ) ;
if ( AtomicData . IsValid ( ) )
{
2021-03-23 17:55:31 -04:00
CastReceiver . PushPayload ( PayloadID , * AtomicData ) ;
2020-09-08 14:13:51 -04:00
}
}
virtual bool IsEmpty ( ) const override
{
return ! AtomicData . IsValid ( ) ;
}
static FName GetDataTypeName ( )
{
2021-03-05 20:06:54 -04:00
return GetMetasoundDataTypeName < TDataType > ( ) ;
2020-09-08 14:13:51 -04:00
}
virtual FName GetDataType ( ) override
{
return GetDataTypeName ( ) ;
}
2021-01-13 10:48:59 -04:00
virtual bool PushLiteral ( const FLiteral & InParam )
2020-09-08 14:13:51 -04:00
{
2020-11-04 14:26:37 -04:00
if ( TLiteralTraits < TDataType > : : IsParsable ( InParam ) )
2020-09-08 14:13:51 -04:00
{
2020-11-04 14:26:37 -04:00
TDataType DataToPush = TDataTypeLiteralFactory < TDataType > : : CreateExplicitArgs ( OperatorSettings , InParam ) ;
2020-09-08 14:13:51 -04:00
FScopeLock ScopeLock ( & AtomicDataLock ) ;
if ( ! AtomicData . IsValid ( ) )
{
2021-03-23 17:55:31 -04:00
AtomicData = MakeUnique < TDataType > ( DataToPush ) ;
2020-09-08 14:13:51 -04:00
}
else
{
* AtomicData = DataToPush ;
}
return true ;
}
else
{
return false ;
}
}
protected :
virtual TUniquePtr < IReceiver > ConstructNewReceiverImplementation ( const FReceiverInitParams & InitParams ) override
{
return TUniquePtr < IReceiver > ( new TReceiver < TDataType > ( InitParams , this - > AsShared ( ) ) ) ;
}
virtual TUniquePtr < ISender > ConstructNewSenderImplementation ( const FSenderInitParams & InitParams ) override
{
return TUniquePtr < ISender > ( new TSender < TDataType > ( InitParams , this - > AsShared ( ) ) ) ;
}
private :
// NOTE- In the future, this could be changed to use a TCircualrAudioBuffer or a TQueue for lockless operation.
// The primary challenge with this is handling multiple senders and receivers.
// In order to support multiple senders and receivers at scale, we'd need a good implementation of a bounded MPMC queue for arbitrary datatypes.
TUniquePtr < TDataType > AtomicData ;
FCriticalSection AtomicDataLock ;
2021-07-21 15:46:42 -04:00
int64 PayloadID = INDEX_NONE ;
2021-03-23 17:55:31 -04:00
2020-09-08 14:13:51 -04:00
FOperatorSettings OperatorSettings ;
2021-07-21 15:46:42 -04:00
std : : atomic < int64 > PayloadIDCounter ;
2020-09-08 14:13:51 -04:00
} ;
// AUDIO SPECIALIZATIONS:
template < typename TDataType >
class TAudioSender : public ISender
{
static constexpr float BufferResizeThreshold = 2.0f ;
static const int32 MaxChannels = 8 ;
public :
bool Push ( const TDataType & InElement )
{
const int32 NumChannelsToPush = InElement . GetNumChannels ( ) ;
check ( NumChannelsToPush < = MaxChannels ) ;
const TArrayView < const FAudioBufferReadRef > InputBuffers = InElement . GetBuffers ( ) ;
for ( int32 ChannelIndex = 0 ; ChannelIndex < NumChannelsToPush ; ChannelIndex + + )
{
const FAudioBuffer & ChannelBuffer = * InputBuffers [ ChannelIndex ] ;
DelayLines [ ChannelIndex ] . Push ( ChannelBuffer . GetData ( ) , ChannelBuffer . Num ( ) ) ;
if ( DelayLines [ ChannelIndex ] . Num ( ) > DelayTimeInFrames )
{
2021-05-04 16:05:46 -04:00
Audio : : FAlignedFloatBuffer & IntermediateBuffer = IntermediaryBuffers [ ChannelIndex ] ;
2020-09-08 14:13:51 -04:00
DelayLines [ ChannelIndex ] . Pop ( IntermediateBuffer . GetData ( ) , IntermediateBuffer . Num ( ) ) ;
DataChannelInputs [ ChannelIndex ] . PushAudio ( IntermediateBuffer . GetData ( ) , IntermediateBuffer . Num ( ) ) ;
}
}
return true ;
}
2021-03-23 17:55:31 -04:00
int64 GetPayloadID ( ) const override
{
2021-07-21 15:46:42 -04:00
return INDEX_NONE ;
2021-03-23 17:55:31 -04:00
}
2021-03-05 20:06:54 -04:00
bool PushLiteral ( const FLiteral & InLiteral ) override
{
ensureMsgf ( false , TEXT ( " Cannot push literal to audio format " ) ) ;
return false ;
}
2020-09-08 14:13:51 -04:00
// Resets the delay for this sender.
bool SetDelay ( float InSeconds )
{
Params . DelayTimeInSeconds = InSeconds ;
DelayTimeInFrames = FMath : : Min < int32 > ( Params . DelayTimeInSeconds * Params . OperatorSettings . GetSampleRate ( ) , Params . OperatorSettings . GetNumFramesPerBlock ( ) ) ;
if ( DelayTimeInFrames > = DelayLines [ 0 ] . Num ( ) )
{
int32 NumSamplesToBuffer = DelayTimeInFrames * BufferResizeThreshold ;
DelayLines . Reset ( ) ;
IntermediaryBuffers . Reset ( ) ;
// For now, all senders/receivers/data channels will just allocate 8 delay lines, but this can be changed in the future.
for ( int32 Index = 0 ; Index < MaxChannels ; Index + + )
{
DelayLines . Emplace ( NumSamplesToBuffer ) ;
2021-05-04 16:05:46 -04:00
Audio : : FAlignedFloatBuffer BufferForChannel ;
2020-09-08 14:13:51 -04:00
BufferForChannel . AddZeroed ( Params . OperatorSettings . GetNumFramesPerBlock ( ) ) ;
IntermediaryBuffers . Add ( MoveTemp ( BufferForChannel ) ) ;
}
}
return true ;
}
static FName GetDataTypeName ( )
{
2021-03-05 20:06:54 -04:00
return GetMetasoundDataTypeName < TDataType > ( ) ;
2020-09-08 14:13:51 -04:00
}
2021-03-05 20:06:54 -04:00
TAudioSender ( const FSenderInitParams & InitParams , TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > InDataChannel , TArray < Audio : : FPatchInput > & & Inputs )
2020-09-08 14:13:51 -04:00
: ISender ( InDataChannel , GetDataTypeName ( ) )
, DataChannelInputs ( MoveTemp ( Inputs ) )
, Params ( InitParams )
{
SetDelay ( InitParams . DelayTimeInSeconds ) ;
}
private :
// This buffer acts as a delay line for this sender specifically.
TArray < Audio : : TCircularAudioBuffer < float > > DelayLines ;
uint32 DelayTimeInFrames ;
TArray < Audio : : FPatchInput > DataChannelInputs ;
2021-05-04 16:05:46 -04:00
TArray < Audio : : FAlignedFloatBuffer > IntermediaryBuffers ;
2020-09-08 14:13:51 -04:00
FSenderInitParams Params ;
} ;
template < typename TDataType >
class TAudioReceiver : public IReceiver
{
static constexpr float BufferResizeThreshold = 2.0f ;
static const int32 MaxChannels = 8 ;
public :
bool CanPop ( ) const
{
// Audio receivers can and should always pop audio,
// because we zero out audio when a datachannel underruns.
return true ;
}
bool Pop ( TDataType & OutElement )
{
const int32 NumChannelsToPop = OutElement . GetNumChannels ( ) ;
check ( NumChannelsToPop < = MaxChannels ) ;
DataChannel - > PopOpaque ( * this ) ;
TArrayView < const FAudioBufferWriteRef > OutputBuffers = OutElement . GetBuffers ( ) ;
for ( int32 ChannelIndex = 0 ; ChannelIndex < NumChannelsToPop ; ChannelIndex + + )
{
FAudioBuffer & OutBuffer = * OutputBuffers [ ChannelIndex ] ;
DataChannelOutputs [ ChannelIndex ] - > PopAudio ( OutBuffer . GetData ( ) , OutBuffer . Num ( ) , false ) ;
}
return true ;
}
static FName GetDataTypeName ( )
{
2021-03-05 20:06:54 -04:00
return GetMetasoundDataTypeName < TDataType > ( ) ;
2020-09-08 14:13:51 -04:00
}
2021-03-05 20:06:54 -04:00
TAudioReceiver ( const FReceiverInitParams & InitParams , TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > InDataChannel , TArray < Audio : : FPatchOutputStrongPtr > & & Outputs )
2020-09-08 14:13:51 -04:00
: IReceiver ( InDataChannel , GetDataTypeName ( ) )
, DataChannelOutputs ( MoveTemp ( Outputs ) )
, Params ( InitParams )
{
}
private :
TArray < Audio : : FPatchOutputStrongPtr > DataChannelOutputs ;
FReceiverInitParams Params ;
} ;
template < typename TDataType >
class TAudioDataChannel : public IDataChannel
{
private :
static const int32 MaxChannels = 8 ;
public :
TAudioDataChannel ( const FOperatorSettings & InOperatorSettings )
: IDataChannel ( GetDataTypeName ( ) )
2021-07-21 15:46:42 -04:00
, PayloadIDCounter ( 0 )
2020-09-08 14:13:51 -04:00
{
AudioBuses . AddDefaulted ( MaxChannels ) ;
}
virtual bool PushOpaque ( ISender & InSender ) override
{
return true ;
}
virtual void PopOpaque ( IReceiver & InReceiver ) override
{
for ( Audio : : FPatchMixerSplitter & Bus : AudioBuses )
{
Bus . ProcessAudio ( ) ;
}
}
2021-07-21 15:46:42 -04:00
virtual int64 CreateNewPayloadID ( ) override
{
// Atomic return and post increment.
return PayloadIDCounter + + ;
}
2020-09-08 14:13:51 -04:00
virtual bool IsEmpty ( ) const override
{
return false ;
}
static FName GetDataTypeName ( )
{
2021-03-05 20:06:54 -04:00
return GetMetasoundDataTypeName < TDataType > ( ) ;
2020-09-08 14:13:51 -04:00
}
virtual FName GetDataType ( ) override
{
return GetDataTypeName ( ) ;
}
protected :
virtual TUniquePtr < IReceiver > ConstructNewReceiverImplementation ( const FReceiverInitParams & InitParams ) override
{
TArray < Audio : : FPatchOutputStrongPtr > Outputs ;
for ( Audio : : FPatchMixerSplitter & Bus : AudioBuses )
{
Outputs . Add ( Bus . AddNewOutput ( 8096 , 1.0f ) ) ;
}
return TUniquePtr < IReceiver > ( new TAudioReceiver < TDataType > ( InitParams , this - > AsShared ( ) , MoveTemp ( Outputs ) ) ) ;
}
virtual TUniquePtr < ISender > ConstructNewSenderImplementation ( const FSenderInitParams & InitParams ) override
{
TArray < Audio : : FPatchInput > Inputs ;
for ( Audio : : FPatchMixerSplitter & Bus : AudioBuses )
{
Inputs . Add ( Bus . AddNewInput ( 8096 , 1.0f ) ) ;
}
return TUniquePtr < ISender > ( new TAudioSender < TDataType > ( InitParams , this - > AsShared ( ) , MoveTemp ( Inputs ) ) ) ;
}
private :
TArray < Audio : : FPatchMixerSplitter > AudioBuses ;
2021-07-21 15:46:42 -04:00
std : : atomic < int64 > PayloadIDCounter ;
2020-09-08 14:13:51 -04:00
} ;
// Coalesce both our standard copying Sender/Receivers and our audio-specific sender/receiver implementations into TSenderPtr and TReceiverPtr:
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename USenderType = typename std : : conditional < TIsDerivedFrom < TDataType , IAudioDataType > : : Value , TAudioSender < TDataType > , TSender < TDataType > > : : type >
2020-09-08 14:13:51 -04:00
using TSenderPtr = TUniquePtr < USenderType > ;
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename UReceiverType = typename std : : conditional < TIsDerivedFrom < TDataType , IAudioDataType > : : Value , TAudioReceiver < TDataType > , TReceiver < TDataType > > : : type >
2020-09-08 14:13:51 -04:00
using TReceiverPtr = TUniquePtr < UReceiverType > ;
// SFINAE for creating the correct data channel type for the given datatype:
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < std : : is_copy_constructible < TDataType > : : value & & ! TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2021-03-05 20:06:54 -04:00
TSharedRef < IDataChannel , ESPMode : : ThreadSafe > MakeDataChannel ( const FOperatorSettings & InSettings )
2020-09-08 14:13:51 -04:00
{
return MakeShareable ( new TCopyableDataChannel < TDataType > ( InSettings ) ) ;
}
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2021-03-05 20:06:54 -04:00
TSharedRef < IDataChannel , ESPMode : : ThreadSafe > MakeDataChannel ( const FOperatorSettings & InSettings )
2020-09-08 14:13:51 -04:00
{
return MakeShareable ( new TAudioDataChannel < TDataType > ( InSettings ) ) ;
}
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < ! std : : is_copy_constructible < TDataType > : : value & & ! TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2021-03-05 20:06:54 -04:00
TSharedRef < IDataChannel , ESPMode : : ThreadSafe > MakeDataChannel ( const FOperatorSettings & InSettings )
2020-09-08 14:13:51 -04:00
{
return MakeShareable ( new TNonOperationalDataChannel < TDataType > ( InSettings ) ) ;
}
// Utility function for properly downcasting to the correct type based on whether TDataType is an audio stream:
// For Audio Senders:
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2020-09-08 14:13:51 -04:00
TSenderPtr < TDataType > Downcast ( TUniquePtr < ISender > & & InPtr )
{
checkf ( InPtr - > CheckType < TAudioSender < TDataType > > ( ) , TEXT ( " Tried to downcast an ISender of type %s to a TSender of type %s! " ) , * ( InPtr - > GetDataType ( ) . ToString ( ) ) , * ( TAudioSender < TDataType > : : GetDataTypeName ( ) . ToString ( ) ) ) ;
return TSenderPtr < TDataType > ( static_cast < TAudioSender < TDataType > * > ( InPtr . Release ( ) ) ) ;
}
// For generic senders for copyable types:
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < std : : is_copy_constructible < TDataType > : : value & & ! TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2020-09-08 14:13:51 -04:00
TSenderPtr < TDataType > Downcast ( TUniquePtr < ISender > & & InPtr )
{
checkf ( InPtr - > CheckType < TSender < TDataType > > ( ) , TEXT ( " Tried to downcast an ISender of type %s to a TSender of type %s! " ) , * ( InPtr - > GetDataType ( ) . ToString ( ) ) , * ( TSender < TDataType > : : GetDataTypeName ( ) . ToString ( ) ) ) ;
return TSenderPtr < TDataType > ( static_cast < TSender < TDataType > * > ( InPtr . Release ( ) ) ) ;
}
// For invalid types (non-copyable AND not an audio type):
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < ! std : : is_copy_constructible < TDataType > : : value & & ! TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2020-09-08 14:13:51 -04:00
TSenderPtr < TDataType > Downcast ( TUniquePtr < ISender > & & InPtr )
{
return nullptr ;
}
// For audio receivers:
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2020-09-08 14:13:51 -04:00
TReceiverPtr < TDataType > Downcast ( TUniquePtr < IReceiver > & & InPtr )
{
checkf ( InPtr - > CheckType < TAudioReceiver < TDataType > > ( ) , TEXT ( " Tried to downcast an IReceiver of type %s to a TSender of type %s! " ) , * ( InPtr - > GetDataType ( ) . ToString ( ) ) , * ( TAudioReceiver < TDataType > : : GetDataTypeName ( ) . ToString ( ) ) ) ;
return TReceiverPtr < TDataType > ( static_cast < TAudioReceiver < TDataType > * > ( InPtr . Release ( ) ) ) ;
}
// For generic receivers for copyable types:
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < std : : is_copy_constructible < TDataType > : : value & & ! TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2020-09-08 14:13:51 -04:00
TReceiverPtr < TDataType > Downcast ( TUniquePtr < IReceiver > & & InPtr )
{
checkf ( InPtr - > CheckType < TReceiver < TDataType > > ( ) , TEXT ( " Tried to downcast an IReceiver of type %s to a TSender of type %s! " ) , * ( InPtr - > GetDataType ( ) . ToString ( ) ) , * ( TReceiver < TDataType > : : GetDataTypeName ( ) . ToString ( ) ) ) ;
return TReceiverPtr < TDataType > ( static_cast < TReceiver < TDataType > * > ( InPtr . Release ( ) ) ) ;
}
// For invalid types (non-copyable AND not an audio type):
2020-11-04 14:26:37 -04:00
template < typename TDataType , typename TEnableIf < ! std : : is_copy_constructible < TDataType > : : value & & ! TIsDerivedFrom < TDataType , IAudioDataType > : : Value , bool > : : Type = true >
2020-09-08 14:13:51 -04:00
TReceiverPtr < TDataType > Downcast ( TUniquePtr < IReceiver > & & InPtr )
{
return nullptr ;
}
// Basic router that takes an FName address,
class METASOUNDFRONTEND_API FAddressRouter
{
2021-03-12 00:09:21 -04:00
2020-09-08 14:13:51 -04:00
public :
2022-07-13 17:16:54 -04:00
TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > FindDataChannel ( const FTransmissionAddress & InAddress ) ;
TSharedPtr < IDataChannel , ESPMode : : ThreadSafe > GetDataChannel ( const FTransmissionAddress & InAddress , const FOperatorSettings & InOperatorSettings ) ;
2021-03-05 20:06:54 -04:00
2022-07-13 17:16:54 -04:00
TUniquePtr < ISender > RegisterNewSender ( const FTransmissionAddress & InAddress , const FSenderInitParams & InitParams ) ;
TUniquePtr < IReceiver > RegisterNewReceiver ( const FTransmissionAddress & InAddress , const FReceiverInitParams & InitParams ) ;
2021-03-05 20:06:54 -04:00
2020-09-08 14:13:51 -04:00
template < typename TDataType >
2022-07-13 17:16:54 -04:00
TReceiverPtr < TDataType > RegisterNewReceiver ( const FTransmissionAddress & InAddress , const FReceiverInitParams & InitParams )
2020-09-08 14:13:51 -04:00
{
2021-03-05 20:06:54 -04:00
TReceiverPtr < TDataType > Receiver ;
2020-09-08 14:13:51 -04:00
2022-07-13 17:16:54 -04:00
TUniquePtr < IReceiver > ReceiverBase = RegisterNewReceiver ( InAddress , InitParams ) ;
if ( ReceiverBase . IsValid ( ) )
2020-09-08 14:13:51 -04:00
{
2022-07-13 17:16:54 -04:00
Receiver = Downcast < TDataType > ( MoveTemp ( ReceiverBase ) ) ;
2020-09-08 14:13:51 -04:00
}
2021-03-05 20:06:54 -04:00
2022-07-13 17:16:54 -04:00
return Receiver ;
2020-09-08 14:13:51 -04:00
}
template < typename TDataType >
2022-07-13 17:16:54 -04:00
TSenderPtr < TDataType > RegisterNewSender ( const FTransmissionAddress & InAddress , const FSenderInitParams & InitParams )
2020-09-08 14:13:51 -04:00
{
2021-03-05 20:06:54 -04:00
TSenderPtr < TDataType > Sender ;
2022-07-13 17:16:54 -04:00
TUniquePtr < ISender > SenderBase = RegisterNewSender ( InAddress , InitParams ) ;
2020-09-08 14:13:51 -04:00
2022-07-13 17:16:54 -04:00
if ( SenderBase . IsValid ( ) )
2020-09-08 14:13:51 -04:00
{
2022-07-13 17:16:54 -04:00
Sender = Downcast < TDataType > ( MoveTemp ( SenderBase ) ) ;
2020-09-08 14:13:51 -04:00
}
2022-07-13 17:16:54 -04:00
return Sender ;
2020-09-08 14:13:51 -04:00
}
2022-07-13 17:16:54 -04:00
UE_DEPRECATED ( 5.1 , " Pushing literals from the Metasound::FAddressRouter will no longer be supported in future released. " )
bool PushLiteral ( const FName & InDataTypeName , const FName & InChannelName , const FLiteral & InParam ) ;
2021-10-12 21:21:22 -04:00
2022-07-13 17:16:54 -04:00
bool UnregisterDataChannel ( const FTransmissionAddress & InAddress ) ;
bool UnregisterDataChannelIfUnconnected ( const FTransmissionAddress & InAddress ) ;
2020-09-08 14:13:51 -04:00
2022-07-13 17:16:54 -04:00
FAddressRouter ( const FAddressRouter & Other ) ;
FAddressRouter ( ) = default ;
2020-09-08 14:13:51 -04:00
private :
2021-03-12 00:09:21 -04:00
2022-07-13 17:16:54 -04:00
// Wrapper class for having an FTransmissionAddress work in a TMap<>
// This implements the copy constructor and copy assignment operator
// by calling the virtual Clone() method.
class FTransmissionAddressKey : public FTransmissionAddress
{
public :
FTransmissionAddressKey ( const FTransmissionAddress & InCopy ) ;
FTransmissionAddressKey ( const FTransmissionAddressKey & InCopy ) ;
FTransmissionAddressKey ( TUniquePtr < FTransmissionAddress > & & InImpl ) ;
virtual ~ FTransmissionAddressKey ( ) = default ;
FTransmissionAddressKey & operator = ( const FTransmissionAddress & InOther ) ;
virtual FName GetAddressType ( ) const override ;
virtual FName GetDataType ( ) const override ;
virtual TUniquePtr < FTransmissionAddress > Clone ( ) const override ;
virtual FString ToString ( ) const override ;
private :
virtual uint32 GetHash ( ) const override ;
virtual bool IsEqual ( const FTransmissionAddress & InOther ) const override ;
TUniquePtr < FTransmissionAddress > PImpl ;
} ;
TMap < FTransmissionAddressKey , TSharedRef < IDataChannel , ESPMode : : ThreadSafe > > DataChannelMap ;
2020-09-08 14:13:51 -04:00
FCriticalSection DataChannelMapMutationLock ;
} ;
// Main entry point for all sender/receiver registration.
class METASOUNDFRONTEND_API FDataTransmissionCenter
{
public :
// Returns the universal router.
static FDataTransmissionCenter & Get ( ) ;
2021-03-05 20:06:54 -04:00
// Creates a new object to push data to an address.
// Returns a new sender, or nullptr if registration failed.
2022-07-13 17:16:54 -04:00
TUniquePtr < ISender > RegisterNewSender ( const FTransmissionAddress & InAddress , const FSenderInitParams & InitParams ) ;
2021-03-05 20:06:54 -04:00
2020-09-08 14:13:51 -04:00
// Creates a new object to push data to an address.
// Returns a new sender, or nullptr if registration failed.
template < typename TDataType >
2022-07-13 17:16:54 -04:00
TSenderPtr < TDataType > RegisterNewSender ( const FTransmissionAddress & InAddress , const FSenderInitParams & InitParams )
2020-09-08 14:13:51 -04:00
{
2021-03-05 20:06:54 -04:00
TSenderPtr < TDataType > Sender ;
2022-07-13 17:16:54 -04:00
TUniquePtr < ISender > SenderBase = RegisterNewSender ( InAddress , InitParams ) ;
2021-10-12 21:21:22 -04:00
2022-07-13 17:16:54 -04:00
if ( SenderBase . IsValid ( ) )
{
Sender = Downcast < TDataType > ( MoveTemp ( SenderBase ) ) ;
2020-09-08 14:13:51 -04:00
}
2021-03-05 20:06:54 -04:00
return Sender ;
2020-09-08 14:13:51 -04:00
}
2021-03-05 20:06:54 -04:00
// Registers a new object to poll data from an address.
// Returns a new receiver, or nullptr if registration failed.
2022-07-13 17:16:54 -04:00
TUniquePtr < IReceiver > RegisterNewReceiver ( const FTransmissionAddress & InAddress , const FReceiverInitParams & InitParams ) ;
2021-03-05 20:06:54 -04:00
2020-09-08 14:13:51 -04:00
// Registers a new object to poll data from an address.
// Returns a new receiver, or nullptr if registration failed.
template < typename TDataType >
2022-07-13 17:16:54 -04:00
TReceiverPtr < TDataType > RegisterNewReceiver ( const FTransmissionAddress & InAddress , const FReceiverInitParams & InitParams )
2020-09-08 14:13:51 -04:00
{
2021-03-05 20:06:54 -04:00
TReceiverPtr < TDataType > Receiver ;
2022-07-13 17:16:54 -04:00
TUniquePtr < IReceiver > ReceiverBase = RegisterNewReceiver ( InAddress , InitParams ) ;
2020-09-08 14:13:51 -04:00
2022-07-13 17:16:54 -04:00
if ( ReceiverBase . IsValid ( ) )
2020-09-08 14:13:51 -04:00
{
2022-07-13 17:16:54 -04:00
Receiver = Downcast < TDataType > ( MoveTemp ( ReceiverBase ) ) ;
2020-09-08 14:13:51 -04:00
}
2021-03-05 20:06:54 -04:00
return Receiver ;
2020-09-08 14:13:51 -04:00
}
2021-04-06 01:41:29 -04:00
// Unregisters DataChannel irrespective of number of receivers or senders still active.
2022-07-13 17:16:54 -04:00
bool UnregisterDataChannel ( const FTransmissionAddress & InAddress ) ;
2021-04-07 22:12:28 -04:00
// Unregister a data channel if there are no senders or receivers
2022-07-13 17:16:54 -04:00
bool UnregisterDataChannelIfUnconnected ( const FTransmissionAddress & InAddress ) ;
2021-04-06 01:41:29 -04:00
2020-09-08 14:13:51 -04:00
// Pushes a literal parameter to a specific data channel in the global router.
// returns false if the literal type isn't supported.
2022-07-13 17:16:54 -04:00
UE_DEPRECATED ( 5.1 , " Pushing literals from the Metasound::FDataTransmissionCenter will no longer be supported in future released. " )
2021-03-12 00:09:21 -04:00
bool PushLiteral ( FName DataTypeName , FName GlobalChannelName , const FLiteral & InParam ) ;
2020-09-08 14:13:51 -04:00
private :
// Single map of FNames to IDataChannels
FAddressRouter GlobalRouter ;
2021-03-05 20:06:54 -04:00
FDataTransmissionCenter ( ) = default ;
2020-09-08 14:13:51 -04:00
} ;
DECLARE_METASOUND_DATA_REFERENCE_TYPES ( FSendAddress , METASOUNDFRONTEND_API , FSendAddressTypeInfo , FSendAddressReadRef , FSendAddressWriteRef )
}
2022-07-13 17:16:54 -04:00