[SCM] calf/master: New FX: Sidechain compressor

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:39:44 UTC 2013


The following commit has been merged in the master branch:
commit c5c8786de3e410c64d9c9d4cd70fd03a4c697a2e
Author: Markus Schmidt <schmidt at boomshop.net>
Date:   Sun Oct 25 10:04:14 2009 +0100

    New FX: Sidechain compressor

diff --git a/gui/gui-sidechaincompressor.xml b/gui/gui-sidechaincompressor.xml
new file mode 100644
index 0000000..e2ff2d0
--- /dev/null
+++ b/gui/gui-sidechaincompressor.xml
@@ -0,0 +1,162 @@
+<hbox spacing="10">
+
+    <vbox spacing="20" expand="0" fill="0">
+        <vbox attach-x="0" attach-y="0" expand="0" fill="0" pad-x="7" pad-y="7" spacing="7" >
+            <label param="bypass" expand="0" fill="0" />
+            <align><toggle param="bypass" shrink="1" size="2"/></align>
+        </vbox>
+        <vbox attach-x="0" attach-y="1" expand="0" fill="0" pad-y="20" pad-x="7">
+            <label param="level_in" expand="0" fill="0" expand-y="0" fill-y="0" />
+            <knob param="level_in" size="5" expand="1" fill="1" />
+            <value param="level_in" />
+        </vbox>
+    </vbox>
+
+    <vbox spacing="5">
+        <frame label="Compressor">
+            <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" />
+                </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>
+    
+    <if cond="directlink">
+      <frame label="Compression">
+        <vbox spacing="20">
+            <vbox>
+                <label param="compression"/>
+                <vumeter param="compression" mode="2" hold="1.5" attach-w="2" expand="0" fill="0"/>
+            </vbox>
+            <line-graph refresh="1" width="255" height="255" param="compression" square="1" expand="1" fill="1"/>
+        </vbox>
+      </frame>
+    </if>
+    
+    <vbox spacing="5">
+        
+        <if cond="directlink">
+            <frame label="Sidechain">
+                <vbox spacing="0">
+                    <hbox spacing="5" expand="0" fill="0">
+                        <vbox expand="0">
+                            <label param="sc_mode" expand="0" fill="0" />
+                            <combo param="sc_mode" />
+                        </vbox>
+                        <vbox expand="0">
+                             <label param="sc_listen" expand="0" fill="0"/>
+                             <toggle param="sc_listen" size="2"/>
+                        </vbox>
+                    </hbox>
+                    <line-graph refresh="1" width="235" height="100" param="f1_freq" expand="1" fill="1" />
+                </vbox>
+            </frame>
+        </if>
+        <hbox spacing="5">
+            <frame label="Filter 1">
+                <vbox>
+                    <hbox spacing="5">
+                        <label param="f1_active" expand="1" fill="1"/>
+                        <led param="f1_active" mode="7" expand="1" fill="1"/>
+                    </hbox>
+                    
+                    <hbox homogeneous="1">
+                        <vbox>
+                            <label param="f1_freq" />
+                            <knob param="f1_freq" size="2" />
+                            <value param="f1_freq" />
+                        </vbox>
+                        <vbox>
+                            <label param="f1_level" />
+                            <knob param="f1_level" size="2" />
+                            <value param="f1_level" />
+                        </vbox>
+                    </hbox>
+                </vbox>
+            </frame>
+            <frame label="Filter 2">
+                <vbox>
+                    <hbox spacing="5">
+                        <label param="f2_active" expand="1" fill="1"/>
+                        <led param="f2_active" mode="7" expand="1" fill="1"/>
+                    </hbox>
+                    
+                    <hbox homogeneous="1">
+                        <vbox>
+                            <label param="f2_freq" />
+                            <knob param="f2_freq" size="2" />
+                            <value param="f2_freq" />
+                        </vbox>
+                        <vbox>
+                            <label param="f2_level" />
+                            <knob param="f2_level" size="2" />
+                            <value param="f2_level" />
+                        </vbox>
+                    </hbox>
+                </vbox>
+            </frame>
+        </hbox>
+    </vbox>
+</hbox>
diff --git a/gui/knob5.png b/knobs/knob5.png
similarity index 100%
copy from gui/knob5.png
copy to knobs/knob5.png
diff --git a/knobs/knob4.py b/knobs/knob5.py
similarity index 95%
copy from knobs/knob4.py
copy to knobs/knob5.py
index b949596..62676bf 100755
--- a/knobs/knob4.py
+++ b/knobs/knob5.py
@@ -3,17 +3,17 @@
 import cairo
 from math import pi, cos, sin
 
-WIDTH, HEIGHT = 80, 80
-background = "knob4_bg.png"
-output = "knob4.png"
+WIDTH, HEIGHT = 100, 100
+background = "knob5_bg.png"
+output = "knob5.png"
 x, y = WIDTH / 2, HEIGHT / 2
-lwidth = WIDTH / 15
-radius = WIDTH / 2 - lwidth
-radiusplus = radius + lwidth / 3
+lwidth = WIDTH / 12
+radius = WIDTH / 2 - lwidth # overall radius (affects all)
+radiusplus = radius + lwidth / 1.5
 radiusminus = radius - lwidth / 2
 radiusminus2 = radius - lwidth
 radiusminus3 = radius - lwidth * 3 / 2
-radiusint = (radius - lwidth / 2) * 0.25
+radiusint = (radius - lwidth / 2) * 0.5
 value = 0.7
 arrow = WIDTH / 10
 phases = 65
diff --git a/knobs/knob5_bg.png b/knobs/knob5_bg.png
new file mode 100644
index 0000000..b58c50c
Binary files /dev/null and b/knobs/knob5_bg.png differ
diff --git a/src/calf/giface.h b/src/calf/giface.h
index 4a23300..56305bc 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -69,6 +69,7 @@ enum parameter_flags
   PF_CTL_BUTTON =  0x0600, ///< push button
   PF_CTL_METER  =  0x0700, ///< volume meter
   PF_CTL_LED    =  0x0800, ///< light emitting diode
+  PF_CTL_LABEL  =  0x0900, ///< label
   
   PF_CTLOPTIONS     = 0x00F000, ///< bit mask for control (widget) options
   PF_CTLO_HORIZ     = 0x001000, ///< horizontal version of the control (unused)
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index 4ce6639..79d4401 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -136,6 +136,17 @@ struct compressor_metadata: public plugin_metadata<compressor_metadata>
     PLUGIN_NAME_ID_LABEL("compressor", "compressor", "Compressor")
 };
 
+/// Markus's sidechain compressor - metadata
+struct sidechaincompressor_metadata: public plugin_metadata<sidechaincompressor_metadata>
+{
+    enum { in_count = 2, out_count = 2, 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_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_compression, 
+           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("sidechaincompressor", "sidechaincompressor", "Sidechain Compressor")
+};
+
 /// Markus's multibandcompressor - metadata
 struct multibandcompressor_metadata: public plugin_metadata<multibandcompressor_metadata>
 {
diff --git a/src/calf/modulelist.h b/src/calf/modulelist.h
index ca99065..904e1b3 100644
--- a/src/calf/modulelist.h
+++ b/src/calf/modulelist.h
@@ -11,6 +11,7 @@
     PER_MODULE_ITEM(multichorus, false, "multichorus")
     PER_MODULE_ITEM(compressor, false, "compressor")
     PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
+    PER_MODULE_ITEM(sidechaincompressor, false, "sidechaincompressor")
 #ifdef ENABLE_EXPERIMENTAL
     PER_MODULE_ITEM(fluidsynth, true, "fluidsynth")
     PER_MODULE_ITEM(wavetable, true, "wavetable")
diff --git a/src/calf/modules.h b/src/calf/modules.h
index fd3f27e..7933aa0 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -926,8 +926,8 @@ class gain_reduction_audio_module {
 private:
     float linSlope, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop;
     float compressedKneeStop, adjKneeStart, thres;
-    float attack, release, threshold, ratio, knee, makeup, detection, bypass, mute, meter_out, meter_comp;
-    float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_mute, old_detection;
+    float attack, release, threshold, ratio, knee, makeup, detection, stereo_link, bypass, mute, meter_out, meter_comp;
+    float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_mute, old_detection, old_stereo_link;
     int last_generation;
     uint32_t srate;
     bool is_active;
@@ -935,8 +935,8 @@ private:
     inline float output_gain(float linSlope, bool rms);
 public:
     gain_reduction_audio_module();
-    void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float byp, float mu);
-    void process(float &left, float &right);
+    void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu);
+    void process(float &left, float &right, float det_left = NULL, float det_right = NULL);
     void activate();
     void deactivate();
     int id;
@@ -949,6 +949,78 @@ public:
     virtual int  get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
 };
 
+
+/// Sidecain Compressor by Markus Schmidt (based on Thor's compressor and Krzysztof's filters)
+class sidechaincompressor_audio_module: public audio_module<sidechaincompressor_metadata>, public frequency_response_line_graph  {
+private:
+    enum CalfScModes {
+        WIDEBAND,
+        DEESSER_WIDE,
+        DEESSER_SPLIT,
+        DERUMBLER_WIDE,
+        DERUMBLER_SPLIT,
+        WEIGHTED_1,
+        WEIGHTED_2,
+        WEIGHTED_3,
+        BANDPASS_1,
+        BANDPASS_2
+    };
+    float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old;
+    CalfScModes sc_mode;
+    float f1_active, f2_active;
+    uint32_t clip_in, clip_out;
+    float meter_in, meter_out;
+    gain_reduction_audio_module compressor;
+    biquad_d2<float> f1L, f1R, f2L, f2R;
+public:
+    typedef std::complex<double> cfloat;
+    float *ins[in_count];
+    float *outs[out_count];
+    float *params[param_count];
+    uint32_t srate;
+    bool is_active;
+    sidechaincompressor_audio_module();
+    void activate();
+    void deactivate();
+    void params_changed();
+    inline cfloat h_z(const cfloat &z) {
+        switch (sc_mode) {
+            default:
+            case WIDEBAND:
+                return false;
+                break;
+            case DEESSER_WIDE:
+            case DERUMBLER_WIDE:
+            case WEIGHTED_1:
+            case WEIGHTED_2:
+            case WEIGHTED_3:
+            case BANDPASS_2:
+                return f1L.h_z(z) * f2L.h_z(z);
+                break;
+            case DEESSER_SPLIT:
+            case DERUMBLER_SPLIT:
+            case BANDPASS_1:
+                return f1L.h_z(z);
+                break;
+        }
+                
+    }
+    float freq_gain(int index, double freq, uint32_t sr)
+    {
+        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 set_sample_rate(uint32_t sr);
+    uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
+    virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context);
+    virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context);
+    virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
+    virtual int  get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
+};
+
 /// Multibandcompressor by Markus Schmidt
 class multibandcompressor_audio_module: public audio_module<multibandcompressor_metadata>, public line_graph_iface {
 private:
diff --git a/src/custom_ctl.cpp b/src/custom_ctl.cpp
index eeb9b7f..414ba42 100644
--- a/src/custom_ctl.cpp
+++ b/src/custom_ctl.cpp
@@ -602,7 +602,6 @@ calf_vumeter_expose (GtkWidget *widget, GdkEventExpose *event)
             vu->last_hold = time;
             vu->holding = false;
         }
-        
         if( vu->mode == VU_MONOCHROME_REVERSE ) {
             if(value < vu->last_value) {
                 // value is above peak hold
diff --git a/src/modules.cpp b/src/modules.cpp
index 8a607f5..43338f4 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -241,6 +241,51 @@ CALF_PLUGIN_INFO(compressor) = { 0x8502, "Compressor", "Calf Compressor", "Thor
 
 ////////////////////////////////////////////////////////////////////////////
 
+CALF_PORT_NAMES(sidechaincompressor) = {"In L", "In R", "Out L", "Out R"};
+
+const char *sidechaincompressor_detection_names[] = { "RMS", "Peak" };
+const char *sidechaincompressor_stereo_link_names[] = { "Average", "Maximum" };
+const char *sidechaincompressor_mode_names[] = {"Wideband (F1:off / F2:off)",
+                                                "Deesser wide (F1:HP / F2:Bell)",
+                                                "Deesser split (F1:HP / F2:off)",
+                                                "Derumbler wide (F1:Bell / F2:LP)",
+                                                "Derumbler split (F1:off / F2:LP)",
+                                                "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)"};
+
+CALF_PORT_PROPS(sidechaincompressor) = {
+    { 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" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" },
+    { 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" },
+    { 2,      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, sidechaincompressor_detection_names, "detection", "Detection" },
+    { 0,      0,  1,    0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_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, "compression", "Gain Reduction" },
+    { 0,      0,  9,    0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_mode_names, "sc_mode", "Sidechain Mode" },
+    { 200,    10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "f1_freq", "Freq" },
+    { 4000,   10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "f2_freq", "Freq" },
+    { 1,      0.0625,  16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f1_level", "Level" },
+    { 1,      0.0625,  16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f2_level", "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", "active" },
+    { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f2_active", "active" },
+};
+
+CALF_PLUGIN_INFO(sidechaincompressor) = { 0x8502, "Sidechaincompressor", "Calf Sidechain Compressor", "Thor Harald Johansen / Markus Schmidt", calf_plugins::calf_copyright_info, "CompressorPlugin" };
+
+////////////////////////////////////////////////////////////////////////////
+
 CALF_PORT_NAMES(multibandcompressor) = {"In L", "In R", "Out L", "Out R"};
 
 const char *multibandcompressor_detection_names[] = { "RMS", "Peak" };
diff --git a/src/modules_dsp.cpp b/src/modules_dsp.cpp
index 4b2820c..b8fedfd 100644
--- a/src/modules_dsp.cpp
+++ b/src/modules_dsp.cpp
@@ -717,16 +717,16 @@ void multibandcompressor_audio_module::params_changed()
     for (int j = 0; j < strips; j ++) {
         switch (j) {
             case 0:
-                strip[j].set_params(*params[param_attack0], *params[param_release0], *params[param_threshold0], *params[param_ratio0], *params[param_knee0], *params[param_makeup0], *params[param_detection0], *params[param_bypass0], *params[param_mute0]);
+                strip[j].set_params(*params[param_attack0], *params[param_release0], *params[param_threshold0], *params[param_ratio0], *params[param_knee0], *params[param_makeup0], *params[param_detection0], 1.f, *params[param_bypass0], *params[param_mute0]);
                 break;
             case 1:
-                strip[j].set_params(*params[param_attack1], *params[param_release1], *params[param_threshold1], *params[param_ratio1], *params[param_knee1], *params[param_makeup1], *params[param_detection1], *params[param_bypass1], *params[param_mute1]);
+                strip[j].set_params(*params[param_attack1], *params[param_release1], *params[param_threshold1], *params[param_ratio1], *params[param_knee1], *params[param_makeup1], *params[param_detection1], 1.f, *params[param_bypass1], *params[param_mute1]);
                 break;
             case 2:
-                strip[j].set_params(*params[param_attack2], *params[param_release2], *params[param_threshold2], *params[param_ratio2], *params[param_knee2], *params[param_makeup2], *params[param_detection2], *params[param_bypass2], *params[param_mute2]);
+                strip[j].set_params(*params[param_attack2], *params[param_release2], *params[param_threshold2], *params[param_ratio2], *params[param_knee2], *params[param_makeup2], *params[param_detection2], 1.f, *params[param_bypass2], *params[param_mute2]);
                 break;
             case 3:
-                strip[j].set_params(*params[param_attack3], *params[param_release3], *params[param_threshold3], *params[param_ratio3], *params[param_knee3], *params[param_makeup3], *params[param_detection3], *params[param_bypass3], *params[param_mute3]);
+                strip[j].set_params(*params[param_attack3], *params[param_release3], *params[param_threshold3], *params[param_ratio3], *params[param_knee3], *params[param_makeup3], *params[param_detection3], 1.f, *params[param_bypass3], *params[param_mute3]);
                 break;
         }
     }
@@ -1050,6 +1050,328 @@ int multibandcompressor_audio_module::get_changed_offsets(int index, int generat
     }
     return 0;
 }
+
+/// Sidecain Compressor by Markus Schmidt
+///
+/// This module splits the signal in a sidechain- and a process signal.
+/// The sidechain is processed through Krzystofs filters and compresses
+/// the process signal via Thor's compression routine afterwards.
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+sidechaincompressor_audio_module::sidechaincompressor_audio_module()
+{
+    is_active = false;
+    srate = 0;
+}
+
+void sidechaincompressor_audio_module::activate()
+{
+    is_active = true;
+    // set all filters and strips
+    compressor.activate();
+    params_changed();
+    meter_in = 0.f;
+    meter_out = 0.f;
+    clip_in = 0.f;
+    clip_out = 0.f;
+}
+void sidechaincompressor_audio_module::deactivate()
+{
+    is_active = false;
+    compressor.deactivate();
+}
+
+void sidechaincompressor_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_sc_mode] != sc_mode
+        or *params[param_f2_freq] != f2_freq_old or *params[param_f2_level] != f2_level_old) {
+        switch ((int)*params[param_sc_mode]) {
+            default:
+            case WIDEBAND:
+                f1L.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
+                f1R.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
+                f2L.set_lp_rbj((float)*params[param_f2_freq], 0.707, (float)srate);
+                f2R.set_lp_rbj((float)*params[param_f2_freq], 0.707, (float)srate);
+                f1_active = 0.f;
+                f2_active = 0.f;
+                break;
+            case DEESSER_WIDE:
+                f1L.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
+                f1R.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
+                f2L.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f2R.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f1_active = 1.f;
+                f2_active = 0.5f;
+                break;
+            case DEESSER_SPLIT:
+                f1L.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), 0.707, (float)srate);
+                f1R.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), 0.707, (float)srate);
+                f2L.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), 0.707, (float)srate);
+                f2R.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), 0.707, (float)srate);
+                f1_active = 1.f;
+                f2_active = 0.f;
+                break;
+            case DERUMBLER_WIDE:
+                f1L.set_lp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
+                f1R.set_lp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
+                f2L.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f2R.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f1_active = 1.f;
+                f2_active = 0.5f;
+                break;
+            case DERUMBLER_SPLIT:
+                f1L.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), 0.707, (float)srate);
+                f1R.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), 0.707, (float)srate);
+                f2L.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), 0.707, (float)srate);
+                f2R.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), 0.707, (float)srate);
+                f1_active = 1.f;
+                f2_active = 0.f;
+                break;
+            case WEIGHTED_1:
+                f1L.set_lowshelf_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
+                f1R.set_lowshelf_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
+                f2L.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f2R.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f1_active = 0.5f;
+                f2_active = 0.5f;
+                break;
+            case WEIGHTED_2:
+                f1L.set_lowshelf_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
+                f1R.set_lowshelf_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
+                f2L.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f2R.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f1_active = 0.5f;
+                f2_active = 0.5f;
+                break;
+            case WEIGHTED_3:
+                f1L.set_peakeq_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
+                f1R.set_peakeq_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
+                f2L.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f2R.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f1_active = 0.5f;
+                f2_active = 0.5f;
+                break;
+            case BANDPASS_1:
+                f1L.set_bp_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
+                f1R.set_bp_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
+                f2L.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f2R.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
+                f1_active = 1.f;
+                f2_active = 0.f;
+                break;
+            case BANDPASS_2:
+                f1L.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
+                f1R.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
+                f2L.set_lp_rbj((float)*params[param_f2_freq], 0.707, (float)srate);
+                f2R.set_lp_rbj((float)*params[param_f2_freq], 0.707, (float)srate);
+                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 compressor module
+    compressor.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);
+}
+
+void sidechaincompressor_audio_module::set_sample_rate(uint32_t sr)
+{
+    srate = sr;
+    compressor.set_sample_rate(srate);
+}
+
+uint32_t sidechaincompressor_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);
+        
+        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:
+                    compressor.process(leftAC, rightAC, leftSC, rightSC);
+                    break;
+                case DEESSER_WIDE:
+                case DERUMBLER_WIDE:
+                case WEIGHTED_1:
+                case WEIGHTED_2:
+                case WEIGHTED_3:
+                case BANDPASS_2:
+                    leftSC = f2L.process(f1L.process(leftSC));
+                    rightSC = f2L.process(f1L.process(rightSC));
+                    leftMC = leftSC;
+                    rightMC = rightSC;
+                    compressor.process(leftAC, rightAC, leftSC, rightSC);
+                    break;
+                case DEESSER_SPLIT:
+                case DERUMBLER_SPLIT:
+                    leftSC = f1L.process(leftSC);
+                    rightSC = f1L.process(rightSC);
+                    leftMC = leftSC;
+                    rightMC = rightSC;
+                    compressor.process(leftSC, rightSC, leftSC, rightSC);
+                    leftAC = f2L.process(leftAC);
+                    rightAC = f2L.process(rightAC);
+                    leftAC += leftSC;
+                    rightAC += rightSC;
+                    break;
+                case BANDPASS_1:
+                    leftSC = f1L.process(leftSC);
+                    rightSC = f1L.process(rightSC);
+                    leftMC = leftSC;
+                    rightMC = rightSC;
+                    compressor.process(leftAC, rightAC, leftSC, rightSC);
+                    break;
+            }
+            f1L.sanitize();
+            f1R.sanitize();
+            f2L.sanitize();
+            f2R.sanitize();
+            
+            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
+    }
+    // draw meters
+    if(params[param_clip_in] != NULL) {
+        *params[param_clip_in] = clip_in;
+    }
+    if(params[param_clip_out] != NULL) {
+        *params[param_clip_out] = clip_out;
+    }
+    if(params[param_meter_in] != NULL) {
+        *params[param_meter_in] = meter_in;
+    }
+    if(params[param_meter_out] != NULL) {
+        *params[param_meter_out] = meter_out;
+    }
+    // draw strip meter
+    if(bypass > 0.5f) {
+        if(params[param_compression] != NULL) {
+            *params[param_compression] = 1.0f;
+        }
+    } else {
+        if(params[param_compression] != NULL) {
+            *params[param_compression] = compressor.get_comp_level();
+        }
+    }
+    // whatever has to be returned x)
+    return outputs_mask;
+}
+bool sidechaincompressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
+{
+    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_compression) {
+        return compressor.get_graph(subindex, data, points, context);
+    }
+    return false;
+}
+
+bool sidechaincompressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
+{
+    if (!is_active)
+        return false;
+    if (index == param_compression) {
+        return compressor.get_dot(subindex, x, y, size, context);
+    }
+    return false;
+}
+
+bool sidechaincompressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
+{
+    if (!is_active)
+        return false;
+    if (index == param_compression) {
+        return compressor.get_gridline(subindex, pos, vertical, legend, context);
+    } else {
+        return get_freq_gridline(subindex, pos, vertical, legend, context);
+    }
+//    return false;
+}
+
+int sidechaincompressor_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
+{
+    if (!is_active)
+        return false;
+    if(index == param_compression) {
+        return compressor.get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
+    }
+    return false;
+}
+
 /// Gain reduction module implemented by Markus Schmidt
 /// Nearly all functions of this module are originally written
 /// by Thor, while some features have been stripped (mainly stereo linking
@@ -1081,14 +1403,20 @@ void gain_reduction_audio_module::deactivate()
     is_active = false;
 }
 
-void gain_reduction_audio_module::process(float &left, float &right)
+void gain_reduction_audio_module::process(float &left, float &right, float det_left, float det_right)
 {
+    if(!det_left) {
+        det_left = left;
+    }
+    if(!det_right) {
+        det_right = right;
+    }
     float gain = 1.f;
-    float maxLR = 0.f;
     if(bypass < 0.5f) {
         // this routine is mainly copied from thor's compressor module
         // greatest sounding compressor I've heard!
         bool rms = detection == 0;
+        bool average = stereo_link == 0;
         float linThreshold = threshold;
         float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
         float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
@@ -1101,7 +1429,7 @@ void gain_reduction_audio_module::process(float &left, float &right)
         kneeStop = log(linKneeStop);
         compressedKneeStop = (kneeStop - thres) / ratio + thres;
         
-        float absample = (fabs(left) + fabs(right)) * 0.5f;
+        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);
@@ -1110,15 +1438,12 @@ void gain_reduction_audio_module::process(float &left, float &right)
             gain = output_gain(linSlope, rms);
         }
 
-        gain *= makeup;
-        
-        left *= gain;
-        right *= gain;
-        maxLR = std::max(fabs(left), fabs(right));
+        left *= gain * makeup;
+        right *= gain * makeup;
+        meter_out = std::max(fabs(left), fabs(right));;
+        meter_comp = gain;
         detected = rms ? sqrt(linSlope) : linSlope;
     }
-    meter_out = maxLR;
-    meter_comp = gain;
 }
 
 float gain_reduction_audio_module::output_level(float slope) {
@@ -1155,7 +1480,7 @@ void gain_reduction_audio_module::set_sample_rate(uint32_t sr)
 {
     srate = sr;
 }
-void gain_reduction_audio_module::set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float byp, float mu)
+void gain_reduction_audio_module::set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu)
 {
     // set all params
     attack          = att;
@@ -1165,6 +1490,7 @@ void gain_reduction_audio_module::set_params(float att, float rel, float thr, fl
     knee            = kn;
     makeup          = mak;
     detection       = det;
+    stereo_link     = stl;
     bypass          = byp;
     mute            = mu;
     if(mute > 0.f) {

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list