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)
This commit is contained in:
Krzysztof Foltman
2010-04-03 01:35:22 +01:00
committed by Tobias Doerffel
parent f8cb1120b0
commit 527a02d648
2 changed files with 80 additions and 160 deletions

View File

@@ -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<multibandcompressor_metadata>, 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;

View File

@@ -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<BaseClass, has_lphp>::process_hplp(float
}
}
#define SET_IF_CONNECTED(param) if (params[AM::param_##param] != NULL) *params[AM::param_##param] = param;
template<class BaseClass, bool has_lphp>
uint32_t equalizerNband_audio_module<BaseClass, has_lphp>::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
{