[SCM] calf/master: Add Sidechain Gate, rename Gate to Expander, cleanups etc.

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:40:19 UTC 2013


The following commit has been merged in the master branch:
commit fd70348c38a139e6f90a7a20f833b5eb2b926694
Author: Markus Schmidt <schmidt at boomshop.net>
Date:   Sun Aug 22 22:16:57 2010 +0100

    Add Sidechain Gate, rename Gate to Expander, cleanups etc.

diff --git a/gui/gui-gate.xml b/gui/gui-gate.xml
index ed18105..325e2b7 100644
--- a/gui/gui-gate.xml
+++ b/gui/gui-gate.xml
@@ -1,78 +1,100 @@
-<table border="10" rows="4" cols="1">
-    <hbox attach-x="0" attach-y="0" shrink-y="1" expand-y="0">
-    	<vbox expand="0">
-             <label param="bypass"/>
-             <align><toggle param="bypass" shrink="1"/></align>
+<hbox spacing="10">
+
+    <vbox spacing="20" expand="0" fill="0">
+        <vbox expand="0" fill="0" spacing="7" >
+            <label param="bypass" expand="0" fill="0" />
+            <align><toggle param="bypass" shrink="1" size="2"/></align>
         </vbox>
-    	<vbox expand="0">
-             <label param="trigger"/>
-             <align><toggle param="trigger" shrink="1"/></align>
+        <vbox expand="0" fill="0" spacing="7">
+            <label param="range" expand="0" fill="0" expand-y="0" fill-y="0" />
+            <knob param="range" size="5" expand="1" fill="1" />
+            <value param="range" />
         </vbox>
-    	<vbox expand="0">
-             <label param="detection"/>
-             <combo param="detection"/>
+        <vbox expand="1" fill="1">
+            <label expand="1" fill="1" />
         </vbox>
-    	<vbox expand="0">
-             <label param="stereo_link"/>
-             <combo param="stereo_link"/>
+    </vbox>
+
+    <vbox spacing="5">
+        <frame label="Gate">
+            <vbox spacing="5">
+                <table expand="0" fill="0" rows="3" cols="3">
+                    <label param="meter_in" expand-x="0" fill-x="0" attach-x="0" attach-y="0" />
+                    <vumeter param="meter_in" mode="0" hold="1.5" falloff="2.5" attach-x="1" attach-y="0" expand-x="1" fill-x="1" />
+                    <led param="clip_in" mode="0" expand-x="0" fill-x="0" attach-x="2" attach-y="0" />
+                    
+                    <label param="meter_out" expand-x="0" fill-x="0" attach-x="0" attach-y="1" />
+                    <vumeter param="meter_out" mode="0" hold="1.5" falloff="2.5" attach-x="1" attach-y="1" expand-x="1" fill-x="1" />
+                    <led param="clip_out" mode="1" expand-x="0" fill-x="0" attach-x="2" attach-y="1" />
+                    
+                    <label param="gating" expand-x="0" fill-x="0" attach-x="0" attach-y="2" />
+                    <vumeter param="gating" mode="2" hold="1.5" expand-x="1" fill-x="1" attach-x="1" attach-y="2" attach-w="2" />
+                </table>
+                
+                <table expand="1" rows="2" cols="3" homogeneous="1">
+                    <vbox expand="0" attach-x="0" attach-y="0">
+                        <label param="attack" />
+                        <knob param="attack" />
+                        <value param="attack" />
+                    </vbox>
+                    <vbox expand="0" attach-x="1" attach-y="0">
+                        <label param="release" />
+                        <knob param="release" />
+                        <value param="release" />
+                    </vbox>
+                    <vbox expand="0" attach-x="2" attach-y="0">
+                        <label param="knee" />
+                        <knob param="knee" />
+                        <value param="knee" />
+                    </vbox>
+                    <vbox expand="0" attach-x="0" attach-y="1">
+                        <label param="ratio" />
+                        <knob param="ratio" />
+                        <value param="ratio" />
+                    </vbox>
+                    <vbox expand="0" attach-x="1" attach-y="1">
+                        <label param="threshold" />
+                        <knob param="threshold"/>
+                        <value param="threshold" />
+                    </vbox>
+                    <vbox expand="0" attach-x="2" attach-y="1">
+                        <label param="makeup" />
+                        <knob param="makeup" />
+                        <value param="makeup" />
+                    </vbox>
+                </table>
+            </vbox>
+        </frame>
+        <frame label="Options">
+            <vbox spacing="10" pad-x="5" fill-y="0" expand-y="0">
+                <vbox expand="1" expand-y="0" expand-x="1" fill-x="1">
+                    <label param="stereo_link" expand-y="0" fill-y="0"/>
+                    <align>
+                        <hbox expand="0" fill-y="0" expand-x="1" fill-x="1">
+                            <radio param="stereo_link" value="Average" expand-x="1" fill-x="1"/>
+                            <radio param="stereo_link" value="Maximum" expand-x="1" fill-x="1"/>
+                        </hbox>
+                    </align>
+                </vbox>
+                <vbox expand="1" expand-y="0">
+                    <label param="detection" expand-y="0" fill-y="0" expand-x="1" fill-x="1"/>
+                    <align>
+                        <hbox expand="0" fill-y="0" expand-x="1" fill-x="1" >
+                            <radio param="detection" value="RMS" expand-x="1" fill-x="1"/>
+                            <radio param="detection" value="Peak" expand-x="1" fill-x="1"/>
+                        </hbox>
+                    </align>
+                </vbox>
+            </vbox>
+        </frame>
+    </vbox>
+    
+    
+      <frame label="Gating">
+        <vbox >
+            <if cond="directlink">
+                <line-graph refresh="1" width="340" height="340" param="gating" square="1" expand="1" fill="1"/>
+            </if>
         </vbox>
-    	<vbox expand="0">
-             <label param="aweighting"/>
-             <combo param="aweighting"/>
-        </vbox>
-    </hbox>
-    <if cond="directlink">
-        <line-graph attach-x="0" attach-y="1" refresh="1" width="384" height="384" param="gating" square="1" expand-y="1" fill-y="1"/>
-    </if>
-    <table attach-x="0" attach-y="2" expand-y="0" expand-x="1" spacing="10" rows="1" cols="3">
-        <vbox expand-x="1" fill-x="1" expand="1" fill="1" attach-x="0" attach-y="0">
-            <label param="gating" />
-            <vumeter param="gating" mode="1" />
-        </vbox>
-        <vbox shrink-x="1" expand-x="0" fill-x="0" expand="0" fill="0" attach-x="1" attach-y="0">
-            <label param="clip" expand="0" fill="0" />
-            <led param="clip" expand="0" fill="0" />
-        </vbox>
-        <vbox expand-x="1" fill-x="1" expand="1" fill="1" attach-x="2" attach-y="0">
-            <label param="peak" />
-            <vumeter param="peak" mode="0" shrink-y="0" />
-        </vbox>
-    </table>
-    <hbox attach-x="0" attach-y="3" expand-y="0">
-        <vbox border="10" expand="0">
-            <label param="attack" />
-            <knob param="attack" />
-            <value param="attack" />
-        </vbox>
-        <vbox border="10" expand="0">
-            <label param="release" />
-            <knob param="release" />
-            <value param="release" />
-        </vbox>
-        <vbox border="10" expand="0">
-            <label param="threshold" />
-            <knob param="threshold"/>
-            <value param="threshold" />
-        </vbox>
-        <vbox border="10" expand="0">
-            <label param="ratio" />
-            <knob param="ratio" />
-            <value param="ratio" />
-        </vbox>
-	<vbox border="10" expand="0">
-	    <label param="range" />
-	    <knob param="range" />
-	    <value param="range" />
-	</vbox>
-        <vbox border="10" expand="0">
-            <label param="makeup" />
-            <knob param="makeup" />
-            <value param="makeup" />
-        </vbox>
-        <vbox border="10" expand="0">
-            <label param="knee" />
-            <knob param="knee" />
-            <value param="knee" />
-        </vbox>
-    </hbox>
-</table>
+      </frame>
+</hbox>
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index de17490..1c2e1f9 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -197,6 +197,28 @@ struct deesser_metadata: public plugin_metadata<deesser_metadata>
     PLUGIN_NAME_ID_LABEL("deesser", "deesser", "Deesser")
 };
 
+/// Damiens' Gate - metadata
+/// Added some meters and stripped the weighting part
+struct gate_metadata: public plugin_metadata<gate_metadata>
+{
+    enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
+    enum { param_bypass, param_level_in, param_meter_in, param_meter_out, param_clip_in, param_clip_out,
+           param_range, param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_gating, 
+           param_count };
+    PLUGIN_NAME_ID_LABEL("gate", "gate", "Gate")
+};
+
+/// Markus's sidechain gate - metadata
+struct sidechaingate_metadata: public plugin_metadata<sidechaingate_metadata>
+{
+    enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
+    enum { param_bypass, param_level_in, param_meter_in, param_meter_out, param_clip_in, param_clip_out,
+           param_range, param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_gating, 
+           param_sc_mode, param_f1_freq, param_f2_freq, param_f1_level, param_f2_level,
+           param_sc_listen, param_f1_active, param_f2_active, param_count };
+    PLUGIN_NAME_ID_LABEL("sidechaingate", "sidechaingate", "Sidechain Gate")
+};
+
 /// Markus's 5-band EQ - metadata
 struct equalizer5band_metadata: public plugin_metadata<equalizer5band_metadata>
 {
@@ -295,15 +317,6 @@ struct bassenhancer_metadata: public plugin_metadata<bassenhancer_metadata>
     PLUGIN_NAME_ID_LABEL("bassenhancer", "bassenhancer", "Bass Enhancer")
 };
 
-/// Damien's gate - metadata
-struct gate_metadata: public plugin_metadata<gate_metadata>
-{
-    enum { in_count = 3, out_count = 2, ins_optional = 1, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
-    enum { param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_aweighting, param_gating, param_peak, param_clip, param_bypass, param_range, param_mono, param_trigger, // param_freq, param_bw,
-        param_count };
-    PLUGIN_NAME_ID_LABEL("gate", "gate", "Gate")
-};
-
 /// Organ - enums for parameter IDs etc. (this mess is caused by organ split between plugin and generic class - which was
 /// a bad design decision and should be sorted out some day) XXXKF @todo
 struct organ_enums
diff --git a/src/calf/modulelist.h b/src/calf/modulelist.h
index baaa5d9..85dead8 100644
--- a/src/calf/modulelist.h
+++ b/src/calf/modulelist.h
@@ -13,6 +13,8 @@
     PER_MODULE_ITEM(sidechaincompressor, false, "sidechaincompressor")
     PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
     PER_MODULE_ITEM(deesser, false, "deesser")
+    PER_MODULE_ITEM(gate, false, "gate")
+    PER_MODULE_ITEM(sidechaingate, false, "sidechaingate")
     PER_MODULE_ITEM(pulsator, false, "pulsator")
     PER_MODULE_ITEM(equalizer5band, false, "eq5")
     PER_MODULE_ITEM(equalizer8band, false, "eq8")
@@ -20,7 +22,6 @@
     PER_MODULE_ITEM(saturator, false, "saturator")
     PER_MODULE_ITEM(exciter, false, "exciter")
     PER_MODULE_ITEM(bassenhancer, false, "bassenhancer")
-    PER_MODULE_ITEM(gate, false, "gate")
 #ifdef ENABLE_EXPERIMENTAL
     PER_MODULE_ITEM(fluidsynth, true, "fluidsynth")
     PER_MODULE_ITEM(wavetable, true, "wavetable")
diff --git a/src/calf/modules_comp.h b/src/calf/modules_comp.h
index 1c85820..934b289 100644
--- a/src/calf/modules_comp.h
+++ b/src/calf/modules_comp.h
@@ -33,6 +33,8 @@
 namespace calf_plugins {
 
 /// Not a true _audio_module style class, just pretends to be one!
+/// Main gain reduction routine by Thor called by various audio modules
+
 class gain_reduction_audio_module
 {
 private:
@@ -62,6 +64,35 @@ public:
     int  get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
 };
 
+/// Not a true _audio_module style class, just pretends to be one!
+/// Main gate routine by Damien called by various audio modules
+class expander_audio_module {
+private:
+    float linSlope, peak, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop, linKneeStop;
+    float compressedKneeStop, adjKneeStart, range, thres, attack_coeff, release_coeff;
+    float attack, release, threshold, ratio, knee, makeup, detection, stereo_link, bypass, mute, meter_out, meter_gate;
+    mutable float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_range, old_trigger, old_mute, old_detection, old_stereo_link;
+    mutable volatile int last_generation;
+    inline float output_level(float slope) const;
+    inline float output_gain(float linSlope, bool rms) const;
+public:
+    uint32_t srate;
+    bool is_active;
+    expander_audio_module();
+    void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu, float ran);
+    void update_curve();
+    void process(float &left, float &right, const float *det_left = NULL, const float *det_right = NULL);
+    void activate();
+    void deactivate();
+    void set_sample_rate(uint32_t sr);
+    float get_output_level();
+    float get_expander_level();
+    bool get_graph(int subindex, float *data, int points, cairo_iface *context) const;
+    bool get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context) const;
+    bool get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
+    int  get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
+};
+
 /// Compressor by Thor
 class compressor_audio_module: public audio_module<compressor_metadata>, public line_graph_iface  {
 private:
@@ -130,7 +161,7 @@ public:
     int  get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
 };
 
-/// Multibandcompressor by Markus Schmidt
+/// Multibandcompressor by Markus Schmidt (based on Thor's compressor and Krzysztof's filters)
 class multibandcompressor_audio_module: public audio_module<multibandcompressor_metadata>, public line_graph_iface {
 private:
     typedef multibandcompressor_audio_module AM;
@@ -190,60 +221,74 @@ public:
     int  get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
 };
 
-
-class gate_audio_module: public audio_module<gate_metadata>, public line_graph_iface {
+/// Gate by Damien
+class gate_audio_module: public audio_module<gate_metadata>, public line_graph_iface  {
 private:
-    float linSlope, peak, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop, linKneeStop, threshold, ratio, knee, makeup, compressedKneeStop, adjKneeStart, range;
-    mutable float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_range, old_trigger, old_mono;
-    mutable volatile int last_generation;
-    uint32_t clip;
-    dsp::aweighter awL, awR;
-    dsp::biquad_d2<float> bpL, bpR;
+    typedef gate_audio_module AM;
+    uint32_t clip_in, clip_out;
+    float meter_in, meter_out;
+    expander_audio_module gate;
 public:
+    typedef std::complex<double> cfloat;
     uint32_t srate;
     bool is_active;
+    mutable volatile int last_generation, last_calculated_generation;
     gate_audio_module();
     void activate();
     void deactivate();
+    void params_changed();
+    void set_sample_rate(uint32_t sr);
     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
+    bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
+    bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
+    bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
+    int  get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
+};
 
-    inline float output_level(float slope) const {
-        bool rms = *params[param_detection] == 0;
-        return slope * output_gain(rms ? slope*slope : slope, rms) * makeup;
-    }
-
-    inline float output_gain(float linSlope, bool rms) const {
-        if(linSlope < linKneeStop) {
-            float slope = log(linSlope);
-
-            //float tratio = rms ? sqrt(ratio) : ratio;
-            float tratio = ratio;
-            float gain = 0.f;
-            float delta = 0.f;
-	    if(IS_FAKE_INFINITY(ratio))
-	        tratio = 1000.f;
-            gain = (slope-threshold) * tratio + threshold;
-            delta = tratio;
-
-            if(knee > 1.f && slope > kneeStart ) {
-		gain = dsp::hermite_interpolation(slope, kneeStart, kneeStop, ((kneeStart - threshold) * tratio  + threshold), kneeStop, delta,1.f);
-	    }
-	    return std::max(range, expf(gain-slope));
-	}
-
-
-        return 1.f;
-    }
-
+/// Sidecain Gate by Markus Schmidt (based on Damiens's gate and Krzysztof's filters)
+class sidechaingate_audio_module: public audio_module<sidechaingate_metadata>, public frequency_response_line_graph  {
+private:
+    typedef sidechaingate_audio_module AM;
+    enum CalfScModes {
+        WIDEBAND,
+        HIGHGATE_WIDE,
+        HIGHGATE_SPLIT,
+        LOWGATE_WIDE,
+        LOWGATE_SPLIT,
+        WEIGHTED_1,
+        WEIGHTED_2,
+        WEIGHTED_3,
+        BANDPASS_1,
+        BANDPASS_2
+    };
+    mutable float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old;
+    mutable float f1_freq_old1, f2_freq_old1, f1_level_old1, f2_level_old1;
+    CalfScModes sc_mode;
+    mutable CalfScModes sc_mode_old, sc_mode_old1;
+    float f1_active, f2_active;
+    uint32_t clip_in, clip_out;
+    float meter_in, meter_out;
+    expander_audio_module gate;
+    dsp::biquad_d2<float> f1L, f1R, f2L, f2R;
+public:
+    typedef std::complex<double> cfloat;
+    uint32_t srate;
+    bool is_active;
+    mutable volatile int last_generation, last_calculated_generation;
+    sidechaingate_audio_module();
+    void activate();
+    void deactivate();
+    void params_changed();
+    cfloat h_z(const cfloat &z) const;
+    float freq_gain(int index, double freq, uint32_t sr) const;
     void set_sample_rate(uint32_t sr);
-
-    virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
-    virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
-    virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
-    virtual int  get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
+    uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
+    bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
+    bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
+    bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
+    int  get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const;
 };
 
-
 };
 
 #endif
diff --git a/src/metadata.cpp b/src/metadata.cpp
index 4bfc377..d655a48 100644
--- a/src/metadata.cpp
+++ b/src/metadata.cpp
@@ -400,6 +400,83 @@ CALF_PORT_PROPS(deesser) = {
 CALF_PLUGIN_INFO(deesser) = { 0x8515, "Deesser", "Calf Deesser", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
+
+CALF_PORT_NAMES(gate) = {"In L", "In R", "Out L", "Out R"};
+
+const char *gate_detection_names[] = { "RMS", "Peak" };
+const char *gate_stereo_link_names[] = { "Average", "Maximum" };
+
+CALF_PORT_PROPS(gate) = {
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
+    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" },
+    { 0,      0,  1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" },
+    { 0,      0,  1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB-In" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB-Out" },
+    { 0.06125,   0.000015849, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "range", "Max Gain Reduction" },
+    { 0.125,      0.000976563, 1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" },
+    { 2,      1, 20,  21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" },
+    { 20,     0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" },
+    { 250,    0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" },
+    { 1,      1, 64,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" },
+    { 2.828427125,      1,  8,   0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" },
+    { 0,      0,  1,    0, PF_ENUM | PF_CTL_COMBO, gate_detection_names, "detection", "Detection" },
+    { 0,      0,  1,    0, PF_ENUM | PF_CTL_COMBO, gate_stereo_link_names, "stereo_link", "Stereo Link" },
+    { 0, 0.03125, 1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "gating", "Gating" },
+};
+
+CALF_PLUGIN_INFO(gate) = { 0x8503, "Gate", "Calf Gate", "Damien Zammit / Thor Harald Johansen", calf_plugins::calf_copyright_info, "ExpanderPlugin" };
+
+////////////////////////////////////////////////////////////////////////////
+
+CALF_PORT_NAMES(sidechaingate) = {"In L", "In R", "Out L", "Out R"};
+
+const char *sidechaingate_detection_names[] = { "RMS", "Peak" };
+const char *sidechaingate_stereo_link_names[] = { "Average", "Maximum" };
+const char *sidechaingate_mode_names[] = {"Wideband (F1:off / F2:off)",
+                                                "High gate wide (F1:Bell / F2:HP)",
+                                                "High gate split (F1:off / F2:HP)",
+                                                "Low Gate wide (F1:LP / F2:Bell)",
+                                                "Low gate split (F1:LP / F2:off)",
+                                                "Weighted #1 (F1:Shelf / F2:Shelf)",
+                                                "Weighted #2 (F1:Shelf / F2:Bell)",
+                                                "Weighted #3 (F1:Bell / F2:Shelf)",
+                                                "Bandpass #1 (F1:BP / F2:off)",
+                                                "Bandpass #2 (F1:HP / F2:LP)"};
+const char *sidechaingate_filter_choices[] = { "12dB", "24dB", "36dB"};
+
+
+CALF_PORT_PROPS(sidechaingate) = {
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
+    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" },
+    { 0,      0,  1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" },
+    { 0,      0,  1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB-In" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB-Out" },
+    { 0.06125,   0.000015849, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "range", "Max Gain Reduction" },
+    { 0.125,      0.000976563, 1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" },
+    { 2,      1, 20,  21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" },
+    { 20,     0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" },
+    { 250,    0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" },
+    { 1,      1, 64,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" },
+    { 2.828427125,      1,  8,   0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" },
+    { 0,      0,  1,    0, PF_ENUM | PF_CTL_COMBO, sidechaingate_detection_names, "detection", "Detection" },
+    { 0,      0,  1,    0, PF_ENUM | PF_CTL_COMBO, sidechaingate_stereo_link_names, "stereo_link", "Stereo Link" },
+    { 0, 0.03125, 1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "gating", "Gating" },
+    { 0,      0,  9,    0, PF_ENUM | PF_CTL_COMBO, sidechaingate_mode_names, "sc_mode", "Sidechain Mode" },
+    { 250,    10,18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "f1_freq", "F1 Freq" },
+    { 4500,   10,18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "f2_freq", "F2 Freq" },
+    { 1,      0.0625,  16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f1_level", "F1 Level" },
+    { 1,      0.0625,  16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f2_level", "F2 Level" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_TOGGLE, NULL, "sc_listen", "S/C-Listen" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f1_active", "F1 Active" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f2_active", "F2 Active" },
+};
+
+CALF_PLUGIN_INFO(sidechaingate) = { 0x8504, "Sidechaingate", "Calf Sidechain Gate", "Markus Schmidt / Damien Zammit / Thor Harald Johansen", calf_plugins::calf_copyright_info, "ExpanderPlugin" };
+
+
+////////////////////////////////////////////////////////////////////////////
 // A few macros to make 
 
 #define BYPASS_AND_LEVEL_PARAMS \
@@ -592,37 +669,6 @@ CALF_PORT_PROPS(bassenhancer) = {
 
 CALF_PLUGIN_INFO(bassenhancer) = { 0x8532, "BassEnhancer", "Calf Bass Enhancer", "Markus Schmidt / Krzysztof Foltman", calf_plugins::calf_copyright_info, "DistortionPlugin" };
 
-
-////////////////////////////////////////////////////////////////////////////
-
-CALF_PORT_NAMES(gate) = {"In L", "In R", "In Trigger", "Out L", "Out R"};
-
-const char *gate_detection_names[] = { "RMS", "Peak" };
-const char *gate_stereo_link_names[] = { "Average", "Maximum" };
-const char *gate_weighting_names[] = { "Normal", "A-weighted", "Deesser (low)", "Deesser (med)", "Deesser (high)" };
-
-CALF_PORT_PROPS(gate) = {
-    { 0.125,      0.000976563, 1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" },
-    { 2,      1, 20,  21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" },
-    { 20,     1, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" },
-    { 250,    1, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" },
-    { 1,      1, 64,   0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" },
-    { 2.828427125,      1,  8,   0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" },
-    { 0,      0,  1,   0, PF_ENUM | PF_CTL_COMBO, gate_detection_names, "detection", "Detection" },
-    { 0,      0,  1,   0, PF_ENUM | PF_CTL_COMBO, gate_stereo_link_names, "stereo_link", "Stereo Link" },
-    { 0,      0,  4,   0, PF_ENUM | PF_CTL_COMBO, gate_weighting_names, "aweighting", "Weighting" },
-    { 0, 0.03125, 1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "gating", "Gating" },
-    { 0,      0,  1,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "peak", "Peak Output" },
-    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip", "0dBFS" },
-    { 0,      0,  1,    0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
-    { 0.01,   0.000015849, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "range", "Max Gain Reduction" },
-    { 0,      0,  1,    0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mono", "Mono (L only)" },
-    { 0,      0,  1,    0, PF_BOOL | PF_CTL_TOGGLE, NULL, "trigger", "Sidechain (Mono In)" },
-
-};
-
-CALF_PLUGIN_INFO(gate) = { 0x8503, "Gate", "Calf Gate", "Damien Zammit / Thor Harald Johansen", calf_plugins::calf_copyright_info, "ExpanderPlugin" };
-
 ////////////////////////////////////////////////////////////////////////////
 
 CALF_PORT_NAMES(monosynth) = {
diff --git a/src/modules_comp.cpp b/src/modules_comp.cpp
index a5d58e2..15f96a8 100644
--- a/src/modules_comp.cpp
+++ b/src/modules_comp.cpp
@@ -1118,6 +1118,540 @@ int deesser_audio_module::get_changed_offsets(int index, int generation, int &su
     return false;
 }
 
+/// Gate originally by Damien
+///
+/// This module provides Damien's original expander based on Thor's compressor
+/// without any weighting
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+gate_audio_module::gate_audio_module()
+{
+    is_active = false;
+    srate = 0;
+    last_generation = 0;
+}
+
+void gate_audio_module::activate()
+{
+    is_active = true;
+    // set all filters and strips
+    gate.activate();
+    params_changed();
+    meter_in = 0.f;
+    meter_out = 0.f;
+    clip_in = 0.f;
+    clip_out = 0.f;
+}
+void gate_audio_module::deactivate()
+{
+    is_active = false;
+    gate.deactivate();
+}
+
+void gate_audio_module::params_changed()
+{
+    gate.set_params(*params[param_attack], *params[param_release], *params[param_threshold], *params[param_ratio], *params[param_knee], *params[param_makeup], *params[param_detection], *params[param_stereo_link], *params[param_bypass], 0.f, *params[param_range]);
+}
+
+void gate_audio_module::set_sample_rate(uint32_t sr)
+{
+    srate = sr;
+    gate.set_sample_rate(srate);
+}
+
+uint32_t gate_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
+{
+    bool bypass = *params[param_bypass] > 0.5f;
+    numsamples += offset;
+    if(bypass) {
+        // everything bypassed
+        while(offset < numsamples) {
+            outs[0][offset] = ins[0][offset];
+            outs[1][offset] = ins[1][offset];
+            ++offset;
+        }
+        // displays, too
+        clip_in    = 0.f;
+        clip_out   = 0.f;
+        meter_in   = 0.f;
+        meter_out  = 0.f;
+    } else {
+        // process
+        clip_in    -= std::min(clip_in,  numsamples);
+        clip_out   -= std::min(clip_out,  numsamples);
+        
+        gate.update_curve();
+        
+        while(offset < numsamples) {
+            // cycle through samples
+            float outL = 0.f;
+            float outR = 0.f;
+            float inL = ins[0][offset];
+            float inR = ins[1][offset];
+            // in level
+            inR *= *params[param_level_in];
+            inL *= *params[param_level_in];
+            
+            float leftAC = inL;
+            float rightAC = inR;
+            
+            gate.process(leftAC, rightAC);
+            
+            outL = leftAC;
+            outR = rightAC;
+            
+            // send to output
+            outs[0][offset] = outL;
+            outs[1][offset] = outR;
+            
+            // clip LED's
+            if(std::max(fabs(inL), fabs(inR)) > 1.f) {
+                clip_in   = srate >> 3;
+            }
+            if(std::max(fabs(outL), fabs(outR)) > 1.f) {
+                clip_out  = srate >> 3;
+            }
+            // rise up out meter
+            meter_in = std::max(fabs(inL), fabs(inR));;
+            meter_out = std::max(fabs(outL), fabs(outR));;
+            
+            // next sample
+            ++offset;
+        } // cycle trough samples
+    }
+    // draw meters
+    SET_IF_CONNECTED(clip_in)
+    SET_IF_CONNECTED(clip_out)
+    SET_IF_CONNECTED(meter_in)
+    SET_IF_CONNECTED(meter_out)
+    // draw strip meter
+    if(bypass > 0.5f) {
+        if(params[param_gating] != NULL) {
+            *params[param_gating] = 1.0f;
+        }
+    } else {
+        if(params[param_gating] != NULL) {
+            *params[param_gating] = gate.get_expander_level();
+        }
+    }
+    // whatever has to be returned x)
+    return outputs_mask;
+}
+bool gate_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
+{
+    if (!is_active)
+        return false;
+    return gate.get_graph(subindex, data, points, context);
+}
+
+bool gate_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const
+{
+    if (!is_active)
+        return false;
+    return gate.get_dot(subindex, x, y, size, context);
+}
+
+bool gate_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
+{
+    if (!is_active)
+        return false;
+    return gate.get_gridline(subindex, pos, vertical, legend, context);
+}
+
+int gate_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const
+{
+    if (!is_active)
+        return false;
+    return gate.get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
+}
+
+/// Sidecain Gate by Markus Schmidt
+///
+/// This module splits the signal in a sidechain- and a process signal.
+/// The sidechain is processed through Krzystofs filters and gates
+/// the process signal via Damiens's gating routine afterwards.
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+sidechaingate_audio_module::sidechaingate_audio_module()
+{
+    is_active = false;
+    srate = 0;
+    last_generation = 0;
+}
+
+void sidechaingate_audio_module::activate()
+{
+    is_active = true;
+    // set all filters and strips
+    gate.activate();
+    params_changed();
+    meter_in = 0.f;
+    meter_out = 0.f;
+    clip_in = 0.f;
+    clip_out = 0.f;
+}
+void sidechaingate_audio_module::deactivate()
+{
+    is_active = false;
+    gate.deactivate();
+}
+
+sidechaingate_audio_module::cfloat sidechaingate_audio_module::h_z(const cfloat &z) const
+{
+    switch (sc_mode) {
+        default:
+        case WIDEBAND:
+            return false;
+            break;
+        case HIGHGATE_WIDE:
+        case LOWGATE_WIDE:
+        case WEIGHTED_1:
+        case WEIGHTED_2:
+        case WEIGHTED_3:
+        case BANDPASS_2:
+            return f1L.h_z(z) * f2L.h_z(z);
+            break;
+        case HIGHGATE_SPLIT:
+            return f2L.h_z(z);
+            break;
+        case LOWGATE_SPLIT:
+        case BANDPASS_1:
+            return f1L.h_z(z);
+            break;
+    }            
+}
+
+float sidechaingate_audio_module::freq_gain(int index, double freq, uint32_t sr) const
+{
+    typedef std::complex<double> cfloat;
+    freq *= 2.0 * M_PI / sr;
+    cfloat z = 1.0 / exp(cfloat(0.0, freq));
+    
+    return std::abs(h_z(z));
+}
+
+void sidechaingate_audio_module::params_changed()
+{
+    // set the params of all filters
+    if(*params[param_f1_freq] != f1_freq_old or *params[param_f1_level] != f1_level_old
+        or *params[param_f2_freq] != f2_freq_old or *params[param_f2_level] != f2_level_old
+        or *params[param_sc_mode] != sc_mode) {
+        float q = 0.707;
+        switch ((int)*params[param_sc_mode]) {
+            default:
+            case WIDEBAND:
+                f1L.set_hp_rbj((float)*params[param_f1_freq], q, (float)srate, *params[param_f1_level]);
+                f1R.copy_coeffs(f1L);
+                f2L.set_lp_rbj((float)*params[param_f2_freq], q, (float)srate, *params[param_f2_level]);
+                f2R.copy_coeffs(f2L);
+                f1_active = 0.f;
+                f2_active = 0.f;
+                break;
+            case HIGHGATE_WIDE:
+                f1L.set_peakeq_rbj((float)*params[param_f1_freq], q, *params[param_f1_level], (float)srate);
+                f1R.copy_coeffs(f1L);
+                f2L.set_hp_rbj((float)*params[param_f2_freq], q, (float)srate, *params[param_f2_level]);
+                f2R.copy_coeffs(f2L);
+                f1_active = 0.5f;
+                f2_active = 1.f;
+                break;
+            case HIGHGATE_SPLIT:
+                f1L.set_lp_rbj((float)*params[param_f2_freq] * (1 + 0.17), q, (float)srate);
+                f1R.copy_coeffs(f1L);
+                f2L.set_hp_rbj((float)*params[param_f2_freq] * (1 - 0.17), q, (float)srate, *params[param_f2_level]);
+                f2R.copy_coeffs(f2L);
+                f1_active = 0.f;
+                f2_active = 1.f;
+                break;
+            case LOWGATE_WIDE:
+                f1L.set_lp_rbj((float)*params[param_f1_freq], q, (float)srate, *params[param_f1_level]);
+                f1R.copy_coeffs(f1L);
+                f2L.set_peakeq_rbj((float)*params[param_f2_freq], q, *params[param_f2_level], (float)srate);
+                f2R.copy_coeffs(f2L);
+                f1_active = 1.f;
+                f2_active = 0.5f;
+                break;
+            case LOWGATE_SPLIT:
+                f1L.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), q, (float)srate, *params[param_f1_level]);
+                f1R.copy_coeffs(f1L);
+                f2L.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), q, (float)srate);
+                f2R.copy_coeffs(f2L);
+                f1_active = 1.f;
+                f2_active = 0.f;
+                break;
+            case WEIGHTED_1:
+                f1L.set_lowshelf_rbj((float)*params[param_f1_freq], q, *params[param_f1_level], (float)srate);
+                f1R.copy_coeffs(f1L);
+                f2L.set_highshelf_rbj((float)*params[param_f2_freq], q, *params[param_f2_level], (float)srate);
+                f2R.copy_coeffs(f2L);
+                f1_active = 0.5f;
+                f2_active = 0.5f;
+                break;
+            case WEIGHTED_2:
+                f1L.set_lowshelf_rbj((float)*params[param_f1_freq], q, *params[param_f1_level], (float)srate);
+                f1R.copy_coeffs(f1L);
+                f2L.set_peakeq_rbj((float)*params[param_f2_freq], q, *params[param_f2_level], (float)srate);
+                f2R.copy_coeffs(f2L);
+                f1_active = 0.5f;
+                f2_active = 0.5f;
+                break;
+            case WEIGHTED_3:
+                f1L.set_peakeq_rbj((float)*params[param_f1_freq], q, *params[param_f1_level], (float)srate);
+                f1R.copy_coeffs(f1L);
+                f2L.set_highshelf_rbj((float)*params[param_f2_freq], q, *params[param_f2_level], (float)srate);
+                f2R.copy_coeffs(f2L);
+                f1_active = 0.5f;
+                f2_active = 0.5f;
+                break;
+            case BANDPASS_1:
+                f1L.set_bp_rbj((float)*params[param_f1_freq], q, (float)srate, *params[param_f1_level]);
+                f1R.copy_coeffs(f1L);
+                f2L.set_hp_rbj((float)*params[param_f2_freq], q, *params[param_f2_level], (float)srate);
+                f2R.copy_coeffs(f2L);
+                f1_active = 1.f;
+                f2_active = 0.f;
+                break;
+            case BANDPASS_2:
+                f1L.set_hp_rbj((float)*params[param_f1_freq], q, (float)srate, *params[param_f1_level]);
+                f1R.copy_coeffs(f1L);
+                f2L.set_lp_rbj((float)*params[param_f2_freq], q, (float)srate, *params[param_f2_level]);
+                f2R.copy_coeffs(f2L);
+                f1_active = 1.f;
+                f2_active = 1.f;
+                break;
+        }
+        f1_freq_old = *params[param_f1_freq];
+        f1_level_old = *params[param_f1_level];
+        f2_freq_old = *params[param_f2_freq];
+        f2_level_old = *params[param_f2_level];
+        sc_mode = (CalfScModes)*params[param_sc_mode];
+    }
+    // light LED's
+    if(params[param_f1_active] != NULL) {
+        *params[param_f1_active] = f1_active;
+    }
+    if(params[param_f2_active] != NULL) {
+        *params[param_f2_active] = f2_active;
+    }
+    // and set the expander module
+    gate.set_params(*params[param_attack], *params[param_release], *params[param_threshold], *params[param_ratio], *params[param_knee], *params[param_makeup], *params[param_detection], *params[param_stereo_link], *params[param_bypass], 0.f, *params[param_range]);
+}
+
+void sidechaingate_audio_module::set_sample_rate(uint32_t sr)
+{
+    srate = sr;
+    gate.set_sample_rate(srate);
+}
+
+uint32_t sidechaingate_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
+{
+    bool bypass = *params[param_bypass] > 0.5f;
+    numsamples += offset;
+    if(bypass) {
+        // everything bypassed
+        while(offset < numsamples) {
+            outs[0][offset] = ins[0][offset];
+            outs[1][offset] = ins[1][offset];
+            ++offset;
+        }
+        // displays, too
+        clip_in    = 0.f;
+        clip_out   = 0.f;
+        meter_in   = 0.f;
+        meter_out  = 0.f;
+    } else {
+        // process
+        
+        clip_in    -= std::min(clip_in,  numsamples);
+        clip_out   -= std::min(clip_out,  numsamples);
+        gate.update_curve();
+        
+        while(offset < numsamples) {
+            // cycle through samples
+            float outL = 0.f;
+            float outR = 0.f;
+            float inL = ins[0][offset];
+            float inR = ins[1][offset];
+            // in level
+            inR *= *params[param_level_in];
+            inL *= *params[param_level_in];
+            
+            
+            float leftAC = inL;
+            float rightAC = inR;
+            float leftSC = inL;
+            float rightSC = inR;
+            float leftMC = inL;
+            float rightMC = inR;
+            
+            switch ((int)*params[param_sc_mode]) {
+                default:
+                case WIDEBAND:
+                    gate.process(leftAC, rightAC);
+                    break;
+                case HIGHGATE_WIDE:
+                case LOWGATE_WIDE:
+                case WEIGHTED_1:
+                case WEIGHTED_2:
+                case WEIGHTED_3:
+                case BANDPASS_2:
+                    leftSC = f2L.process(f1L.process(leftSC));
+                    rightSC = f2R.process(f1R.process(rightSC));
+                    leftMC = leftSC;
+                    rightMC = rightSC;
+                    gate.process(leftAC, rightAC, &leftSC, &rightSC);
+                    break;
+                case HIGHGATE_SPLIT:
+                    leftSC = f2L.process(leftSC);
+                    rightSC = f2R.process(rightSC);
+                    leftMC = leftSC;
+                    rightMC = rightSC;
+                    gate.process(leftSC, rightSC, &leftSC, &rightSC);
+                    leftAC = f1L.process(leftAC);
+                    rightAC = f1R.process(rightAC);
+                    leftAC += leftSC;
+                    rightAC += rightSC;
+                    break;
+                case LOWGATE_SPLIT:
+                    leftSC = f1L.process(leftSC);
+                    rightSC = f1R.process(rightSC);
+                    leftMC = leftSC;
+                    rightMC = rightSC;
+                    gate.process(leftSC, rightSC);
+                    leftAC = f2L.process(leftAC);
+                    rightAC = f2R.process(rightAC);
+                    leftAC += leftSC;
+                    rightAC += rightSC;
+                    break;
+                case BANDPASS_1:
+                    leftSC = f1L.process(leftSC);
+                    rightSC = f1R.process(rightSC);
+                    leftMC = leftSC;
+                    rightMC = rightSC;
+                    gate.process(leftAC, rightAC, &leftSC, &rightSC);
+                    break;
+            }
+            
+            if(*params[param_sc_listen] > 0.f) {
+                outL = leftMC;
+                outR = rightMC;
+            } else {
+                outL = leftAC;
+                outR = rightAC;
+            }
+            
+            // send to output
+            outs[0][offset] = outL;
+            outs[1][offset] = outR;
+            
+            // clip LED's
+            if(std::max(fabs(inL), fabs(inR)) > 1.f) {
+                clip_in   = srate >> 3;
+            }
+            if(std::max(fabs(outL), fabs(outR)) > 1.f) {
+                clip_out  = srate >> 3;
+            }
+            // rise up out meter
+            meter_in = std::max(fabs(inL), fabs(inR));;
+            meter_out = std::max(fabs(outL), fabs(outR));;
+            
+            // next sample
+            ++offset;
+        } // cycle trough samples
+        f1L.sanitize();
+        f1R.sanitize();
+        f2L.sanitize();
+        f2R.sanitize();
+            
+    }
+    // draw meters
+    SET_IF_CONNECTED(clip_in)
+    SET_IF_CONNECTED(clip_out)
+    SET_IF_CONNECTED(meter_in)
+    SET_IF_CONNECTED(meter_out)
+    // draw strip meter
+    if(bypass > 0.5f) {
+        if(params[param_gating] != NULL) {
+            *params[param_gating] = 1.0f;
+        }
+    } else {
+        if(params[param_gating] != NULL) {
+            *params[param_gating] = gate.get_expander_level();
+        }
+    }
+    // whatever has to be returned x)
+    return outputs_mask;
+}
+bool sidechaingate_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
+{
+    if (!is_active)
+        return false;
+    if (index == param_f1_freq && !subindex) {
+        context->set_line_width(1.5);
+        return ::get_graph(*this, subindex, data, points);
+    } else if(index == param_gating) {
+        return gate.get_graph(subindex, data, points, context);
+    }
+    return false;
+}
+
+bool sidechaingate_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const
+{
+    if (!is_active)
+        return false;
+    if (index == param_gating) {
+        return gate.get_dot(subindex, x, y, size, context);
+    }
+    return false;
+}
+
+bool sidechaingate_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
+{
+    if (!is_active)
+        return false;
+    if (index == param_gating) {
+        return gate.get_gridline(subindex, pos, vertical, legend, context);
+    } else {
+        return get_freq_gridline(subindex, pos, vertical, legend, context);
+    }
+//    return false;
+}
+
+int sidechaingate_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const
+{
+    if (!is_active)
+        return false;
+    if(index == param_gating) {
+        return gate.get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
+    } else {
+        //  (fabs(inertia_cutoff.get_last() - old_cutoff) + 100 * fabs(inertia_resonance.get_last() - old_resonance) + fabs(*params[par_mode] - old_mode) > 0.1f)
+        if (*params[param_f1_freq] != f1_freq_old1
+            or *params[param_f2_freq] != f2_freq_old1
+            or *params[param_f1_level] != f1_level_old1
+            or *params[param_f2_level] != f2_level_old1
+            or *params[param_sc_mode] !=sc_mode_old1)
+        {
+            f1_freq_old1 = *params[param_f1_freq];
+            f2_freq_old1 = *params[param_f2_freq];
+            f1_level_old1 = *params[param_f1_level];
+            f2_level_old1 = *params[param_f2_level];
+            sc_mode_old1 = (CalfScModes)*params[param_sc_mode];
+            last_generation++;
+            subindex_graph = 0;
+            subindex_dot = INT_MAX;
+            subindex_gridline = INT_MAX;
+        }
+        else {
+            subindex_graph = 0;
+            subindex_dot = subindex_gridline = generation ? INT_MAX : 0;
+        }
+        if (generation == last_calculated_generation)
+            subindex_graph = INT_MAX;
+        return last_generation;
+    }
+    return false;
+}
+
 /// Gain reduction module by Thor
 /// All functions of this module are originally written
 /// by Thor, while some features have been stripped (mainly stereo linking
@@ -1127,6 +1661,7 @@ int deesser_audio_module::get_changed_offsets(int index, int generation, int &su
 gain_reduction_audio_module::gain_reduction_audio_module()
 {
     is_active       = false;
+    srate           = 0;
     last_generation = 0;
 }
 
@@ -1170,7 +1705,6 @@ void gain_reduction_audio_module::process(float &left, float &right, const float
     if(!det_right) {
         det_right = &right;
     }
-    float gain = 1.f;
     if(bypass < 0.5f) {
         // this routine is mainly copied from thor's compressor module
         // greatest sounding compressor I've heard!
@@ -1183,7 +1717,7 @@ void gain_reduction_audio_module::process(float &left, float &right, const float
         if(rms) absample *= absample;
             
         linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
-        
+        float gain = 1.f;
         if(linSlope > 0.f) {
             gain = output_gain(linSlope, rms);
         }
@@ -1344,37 +1878,143 @@ int gain_reduction_audio_module::get_changed_offsets(int generation, int &subind
 }
 
 
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-gate_audio_module::gate_audio_module()
+/// Gate module by Damien
+/// All functions of this module are originally written
+/// by Damien, while some features have been stripped (mainly stereo linking
+/// and frequency correction as implemented in Sidechain Gate above)
+/// To save some CPU.
+////////////////////////////////////////////////////////////////////////////////
+expander_audio_module::expander_audio_module()
 {
-    is_active = false;
-    srate = 0;
+    is_active       = false;
+    srate           = 0;
     last_generation = 0;
 }
 
-void gate_audio_module::activate()
+void expander_audio_module::activate()
 {
     is_active = true;
-    linSlope = 0.f;
-    peak = 0.f;
-    clip = 0.f;
+    linSlope   = 0.f;
+    meter_out  = 0.f;
+    meter_gate = 1.f;
+    float l, r;
+    l = r = 0.f;
+    float byp = bypass;
+    bypass = 0.0;
+    process(l, r);
+    bypass = byp;
 }
 
-void gate_audio_module::deactivate()
+void expander_audio_module::deactivate()
 {
     is_active = false;
 }
 
-void gate_audio_module::set_sample_rate(uint32_t sr)
+void expander_audio_module::update_curve()
+{
+    bool rms = detection == 0;
+    float linThreshold = threshold;
+    if (rms)
+        linThreshold = linThreshold * linThreshold;
+    attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
+    release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
+    float linKneeSqrt = sqrt(knee);
+    linKneeStart = linThreshold / linKneeSqrt;
+    adjKneeStart = linKneeStart*linKneeStart;
+    linKneeStop = linThreshold * linKneeSqrt;
+    thres = log(linThreshold);
+    kneeStart = log(linKneeStart);
+    kneeStop = log(linKneeStop);
+    compressedKneeStop = (kneeStop - thres) / ratio + thres;
+}
+
+void expander_audio_module::process(float &left, float &right, const float *det_left, const float *det_right)
+{
+    if(!det_left) {
+        det_left = &left;
+    }
+    if(!det_right) {
+        det_right = &right;
+    }
+    if(bypass < 0.5f) {
+        // this routine is mainly copied from Damien's expander module based on Thor's compressor
+        bool rms = detection == 0;
+        bool average = stereo_link == 0;
+        float absample = average ? (fabs(*det_left) + fabs(*det_right)) * 0.5f : std::max(fabs(*det_left), fabs(*det_right));
+        if(rms) absample *= absample;
+            
+        linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
+        float gain = 1.f;
+        if(linSlope > 0.f) {
+            gain = output_gain(linSlope, rms);
+        }
+        left *= gain * makeup;
+        right *= gain * makeup;
+        meter_out = std::max(fabs(left), fabs(right));
+        meter_gate = gain;
+        detected = linSlope;
+    }
+}
+
+float expander_audio_module::output_level(float slope) const {
+    bool rms = detection == 0;
+    return slope * output_gain(rms ? slope*slope : slope, rms) * makeup;
+}
+
+float expander_audio_module::output_gain(float linSlope, bool rms) const {
+    //this calculation is also Damiens's work based on Thor's compressor
+    if(linSlope < linKneeStop) {
+        float slope = log(linSlope);
+        //float tratio = rms ? sqrt(ratio) : ratio;
+        float tratio = ratio;
+        float gain = 0.f;
+        float delta = 0.f;
+        if(IS_FAKE_INFINITY(ratio))
+            tratio = 1000.f;
+        gain = (slope-thres) * tratio + thres;
+        delta = tratio;
+
+        if(knee > 1.f && slope > kneeStart ) {
+            gain = dsp::hermite_interpolation(slope, kneeStart, kneeStop, ((kneeStart - thres) * tratio  + thres), kneeStop, delta,1.f);
+        }
+        return std::max(range, expf(gain-slope));
+    }
+    return 1.f;
+}
+
+void expander_audio_module::set_sample_rate(uint32_t sr)
 {
     srate = sr;
-    awL.set(sr);
-    awR.set(sr);
+}
+void expander_audio_module::set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu, float ran)
+{
+    // set all params
+    attack          = att;
+    release         = rel;
+    threshold       = thr;
+    ratio           = rat;
+    knee            = kn;
+    makeup          = mak;
+    detection       = det;
+    stereo_link     = stl;
+    bypass          = byp;
+    mute            = mu;
+    range           = ran;
+    if(mute > 0.f) {
+        meter_out  = 0.f;
+        meter_gate = 1.f;
+    }
+}
+float expander_audio_module::get_output_level() {
+    // returns output level (max(left, right))
+    return meter_out;
+}
+float expander_audio_module::get_expander_level() {
+    // returns amount of gating
+    return meter_gate;
 }
 
-bool gate_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
+bool expander_audio_module::get_graph(int subindex, float *data, int points, cairo_iface *context) const
 {
     if (!is_active)
         return false;
@@ -1383,13 +2023,14 @@ bool gate_audio_module::get_graph(int index, int subindex, float *data, int poin
     for (int i = 0; i < points; i++)
     {
         float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1));
-        float output = output_level(input);
         if (subindex == 0)
             data[i] = dB_grid(input);
-        else
+        else {
+            float output = output_level(input);
             data[i] = dB_grid(output);
+        }
     }
-    if (subindex == (*params[param_bypass] > 0.f ? 1 : 0))
+    if (subindex == (bypass > 0.5f ? 1 : 0) or mute > 0.1f)
         context->set_source_rgba(0.35, 0.4, 0.2, 0.3);
     else {
         context->set_source_rgba(0.35, 0.4, 0.2, 1);
@@ -1398,22 +2039,26 @@ bool gate_audio_module::get_graph(int index, int subindex, float *data, int poin
     return true;
 }
 
-bool gate_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const
+bool expander_audio_module::get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context) const
 {
     if (!is_active)
         return false;
     if (!subindex)
     {
-        bool rms = *params[param_detection] == 0;
-        float det = rms ? sqrt(detected) : detected;
-        x = 0.5 + 0.5 * dB_grid(det);
-        y = dB_grid(*params[param_bypass] > 0.f ? det : output_level(det));
-        return *params[param_bypass] > 0.f ? false : true;
+        if(bypass > 0.5f or mute > 0.f) {
+            return false;
+        } else {
+            bool rms = detection == 0;
+            float det = rms ? sqrt(detected) : detected;
+            x = 0.5 + 0.5 * dB_grid(det);
+            y = dB_grid(bypass > 0.5f or mute > 0.f ? det : output_level(det));
+            return true;
+        }
     }
     return false;
 }
 
-bool gate_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
+bool expander_audio_module::get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
 {
     bool tmp;
     vertical = (subindex & 1) != 0;
@@ -1432,161 +2077,26 @@ bool gate_audio_module::get_gridline(int index, int subindex, float &pos, bool &
     return result;
 }
 
-uint32_t gate_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
-{
-    bool bypass = *params[param_bypass] > 0.f;
-
-    if(bypass) {
-        int count = numsamples * sizeof(float);
-        memcpy(outs[0], ins[0], count);
-        memcpy(outs[1], ins[1], count);
-
-        if(params[param_gating] != NULL) {
-            *params[param_gating] = 1.f;
-        }
-
-        if(params[param_clip] != NULL) {
-            *params[param_clip] = 0.f;
-        }
-
-        if(params[param_peak] != NULL) {
-            *params[param_peak] = 0.f;
-        }
-
-        return inputs_mask;
-    }
-
-    bool rms = *params[param_detection] == 0;
-    bool average = *params[param_stereo_link] == 0;
-    int aweighting = fastf2i_drm(*params[param_aweighting]);
-    float linThreshold = *params[param_threshold];
-    if (rms)
-        linThreshold = linThreshold * linThreshold;
-    ratio = *params[param_ratio];
-    float attack = *params[param_attack];
-    float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
-    float release = *params[param_release];
-    float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
-    makeup = *params[param_makeup];
-    knee = *params[param_knee];
-
-    range = *params[param_range];
-
-    float linKneeSqrt = sqrt(knee);
-    linKneeStart = linThreshold / linKneeSqrt;
-    adjKneeStart = linKneeStart*linKneeStart;
-    linKneeStop = linThreshold * linKneeSqrt;
-
-    threshold = log(linThreshold);
-    kneeStart = log(linKneeStart);
-    kneeStop = log(linKneeStop);
-    compressedKneeStop = (kneeStop - threshold) / ratio + threshold;
-
-    if (aweighting >= 2)
-    {
-        bpL.set_highshelf_rbj(5000, 0.707, 10 << (aweighting - 2), srate);
-        bpR.copy_coeffs(bpL);
-        bpL.sanitize();
-        bpR.sanitize();
-    }
-
-    numsamples += offset;
-
-    float gating = 1.f;
-
-    peak -= peak * 5.f * numsamples / srate;
-
-    clip -= std::min(clip, numsamples);
-    float left;
-    float right;
-
-    while(offset < numsamples) {
-        if(*params[param_trigger]) {
-	    left = ins[2][offset];  // Use sidechain to trigger input
-	    right = left;           // (mono sidechain)
-	} else {
-	    left = ins[0][offset];
-            right = ins[1][offset];
-        }
-
-        if(aweighting == 1) {
-            left = awL.process(left);
-            right = awR.process(right);
-        }
-        else if(aweighting >= 2) {
-            left = bpL.process(left);
-            right = bpR.process(right);
-        }
-
-        float absample = average ? (fabs(left) + fabs(right)) * 0.5f : std::max(fabs(left), fabs(right));
-        if(rms) absample *= absample;
-
-        linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
-
-        float gain = 1.f;
-
-        if(linSlope > 0.f) {
-            gain = output_gain(linSlope, rms);
-        }
-
-        gating = gain;
-        gain *= makeup;
-
-        float outL = ins[0][offset] * gain;
-        float outR = ins[1][offset] * gain;
-
-        outs[0][offset] = outL;
-        outs[1][offset] = outR;
-
-        ++offset;
-
-        float maxLR = std::max(fabs(outL), fabs(outR));
-
-        if(maxLR > 1.f) clip = srate >> 3; /* blink clip LED for 125 ms */
-
-        if(maxLR > peak) {
-            peak = maxLR;
-        }
-    }
-
-    detected = linSlope;
-
-    if(params[param_gating] != NULL) {
-        *params[param_gating] = gating;
-    }
-
-    if(params[param_clip] != NULL) {
-        *params[param_clip] = clip;
-    }
-
-    if(params[param_peak] != NULL) {
-        *params[param_peak] = peak;
-    }
-
-    return inputs_mask;
-}
-
-int gate_audio_module::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const
+int expander_audio_module::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const
 {
     subindex_graph = 0;
     subindex_dot = 0;
     subindex_gridline = generation ? INT_MAX : 0;
 
-    if (fabs(range-old_range) + fabs(threshold-old_threshold) + fabs(ratio - old_ratio) + fabs(knee - old_knee) + fabs( makeup - old_makeup) + fabs( *params[param_bypass] - old_bypass) > 0.01f)
+    if (fabs(range-old_range) + fabs(threshold-old_threshold) + fabs(ratio - old_ratio) + fabs(knee - old_knee) + fabs(makeup - old_makeup) + fabs(detection - old_detection) + fabs(bypass - old_bypass) + fabs(mute - old_mute) > 0.000001f)
     {
-        old_range = range;
+        old_range     = range;
         old_threshold = threshold;
-        old_ratio = ratio;
-        old_knee = knee;
-        old_makeup = makeup;
-        old_bypass = *params[param_bypass];
-        old_trigger = *params[param_trigger];
-        old_mono = *params[param_mono];
+        old_ratio     = ratio;
+        old_knee      = knee;
+        old_makeup    = makeup;
+        old_detection = detection;
+        old_bypass    = bypass;
+        old_mute      = mute;
         last_generation++;
     }
-        old_trigger = *params[param_trigger];
-
     if (generation == last_generation)
         subindex_graph = 2;
     return last_generation;
 }
+

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list