diff --git a/plugins/ladspa_effect/calf/calf/giface.h b/plugins/ladspa_effect/calf/calf/giface.h index 56305bcb9..92cb1f941 100644 --- a/plugins/ladspa_effect/calf/calf/giface.h +++ b/plugins/ladspa_effect/calf/calf/giface.h @@ -306,6 +306,10 @@ struct plugin_metadata_iface virtual int get_input_count()=0; /// @return number of audio outputs virtual int get_output_count()=0; + /// @return number of optional inputs + virtual int get_inputs_optional()=0; + /// @return number of optional outputs + virtual int get_outputs_optional()=0; /// @return true if plugin can work in hard-realtime conditions virtual bool is_rt_capable()=0; /// @return true if plugin has MIDI input @@ -489,6 +493,8 @@ public: const char *get_label() { return Metadata::impl_get_label(); } int get_input_count() { return Metadata::in_count; } int get_output_count() { return Metadata::out_count; } + int get_inputs_optional() { return Metadata::ins_optional; } + int get_outputs_optional() { return Metadata::outs_optional; } int get_param_count() { return Metadata::param_count; } bool get_midi() { return Metadata::support_midi; } bool requires_midi() { return Metadata::require_midi; } @@ -528,6 +534,8 @@ public: const char *get_label() { return impl->get_label(); } int get_input_count() { return impl->get_input_count(); } int get_output_count() { return impl->get_output_count(); } + int get_inputs_optional() { return impl->get_inputs_optional(); } + int get_outputs_optional() { return impl->get_outputs_optional(); } int get_param_count() { return impl->get_param_count(); } bool get_midi() { return impl->get_midi(); } bool requires_midi() { return impl->requires_midi(); } diff --git a/plugins/ladspa_effect/calf/calf/metadata.h b/plugins/ladspa_effect/calf/calf/metadata.h index c959e1940..2ba9e02b7 100644 --- a/plugins/ladspa_effect/calf/calf/metadata.h +++ b/plugins/ladspa_effect/calf/calf/metadata.h @@ -31,21 +31,21 @@ struct flanger_metadata: public plugin_metadata { public: enum { par_delay, par_depth, par_rate, par_fb, par_stereo, par_reset, par_amount, par_dryamount, param_count }; - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true }; PLUGIN_NAME_ID_LABEL("flanger", "flanger", "Flanger") }; struct phaser_metadata: public plugin_metadata { enum { par_freq, par_depth, par_rate, par_fb, par_stages, par_stereo, par_reset, par_amount, par_dryamount, param_count }; - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true }; PLUGIN_NAME_ID_LABEL("phaser", "phaser", "Phaser") }; struct filter_metadata: public plugin_metadata { enum { par_cutoff, par_resonance, par_mode, par_inertia, param_count }; - enum { in_count = 2, out_count = 2, rt_capable = true, require_midi = false, support_midi = false }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, require_midi = false, support_midi = false }; PLUGIN_NAME_ID_LABEL("filter", "filter", "Filter") /// do not export mode and inertia as CVs, as those are settings and not parameters bool is_cv(int param_no) { return param_no != par_mode && param_no != par_inertia; } @@ -55,7 +55,7 @@ struct filter_metadata: public plugin_metadata struct filterclavier_metadata: public plugin_metadata { enum { par_transpose, par_detune, par_max_resonance, par_mode, par_inertia, param_count }; - enum { in_count = 2, out_count = 2, rt_capable = true, require_midi = true, support_midi = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, require_midi = true, support_midi = true }; PLUGIN_NAME_ID_LABEL("filterclavier", "filterclavier", "Filterclavier") /// do not export mode and inertia as CVs, as those are settings and not parameters bool is_cv(int param_no) { return param_no != par_mode && param_no != par_inertia; } @@ -64,14 +64,14 @@ struct filterclavier_metadata: public plugin_metadata struct reverb_metadata: public plugin_metadata { enum { par_clip, par_meter_wet, par_meter_out, par_decay, par_hfdamp, par_roomsize, par_diffusion, par_amount, par_dry, par_predelay, par_basscut, par_treblecut, param_count }; - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true }; PLUGIN_NAME_ID_LABEL("reverb", "reverb", "Reverb") }; struct vintage_delay_metadata: public plugin_metadata { enum { par_bpm, par_divide, par_time_l, par_time_r, par_feedback, par_amount, par_mixmode, par_medium, par_dryamount, param_count }; - enum { in_count = 2, out_count = 2, rt_capable = true, support_midi = false, require_midi = false }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, support_midi = false, require_midi = false }; PLUGIN_NAME_ID_LABEL("vintage_delay", "vintagedelay", "Vintage Delay") }; @@ -79,7 +79,7 @@ struct rotary_speaker_metadata: public plugin_metadata { public: enum { par_speed, par_spacing, par_shift, par_moddepth, par_treblespeed, par_bassspeed, par_micdistance, par_reflection, par_meter_l, par_meter_h, param_count }; - enum { in_count = 2, out_count = 2, support_midi = true, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = false, rt_capable = true }; PLUGIN_NAME_ID_LABEL("rotary_speaker", "rotaryspeaker", "Rotary Speaker") }; @@ -88,7 +88,7 @@ struct multichorus_metadata: public plugin_metadata { public: enum { par_delay, par_depth, par_rate, par_stereo, par_voices, par_vphase, par_amount, par_dryamount, par_freq, par_freq2, par_q, par_overlap, param_count }; - enum { in_count = 2, out_count = 2, rt_capable = true, support_midi = false, require_midi = false }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, support_midi = false, require_midi = false }; PLUGIN_NAME_ID_LABEL("multichorus", "multichorus", "Multi Chorus") }; @@ -101,7 +101,7 @@ struct monosynth_metadata: public plugin_metadata par_keyfollow, par_legato, par_portamento, par_vel2filter, par_vel2amp, par_master, par_pwhlrange, par_lforate, par_lfodelay, par_lfofilter, par_lfopitch, par_lfopw, par_mwhl_lfo, par_scaledetune, param_count }; - enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = true }; + enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true }; enum { step_size = 64, step_shift = 6 }; enum { modsrc_none, @@ -128,18 +128,20 @@ struct monosynth_metadata: public plugin_metadata }; /// Thor's compressor - metadata +/// Added some meters and stripped the weighting part struct compressor_metadata: public plugin_metadata { - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; - enum { param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_aweighting, param_compression, param_peak, param_clip, param_bypass, param_input,// param_freq, param_bw, - param_count }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true }; + enum { param_bypass, param_level_in, param_meter_in, param_meter_out, param_clip_in, param_clip_out, + param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_compression, + param_count }; PLUGIN_NAME_ID_LABEL("compressor", "compressor", "Compressor") }; /// Markus's sidechain compressor - metadata struct sidechaincompressor_metadata: public plugin_metadata { - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true }; enum { param_bypass, param_level_in, param_meter_in, param_meter_out, param_clip_in, param_clip_out, param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_compression, param_sc_mode, param_f1_freq, param_f2_freq, param_f1_level, param_f2_level, @@ -150,7 +152,7 @@ struct sidechaincompressor_metadata: public plugin_metadata { - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, 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, @@ -171,7 +173,7 @@ struct multibandcompressor_metadata: public plugin_metadata { - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true }; enum { param_bypass, param_detected, param_compression, param_detected_led, param_clip_out, param_detection, param_mode, param_threshold, param_ratio, param_laxity, param_makeup, @@ -183,7 +185,7 @@ struct deesser_metadata: public plugin_metadata /// Markus's 5-band EQ - metadata struct equalizer5band_metadata: public plugin_metadata { - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true }; enum { param_bypass, param_level_in, param_level_out, param_meter_in, param_meter_out, param_clip_in, param_clip_out, param_ls_active, param_ls_level, param_ls_freq, @@ -197,7 +199,7 @@ struct equalizer5band_metadata: public plugin_metadata /// Markus's 8-band EQ - metadata struct equalizer8band_metadata: public plugin_metadata { - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, 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_hp_active, param_hp_freq, param_hp_mode, @@ -214,7 +216,7 @@ struct equalizer8band_metadata: public plugin_metadata /// Markus's 12-band EQ - metadata struct equalizer12band_metadata: public plugin_metadata { - enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true }; + enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, 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_hp_active, param_hp_freq, param_hp_mode, @@ -319,7 +321,7 @@ struct organ_enums /// Organ - metadata struct organ_metadata: public organ_enums, public plugin_metadata { - enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = true }; + enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true }; PLUGIN_NAME_ID_LABEL("organ", "organ", "Organ") plugin_command_info *get_commands(); const char **get_default_configure_vars(); @@ -329,7 +331,7 @@ struct organ_metadata: public organ_enums, public plugin_metadata { enum { par_master, par_soundfont, par_interpolation, par_reverb, par_chorus, param_count }; - enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = false }; + enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = false }; PLUGIN_NAME_ID_LABEL("fluidsynth", "fluidsynth", "Fluidsynth") const char **get_default_configure_vars(); }; @@ -399,7 +401,7 @@ struct wavetable_metadata: public plugin_metadata par_eg3attack, par_eg3decay, par_eg3sustain, par_eg3fade, par_eg3release, par_eg3velscl, par_pwhlrange, param_count }; - enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = true }; + enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true }; enum { step_size = 64 }; PLUGIN_NAME_ID_LABEL("wavetable", "wavetable", "Wavetable") }; diff --git a/plugins/ladspa_effect/calf/calf/modules.h b/plugins/ladspa_effect/calf/calf/modules.h index e8c4a5e22..5f42b369e 100644 --- a/plugins/ladspa_effect/calf/calf/modules.h +++ b/plugins/ladspa_effect/calf/calf/modules.h @@ -846,82 +846,6 @@ public: bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context); }; -class compressor_audio_module: public audio_module, public line_graph_iface { -private: - float linSlope, peak, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop, threshold, ratio, knee, makeup, compressedKneeStop, adjKneeStart; - float old_threshold, old_ratio, old_knee, old_makeup, old_bypass; - int last_generation; - uint32_t clip; - aweighter awL, awR; - biquad_d2 bpL, bpR; -public: - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool is_active; - compressor_audio_module(); - void activate(); - void deactivate(); - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); - - inline float output_level(float slope) { - return slope * output_gain(slope, false) * makeup; - } - - inline float output_gain(float linSlope, bool rms) { - 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 = threshold; - delta = 0.f; - } else { - gain = (slope - threshold) / ratio + threshold; - 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 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) - { - 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_bypass = *params[param_bypass]; - last_generation++; - } - - if (generation == last_generation) - subindex_graph = 2; - return last_generation; - } -}; - class gain_reduction_audio_module { private: float linSlope, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop; @@ -949,6 +873,32 @@ public: virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline); }; +/// Compressor by Thor +class compressor_audio_module: public audio_module, public line_graph_iface { +private: + uint32_t clip_in, clip_out; + float meter_in, meter_out; + gain_reduction_audio_module compressor; +public: + typedef std::complex cfloat; + float *ins[in_count]; + float *outs[out_count]; + float *params[param_count]; + uint32_t srate; + bool is_active; + volatile int last_generation, last_calculated_generation; + compressor_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + void set_sample_rate(uint32_t sr); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context); + bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context); + bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context); + int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline); +}; + /// Sidecain Compressor by Markus Schmidt (based on Thor's compressor and Krzysztof's filters) class sidechaincompressor_audio_module: public audio_module, public frequency_response_line_graph { private: diff --git a/plugins/ladspa_effect/calf/src/modules.cpp b/plugins/ladspa_effect/calf/src/modules.cpp index 225e38712..73d1d6184 100644 --- a/plugins/ladspa_effect/calf/src/modules.cpp +++ b/plugins/ladspa_effect/calf/src/modules.cpp @@ -215,25 +215,23 @@ CALF_PORT_NAMES(compressor) = {"In L", "In R", "Out L", "Out R"}; const char *compressor_detection_names[] = { "RMS", "Peak" }; const char *compressor_stereo_link_names[] = { "Average", "Maximum" }; -const char *compressor_weighting_names[] = { "Normal", "A-weighted", "Deesser (low)", "Deesser (med)", "Deesser (high)" }; CALF_PORT_PROPS(compressor) = { + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" }, { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" }, { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" }, { 20, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" }, { 250, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" }, - { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" }, + { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" }, { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" }, - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, compressor_detection_names, "detection", "Detection" }, - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, compressor_stereo_link_names, "stereo_link", "Stereo Link" }, - { 0, 0, 4, 0, PF_ENUM | PF_CTL_COMBO, compressor_weighting_names, "aweighting", "Weighting" }, - { 0, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression", "Compression" }, - { 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, "peak", "Peak Output" }, - { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip", "0dB" }, - { 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, "input", "Input" }, - // { 2000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "deess_freq", "Frequency" }, - // { 0.707, 0.707, 32, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "deess_res", "Q" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, compressor_detection_names, "detection", "Detection" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, compressor_stereo_link_names, "stereo_link", "Stereo Link" }, + { 0, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression", "Reduction" }, }; CALF_PLUGIN_INFO(compressor) = { 0x8502, "Compressor", "Calf Compressor", "Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; diff --git a/plugins/ladspa_effect/calf/src/modules_dsp.cpp b/plugins/ladspa_effect/calf/src/modules_dsp.cpp index 5258c0475..ba4a48de9 100644 --- a/plugins/ladspa_effect/calf/src/modules_dsp.cpp +++ b/plugins/ladspa_effect/calf/src/modules_dsp.cpp @@ -425,218 +425,6 @@ float multichorus_audio_module::freq_gain(int subindex, float freq, float srate) return (subindex ? right : left).freq_gain(freq, srate); } -/////////////////////////////////////////////////////////////////////////////////////////////// - -compressor_audio_module::compressor_audio_module() -{ - is_active = false; - srate = 0; - last_generation = 0; -} - -void compressor_audio_module::activate() -{ - is_active = true; - linSlope = 0.f; - peak = 0.f; - clip = 0.f; -} - -void compressor_audio_module::deactivate() -{ - is_active = false; -} - -void compressor_audio_module::set_sample_rate(uint32_t sr) -{ - srate = sr; - awL.set(sr); - awR.set(sr); -} - -bool compressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) -{ - if (!is_active) - return false; - if (subindex > 1) // 1 - return false; - for (int i = 0; i < points; i++) - { - float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1)); - float output = output_level(input); - if (subindex == 0) - data[i] = dB_grid(input); - else - data[i] = dB_grid(output); - } - if (subindex == (*params[param_bypass] > 0.5f ? 1 : 0)) - context->set_source_rgba(0.35, 0.4, 0.2, 0.3); - else { - context->set_source_rgba(0.35, 0.4, 0.2, 1); - context->set_line_width(2); - } - return true; -} - -bool compressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) -{ - if (!is_active) - return false; - if (!subindex) - { - bool rms = *params[param_detection] == 0; - float det = rms ? sqrt(detected) : detected; - x = 0.5 + 0.5 * dB_grid(det); - y = dB_grid(*params[param_bypass] > 0.5f ? det : output_level(det)); - return *params[param_bypass] > 0.5f ? false : true; - } - return false; -} - -bool compressor_audio_module::get_gridline(int index, 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; -} - -// In case of doubt: this function is written by Thor. I just moved it to this file, damaging -// the output of "git annotate" in the process. -uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) -{ - bool bypass = *params[param_bypass] > 0.5f; - - if(bypass) { - 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; - } - - if(params[param_clip] != NULL) { - *params[param_clip] = 0.f; - } - - if(params[param_peak] != NULL) { - *params[param_peak] = 0.f; - } - - return inputs_mask; - } - - bool rms = *params[param_detection] == 0; - bool average = *params[param_stereo_link] == 0; - int aweighting = fastf2i_drm(*params[param_aweighting]); - float linThreshold = *params[param_threshold]; - ratio = *params[param_ratio]; - float attack = *params[param_attack]; - float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f)); - float release = *params[param_release]; - float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f)); - makeup = *params[param_makeup]; - knee = *params[param_knee]; - - float linKneeSqrt = sqrt(knee); - linKneeStart = linThreshold / linKneeSqrt; - adjKneeStart = linKneeStart*linKneeStart; - float linKneeStop = linThreshold * linKneeSqrt; - - threshold = log(linThreshold); - kneeStart = log(linKneeStart); - kneeStop = log(linKneeStop); - compressedKneeStop = (kneeStop - threshold) / ratio + threshold; - - if (aweighting >= 2) - { - bpL.set_highshelf_rbj(5000, 0.707, 10 << (aweighting - 2), srate); - bpR.copy_coeffs(bpL); - bpL.sanitize(); - bpR.sanitize(); - } - - numsamples += offset; - - float compression = 1.f; - peak = 0.f; - clip -= std::min(clip, numsamples); - - while(offset < numsamples) { - float left = ins[0][offset] * *params[param_input]; - float right = ins[1][offset] * *params[param_input]; - - if(aweighting == 1) { - left = awL.process(left); - right = awR.process(right); - } - else if(aweighting >= 2) { - left = bpL.process(left); - right = bpR.process(right); - } - - float absample = average ? (fabs(left) + fabs(right)) * 0.5f : std::max(fabs(left), fabs(right)); - 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; - - float outL = ins[0][offset] * gain * *params[param_input]; - float outR = ins[1][offset] * gain * *params[param_input]; - - outs[0][offset] = outL; - outs[1][offset] = outR; - - ++offset; - - float maxLR = std::max(fabs(outL), fabs(outR)); - if(maxLR > peak) - peak = maxLR; - - if(peak > 1.f) clip = srate >> 3; /* blink clip LED for 125 ms */ - } - - detected = linSlope; - - if(params[param_compression] != NULL) { - *params[param_compression] = compression; - } - - if(params[param_clip] != NULL) { - *params[param_clip] = clip; - } - - if(params[param_peak] != NULL) { - *params[param_peak] = peak; - } - - return inputs_mask; -} - - /// Multibandcompressor by Markus Schmidt /// /// This module splits the signal in four different bands @@ -1050,6 +838,161 @@ int multibandcompressor_audio_module::get_changed_offsets(int index, int generat return 0; } +/// Compressor originally by Thor +/// +/// This module provides Thor's original compressor without any sidechain or weighting +/////////////////////////////////////////////////////////////////////////////////////////////// + +compressor_audio_module::compressor_audio_module() +{ + is_active = false; + srate = 0; + last_generation = 0; +} + +void compressor_audio_module::activate() +{ + is_active = true; + // set all filters and strips + compressor.activate(); + params_changed(); + meter_in = 0.f; + meter_out = 0.f; + clip_in = 0.f; + clip_out = 0.f; +} +void compressor_audio_module::deactivate() +{ + is_active = false; + compressor.deactivate(); +} + +void compressor_audio_module::params_changed() +{ + compressor.set_params(*params[param_attack], *params[param_release], *params[param_threshold], *params[param_ratio], *params[param_knee], *params[param_makeup], *params[param_detection], *params[param_stereo_link], *params[param_bypass], 0.f); +} + +void compressor_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + compressor.set_sample_rate(srate); +} + +uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) +{ + bool bypass = *params[param_bypass] > 0.5f; + numsamples += offset; + if(bypass) { + // everything bypassed + while(offset < numsamples) { + outs[0][offset] = ins[0][offset]; + outs[1][offset] = ins[1][offset]; + ++offset; + } + // displays, too + clip_in = 0.f; + clip_out = 0.f; + meter_in = 0.f; + meter_out = 0.f; + } else { + // process + + clip_in -= std::min(clip_in, numsamples); + clip_out -= std::min(clip_out, numsamples); + + while(offset < numsamples) { + // cycle through samples + float outL = 0.f; + float outR = 0.f; + float inL = ins[0][offset]; + float inR = ins[1][offset]; + // in level + inR *= *params[param_level_in]; + inL *= *params[param_level_in]; + + float leftAC = inL; + float rightAC = inR; + float leftSC = inL; + float rightSC = inR; + + compressor.process(leftAC, rightAC, leftSC, rightSC); + + outL = leftAC; + outR = rightAC; + + // send to output + outs[0][offset] = outL; + outs[1][offset] = outR; + + // clip LED's + if(std::max(fabs(inL), fabs(inR)) > 1.f) { + clip_in = srate >> 3; + } + if(std::max(fabs(outL), fabs(outR)) > 1.f) { + clip_out = srate >> 3; + } + // rise up out meter + meter_in = std::max(fabs(inL), fabs(inR));; + meter_out = std::max(fabs(outL), fabs(outR));; + + // next sample + ++offset; + } // cycle trough samples + } + // draw meters + if(params[param_clip_in] != NULL) { + *params[param_clip_in] = clip_in; + } + if(params[param_clip_out] != NULL) { + *params[param_clip_out] = clip_out; + } + if(params[param_meter_in] != NULL) { + *params[param_meter_in] = meter_in; + } + if(params[param_meter_out] != NULL) { + *params[param_meter_out] = meter_out; + } + // draw strip meter + if(bypass > 0.5f) { + if(params[param_compression] != NULL) { + *params[param_compression] = 1.0f; + } + } else { + if(params[param_compression] != NULL) { + *params[param_compression] = compressor.get_comp_level(); + } + } + // whatever has to be returned x) + return outputs_mask; +} +bool compressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) +{ + if (!is_active) + return false; + return compressor.get_graph(subindex, data, points, context); +} + +bool compressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) +{ + if (!is_active) + return false; + return compressor.get_dot(subindex, x, y, size, context); +} + +bool compressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) +{ + if (!is_active) + return false; + return compressor.get_gridline(subindex, pos, vertical, legend, context); +} + +int compressor_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) +{ + if (!is_active) + return false; + return compressor.get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline); +} + /// Sidecain Compressor by Markus Schmidt /// /// This module splits the signal in a sidechain- and a process signal.