[SCM] calf/master: limiter and multiband limiter done, some bugs left.

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


The following commit has been merged in the master branch:
commit f40107fdd39faaae613e364da85486cc5ab646be
Author: Markus Schmidt <schmidt at boomshop.net>
Date:   Thu Dec 1 11:31:02 2011 +0100

    limiter and multiband limiter done, some bugs left.

diff --git a/gui/gui-multibandlimiter.xml b/gui/gui-multibandlimiter.xml
index 4a7f97f..3efc558 100644
--- a/gui/gui-multibandlimiter.xml
+++ b/gui/gui-multibandlimiter.xml
@@ -118,10 +118,30 @@
                     <line-graph refresh="1" width="220" height="90" param="limit" expand="0" fill="1"/>
                 </if>
                 <hbox homogenous="1">
-                    <vumeter attach-x="1" attach-y="0" param="att0" mode="2" hold="1.5" falloff="2.5" expand-x="1" fill-y="0" expand-y="0" height="12" position="2" />
-                    <vumeter attach-x="1" attach-y="1" param="att1" mode="2" hold="1.5" falloff="2.6" expand-x="1" fill-y="0" expand-y="0" height="12" position="2" />
-                    <vumeter attach-x="1" attach-y="2" param="att2" mode="2" hold="1.5" falloff="2.5" expand-x="1" fill-y="0" expand-y="0" height="12" position="2" />
-                    <vumeter attach-x="1" attach-y="3" param="att3" mode="2" hold="1.5" falloff="2.5" expand-x="1" fill-y="0" expand-y="0" height="12" position="2" />
+                    <vbox>
+                        <label param="weight0" />
+                        <knob param="weight0" size="2" />
+                        <value param="weight0" />
+                        <vumeter attach-x="1" attach-y="0" param="att0" mode="2" hold="1.5" falloff="2.5" expand-x="1" fill-y="0" expand-y="0" height="12" position="2" />
+                    </vbox>
+                    <vbox>
+                        <label param="weight1" />
+                        <knob param="weight1" size="2" />
+                        <value param="weight1" />
+                        <vumeter attach-x="1" attach-y="1" param="att1" mode="2" hold="1.5" falloff="2.6" expand-x="1" fill-y="0" expand-y="0" height="12" position="2" />
+                    </vbox>
+                    <vbox>  
+                        <label param="weight2" />
+                        <knob param="weight2" size="2" />
+                        <value param="weight2" />
+                        <vumeter attach-x="1" attach-y="2" param="att2" mode="2" hold="1.5" falloff="2.5" expand-x="1" fill-y="0" expand-y="0" height="12" position="2" />
+                    </vbox>
+                    <vbox>
+                        <label param="weight3" />
+                        <knob param="weight3" size="2" />
+                        <value param="weight3" />
+                        <vumeter attach-x="1" attach-y="3" param="att3" mode="2" hold="1.5" falloff="2.5" expand-x="1" fill-y="0" expand-y="0" height="12" position="2" />
+                    </vbox>
                 </hbox>
             </vbox>
         </frame>
diff --git a/src/audio_fx.cpp b/src/audio_fx.cpp
index 0626f80..df69576 100644
--- a/src/audio_fx.cpp
+++ b/src/audio_fx.cpp
@@ -532,61 +532,36 @@ bool simple_lfo::get_dot(float &x, float &y, int &size, cairo_iface *context) co
 }
 
 
-/// Fast Lookahead Limiter by Steve Harris
-/// [This module is used with permission of Steve Harris]
-/// THERE'S NO PERMISSION TO USE IT BY NOW!!
-/// This is a limiter with an attack time of 5ms.
-/// It adds just over 5ms of lantecy to the input signal, but it guatantees that
-/// there will be no signals over the limit, and tries to get the minimum
-/// ammount of distortion. 
+/// Lookahead Limiter by Christian Holschuh and Markus Schmidt
 
 lookahead_limiter::lookahead_limiter() {
     is_active = false;
+    channels = 2;
     
-    buffer_time = 0.0053;
-    buffer_len = 128;
-    buffer_pos = 0;
-    num_chunks = 16; // length of chunks array
-    
-    /* Find size for power-of-two interleaved delay buffer */
-    while(buffer_len < srate * buffer_time * 2) {
-        buffer_len *= 2; // (512 @ 48kHz) length of buffer array
-    }
-    buffer = (float*) calloc(buffer_len, sizeof(float));
-    memset(buffer, 0, num_chunks * sizeof(float)); // reset buffer to zero
-    delay = (int)(0.005 * srate); // (240 @ 48kHz) delay of returned samples in buffer
-
-    chunk_pos = 0; // position in chunk
-    chunk_num = 0; // count of processed chunks
-    
-    chunks = (float*) calloc(num_chunks, sizeof(float));
-    
-    
-    peak = 0.0f; // holds the latest maximum of the input values left and right
-    atten = 1.0f; // holds the "pure" attenuation level
-    atten_lp = 1.0f; // holds the calculated attenuation level
-    delta = 0.0f;
-    
-    atten_max = 1.0; // holds the latest attenuation level since last get_attenuation()
 }
 
 void lookahead_limiter::activate()
 {
     is_active = true;
+    buffer_size = (int)srate * attack * channels; // buffer size attack rate multiplied by 2 channels
+    buffer = (float*) calloc(buffer_size, sizeof(float));
+    memset(buffer, 0, buffer_size * sizeof(float)); // reset buffer to zero
     
-    memset(buffer, 0, num_chunks * sizeof(float)); // reset buffer to zero
-    
-    chunk_pos = 0;
-    chunk_num = 0;
-    
-    peak = 0.0f;
-    atten = 1.0f;
-    atten_lp = 1.0f;
-    atten_max = 1.0;
-    delta = 0.0f;
-    attask = 0;
+    att = 1.f;
+    att_max = 1.0;
+    pos = 0;
+    delta = 0.f;
+    _delta = 0.f;
+    peak = 0.f;
+    over_s = 0;
+    over_c = 1.f;
+    attack = 0.005;
+    pos_next = -1;
+    use_multi = false;
 }
 
+void lookahead_limiter::set_multi(bool set) { use_multi = set; }
+
 void lookahead_limiter::deactivate()
 {
     is_active = false;
@@ -594,90 +569,134 @@ void lookahead_limiter::deactivate()
 
 float lookahead_limiter::get_attenuation()
 {
-    float a = atten_max;
-    atten_max = 1.0;
+    float a = att_max;
+    att_max = 1.0;
     return a;
 }
 
 void lookahead_limiter::set_sample_rate(uint32_t sr)
 {
     srate = sr;
-    /* find a chunk size (in smaples) thats roughly 0.5ms */
-    chunk_size = srate / 2000; // 24 @ 48kHz
 }
 
-void lookahead_limiter::set_params(float l, float r, float g, uint32_t sr, bool d)
+void lookahead_limiter::set_params(float l, float a, float r, float w, bool ar, bool d)
 {
     limit = l;
+    attack = a / 1000.f;
     release = r / 1000.f;
-    gain = g;
-    srate = sr;
+    auto_release = ar;
     debug = d;
+    weight = w;
+    
+    if( attack != attack__) {
+        // rebuild buffer
+        buffer_size = (int)srate * attack * channels; // buffer size attack rate multiplied by 2 channels
+        buffer = (float*) calloc(buffer_size, sizeof(float));
+        memset(buffer, 0, buffer_size * sizeof(float)); // reset buffer to zero
+        attack__ = attack;
+        pos = 0;
+    }
 }
 
-void lookahead_limiter::process(float &left, float &right)
-{
-    const float trim = 1.f; // output multiplicator (added on input)
-    float sig; // cache for choosing max between peak and max between left and right
-    unsigned int i;
-    if (chunk_pos++ == chunk_size) {
-        /* we've got a full chunk */
-        // one chunk contains a peak inside [chunk_size] sample blocks
-        delta = (1.0f - atten) / (srate * release); // (0.002083 @ 48kHz/50ms)
-        round_to_zero(&delta);
-        if(debug) printf("%.5f\n", atten);
-        for (i=0; i<10; i++) {
-            // cycle over last 10 chunks
-            const int p = (chunk_num - 9 + i) & (num_chunks - 1);
-            const float this_delta = (limit / chunks[p] - atten) /
-                ((float)(i) * srate * 0.0005f + 1.0f);
-            if(debug) printf("%.5f - %.5f\n", this_delta, delta);
-            if (this_delta < delta) {
-                delta = this_delta;
-            }
+void lookahead_limiter::process(float &left, float &right, float * multi_buffer)
+{
+    // write left and right to buffer
+    buffer[pos] = left;
+    buffer[pos + 1] = right;
+    
+    // are we using multiband? get the multiband coefficient
+    float multi_coeff = (use_multi) ? multi_buffer[pos] : 1.f;
+    if(debug) printf("%.5f\n", multi_coeff);
+    // input peak - impact in left or right channel?
+    peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right);
+    
+    // if we have a peak in input over our limit, check if delta to reach is
+    // more important than actual delta
+    if(peak > limit * multi_coeff * weight) {
+        _delta = ((limit * multi_coeff * weight) / peak - att) / buffer_size * channels;
+        if(_delta < delta) {
+            delta = _delta;
+            pos_next = pos;
         }
-        if(debug) printf("%.5f\n\n", delta);
-        // store actual peak and reset peak to 0.f
-        chunks[chunk_num++ & (num_chunks - 1)] = peak;
-        peak = 0.0f;
-        
-        chunk_pos = 0;
-        //if(debug) printf("\ratt: %.4f -  - cnum: %d",
-        //          atten, chunk_num);
+        _delta = 0;
     }
     
-    // store left and right in buffer array
-    buffer[(buffer_pos * 2) & (buffer_len - 1)] =     left * trim  + 1.0e-30;
-    buffer[(buffer_pos * 2 + 1) & (buffer_len - 1)] = right * trim + 1.0e-30;
+    // switch left and right pointers to output
+    left = buffer[(pos + 2) % buffer_size];
+    right = buffer[(pos + 3) % buffer_size];
     
-    // find absolute max between left and right and store it in peak if bigger
-    sig = fabs(left) > fabs(right) ? fabs(left) : fabs(right);
-    sig += 1.0e-30;
-    if (sig * trim > peak) {
-        peak = sig * trim;
-    }
+    // check multiband coefficient again for output pointer
+    multi_coeff = (use_multi) ? multi_buffer[pos + 2] : 1.f;
+    
+    // output peak - impact in left or right channel?
+    peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right);
     
-    // calculate atten and atten_lp
-    atten += delta;
-    atten_lp = atten * 0.1f + atten_lp * 0.9f;
-    if (delta > 0.0f && atten > 1.0f) {
-        atten = 1.0f;
-        delta = 0.0f;
+    // we need  "and (pos == pos_next or pos_next < 0)" in the next if
+    // but that fucks up delta = release
+    // because this screws the CPU
+    
+    // output is over the limit?
+    if(peak > limit * multi_coeff * weight) {
+        pos_next = -1;
+        unsigned int j;
+        for(unsigned int i = 2; i < buffer_size; i += channels) {
+            // iterate over buffer (ewxcept input and output pointer positions)
+            // and search for maximum slope
+            j = (i + pos + 2) % buffer_size;
+            multi_coeff = (use_multi) ? multi_buffer[j] : 1.f;
+            float _peak = fabs(buffer[j]) > fabs(buffer[j + 1]) ? fabs(buffer[j]) : fabs(buffer[j + 1]);
+            // calculate steepness of slope
+            if(_peak > limit * multi_coeff * weight) {
+                _delta = ((limit * multi_coeff * weight) / peak - att) / i;
+            }
+            // if slope is steeper, use it, fucker.
+            if(_delta < delta) {
+                delta = _delta;
+                pos_next = j;
+            } else {
+                // or do a normal release
+                delta = (1.0f - att) / (srate * release);
+            }
+        }
+        _delta = 0;
     }
     
-    // return left and right from buffer and multiply with atten_lp
-    left = buffer[(buffer_pos * 2 - delay * 2) & (buffer_len - 1)] * atten_lp;
-    right = buffer[(buffer_pos * 2 - delay * 2 + 1) & (buffer_len - 1)] * atten_lp;
+    // change the attenuation level
+    att += delta;
+    
+    // ...and calculate outpout from it
+    left *= att;
+    right *= att;
+    
     
+    // some security personnel pawing your values
+    if (att > 1.0f) {
+	    att = 1.0f;
+	    delta = 0.0f;
+	}
+	
+	if(att < 0.f) {
+	    att = 0.0000000001;
+	    delta = (1.0f - att) / (srate * release);
+	}
+	
+	if(1 - att < 0.00000001) {
+	    att = 1.f;
+	}
+	
+	if(fabs(delta) < 0.000000001) {
+	    delta = 0.f;
+	}
+	
     // post treatment (denormal, limit)
-    round_to_zero(&left);
-    round_to_zero(&right);
-    std::max(left, -limit);
-    std::min(left, limit);
-    std::max(right, -limit);
-    std::min(right, limit);
+    denormal(&left);
+    denormal(&right);
+    left = std::max(left, -limit * multi_coeff * weight);
+    left = std::min(left, limit * multi_coeff * weight);
+    right = std::max(right, -limit * multi_coeff * weight);
+    right = std::min(right, limit * multi_coeff * weight);
     
-    atten_max = (atten < atten_max) ? atten : atten_max; // store max atten for meter output
+    att_max = (att < att_max) ? att : att_max; // store max atten for meter output
     
-    buffer_pos++; // iterator
+    pos = (pos + channels) % buffer_size;
 }
diff --git a/src/calf/audio_fx.h b/src/calf/audio_fx.h
index 7aa5480..c0df094 100644
--- a/src/calf/audio_fx.h
+++ b/src/calf/audio_fx.h
@@ -566,52 +566,38 @@ public:
 };
 
 
-/// Fast Lookahead Limiter by Steve Harris
-/// [This module is used with permission of Steve Harris]
-/// THERE'S NO PERMISSION TO USE IT BY NOW!!
-/// This is a limiter with an attack time of 5ms.
-/// It adds just over 5ms of lantecy to the input signal, but it guatantees that
-/// there will be no signals over the limit, and tries to get the minimum
-/// ammount of distortion. 
-
-// Convert a value in dB's to a coefficent
-#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f)
-#define CO_DB(v) (20.0f * log10f(v))
-
+/// Lookahead Limiter by Markus Schmidt
 class lookahead_limiter {
 private:
-    float limit, release, gain;
-    int num_chunks;
-    float buffer_time;
-    float latency;
-    float * buffer;
-    unsigned int buffer_len;
-    unsigned int buffer_pos;
+    float limit, attack, release, weight;
+    float attack__;
     uint32_t srate;
-    float atten;
-    float atten_lp;
-    float atten_max;
-    float peak;
-    float delta;
-    int attask;
-    unsigned int delay;
-    unsigned int chunk_num;
-    unsigned int chunk_pos;
-    unsigned int chunk_size;
-    float * chunks;
+    float att;
+    float att_max;
+    unsigned int pos;
+    unsigned int buffer_size;
     bool is_active;
     bool debug;
+    bool auto_release;
+    float *buffer;
+    int channels;
+    float delta;
+    float _delta;
+    float peak;
+    unsigned int over_s;
+    float over_c;
+    int pos_next;
+    bool use_multi;
 public:
-    int id;
     lookahead_limiter();
-    void process(float &left, float &right);
+    void set_multi(bool set);
+    void process(float &left, float &right, float * multi_buffer);
     void set_sample_rate(uint32_t sr);
-    void set_params(float l, float r, float g, uint32_t sr, bool d = false);
+    void set_params(float l, float a, float r, float weight = 1.f, bool ar = false, bool d = false);
     float get_attenuation();
     void activate();
     void deactivate();
-    static inline void round_to_zero(volatile float *f)
-    {
+    static inline void denormal(volatile float *f) {
 	    *f += 1e-18;
 	    *f -= 1e-18;
     }
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index 8723770..0c496a3 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -252,8 +252,9 @@ struct multibandlimiter_metadata: public plugin_metadata<multibandlimiter_metada
            param_sep0, param_sep1, param_sep2,
            param_q0, param_q1, param_q2,
            param_mode,
-           param_limit, param_release,
+           param_limit, param_attack, param_release,
            param_att0, param_att1, param_att2, param_att3,
+           param_weight0, param_weight1, param_weight2, param_weight3, 
            param_count };
     PLUGIN_NAME_ID_LABEL("multiband_limiter", "multibandlimiter", "Multiband Limiter")
 };
diff --git a/src/calf/modules_limit.h b/src/calf/modules_limit.h
index 8a20c35..1626ab3 100644
--- a/src/calf/modules_limit.h
+++ b/src/calf/modules_limit.h
@@ -62,6 +62,11 @@ private:
     dsp::lookahead_limiter strip[strips];
     dsp::biquad_d2<float> lpL[3][3], lpR[3][3], hpL[3][3], hpR[3][3];
     float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1];
+    unsigned int pos;
+    unsigned int buffer_size;
+    float attack_old;
+    float *buffer;
+    int channels;
 public:
     uint32_t srate;
     bool is_active;
diff --git a/src/gui.cpp b/src/gui.cpp
index b26e291..f540f56 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -445,6 +445,7 @@ void about_action(GtkAction *action, plugin_gui_window *gui_win)
         "Hans Baier <hansfbaier at googlemail.com>",
         "Torben Hohn <torbenh at gmx.de>",
         "Markus Schmidt <schmidt at boomshop.net>",
+        "Christian Holschuh <chrisch.holli at gmx.de>",
         "Tom Szilagyi <tomszilagyi at gmail.com>",
         "Damien Zammit <damien.zammit at gmail.com>",
         "David T\xC3\xA4ht <d at teklibre.com>",
@@ -461,7 +462,7 @@ void about_action(GtkAction *action, plugin_gui_window *gui_win)
     gtk_about_dialog_set_program_name(dlg, ("Calf " + label).c_str());
     gtk_about_dialog_set_version(dlg, PACKAGE_VERSION);
     gtk_about_dialog_set_website(dlg, "http://calf.sourceforge.net/");
-    gtk_about_dialog_set_copyright(dlg, "Copyright \xC2\xA9 2001-2010 Krzysztof Foltman, Thor Harald Johansen, Markus Schmidt and others.\nSee AUTHORS file for the full list.");
+    gtk_about_dialog_set_copyright(dlg, "Copyright \xC2\xA9 2001-2011 Krzysztof Foltman, Thor Harald Johansen, Markus Schmidt and others.\nSee AUTHORS file for the full list.");
     gtk_about_dialog_set_logo_icon_name(dlg, "calf");
     gtk_about_dialog_set_artists(dlg, artists);
     gtk_about_dialog_set_authors(dlg, authors);
diff --git a/src/metadata.cpp b/src/metadata.cpp
index 20e23ee..ae0ec72 100644
--- a/src/metadata.cpp
+++ b/src/metadata.cpp
@@ -507,7 +507,7 @@ CALF_PORT_PROPS(limiter) = {
     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" },
     
     { 1,      0.0625, 1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "limit", "Limit" },
-    { 2,         0.1,        10,  0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" },
+    { 5,         0.1,        100,  0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" },
     { 50,         1,        1000,  0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" },
     
     { 1,           0.125,     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, "att", "Attenuation" },
@@ -515,7 +515,7 @@ CALF_PORT_PROPS(limiter) = {
     {}
 };
 
-CALF_PLUGIN_INFO(limiter) = { 0x8521, "Limiter", "Calf Limiter", "Markus Schmidt", calf_plugins::calf_copyright_info, "LimiterPlugin" };
+CALF_PLUGIN_INFO(limiter) = { 0x8521, "Limiter", "Calf Limiter", "Christian Holschuh / Markus Schmidt", calf_plugins::calf_copyright_info, "LimiterPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 
@@ -543,13 +543,14 @@ CALF_PORT_PROPS(multibandlimiter) = {
     { -0.17,      -0.5,         0.5,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep1", "S2" },
     { -0.17,      -0.5,         0.5,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep2", "S3" },
     
-    { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q1" },
-    { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q2" },
-    { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q3" },
+    { 0.7762471166286917,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q1" },
+    { 0.7762471166286917,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q2" },
+    { 0.7762471166286917,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q3" },
     
     { 1,      0,  1,    0, PF_ENUM | PF_CTL_COMBO, multibandlimiter_filter_choices, "mode", "Filter Mode" },
     
     { 1,      0.0625, 1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "limit", "Limit" },
+    { 5,         0.1,        100,  0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" },
     { 50,         1,        1000,  0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" },
     
     { 1,           0.125,     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, "att0", "Low" },
@@ -557,10 +558,15 @@ CALF_PORT_PROPS(multibandlimiter) = {
     { 1,           0.125,     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, "att2", "HMid" },
     { 1,           0.125,     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, "att3", "Hi" },
     
+    { 0.f,      -1.f,         1.f,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "weight0", "Weight 1" },
+    { 0.f,      -1.f,         1.f,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "weight1", "Weight 2" },
+    { 0.f,      -1.f,         1.f,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "weight2", "Weight 3" },
+    { 0.f,      -1.f,         1.f,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "weight3", "Weight 4" },
+    
     {}
 };
 
-CALF_PLUGIN_INFO(multibandlimiter) = { 0x8520, "Multibandlimiter", "Calf Multiband Limiter", "Markus Schmidt", calf_plugins::calf_copyright_info, "LimiterPlugin" };
+CALF_PLUGIN_INFO(multibandlimiter) = { 0x8520, "Multibandlimiter", "Calf Multiband Limiter", "Markus Schmidt / Christian Holschuh", calf_plugins::calf_copyright_info, "LimiterPlugin" };
 
 
 ////////////////////////////////////////////////////////////////////////////
diff --git a/src/modules_limit.cpp b/src/modules_limit.cpp
index a82f645..f826f05 100644
--- a/src/modules_limit.cpp
+++ b/src/modules_limit.cpp
@@ -68,7 +68,7 @@ void limiter_audio_module::deactivate()
 
 void limiter_audio_module::params_changed()
 {
-    limiter.set_params(*params[param_limit], *params[param_release], 1.f, srate);
+    limiter.set_params(*params[param_limit], *params[param_attack], *params[param_release], 1.f, true, true);
 }
 
 void limiter_audio_module::set_sample_rate(uint32_t sr)
@@ -119,7 +119,12 @@ uint32_t limiter_audio_module::process(uint32_t offset, uint32_t numsamples, uin
             float outR = inR;
             
             // process gain reduction
-            limiter.process(outL, outR);
+            float fickdich[0];
+            limiter.process(outL, outR, fickdich);
+            
+            // autolevel
+            outL /= *params[param_limit];
+            outR /= *params[param_limit];
             
             // out level
             outL *= *params[param_level_out];
@@ -204,6 +209,8 @@ multibandlimiter_audio_module::multibandlimiter_audio_module()
     meter_inR  = 0.f;
     meter_outL = 0.f;
     meter_outR = 0.f;
+    attack_old = -1.f;
+    channels = 2;
 }
 
 void multibandlimiter_audio_module::activate()
@@ -214,8 +221,9 @@ void multibandlimiter_audio_module::activate()
     // activate all strips
     for (int j = 0; j < strips; j ++) {
         strip[j].activate();
-        strip[j].id = j;
+        strip[j].set_multi(true);
     }
+    pos = 0;
 }
 
 void multibandlimiter_audio_module::deactivate()
@@ -288,10 +296,20 @@ void multibandlimiter_audio_module::params_changed()
         q_old[2]    = *params[param_q2];
     }
     // set the params of all strips
-    strip[0].set_params(*params[param_limit], std::max(1.f / 30, *params[param_release]), 1.f, srate);
-    strip[1].set_params(*params[param_limit], std::max(1.f / *params[param_freq0], *params[param_release]), 1.f, srate);
-    strip[2].set_params(*params[param_limit], std::max(1.f / *params[param_freq1], *params[param_release]), 1.f, srate);
-    strip[3].set_params(*params[param_limit], std::max(1.f / *params[param_freq2], *params[param_release]), 1.f, srate, true);
+    strip[0].set_params(*params[param_limit], *params[param_attack], std::max(3 * (1.f / 30), *params[param_release]), *params[param_weight0] + 1, true, true);
+    strip[1].set_params(*params[param_limit], *params[param_attack], std::max(3 * (1.f / *params[param_freq0]), *params[param_release]), *params[param_weight1] + 1, true);
+    strip[2].set_params(*params[param_limit], *params[param_attack], std::max(3 * (1.f / *params[param_freq1]), *params[param_release]), *params[param_weight2] + 1, true);
+    strip[3].set_params(*params[param_limit], *params[param_attack], std::max(3 * (1.f / *params[param_freq2]), *params[param_release]), *params[param_weight3] + 1, true);
+    
+    // rebuild multiband buffer
+    if( *params[param_attack] != attack_old) {
+        // rebuild buffer
+        buffer_size = (int)srate * *params[param_attack] * channels; // buffer size attack rate
+        buffer = (float*) calloc(buffer_size, sizeof(float));
+        memset(buffer, 0, buffer_size * sizeof(float)); // reset buffer to zero
+        attack_old = *params[param_attack];
+        pos = 0;
+    }
 }
 
 void multibandlimiter_audio_module::set_sample_rate(uint32_t sr)
@@ -310,7 +328,7 @@ void multibandlimiter_audio_module::set_sample_rate(uint32_t sr)
 #define ACTIVE_COMPRESSION(index) \
     if(params[param_att##index] != NULL) \
         *params[param_att##index] = strip[index].get_attenuation(); \
-
+        
 uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
 {
     bool bypass = *params[param_bypass] > 0.5f;
@@ -345,6 +363,8 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
         meter_inR = 0.f;
         meter_outL = 0.f;
         meter_outR = 0.f;
+        float _tmpL[channels];
+        float _tmpR[channels];
         while(offset < numsamples) {
             // cycle through samples
             float inL = ins[0][offset];
@@ -358,6 +378,8 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
             int j1;
             float left;
             float right;
+            float sum_left = 0.f;
+            float sum_right = 0.f;
             for (int i = 0; i < strips; i++) {
                 left  = inL;
                 right = inR;
@@ -385,12 +407,41 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
                         hpR[i - 1][j].sanitize();
                     }
                 }
+                _tmpL[i] = left;
+                _tmpR[i] = right;
+                float k;
+                switch (i) {
+                    case 0:
+                        k = *params[param_weight0] + 1;
+                        break;
+                    case 1:
+                        k = *params[param_weight1] + 1;
+                        break;
+                    case 2:
+                        k = *params[param_weight2] + 1;
+                        break;
+                    case 3:
+                        k = *params[param_weight3] + 1;
+                        break;
+                }
+                            
+                sum_left += left * k;
+                sum_right += right * k;
+            } // process single strip with filter
+            
+            // write multiband coefficient to buffer
+            buffer[pos] = *params[param_limit] / std::min(fabs(sum_left), fabs(sum_right));
+            
+            for (int i = 0; i < strips; i++) {
                 // process gain reduction
-                strip[i].process(left, right);
+                strip[i].process(_tmpL[i], _tmpR[i], buffer);
                 // sum up output
-                outL += left;
-                outR += right;
-            } // process single strip
+                // autolevel
+                _tmpL[i] /= *params[param_limit];
+                _tmpR[i] /= *params[param_limit];
+                outL += _tmpL[i];
+                outR += _tmpR[i];
+            } // process single strip again for limiter
             
             // even out filters gain reduction
             // 3dB - levelled manually (based on default sep and q settings)
@@ -400,8 +451,8 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
                     outR *= 1.414213562;
                     break;
                 case 1:
-                    outL *= 0.61;
-                    outR *= 0.61;
+                    outL *= 0.88;
+                    outR *= 0.88;
                     break;
             }
             // out level
@@ -465,6 +516,8 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
         ACTIVE_COMPRESSION(2)
         ACTIVE_COMPRESSION(3)
     }
+    
+    pos = (pos += channels) % buffer_size;
     // whatever has to be returned x)
     return outputs_mask;
 }

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list