1+ #include " noise_gate_module.h"
2+ #include < q/fx/envelope.hpp>
3+
4+ using namespace bkshepherd ;
5+
6+ // The threshold knob/parameter will generate a float between 0 and 1 which gets
7+ // multiplied by this value to be used as the threshold against the audio input
8+ // signal
9+ const float maxThreshold = 0.2 ;
10+
11+ // These are placeholder values that will get overwritten with the attack and release parameters at initialization
12+ cycfi::q::ar_envelope_follower env_follower (48000.0 , 0 .002f , 0 .020f );
13+
14+ static const int s_paramCount = 5 ;
15+ static const ParameterMetaData s_metaData[s_paramCount] = {{
16+ name : " Threshold" ,
17+ valueType : ParameterValueType::Float,
18+ valueBinCount : 0 ,
19+ defaultValue : {.float_value = 0 .5f },
20+ knobMapping : 0 ,
21+ midiCCMapping : -1
22+ },
23+ {
24+ name : " Atk [ms]" ,
25+ valueType : ParameterValueType::Float,
26+ valueBinCount : 0 ,
27+ defaultValue : {.float_value = 1 .0f },
28+ knobMapping : 1 ,
29+ midiCCMapping : -1 ,
30+ minValue : static_cast <int >(1 ),
31+ maxValue : static_cast <int >(20 )
32+ },
33+ {
34+ name : " Rel [ms]" ,
35+ valueType : ParameterValueType::Float,
36+ valueBinCount : 0 ,
37+ defaultValue : {.float_value = 50 .0f },
38+ knobMapping : 2 ,
39+ midiCCMapping : -1 ,
40+ minValue : static_cast <int >(1 ),
41+ maxValue : static_cast <int >(500 )
42+ },
43+ {
44+ name : " Hold [ms]" ,
45+ valueType : ParameterValueType::Float,
46+ valueBinCount : 0 ,
47+ defaultValue : {.float_value = 50 .0f },
48+ knobMapping : 3 ,
49+ midiCCMapping : -1 ,
50+ minValue : static_cast <int >(0 ),
51+ maxValue : static_cast <int >(1000 )
52+ },
53+ {
54+ name : " Fade [ms]" ,
55+ valueType : ParameterValueType::Float,
56+ valueBinCount : 0 ,
57+ defaultValue : {.float_value = 200 .0f },
58+ knobMapping : 4 ,
59+ midiCCMapping : -1 ,
60+ minValue : static_cast <int >(0 ),
61+ maxValue : static_cast <int >(500 )
62+ }};
63+
64+ // Default Constructor
65+ NoiseGateModule::NoiseGateModule () : BaseEffectModule() {
66+ // Set the name of the effect
67+ m_name = " Noise Gate" ;
68+
69+ // Setup the meta data reference for this Effect
70+ m_paramMetaData = s_metaData;
71+
72+ // Initialize Parameters for this Effect
73+ this ->InitParams (s_paramCount);
74+ }
75+
76+ // Destructor
77+ NoiseGateModule::~NoiseGateModule () {
78+ // No Code Needed
79+ }
80+
81+ void NoiseGateModule::Init (float sample_rate) {
82+ BaseEffectModule::Init (sample_rate);
83+
84+ env_follower.config (GetParameterAsFloat (1 ) / 1000 .f , GetParameterAsFloat (2 ) / 1000 .f , sample_rate);
85+ }
86+
87+ void NoiseGateModule::ParameterChanged (int parameter_id) {
88+ switch (parameter_id) {
89+ case 1 :
90+ env_follower.attack (GetParameterAsFloat (1 ) / 1000 .f , GetSampleRate ());
91+ break ;
92+ case 2 :
93+ env_follower.release (GetParameterAsFloat (2 ) / 1000 .f , GetSampleRate ());
94+ break ;
95+ }
96+ }
97+
98+ void NoiseGateModule::ProcessMono (float in) {
99+ // Update envelope follower with input signal
100+ const float raw_env_level = env_follower (std::abs (in));
101+
102+ // Run a smoothing filter on the envelope to prevent crackling due to rapid adjustments of the envelope state
103+ const float currentTimeInSeconds = static_cast <float >(daisy::System::GetNow ()) / 1000 .f ;
104+ const float smoothed_env_level = m_smoothingFilter (raw_env_level, currentTimeInSeconds);
105+
106+ if (smoothed_env_level > GetParameterAsFloat (0 ) * maxThreshold) {
107+ // Signal is above the threshold, open the gate and reset the timer
108+ m_gateOpen = true ;
109+ m_holdTimer = 0 .0f ;
110+ m_currentGain = 1 .0f ; // Fully open
111+ } else if (m_gateOpen) {
112+ // Signal is below the threshold but within hold time
113+
114+ const float dt = currentTimeInSeconds - m_prevTimeSeconds;
115+ m_holdTimer += dt;
116+
117+ if (m_holdTimer >= (GetParameterAsFloat (3 ) / 1000 .0f )) {
118+ // Gate is closing: start fading out
119+ const float fadeOutStep = dt / (GetParameterAsFloat (4 ) / 1000 .0f );
120+ m_currentGain -= fadeOutStep;
121+ if (m_currentGain <= 0 .0f ) {
122+ m_currentGain = 0 .0f ;
123+ m_gateOpen = false ;
124+ }
125+ }
126+ }
127+
128+ m_prevTimeSeconds = currentTimeInSeconds;
129+
130+ // Apply noise gate using the smoothed envelope value and hold time, and
131+ // also the current gain value (used for fade)
132+ const float out = m_gateOpen ? in * m_currentGain : 0 .0f ;
133+
134+ m_audioLeft = out;
135+ m_audioRight = m_audioLeft;
136+ }
137+
138+ void NoiseGateModule::ProcessStereo (float inL, float inR) {
139+ // Calculate the mono effect
140+ ProcessMono (inL);
141+ }
142+
143+ float NoiseGateModule::GetBrightnessForLED (int led_id) const {
144+ float value = BaseEffectModule::GetBrightnessForLED (led_id);
145+
146+ if (led_id == 1 ) {
147+ return m_gateOpen ? 1 .0f : 0 .0f ;
148+ }
149+
150+ return value;
151+ }
0 commit comments