2020-07-28 11:45:27 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "MetasoundWavePlayerNode.h"
|
|
|
|
|
#include "MetasoundExecutableOperator.h"
|
2020-08-11 01:36:57 -04:00
|
|
|
#include "MetasoundNodeRegistrationMacro.h"
|
2020-07-28 11:45:27 -04:00
|
|
|
#include "MetasoundPrimitives.h"
|
|
|
|
|
#include "MetasoundWave.h"
|
2020-07-29 10:43:43 -04:00
|
|
|
#include "MetasoundNodeRegistrationMacro.h"
|
2020-07-30 19:14:41 -04:00
|
|
|
#include "MetasoundBuildError.h"
|
2020-07-28 11:45:27 -04:00
|
|
|
|
|
|
|
|
#include "IAudioCodecRegistry.h"
|
|
|
|
|
#include "IAudioCodec.h"
|
|
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "MetasoundWaveNode"
|
|
|
|
|
|
|
|
|
|
namespace Metasound
|
|
|
|
|
{
|
|
|
|
|
METASOUND_REGISTER_NODE(FWavePlayerNode)
|
2020-07-30 19:14:41 -04:00
|
|
|
|
|
|
|
|
// WavePlayer custom error
|
|
|
|
|
class FWavePlayerError : public FBuildErrorBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
2020-11-04 14:26:37 -04:00
|
|
|
FWavePlayerError(const FWavePlayerNode& InNode, FText InErrorDescription)
|
|
|
|
|
: FBuildErrorBase(ErrorType, InErrorDescription)
|
|
|
|
|
{
|
|
|
|
|
AddNode(InNode);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 19:14:41 -04:00
|
|
|
virtual ~FWavePlayerError() = default;
|
2020-11-04 14:26:37 -04:00
|
|
|
|
|
|
|
|
static const FName ErrorType;
|
2020-07-30 19:14:41 -04:00
|
|
|
};
|
2020-11-04 14:26:37 -04:00
|
|
|
|
|
|
|
|
const FName FWavePlayerError::ErrorType = FName(TEXT("WavePlayerError"));
|
2020-07-30 19:14:41 -04:00
|
|
|
|
2020-07-28 11:45:27 -04:00
|
|
|
class FWavePlayerOperator : public TExecutableOperator<FWavePlayerOperator>
|
|
|
|
|
{
|
2020-07-30 19:14:41 -04:00
|
|
|
public:
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-07-30 19:14:41 -04:00
|
|
|
// Silent setup
|
|
|
|
|
FWavePlayerOperator(
|
|
|
|
|
const FOperatorSettings& InSettings,
|
2020-09-08 18:12:55 -04:00
|
|
|
const FWaveAssetReadRef& InWave )
|
2020-07-30 19:14:41 -04:00
|
|
|
: OperatorSettings(InSettings)
|
|
|
|
|
, Wave(InWave)
|
|
|
|
|
, AudioBuffer(FAudioBufferWriteRef::CreateNew(InSettings))
|
|
|
|
|
{
|
|
|
|
|
check(AudioBuffer->Num() == InSettings.GetNumFramesPerBlock());
|
|
|
|
|
OutputDataReferences.AddDataReadReference(TEXT("Audio"), FAudioBufferReadRef(AudioBuffer));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FWavePlayerOperator(
|
|
|
|
|
const FOperatorSettings& InSettings,
|
2020-09-08 18:12:55 -04:00
|
|
|
const FWaveAssetReadRef& InWave,
|
|
|
|
|
FWaveAsset::FDecoderInputPtr&& InDecoderInput,
|
2020-07-30 19:14:41 -04:00
|
|
|
TUniquePtr<Audio::IDecoderOutput>&& InDecoderOutput,
|
|
|
|
|
TUniquePtr<Audio::IDecoder>&& InDecoder )
|
|
|
|
|
: OperatorSettings(InSettings)
|
|
|
|
|
, Wave(InWave)
|
|
|
|
|
, AudioBuffer(FAudioBufferWriteRef::CreateNew(InSettings))
|
|
|
|
|
, Decoder(MoveTemp(InDecoder))
|
|
|
|
|
, DecoderInput(MoveTemp(InDecoderInput))
|
|
|
|
|
, DecoderOutput(MoveTemp(InDecoderOutput))
|
|
|
|
|
{
|
|
|
|
|
check(AudioBuffer->Num() == InSettings.GetNumFramesPerBlock());
|
|
|
|
|
OutputDataReferences.AddDataReadReference(TEXT("Audio"), FAudioBufferReadRef(AudioBuffer));
|
|
|
|
|
}
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-07-30 19:14:41 -04:00
|
|
|
virtual const FDataReferenceCollection& GetInputs() const override
|
|
|
|
|
{
|
|
|
|
|
return InputDataReferences;
|
|
|
|
|
}
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-07-30 19:14:41 -04:00
|
|
|
virtual const FDataReferenceCollection& GetOutputs() const override
|
|
|
|
|
{
|
|
|
|
|
return OutputDataReferences;
|
|
|
|
|
}
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-07-30 19:14:41 -04:00
|
|
|
// Scheduler/decoder holds weakref, and pins the sharedptr to the output when it writes.
|
|
|
|
|
// FBufferedDecoderOutput
|
|
|
|
|
// 1 write [... .. .. ]
|
|
|
|
|
// n free
|
|
|
|
|
// m queued
|
|
|
|
|
// 1 read [...........]
|
|
|
|
|
|
|
|
|
|
// ApuMemory 2kb compress -> 512 frames
|
|
|
|
|
|
|
|
|
|
// TCircularAudioBuffer //consider for Output object.
|
|
|
|
|
|
|
|
|
|
void Execute()
|
|
|
|
|
{
|
2020-08-04 19:08:01 -04:00
|
|
|
int32 NumPopped = 0;
|
2020-07-30 19:14:41 -04:00
|
|
|
float* Dst = AudioBuffer->GetData();
|
|
|
|
|
|
|
|
|
|
// If we don't have a valid state, just output silence.
|
|
|
|
|
if (Decoder && DecoderOutput && DecoderInput )
|
2020-07-28 11:45:27 -04:00
|
|
|
{
|
|
|
|
|
// V1. Do the decode inline, this will sound bad.
|
|
|
|
|
Decoder->Decode();
|
|
|
|
|
|
2020-08-04 19:08:01 -04:00
|
|
|
Audio::IDecoderOutput::FPushedAudioDetails Details;
|
|
|
|
|
NumPopped = DecoderOutput->PopAudio(MakeArrayView(Dst, AudioBuffer->Num()), Details);
|
2020-07-28 11:45:27 -04:00
|
|
|
}
|
2020-08-04 19:08:01 -04:00
|
|
|
|
|
|
|
|
// Pad with Silence if we didn't pop enough
|
|
|
|
|
for ( int32 i = NumPopped; i < OperatorSettings.GetNumFramesPerBlock(); ++i)
|
2020-07-30 19:14:41 -04:00
|
|
|
{
|
|
|
|
|
Dst[i] = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-07-30 19:14:41 -04:00
|
|
|
private:
|
|
|
|
|
const FOperatorSettings OperatorSettings;
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-09-08 18:12:55 -04:00
|
|
|
FWaveAssetReadRef Wave;
|
2020-07-30 19:14:41 -04:00
|
|
|
FAudioBufferWriteRef AudioBuffer;
|
|
|
|
|
FDataReferenceCollection InputDataReferences;
|
|
|
|
|
FDataReferenceCollection OutputDataReferences;
|
|
|
|
|
|
|
|
|
|
// Decoder/IO.
|
|
|
|
|
Audio::ICodec::FDecoderPtr Decoder;
|
2020-09-08 18:12:55 -04:00
|
|
|
FWaveAsset::FDecoderInputPtr DecoderInput;
|
2020-07-30 19:14:41 -04:00
|
|
|
TUniquePtr<Audio::IDecoderOutput> DecoderOutput;
|
2020-07-28 11:45:27 -04:00
|
|
|
};
|
|
|
|
|
|
2020-08-24 10:57:03 -04:00
|
|
|
const FNodeInfo FWavePlayerNode::Info = FNodeInfo(
|
2020-09-08 18:12:55 -04:00
|
|
|
{
|
|
|
|
|
FName(TEXT("Wave Player")),
|
|
|
|
|
LOCTEXT("Metasound_WavePlayerNodeDescription", "Plays a supplied Wave"),
|
|
|
|
|
PluginAuthor,
|
|
|
|
|
PluginNodeMissingPrompt
|
|
|
|
|
});
|
2020-07-28 11:45:27 -04:00
|
|
|
|
|
|
|
|
TUniquePtr<IOperator> FWavePlayerNode::FOperatorFactory::CreateOperator(
|
2020-08-24 10:57:03 -04:00
|
|
|
const FCreateOperatorParams& InParams,
|
|
|
|
|
FBuildErrorArray& OutErrors)
|
2020-07-28 11:45:27 -04:00
|
|
|
{
|
|
|
|
|
using namespace Audio;
|
|
|
|
|
|
2020-08-24 10:57:03 -04:00
|
|
|
const FWavePlayerNode& WaveNode = static_cast<const FWavePlayerNode&>(InParams.Node);
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-08-24 10:57:03 -04:00
|
|
|
const FDataReferenceCollection& InputCol = InParams.InputDataReferences;
|
|
|
|
|
|
2020-09-08 18:12:55 -04:00
|
|
|
FWaveAssetReadRef Wave = InputCol.GetDataReadReferenceOrConstruct<FWaveAsset>(TEXT("Wave"));
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-09-25 16:12:21 -04:00
|
|
|
if(Wave->GetSoundWave())
|
2020-07-28 11:45:27 -04:00
|
|
|
{
|
2020-09-25 16:12:21 -04:00
|
|
|
FWaveAsset::FDecoderInputPtr Input = FWaveAsset::CreateDecoderInput(Wave);
|
|
|
|
|
if (Input)
|
2020-07-28 11:45:27 -04:00
|
|
|
{
|
2020-09-25 16:12:21 -04:00
|
|
|
ICodecRegistry::FCodecPtr Codec = ICodecRegistry::Get().FindCodecByParsingInput(Input.Get());
|
|
|
|
|
if (Codec)
|
|
|
|
|
{
|
|
|
|
|
IDecoderOutput::FRequirements Reqs
|
|
|
|
|
{
|
|
|
|
|
Float32_Interleaved,
|
|
|
|
|
InParams.OperatorSettings.GetNumFramesPerBlock(),
|
|
|
|
|
static_cast<int32>(InParams.OperatorSettings.GetSampleRate())
|
|
|
|
|
};
|
|
|
|
|
TUniquePtr<IDecoderOutput> Output = IDecoderOutput::Create(Reqs);
|
|
|
|
|
TUniquePtr<IDecoder> Decoder = Codec->CreateDecoder(Input.Get(), Output.Get());
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-09-25 16:12:21 -04:00
|
|
|
return MakeUnique<FWavePlayerOperator>(
|
|
|
|
|
InParams.OperatorSettings,
|
|
|
|
|
Wave,
|
|
|
|
|
MoveTemp(Input),
|
|
|
|
|
MoveTemp(Output),
|
|
|
|
|
MoveTemp(Decoder)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-11-04 14:26:37 -04:00
|
|
|
AddBuildError<FWavePlayerError>(OutErrors, WaveNode, LOCTEXT("FailedToFindCodec", "Failed to find codec for opening the supplied Wave"));
|
2020-09-25 16:12:21 -04:00
|
|
|
}
|
2020-07-28 11:45:27 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-11-04 14:26:37 -04:00
|
|
|
AddBuildError<FWavePlayerError>(OutErrors, WaveNode, LOCTEXT("FailedToParseInput", "Failed to parse the compressed data"));
|
2020-07-28 11:45:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
2020-11-04 14:26:37 -04:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AddBuildError<FWavePlayerError>(OutErrors, WaveNode, LOCTEXT("NoSoundWave", "No Sound Wave"));
|
|
|
|
|
}
|
2020-07-28 11:45:27 -04:00
|
|
|
|
2020-07-30 19:14:41 -04:00
|
|
|
// Create the player without any inputs, will just produce silence.
|
2020-08-24 10:57:03 -04:00
|
|
|
return MakeUnique<FWavePlayerOperator>(InParams.OperatorSettings, Wave);
|
2020-07-28 11:45:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FWavePlayerNode::FWavePlayerNode(const FString& InName)
|
2020-08-24 10:57:03 -04:00
|
|
|
: FNode(InName, FWavePlayerNode::Info)
|
|
|
|
|
, Factory(MakeOperatorFactoryRef<FWavePlayerNode::FOperatorFactory>())
|
2020-07-28 11:45:27 -04:00
|
|
|
{
|
2020-09-08 18:12:55 -04:00
|
|
|
Interface.GetInputInterface().Add(TInputDataVertexModel<FWaveAsset>(TEXT("Wave"), LOCTEXT("WaveTooltip", "The Wave to be decoded")));
|
2020-08-24 10:57:03 -04:00
|
|
|
Interface.GetOutputInterface().Add(TOutputDataVertexModel<FAudioBuffer>(TEXT("Audio"), LOCTEXT("AudioTooltip", "The output audio")));
|
2020-07-28 11:45:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FWavePlayerNode::FWavePlayerNode(const FNodeInitData& InInitData)
|
|
|
|
|
: FWavePlayerNode(InInitData.InstanceName)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-24 10:57:03 -04:00
|
|
|
FOperatorFactorySharedRef FWavePlayerNode::GetDefaultOperatorFactory() const
|
2020-07-28 11:45:27 -04:00
|
|
|
{
|
|
|
|
|
return Factory;
|
|
|
|
|
}
|
2020-08-24 10:57:03 -04:00
|
|
|
|
|
|
|
|
const FVertexInterface& FWavePlayerNode::GetVertexInterface() const
|
|
|
|
|
{
|
|
|
|
|
return Interface;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FVertexInterface& FWavePlayerNode::GetDefaultVertexInterface() const
|
|
|
|
|
{
|
|
|
|
|
return Interface;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FWavePlayerNode::SetVertexInterface(const FVertexInterface& InInterface)
|
|
|
|
|
{
|
|
|
|
|
return InInterface == Interface;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FWavePlayerNode::IsVertexInterfaceSupported(const FVertexInterface& InInterface) const
|
|
|
|
|
{
|
|
|
|
|
return InInterface == Interface;
|
|
|
|
|
}
|
2020-07-28 11:45:27 -04:00
|
|
|
}
|
|
|
|
|
#undef LOCTEXT_NAMESPACE //MetasoundWaveNode
|