[SCM] calf/master: Implement Automatic Smoothing Control.
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:40:48 UTC 2013
The following commit has been merged in the master branch:
commit 34029715279608cc5e23e903824323dc5e074a12
Author: Markus Schmidt <schmidt at boomshop.net>
Date: Sun Dec 25 12:14:14 2011 +0000
Implement Automatic Smoothing Control.
diff --git a/gui/gui-limiter.xml b/gui/gui-limiter.xml
index b4d3d13..2d678b2 100644
--- a/gui/gui-limiter.xml
+++ b/gui/gui-limiter.xml
@@ -17,10 +17,7 @@
<led param="clip_inR" expand="0" fill="0" />
<label text="0dB" expand="0" fill="0" />
</vbox>
- <vbox expand="0" attach-x="3" attach-y="0" expand-x="0" fill-x="0" fill="0" pad-x="2">
- <label param="bypass"/>
- <align><toggle param="bypass" shrink="1"/></align>
- </vbox>
+ <label attach-x="3" attach-y="0"/>
<vbox shrink-x="1" expand-x="1" fill-x="1" expand="0" fill="0" attach-x="4" attach-y="0">
<label param="meter_outL" />
<vumeter param="meter_outL" mode="0" hold="1.5" falloff="2.5" shrink-y="0" position="2" width="120" />
@@ -41,7 +38,12 @@
</table>
<frame attach-x="0" attach-y="1" label="Limit" expand="0" fill="1">
- <hbox homogenous="1">
+ <hbox homogenous="1" spacing="25">
+ <vbox>
+ <label param="bypass"/>
+ <align><toggle param="bypass" shrink="1"/></align>
+ <label />
+ </vbox>
<vbox>
<label param="attack" />
<knob param="attack" size="3" />
@@ -57,6 +59,11 @@
<knob param="release" size="3" />
<value param="release" />
</vbox>
+ <vbox>
+ <label param="asc"/>
+ <align><toggle param="asc"/></align>
+ <align><led param="asc_led" /></align>
+ </vbox>
</hbox>
</frame>
diff --git a/gui/gui-multibandlimiter.xml b/gui/gui-multibandlimiter.xml
index d0657db..02dfb7c 100644
--- a/gui/gui-multibandlimiter.xml
+++ b/gui/gui-multibandlimiter.xml
@@ -109,20 +109,15 @@
<frame label="Limit" expand="0" fill="1">
<vbox spacing="20">
- <vbox>
- <knob param="limit" size="5" type="2" />
- <value param="limit" />
- </vbox>
<hbox>
- <vbox>
+ <vbox spacing="0">
<label param="attack" />
<knob param="attack" />
<value param="attack" />
</vbox>
<vbox>
- <label param="minrel" />
- <toggle param="minrel" />
- <label/>
+ <knob param="limit" size="5" type="2" />
+ <value param="limit" />
</vbox>
<vbox>
<label param="release" />
@@ -130,6 +125,22 @@
<value param="release" />
</vbox>
</hbox>
+
+ <hbox>
+ <label />
+ <vbox expand="0" fill="0" spacing="8">
+ <label param="minrel" />
+ <toggle param="minrel" />
+ <label />
+ </vbox>
+ <label />
+ <vbox expand="0" fill="0" spacing="8">
+ <label param="asc" />
+ <toggle param="asc" />
+ <align><led param="asc_led" /></align>
+ </vbox>
+ <label />
+ </hbox>
</vbox>
</frame>
diff --git a/src/audio_fx.cpp b/src/audio_fx.cpp
index 024b207..decb839 100644
--- a/src/audio_fx.cpp
+++ b/src/audio_fx.cpp
@@ -551,10 +551,11 @@ lookahead_limiter::lookahead_limiter() {
over_c = 1.f;
attack = 0.005;
__attack = -1;
- pos_next = -1;
use_multi = false;
weight = 1.f;
_sanitize = false;
+ auto_release = false;
+ asc_active = false;
}
void lookahead_limiter::activate()
@@ -607,7 +608,10 @@ void lookahead_limiter::set_params(float l, float a, float r, float w, bool ar,
}
void lookahead_limiter::process(float &left, float &right, float * multi_buffer)
-{
+{
+ // PROTIP: harming paying customers enough to make them develop a competing
+ // product may be considered an example of a less than sound business practice.
+
// write left and right to buffer
buffer[pos] = 0.f;
buffer[pos + 1] = 0.f;
@@ -629,7 +633,6 @@ void lookahead_limiter::process(float &left, float &right, float * multi_buffer)
_delta = ((limit * multi_coeff * weight) / peak - att) / (buffer_size / channels - channels);
if(_delta < delta) {
delta = _delta;
- pos_next = pos;
}
}
@@ -643,21 +646,19 @@ void lookahead_limiter::process(float &left, float &right, float * multi_buffer)
// output peak - impact in left or right channel?
peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right);
- // 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?
// then we have to search for new delta.
// the idea is to calculate a delta for every peak and always use the
// lowest. this produces a soft transition between limiting targets without
// passing values above limit
+ asc_active = false;
if(peak > limit * multi_coeff * weight) {
// default is to do a release
- delta = (1.0f - att) / (srate * release);
- pos_next = -1;
+ delta = (1.f - att) / (srate * release);
unsigned int j;
+ float b_sum = 0.f;
+ unsigned int b_sum_c = 0;
for(unsigned int i = channels; i < buffer_size; i += channels) {
// iterate over buffer (except input and output pointer positions)
// and search for maximum slope
@@ -670,12 +671,22 @@ void lookahead_limiter::process(float &left, float &right, float * multi_buffer)
// if slope is steeper, use it, fucker.
if(_delta < delta) {
delta = _delta;
- pos_next = j;
}
+ b_sum += _peak;
+ b_sum_c ++;
}
}
+ if(auto_release) {
+ // This is Auto-Smoothness-Control (wink wink, nudge nudge)
+ // check if releasing to average level of peaks is steeper than
+ // releasing to 1.f
+ _delta = ((limit * weight) / (float)(b_sum / b_sum_c) - att) / (srate * release);
+ asc_active = _delta < delta ? true : false;
+ delta = _delta < delta ? _delta : delta;
+ } else {
+ asc_active = false;
+ }
}
-
// change the attenuation level
att += delta;
// ...and calculate outpout from it
@@ -725,3 +736,7 @@ void lookahead_limiter::process(float &left, float &right, float * multi_buffer)
pos = (pos + channels) % buffer_size;
if(pos == 0) _sanitize = false;
}
+
+bool lookahead_limiter::get_arc() {
+ return asc_active;
+}
diff --git a/src/calf/audio_fx.h b/src/calf/audio_fx.h
index 5d23849..33c3ebf 100644
--- a/src/calf/audio_fx.h
+++ b/src/calf/audio_fx.h
@@ -567,7 +567,6 @@ public:
/// Lookahead Limiter by Markus Schmidt and Christian Holschuh
-
class lookahead_limiter {
private:
public:
@@ -582,6 +581,7 @@ public:
bool is_active;
bool debug;
bool auto_release;
+ bool asc_active;
float *buffer;
int channels;
float delta;
@@ -589,7 +589,6 @@ public:
float peak;
unsigned int over_s;
float over_c;
- int pos_next;
bool use_multi;
unsigned int id;
bool _sanitize;
@@ -597,6 +596,7 @@ public:
*f += 1e-18;
*f -= 1e-18;
}
+ bool get_arc();
lookahead_limiter();
void set_multi(bool set);
void process(float &left, float &right, float *multi_buffer);
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index 85eff76..5ffcea6 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -239,6 +239,7 @@ struct limiter_metadata: public plugin_metadata<limiter_metadata>
STEREO_VU_METER_PARAMS,
param_limit, param_attack, param_release,
param_att,
+ param_asc, param_asc_led,
param_count };
PLUGIN_NAME_ID_LABEL("limiter", "limiter", "Limiter")
};
@@ -258,7 +259,8 @@ struct multibandlimiter_metadata: public plugin_metadata<multibandlimiter_metada
param_weight0, param_weight1, param_weight2, param_weight3,
param_release0, param_release1, param_release2, param_release3,
param_solo0, param_solo1, param_solo2, param_solo3,
- param_effrelease0, param_effrelease1, param_effrelease2, param_effrelease3,
+ param_effrelease0, param_effrelease1, param_effrelease2, param_effrelease3,
+ param_asc, param_asc_led,
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 3c6c3f6..74bfe19 100644
--- a/src/calf/modules_limit.h
+++ b/src/calf/modules_limit.h
@@ -36,7 +36,7 @@ namespace calf_plugins {
class limiter_audio_module: public audio_module<limiter_metadata>, public line_graph_iface {
private:
typedef limiter_audio_module AM;
- uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
+ uint32_t clip_inL, clip_inR, clip_outL, clip_outR, asc_led;
int mode, mode_old;
float meter_inL, meter_inR, meter_outL, meter_outR;
dsp::lookahead_limiter limiter;
@@ -56,7 +56,7 @@ class multibandlimiter_audio_module: public audio_module<multibandlimiter_metada
private:
typedef multibandlimiter_audio_module AM;
static const int strips = 4;
- uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
+ uint32_t clip_inL, clip_inR, clip_outL, clip_outR, asc_led;
int mode, mode_old;
bool solo[strips];
bool no_solo;
diff --git a/src/metadata.cpp b/src/metadata.cpp
index 42d3c22..b7172fb 100644
--- a/src/metadata.cpp
+++ b/src/metadata.cpp
@@ -514,6 +514,10 @@ CALF_PORT_PROPS(limiter) = {
{ 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" },
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "asc", "ASC" },
+
+ { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "asc_led", "asc active" },
+
{}
};
@@ -580,6 +584,11 @@ CALF_PORT_PROPS(multibandlimiter) = {
{ 1, 0.f, 1000, 0, PF_FLOAT | PF_UNIT_MSEC | PF_PROP_OUTPUT, NULL, "effrelease1", "Effectively Release 2" },
{ 1, 0.f, 1000, 0, PF_FLOAT | PF_UNIT_MSEC | PF_PROP_OUTPUT, NULL, "effrelease2", "Effectively Release 3" },
{ 1, 0.f, 1000, 0, PF_FLOAT | PF_UNIT_MSEC | PF_PROP_OUTPUT, NULL, "effrelease3", "Effectively Release 4" },
+
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "asc", "ASC" },
+
+ { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "asc_led", "asc active" },
+
{}
};
diff --git a/src/modules_limit.cpp b/src/modules_limit.cpp
index 9126cee..05f2176 100644
--- a/src/modules_limit.cpp
+++ b/src/modules_limit.cpp
@@ -47,6 +47,7 @@ limiter_audio_module::limiter_audio_module()
meter_inR = 0.f;
meter_outL = 0.f;
meter_outR = 0.f;
+ asc_led = 0.f;
}
void limiter_audio_module::activate()
@@ -65,7 +66,7 @@ void limiter_audio_module::deactivate()
void limiter_audio_module::params_changed()
{
- limiter.set_params(*params[param_limit], *params[param_attack], *params[param_release], 1.f, true, true);
+ limiter.set_params(*params[param_limit], *params[param_attack], *params[param_release], 1.f, *params[param_asc], true);
}
void limiter_audio_module::set_sample_rate(uint32_t sr)
@@ -94,6 +95,7 @@ uint32_t limiter_audio_module::process(uint32_t offset, uint32_t numsamples, uin
meter_inR = 0.f;
meter_outL = 0.f;
meter_outR = 0.f;
+ asc_led = 0.f;
} else {
// let meters fall a bit
clip_inL -= std::min(clip_inL, numsamples);
@@ -104,6 +106,8 @@ uint32_t limiter_audio_module::process(uint32_t offset, uint32_t numsamples, uin
meter_inR = 0.f;
meter_outL = 0.f;
meter_outR = 0.f;
+ asc_led -= std::min(asc_led, numsamples);
+
while(offset < numsamples) {
// cycle through samples
float inL = ins[0][offset];
@@ -118,6 +122,8 @@ uint32_t limiter_audio_module::process(uint32_t offset, uint32_t numsamples, uin
// process gain reduction
float fickdich[0];
limiter.process(outL, outR, fickdich);
+ if(limiter.get_arc())
+ asc_led = srate >> 3;
// autolevel
outL /= *params[param_limit];
@@ -173,6 +179,8 @@ uint32_t limiter_audio_module::process(uint32_t offset, uint32_t numsamples, uin
SET_IF_CONNECTED(meter_outL);
SET_IF_CONNECTED(meter_outR);
+ if (params[param_asc_led] != NULL) *params[param_asc_led] = asc_led;
+
if (*params[param_att]) {
if(bypass)
*params[param_att] = 1.f;
@@ -205,6 +213,7 @@ multibandlimiter_audio_module::multibandlimiter_audio_module()
meter_inR = 0.f;
meter_outL = 0.f;
meter_outR = 0.f;
+ asc_led = 0.f;
__attack = -1.f;
channels = 2;
buffer_size = 0;
@@ -320,24 +329,24 @@ void multibandlimiter_audio_module::params_changed()
rel = *params[param_release] * pow(0.25, *params[param_release0] * -1);
rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / 30), rel) : rel;
weight[0] = pow(0.25, *params[param_weight0] * -1);
- strip[0].set_params(*params[param_limit], *params[param_attack], rel, weight[0], true, true);
+ strip[0].set_params(*params[param_limit], *params[param_attack], rel, weight[0], *params[param_asc], true);
*params[param_effrelease0] = rel;
rel = *params[param_release] * pow(0.25, *params[param_release1] * -1);
rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq0]), rel) : rel;
weight[1] = pow(0.25, *params[param_weight1] * -1);
- strip[1].set_params(*params[param_limit], *params[param_attack], rel, weight[1], true);
+ strip[1].set_params(*params[param_limit], *params[param_attack], rel, weight[1], *params[param_asc]);
*params[param_effrelease1] = rel;
rel = *params[param_release] * pow(0.25, *params[param_release2] * -1);
rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq1]), rel) : rel;
weight[2] = pow(0.25, *params[param_weight2] * -1);
- strip[2].set_params(*params[param_limit], *params[param_attack], rel, weight[2], true);
+ strip[2].set_params(*params[param_limit], *params[param_attack], rel, weight[2], *params[param_asc]);
*params[param_effrelease2] = rel;
rel = *params[param_release] * pow(0.25, *params[param_release3] * -1);
rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq2]), rel) : rel;
weight[3] = pow(0.25, *params[param_weight3] * -1);
- strip[3].set_params(*params[param_limit], *params[param_attack], rel, weight[3], true);
+ strip[3].set_params(*params[param_limit], *params[param_attack], rel, weight[3], *params[param_asc]);
*params[param_effrelease3] = rel;
- broadband.set_params(*params[param_limit], *params[param_attack], rel, 1.f);
+ broadband.set_params(*params[param_limit], *params[param_attack], rel, 1.f, *params[param_asc]);
// rebuild multiband buffer
if( *params[param_attack] != __attack) {
int bs = (int)(srate * (*params[param_attack] / 1000.f) * channels);
@@ -392,6 +401,7 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
meter_inR = 0.f;
meter_outL = 0.f;
meter_outR = 0.f;
+ asc_led = 0.f;
} else {
// process all strips
@@ -400,6 +410,7 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
clip_inR -= std::min(clip_inR, numsamples);
clip_outL -= std::min(clip_outL, numsamples);
clip_outR -= std::min(clip_outR, numsamples);
+ asc_led -= std::min(asc_led, numsamples);
meter_inL = 0.f;
meter_inR = 0.f;
meter_outL = 0.f;
@@ -437,6 +448,7 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
float right;
float sum_left = 0.f;
float sum_right = 0.f;
+ bool asc_active = false;
for (int i = 0; i < strips; i++) {
left = inL;
right = inR;
@@ -489,6 +501,7 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
outL += _tmpL[i];
outR += _tmpR[i];
}
+ asc_active = asc_active || strip[i].get_arc();
} // process single strip again for limiter
float fickdich[0];
broadband.process(outL, outR, fickdich);
@@ -532,6 +545,9 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
if(outR > meter_outR) {
meter_outR = outR;
}
+ if(asc_active) {
+ asc_led = srate >> 3;
+ }
// next sample
++offset;
pos = (pos + channels) % buffer_size;
@@ -549,6 +565,9 @@ uint32_t multibandlimiter_audio_module::process(uint32_t offset, uint32_t numsam
SET_IF_CONNECTED(meter_inR);
SET_IF_CONNECTED(meter_outL);
SET_IF_CONNECTED(meter_outR);
+
+ if (params[param_asc_led] != NULL) *params[param_asc_led] = asc_led;
+
// draw strip meters
if(bypass > 0.5f) {
if(params[param_att0] != NULL) *params[param_att0] = 1.0;
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list