[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