+ Multiband Compressor: new module (first version, by Markus Schmidt, based on code by me and Thor) plus associated refactoring and graph colour scheme update
(cherry picked from commit 9912931955299424aac7f32685d1a04003765995)
This commit is contained in:
committed by
Tobias Doerffel
parent
49c2f6bad1
commit
5fd28cb5f3
@@ -45,7 +45,7 @@ enum parameter_flags
|
||||
PF_TYPEMASK = 0x000F, ///< bit mask for type
|
||||
PF_FLOAT = 0x0000, ///< any float value
|
||||
PF_INT = 0x0001, ///< integer value (still represented as float)
|
||||
PF_BOOL = 0x0002, ///< bool value (usually >=0.5f is treated as true, which is inconsistent with LV2 etc. which treats anything >0 as true)
|
||||
PF_BOOL = 0x0002, ///< bool value (usually >=0.5f is treated as TRUE, which is inconsistent with LV2 etc. which treats anything >0 as TRUE)
|
||||
PF_ENUM = 0x0003, ///< enum value (min, min+1, ..., max, only guaranteed to work when min = 0)
|
||||
PF_ENUM_MULTI = 0x0004, ///< SET / multiple-choice
|
||||
PF_STRING = 0x0005, ///< see: http://lv2plug.in/docs/index.php?title=String_port
|
||||
@@ -195,7 +195,7 @@ struct line_graph_iface
|
||||
/// @param subindex_dot First dot that has to be redrawn
|
||||
/// @param subindex_gridline First gridline/legend that has to be redrawn
|
||||
/// @retval Current generation (to pass when calling the function next time); if different than passed generation value, call the function again to retrieve which graph offsets should be put into cache
|
||||
virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) { subindex_graph = subindex_dot = subindex_gridline = 0; return 0; }
|
||||
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) { subindex_graph = subindex_dot = subindex_gridline = 0; return 0; }
|
||||
|
||||
/// Standard destructor to make compiler happy
|
||||
virtual ~line_graph_iface() {}
|
||||
|
||||
@@ -136,6 +136,27 @@ struct compressor_metadata: public plugin_metadata<compressor_metadata>
|
||||
PLUGIN_NAME_ID_LABEL("compressor", "compressor", "Compressor")
|
||||
};
|
||||
|
||||
/// Markus's multibandcompressor - metadata
|
||||
struct multibandcompressor_metadata: public plugin_metadata<multibandcompressor_metadata>
|
||||
{
|
||||
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
|
||||
enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
|
||||
param_meter_outL, param_meter_outR, param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR,
|
||||
param_freq0, param_freq1, param_freq2,
|
||||
param_sep0, param_sep1, param_sep2,
|
||||
param_q0, param_q1, param_q2,
|
||||
param_threshold0, param_ratio0, param_attack0, param_release0, param_makeup0, param_knee0,
|
||||
param_detection0, param_compression0, param_output0, param_bypass0, param_mute0,
|
||||
param_threshold1, param_ratio1, param_attack1, param_release1, param_makeup1, param_knee1,
|
||||
param_detection1, param_compression1, param_output1, param_bypass1, param_mute1,
|
||||
param_threshold2, param_ratio2, param_attack2, param_release2, param_makeup2, param_knee2,
|
||||
param_detection2, param_compression2, param_output2, param_bypass2, param_mute2,
|
||||
param_threshold3, param_ratio3, param_attack3, param_release3, param_makeup3, param_knee3,
|
||||
param_detection3, param_compression3, param_output3, param_bypass3, param_mute3,
|
||||
param_count };
|
||||
PLUGIN_NAME_ID_LABEL("multibandcompressor", "multibandcompressor", "Multibandcompressor")
|
||||
};
|
||||
|
||||
/// Organ - enums for parameter IDs etc. (this mess is caused by organ split between plugin and generic class - which was
|
||||
/// a bad design decision and should be sorted out some day) XXXKF @todo
|
||||
struct organ_enums
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
PER_MODULE_ITEM(phaser, false, "phaser")
|
||||
PER_MODULE_ITEM(multichorus, false, "multichorus")
|
||||
PER_MODULE_ITEM(compressor, false, "compressor")
|
||||
PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
|
||||
#ifdef ENABLE_EXPERIMENTAL
|
||||
PER_MODULE_ITEM(fluidsynth, true, "fluidsynth")
|
||||
PER_MODULE_ITEM(wavetable, true, "wavetable")
|
||||
|
||||
@@ -66,7 +66,7 @@ class frequency_response_line_graph: public line_graph_iface
|
||||
{
|
||||
public:
|
||||
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
|
||||
virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
|
||||
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
|
||||
};
|
||||
|
||||
class flanger_audio_module: public audio_module<flanger_metadata>, public frequency_response_line_graph
|
||||
@@ -754,7 +754,7 @@ public:
|
||||
}
|
||||
|
||||
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context);
|
||||
int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
|
||||
int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
|
||||
};
|
||||
|
||||
/// A multitap stereo chorus thing - processing
|
||||
@@ -875,18 +875,18 @@ public:
|
||||
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 generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
{
|
||||
subindex_graph = 0;
|
||||
subindex_dot = 0;
|
||||
subindex_gridline = generation ? INT_MAX : 0;
|
||||
subindex_graph = 0;
|
||||
subindex_dot = 0;
|
||||
subindex_gridline = generation ? INT_MAX : 0;
|
||||
|
||||
if (fabs(threshold-old_threshold) + fabs(ratio - old_ratio) + fabs(knee - old_knee) + fabs( makeup - old_makeup) + fabs( *params[param_bypass] - old_bypass) > 0.01f)
|
||||
{
|
||||
old_threshold = threshold;
|
||||
old_ratio = ratio;
|
||||
old_knee = knee;
|
||||
old_makeup = makeup;
|
||||
old_threshold = threshold;
|
||||
old_ratio = ratio;
|
||||
old_knee = knee;
|
||||
old_makeup = makeup;
|
||||
old_bypass = *params[param_bypass];
|
||||
last_generation++;
|
||||
}
|
||||
@@ -897,6 +897,64 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
int last_generation;
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
inline float output_level(float slope);
|
||||
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 activate();
|
||||
void deactivate();
|
||||
int id;
|
||||
void set_sample_rate(uint32_t sr);
|
||||
float get_output_level();
|
||||
float get_comp_level();
|
||||
virtual bool get_graph(int subindex, float *data, int points, cairo_iface *context);
|
||||
virtual bool get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context);
|
||||
virtual bool get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
|
||||
virtual int get_changed_offsets(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:
|
||||
static const int strips = 4;
|
||||
float meter_out[strips];
|
||||
float meter_comp[strips];
|
||||
bool mute[strips];
|
||||
uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
|
||||
float meter_inL, meter_inR, meter_outL, meter_outR;
|
||||
gain_reduction_audio_module strip[strips];
|
||||
dsp::biquad_d2<float> lpL0, lpR0, lpL1, lpR1, lpL2, lpR2, hpL0, hpR0, hpL1, hpR1, hpL2, hpR2;
|
||||
float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1];
|
||||
public:
|
||||
float *ins[in_count];
|
||||
float *outs[out_count];
|
||||
float *params[param_count];
|
||||
uint32_t srate;
|
||||
bool is_active;
|
||||
multibandcompressor_audio_module();
|
||||
void activate();
|
||||
void deactivate();
|
||||
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);
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
/// Filterclavier --- MIDI controlled filter by Hans Baier
|
||||
class filterclavier_audio_module:
|
||||
public audio_module<filterclavier_metadata>,
|
||||
|
||||
@@ -234,6 +234,92 @@ CALF_PLUGIN_INFO(compressor) = { 0x8502, "Compressor", "Calf Compressor", "Thor
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CALF_PORT_NAMES(multibandcompressor) = {"In L", "In R", "Out L", "Out R"};
|
||||
|
||||
const char *multibandcompressor_detection_names[] = { "RMS", "Peak" };
|
||||
|
||||
CALF_PORT_PROPS(multibandcompressor) = {
|
||||
{ 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" },
|
||||
{ 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output" },
|
||||
{ 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_inL", "Input L" },
|
||||
{ 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_inR", "Input R" },
|
||||
{ 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_outL", "Output L" },
|
||||
{ 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_outR", "Output R" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inL", "0dB" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inR", "0dB" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB" },
|
||||
|
||||
{ 120, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq0", "Split 1/2" },
|
||||
{ 1200, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq1", "Split 2/3" },
|
||||
{ 6000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq2", "Split 3/4" },
|
||||
|
||||
{ -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep0", "S" },
|
||||
{ -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep1", "S" },
|
||||
{ -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep2", "S" },
|
||||
|
||||
{ 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q" },
|
||||
{ 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q" },
|
||||
{ 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q" },
|
||||
|
||||
|
||||
{ 0.0625, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold0", "Threshold" },
|
||||
{ 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio0", "Ratio" },
|
||||
{ 50, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack0", "Attack" },
|
||||
{ 100, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release0", "Release" },
|
||||
{ 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup0", "Makeup" },
|
||||
{ 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee0", "Knee" },
|
||||
{ 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection0", "Detection" },
|
||||
{ 1, 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, "compression0", "Gain Reduction" },
|
||||
{ 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, "output0", "Output" },
|
||||
{ 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass0", "Bypass" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute0", "Mute" },
|
||||
|
||||
|
||||
{ 0.03125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold1", "Threshold" },
|
||||
{ 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio1", "Ratio" },
|
||||
{ 25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack1", "Attack" },
|
||||
{ 50, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release1", "Release" },
|
||||
{ 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup1", "Makeup" },
|
||||
{ 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee1", "Knee" },
|
||||
{ 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection1", "Detection" },
|
||||
{ 1, 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, "compression1", "Gain Reduction" },
|
||||
{ 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, "output1", "Output" },
|
||||
{ 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass1", "Bypass" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute1", "Mute" },
|
||||
|
||||
|
||||
{ 0.015625, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold2", "Threshold" },
|
||||
{ 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio2", "Ratio" },
|
||||
{ 12.5, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack2", "Attack" },
|
||||
{ 25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release2", "Release" },
|
||||
{ 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup2", "Makeup" },
|
||||
{ 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee2", "Knee" },
|
||||
{ 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection2", "Detection" },
|
||||
{ 1, 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, "compression2", "Gain Reduction" },
|
||||
{ 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, "output2", "Output" },
|
||||
{ 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass2", "Bypass" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute2", "Mute" },
|
||||
|
||||
|
||||
{ 0.0078125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold3", "Threshold" },
|
||||
{ 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio3", "Ratio" },
|
||||
{ 6.25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack3", "Attack" },
|
||||
{ 12.5, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release3", "Release" },
|
||||
{ 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup3", "Makeup" },
|
||||
{ 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee3", "Knee" },
|
||||
{ 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection3", "Detection" },
|
||||
{ 1, 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, "compression3", "Gain Reduction" },
|
||||
{ 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, "output3", "Output" },
|
||||
{ 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass3", "Bypass" },
|
||||
{ 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute3", "Mute" },
|
||||
};
|
||||
|
||||
CALF_PLUGIN_INFO(multibandcompressor) = { 0x8502, "Multibandcompressor", "Calf Multibandcompressor", "Markus Schmidt", calf_plugins::calf_copyright_info, "CompressorPlugin" };
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CALF_PORT_NAMES(monosynth) = {
|
||||
"Out L", "Out R",
|
||||
};
|
||||
|
||||
@@ -58,9 +58,9 @@ static inline float dB_grid_inv(float pos)
|
||||
static void set_channel_color(cairo_iface *context, int channel)
|
||||
{
|
||||
if (channel & 1)
|
||||
context->set_source_rgba(0.75, 1, 0);
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 1);
|
||||
else
|
||||
context->set_source_rgba(0, 1, 0.75);
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
|
||||
context->set_line_width(1.5);
|
||||
}
|
||||
|
||||
@@ -87,9 +87,9 @@ static bool get_freq_gridline(int subindex, float &pos, bool &vertical, std::str
|
||||
freq = 10000 * (subindex - 27 + 1);
|
||||
pos = log(freq / 20.0) / log(1000);
|
||||
if (!legend.empty())
|
||||
context->set_source_rgba(0.25, 0.25, 0.25, 0.75);
|
||||
context->set_source_rgba(0, 0, 0, 0.2);
|
||||
else
|
||||
context->set_source_rgba(0.25, 0.25, 0.25, 0.5);
|
||||
context->set_source_rgba(0, 0, 0, 0.1);
|
||||
return true;
|
||||
}
|
||||
subindex -= 28;
|
||||
@@ -101,7 +101,7 @@ static bool get_freq_gridline(int subindex, float &pos, bool &vertical, std::str
|
||||
if (pos < -1)
|
||||
return false;
|
||||
if (subindex != 4)
|
||||
context->set_source_rgba(0.25, 0.25, 0.25, subindex & 1 ? 0.5 : 0.75);
|
||||
context->set_source_rgba(0, 0, 0, subindex & 1 ? 0.1 : 0.2);
|
||||
if (!(subindex & 1))
|
||||
{
|
||||
std::stringstream ss;
|
||||
@@ -119,7 +119,7 @@ bool frequency_response_line_graph::get_gridline(int index, int subindex, float
|
||||
return get_freq_gridline(subindex, pos, vertical, legend, context);
|
||||
}
|
||||
|
||||
int frequency_response_line_graph::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
int frequency_response_line_graph::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
{
|
||||
subindex_graph = 0;
|
||||
subindex_dot = 0;
|
||||
@@ -242,7 +242,7 @@ bool filter_audio_module::get_graph(int index, int subindex, float *data, int po
|
||||
return false;
|
||||
}
|
||||
|
||||
int filter_audio_module::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
int filter_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
{
|
||||
if (fabs(inertia_cutoff.get_last() - old_cutoff) + 100 * fabs(inertia_resonance.get_last() - old_resonance) + fabs(*params[par_mode] - old_mode) > 0.1f)
|
||||
{
|
||||
@@ -359,7 +359,7 @@ bool multichorus_audio_module::get_graph(int index, int subindex, float *data, i
|
||||
if (subindex < 2)
|
||||
set_channel_color(context, subindex);
|
||||
else {
|
||||
context->set_source_rgba(0, 1, 0);
|
||||
context->set_source_rgba(0.35, 0.4, 0.2);
|
||||
context->set_line_width(1.0);
|
||||
}
|
||||
return ::get_graph(*this, subindex, data, points);
|
||||
@@ -470,9 +470,9 @@ bool compressor_audio_module::get_graph(int index, int subindex, float *data, in
|
||||
data[i] = dB_grid(output);
|
||||
}
|
||||
if (subindex == (*params[param_bypass] > 0.5f ? 1 : 0))
|
||||
context->set_source_rgba(0.5, 0.5, 0.5, 0.5);
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 0.3);
|
||||
else {
|
||||
context->set_source_rgba(0, 1, 0, 1);
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 1);
|
||||
context->set_line_width(2);
|
||||
}
|
||||
return true;
|
||||
@@ -636,3 +636,628 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples,
|
||||
|
||||
return inputs_mask;
|
||||
}
|
||||
|
||||
/// Multibandcompressor by Markus Schmidt
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
multibandcompressor_audio_module::multibandcompressor_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
// zero all dsplays
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
}
|
||||
|
||||
void multibandcompressor_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
// set all filters and strips
|
||||
params_changed();
|
||||
// activate all strips
|
||||
for (int j = 0; j < strips; j ++) {
|
||||
strip[j].activate();
|
||||
strip[j].id = j;
|
||||
}
|
||||
}
|
||||
|
||||
void multibandcompressor_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
// deactivate all strips
|
||||
for (int j = 0; j < strips; j ++) {
|
||||
strip[j].deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void multibandcompressor_audio_module::params_changed()
|
||||
{
|
||||
// set the params of all filters
|
||||
if(*params[param_freq0] != freq_old[0] or *params[param_sep0] != sep_old[0] or *params[param_q0] != q_old[0]) {
|
||||
lpL0.set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate);
|
||||
lpR0.set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate);
|
||||
hpL0.set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate);
|
||||
hpR0.set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate);
|
||||
freq_old[0] = *params[param_freq0];
|
||||
sep_old[0] = *params[param_sep2];
|
||||
q_old[0] = *params[param_q2];
|
||||
}
|
||||
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);
|
||||
lpR1.set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate);
|
||||
hpL1.set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate);
|
||||
hpR1.set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate);
|
||||
freq_old[1] = *params[param_freq1];
|
||||
sep_old[1] = *params[param_sep2];
|
||||
q_old[1] = *params[param_q2];
|
||||
}
|
||||
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);
|
||||
lpR2.set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate);
|
||||
hpL2.set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate);
|
||||
hpR2.set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate);
|
||||
freq_old[2] = *params[param_freq2];
|
||||
sep_old[2] = *params[param_sep2];
|
||||
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], *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]);
|
||||
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]);
|
||||
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]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void multibandcompressor_audio_module::set_sample_rate(uint32_t sr)
|
||||
{
|
||||
srate = sr;
|
||||
// set srate of all strips
|
||||
for (int j = 0; j < strips; j ++) {
|
||||
strip[j].set_sample_rate(srate);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if(bypass) {
|
||||
// everything bypassed
|
||||
while(offset < numsamples) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
++offset;
|
||||
}
|
||||
// displays, too
|
||||
clip_inL = 0.f;
|
||||
clip_inR = 0.f;
|
||||
clip_outL = 0.f;
|
||||
clip_outR = 0.f;
|
||||
meter_inL = 0.f;
|
||||
meter_inR = 0.f;
|
||||
meter_outL = 0.f;
|
||||
meter_outR = 0.f;
|
||||
} else {
|
||||
// process all strips
|
||||
|
||||
// determine mute state of strips
|
||||
mute[0] = *params[param_mute0] > 0.f ? true : false;
|
||||
mute[1] = *params[param_mute1] > 0.f ? true : false;
|
||||
mute[2] = *params[param_mute2] > 0.f ? true : false;
|
||||
mute[3] = *params[param_mute3] > 0.f ? true : false;
|
||||
|
||||
// let meters fall a bit
|
||||
clip_inL -= std::min(clip_inL, numsamples);
|
||||
clip_inR -= std::min(clip_inR, numsamples);
|
||||
clip_outL -= std::min(clip_outL, numsamples);
|
||||
clip_outR -= std::min(clip_outR, numsamples);
|
||||
meter_inL -= meter_inL * 5.f * numsamples / srate;
|
||||
meter_inR -= meter_inR * 5.f * numsamples / srate;
|
||||
meter_outL -= meter_outL * 5.f * numsamples / srate;
|
||||
meter_outR -= meter_outR * 5.f * numsamples / srate;
|
||||
for(int k = 0; k < strips; k ++) {
|
||||
meter_out[k] -= meter_out[k] * 5.f * numsamples / srate;
|
||||
}
|
||||
|
||||
while(offset < numsamples) {
|
||||
// cycle trough samples
|
||||
float inL = ins[0][offset];
|
||||
float inR = ins[1][offset];
|
||||
// in level
|
||||
inR *= *params[param_level_in];
|
||||
inL *= *params[param_level_in];
|
||||
// out vars
|
||||
float outL = 0.f;
|
||||
float outR = 0.f;
|
||||
for (int i = 0; i < strips; i ++) {
|
||||
// cycle trough strips
|
||||
if (!mute[i]) {
|
||||
// strip unmuted
|
||||
float left = inL;
|
||||
float right = inR;
|
||||
// send trough filters
|
||||
switch (i) {
|
||||
case 0:
|
||||
left = lpL0.process(left);
|
||||
right = lpR0.process(right);
|
||||
lpL0.sanitize();
|
||||
lpR0.sanitize();
|
||||
break;
|
||||
case 1:
|
||||
left = lpL1.process(left);
|
||||
right = lpR1.process(right);
|
||||
left = hpL0.process(left);
|
||||
right = hpR0.process(right);
|
||||
lpL1.sanitize();
|
||||
lpR1.sanitize();
|
||||
hpL0.sanitize();
|
||||
hpR0.sanitize();
|
||||
break;
|
||||
case 2:
|
||||
left = lpL2.process(left);
|
||||
right = lpR2.process(right);
|
||||
left = hpL1.process(left);
|
||||
right = hpR1.process(right);
|
||||
lpL2.sanitize();
|
||||
lpR2.sanitize();
|
||||
hpL1.sanitize();
|
||||
hpR1.sanitize();
|
||||
break;
|
||||
case 3:
|
||||
left = hpL2.process(left);
|
||||
right = hpR2.process(right);
|
||||
hpL2.sanitize();
|
||||
hpR2.sanitize();
|
||||
break;
|
||||
}
|
||||
// process gain reduction
|
||||
strip[i].process(left, right);
|
||||
// sum up output
|
||||
outL += left;
|
||||
outR += right;
|
||||
} else {
|
||||
// strip muted
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // process single strip
|
||||
|
||||
// even out filters gain reduction
|
||||
// 3dB - levelled manually (based on sep and q settings)
|
||||
outL *= 1.414213562;
|
||||
outR *= 1.414213562;
|
||||
|
||||
// out level
|
||||
outL *= *params[param_level_out];
|
||||
outR *= *params[param_level_out];
|
||||
|
||||
// send to output
|
||||
outs[0][offset] = outL;
|
||||
outs[1][offset] = outR;
|
||||
|
||||
// clip LED's
|
||||
if(inL > 1.f) {
|
||||
clip_inL = srate >> 3;
|
||||
}
|
||||
if(inR > 1.f) {
|
||||
clip_inR = srate >> 3;
|
||||
}
|
||||
if(outL > 1.f) {
|
||||
clip_outL = srate >> 3;
|
||||
}
|
||||
if(outR > 1.f) {
|
||||
clip_outR = srate >> 3;
|
||||
}
|
||||
// in / out meters
|
||||
if(meter_inL < inL) {
|
||||
meter_inL = inL;
|
||||
}
|
||||
if(meter_inR < inR) {
|
||||
meter_inR = inR;
|
||||
}
|
||||
if(meter_outL < outL) {
|
||||
meter_outL = outL;
|
||||
}
|
||||
if(meter_outR < outR) {
|
||||
meter_outR = outR;
|
||||
}
|
||||
// next sample
|
||||
++offset;
|
||||
// printf("inL: %+7.4f inR: %+7.4f outL: %+7.4f outR: %+7.4f input: %+7.4f output: %+7.4f\n", inL, inR, outL, outR, *params[param_level_in], *params[param_level_out]);
|
||||
} // cycle trough samples
|
||||
|
||||
} // 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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
// printf("get_graph : %i\n", index);
|
||||
switch (index) {
|
||||
case param_compression0:
|
||||
return strip[0].get_graph(subindex, data, points, context);
|
||||
break;
|
||||
case param_compression1:
|
||||
return strip[1].get_graph(subindex, data, points, context);
|
||||
break;
|
||||
case param_compression2:
|
||||
return strip[2].get_graph(subindex, data, points, context);
|
||||
break;
|
||||
case param_compression3:
|
||||
return strip[3].get_graph(subindex, data, points, context);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool multibandcompressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
|
||||
{
|
||||
// printf("get_dot : %i\n", index);
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool multibandcompressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
|
||||
{
|
||||
// printf("get_gridline: %i\n", index);
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int multibandcompressor_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
{
|
||||
// printf("get_changed : %i\n", index);
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/// Gain reduction module by Markus Schmidt
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
gain_reduction_audio_module::gain_reduction_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
last_generation = 0;
|
||||
}
|
||||
|
||||
void gain_reduction_audio_module::activate()
|
||||
{
|
||||
is_active = true;
|
||||
linSlope = 0.f;
|
||||
meter_out = 0.f;
|
||||
meter_comp = 0.f;
|
||||
float l, r;
|
||||
float byp = bypass;
|
||||
bypass = 0.0;
|
||||
process(l, r);
|
||||
bypass = byp;
|
||||
}
|
||||
|
||||
void gain_reduction_audio_module::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
void gain_reduction_audio_module::process(float &left, float &right)
|
||||
{
|
||||
if(bypass > 0.5f) {
|
||||
meter_comp = 1.f;
|
||||
meter_out = 0.f;
|
||||
return;
|
||||
}
|
||||
// this routine is mainly copied from thor's compressor module
|
||||
// greatest sounding compressor I've heard!
|
||||
bool rms = detection == 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;
|
||||
float compression = 1.f;
|
||||
float absample = (fabs(left) + fabs(right)) * 0.5f;
|
||||
if(rms) absample *= absample;
|
||||
meter_out -= meter_out * 5.f * 1 / srate;
|
||||
|
||||
linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
|
||||
|
||||
float gain = 1.f;
|
||||
|
||||
if(linSlope > 0.f) {
|
||||
gain = output_gain(linSlope, rms);
|
||||
}
|
||||
|
||||
compression = gain;
|
||||
gain *= makeup;
|
||||
|
||||
left *= gain;
|
||||
right *= gain;
|
||||
|
||||
float maxLR = std::max(fabs(left), fabs(right));
|
||||
|
||||
if(maxLR > meter_out) {
|
||||
meter_out = maxLR;
|
||||
}
|
||||
meter_comp = compression;
|
||||
|
||||
detected = rms ? sqrt(linSlope) : linSlope;
|
||||
}
|
||||
|
||||
float gain_reduction_audio_module::output_level(float slope) {
|
||||
return slope * output_gain(slope, false) * makeup;
|
||||
}
|
||||
|
||||
float gain_reduction_audio_module::output_gain(float linSlope, bool rms) {
|
||||
//this calculation is also thor's work
|
||||
if(linSlope > (rms ? adjKneeStart : linKneeStart)) {
|
||||
float slope = log(linSlope);
|
||||
if(rms) slope *= 0.5f;
|
||||
|
||||
float gain = 0.f;
|
||||
float delta = 0.f;
|
||||
if(IS_FAKE_INFINITY(ratio)) {
|
||||
gain = thres;
|
||||
delta = 0.f;
|
||||
} else {
|
||||
gain = (slope - thres) / ratio + thres;
|
||||
delta = 1.f / ratio;
|
||||
}
|
||||
|
||||
if(knee > 1.f && slope < kneeStop) {
|
||||
gain = hermite_interpolation(slope, kneeStart, kneeStop, kneeStart, compressedKneeStop, 1.f, delta);
|
||||
}
|
||||
|
||||
return exp(gain - slope);
|
||||
}
|
||||
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// set all params
|
||||
attack = att;
|
||||
release = rel;
|
||||
threshold = thr;
|
||||
ratio = rat;
|
||||
knee = kn;
|
||||
makeup = mak;
|
||||
detection = det;
|
||||
bypass = byp;
|
||||
mute = mu;
|
||||
// if bypass, zero meters
|
||||
if(bypass > 0.5 or mute > 0.f) {
|
||||
meter_out = 0.f;
|
||||
meter_comp = 1.f;
|
||||
}
|
||||
}
|
||||
float gain_reduction_audio_module::get_output_level() {
|
||||
// returns output level (max(left, right))
|
||||
return meter_out;
|
||||
}
|
||||
float gain_reduction_audio_module::get_comp_level() {
|
||||
// returns amount of compression
|
||||
return meter_comp;
|
||||
}
|
||||
|
||||
bool gain_reduction_audio_module::get_graph(int subindex, float *data, int points, cairo_iface *context)
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (subindex > 1) // 1
|
||||
return false;
|
||||
for (int i = 0; i < points; i++)
|
||||
{
|
||||
float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1));
|
||||
float output = output_level(input);
|
||||
if (subindex == 0)
|
||||
data[i] = dB_grid(input);
|
||||
else
|
||||
data[i] = dB_grid(output);
|
||||
}
|
||||
if (subindex == (bypass > 0.5f ? 1 : 0))
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 0.3);
|
||||
else {
|
||||
context->set_source_rgba(0.35, 0.4, 0.2, 1);
|
||||
context->set_line_width(2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gain_reduction_audio_module::get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context)
|
||||
{
|
||||
if (!is_active)
|
||||
return false;
|
||||
if (!subindex)
|
||||
{
|
||||
x = 0.5 + 0.5 * dB_grid(detected);
|
||||
y = dB_grid(bypass > 0.5f ? detected : output_level(detected));
|
||||
return bypass > 0.5f ? false : true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gain_reduction_audio_module::get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
|
||||
{
|
||||
bool tmp;
|
||||
vertical = (subindex & 1) != 0;
|
||||
bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
|
||||
if (result && vertical) {
|
||||
if ((subindex & 4) && !legend.empty()) {
|
||||
legend = "";
|
||||
}
|
||||
else {
|
||||
size_t pos = legend.find(" dB");
|
||||
if (pos != std::string::npos)
|
||||
legend.erase(pos);
|
||||
}
|
||||
pos = 0.5 + 0.5 * pos;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int gain_reduction_audio_module::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
{
|
||||
subindex_graph = 0;
|
||||
subindex_dot = 0;
|
||||
subindex_gridline = generation ? INT_MAX : 0;
|
||||
|
||||
if (fabs(threshold-old_threshold) + fabs(ratio - old_ratio) + fabs(knee - old_knee) + fabs(makeup - old_makeup) + fabs(bypass - old_bypass) > 0.01f)
|
||||
{
|
||||
old_threshold = threshold;
|
||||
old_ratio = ratio;
|
||||
old_knee = knee;
|
||||
old_makeup = makeup;
|
||||
old_bypass = bypass;
|
||||
last_generation++;
|
||||
}
|
||||
|
||||
if (generation == last_generation)
|
||||
subindex_graph = 2;
|
||||
return last_generation;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user