From ed23c82c239222cf374e1994d669844af06e2cda Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Sat, 17 Oct 2009 23:34:23 +0200 Subject: [PATCH] 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 65f6bb7135db1bd0bf7a52d7e1b19dbc55eda0b7) --- plugins/ladspa_effect/calf/AUTHORS | 2 + plugins/ladspa_effect/calf/calf/giface.h | 5 +- plugins/ladspa_effect/calf/calf/metadata.h | 21 + plugins/ladspa_effect/calf/calf/modulelist.h | 1 + plugins/ladspa_effect/calf/calf/modules.h | 75 +- plugins/ladspa_effect/calf/calf/primitives.h | 6 +- plugins/ladspa_effect/calf/src/modules.cpp | 88 +++ .../ladspa_effect/calf/src/modules_dsp.cpp | 668 +++++++++++++++++- plugins/ladspa_effect/calf/src/monosynth.cpp | 2 +- 9 files changed, 839 insertions(+), 29 deletions(-) diff --git a/plugins/ladspa_effect/calf/AUTHORS b/plugins/ladspa_effect/calf/AUTHORS index c354559b1..8c4bf4833 100644 --- a/plugins/ladspa_effect/calf/AUTHORS +++ b/plugins/ladspa_effect/calf/AUTHORS @@ -4,6 +4,8 @@ Thor Harald Johansen Thorsten Wilms Hans Baier Torben Hohn +Markus Schmidt Additional bugfixes/enhancement patches: David Täht +Dave Robillard diff --git a/plugins/ladspa_effect/calf/calf/giface.h b/plugins/ladspa_effect/calf/calf/giface.h index 60e609f31..4a23300ca 100644 --- a/plugins/ladspa_effect/calf/calf/giface.h +++ b/plugins/ladspa_effect/calf/calf/giface.h @@ -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() {} diff --git a/plugins/ladspa_effect/calf/calf/metadata.h b/plugins/ladspa_effect/calf/calf/metadata.h index 4d2bd0c1f..fd89b6040 100644 --- a/plugins/ladspa_effect/calf/calf/metadata.h +++ b/plugins/ladspa_effect/calf/calf/metadata.h @@ -136,6 +136,27 @@ struct compressor_metadata: public plugin_metadata PLUGIN_NAME_ID_LABEL("compressor", "compressor", "Compressor") }; +/// Markus's multibandcompressor - metadata +struct multibandcompressor_metadata: public plugin_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 diff --git a/plugins/ladspa_effect/calf/calf/modulelist.h b/plugins/ladspa_effect/calf/calf/modulelist.h index 0c9f0b818..ca990654b 100644 --- a/plugins/ladspa_effect/calf/calf/modulelist.h +++ b/plugins/ladspa_effect/calf/calf/modulelist.h @@ -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") diff --git a/plugins/ladspa_effect/calf/calf/modules.h b/plugins/ladspa_effect/calf/calf/modules.h index 29aa47e89..d1545eb87 100644 --- a/plugins/ladspa_effect/calf/calf/modules.h +++ b/plugins/ladspa_effect/calf/calf/modules.h @@ -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, 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, 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 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, diff --git a/plugins/ladspa_effect/calf/calf/primitives.h b/plugins/ladspa_effect/calf/calf/primitives.h index 08f8e9012..79cbe3f96 100644 --- a/plugins/ladspa_effect/calf/calf/primitives.h +++ b/plugins/ladspa_effect/calf/calf/primitives.h @@ -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). diff --git a/plugins/ladspa_effect/calf/src/modules.cpp b/plugins/ladspa_effect/calf/src/modules.cpp index 84d64a8ac..5dc413e6d 100644 --- a/plugins/ladspa_effect/calf/src/modules.cpp +++ b/plugins/ladspa_effect/calf/src/modules.cpp @@ -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", }; diff --git a/plugins/ladspa_effect/calf/src/modules_dsp.cpp b/plugins/ladspa_effect/calf/src/modules_dsp.cpp index 69293a4c9..3ef471b0b 100644 --- a/plugins/ladspa_effect/calf/src/modules_dsp.cpp +++ b/plugins/ladspa_effect/calf/src/modules_dsp.cpp @@ -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; +} diff --git a/plugins/ladspa_effect/calf/src/monosynth.cpp b/plugins/ladspa_effect/calf/src/monosynth.cpp index 7c1b10927..33b24f3ae 100644 --- a/plugins/ladspa_effect/calf/src/monosynth.cpp +++ b/plugins/ladspa_effect/calf/src/monosynth.cpp @@ -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));