New FX: Sidechain compressor
(cherry picked from commit c5c8786de3e410c64d9c9d4cd70fd03a4c697a2e)
This commit is contained in:
committed by
Tobias Doerffel
parent
4ab2c68bd1
commit
17425ce70f
@@ -69,6 +69,7 @@ enum parameter_flags
|
||||
PF_CTL_BUTTON = 0x0600, ///< push button
|
||||
PF_CTL_METER = 0x0700, ///< volume meter
|
||||
PF_CTL_LED = 0x0800, ///< light emitting diode
|
||||
PF_CTL_LABEL = 0x0900, ///< label
|
||||
|
||||
PF_CTLOPTIONS = 0x00F000, ///< bit mask for control (widget) options
|
||||
PF_CTLO_HORIZ = 0x001000, ///< horizontal version of the control (unused)
|
||||
|
||||
@@ -136,6 +136,17 @@ struct compressor_metadata: public plugin_metadata<compressor_metadata>
|
||||
PLUGIN_NAME_ID_LABEL("compressor", "compressor", "Compressor")
|
||||
};
|
||||
|
||||
/// Markus's sidechain compressor - metadata
|
||||
struct sidechaincompressor_metadata: public plugin_metadata<sidechaincompressor_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_meter_in, param_meter_out, param_clip_in, param_clip_out,
|
||||
param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_compression,
|
||||
param_sc_mode, param_f1_freq, param_f2_freq, param_f1_level, param_f2_level,
|
||||
param_sc_listen, param_f1_active, param_f2_active, param_count };
|
||||
PLUGIN_NAME_ID_LABEL("sidechaincompressor", "sidechaincompressor", "Sidechain Compressor")
|
||||
};
|
||||
|
||||
/// Markus's multibandcompressor - metadata
|
||||
struct multibandcompressor_metadata: public plugin_metadata<multibandcompressor_metadata>
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
PER_MODULE_ITEM(multichorus, false, "multichorus")
|
||||
PER_MODULE_ITEM(compressor, false, "compressor")
|
||||
PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
|
||||
PER_MODULE_ITEM(sidechaincompressor, false, "sidechaincompressor")
|
||||
#ifdef ENABLE_EXPERIMENTAL
|
||||
PER_MODULE_ITEM(fluidsynth, true, "fluidsynth")
|
||||
PER_MODULE_ITEM(wavetable, true, "wavetable")
|
||||
|
||||
@@ -926,8 +926,8 @@ class gain_reduction_audio_module {
|
||||
private:
|
||||
float linSlope, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop;
|
||||
float compressedKneeStop, adjKneeStart, thres;
|
||||
float attack, release, threshold, ratio, knee, makeup, detection, bypass, mute, meter_out, meter_comp;
|
||||
float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_mute, old_detection;
|
||||
float attack, release, threshold, ratio, knee, makeup, detection, stereo_link, bypass, mute, meter_out, meter_comp;
|
||||
float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_mute, old_detection, old_stereo_link;
|
||||
int last_generation;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
@@ -935,8 +935,8 @@ private:
|
||||
inline float output_gain(float linSlope, bool rms);
|
||||
public:
|
||||
gain_reduction_audio_module();
|
||||
void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float byp, float mu);
|
||||
void process(float &left, float &right);
|
||||
void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu);
|
||||
void process(float &left, float &right, float det_left = NULL, float det_right = NULL);
|
||||
void activate();
|
||||
void deactivate();
|
||||
int id;
|
||||
@@ -949,6 +949,78 @@ public:
|
||||
virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
|
||||
};
|
||||
|
||||
|
||||
/// Sidecain Compressor by Markus Schmidt (based on Thor's compressor and Krzysztof's filters)
|
||||
class sidechaincompressor_audio_module: public audio_module<sidechaincompressor_metadata>, public frequency_response_line_graph {
|
||||
private:
|
||||
enum CalfScModes {
|
||||
WIDEBAND,
|
||||
DEESSER_WIDE,
|
||||
DEESSER_SPLIT,
|
||||
DERUMBLER_WIDE,
|
||||
DERUMBLER_SPLIT,
|
||||
WEIGHTED_1,
|
||||
WEIGHTED_2,
|
||||
WEIGHTED_3,
|
||||
BANDPASS_1,
|
||||
BANDPASS_2
|
||||
};
|
||||
float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old;
|
||||
CalfScModes sc_mode;
|
||||
float f1_active, f2_active;
|
||||
uint32_t clip_in, clip_out;
|
||||
float meter_in, meter_out;
|
||||
gain_reduction_audio_module compressor;
|
||||
biquad_d2<float> f1L, f1R, f2L, f2R;
|
||||
public:
|
||||
typedef std::complex<double> cfloat;
|
||||
float *ins[in_count];
|
||||
float *outs[out_count];
|
||||
float *params[param_count];
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
sidechaincompressor_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void params_changed();
|
||||
inline cfloat h_z(const cfloat &z) {
|
||||
switch (sc_mode) {
|
||||
default:
|
||||
case WIDEBAND:
|
||||
return false;
|
||||
break;
|
||||
case DEESSER_WIDE:
|
||||
case DERUMBLER_WIDE:
|
||||
case WEIGHTED_1:
|
||||
case WEIGHTED_2:
|
||||
case WEIGHTED_3:
|
||||
case BANDPASS_2:
|
||||
return f1L.h_z(z) * f2L.h_z(z);
|
||||
break;
|
||||
case DEESSER_SPLIT:
|
||||
case DERUMBLER_SPLIT:
|
||||
case BANDPASS_1:
|
||||
return f1L.h_z(z);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
float freq_gain(int index, double freq, uint32_t sr)
|
||||
{
|
||||
typedef std::complex<double> cfloat;
|
||||
freq *= 2.0 * M_PI / sr;
|
||||
cfloat z = 1.0 / exp(cfloat(0.0, freq));
|
||||
|
||||
return std::abs(h_z(z));
|
||||
}
|
||||
void set_sample_rate(uint32_t sr);
|
||||
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context);
|
||||
virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context);
|
||||
virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
|
||||
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
|
||||
};
|
||||
|
||||
/// Multibandcompressor by Markus Schmidt
|
||||
class multibandcompressor_audio_module: public audio_module<multibandcompressor_metadata>, public line_graph_iface {
|
||||
private:
|
||||
|
||||
@@ -240,6 +240,51 @@ CALF_PLUGIN_INFO(compressor) = { 0x8502, "Compressor", "Calf Compressor", "Thor
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CALF_PORT_NAMES(sidechaincompressor) = {"In L", "In R", "Out L", "Out R"};
|
||||
|
||||
const char *sidechaincompressor_detection_names[] = { "RMS", "Peak" };
|
||||
const char *sidechaincompressor_stereo_link_names[] = { "Average", "Maximum" };
|
||||
const char *sidechaincompressor_mode_names[] = {"Wideband (F1:off / F2:off)",
|
||||
"Deesser wide (F1:HP / F2:Bell)",
|
||||
"Deesser split (F1:HP / F2:off)",
|
||||
"Derumbler wide (F1:Bell / F2:LP)",
|
||||
"Derumbler split (F1:off / F2:LP)",
|
||||
"Weighted #1 (F1:Shelf / F2:Shelf)",
|
||||
"Weighted #2 (F1:Shelf / F2:Bell)",
|
||||
"Weighted #3 (F1:Bell / F2:Shelf)",
|
||||
"Bandpass #1 (F1:BP / F2:off)",
|
||||
"Bandpass #2 (F1:HP / F2:LP)"};
|
||||
|
||||
CALF_PORT_PROPS(sidechaincompressor) = {
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
|
||||
{ 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" },
|
||||
{ 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" },
|
||||
{ 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" },
|
||||
{ 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" },
|
||||
{ 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" },
|
||||
{ 20, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" },
|
||||
{ 250, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" },
|
||||
{ 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" },
|
||||
{ 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" },
|
||||
{ 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_detection_names, "detection", "Detection" },
|
||||
{ 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_stereo_link_names, "stereo_link", "Stereo Link" },
|
||||
{ 0, 0.03125, 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, "compression", "Gain Reduction" },
|
||||
{ 0, 0, 9, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_mode_names, "sc_mode", "Sidechain Mode" },
|
||||
{ 200, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "f1_freq", "Freq" },
|
||||
{ 4000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "f2_freq", "Freq" },
|
||||
{ 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f1_level", "Level" },
|
||||
{ 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f2_level", "Level" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "sc_listen", "S/C-Listen" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f1_active", "active" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f2_active", "active" },
|
||||
};
|
||||
|
||||
CALF_PLUGIN_INFO(sidechaincompressor) = { 0x8502, "Sidechaincompressor", "Calf Sidechain Compressor", "Thor Harald Johansen / Markus Schmidt", calf_plugins::calf_copyright_info, "CompressorPlugin" };
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CALF_PORT_NAMES(multibandcompressor) = {"In L", "In R", "Out L", "Out R"};
|
||||
|
||||
const char *multibandcompressor_detection_names[] = { "RMS", "Peak" };
|
||||
|
||||
@@ -716,16 +716,16 @@ void multibandcompressor_audio_module::params_changed()
|
||||
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], *params[param_bypass0], *params[param_mute0]);
|
||||
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], *params[param_bypass1], *params[param_mute1]);
|
||||
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], *params[param_bypass2], *params[param_mute2]);
|
||||
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], *params[param_bypass3], *params[param_mute3]);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1049,6 +1049,328 @@ int multibandcompressor_audio_module::get_changed_offsets(int index, int generat
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Sidecain Compressor by Markus Schmidt
|
||||
///
|
||||
/// This module splits the signal in a sidechain- and a process signal.
|
||||
/// The sidechain is processed through Krzystofs filters and compresses
|
||||
/// the process signal via Thor's compression routine afterwards.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sidechaincompressor_audio_module::sidechaincompressor_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
}
|
||||
|
||||
void sidechaincompressor_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
// set all filters and strips
|
||||
compressor.activate();
|
||||
params_changed();
|
||||
meter_in = 0.f;
|
||||
meter_out = 0.f;
|
||||
clip_in = 0.f;
|
||||
clip_out = 0.f;
|
||||
}
|
||||
void sidechaincompressor_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
compressor.deactivate();
|
||||
}
|
||||
|
||||
void sidechaincompressor_audio_module::params_changed()
|
||||
{
|
||||
// set the params of all filters
|
||||
if(*params[param_f1_freq] != f1_freq_old or *params[param_f1_level] != f1_level_old or *params[param_sc_mode] != sc_mode
|
||||
or *params[param_f2_freq] != f2_freq_old or *params[param_f2_level] != f2_level_old) {
|
||||
switch ((int)*params[param_sc_mode]) {
|
||||
default:
|
||||
case WIDEBAND:
|
||||
f1L.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
|
||||
f1R.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
|
||||
f2L.set_lp_rbj((float)*params[param_f2_freq], 0.707, (float)srate);
|
||||
f2R.set_lp_rbj((float)*params[param_f2_freq], 0.707, (float)srate);
|
||||
f1_active = 0.f;
|
||||
f2_active = 0.f;
|
||||
break;
|
||||
case DEESSER_WIDE:
|
||||
f1L.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
|
||||
f1R.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
|
||||
f2L.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f2R.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f1_active = 1.f;
|
||||
f2_active = 0.5f;
|
||||
break;
|
||||
case DEESSER_SPLIT:
|
||||
f1L.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), 0.707, (float)srate);
|
||||
f1R.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), 0.707, (float)srate);
|
||||
f2L.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), 0.707, (float)srate);
|
||||
f2R.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), 0.707, (float)srate);
|
||||
f1_active = 1.f;
|
||||
f2_active = 0.f;
|
||||
break;
|
||||
case DERUMBLER_WIDE:
|
||||
f1L.set_lp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
|
||||
f1R.set_lp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
|
||||
f2L.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f2R.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f1_active = 1.f;
|
||||
f2_active = 0.5f;
|
||||
break;
|
||||
case DERUMBLER_SPLIT:
|
||||
f1L.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), 0.707, (float)srate);
|
||||
f1R.set_lp_rbj((float)*params[param_f1_freq] * (1 + 0.17), 0.707, (float)srate);
|
||||
f2L.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), 0.707, (float)srate);
|
||||
f2R.set_hp_rbj((float)*params[param_f1_freq] * (1 - 0.17), 0.707, (float)srate);
|
||||
f1_active = 1.f;
|
||||
f2_active = 0.f;
|
||||
break;
|
||||
case WEIGHTED_1:
|
||||
f1L.set_lowshelf_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
|
||||
f1R.set_lowshelf_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
|
||||
f2L.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f2R.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f1_active = 0.5f;
|
||||
f2_active = 0.5f;
|
||||
break;
|
||||
case WEIGHTED_2:
|
||||
f1L.set_lowshelf_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
|
||||
f1R.set_lowshelf_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
|
||||
f2L.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f2R.set_peakeq_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f1_active = 0.5f;
|
||||
f2_active = 0.5f;
|
||||
break;
|
||||
case WEIGHTED_3:
|
||||
f1L.set_peakeq_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
|
||||
f1R.set_peakeq_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
|
||||
f2L.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f2R.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f1_active = 0.5f;
|
||||
f2_active = 0.5f;
|
||||
break;
|
||||
case BANDPASS_1:
|
||||
f1L.set_bp_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
|
||||
f1R.set_bp_rbj((float)*params[param_f1_freq], 0.707, *params[param_f1_level], (float)srate);
|
||||
f2L.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f2R.set_highshelf_rbj((float)*params[param_f2_freq], 0.707, *params[param_f2_level], (float)srate);
|
||||
f1_active = 1.f;
|
||||
f2_active = 0.f;
|
||||
break;
|
||||
case BANDPASS_2:
|
||||
f1L.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
|
||||
f1R.set_hp_rbj((float)*params[param_f1_freq], 0.707, (float)srate);
|
||||
f2L.set_lp_rbj((float)*params[param_f2_freq], 0.707, (float)srate);
|
||||
f2R.set_lp_rbj((float)*params[param_f2_freq], 0.707, (float)srate);
|
||||
f1_active = 1.f;
|
||||
f2_active = 1.f;
|
||||
break;
|
||||
}
|
||||
f1_freq_old = *params[param_f1_freq];
|
||||
f1_level_old = *params[param_f1_level];
|
||||
f2_freq_old = *params[param_f2_freq];
|
||||
f2_level_old = *params[param_f2_level];
|
||||
sc_mode = (CalfScModes)*params[param_sc_mode];
|
||||
}
|
||||
// light LED's
|
||||
if(params[param_f1_active] != NULL) {
|
||||
*params[param_f1_active] = f1_active;
|
||||
}
|
||||
if(params[param_f2_active] != NULL) {
|
||||
*params[param_f2_active] = f2_active;
|
||||
}
|
||||
// and set the compressor module
|
||||
compressor.set_params(*params[param_attack], *params[param_release], *params[param_threshold], *params[param_ratio], *params[param_knee], *params[param_makeup], *params[param_detection], *params[param_stereo_link], *params[param_bypass], 0.f);
|
||||
}
|
||||
|
||||
void sidechaincompressor_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
compressor.set_sample_rate(srate);
|
||||
}
|
||||
|
||||
uint32_t sidechaincompressor_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;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < numsamples) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
++offset;
|
||||
}
|
||||
// displays, too
|
||||
clip_in = 0.f;
|
||||
clip_out = 0.f;
|
||||
meter_in = 0.f;
|
||||
meter_out = 0.f;
|
||||
} else {
|
||||
// process
|
||||
|
||||
clip_in -= std::min(clip_in, numsamples);
|
||||
clip_out -= std::min(clip_out, numsamples);
|
||||
|
||||
while(offset < numsamples) {
|
||||
// cycle through samples
|
||||
float outL = 0.f;
|
||||
float outR = 0.f;
|
||||
float inL = ins[0][offset];
|
||||
float inR = ins[1][offset];
|
||||
// in level
|
||||
inR *= *params[param_level_in];
|
||||
inL *= *params[param_level_in];
|
||||
|
||||
|
||||
float leftAC = inL;
|
||||
float rightAC = inR;
|
||||
float leftSC = inL;
|
||||
float rightSC = inR;
|
||||
float leftMC = inL;
|
||||
float rightMC = inR;
|
||||
|
||||
switch ((int)*params[param_sc_mode]) {
|
||||
default:
|
||||
case WIDEBAND:
|
||||
compressor.process(leftAC, rightAC, leftSC, rightSC);
|
||||
break;
|
||||
case DEESSER_WIDE:
|
||||
case DERUMBLER_WIDE:
|
||||
case WEIGHTED_1:
|
||||
case WEIGHTED_2:
|
||||
case WEIGHTED_3:
|
||||
case BANDPASS_2:
|
||||
leftSC = f2L.process(f1L.process(leftSC));
|
||||
rightSC = f2L.process(f1L.process(rightSC));
|
||||
leftMC = leftSC;
|
||||
rightMC = rightSC;
|
||||
compressor.process(leftAC, rightAC, leftSC, rightSC);
|
||||
break;
|
||||
case DEESSER_SPLIT:
|
||||
case DERUMBLER_SPLIT:
|
||||
leftSC = f1L.process(leftSC);
|
||||
rightSC = f1L.process(rightSC);
|
||||
leftMC = leftSC;
|
||||
rightMC = rightSC;
|
||||
compressor.process(leftSC, rightSC, leftSC, rightSC);
|
||||
leftAC = f2L.process(leftAC);
|
||||
rightAC = f2L.process(rightAC);
|
||||
leftAC += leftSC;
|
||||
rightAC += rightSC;
|
||||
break;
|
||||
case BANDPASS_1:
|
||||
leftSC = f1L.process(leftSC);
|
||||
rightSC = f1L.process(rightSC);
|
||||
leftMC = leftSC;
|
||||
rightMC = rightSC;
|
||||
compressor.process(leftAC, rightAC, leftSC, rightSC);
|
||||
break;
|
||||
}
|
||||
f1L.sanitize();
|
||||
f1R.sanitize();
|
||||
f2L.sanitize();
|
||||
f2R.sanitize();
|
||||
|
||||
if(*params[param_sc_listen] > 0.f) {
|
||||
outL = leftMC;
|
||||
outR = rightMC;
|
||||
} else {
|
||||
outL = leftAC;
|
||||
outR = rightAC;
|
||||
}
|
||||
|
||||
// send to output
|
||||
outs[0][offset] = outL;
|
||||
outs[1][offset] = outR;
|
||||
|
||||
// clip LED's
|
||||
if(std::max(fabs(inL), fabs(inR)) > 1.f) {
|
||||
clip_in = srate >> 3;
|
||||
}
|
||||
if(std::max(fabs(outL), fabs(outR)) > 1.f) {
|
||||
clip_out = srate >> 3;
|
||||
}
|
||||
// rise up out meter
|
||||
meter_in = std::max(fabs(inL), fabs(inR));;
|
||||
meter_out = std::max(fabs(outL), fabs(outR));;
|
||||
|
||||
// next sample
|
||||
++offset;
|
||||
} // cycle trough samples
|
||||
}
|
||||
// draw meters
|
||||
if(params[param_clip_in] != NULL) {
|
||||
*params[param_clip_in] = clip_in;
|
||||
}
|
||||
if(params[param_clip_out] != NULL) {
|
||||
*params[param_clip_out] = clip_out;
|
||||
}
|
||||
if(params[param_meter_in] != NULL) {
|
||||
*params[param_meter_in] = meter_in;
|
||||
}
|
||||
if(params[param_meter_out] != NULL) {
|
||||
*params[param_meter_out] = meter_out;
|
||||
}
|
||||
// draw strip meter
|
||||
if(bypass > 0.5f) {
|
||||
if(params[param_compression] != NULL) {
|
||||
*params[param_compression] = 1.0f;
|
||||
}
|
||||
} else {
|
||||
if(params[param_compression] != NULL) {
|
||||
*params[param_compression] = compressor.get_comp_level();
|
||||
}
|
||||
}
|
||||
// whatever has to be returned x)
|
||||
return outputs_mask;
|
||||
}
|
||||
bool sidechaincompressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (index == param_f1_freq && !subindex) {
|
||||
context->set_line_width(1.5);
|
||||
return ::get_graph(*this, subindex, data, points);
|
||||
} else if(index == param_compression) {
|
||||
return compressor.get_graph(subindex, data, points, context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sidechaincompressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (index == param_compression) {
|
||||
return compressor.get_dot(subindex, x, y, size, context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sidechaincompressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (index == param_compression) {
|
||||
return compressor.get_gridline(subindex, pos, vertical, legend, context);
|
||||
} else {
|
||||
return get_freq_gridline(subindex, pos, vertical, legend, context);
|
||||
}
|
||||
// return false;
|
||||
}
|
||||
|
||||
int sidechaincompressor_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if(index == param_compression) {
|
||||
return compressor.get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Gain reduction module implemented by Markus Schmidt
|
||||
/// Nearly all functions of this module are originally written
|
||||
/// by Thor, while some features have been stripped (mainly stereo linking
|
||||
@@ -1080,14 +1402,20 @@ void gain_reduction_audio_module::deactivate()
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
void gain_reduction_audio_module::process(float &left, float &right)
|
||||
void gain_reduction_audio_module::process(float &left, float &right, float det_left, float det_right)
|
||||
{
|
||||
if(!det_left) {
|
||||
det_left = left;
|
||||
}
|
||||
if(!det_right) {
|
||||
det_right = right;
|
||||
}
|
||||
float gain = 1.f;
|
||||
float maxLR = 0.f;
|
||||
if(bypass < 0.5f) {
|
||||
// this routine is mainly copied from thor's compressor module
|
||||
// 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));
|
||||
@@ -1100,7 +1428,7 @@ void gain_reduction_audio_module::process(float &left, float &right)
|
||||
kneeStop = log(linKneeStop);
|
||||
compressedKneeStop = (kneeStop - thres) / ratio + thres;
|
||||
|
||||
float absample = (fabs(left) + fabs(right)) * 0.5f;
|
||||
float absample = average ? (fabs(det_left) + fabs(det_right)) * 0.5f : std::max(fabs(det_left), fabs(det_right));
|
||||
if(rms) absample *= absample;
|
||||
|
||||
linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
|
||||
@@ -1109,15 +1437,12 @@ void gain_reduction_audio_module::process(float &left, float &right)
|
||||
gain = output_gain(linSlope, rms);
|
||||
}
|
||||
|
||||
gain *= makeup;
|
||||
|
||||
left *= gain;
|
||||
right *= gain;
|
||||
maxLR = std::max(fabs(left), fabs(right));
|
||||
left *= gain * makeup;
|
||||
right *= gain * makeup;
|
||||
meter_out = std::max(fabs(left), fabs(right));;
|
||||
meter_comp = gain;
|
||||
detected = rms ? sqrt(linSlope) : linSlope;
|
||||
}
|
||||
meter_out = maxLR;
|
||||
meter_comp = gain;
|
||||
}
|
||||
|
||||
float gain_reduction_audio_module::output_level(float slope) {
|
||||
@@ -1154,7 +1479,7 @@ void gain_reduction_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
}
|
||||
void gain_reduction_audio_module::set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float byp, float mu)
|
||||
void gain_reduction_audio_module::set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu)
|
||||
{
|
||||
// set all params
|
||||
attack = att;
|
||||
@@ -1164,6 +1489,7 @@ void gain_reduction_audio_module::set_params(float att, float rel, float thr, fl
|
||||
knee = kn;
|
||||
makeup = mak;
|
||||
detection = det;
|
||||
stereo_link = stl;
|
||||
bypass = byp;
|
||||
mute = mu;
|
||||
if(mute > 0.f) {
|
||||
|
||||
Reference in New Issue
Block a user