Merge branch 'calf-updates'
* calf-updates: + DSP primitives: fix a rather stupid bug in clamping functions + Monosynth: fix type bug that made it impossible to compile with g++ 4.2 + AutoHell: update AUTHORS file + GUI, Multiband Compressor, Toggle button: apply more fixes and additions by Markus Schmidt + Multiband Compressor: better metadata + Multiband Compressor: new module (first version, by Markus Schmidt, based on code by me and Thor) plus associated refactoring and graph colour scheme update
This commit is contained in:
@@ -4,6 +4,8 @@ Thor Harald Johansen <thj@thj.no>
|
||||
Thorsten Wilms <t_w_@freenet.de>
|
||||
Hans Baier <hansfbaier@googlemail.com>
|
||||
Torben Hohn <torbenh@gmx.de>
|
||||
Markus Schmidt <schmidt@boomshop.net>
|
||||
|
||||
Additional bugfixes/enhancement patches:
|
||||
David Täht <d@teklibre.com>
|
||||
Dave Robillard <dave@drobilla.net>
|
||||
|
||||
@@ -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
|
||||
@@ -190,12 +190,13 @@ struct line_graph_iface
|
||||
virtual bool get_static_graph(int index, int subindex, float value, float *data, int points, cairo_iface *context) { return false; }
|
||||
|
||||
/// Return which graphs need to be redrawn and which can be cached for later reuse
|
||||
/// @param index Parameter/graph number (usually tied to particular plugin control port)
|
||||
/// @param generation 0 (at start) or the last value returned by the function (corresponds to a set of input values)
|
||||
/// @param subindex_graph First graph that has to be redrawn (because it depends on values that might have changed)
|
||||
/// @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("multiband_compressor", "multibandcompressor", "Multiband Compressor")
|
||||
};
|
||||
|
||||
/// 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,61 @@ 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, old_mute, old_detection;
|
||||
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;
|
||||
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>,
|
||||
|
||||
@@ -224,14 +224,14 @@ inline T clip(T value, T min, T max) {
|
||||
inline double clip11(double value) {
|
||||
double a = fabs(value);
|
||||
if (a<=1) return value;
|
||||
return (a<0) ? -1.0 : 1.0;
|
||||
return (value<0) ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
/// Clip a float to [-1.0f, +1.0f]
|
||||
inline float clip11(float value) {
|
||||
float a = fabsf(value);
|
||||
if (a<=1) return value;
|
||||
return (a<0) ? -1.0f : 1.0f;
|
||||
return (value<0) ? -1.0f : 1.0f;
|
||||
}
|
||||
|
||||
/// Clip a double to [0.0, +1.0]
|
||||
@@ -245,7 +245,7 @@ inline double clip01(double value) {
|
||||
inline float clip01(float value) {
|
||||
float a = fabsf(value-0.5f);
|
||||
if (a<=0.5f) return value;
|
||||
return (a<0) ? -0.0f : 1.0f;
|
||||
return (value < 0) ? -0.0f : 1.0f;
|
||||
}
|
||||
|
||||
// Linear interpolation (mix-way between v1 and v2).
|
||||
|
||||
@@ -234,6 +234,94 @@ 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" },
|
||||
|
||||
{ 100, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq0", "Split 1/2" },
|
||||
{ 1000, 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 Multiband Compressor", "Markus Schmidt / Thor Harald Johansen", 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;
|
||||
@@ -519,9 +519,12 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples,
|
||||
bool bypass = *params[param_bypass] > 0.5f;
|
||||
|
||||
if(bypass) {
|
||||
int count = numsamples * sizeof(float);
|
||||
memcpy(outs[0], ins[0], count);
|
||||
memcpy(outs[1], ins[1], count);
|
||||
numsamples += offset;
|
||||
while(offset < numsamples) {
|
||||
outs[0][offset] = ins[0][offset];
|
||||
outs[1][offset] = ins[1][offset];
|
||||
++offset;
|
||||
}
|
||||
|
||||
if(params[param_compression] != NULL) {
|
||||
*params[param_compression] = 1.f;
|
||||
@@ -636,3 +639,642 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples,
|
||||
|
||||
return inputs_mask;
|
||||
}
|
||||
|
||||
|
||||
/// Multibandcompressor by Markus Schmidt
|
||||
///
|
||||
/// This module splits the signal in four different bands
|
||||
/// and sends them through multiple filters (implemented by
|
||||
/// Krzysztof). They are processed by a compressing routine
|
||||
/// (implemented by Thor) afterwards and summed up to the
|
||||
/// final output again.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
multibandcompressor_audio_module::multibandcompressor_audio_module()
|
||||
{
|
||||
is_active = false;
|
||||
srate = 0;
|
||||
// zero all displays
|
||||
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 * 2.5 * numsamples / srate;
|
||||
meter_inR -= meter_inR * 2.5 * numsamples / srate;
|
||||
meter_outL -= meter_outL * 2.5 * numsamples / srate;
|
||||
meter_outR -= meter_outR * 2.5 * numsamples / srate;
|
||||
|
||||
while(offset < numsamples) {
|
||||
// cycle through 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 default 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;
|
||||
}
|
||||
// rise up in / out meters
|
||||
if(inL > meter_inL) {
|
||||
meter_inL = inL;
|
||||
}
|
||||
if(inR > meter_inR) {
|
||||
meter_inR = inR;
|
||||
}
|
||||
if(outL > meter_outL) {
|
||||
meter_outL = outL;
|
||||
}
|
||||
if(outR > meter_outR) {
|
||||
meter_outR = outR;
|
||||
}
|
||||
// next sample
|
||||
++offset;
|
||||
} // 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)
|
||||
{
|
||||
// let's handle by the corresponding strip
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool multibandcompressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int multibandcompressor_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/// 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
|
||||
/// and frequency correction as implemented in his Compressor above)
|
||||
/// To save some CPU.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
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 = 1.f;
|
||||
float l, r;
|
||||
l = r = 0.f;
|
||||
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)
|
||||
{
|
||||
float compression = 1.f;
|
||||
meter_out -= meter_out * 5.f * 1 / srate;
|
||||
if(bypass < 0.5f) {
|
||||
// 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 absample = (fabs(left) + fabs(right)) * 0.5f;
|
||||
if(rms) absample *= absample;
|
||||
|
||||
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;
|
||||
|
||||
detected = rms ? sqrt(linSlope) : linSlope;
|
||||
}
|
||||
|
||||
float maxLR = std::max(fabs(left), fabs(right));
|
||||
|
||||
if(maxLR > meter_out) {
|
||||
meter_out = maxLR;
|
||||
}
|
||||
meter_comp = compression;
|
||||
}
|
||||
|
||||
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(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));
|
||||
if (subindex == 0)
|
||||
data[i] = dB_grid(input);
|
||||
else {
|
||||
float output = output_level(input);
|
||||
data[i] = dB_grid(output);
|
||||
}
|
||||
}
|
||||
if (subindex == (bypass > 0.5f ? 1 : 0) or mute > 0.1f)
|
||||
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(1.5);
|
||||
}
|
||||
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)
|
||||
{
|
||||
if(bypass > 0.5f or mute > 0.f) {
|
||||
return false;
|
||||
} else {
|
||||
bool rms = detection == 0;
|
||||
float det = rms ? sqrt(detected) : detected;
|
||||
x = 0.5 + 0.5 * dB_grid(det);
|
||||
y = dB_grid(bypass > 0.5f or mute > 0.f ? det : output_level(det));
|
||||
return 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(detection - old_detection) + fabs(bypass - old_bypass) + fabs(mute - old_mute) > 0.000001f)
|
||||
{
|
||||
old_threshold = threshold;
|
||||
old_ratio = ratio;
|
||||
old_knee = knee;
|
||||
old_makeup = makeup;
|
||||
old_detection = detection;
|
||||
old_bypass = bypass;
|
||||
old_mute = mute;
|
||||
last_generation++;
|
||||
}
|
||||
|
||||
if (generation == last_generation)
|
||||
subindex_graph = 2;
|
||||
return last_generation;
|
||||
}
|
||||
|
||||
@@ -626,7 +626,7 @@ void monosynth_audio_module::set_frequency()
|
||||
{
|
||||
float detune_scaled = (detune - 1); // * log(freq / 440);
|
||||
if (*params[par_scaledetune] > 0)
|
||||
detune_scaled *= pow(20.0 / freq, *params[par_scaledetune]);
|
||||
detune_scaled *= pow(20.0 / freq, (double)*params[par_scaledetune]);
|
||||
float p1 = 1, p2 = 1;
|
||||
if (moddest[moddest_o1detune] != 0)
|
||||
p1 = pow(2.0, moddest[moddest_o1detune] * (1.0 / 1200.0));
|
||||
|
||||
Reference in New Issue
Block a user