// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "MetasoundDataReference.h" #include "MetasoundAudioBuffer.h" #include "MetasoundDataTypeRegistrationMacro.h" #define UE_API METASOUNDSTANDARDNODES_API namespace Metasound { /** FMultichannelAudioFormat * * FMultichannelAudioFormat represents deinterleaved multichannel audio which supports a constant * number of channels for the lifetime of the object. * * The audio buffers in FMultichannelAudioFormat are shared data references which can be accessed outside * of the FMultichannelAudioFormat. All audio buffers within a FMultichannelAudioFormat object must contain the * same number of audio frames. */ class FMultichannelAudioFormat : public IAudioDataType { public: UE_API FMultichannelAudioFormat(); /** FMultichannelAudioFormat Constructor. * * @param InNumFrames - The number of frames per an audio buffer. * @param InNumChannels - The number of audio channels. */ UE_API FMultichannelAudioFormat(int32 InNumFrames, int32 InNumChannels); /** * FMultichannelAudioFormat Constructor used by the metasound frontend. * * @param InSettings - Operator Settings passed in on construction. * @param InNumChannels - initial number of audio channels. */ UE_API explicit FMultichannelAudioFormat(const FOperatorSettings& InSettings, int32 InNumChannels); /** FMultichannelAudioFormat Constructor. * * This constructor accepts an array of writable audio buffer references. Each * buffer in the array must contain equal number of frames. * * @param InWriteRefs - An array of writable audio buffer references. */ UE_API FMultichannelAudioFormat(TArrayView InWriteRefs); // Enable the copy constructor. FMultichannelAudioFormat(const FMultichannelAudioFormat& InOther) = default; // Disable move constructor as incoming object should not be altered. //FMultichannelAudioFormat(FMultichannelAudioFormat&& InOther) = delete; // Disable equal operator so channel count does not change FMultichannelAudioFormat& operator=(const FMultichannelAudioFormat& Other) = delete; // Disable move operator so channel count does not change //FMultichannelAudioFormat& operator=(FMultichannelAudioFormat&& Other) = delete; /** Return the number of audio channels. */ int32 GetNumChannels() const { return NumChannels; } /** Return the maximum number of channels. Multichannel audio buffers cannot be resized after construction. */ int32 GetMaxNumChannels() const { return NumChannels; } /** Return an array view of the readable buffer references. * * This array will have GetNumChannels() elements. */ const TArrayView GetBuffers() const { return ReadableBuffers; } /** Return an array view of the writable buffer references. * * This array will have GetNumChannels() elements. */ const TArrayView GetBuffers() { return WritableBuffers; } /** Return an array of the readable buffer reference storage. * * This array will have GetNumChannels() elements. */ const TArray& GetStorage() const { return ReadableBufferStorage; } /** Return an array of the writable buffer reference storage. * * This array will have GetNumChannels() elements. */ const TArray& GetStorage() { return WritableBufferStorage; } private: // Friendship with the data reference class gives it access to the protected constructor // for the scenario where a TDataReadReference is constructed // with FAudioBufferReadRefs. The constructor cannot be public as it would provide writable // access to the passed in audio buffers, even though the passed buffers explicitly were // read references. friend class TDataReadReference; // Construct a FMultichannelAudioFormat with an array of readable buffers. // // This constructor should only be used when it can be assured that the constructed object // will not provide writable access to the passed in audio buffers. UE_API FMultichannelAudioFormat(TArrayView InReadRefs); int32 NumChannels; TArrayView WritableBuffers; TArrayView ReadableBuffers; TArray WritableBufferStorage; TArray ReadableBufferStorage; }; /** A TStaticChannelAudioFormat represents deinterleaved multichannel audio * where the number of channels is known at compile time. This is primarily * useful to define such cases as Stereo, Mono, Qaud, 5.1, etc. * * The audio buffers in FMultichannelAudioFormat are shared data references * which can be accessed outside of the FMultichannelAudioFormat. All audio * buffers within a FMultichannelAudioFormat object must contain the same * number of audio frames. */ template class TStaticChannelAudioFormat : public IAudioDataType { public: static constexpr int32 NumChannels = TNumChannels; /** TStaticChannelAudioFormat Constructor * * @param InNumFrames - The number of frames per an audio buffer. */ TStaticChannelAudioFormat(int32 InNumFrames) { static_assert(NumChannels > 0, "NumChannels must be greater than zero"); InNumFrames = FMath::Max(InNumFrames, 0); for (int32 i = 0; i < NumChannels; i++) { FAudioBufferWriteRef Audio = FAudioBufferWriteRef::CreateNew(InNumFrames); Audio->Zero(); WritableBufferStorage.Add(Audio); ReadableBufferStorage.Add(Audio); } WritableBuffers = WritableBufferStorage; ReadableBuffers = ReadableBufferStorage; } TStaticChannelAudioFormat(const FOperatorSettings& InOperatorSettings) : TStaticChannelAudioFormat(InOperatorSettings.GetNumFramesPerBlock()) { } /** Return the number of audio channels. */ int32 GetNumChannels() const { return NumChannels; } /** Return the maximum number of channels. static channel audio buffers cannot be resized after construction. */ int32 GetMaxNumChannels() const { return NumChannels; } /** Return an readable buffer reference for a specific channel. */ template FAudioBufferReadRef GetBuffer() const { static_assert(ChannelIndex >= 0, "Index must be within range of channels"); static_assert(ChannelIndex < NumChannels, "Index must be within range of channels"); return ReadableBuffers.GetData()[ChannelIndex]; } /** Return an writable buffer reference for a specific channel. */ template FAudioBufferWriteRef GetBuffer() { static_assert(ChannelIndex >= 0, "Index must be within range of channels"); static_assert(ChannelIndex < NumChannels, "Index must be within range of channels"); return WritableBuffers.GetData()[ChannelIndex]; } /** Return an array view of the readable buffer references. * * This array will have GetNumChannels() elements. */ const TArrayView GetBuffers() const { return ReadableBuffers; } /** Return an array view of the writable buffer references. * * This array will have GetNumChannels() elements. */ const TArrayView GetBuffers() { return WritableBuffers; } /** Return an array of the readable buffer references. * * This array will have GetNumChannels() elements. */ const TArray GetStorage() const { return ReadableBufferStorage; } /** Return an array of the writable buffer references. * * This array will have GetNumChannels() elements. */ const TArray GetStorage() { return WritableBufferStorage; } protected: // TStaticChannelAudioFormat constructor with an array of writable buffers. TStaticChannelAudioFormat(const FAudioBufferWriteRef(&InBuffers)[NumChannels]) { int32 NumFrames = 0; if (NumChannels > 0) { NumFrames = InBuffers[0]->Num(); } for (int32 i = 0; i < NumChannels; i++) { checkf(NumFrames == InBuffers[i]->Num(), TEXT("All buffers must have same number of frames (%d != %d)"), NumFrames, InBuffers[i]->Num()); WritableBufferStorage.Add(InBuffers[i]); ReadableBufferStorage.Add(InBuffers[i]); } WritableBuffers = WritableBufferStorage; ReadableBuffers = ReadableBufferStorage; } private: TArrayView WritableBuffers; TArrayView ReadableBuffers; TArray WritableBufferStorage; TArray ReadableBufferStorage; }; /** FMonoAudioFormat represents mono audio containing one channel of audio. * * The audio buffer is a shared data references which can be accessed * outside of the FMonoAudioFormat. */ class FMonoAudioFormat : public TStaticChannelAudioFormat<1> { public: using Super = TStaticChannelAudioFormat<1>; // Inherit constructors of base class. using Super::Super; /** FMonoAudioFormat Construtor * * Construct with a single writable audio buffer reference. * * @param InAudio - A writable audio buffer reference. */ FMonoAudioFormat(const FAudioBufferWriteRef& InAudio) : Super({InAudio}) { } /** Return writable audio buffer reference of center channel. */ FAudioBufferWriteRef GetCenter() { return GetBuffer<0>(); } /** Return readable audio buffer reference of center channel. */ FAudioBufferReadRef GetCenter() const { return GetBuffer<0>(); } }; /** FStereoAudioFormat represents stereo audio containing two channels of * audio. * * The audio buffers are shared data references which can be accessed * outside of the FStereoAudioFormat. */ class FStereoAudioFormat : public TStaticChannelAudioFormat<2> { public: using Super = TStaticChannelAudioFormat<2>; // Inherit constructors of base class. using Super::Super; /** FStereoAudioFormat Construtor * * Construct with a two writable audio buffer reference. * * @param InLeftAudio - A writable audio buffer reference for the left channel. * @param InRightAudio - A writable audio buffer reference for the right channel. */ FStereoAudioFormat(const FAudioBufferWriteRef& InLeftAudio, const FAudioBufferWriteRef& InRightAudio) : Super({InLeftAudio, InRightAudio}) { } /** Return writable audio buffer reference of left channel. */ FAudioBufferWriteRef GetLeft() { return GetBuffer<0>(); } /** Return readable audio buffer reference of left channel. */ FAudioBufferReadRef GetLeft() const { return GetBuffer<0>(); } /** Return writable audio buffer reference of right channel. */ FAudioBufferWriteRef GetRight() { return GetBuffer<1>(); } /** Return readable audio buffer reference of right channel. */ FAudioBufferReadRef GetRight() const { return GetBuffer<1>(); } }; // TODO: currently unused. Commenting out to keep clean UX. //DECLARE_METASOUND_DATA_REFERENCE_TYPES(FMultichannelAudioFormat, METASOUNDSTANDARDNODES_API, FMultichannelAudioFormatTypeInfo, FMultichannelAudioFormatReadRef, FMultichannelAudioFormatWriteRef); DECLARE_METASOUND_DATA_REFERENCE_TYPES(FMonoAudioFormat, METASOUNDSTANDARDNODES_API, FMonoAudioFormatTypeInfo, FMonoAudioFormatReadRef, FMonoAudioFormatWriteRef); DECLARE_METASOUND_DATA_REFERENCE_TYPES(FStereoAudioFormat, METASOUNDSTANDARDNODES_API, FStereoAudioFormatTypeInfo, FStereoAudioFormatReadRef, FStereoAudioFormatWriteRef); } #undef UE_API