From 527a02d648387bc8d666b5adb34abc03e6b7cda0 Mon Sep 17 00:00:00 2001 From: Krzysztof Foltman Date: Sat, 3 Apr 2010 01:35:22 +0100 Subject: [PATCH] Simplify Multiband Compressor code and fix several bugs. Eliminated some (not all) repetition in the code. Fixed a bug where old value for Q and separation was taken from the wrong variable. Fixed a bug where having a band bypassed or muted caused the graph to stop redrawing properly. (cherry picked from commit 3be583385b0bfb69bb7e52ee7426fe27d515560c) --- plugins/ladspa_effect/calf/calf/modules.h | 3 + .../ladspa_effect/calf/src/modules_dsp.cpp | 237 ++++++------------ 2 files changed, 80 insertions(+), 160 deletions(-) diff --git a/plugins/ladspa_effect/calf/calf/modules.h b/plugins/ladspa_effect/calf/calf/modules.h index b3ed83b89..6bce138e3 100644 --- a/plugins/ladspa_effect/calf/calf/modules.h +++ b/plugins/ladspa_effect/calf/calf/modules.h @@ -792,6 +792,7 @@ private: public: gain_reduction_audio_module(); void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu); + void update_curve(); void process(float &left, float &right, float det_left = NULL, float det_right = NULL); void activate(); void deactivate(); @@ -910,6 +911,7 @@ public: /// Multibandcompressor by Markus Schmidt class multibandcompressor_audio_module: public audio_module, public line_graph_iface { private: + typedef multibandcompressor_audio_module AM; static const int strips = 4; bool mute[strips]; uint32_t clip_inL, clip_inR, clip_outL, clip_outR; @@ -929,6 +931,7 @@ public: void params_changed(); uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); void set_sample_rate(uint32_t sr); + const gain_reduction_audio_module *get_strip_by_param_index(int index) const; virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; diff --git a/plugins/ladspa_effect/calf/src/modules_dsp.cpp b/plugins/ladspa_effect/calf/src/modules_dsp.cpp index d7f03b025..66eba417d 100644 --- a/plugins/ladspa_effect/calf/src/modules_dsp.cpp +++ b/plugins/ladspa_effect/calf/src/modules_dsp.cpp @@ -31,6 +31,8 @@ using namespace dsp; using namespace calf_plugins; +#define SET_IF_CONNECTED(name) if (params[AM::param_##name] != NULL) *params[AM::param_##name] = name; + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool frequency_response_line_graph::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const @@ -398,8 +400,8 @@ void multibandcompressor_audio_module::params_changed() hpL0.set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate); hpR0.copy_coeffs(hpL0); freq_old[0] = *params[param_freq0]; - sep_old[0] = *params[param_sep2]; - q_old[0] = *params[param_q2]; + sep_old[0] = *params[param_sep0]; + q_old[0] = *params[param_q0]; } if(*params[param_freq1] != freq_old[1] or *params[param_sep1] != sep_old[1] or *params[param_q1] != q_old[1]) { lpL1.set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate); @@ -407,8 +409,8 @@ void multibandcompressor_audio_module::params_changed() hpL1.set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate); hpR1.copy_coeffs(hpL1); freq_old[1] = *params[param_freq1]; - sep_old[1] = *params[param_sep2]; - q_old[1] = *params[param_q2]; + sep_old[1] = *params[param_sep1]; + q_old[1] = *params[param_q1]; } if(*params[param_freq2] != freq_old[2] or *params[param_sep2] != sep_old[2] or *params[param_q2] != q_old[2]) { lpL2.set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate); @@ -420,22 +422,10 @@ void multibandcompressor_audio_module::params_changed() q_old[2] = *params[param_q2]; } // set the params of all strips - for (int j = 0; j < strips; j ++) { - switch (j) { - case 0: - strip[j].set_params(*params[param_attack0], *params[param_release0], *params[param_threshold0], *params[param_ratio0], *params[param_knee0], *params[param_makeup0], *params[param_detection0], 1.f, *params[param_bypass0], *params[param_mute0]); - break; - case 1: - strip[j].set_params(*params[param_attack1], *params[param_release1], *params[param_threshold1], *params[param_ratio1], *params[param_knee1], *params[param_makeup1], *params[param_detection1], 1.f, *params[param_bypass1], *params[param_mute1]); - break; - case 2: - strip[j].set_params(*params[param_attack2], *params[param_release2], *params[param_threshold2], *params[param_ratio2], *params[param_knee2], *params[param_makeup2], *params[param_detection2], 1.f, *params[param_bypass2], *params[param_mute2]); - break; - case 3: - strip[j].set_params(*params[param_attack3], *params[param_release3], *params[param_threshold3], *params[param_ratio3], *params[param_knee3], *params[param_makeup3], *params[param_detection3], 1.f, *params[param_bypass3], *params[param_mute3]); - break; - } - } + strip[0].set_params(*params[param_attack0], *params[param_release0], *params[param_threshold0], *params[param_ratio0], *params[param_knee0], *params[param_makeup0], *params[param_detection0], 1.f, *params[param_bypass0], *params[param_mute0]); + strip[1].set_params(*params[param_attack1], *params[param_release1], *params[param_threshold1], *params[param_ratio1], *params[param_knee1], *params[param_makeup1], *params[param_detection1], 1.f, *params[param_bypass1], *params[param_mute1]); + strip[2].set_params(*params[param_attack2], *params[param_release2], *params[param_threshold2], *params[param_ratio2], *params[param_knee2], *params[param_makeup2], *params[param_detection2], 1.f, *params[param_bypass2], *params[param_mute2]); + strip[3].set_params(*params[param_attack3], *params[param_release3], *params[param_threshold3], *params[param_ratio3], *params[param_knee3], *params[param_makeup3], *params[param_detection3], 1.f, *params[param_bypass3], *params[param_mute3]); } void multibandcompressor_audio_module::set_sample_rate(uint32_t sr) @@ -447,10 +437,24 @@ void multibandcompressor_audio_module::set_sample_rate(uint32_t sr) } } +#define BYPASSED_COMPRESSION(index) \ + if(params[param_compression##index] != NULL) \ + *params[param_compression##index] = 1.0; \ + if(params[param_output##index] != NULL) \ + *params[param_output##index] = 0.0; + +#define ACTIVE_COMPRESSION(index) \ + if(params[param_compression##index] != NULL) \ + *params[param_compression##index] = strip[index].get_comp_level(); \ + if(params[param_output##index] != NULL) \ + *params[param_output##index] = strip[index].get_output_level(); + uint32_t multibandcompressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { bool bypass = *params[param_bypass] > 0.5f; numsamples += offset; + for (int i = 0; i < strips; i++) + strip[i].update_curve(); if(bypass) { // everything bypassed while(offset < numsamples) { @@ -595,165 +599,75 @@ uint32_t multibandcompressor_audio_module::process(uint32_t offset, uint32_t num } // process all strips (no bypass) // draw meters - if(params[param_clip_inL] != NULL) { - *params[param_clip_inL] = clip_inL; - } - if(params[param_clip_inR] != NULL) { - *params[param_clip_inR] = clip_inR; - } - if(params[param_clip_outL] != NULL) { - *params[param_clip_outL] = clip_outL; - } - if(params[param_clip_outR] != NULL) { - *params[param_clip_outR] = clip_outR; - } - - if(params[param_meter_inL] != NULL) { - *params[param_meter_inL] = meter_inL; - } - if(params[param_meter_inR] != NULL) { - *params[param_meter_inR] = meter_inR; - } - if(params[param_meter_outL] != NULL) { - *params[param_meter_outL] = meter_outL; - } - if(params[param_meter_outR] != NULL) { - *params[param_meter_outR] = meter_outR; - } + SET_IF_CONNECTED(clip_inL); + SET_IF_CONNECTED(clip_inR); + SET_IF_CONNECTED(clip_outL); + SET_IF_CONNECTED(clip_outR); + SET_IF_CONNECTED(meter_inL); + SET_IF_CONNECTED(meter_inR); + SET_IF_CONNECTED(meter_outL); + SET_IF_CONNECTED(meter_outR); // draw strip meters if(bypass > 0.5f) { - if(params[param_compression0] != NULL) { - *params[param_compression0] = 1.0f; - } - if(params[param_compression1] != NULL) { - *params[param_compression1] = 1.0f; - } - if(params[param_compression2] != NULL) { - *params[param_compression2] = 1.0f; - } - if(params[param_compression3] != NULL) { - *params[param_compression3] = 1.0f; - } - - if(params[param_output0] != NULL) { - *params[param_output0] = 0.0f; - } - if(params[param_output1] != NULL) { - *params[param_output1] = 0.0f; - } - if(params[param_output2] != NULL) { - *params[param_output2] = 0.0f; - } - if(params[param_output3] != NULL) { - *params[param_output3] = 0.0f; - } + BYPASSED_COMPRESSION(0) + BYPASSED_COMPRESSION(1) + BYPASSED_COMPRESSION(2) + BYPASSED_COMPRESSION(3) } else { - if(params[param_compression0] != NULL) { - *params[param_compression0] = strip[0].get_comp_level(); - } - if(params[param_compression1] != NULL) { - *params[param_compression1] = strip[1].get_comp_level(); - } - if(params[param_compression2] != NULL) { - *params[param_compression2] = strip[2].get_comp_level(); - } - if(params[param_compression3] != NULL) { - *params[param_compression3] = strip[3].get_comp_level(); - } - - if(params[param_output0] != NULL) { - *params[param_output0] = strip[0].get_output_level(); - } - if(params[param_output1] != NULL) { - *params[param_output1] = strip[1].get_output_level(); - } - if(params[param_output2] != NULL) { - *params[param_output2] = strip[2].get_output_level(); - } - if(params[param_output3] != NULL) { - *params[param_output3] = strip[3].get_output_level(); - } + ACTIVE_COMPRESSION(0) + ACTIVE_COMPRESSION(1) + ACTIVE_COMPRESSION(2) + ACTIVE_COMPRESSION(3) } // whatever has to be returned x) return outputs_mask; } -bool multibandcompressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const + +const gain_reduction_audio_module *multibandcompressor_audio_module::get_strip_by_param_index(int index) const { // let's handle by the corresponding strip switch (index) { case param_compression0: - return strip[0].get_graph(subindex, data, points, context); - break; + return &strip[0]; case param_compression1: - return strip[1].get_graph(subindex, data, points, context); - break; + return &strip[1]; case param_compression2: - return strip[2].get_graph(subindex, data, points, context); - break; + return &strip[2]; case param_compression3: - return strip[3].get_graph(subindex, data, points, context); - break; + return &strip[3]; } + return NULL; +} + +bool multibandcompressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + const gain_reduction_audio_module *m = get_strip_by_param_index(index); + if (m) + return m->get_graph(subindex, data, points, context); return false; } bool multibandcompressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const { - // let's handle by the corresponding strip - switch (index) { - case param_compression0: - return strip[0].get_dot(subindex, x, y, size, context); - break; - case param_compression1: - return strip[1].get_dot(subindex, x, y, size, context); - break; - case param_compression2: - return strip[2].get_dot(subindex, x, y, size, context); - break; - case param_compression3: - return strip[3].get_dot(subindex, x, y, size, context); - break; - } + const gain_reduction_audio_module *m = get_strip_by_param_index(index); + if (m) + return m->get_dot(subindex, x, y, size, context); return false; } bool multibandcompressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const { - // let's handle by the corresponding strip - switch (index) { - case param_compression0: - return strip[0].get_gridline(subindex, pos, vertical, legend, context); - break; - case param_compression1: - return strip[1].get_gridline(subindex, pos, vertical, legend, context); - break; - case param_compression2: - return strip[2].get_gridline(subindex, pos, vertical, legend, context); - break; - case param_compression3: - return strip[3].get_gridline(subindex, pos, vertical, legend, context); - break; - } + const gain_reduction_audio_module *m = get_strip_by_param_index(index); + if (m) + return m->get_gridline(subindex, pos, vertical, legend, context); return false; } int multibandcompressor_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const { - // let's handle by the corresponding strip - switch (index) { - case param_compression0: - return strip[0].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline); - break; - case param_compression1: - return strip[1].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline); - break; - case param_compression2: - return strip[2].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline); - break; - case param_compression3: - return strip[3].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline); - break; - } + const gain_reduction_audio_module *m = get_strip_by_param_index(index); + if (m) + return m->get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline); return 0; } @@ -1533,6 +1447,19 @@ void gain_reduction_audio_module::deactivate() is_active = false; } +void gain_reduction_audio_module::update_curve() +{ + float linThreshold = threshold; + float linKneeSqrt = sqrt(knee); + linKneeStart = linThreshold / linKneeSqrt; + adjKneeStart = linKneeStart*linKneeStart; + float linKneeStop = linThreshold * linKneeSqrt; + thres = log(linThreshold); + kneeStart = log(linKneeStart); + kneeStop = log(linKneeStop); + compressedKneeStop = (kneeStop - thres) / ratio + thres; +} + void gain_reduction_audio_module::process(float &left, float &right, float det_left, float det_right) { if(!det_left) { @@ -1547,17 +1474,9 @@ void gain_reduction_audio_module::process(float &left, float &right, float det_l // greatest sounding compressor I've heard! bool rms = detection == 0; bool average = stereo_link == 0; - float linThreshold = threshold; float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f)); float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f)); - float linKneeSqrt = sqrt(knee); - linKneeStart = linThreshold / linKneeSqrt; - adjKneeStart = linKneeStart*linKneeStart; - float linKneeStop = linThreshold * linKneeSqrt; - thres = log(linThreshold); - kneeStart = log(linKneeStart); - kneeStop = log(linKneeStop); - compressedKneeStop = (kneeStop - thres) / ratio + thres; + update_curve(); float absample = average ? (fabs(det_left) + fabs(det_right)) * 0.5f : std::max(fabs(det_left), fabs(det_right)); if(rms) absample *= absample; @@ -1861,8 +1780,6 @@ inline void equalizerNband_audio_module::process_hplp(float } } -#define SET_IF_CONNECTED(param) if (params[AM::param_##param] != NULL) *params[AM::param_##param] = param; - template uint32_t equalizerNband_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {