2021-08-04 18:06:59 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "DSP/Dsp.h"
# include "DSP/DynamicsProcessor.h"
2022-06-15 01:43:38 -04:00
# include "DSP/FloatArrayMath.h"
2022-06-15 21:53:48 -04:00
# include "DSP/IntegerDelay.h"
2021-08-09 16:57:11 -04:00
# include "Internationalization/Text.h"
# include "MetasoundAudioBuffer.h"
# include "MetasoundEnumRegistrationMacro.h"
# include "MetasoundExecutableOperator.h"
2021-11-18 14:37:34 -05:00
# include "MetasoundEnvelopeFollowerTypes.h"
2021-08-09 16:57:11 -04:00
# include "MetasoundFacade.h"
# include "MetasoundNodeRegistrationMacro.h"
# include "MetasoundParamHelper.h"
# include "MetasoundPrimitives.h"
# include "MetasoundStandardNodesCategories.h"
# include "MetasoundStandardNodesNames.h"
2021-08-04 18:06:59 -04:00
# define LOCTEXT_NAMESPACE "MetasoundStandardNodes_CompressorNode"
namespace Metasound
{
/* Mid-Side Encoder */
namespace CompressorVertexNames
{
METASOUND_PARAM ( InputAudio , " Audio " , " Incoming audio signal to compress. " ) ;
METASOUND_PARAM ( InputRatio , " Ratio " , " Amount of gain reduction. 1 = no reduction, higher = more reduction. " ) ;
2021-08-11 15:04:27 -04:00
METASOUND_PARAM ( InputThreshold , " Threshold dB " , " Amplitude threshold (dB) above which gain will be reduced. " ) ;
2021-08-04 18:06:59 -04:00
METASOUND_PARAM ( InputAttackTime , " Attack Time " , " How long it takes for audio above the threshold to reach its compressed volume level. " ) ;
METASOUND_PARAM ( InputReleaseTime , " Release Time " , " How long it takes for audio below the threshold to return to its original volume level. " ) ;
2022-06-15 21:53:48 -04:00
METASOUND_PARAM ( InputLookaheadTime , " Lookahead Time " , " How much time the compressor has to lookahead and catch peaks. This delays the signal. " ) ;
2021-08-04 18:06:59 -04:00
METASOUND_PARAM ( InputKnee , " Knee " , " How hard or soft the gain reduction blends from no gain reduction to gain reduction. 0 dB = no blending. " ) ;
2022-01-07 02:53:21 -05:00
METASOUND_PARAM ( InputSidechain , " Sidechain " , " (Optional) External audio signal to control the compressor with. If empty, uses the input audio signal. " ) ;
2021-08-04 18:06:59 -04:00
METASOUND_PARAM ( InputEnvelopeMode , " Envelope Mode " , " The envelope-following method the compressor will use for gain detection. " ) ;
METASOUND_PARAM ( InputIsAnalog , " Analog Mode " , " Enable Analog Mode for the compressor's envelope follower. " ) ;
2022-01-18 17:56:27 -05:00
METASOUND_PARAM ( InputIsUpwards , " Upwards Mode " , " Enable to switch from a standard downwards compresser to an upwards compressor. " ) ;
2021-08-04 18:06:59 -04:00
METASOUND_PARAM ( InputWetDryMix , " Wet/Dry " , " Ratio between the processed/wet signal and the unprocessed/dry signal. 0 is full dry, 1 is full wet, and 0.5 is 50/50. " ) ;
METASOUND_PARAM ( OutputAudio , " Audio " , " The output audio signal. " ) ;
METASOUND_PARAM ( OutputEnvelope , " Gain Envelope " , " The compressor's gain being applied to the signal. " ) ;
}
2021-11-18 14:37:34 -05:00
// Operator Class
2021-08-04 18:06:59 -04:00
class FCompressorOperator : public TExecutableOperator < FCompressorOperator >
{
public :
FCompressorOperator ( const FOperatorSettings & InSettings ,
const FAudioBufferReadRef & InAudio ,
const FFloatReadRef & InRatio ,
2021-08-11 15:04:27 -04:00
const FFloatReadRef & InThresholdDb ,
2021-08-04 18:06:59 -04:00
const FTimeReadRef & InAttackTime ,
const FTimeReadRef & InReleaseTime ,
2022-01-18 17:56:27 -05:00
const FTimeReadRef & InLookaheadTime ,
2021-08-04 18:06:59 -04:00
const FFloatReadRef & InKnee ,
const bool & bInUseSidechain ,
const FAudioBufferReadRef & InSidechain ,
const FEnvelopePeakModeReadRef & InEnvelopeMode ,
const FBoolReadRef & bInIsAnalog ,
2022-01-18 17:56:27 -05:00
const FBoolReadRef & bInIsUpwards ,
2021-08-04 18:06:59 -04:00
const FFloatReadRef & InWetDryMix )
: AudioInput ( InAudio )
, RatioInput ( InRatio )
2021-08-11 15:04:27 -04:00
, ThresholdDbInput ( InThresholdDb )
2021-08-04 18:06:59 -04:00
, AttackTimeInput ( InAttackTime )
, ReleaseTimeInput ( InReleaseTime )
2022-01-18 17:56:27 -05:00
, LookaheadTimeInput ( InLookaheadTime )
2021-08-04 18:06:59 -04:00
, KneeInput ( InKnee )
, SidechainInput ( InSidechain )
, EnvelopeModeInput ( InEnvelopeMode )
, bIsAnalogInput ( bInIsAnalog )
2022-01-18 17:56:27 -05:00
, bIsUpwardsInput ( bInIsUpwards )
2021-08-04 18:06:59 -04:00
, WetDryMixInput ( InWetDryMix )
, AudioOutput ( FAudioBufferWriteRef : : CreateNew ( InSettings ) )
, EnvelopeOutput ( FAudioBufferWriteRef : : CreateNew ( InSettings ) )
2022-06-15 21:53:48 -04:00
, InputDelay ( FMath : : CeilToInt ( InSettings . GetSampleRate ( ) * Compressor . GetMaxLookaheadMsec ( ) / 1000.f ) + 1 , InSettings . GetSampleRate ( ) * 10.0f / 1000.0f )
, DelayedInputSignal ( InSettings . GetNumFramesPerBlock ( ) )
2021-08-04 18:06:59 -04:00
, bUseSidechain ( bInUseSidechain )
2022-06-15 21:53:48 -04:00
, MsToSamples ( InSettings . GetSampleRate ( ) / 1000.0f )
2021-08-04 18:06:59 -04:00
, PrevAttackTime ( FMath : : Max ( FTime : : ToMilliseconds ( * InAttackTime ) , 0.0 ) )
, PrevReleaseTime ( FMath : : Max ( FTime : : ToMilliseconds ( * InReleaseTime ) , 0.0 ) )
2022-01-18 17:56:27 -05:00
, PrevLookaheadTime ( FMath : : Max ( FTime : : ToMilliseconds ( * InLookaheadTime ) , 0.0 ) )
2021-08-04 18:06:59 -04:00
{
Compressor . Init ( InSettings . GetSampleRate ( ) , 1 ) ;
Compressor . SetKeyNumChannels ( 1 ) ;
2021-08-11 15:04:27 -04:00
Compressor . SetRatio ( FMath : : Max ( * InRatio , 1.0f ) ) ;
Compressor . SetThreshold ( * ThresholdDbInput ) ;
2021-08-04 18:06:59 -04:00
Compressor . SetAttackTime ( PrevAttackTime ) ;
Compressor . SetReleaseTime ( PrevReleaseTime ) ;
2022-01-18 17:56:27 -05:00
Compressor . SetLookaheadMsec ( PrevLookaheadTime ) ;
2021-08-04 18:06:59 -04:00
Compressor . SetKneeBandwidth ( * KneeInput ) ;
2022-01-18 17:56:27 -05:00
if ( * bIsUpwardsInput )
{
Compressor . SetProcessingMode ( Audio : : EDynamicsProcessingMode : : UpwardsCompressor ) ;
}
else
{
Compressor . SetProcessingMode ( Audio : : EDynamicsProcessingMode : : Compressor ) ;
}
2021-08-04 18:06:59 -04:00
switch ( * EnvelopeModeInput )
{
default :
case EEnvelopePeakMode : : MeanSquared :
Compressor . SetPeakMode ( Audio : : EPeakMode : : MeanSquared ) ;
break ;
case EEnvelopePeakMode : : RootMeanSquared :
Compressor . SetPeakMode ( Audio : : EPeakMode : : RootMeanSquared ) ;
break ;
case EEnvelopePeakMode : : Peak :
Compressor . SetPeakMode ( Audio : : EPeakMode : : Peak ) ;
break ;
}
}
static const FNodeClassMetadata & GetNodeInfo ( )
{
auto CreateNodeClassMetadata = [ ] ( ) - > FNodeClassMetadata
{
FVertexInterface NodeInterface = DeclareVertexInterface ( ) ;
FNodeClassMetadata Metadata
{
2021-08-09 16:57:11 -04:00
FNodeClassName { StandardNodes : : Namespace , " Compressor " , StandardNodes : : AudioVariant } ,
2021-08-04 18:06:59 -04:00
1 , // Major Version
0 , // Minor Version
2022-02-10 18:36:47 -05:00
METASOUND_LOCTEXT ( " CompressorDisplayName " , " Compressor " ) ,
METASOUND_LOCTEXT ( " CompressorDesc " , " Lowers the dynamic range of a signal. " ) ,
2021-08-04 18:06:59 -04:00
PluginAuthor ,
PluginNodeMissingPrompt ,
NodeInterface ,
2021-08-09 16:57:11 -04:00
{ NodeCategories : : Dynamics } ,
2022-08-17 16:42:56 -04:00
{ METASOUND_LOCTEXT ( " SidechainKeyword " , " Sidechain " ) , METASOUND_LOCTEXT ( " UpwardsKeyword " , " Upwards Compressor " ) } ,
2021-08-09 16:57:11 -04:00
FNodeDisplayStyle ( )
2021-08-04 18:06:59 -04:00
} ;
return Metadata ;
} ;
static const FNodeClassMetadata Metadata = CreateNodeClassMetadata ( ) ;
return Metadata ;
}
static const FVertexInterface & DeclareVertexInterface ( )
{
using namespace CompressorVertexNames ;
static const FVertexInterface Interface (
FInputVertexInterface (
2022-03-31 16:49:59 -04:00
TInputDataVertex < FAudioBuffer > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputAudio ) ) ,
TInputDataVertex < float > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputRatio ) , 1.5f ) ,
TInputDataVertex < float > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputThreshold ) , - 6.0f ) ,
TInputDataVertex < FTime > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputAttackTime ) , 0.01f ) ,
TInputDataVertex < FTime > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputReleaseTime ) , 0.1f ) ,
TInputDataVertex < FTime > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputLookaheadTime ) , 0.01f ) ,
TInputDataVertex < float > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputKnee ) , 10.0f ) ,
TInputDataVertex < FAudioBuffer > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputSidechain ) ) ,
2023-05-25 18:13:32 -04:00
TInputDataVertex < FEnumEnvelopePeakMode > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputEnvelopeMode ) , ( int32 ) EEnvelopePeakMode : : Peak ) ,
2022-03-31 16:49:59 -04:00
TInputDataVertex < bool > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputIsAnalog ) , true ) ,
TInputDataVertex < bool > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputIsUpwards ) , false ) ,
TInputDataVertex < float > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputWetDryMix ) , 1.0f )
2021-08-04 18:06:59 -04:00
) ,
FOutputVertexInterface (
2022-03-31 16:49:59 -04:00
TOutputDataVertex < FAudioBuffer > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputAudio ) ) ,
TOutputDataVertex < FAudioBuffer > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputEnvelope ) )
2021-08-04 18:06:59 -04:00
)
) ;
return Interface ;
}
2023-05-22 13:28:27 -04:00
virtual void BindInputs ( FInputVertexInterfaceData & InOutVertexData ) override
2021-08-04 18:06:59 -04:00
{
using namespace CompressorVertexNames ;
2023-05-22 13:28:27 -04:00
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputAudio ) , AudioInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputRatio ) , RatioInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputThreshold ) , ThresholdDbInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputAttackTime ) , AttackTimeInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputReleaseTime ) , ReleaseTimeInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputLookaheadTime ) , LookaheadTimeInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputKnee ) , KneeInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputSidechain ) , SidechainInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputEnvelopeMode ) , EnvelopeModeInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputIsUpwards ) , bIsUpwardsInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputIsAnalog ) , bIsAnalogInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputWetDryMix ) , WetDryMixInput ) ;
}
2021-08-04 18:06:59 -04:00
2023-05-22 13:28:27 -04:00
virtual void BindOutputs ( FOutputVertexInterfaceData & InOutVertexData ) override
{
using namespace CompressorVertexNames ;
2021-08-04 18:06:59 -04:00
2023-05-22 13:28:27 -04:00
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( OutputAudio ) , AudioOutput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( OutputEnvelope ) , EnvelopeOutput ) ;
}
2021-08-04 18:06:59 -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 { } ;
2021-08-04 18:06:59 -04:00
}
virtual FDataReferenceCollection GetOutputs ( ) const override
{
2023-05-22 13:28:27 -04:00
// 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-08-04 18:06:59 -04:00
}
static TUniquePtr < IOperator > CreateOperator ( const FCreateOperatorParams & InParams , FBuildErrorArray & OutErrors )
{
using namespace CompressorVertexNames ;
const FDataReferenceCollection & Inputs = InParams . InputDataReferences ;
const FInputVertexInterface & InputInterface = DeclareVertexInterface ( ) . GetInputInterface ( ) ;
FAudioBufferReadRef AudioIn = Inputs . GetDataReadReferenceOrConstruct < FAudioBuffer > ( METASOUND_GET_PARAM_NAME ( InputAudio ) , InParams . OperatorSettings ) ;
FFloatReadRef RatioIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < float > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputRatio ) , InParams . OperatorSettings ) ;
2021-08-11 15:04:27 -04:00
FFloatReadRef ThresholdDbIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < float > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputThreshold ) , InParams . OperatorSettings ) ;
2021-08-04 18:06:59 -04:00
FTimeReadRef AttackTimeIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < FTime > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputAttackTime ) , InParams . OperatorSettings ) ;
FTimeReadRef ReleaseTimeIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < FTime > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputReleaseTime ) , InParams . OperatorSettings ) ;
2022-01-18 17:56:27 -05:00
FTimeReadRef LookaheadTimeIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < FTime > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputLookaheadTime ) , InParams . OperatorSettings ) ;
2021-08-04 18:06:59 -04:00
FFloatReadRef KneeIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < float > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputKnee ) , InParams . OperatorSettings ) ;
FAudioBufferReadRef SidechainIn = Inputs . GetDataReadReferenceOrConstruct < FAudioBuffer > ( METASOUND_GET_PARAM_NAME ( InputSidechain ) , InParams . OperatorSettings ) ;
2023-05-25 18:13:32 -04:00
FEnvelopePeakModeReadRef EnvelopeModeIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < FEnumEnvelopePeakMode > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputEnvelopeMode ) , InParams . OperatorSettings ) ;
2021-08-04 18:06:59 -04:00
FBoolReadRef bIsAnalogIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < bool > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputIsAnalog ) , InParams . OperatorSettings ) ;
2022-01-18 17:56:27 -05:00
FBoolReadRef bIsUpwardsIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < bool > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputIsUpwards ) , InParams . OperatorSettings ) ;
2021-08-04 18:06:59 -04:00
FFloatReadRef WetDryMixIn = Inputs . GetDataReadReferenceOrConstructWithVertexDefault < float > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputWetDryMix ) , InParams . OperatorSettings ) ;
bool bIsSidechainConnected = Inputs . ContainsDataReadReference < FAudioBuffer > ( METASOUND_GET_PARAM_NAME ( InputSidechain ) ) ;
2022-01-18 17:56:27 -05:00
return MakeUnique < FCompressorOperator > ( InParams . OperatorSettings , AudioIn , RatioIn , ThresholdDbIn , AttackTimeIn , ReleaseTimeIn , LookaheadTimeIn , KneeIn , bIsSidechainConnected , SidechainIn , EnvelopeModeIn , bIsAnalogIn , bIsUpwardsIn , WetDryMixIn ) ;
2021-08-04 18:06:59 -04:00
}
2023-03-02 14:40:35 -05:00
void Reset ( const IOperator : : FResetParams & InParams )
{
// Flush audio buffers
AudioOutput - > Zero ( ) ;
EnvelopeOutput - > Zero ( ) ;
InputDelay . Reset ( ) ;
DelayedInputSignal . Zero ( ) ;
// Cache dynamics timing
PrevAttackTime = FMath : : Max ( FTime : : ToMilliseconds ( * AttackTimeInput ) , 0.0 ) ;
PrevReleaseTime = FMath : : Max ( FTime : : ToMilliseconds ( * ReleaseTimeInput ) , 0.0 ) ;
PrevLookaheadTime = FMath : : Max ( FTime : : ToMilliseconds ( * LookaheadTimeInput ) , 0.0 ) ;
// Initialize compressor
Compressor . Init ( InParams . OperatorSettings . GetSampleRate ( ) , 1 ) ;
Compressor . SetKeyNumChannels ( 1 ) ;
Compressor . SetRatio ( FMath : : Max ( * RatioInput , 1.0f ) ) ;
Compressor . SetThreshold ( * ThresholdDbInput ) ;
Compressor . SetAttackTime ( PrevAttackTime ) ;
Compressor . SetReleaseTime ( PrevReleaseTime ) ;
Compressor . SetLookaheadMsec ( PrevLookaheadTime ) ;
Compressor . SetKneeBandwidth ( * KneeInput ) ;
if ( * bIsUpwardsInput )
{
Compressor . SetProcessingMode ( Audio : : EDynamicsProcessingMode : : UpwardsCompressor ) ;
}
else
{
Compressor . SetProcessingMode ( Audio : : EDynamicsProcessingMode : : Compressor ) ;
}
switch ( * EnvelopeModeInput )
{
default :
case EEnvelopePeakMode : : MeanSquared :
Compressor . SetPeakMode ( Audio : : EPeakMode : : MeanSquared ) ;
break ;
case EEnvelopePeakMode : : RootMeanSquared :
Compressor . SetPeakMode ( Audio : : EPeakMode : : RootMeanSquared ) ;
break ;
case EEnvelopePeakMode : : Peak :
Compressor . SetPeakMode ( Audio : : EPeakMode : : Peak ) ;
break ;
}
}
2021-08-04 18:06:59 -04:00
void Execute ( )
{
/* Update parameters */
// For a compressor, ratio values should be 1 or greater
Compressor . SetRatio ( FMath : : Max ( * RatioInput , 1.0f ) ) ;
2022-01-18 17:56:27 -05:00
Compressor . SetThreshold ( * ThresholdDbInput ) ;
2021-08-11 15:04:27 -04:00
2021-08-04 18:06:59 -04:00
// Attack time cannot be negative
2022-01-18 17:56:27 -05:00
float CurrAttack = FMath : : Max ( FTime : : ToMilliseconds ( * AttackTimeInput ) , 0.0f ) ;
2022-01-13 13:03:34 -05:00
if ( FMath : : IsNearlyEqual ( CurrAttack , PrevAttackTime ) = = false )
2021-08-11 15:04:27 -04:00
{
Compressor . SetAttackTime ( CurrAttack ) ;
2022-01-18 17:56:27 -05:00
PrevAttackTime = CurrAttack ;
2021-08-11 15:04:27 -04:00
}
2022-01-18 17:56:27 -05:00
2021-08-04 18:06:59 -04:00
// Release time cannot be negative
2022-01-18 17:56:27 -05:00
float CurrRelease = FMath : : Max ( FTime : : ToMilliseconds ( * ReleaseTimeInput ) , 0.0f ) ;
2022-01-13 13:03:34 -05:00
if ( FMath : : IsNearlyEqual ( CurrRelease , PrevReleaseTime ) = = false )
2021-08-04 18:06:59 -04:00
{
Compressor . SetReleaseTime ( CurrRelease ) ;
2022-01-18 17:56:27 -05:00
PrevReleaseTime = CurrRelease ;
}
2022-06-15 21:53:48 -04:00
float CurrLookahead = FMath : : Clamp ( FTime : : ToMilliseconds ( * LookaheadTimeInput ) , 0.0f , Compressor . GetMaxLookaheadMsec ( ) ) ;
2022-01-18 17:56:27 -05:00
if ( FMath : : IsNearlyEqual ( CurrLookahead , PrevLookaheadTime ) = = false )
{
Compressor . SetLookaheadMsec ( CurrLookahead ) ;
PrevLookaheadTime = CurrLookahead ;
2021-08-04 18:06:59 -04:00
}
2022-06-15 21:53:48 -04:00
InputDelay . SetDelayLengthSamples ( CurrLookahead * MsToSamples ) ;
2021-08-11 15:04:27 -04:00
Compressor . SetKneeBandwidth ( * KneeInput ) ;
2022-01-18 17:56:27 -05:00
if ( * bIsUpwardsInput )
{
Compressor . SetProcessingMode ( Audio : : EDynamicsProcessingMode : : UpwardsCompressor ) ;
}
else
{
Compressor . SetProcessingMode ( Audio : : EDynamicsProcessingMode : : Compressor ) ;
}
2021-08-11 15:04:27 -04:00
switch ( * EnvelopeModeInput )
2021-08-04 18:06:59 -04:00
{
2021-08-11 15:04:27 -04:00
default :
case EEnvelopePeakMode : : MeanSquared :
Compressor . SetPeakMode ( Audio : : EPeakMode : : MeanSquared ) ;
break ;
case EEnvelopePeakMode : : RootMeanSquared :
Compressor . SetPeakMode ( Audio : : EPeakMode : : RootMeanSquared ) ;
break ;
case EEnvelopePeakMode : : Peak :
Compressor . SetPeakMode ( Audio : : EPeakMode : : Peak ) ;
break ;
2021-08-04 18:06:59 -04:00
}
2022-06-15 21:53:48 -04:00
// Apply lookahead delay to dry signal
InputDelay . ProcessAudio ( * AudioInput , DelayedInputSignal ) ;
2021-08-04 18:06:59 -04:00
if ( bUseSidechain )
{
2021-08-09 17:10:15 -04:00
Compressor . ProcessAudio ( AudioInput - > GetData ( ) , AudioInput - > Num ( ) , AudioOutput - > GetData ( ) , SidechainInput - > GetData ( ) , EnvelopeOutput - > GetData ( ) ) ;
2021-08-04 18:06:59 -04:00
}
else
{
2021-08-09 17:10:15 -04:00
Compressor . ProcessAudio ( AudioInput - > GetData ( ) , AudioInput - > Num ( ) , AudioOutput - > GetData ( ) , nullptr , EnvelopeOutput - > GetData ( ) ) ;
2021-08-04 18:06:59 -04:00
}
// Calculate Wet/Dry mix
float NewWetDryMix = FMath : : Clamp ( * WetDryMixInput , 0.0f , 1.0f ) ;
// Wet signal
Audio : : ArrayMultiplyByConstantInPlace ( * AudioOutput , NewWetDryMix ) ;
// Add Dry signal
2022-06-15 21:53:48 -04:00
Audio : : ArrayMultiplyAddInPlace ( DelayedInputSignal , 1.0f - NewWetDryMix , * AudioOutput ) ;
2021-08-04 18:06:59 -04:00
}
private :
// Audio input and output
FAudioBufferReadRef AudioInput ;
FFloatReadRef RatioInput ;
2021-08-11 15:04:27 -04:00
FFloatReadRef ThresholdDbInput ;
2021-08-04 18:06:59 -04:00
FTimeReadRef AttackTimeInput ;
FTimeReadRef ReleaseTimeInput ;
2022-01-18 17:56:27 -05:00
FTimeReadRef LookaheadTimeInput ;
2021-08-04 18:06:59 -04:00
FFloatReadRef KneeInput ;
FAudioBufferReadRef SidechainInput ;
FEnvelopePeakModeReadRef EnvelopeModeInput ;
FBoolReadRef bIsAnalogInput ;
2022-01-18 17:56:27 -05:00
FBoolReadRef bIsUpwardsInput ;
2021-08-04 18:06:59 -04:00
FFloatReadRef WetDryMixInput ;
FAudioBufferWriteRef AudioOutput ;
// The gain being applied to the input buffer
FAudioBufferWriteRef EnvelopeOutput ;
// Internal DSP Compressor
Audio : : FDynamicsProcessor Compressor ;
2022-06-15 21:53:48 -04:00
// Compressor does not have a wet/dry signal built in, so
// we need to account for lookahead delay in the input to prevent phase issues.
Audio : : FIntegerDelay InputDelay ;
FAudioBuffer DelayedInputSignal ;
2021-08-04 18:06:59 -04:00
// Whether or not to use sidechain input (is false if no input pin is connected to sidechain input)
bool bUseSidechain ;
2022-06-15 21:53:48 -04:00
// Conversion from milliseconds to samples
float MsToSamples ;
2021-08-04 18:06:59 -04:00
// Cached variables
2022-01-18 17:56:27 -05:00
float PrevAttackTime ;
float PrevReleaseTime ;
float PrevLookaheadTime ;
2021-08-04 18:06:59 -04:00
} ;
// Node Class
class FCompressorNode : public FNodeFacade
{
public :
FCompressorNode ( const FNodeInitData & InitData )
: FNodeFacade ( InitData . InstanceName , InitData . InstanceID , TFacadeOperatorClass < FCompressorOperator > ( ) )
{
}
} ;
// Register node
METASOUND_REGISTER_NODE ( FCompressorNode )
}
# undef LOCTEXT_NAMESPACE