2021-03-06 03:52:08 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundEnvelopeFollowerNode.h"
2021-09-02 20:50:45 -04:00
# include "Algo/MaxElement.h"
2021-08-20 18:36:01 -04:00
# include "Internationalization/Text.h"
2021-03-06 03:52:08 -04:00
# include "MetasoundAudioBuffer.h"
2021-11-18 14:37:34 -05:00
# include "MetasoundEnvelopeFollowerTypes.h"
2021-03-06 03:52:08 -04:00
# include "MetasoundExecutableOperator.h"
# include "MetasoundFacade.h"
2021-08-20 18:36:01 -04:00
# include "MetasoundEnumRegistrationMacro.h"
2021-03-06 03:52:08 -04:00
# include "MetasoundNodeRegistrationMacro.h"
# include "MetasoundDataTypeRegistrationMacro.h"
# include "MetasoundOperatorSettings.h"
# include "MetasoundPrimitives.h"
# include "MetasoundStandardNodesNames.h"
# include "MetasoundTrigger.h"
# include "MetasoundTime.h"
# include "MetasoundVertex.h"
2021-08-20 18:36:01 -04:00
# include "MetasoundParamHelper.h"
2021-03-06 03:52:08 -04:00
# include "DSP/EnvelopeFollower.h"
2021-04-07 02:57:54 -04:00
# define LOCTEXT_NAMESPACE "MetasoundStandardNodes_EnvelopeFollower"
2021-03-06 03:52:08 -04:00
namespace Metasound
{
namespace EnvelopeFollower
{
static const TCHAR * InParamNameAudioInput = TEXT ( " In " ) ;
static const TCHAR * InParamNameAttackTime = TEXT ( " Attack Time " ) ;
static const TCHAR * InParamNameReleaseTime = TEXT ( " Release Time " ) ;
2021-08-20 18:36:01 -04:00
static const TCHAR * InParamNameFollowMode = TEXT ( " Peak Mode " ) ;
2021-03-06 03:52:08 -04:00
static const TCHAR * OutParamNameEnvelope = TEXT ( " Envelope " ) ;
}
2021-08-20 18:36:01 -04:00
METASOUND_PARAM ( OutputAudioEnvelope , " Audio Envelope " , " The output envelope value of the audio signal (audio rate). " ) ;
2021-03-06 03:52:08 -04:00
class FEnvelopeFollowerOperator : public TExecutableOperator < FEnvelopeFollowerOperator >
{
public :
static const FNodeClassMetadata & GetNodeInfo ( ) ;
static const FVertexInterface & GetVertexInterface ( ) ;
static TUniquePtr < IOperator > CreateOperator ( const FCreateOperatorParams & InParams , FBuildErrorArray & OutErrors ) ;
2021-08-20 18:36:01 -04:00
FEnvelopeFollowerOperator ( const FOperatorSettings & InSettings ,
const FAudioBufferReadRef & InAudioInput ,
const FTimeReadRef & InAttackTime ,
const FTimeReadRef & InReleaseTime ,
2021-11-18 14:37:34 -05:00
const FEnvelopePeakModeReadRef & InEnvelopeMode ) ;
2021-03-06 03:52:08 -04:00
virtual FDataReferenceCollection GetInputs ( ) const override ;
virtual FDataReferenceCollection GetOutputs ( ) const override ;
void Execute ( ) ;
private :
// The input audio buffer
FAudioBufferReadRef AudioInput ;
// The amount of attack time
2021-08-20 18:36:01 -04:00
FTimeReadRef AttackTimeInput ;
2021-03-06 03:52:08 -04:00
// The amount of release time
2021-08-20 18:36:01 -04:00
FTimeReadRef ReleaseTimeInput ;
2021-03-06 03:52:08 -04:00
2021-08-20 18:36:01 -04:00
// The Envelope-Following method
2021-11-18 14:37:34 -05:00
FEnvelopePeakModeReadRef FollowModeInput ;
2021-08-20 18:36:01 -04:00
// The envelope outputs
FFloatWriteRef EnvelopeFloatOutput ;
FAudioBufferWriteRef EnvelopeAudioOutput ;
2021-03-06 03:52:08 -04:00
// The envelope follower DSP object
Audio : : FEnvelopeFollower EnvelopeFollower ;
double PrevAttackTime = 0.0 ;
double PrevReleaseTime = 0.0 ;
2021-11-18 14:37:34 -05:00
EEnvelopePeakMode PrevFollowMode = EEnvelopePeakMode : : Peak ;
2021-03-06 03:52:08 -04:00
} ;
2021-08-20 18:36:01 -04:00
FEnvelopeFollowerOperator : : FEnvelopeFollowerOperator ( const FOperatorSettings & InSettings ,
const FAudioBufferReadRef & InAudioInput ,
2021-03-06 03:52:08 -04:00
const FTimeReadRef & InAttackTime ,
2021-08-20 18:36:01 -04:00
const FTimeReadRef & InReleaseTime ,
2021-11-18 14:37:34 -05:00
const FEnvelopePeakModeReadRef & InEnvelopeMode )
2021-03-06 03:52:08 -04:00
: AudioInput ( InAudioInput )
2021-08-20 18:36:01 -04:00
, AttackTimeInput ( InAttackTime )
, ReleaseTimeInput ( InReleaseTime )
, FollowModeInput ( InEnvelopeMode )
, EnvelopeFloatOutput ( FFloatWriteRef : : CreateNew ( ) )
, EnvelopeAudioOutput ( FAudioBufferWriteRef : : CreateNew ( InSettings ) )
2021-03-06 03:52:08 -04:00
{
2021-08-20 18:36:01 -04:00
PrevAttackTime = FMath : : Max ( FTime : : ToMilliseconds ( * AttackTimeInput ) , 0.0 ) ;
PrevReleaseTime = FMath : : Max ( FTime : : ToMilliseconds ( * ReleaseTimeInput ) , 0.0 ) ;
2021-03-06 03:52:08 -04:00
2021-09-02 20:50:45 -04:00
Audio : : FEnvelopeFollowerInitParams EnvelopeParamsInitParams ;
EnvelopeParamsInitParams . SampleRate = InSettings . GetSampleRate ( ) ;
EnvelopeParamsInitParams . NumChannels = 1 ;
EnvelopeParamsInitParams . AttackTimeMsec = PrevAttackTime ;
EnvelopeParamsInitParams . ReleaseTimeMsec = PrevReleaseTime ;
EnvelopeFollower . Init ( EnvelopeParamsInitParams ) ;
2021-03-06 03:52:08 -04:00
}
FDataReferenceCollection FEnvelopeFollowerOperator : : GetInputs ( ) const
{
FDataReferenceCollection InputDataReferences ;
InputDataReferences . AddDataReadReference ( EnvelopeFollower : : InParamNameAudioInput , AudioInput ) ;
2021-08-20 18:36:01 -04:00
InputDataReferences . AddDataReadReference ( EnvelopeFollower : : InParamNameAttackTime , AttackTimeInput ) ;
InputDataReferences . AddDataReadReference ( EnvelopeFollower : : InParamNameReleaseTime , ReleaseTimeInput ) ;
InputDataReferences . AddDataReadReference ( EnvelopeFollower : : InParamNameFollowMode , FollowModeInput ) ;
2021-03-06 03:52:08 -04:00
return InputDataReferences ;
}
FDataReferenceCollection FEnvelopeFollowerOperator : : GetOutputs ( ) const
{
FDataReferenceCollection OutputDataReferences ;
2021-08-20 18:36:01 -04:00
OutputDataReferences . AddDataReadReference ( EnvelopeFollower : : OutParamNameEnvelope , EnvelopeFloatOutput ) ;
OutputDataReferences . AddDataReadReference ( METASOUND_GET_PARAM_NAME ( OutputAudioEnvelope ) , EnvelopeAudioOutput ) ;
2021-03-06 03:52:08 -04:00
return OutputDataReferences ;
}
void FEnvelopeFollowerOperator : : Execute ( )
{
// Check for any input changes
2021-08-20 18:36:01 -04:00
double CurrentAttackTime = FMath : : Max ( FTime : : ToMilliseconds ( * AttackTimeInput ) , 0.0 ) ;
2021-03-06 03:52:08 -04:00
if ( ! FMath : : IsNearlyEqual ( CurrentAttackTime , PrevAttackTime ) )
{
PrevAttackTime = CurrentAttackTime ;
EnvelopeFollower . SetAttackTime ( CurrentAttackTime ) ;
}
2021-08-20 18:36:01 -04:00
double CurrentReleaseTime = FMath : : Max ( FTime : : ToMilliseconds ( * ReleaseTimeInput ) , 0.0 ) ;
2021-03-06 03:52:08 -04:00
if ( ! FMath : : IsNearlyEqual ( CurrentReleaseTime , PrevReleaseTime ) )
{
PrevReleaseTime = CurrentReleaseTime ;
EnvelopeFollower . SetReleaseTime ( CurrentReleaseTime ) ;
}
2021-08-20 18:36:01 -04:00
if ( PrevFollowMode ! = * FollowModeInput )
{
PrevFollowMode = * FollowModeInput ;
switch ( PrevFollowMode )
{
2021-11-18 14:37:34 -05:00
case EEnvelopePeakMode : : MeanSquared :
2021-08-20 18:36:01 -04:00
default :
EnvelopeFollower . SetMode ( Audio : : EPeakMode : : Type : : MeanSquared ) ;
break ;
2021-11-18 14:37:34 -05:00
case EEnvelopePeakMode : : RootMeanSquared :
2021-08-20 18:36:01 -04:00
EnvelopeFollower . SetMode ( Audio : : EPeakMode : : Type : : RootMeanSquared ) ;
break ;
2021-11-18 14:37:34 -05:00
case EEnvelopePeakMode : : Peak :
2021-08-20 18:36:01 -04:00
EnvelopeFollower . SetMode ( Audio : : EPeakMode : : Type : : Peak ) ;
break ;
}
}
2021-03-06 03:52:08 -04:00
2021-08-20 18:36:01 -04:00
// Process the audio through the envelope follower
2021-09-02 20:50:45 -04:00
EnvelopeFollower . ProcessAudio ( AudioInput - > GetData ( ) , AudioInput - > Num ( ) , EnvelopeAudioOutput - > GetData ( ) ) ;
if ( const float * MaxElement = Algo : : MaxElement ( EnvelopeFollower . GetEnvelopeValues ( ) ) )
{
* EnvelopeFloatOutput = * MaxElement ;
}
else
{
* EnvelopeFloatOutput = 0.f ;
}
2021-03-06 03:52:08 -04:00
}
const FVertexInterface & FEnvelopeFollowerOperator : : GetVertexInterface ( )
{
static const FVertexInterface Interface (
FInputVertexInterface (
TInputDataVertexModel < FAudioBuffer > ( EnvelopeFollower : : InParamNameAudioInput , LOCTEXT ( " AudioInputToolTT " , " Audio input. " ) ) ,
TInputDataVertexModel < FTime > ( EnvelopeFollower : : InParamNameAttackTime , LOCTEXT ( " AttackTimeTT " , " The attack time of the envelope follower. " ) , 0.01f ) ,
2021-08-20 18:36:01 -04:00
TInputDataVertexModel < FTime > ( EnvelopeFollower : : InParamNameReleaseTime , LOCTEXT ( " ReleaseTimeTT " , " The release time of the envelope follower. " ) , 0.1f ) ,
2021-11-18 14:37:34 -05:00
TInputDataVertexModel < FEnumEnvelopePeakMode > ( EnvelopeFollower : : InParamNameFollowMode , LOCTEXT ( " FollowModeTT " , " The following-method of the envelope follower. " ) )
2021-03-06 03:52:08 -04:00
) ,
FOutputVertexInterface (
2021-08-20 18:36:01 -04:00
TOutputDataVertexModel < float > ( EnvelopeFollower : : OutParamNameEnvelope , LOCTEXT ( " EnvelopeFollowerOutputTT " , " The output envelope value of the audio signal. " ) ) ,
TOutputDataVertexModel < FAudioBuffer > ( METASOUND_GET_PARAM_NAME_AND_TT ( OutputAudioEnvelope ) )
2021-03-06 03:52:08 -04:00
)
) ;
return Interface ;
}
const FNodeClassMetadata & FEnvelopeFollowerOperator : : GetNodeInfo ( )
{
auto InitNodeInfo = [ ] ( ) - > FNodeClassMetadata
{
FNodeClassMetadata Info ;
2021-08-09 15:13:40 -04:00
Info . ClassName = { StandardNodes : : Namespace , TEXT ( " Envelope Follower " ) , TEXT ( " " ) } ;
2021-03-06 03:52:08 -04:00
Info . MajorVersion = 1 ;
2021-08-20 18:36:01 -04:00
Info . MinorVersion = 3 ;
2021-03-06 03:52:08 -04:00
Info . DisplayName = LOCTEXT ( " Metasound_EnvelopeFollowerDisplayName " , " Envelope Follower " ) ;
Info . Description = LOCTEXT ( " Metasound_EnvelopeFollowerDescription " , " Outputs an envelope from an input audio signal. " ) ;
Info . Author = PluginAuthor ;
Info . PromptIfMissing = PluginNodeMissingPrompt ;
Info . DefaultInterface = GetVertexInterface ( ) ;
return Info ;
} ;
static const FNodeClassMetadata Info = InitNodeInfo ( ) ;
return Info ;
}
TUniquePtr < IOperator > FEnvelopeFollowerOperator : : CreateOperator ( const FCreateOperatorParams & InParams , FBuildErrorArray & OutErrors )
{
const FEnvelopeFollowerNode & EnvelopeFollowerNode = static_cast < const FEnvelopeFollowerNode & > ( InParams . Node ) ;
const FDataReferenceCollection & InputCollection = InParams . InputDataReferences ;
const FInputVertexInterface & InputInterface = GetVertexInterface ( ) . GetInputInterface ( ) ;
FAudioBufferReadRef AudioIn = InputCollection . GetDataReadReferenceOrConstruct < FAudioBuffer > ( EnvelopeFollower : : InParamNameAudioInput , InParams . OperatorSettings ) ;
2021-03-23 22:43:28 -04:00
FTimeReadRef AttackTime = InputCollection . GetDataReadReferenceOrConstructWithVertexDefault < FTime > ( InputInterface , EnvelopeFollower : : InParamNameAttackTime , InParams . OperatorSettings ) ;
FTimeReadRef ReleaseTime = InputCollection . GetDataReadReferenceOrConstructWithVertexDefault < FTime > ( InputInterface , EnvelopeFollower : : InParamNameReleaseTime , InParams . OperatorSettings ) ;
2021-11-18 14:37:34 -05:00
FEnvelopePeakModeReadRef EnvelopeModeIn = InputCollection . GetDataReadReferenceOrConstruct < FEnumEnvelopePeakMode > ( EnvelopeFollower : : InParamNameFollowMode ) ;
2021-03-06 03:52:08 -04:00
2021-08-20 18:36:01 -04:00
return MakeUnique < FEnvelopeFollowerOperator > ( InParams . OperatorSettings , AudioIn , AttackTime , ReleaseTime , EnvelopeModeIn ) ;
2021-03-06 03:52:08 -04:00
}
FEnvelopeFollowerNode : : FEnvelopeFollowerNode ( const FNodeInitData & InitData )
: FNodeFacade ( InitData . InstanceName , InitData . InstanceID , TFacadeOperatorClass < FEnvelopeFollowerOperator > ( ) )
{
}
METASOUND_REGISTER_NODE ( FEnvelopeFollowerNode )
}
# undef LOCTEXT_NAMESPACE