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
(cherry picked from commit 65f6bb7135)
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