New attack and release behavior for a-comp

Details in http://tracker.ardour.org/view.php?id=7439
This commit is contained in:
Johannes Mueller 2017-08-03 12:05:46 +02:00 committed by Robin Gareus
parent 112ac13b90
commit d29880da89

View file

@ -78,9 +78,8 @@ typedef struct {
float* output1; float* output1;
float srate; float srate;
float old_yl;
float old_y1; float old_in_peak_db;
float old_yg;
float makeup_gain; float makeup_gain;
@ -100,8 +99,6 @@ typedef struct {
float v_thresdb; float v_thresdb;
float v_gainr; float v_gainr;
float v_makeup; float v_makeup;
float v_lvl;
float v_lv1;
float v_lvl_in; float v_lvl_in;
float v_lvl_out; float v_lvl_out;
#endif #endif
@ -124,7 +121,6 @@ instantiate(const LV2_Descriptor* descriptor,
} }
acomp->srate = rate; acomp->srate = rate;
acomp->old_yl=acomp->old_y1=acomp->old_yg=0.f;
acomp->makeup_gain = 1.f; acomp->makeup_gain = 1.f;
#ifdef LV2_EXTENDED #ifdef LV2_EXTENDED
acomp->need_expose = true; acomp->need_expose = true;
@ -134,7 +130,6 @@ instantiate(const LV2_Descriptor* descriptor,
return (LV2_Handle)acomp; return (LV2_Handle)acomp;
} }
static void static void
connect_port(LV2_Handle instance, connect_port(LV2_Handle instance,
uint32_t port, uint32_t port,
@ -256,7 +251,7 @@ activate(LV2_Handle instance)
*(acomp->gainr) = 0.0f; *(acomp->gainr) = 0.0f;
*(acomp->outlevel) = -45.0f; *(acomp->outlevel) = -45.0f;
acomp->old_yl=acomp->old_y1=acomp->old_yg=0.f; acomp->old_in_peak_db = -160.0f;
} }
static void static void
@ -270,14 +265,16 @@ run_mono(LV2_Handle instance, uint32_t n_samples)
float srate = acomp->srate; float srate = acomp->srate;
float width = (6.f * *(acomp->knee)) + 0.01; float width = (6.f * *(acomp->knee)) + 0.01;
float cdb=0.f;
float attack_coeff = exp(-1000.f/(*(acomp->attack) * srate)); float attack_coeff = exp(-1000.f/(*(acomp->attack) * srate));
float release_coeff = exp(-1000.f/(*(acomp->release) * srate)); float release_coeff = exp(-1000.f/(*(acomp->release) * srate));
float max = 0.f; float max = 0.f;
float lgaininp = 0.f; float lgaininp = 0.f;
float Lgain = 1.f; float Lgain = 1.f;
float Lxg, Lxl, Lyg, Lyl, Ly1; float Lxg, Lyg;
float current_gainr;
float old_gainr = *acomp->gainr;
int usesidechain = (*(acomp->sidechain) <= 0.f) ? 0 : 1; int usesidechain = (*(acomp->sidechain) <= 0.f) ? 0 : 1;
uint32_t i; uint32_t i;
float ingain; float ingain;
@ -333,7 +330,6 @@ run_mono(LV2_Handle instance, uint32_t n_samples)
Lxg = (ingain==0.f) ? -160.f : to_dB(ingain); Lxg = (ingain==0.f) ? -160.f : to_dB(ingain);
Lxg = sanitize_denormal(Lxg); Lxg = sanitize_denormal(Lxg);
if (2.f*(Lxg-thresdb) < -width) { if (2.f*(Lxg-thresdb) < -width) {
Lyg = Lxg; Lyg = Lxg;
} else if (2.f*(Lxg-thresdb) > width) { } else if (2.f*(Lxg-thresdb) > width) {
@ -343,21 +339,23 @@ run_mono(LV2_Handle instance, uint32_t n_samples)
Lyg = Lxg + (1.f/ratio-1.f)*(Lxg-thresdb+width/2.f)*(Lxg-thresdb+width/2.f)/(2.f*width); Lyg = Lxg + (1.f/ratio-1.f)*(Lxg-thresdb+width/2.f)*(Lxg-thresdb+width/2.f)/(2.f*width);
} }
Lxl = Lxg - Lyg; current_gainr = Lxg - Lyg;
acomp->old_y1 = sanitize_denormal(acomp->old_y1); if (current_gainr < old_gainr) {
acomp->old_yl = sanitize_denormal(acomp->old_yl); current_gainr = release_coeff*old_gainr + (1.f-release_coeff)*current_gainr;
Ly1 = fmaxf(Lxl, release_coeff * acomp->old_y1+(1.f-release_coeff)*Lxl); } else if (current_gainr > old_gainr) {
Lyl = attack_coeff * acomp->old_yl+(1.f-attack_coeff)*Ly1; current_gainr = attack_coeff*old_gainr + (1.f-attack_coeff)*current_gainr;
Ly1 = sanitize_denormal(Ly1); }
Lyl = sanitize_denormal(Lyl);
cdb = -Lyl; current_gainr = sanitize_denormal(current_gainr);
Lgain = from_dB(cdb);
*(acomp->gainr) = Lyl; Lgain = from_dB(-current_gainr);
if (Lyl > max_gainr) {
max_gainr = Lyl; old_gainr = current_gainr;
*(acomp->gainr) = current_gainr;
if (current_gainr > max_gainr) {
max_gainr = current_gainr;
} }
lgaininp = in0 * Lgain; lgaininp = in0 * Lgain;
@ -365,12 +363,6 @@ run_mono(LV2_Handle instance, uint32_t n_samples)
output[i] = lgaininp * makeup_gain; output[i] = lgaininp * makeup_gain;
max = (fabsf(output[i]) > max) ? fabsf(output[i]) : sanitize_denormal(max); max = (fabsf(output[i]) > max) ? fabsf(output[i]) : sanitize_denormal(max);
// TODO re-use local variables on stack
// store values back to acomp at the end of the inner-loop
acomp->old_yl = Lyl;
acomp->old_y1 = Ly1;
acomp->old_yg = Lyg;
} }
if ( fabsf(makeup_target - makeup_gain) < 1e-6 ) { if ( fabsf(makeup_target - makeup_gain) < 1e-6 ) {
@ -385,17 +377,25 @@ run_mono(LV2_Handle instance, uint32_t n_samples)
#ifdef LV2_EXTENDED #ifdef LV2_EXTENDED
acomp->v_gainr = max_gainr; acomp->v_gainr = max_gainr;
const float old_v_lv1 = acomp->v_lv1; float in_peak_db = to_dB(in_peak);
const float old_v_lvl = acomp->v_lvl;
if (!isfinite_local (in_peak_db)) {
in_peak_db = -160.0f;
}
const float tot_rel_c = exp(-1000.f/(*(acomp->release) * srate) * n_samples); const float tot_rel_c = exp(-1000.f/(*(acomp->release) * srate) * n_samples);
const float tot_atk_c = exp(-1000.f/(*(acomp->attack) * srate) * n_samples); const float tot_atk_c = exp(-1000.f/(*(acomp->attack) * srate) * n_samples);
acomp->v_lv1 = fmaxf (in_peak, tot_rel_c*old_v_lv1 + (1.f-tot_rel_c)*in_peak);
acomp->v_lvl = tot_atk_c*old_v_lvl + (1.f-tot_atk_c)*acomp->v_lv1;
if (!isfinite_local (acomp->v_lvl)) { const float old_in_peak_db = acomp->old_in_peak_db;
acomp->v_lvl = 0.f;
if (in_peak_db < old_in_peak_db && in_peak_db < thresdb) {
in_peak_db = tot_rel_c*old_in_peak_db + (1.f-tot_rel_c)*in_peak_db;
} else if (in_peak_db > acomp->old_in_peak_db && in_peak_db > thresdb) {
in_peak_db = tot_atk_c*old_in_peak_db+ (1.f*tot_atk_c)*in_peak_db;
} }
const float v_lvl_in = (acomp->v_lvl < 0.001f) ? -60.f : to_dB(acomp->v_lvl);
acomp->old_in_peak_db = in_peak_db;
const float v_lvl_in = in_peak_db;
const float v_lvl_out = (max < 0.001f) ? -60.f : to_dB(max); const float v_lvl_out = (max < 0.001f) ? -60.f : to_dB(max);
if (fabsf (acomp->v_lvl_out - v_lvl_out) >= 1 || fabsf (acomp->v_lvl_in - v_lvl_in) >= 1) { if (fabsf (acomp->v_lvl_out - v_lvl_out) >= 1 || fabsf (acomp->v_lvl_in - v_lvl_in) >= 1) {
// >= 1dB difference // >= 1dB difference
@ -424,7 +424,6 @@ run_stereo(LV2_Handle instance, uint32_t n_samples)
float srate = acomp->srate; float srate = acomp->srate;
float width = (6.f * *(acomp->knee)) + 0.01; float width = (6.f * *(acomp->knee)) + 0.01;
float cdb=0.f;
float attack_coeff = exp(-1000.f/(*(acomp->attack) * srate)); float attack_coeff = exp(-1000.f/(*(acomp->attack) * srate));
float release_coeff = exp(-1000.f/(*(acomp->release) * srate)); float release_coeff = exp(-1000.f/(*(acomp->release) * srate));
@ -432,7 +431,10 @@ run_stereo(LV2_Handle instance, uint32_t n_samples)
float lgaininp = 0.f; float lgaininp = 0.f;
float rgaininp = 0.f; float rgaininp = 0.f;
float Lgain = 1.f; float Lgain = 1.f;
float Lxg, Lxl, Lyg, Lyl, Ly1; float Lxg, Lyg;
float current_gainr;
float old_gainr = *acomp->gainr;
int usesidechain = (*(acomp->sidechain) <= 0.f) ? 0 : 1; int usesidechain = (*(acomp->sidechain) <= 0.f) ? 0 : 1;
uint32_t i; uint32_t i;
float ingain; float ingain;
@ -492,7 +494,6 @@ run_stereo(LV2_Handle instance, uint32_t n_samples)
Lxg = (ingain==0.f) ? -160.f : to_dB(ingain); Lxg = (ingain==0.f) ? -160.f : to_dB(ingain);
Lxg = sanitize_denormal(Lxg); Lxg = sanitize_denormal(Lxg);
if (2.f*(Lxg-thresdb) < -width) { if (2.f*(Lxg-thresdb) < -width) {
Lyg = Lxg; Lyg = Lxg;
} else if (2.f*(Lxg-thresdb) > width) { } else if (2.f*(Lxg-thresdb) > width) {
@ -502,21 +503,23 @@ run_stereo(LV2_Handle instance, uint32_t n_samples)
Lyg = Lxg + (1.f/ratio-1.f)*(Lxg-thresdb+width/2.f)*(Lxg-thresdb+width/2.f)/(2.f*width); Lyg = Lxg + (1.f/ratio-1.f)*(Lxg-thresdb+width/2.f)*(Lxg-thresdb+width/2.f)/(2.f*width);
} }
Lxl = Lxg - Lyg; current_gainr = Lxg - Lyg;
acomp->old_y1 = sanitize_denormal(acomp->old_y1); if (current_gainr < old_gainr) {
acomp->old_yl = sanitize_denormal(acomp->old_yl); current_gainr = release_coeff*old_gainr + (1.f-release_coeff)*current_gainr;
Ly1 = fmaxf(Lxl, release_coeff * acomp->old_y1+(1.f-release_coeff)*Lxl); } else if (current_gainr > old_gainr) {
Lyl = attack_coeff * acomp->old_yl+(1.f-attack_coeff)*Ly1; current_gainr = attack_coeff*old_gainr + (1.f-attack_coeff)*current_gainr;
Ly1 = sanitize_denormal(Ly1); }
Lyl = sanitize_denormal(Lyl);
cdb = -Lyl; current_gainr = sanitize_denormal(current_gainr);
Lgain = from_dB(cdb);
*(acomp->gainr) = Lyl; Lgain = from_dB(-current_gainr);
if (Lyl > max_gainr) {
max_gainr = Lyl; old_gainr = current_gainr;
*(acomp->gainr) = current_gainr;
if (current_gainr > max_gainr) {
max_gainr = current_gainr;
} }
lgaininp = in0 * Lgain; lgaininp = in0 * Lgain;
@ -526,12 +529,6 @@ run_stereo(LV2_Handle instance, uint32_t n_samples)
output1[i] = rgaininp * makeup_gain; output1[i] = rgaininp * makeup_gain;
max = (fmaxf(fabs(output0[i]), fabs(output1[i])) > max) ? fmaxf(fabs(output0[i]), fabs(output1[i])) : sanitize_denormal(max); max = (fmaxf(fabs(output0[i]), fabs(output1[i])) > max) ? fmaxf(fabs(output0[i]), fabs(output1[i])) : sanitize_denormal(max);
// TODO re-use local variables on stack
// store values back to acomp at the end of the inner-loop
acomp->old_yl = Lyl;
acomp->old_y1 = Ly1;
acomp->old_yg = Lyg;
} }
if ( fabsf(makeup_target - makeup_gain) < 1e-6 ) { if ( fabsf(makeup_target - makeup_gain) < 1e-6 ) {
@ -546,16 +543,26 @@ run_stereo(LV2_Handle instance, uint32_t n_samples)
#ifdef LV2_EXTENDED #ifdef LV2_EXTENDED
acomp->v_gainr = max_gainr; acomp->v_gainr = max_gainr;
const float old_v_lv1 = acomp->v_lv1; float in_peak_db = to_dB(in_peak);
const float old_v_lvl = acomp->v_lvl;
if (!isfinite_local (in_peak_db)) {
in_peak_db = -160.0f;
}
const float tot_rel_c = exp(-1000.f/(*(acomp->release) * srate) * n_samples); const float tot_rel_c = exp(-1000.f/(*(acomp->release) * srate) * n_samples);
const float tot_atk_c = exp(-1000.f/(*(acomp->attack) * srate) * n_samples); const float tot_atk_c = exp(-1000.f/(*(acomp->attack) * srate) * n_samples);
acomp->v_lv1 = fmaxf (in_peak, tot_rel_c*old_v_lv1 + (1.f-tot_rel_c)*in_peak);
acomp->v_lvl = tot_atk_c*old_v_lvl + (1.f-tot_atk_c)*acomp->v_lv1; const float old_in_peak_db = acomp->old_in_peak_db;
if (!isfinite_local (acomp->v_lvl)) {
acomp->v_lvl = 0.f; if (in_peak_db < old_in_peak_db && in_peak_db < thresdb) {
in_peak_db = tot_rel_c*old_in_peak_db + (1.f-tot_rel_c)*in_peak_db;
} else if (in_peak_db > acomp->old_in_peak_db && in_peak_db > thresdb) {
in_peak_db = tot_atk_c*old_in_peak_db+ (1.f*tot_atk_c)*in_peak_db;
} }
const float v_lvl_in = (acomp->v_lvl < 0.001f) ? -60.f : to_dB(acomp->v_lvl);
acomp->old_in_peak_db = in_peak_db;
const float v_lvl_in = in_peak_db;
const float v_lvl_out = (max < 0.001f) ? -60.f : to_dB(max); const float v_lvl_out = (max < 0.001f) ? -60.f : to_dB(max);
if (fabsf (acomp->v_lvl_out - v_lvl_out) >= 1 || fabsf (acomp->v_lvl_in - v_lvl_in) >= 1) { if (fabsf (acomp->v_lvl_out - v_lvl_out) >= 1 || fabsf (acomp->v_lvl_in - v_lvl_in) >= 1) {
// >= 1dB difference // >= 1dB difference