From a6ff6573bdb24b42eb8301b8340980d2b2c56f37 Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Fri, 10 Feb 2012 00:29:00 +0000 Subject: [PATCH] Multiband limiter: ASC fixes. --- src/audio_fx.cpp | 76 ++++++++++++++++++++++++++++++++++-------------- src/calf/audio_fx.h | 8 +++-- src/calf/modules_limit.h | 2 +- src/modules_limit.cpp | 27 +++++++---------- 4 files changed, 70 insertions(+), 43 deletions(-) diff --git a/src/audio_fx.cpp b/src/audio_fx.cpp index a5695be..139c090 100644 --- a/src/audio_fx.cpp +++ b/src/audio_fx.cpp @@ -633,6 +633,26 @@ void lookahead_limiter::reset_asc() { asc_changed = true; } +float lookahead_limiter::get_rdelta(float peak, float _limit, float _att, bool _asc) { + + // calc the att for average input to walk to if we use asc (att of average signal) + float _a_att = (limit * weight) / (asc_coeff * asc) * (float)asc_c; + + // calc a release delta from this attenuation + float _rdelta = (1.0 - _att) / (srate * release); + if(_asc and auto_release and asc_c > 0 and _a_att > _att) { + // check if releasing to average level of peaks is steeper than + // releasing to 1.f + float _delta = std::max((_a_att - _att) / (srate * release), _rdelta / 10); + if(_delta < _rdelta) { + asc_active = true; + _asc_used = true; + _rdelta = _delta; + } + } + return _rdelta; +} + void lookahead_limiter::process(float &left, float &right, float * multi_buffer) { // PROTIP: harming paying customers enough to make them develop a competing @@ -648,15 +668,15 @@ void lookahead_limiter::process(float &left, float &right, float * multi_buffer) buffer[pos] = left; buffer[pos + 1] = right; } - + // are we using multiband? get the multiband coefficient or use 1.f float multi_coeff = (use_multi) ? multi_buffer[pos] : 1.f; - - // input peak - impact higher in left or right channel? - peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right); - + // calc the real limit including weight and multi coeff float _limit = limit * multi_coeff * weight; + + // input peak - impact higher in left or right channel? + peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right); // add an eventually appearing peak to the asc fake buffer if asc active if(auto_release and peak > _limit) { @@ -667,22 +687,11 @@ void lookahead_limiter::process(float &left, float &right, float * multi_buffer) if(peak > _limit or multi_coeff < 1.0) { float _multi_coeff = 1.f; float _peak; - + // calc the attenuation needed to reduce incoming peak float _att = std::min(_limit / peak, 1.f); - - - // calc a release delta from this attenuation - float _rdelta = (1.0 - _att) / (srate * release); - if(auto_release and asc_c > 0) { - // check if releasing to average level of peaks is steeper than - // releasing to 1.f - float _delta = std::max((limit * weight) / (asc_coeff * asc) * (float)asc_c - _att, 0.000001f) / (srate * release); - if(_delta < _rdelta) { - asc_active = true; - _rdelta = _delta; - } - } + // calc release without any asc to keep all relevant peaks + float _rdelta = get_rdelta(peak, _limit, _att, false); // calc the delta for walking to incoming peak attenuation float _delta = (_limit / peak - att) / buffer_size * channels; @@ -764,12 +773,32 @@ void lookahead_limiter::process(float &left, float &right, float * multi_buffer) // ...and calculate outpout from it left *= att; right *= att; - + if((pos + channels) % buffer_size == nextpos[nextiter]) { // if we reach a buffered position, change the actual delta and erase // this (the first) element from nextpos and nextdelta buffer - delta = nextdelta[nextiter]; - nextlen = (nextlen - 1) % buffer_size; + if(auto_release) { + // set delta to asc influenced release delta + delta = get_rdelta(_peak, (limit * weight * _multi_coeff), att); + if(nextlen > 1) { + // if there are more positions to walk to, calc delta to next + // position in buffer and compare it to release delta (keep + // changes between peaks below asc steepness) + int _nextpos = nextpos[(nextiter + 1) % buffer_size]; + float __peak = fabs(buffer[_nextpos]) > fabs(buffer[_nextpos + 1]) ? fabs(buffer[_nextpos]) : fabs(buffer[_nextpos + 1]); + float __multi_coeff = (use_multi) ? multi_buffer[_nextpos] : 1.f; + float __delta = ((limit * __multi_coeff * weight) / __peak - att) / (((buffer_size + _nextpos - ((pos + channels) % buffer_size)) % buffer_size) / channels); + if(__delta < delta) { + delta = __delta; + } + } + } else { + // if no asc set delta from nextdelta buffer and fix the attenuation + delta = nextdelta[nextiter]; + att = (limit * weight * _multi_coeff) / _peak; + } + // remove first element from circular nextpos buffer + nextlen -= 1; nextpos[nextiter] = -1; nextiter = (nextiter + 1) % buffer_size; } @@ -778,6 +807,9 @@ void lookahead_limiter::process(float &left, float &right, float * multi_buffer) // release time seems over, reset attenuation and delta att = 1.0f; delta = 0.0f; + nextiter = 0; + nextlen = 0; + nextpos[0] = -1; } // main limiting party is over, let's cleanup the puke diff --git a/src/calf/audio_fx.h b/src/calf/audio_fx.h index b4db50f..e2032e2 100644 --- a/src/calf/audio_fx.h +++ b/src/calf/audio_fx.h @@ -574,9 +574,9 @@ public: uint32_t srate; float att; // a coefficient the output is multiplied with float att_max; // a memory for the highest attenuation - used for display - unsigned int pos; // where we are actually in our sample buffer - unsigned int buffer_size; - unsigned int overall_buffer_size; + int pos; // where we are actually in our sample buffer + int buffer_size; + int overall_buffer_size; bool is_active; bool debug; bool auto_release; @@ -600,10 +600,12 @@ public: int asc_pos; bool asc_changed; float asc_coeff; + bool _asc_used; static inline void denormal(volatile float *f) { *f += 1e-18; *f -= 1e-18; } + inline float get_rdelta(float peak, float _limit, float _att, bool _asc = true); void reset(); void reset_asc(); bool get_asc(); diff --git a/src/calf/modules_limit.h b/src/calf/modules_limit.h index d5d4b9a..29a61ba 100644 --- a/src/calf/modules_limit.h +++ b/src/calf/modules_limit.h @@ -66,7 +66,7 @@ private: float meter_inL, meter_inR, meter_outL, meter_outR; dsp::lookahead_limiter strip[strips]; dsp::lookahead_limiter broadband; - dsp::biquad_d2 lpL[strips - 1][3], lpR[strips - 1][3], hpL[strips - 1][3], hpR[strips - 1][3]; + dsp::biquad_d2 lpL[strips - 1][strips - 1], lpR[strips - 1][strips - 1], hpL[strips - 1][strips - 1], hpR[strips - 1][strips - 1]; float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1]; unsigned int pos; unsigned int buffer_size; diff --git a/src/modules_limit.cpp b/src/modules_limit.cpp index f7fb6fc..e8a4666 100644 --- a/src/modules_limit.cpp +++ b/src/modules_limit.cpp @@ -354,12 +354,12 @@ 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], *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1), true); + strip[0].set_params(*params[param_limit], *params[param_attack], rel, weight[0], *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1)); *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], *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1)); + strip[1].set_params(*params[param_limit], *params[param_attack], rel, weight[1], *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1), true); *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; @@ -421,6 +421,7 @@ void multibandlimiter_audio_module::set_sample_rate(uint32_t sr) 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; @@ -656,22 +657,14 @@ bool multibandlimiter_audio_module::get_graph(int index, int subindex, float *da break; } for(int j = 0; j <= j1; j ++) { - switch(subindex) { - case 0: - ret *= lpL[0][j].freq_gain(freq, (float)srate); - break; - case 1: - ret *= hpL[0][j].freq_gain(freq, (float)srate); - ret *= lpL[1][j].freq_gain(freq, (float)srate); - break; - case 2: - ret *= hpL[1][j].freq_gain(freq, (float)srate); - ret *= lpL[2][j].freq_gain(freq, (float)srate); - break; - case 3: - ret *= hpL[2][j].freq_gain(freq, (float)srate); - break; + if(subindex == 0) + ret *= lpL[0][j].freq_gain(freq, (float)srate); + if(subindex > 0 and subindex < strips - 1) { + ret *= hpL[subindex - 1][j].freq_gain(freq, (float)srate); + ret *= lpL[subindex][j].freq_gain(freq, (float)srate); } + if(subindex == strips - 1) + ret *= hpL[2][j].freq_gain(freq, (float)srate); } data[i] = dB_grid(ret); } -- 2.11.4.GIT