2021-03-30 15:49:01 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
2023-10-17 18:43:53 -04:00
# include "Audio/SimpleWaveWriter.h"
2021-03-31 02:29:57 -04:00
# include "HAL/FileManager.h"
2021-04-05 20:22:19 -04:00
# include "MetasoundBuildError.h"
# include "MetasoundEnumRegistrationMacro.h"
# include "MetasoundExecutableOperator.h"
2021-03-30 15:49:01 -04:00
# include "MetasoundNodeRegistrationMacro.h"
2022-03-17 13:14:50 -04:00
# include "MetasoundParamHelper.h"
2021-03-30 15:49:01 -04:00
# include "MetasoundPrimitives.h"
# include "MetasoundStandardNodesCategories.h"
2021-04-05 20:22:19 -04:00
# include "MetasoundStandardNodesNames.h"
2021-09-13 14:14:37 -04:00
# include "MetasoundVertex.h"
2021-03-31 02:29:57 -04:00
# include "Misc/Paths.h"
2021-03-30 15:49:01 -04:00
# include "Misc/ScopeLock.h"
2021-04-07 02:57:54 -04:00
# define LOCTEXT_NAMESPACE "MetasoundStandardNodes_WaveWriterNode"
2021-03-30 15:49:01 -04:00
2021-09-13 14:14:37 -04:00
2021-03-30 15:49:01 -04:00
namespace Metasound
2021-09-13 14:14:37 -04:00
{
2022-03-17 13:14:50 -04:00
namespace WaveWriterVertexNames
{
METASOUND_PARAM ( InEnabledPin , " Enabled " , " If this wave writer is enabled or not. " ) ;
METASOUND_PARAM ( InFilenamePrefixPin , " Filename Prefix " , " Filename Prefix of file you are writing. " ) ;
}
2021-03-30 15:49:01 -04:00
class FFileWriteError : public FBuildErrorBase
{
public :
static const FName ErrorType ;
virtual ~ FFileWriteError ( ) = default ;
FFileWriteError ( const FNode & InNode , const FString & InFilename )
2022-02-10 18:36:47 -05:00
# if WITH_EDITOR
: FBuildErrorBase ( ErrorType , METASOUND_LOCTEXT_FORMAT ( " MetasoundFileWriterErrorDescription " , " File Writer Error while trying to write '{0}' " , FText : : FromString ( InFilename ) ) )
# else
: FBuildErrorBase ( ErrorType , FText : : GetEmpty ( ) )
# endif // WITH_EDITOR
2021-03-30 15:49:01 -04:00
{
AddNode ( InNode ) ;
}
} ;
const FName FFileWriteError : : ErrorType = FName ( TEXT ( " MetasoundFileWriterError " ) ) ;
class FNumberedFileCache
{
public :
static const FString Seperator ;
FNumberedFileCache ( const FString & InRootPath , const FString & InExt )
: RootPath { InRootPath } , FileExtention { InExt }
{
CacheFilenames ( ) ;
}
2021-03-30 19:41:18 -04:00
FString GenerateNextNumberedFilename ( const FString & InPrefix )
2021-03-30 15:49:01 -04:00
{
FScopeLock Lock { & Cs } ;
2021-03-30 19:41:18 -04:00
uint32 & CurrentMax = FileIndexMap . FindOrAdd ( InPrefix . ToUpper ( ) ) ;
FString Filename { InPrefix } ;
2021-03-30 15:49:01 -04:00
Filename . Append ( * Seperator ) ;
Filename . AppendInt ( + + CurrentMax ) ;
Filename . Append ( * FileExtention ) ;
return RootPath / Filename ;
}
private :
// Slow directory search of the root path for filenames.
void CacheFilenames ( )
{
FScopeLock Lock { & Cs } ;
// Find all files, split filenames into prefix + number, saving max number we find.
TArray < FString > Files ;
IFileManager : : Get ( ) . FindFiles ( Files , * RootPath , * FileExtention ) ;
for ( const FString & i : Files )
{
FString Prefix , Postfix ;
if ( i . Split ( Seperator , & Prefix , & Postfix , ESearchCase : : IgnoreCase , ESearchDir : : FromEnd ) )
{
FString NumberString = FPaths : : GetBaseFilename ( Postfix ) ;
if ( FCString : : IsNumeric ( * NumberString ) )
{
int32 Number = FCString : : Atoi ( * NumberString ) ;
if ( Number > = 0 )
{
2021-03-30 19:41:18 -04:00
uint32 & CurrentMax = FileIndexMap . FindOrAdd ( * Prefix . ToUpper ( ) ) ;
2021-03-30 15:49:01 -04:00
if ( static_cast < uint32 > ( Number ) > CurrentMax )
{
CurrentMax = static_cast < uint32 > ( Number ) ;
}
}
}
}
}
}
FCriticalSection Cs ;
FString RootPath ;
FString FileExtention ;
2021-03-30 19:41:18 -04:00
TMap < FString , uint32 > FileIndexMap ;
2021-03-30 15:49:01 -04:00
} ;
const FString FNumberedFileCache : : Seperator { TEXT ( " _ " ) } ;
2021-11-29 20:45:14 -05:00
namespace WaveWriterOperatorPrivate
{
// Need to keep this outside the template so there's only 1
TSharedPtr < FNumberedFileCache > GetNameCache ( )
{
static const TCHAR * WaveExt = TEXT ( " .wav " ) ;
// Build cache of numbered files (do this once only).
static TSharedPtr < FNumberedFileCache > NumberedFileCacheSP = MakeShared < FNumberedFileCache > ( * FPaths : : AudioCaptureDir ( ) , WaveExt ) ;
return NumberedFileCacheSP ;
}
static const FString GetDefaultFileName ( )
{
static const FString DefaultFileName = TEXT ( " Output " ) ;
return DefaultFileName ;
}
}
template < int32 NumInputChannels >
class TWaveWriterOperator : public TExecutableOperator < TWaveWriterOperator < NumInputChannels > >
2021-03-30 15:49:01 -04:00
{
public :
2021-11-29 20:45:14 -05:00
// Theoretical limit of .WAV files.
static_assert ( NumInputChannels > 0 & & NumInputChannels < = 65535 , " Num Channels > 0 and <= 65535 " ) ;
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
TWaveWriterOperator ( const FOperatorSettings & InSettings , TArray < FAudioBufferReadRef > & & InAudioBuffers , FBoolReadRef & & InEnabled , const TSharedPtr < FNumberedFileCache , ESPMode : : ThreadSafe > & InNumberedFileCache , FStringReadRef & & InFilenamePrefix )
2021-11-29 20:45:14 -05:00
: AudioInputs { MoveTemp ( InAudioBuffers ) }
2021-03-30 15:49:01 -04:00
, Enabled { MoveTemp ( InEnabled ) }
2021-11-29 20:45:14 -05:00
, NumberedFileCacheSP { InNumberedFileCache }
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
, FileNamePrefix { MoveTemp ( InFilenamePrefix ) }
2021-11-29 20:45:14 -05:00
, SampleRate { InSettings . GetSampleRate ( ) }
{
check ( AudioInputs . Num ( ) = = NumInputChannels ) ;
// Make an interleave buffer if we need one.
if ( NumInputChannels > 1 )
{
InterleaveBuffer . SetNum ( InSettings . GetNumFramesPerBlock ( ) * NumInputChannels ) ;
AudioInputBufferPtrs . SetNum ( NumInputChannels ) ;
for ( int32 i = 0 ; i < NumInputChannels ; + + i )
{
AudioInputBufferPtrs [ i ] = AudioInputs [ i ] - > GetData ( ) ;
}
}
}
2021-03-30 15:49:01 -04:00
2023-05-22 13:28:27 -04:00
virtual void BindInputs ( FInputVertexInterfaceData & InOutVertexData ) override
2021-03-30 15:49:01 -04:00
{
2021-11-29 20:45:14 -05:00
for ( int32 i = 0 ; i < NumInputChannels ; + + i )
{
2023-05-22 13:28:27 -04:00
InOutVertexData . BindReadVertex ( GetAudioInputName ( i ) , AudioInputs [ i ] ) ;
2021-11-29 20:45:14 -05:00
}
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
using namespace WaveWriterVertexNames ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InEnabledPin ) , Enabled ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InFilenamePrefixPin ) , FileNamePrefix ) ;
2021-03-30 15:49:01 -04:00
}
2023-05-22 13:28:27 -04:00
virtual void BindOutputs ( FOutputVertexInterfaceData & ) override
2021-03-30 15:49:01 -04:00
{
2023-05-22 13:28:27 -04:00
}
virtual FDataReferenceCollection GetInputs ( ) const override
{
// This should never be called. Bind(...) is called instead. This method
// exists as a stop-gap until the API can be deprecated and removed.
checkNoEntry ( ) ;
return { } ;
}
virtual FDataReferenceCollection GetOutputs ( ) const override
{
// This should never be called. Bind(...) is called instead. This method
// exists as a stop-gap until the API can be deprecated and removed.
checkNoEntry ( ) ;
return { } ;
2021-03-30 15:49:01 -04:00
}
2021-11-29 20:45:14 -05:00
static const FVertexInterface & DeclareVertexInterface ( )
2021-03-30 15:49:01 -04:00
{
2021-11-29 20:45:14 -05:00
auto CreateDefaultInterface = [ ] ( ) - > FVertexInterface
{
using namespace WaveWriterOperatorPrivate ;
2022-03-17 13:14:50 -04:00
using namespace WaveWriterVertexNames ;
2021-11-29 20:45:14 -05:00
// inputs
FInputVertexInterface InputInterface (
2022-03-31 16:49:59 -04:00
TInputDataVertex < FString > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InFilenamePrefixPin ) , GetDefaultFileName ( ) ) ,
TInputDataVertex < bool > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InEnabledPin ) , true )
2021-11-29 20:45:14 -05:00
) ;
2022-03-17 13:14:50 -04:00
2021-11-29 20:45:14 -05:00
// For backwards compatibility with previous (mono) node, in the case of 1 channels, just provide the old interface.
for ( int32 InputIndex = 0 ; InputIndex < NumInputChannels ; + + InputIndex )
{
2022-10-20 16:38:58 -04:00
# if WITH_EDITOR
2022-03-17 13:14:50 -04:00
const FDataVertexMetadata AudioInputMetadata
{
GetAudioInputDescription ( InputIndex ) // description
, GetAudioInputDisplayName ( InputIndex ) // display name
} ;
2022-10-20 16:38:58 -04:00
# else
const FDataVertexMetadata AudioInputMetadata ;
# endif //WITH_EDITOR
2022-03-31 16:49:59 -04:00
InputInterface . Add ( TInputDataVertex < FAudioBuffer > ( GetAudioInputName ( InputIndex ) , AudioInputMetadata ) ) ;
2021-11-29 20:45:14 -05:00
}
FOutputVertexInterface OutputInterface ;
return FVertexInterface ( InputInterface , OutputInterface ) ;
} ;
static const FVertexInterface DefaultInterface = CreateDefaultInterface ( ) ;
return DefaultInterface ;
2021-03-30 15:49:01 -04:00
}
static const FNodeClassMetadata & GetNodeInfo ( )
{
2021-11-29 20:45:14 -05:00
// used if NumChannels == 1
auto CreateNodeClassMetadataMono = [ ] ( ) - > FNodeClassMetadata
2021-03-30 15:49:01 -04:00
{
2021-11-29 20:45:14 -05:00
// For backwards compatibility with previous (mono) WaveWriters keep the node name the same.
FName OperatorName = TEXT ( " WaveWriter " ) ;
2023-08-02 14:44:13 -04:00
FText NodeDisplayName = METASOUND_LOCTEXT ( " Metasound_WaveWriterNodeMonoDisplayName " , " Wave Writer (1-channel, Mono) " ) ;
2022-02-10 18:36:47 -05:00
const FText NodeDescription = METASOUND_LOCTEXT ( " Metasound_WaveWriterNodeMonoDescription " , " Write a mono audio signal to disk " ) ;
2021-11-29 20:45:14 -05:00
FVertexInterface NodeInterface = DeclareVertexInterface ( ) ;
return CreateNodeClassMetadata ( OperatorName , NodeDisplayName , NodeDescription , NodeInterface ) ;
2021-03-30 15:49:01 -04:00
} ;
2021-11-29 20:45:14 -05:00
// used if NumChannels == 2
auto CreateNodeClassMetadataStereo = [ ] ( ) - > FNodeClassMetadata
2021-03-30 15:49:01 -04:00
{
2021-11-29 20:45:14 -05:00
FName OperatorName = TEXT ( " Wave Writer (Stereo) " ) ;
2023-08-02 14:44:13 -04:00
FText NodeDisplayName = METASOUND_LOCTEXT ( " Metasound_WaveWriterNodeStereoDisplayName " , " Wave Writer (2-channel, Stereo) " ) ;
2022-02-10 18:36:47 -05:00
const FText NodeDescription = METASOUND_LOCTEXT ( " Metasound_WaveWriterNodeStereoDescription " , " Write a stereo audio signal to disk " ) ;
2021-11-29 20:45:14 -05:00
FVertexInterface NodeInterface = DeclareVertexInterface ( ) ;
2021-03-30 19:41:18 -04:00
2021-11-29 20:45:14 -05:00
return CreateNodeClassMetadata ( OperatorName , NodeDisplayName , NodeDescription , NodeInterface ) ;
} ;
// used if NumChannels > 2
auto CreateNodeClassMetadataMultiChan = [ ] ( ) - > FNodeClassMetadata
{
FName OperatorName = * FString : : Printf ( TEXT ( " Wave Writer (%d-Channel) " ) , NumInputChannels ) ;
2022-02-10 18:36:47 -05:00
FText NodeDisplayName = METASOUND_LOCTEXT_FORMAT ( " Metasound_WaveWriterNodeMultiChannelDisplayName " , " Wave Writer ({0}-channel) " , NumInputChannels ) ;
const FText NodeDescription = METASOUND_LOCTEXT ( " Metasound_WaveWriterNodeMultiDescription " , " Write a multi-channel audio signal to disk " ) ;
2021-11-29 20:45:14 -05:00
FVertexInterface NodeInterface = DeclareVertexInterface ( ) ;
return CreateNodeClassMetadata ( OperatorName , NodeDisplayName , NodeDescription , NodeInterface ) ;
} ;
static const FNodeClassMetadata Metadata = ( NumInputChannels = = 1 ) ? CreateNodeClassMetadataMono ( )
: ( NumInputChannels = = 2 ) ? CreateNodeClassMetadataStereo ( ) : CreateNodeClassMetadataMultiChan ( ) ;
return Metadata ;
2021-03-30 15:49:01 -04:00
}
2023-10-13 20:28:22 -04:00
static TUniquePtr < IOperator > CreateOperator ( const FBuildOperatorParams & InParams , FBuildResults & OutResults ) ;
2021-11-29 20:45:14 -05:00
2021-03-30 15:49:01 -04:00
void Execute ( )
{
2021-11-29 20:45:14 -05:00
// Enabled and wasn't before? Enable.
if ( ! bIsEnabled & & * Enabled )
{
Enable ( ) ;
}
// Disabled but currently Enabled? Disable.
else if ( bIsEnabled & & ! * Enabled )
{
Disable ( ) ;
}
// If we have a valid writer and enabled.
2021-03-30 15:49:01 -04:00
if ( Writer & & * Enabled )
{
2021-11-29 20:45:14 -05:00
// Need to Interleave?
if ( NumInputChannels > 1 )
{
InterleaveChannels ( AudioInputBufferPtrs . GetData ( ) , NumInputChannels , AudioInputs [ 0 ] - > Num ( ) , InterleaveBuffer . GetData ( ) ) ;
Writer - > Write ( MakeArrayView ( InterleaveBuffer . GetData ( ) , InterleaveBuffer . Num ( ) ) ) ;
}
else if ( NumInputChannels = = 1 )
{
Writer - > Write ( MakeArrayView ( AudioInputs [ 0 ] - > GetData ( ) , AudioInputs [ 0 ] - > Num ( ) ) ) ;
}
2021-03-30 15:49:01 -04:00
}
}
2023-03-02 14:40:35 -05:00
void Reset ( const IOperator : : FResetParams & InParams )
{
if ( bIsEnabled )
{
Disable ( ) ;
}
}
2021-03-30 15:49:01 -04:00
protected :
2021-11-29 20:45:14 -05:00
static const FVertexName GetAudioInputName ( int32 InInputIndex )
{
if ( NumInputChannels = = 1 )
{
// To maintain backwards compatibility with previous implementation keep the pin name the same.
static const FName AudioInputPinName = TEXT ( " In " ) ;
return AudioInputPinName ;
}
else if ( NumInputChannels = = 2 )
{
return * FString : : Printf ( TEXT ( " In %d %s " ) , InInputIndex , ( InInputIndex = = 0 ) ? TEXT ( " L " ) : TEXT ( " R " ) ) ;
}
return * FString : : Printf ( TEXT ( " In %d " ) , InInputIndex ) ;
}
2022-10-20 16:38:58 -04:00
# if WITH_EDITOR
2022-03-17 13:14:50 -04:00
static const FText GetAudioInputDisplayName ( int32 InInputIndex )
{
if ( NumInputChannels = = 1 )
{
// To maintain backwards compatibility with previous implementation keep the pin name the same.
static const FText AudioInputPinName = METASOUND_LOCTEXT ( " AudioInputPinNameIn " , " In " ) ;
return AudioInputPinName ;
}
else if ( NumInputChannels = = 2 )
{
if ( InInputIndex = = 0 )
{
2022-10-20 16:38:58 -04:00
return METASOUND_LOCTEXT_FORMAT ( " AudioInputIn2ChannelNameL " , " In {0} L " , InInputIndex ) ;
2022-03-17 13:14:50 -04:00
}
else
{
2022-10-20 16:38:58 -04:00
return METASOUND_LOCTEXT_FORMAT ( " AudioInputIn2ChannelNameR " , " In {0} R " , InInputIndex ) ;
2022-03-17 13:14:50 -04:00
}
}
return METASOUND_LOCTEXT_FORMAT ( " AudioInputInChannelName " , " In {0} " , InInputIndex ) ;
}
2021-11-29 20:45:14 -05:00
static const FText GetAudioInputDescription ( int32 InputIndex )
{
2022-02-10 18:36:47 -05:00
return METASOUND_LOCTEXT_FORMAT ( " WaveWriterAudioInputDescription " , " Audio Input #: {0} " , InputIndex ) ;
2021-11-29 20:45:14 -05:00
}
2022-10-20 16:38:58 -04:00
# endif // WITH_EDITOR
2021-11-29 20:45:14 -05:00
static FNodeClassMetadata CreateNodeClassMetadata ( const FName & InOperatorName , const FText & InDisplayName , const FText & InDescription , const FVertexInterface & InDefaultInterface )
{
FNodeClassMetadata Metadata
{
FNodeClassName { StandardNodes : : Namespace , InOperatorName , StandardNodes : : AudioVariant } ,
1 , // Major Version
1 , // Minor Version
InDisplayName ,
InDescription ,
PluginAuthor ,
PluginNodeMissingPrompt ,
InDefaultInterface ,
{ NodeCategories : : Io } ,
2022-02-10 18:36:47 -05:00
{ METASOUND_LOCTEXT ( " Metasound_AudioMixerKeyword " , " Writer " ) } ,
2021-11-29 20:45:14 -05:00
FNodeDisplayStyle { }
} ;
return Metadata ;
}
// TODO. Move to DSP lib.
static void InterleaveChannels ( const float * RESTRICT InMonoChannelsToInterleave [ ] , const int32 InNumChannelsToInterleave , const int32 NumSamplesPerChannel , float * RESTRICT OutInterleavedBuffer )
{
for ( int32 Sample = 0 ; Sample < NumSamplesPerChannel ; + + Sample )
{
for ( int32 Channel = 0 ; Channel < InNumChannelsToInterleave ; + + Channel )
{
* OutInterleavedBuffer + + = InMonoChannelsToInterleave [ Channel ] [ Sample ] ;
}
}
}
void Enable ( )
{
if ( ensure ( ! bIsEnabled ) )
{
bIsEnabled = true ;
FString Filename = NumberedFileCacheSP - > GenerateNextNumberedFilename ( * FileNamePrefix ) ;
TUniquePtr < FArchive > Stream { IFileManager : : Get ( ) . CreateFileWriter ( * Filename , IO_WRITE ) } ;
if ( Stream . IsValid ( ) )
{
2023-10-17 18:43:53 -04:00
Writer = MakeUnique < Audio : : FSimpleWaveWriter > ( MoveTemp ( Stream ) , SampleRate , NumInputChannels , true ) ;
2021-11-29 20:45:14 -05:00
}
}
}
void Disable ( )
{
if ( ensure ( bIsEnabled ) )
{
bIsEnabled = false ;
Writer . Reset ( ) ;
}
}
TArray < FAudioBufferReadRef > AudioInputs ;
TArray < const float * > AudioInputBufferPtrs ;
TArray < float > InterleaveBuffer ;
2021-03-30 15:49:01 -04:00
FBoolReadRef Enabled ;
2023-10-17 18:43:53 -04:00
TUniquePtr < Audio : : FSimpleWaveWriter > Writer ;
2021-11-29 20:45:14 -05:00
TSharedPtr < FNumberedFileCache , ESPMode : : ThreadSafe > NumberedFileCacheSP ;
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
FStringReadRef FileNamePrefix ;
2021-11-29 20:45:14 -05:00
float SampleRate = 0.f ;
bool bIsEnabled = false ;
2021-03-30 15:49:01 -04:00
} ;
2021-11-29 20:45:14 -05:00
template < int32 NumInputChannels >
2023-10-13 20:28:22 -04:00
TUniquePtr < Metasound : : IOperator > TWaveWriterOperator < NumInputChannels > : : CreateOperator ( const FBuildOperatorParams & InParams , FBuildResults & OutResults )
2021-09-13 14:14:37 -04:00
{
2021-11-29 20:45:14 -05:00
using namespace WaveWriterOperatorPrivate ;
2022-03-17 13:14:50 -04:00
using namespace WaveWriterVertexNames ;
2021-11-29 20:45:14 -05:00
const FOperatorSettings & Settings = InParams . OperatorSettings ;
2023-10-13 20:28:22 -04:00
const FInputVertexInterfaceData & InputData = InParams . InputData ;
2021-11-29 20:45:14 -05:00
2021-12-09 00:28:43 -05:00
int32 NumConnectedAudioPins = 0 ;
2021-11-29 20:45:14 -05:00
TArray < FAudioBufferReadRef > InputBuffers ;
for ( int32 i = 0 ; i < NumInputChannels ; + + i )
{
2021-12-09 00:28:43 -05:00
const FVertexName PinName = GetAudioInputName ( i ) ;
2023-10-13 20:28:22 -04:00
if ( InputData . IsVertexBound ( PinName ) )
{
NumConnectedAudioPins + + ;
}
InputBuffers . Add ( InputData . GetOrConstructDataReadReference < FAudioBuffer > ( PinName , InParams . OperatorSettings ) ) ;
2021-12-09 00:28:43 -05:00
}
// Only create a real operator if there's some connected pins.
if ( NumConnectedAudioPins > 0 )
{
return MakeUnique < TWaveWriterOperator > (
Settings ,
MoveTemp ( InputBuffers ) ,
2023-10-13 20:28:22 -04:00
InputData . GetOrCreateDefaultDataReadReference < bool > ( METASOUND_GET_PARAM_NAME ( InEnabledPin ) , Settings ) ,
2021-12-09 00:28:43 -05:00
GetNameCache ( ) ,
2023-10-13 20:28:22 -04:00
InputData . GetOrCreateDefaultDataReadReference < FString > ( METASOUND_GET_PARAM_NAME ( InFilenamePrefixPin ) , Settings )
2021-12-09 00:28:43 -05:00
) ;
2021-11-29 20:45:14 -05:00
}
2021-12-09 00:28:43 -05:00
// Create a no-op operator.
return MakeUnique < FNoOpOperator > ( ) ;
2021-09-13 14:14:37 -04:00
}
2021-03-30 15:49:01 -04:00
2021-11-29 20:45:14 -05:00
template < int32 NumInputChannels >
class METASOUNDSTANDARDNODES_API TWaveWriterNode : public FNodeFacade
2021-09-13 14:14:37 -04:00
{
2021-11-29 20:45:14 -05:00
public :
TWaveWriterNode ( const FVertexName & InName , const FGuid & InInstanceID )
: FNodeFacade ( InName , InInstanceID , TFacadeOperatorClass < TWaveWriterOperator < NumInputChannels > > ( ) )
{
}
2021-03-30 15:49:01 -04:00
2021-11-29 20:45:14 -05:00
TWaveWriterNode ( const FNodeInitData & InInitData )
: TWaveWriterNode ( InInitData . InstanceName , InInitData . InstanceID )
{
}
} ;
# define REGISTER_WAVEWRITER_NODE(A) \
using FWaveWriterNode_ # # A = TWaveWriterNode < A > ; \
METASOUND_REGISTER_NODE ( FWaveWriterNode_ # # A )
REGISTER_WAVEWRITER_NODE ( 1 ) ;
REGISTER_WAVEWRITER_NODE ( 2 ) ;
REGISTER_WAVEWRITER_NODE ( 3 ) ;
REGISTER_WAVEWRITER_NODE ( 4 ) ;
REGISTER_WAVEWRITER_NODE ( 5 ) ;
REGISTER_WAVEWRITER_NODE ( 6 ) ;
REGISTER_WAVEWRITER_NODE ( 7 ) ;
REGISTER_WAVEWRITER_NODE ( 8 ) ;
2021-03-30 15:49:01 -04:00
}
# undef LOCTEXT_NAMESPACE