diff --git a/plugins/ladspa_effect/calf/AUTHORS b/plugins/ladspa_effect/calf/AUTHORS index 69803a136..e28cf0bba 100644 --- a/plugins/ladspa_effect/calf/AUTHORS +++ b/plugins/ladspa_effect/calf/AUTHORS @@ -7,8 +7,10 @@ Torben Hohn Markus Schmidt Tom Szilagyi Damien Zammit +Christian Holschuh Additional bugfixes/enhancement patches: David Täht Dave Robillard Alexandre Prokoudine +Carl Hetherington diff --git a/plugins/ladspa_effect/calf/src/audio_fx.cpp b/plugins/ladspa_effect/calf/src/audio_fx.cpp index 54d6b77df..decb839f5 100644 --- a/plugins/ladspa_effect/calf/src/audio_fx.cpp +++ b/plugins/ladspa_effect/calf/src/audio_fx.cpp @@ -351,6 +351,8 @@ tap_distortion::tap_distortion() is_active = false; srate = 0; meter = 0.f; + prev_med = prev_out = 0.f; + drive_old = blend_old = -1.f; } void tap_distortion::activate() @@ -530,3 +532,211 @@ bool simple_lfo::get_dot(float &x, float &y, int &size, cairo_iface *context) co return true; } + +/// Lookahead Limiter by Christian Holschuh and Markus Schmidt + +lookahead_limiter::lookahead_limiter() { + is_active = false; + channels = 2; + id = 0; + buffer_size = 0; + overall_buffer_size = 0; + att = 1.f; + att_max = 1.0; + pos = 0; + delta = 0.f; + _delta = 0.f; + peak = 0.f; + over_s = 0; + over_c = 1.f; + attack = 0.005; + __attack = -1; + use_multi = false; + weight = 1.f; + _sanitize = false; + auto_release = false; + asc_active = false; +} + +void lookahead_limiter::activate() +{ + is_active = true; + pos = 0; + +} + +void lookahead_limiter::set_multi(bool set) { use_multi = set; } + +void lookahead_limiter::deactivate() +{ + is_active = false; +} + +float lookahead_limiter::get_attenuation() +{ + float a = att_max; + att_max = 1.0; + return a; +} + +void lookahead_limiter::set_sample_rate(uint32_t sr) +{ + srate = sr; + // rebuild buffer + overall_buffer_size = (int)(srate * (100.f / 1000.f) * channels) + channels; // buffer size attack rate multiplied by 2 channels + buffer = (float*) calloc(overall_buffer_size, sizeof(float)); + memset(buffer, 0, overall_buffer_size * sizeof(float)); // reset buffer to zero + pos = 0; +} + +void lookahead_limiter::set_params(float l, float a, float r, float w, bool ar, bool d) +{ + limit = l; + attack = a / 1000.f; + release = r / 1000.f; + auto_release = ar; + debug = d; + weight = w; + //if(debug) printf("%.5f\n", release); + if( attack != __attack) { + int bs = (int)(srate * attack * channels); + buffer_size = bs - bs % channels; // buffer size attack rate + __attack = attack; + _sanitize = true; + pos = 0; + } +} + +void lookahead_limiter::process(float &left, float &right, float * multi_buffer) +{ + // PROTIP: harming paying customers enough to make them develop a competing + // product may be considered an example of a less than sound business practice. + + // write left and right to buffer + buffer[pos] = 0.f; + buffer[pos + 1] = 0.f; + if(!_sanitize) { + buffer[pos] = left; + buffer[pos + 1] = right; + } + + // are we using multiband? get the multiband coefficient + float multi_coeff = (use_multi) ? multi_buffer[pos] : 1.f; + //if(debug and pos%10 == 0) printf("%03d: %.5f\n", pos, multi_buffer[pos]); + + // input peak - impact in left or right channel? + peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right); + + // if we have a peak in input over our limit, check if delta to reach is + // more important than actual delta + if(peak > limit * multi_coeff * weight or multi_coeff < 1.f) { + _delta = ((limit * multi_coeff * weight) / peak - att) / (buffer_size / channels - channels); + if(_delta < delta) { + delta = _delta; + } + } + + // switch left and right pointers to output + left = buffer[(pos + channels) % buffer_size]; + right = buffer[(pos + channels + 1) % buffer_size]; + + // check multiband coefficient again for output pointer + multi_coeff = (use_multi) ? multi_buffer[(pos + channels) % buffer_size] : 1.f; + + // output peak - impact in left or right channel? + peak = fabs(left) > fabs(right) ? fabs(left) : fabs(right); + + // output is over the limit? + // then we have to search for new delta. + // the idea is to calculate a delta for every peak and always use the + // lowest. this produces a soft transition between limiting targets without + // passing values above limit + + asc_active = false; + if(peak > limit * multi_coeff * weight) { + // default is to do a release + delta = (1.f - att) / (srate * release); + unsigned int j; + float b_sum = 0.f; + unsigned int b_sum_c = 0; + for(unsigned int i = channels; i < buffer_size; i += channels) { + // iterate over buffer (except input and output pointer positions) + // and search for maximum slope + j = (i + pos + channels) % buffer_size; + float _multi_coeff = (use_multi) ? multi_buffer[j] : 1.f; + float _peak = fabs(buffer[j]) > fabs(buffer[j + 1]) ? fabs(buffer[j]) : fabs(buffer[j + 1]); + // calculate steepness of slope + if(_peak > limit * _multi_coeff * weight) { + _delta = ((limit * _multi_coeff * weight) / _peak - att) / (i / channels); + // if slope is steeper, use it, fucker. + if(_delta < delta) { + delta = _delta; + } + b_sum += _peak; + b_sum_c ++; + } + } + if(auto_release) { + // This is Auto-Smoothness-Control (wink wink, nudge nudge) + // check if releasing to average level of peaks is steeper than + // releasing to 1.f + _delta = ((limit * weight) / (float)(b_sum / b_sum_c) - att) / (srate * release); + asc_active = _delta < delta ? true : false; + delta = _delta < delta ? _delta : delta; + } else { + asc_active = false; + } + } + // change the attenuation level + att += delta; + // ...and calculate outpout from it + left *= att; + right *= att; + + if(_sanitize) { + left = 0.f; + right = 0.f; + } + + // release time seems over + if (att > 1.0f) { + att = 1.0f; + delta = 0.0f; + } + + // security personnel pawing your values + if(att < 0.f) { + // if this happens we're doomed!! + // may happen on manually lowering attack + att = 0.0000000001; + delta = (1.0f - att) / (srate * release); + } + + if(att != 1.f and 1 - att < 0.0000000000001) { + // denormalize att + att = 1.f; + } + + if(delta != 0.f and fabs(delta) < 0.00000000000001) { + // denormalize delta + delta = 0.f; + } + + // post treatment (denormal, limit) + denormal(&left); + denormal(&right); + + left = std::max(left, -limit * multi_coeff * weight); + left = std::min(left, limit * multi_coeff * weight); + right = std::max(right, -limit * multi_coeff * weight); + right = std::min(right, limit * multi_coeff * weight); + + att_max = (att < att_max) ? att : att_max; // store max atten for meter output + + pos = (pos + channels) % buffer_size; + if(pos == 0) _sanitize = false; +} + +bool lookahead_limiter::get_arc() { + return asc_active; +} diff --git a/plugins/ladspa_effect/calf/src/calf/audio_fx.h b/plugins/ladspa_effect/calf/src/calf/audio_fx.h index b9e5012fe..33c3ebfa4 100644 --- a/plugins/ladspa_effect/calf/src/calf/audio_fx.h +++ b/plugins/ladspa_effect/calf/src/calf/audio_fx.h @@ -565,6 +565,48 @@ public: bool get_dot(float &x, float &y, int &size, calf_plugins::cairo_iface *context) const; }; + +/// Lookahead Limiter by Markus Schmidt and Christian Holschuh +class lookahead_limiter { +private: +public: + float limit, attack, release, weight; + float __attack; + uint32_t srate; + float att; + float att_max; + unsigned int pos; + unsigned int buffer_size; + unsigned int overall_buffer_size; + bool is_active; + bool debug; + bool auto_release; + bool asc_active; + float *buffer; + int channels; + float delta; + float _delta; + float peak; + unsigned int over_s; + float over_c; + bool use_multi; + unsigned int id; + bool _sanitize; + static inline void denormal(volatile float *f) { + *f += 1e-18; + *f -= 1e-18; + } + bool get_arc(); + lookahead_limiter(); + void set_multi(bool set); + void process(float &left, float &right, float *multi_buffer); + void set_sample_rate(uint32_t sr); + void set_params(float l, float a, float r, float weight = 1.f, bool ar = false, bool d = false); + float get_attenuation(); + void activate(); + void deactivate(); +}; + #if 0 { to keep editor happy #endif diff --git a/plugins/ladspa_effect/calf/src/calf/biquad.h b/plugins/ladspa_effect/calf/src/calf/biquad.h index 99cf2a40a..a6d5a959c 100644 --- a/plugins/ladspa_effect/calf/src/calf/biquad.h +++ b/plugins/ladspa_effect/calf/src/calf/biquad.h @@ -429,6 +429,11 @@ struct biquad_d2: public biquad_coeffs /// direct II form with two state variables inline T process(T in) { + dsp::sanitize_denormal(in); + dsp::sanitize(in); + dsp::sanitize(w1); + dsp::sanitize(w2); + T tmp = in - w1 * b1 - w2 * b2; T out = tmp * a0 + w1 * a1 + w2 * a2; w2 = w1; diff --git a/plugins/ladspa_effect/calf/src/calf/delay.h b/plugins/ladspa_effect/calf/src/calf/delay.h index 4fd37a56f..7ff6e7bb8 100644 --- a/plugins/ladspa_effect/calf/src/calf/delay.h +++ b/plugins/ladspa_effect/calf/src/calf/delay.h @@ -92,7 +92,7 @@ struct simple_delay { */ template inline void get_interp(U &odata, int delay, float udelay) { -// assert(delay >= 0 && delay < N-1); +// assert(delay >= 0 && delay <= N-1); int ppos = wrap_around(pos + N - delay); int pppos = wrap_around(ppos + N - 1); odata = lerp(data[ppos], data[pppos], udelay); diff --git a/plugins/ladspa_effect/calf/src/calf/ladspa_wrap.h b/plugins/ladspa_effect/calf/src/calf/ladspa_wrap.h deleted file mode 100644 index d94ebcea3..000000000 --- a/plugins/ladspa_effect/calf/src/calf/ladspa_wrap.h +++ /dev/null @@ -1,130 +0,0 @@ -/* Calf DSP Library - * API wrappers for LADSPA/DSSI - * - * Copyright (C) 2007-2008 Krzysztof Foltman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this program; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02111-1307, USA. - */ -#ifndef __CALF_LADSPA_WRAP_H -#define __CALF_LADSPA_WRAP_H - -#if USE_LADSPA - -#include -#include -#if USE_DSSI -#include -#endif -#include "giface.h" -#include "preset.h" - -namespace calf_plugins { - -struct ladspa_plugin_metadata_set; -/// A template implementing plugin_ctl_iface for a given plugin -struct ladspa_instance: public plugin_ctl_iface -{ - audio_module_iface *module; - const plugin_metadata_iface *metadata; - ladspa_plugin_metadata_set *ladspa; - bool activate_flag; - float **ins, **outs, **params; -#if USE_DSSI - dssi_feedback_sender *feedback_sender; -#endif - - ladspa_instance(audio_module_iface *_module, ladspa_plugin_metadata_set *_ladspa, int sample_rate); - virtual const line_graph_iface *get_line_graph_iface() const { return module->get_line_graph_iface(); } - virtual float get_param_value(int param_no); - virtual void set_param_value(int param_no, float value); - virtual bool activate_preset(int bank, int program); - virtual char *configure(const char *key, const char *value); - virtual float get_level(unsigned int port) { return 0.f; } - virtual void execute(int cmd_no) { - module->execute(cmd_no); - } - virtual void send_configures(send_configure_iface *sci) { - module->send_configures(sci); - } - virtual int send_status_updates(send_updates_iface *sui, int last_serial) { return module->send_status_updates(sui, last_serial); } - void run(unsigned long SampleCount); -#if USE_DSSI - /// Utility function: handle MIDI event (only handles a subset in this version) - void process_dssi_event(snd_seq_event_t &event); - void run_synth(unsigned long SampleCount, snd_seq_event_t *Events, unsigned long EventCount); -#endif - virtual const plugin_metadata_iface *get_metadata_iface() const - { - return metadata; - } -}; - -/// Set of metadata produced by LADSPA wrapper for LADSPA-related purposes -struct ladspa_plugin_metadata_set -{ - /// LADSPA descriptor - LADSPA_Descriptor descriptor; - /// LADSPA descriptor for DSSI (uses a different name for the plugin, otherwise same as descriptor) - LADSPA_Descriptor descriptor_for_dssi; -#if USE_DSSI - /// Extended DSSI descriptor (points to descriptor_for_dssi for things like name/label/port info etc.) - DSSI_Descriptor dssi_descriptor; - DSSI_Program_Descriptor dssi_default_program; - - std::vector *presets; - std::vector *preset_descs; -#endif - - int input_count, output_count, param_count; - const plugin_metadata_iface *metadata; - - ladspa_plugin_metadata_set(); - void prepare(const plugin_metadata_iface *md, LADSPA_Handle (*cb_instantiate)(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate)); - void prepare_dssi(); - ~ladspa_plugin_metadata_set(); -}; - -/// A wrapper class for plugin class object (there is only one ladspa_wrapper singleton for many instances of the same plugin) -template -struct ladspa_wrapper -{ - static ladspa_plugin_metadata_set output; - -private: - ladspa_wrapper(const plugin_metadata_iface *md) - { - output.prepare(md, cb_instantiate); - } - -public: - /// LADSPA instantiation function (create a plugin instance) - static LADSPA_Handle cb_instantiate(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate) - { - return new ladspa_instance(new Module, &output, sample_rate); - } - - /// Get a wrapper singleton - used to prevent initialization order problems which were present in older versions - static ladspa_plugin_metadata_set &get() { - static ladspa_wrapper instance(new typename Module::metadata_class); - return instance.output; - } -}; - -}; - -#endif - -#endif diff --git a/plugins/ladspa_effect/calf/src/calf/lv2wrap.h b/plugins/ladspa_effect/calf/src/calf/lv2wrap.h index ed2ccf8d7..f204db6ca 100644 --- a/plugins/ladspa_effect/calf/src/calf/lv2wrap.h +++ b/plugins/ladspa_effect/calf/src/calf/lv2wrap.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -86,17 +86,17 @@ struct lv2_instance: public plugin_ctl_iface, public progress_report_iface void send_configures(send_configure_iface *sci) { module->send_configures(sci); } - void impl_restore(LV2_Persist_Retrieve_Function retrieve, void *callback_data) + void impl_restore(LV2_State_Retrieve_Function retrieve, void *callback_data) { const char *const *vars = module->get_metadata_iface()->get_configure_vars(); if (!vars) return; assert(uri_map); - uint32_t string_type = uri_map->uri_to_id(uri_map, NULL, "http://lv2plug.in/ns/ext/atom#String"); + uint32_t string_type = uri_map->uri_to_id(uri_map->callback_data, NULL, "http://lv2plug.in/ns/ext/atom#String"); assert(string_type); for (unsigned int i = 0; vars[i]; i++) { - const uint32_t key = uri_map->uri_to_id(uri_map, NULL, vars[i]); + const uint32_t key = uri_map->uri_to_id(uri_map->callback_data, NULL, vars[i]); size_t len = 0; uint32_t type = 0; uint32_t flags = 0; @@ -182,7 +182,7 @@ struct lv2_wrapper typedef lv2_instance instance; static LV2_Descriptor descriptor; static LV2_Calf_Descriptor calf_descriptor; - static LV2_Persist persist; + static LV2_State_Interface state_iface; std::string uri; lv2_wrapper() @@ -197,8 +197,8 @@ struct lv2_wrapper descriptor.deactivate = cb_deactivate; descriptor.cleanup = cb_cleanup; descriptor.extension_data = cb_ext_data; - persist.save = cb_persist_save; - persist.restore = cb_persist_restore; + state_iface.save = cb_state_save; + state_iface.restore = cb_state_restore; calf_descriptor.get_pci = cb_get_pci; } @@ -294,16 +294,18 @@ struct lv2_wrapper { if (!strcmp(URI, "http://foltman.com/ns/calf-plugin-instance")) return &calf_descriptor; - if (!strcmp(URI, LV2_PERSIST_URI)) - return &persist; + if (!strcmp(URI, LV2_STATE_INTERFACE_URI)) + return &state_iface; return NULL; } - static void cb_persist_save(LV2_Handle Instance, LV2_Persist_Store_Function store, void *callback_data) + static void cb_state_save(LV2_Handle Instance, + LV2_State_Store_Function store, LV2_State_Handle handle, + uint32_t flags, const LV2_Feature *const * features) { instance *const inst = (instance *)Instance; struct store_state: public send_configure_iface { - LV2_Persist_Store_Function store; + LV2_State_Store_Function store; void *callback_data; instance *inst; uint32_t string_data_type; @@ -311,24 +313,26 @@ struct lv2_wrapper virtual void send_configure(const char *key, const char *value) { (*store)(callback_data, - inst->uri_map->uri_to_id(inst->uri_map, NULL, key), + inst->uri_map->uri_to_id(inst->uri_map->callback_data, NULL, key), value, strlen(value) + 1, string_data_type, - LV2_PERSIST_IS_POD|LV2_PERSIST_IS_PORTABLE); + LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE); } }; - // A host that supports Persist MUST support URI-Map as well. + // A host that supports State MUST support URI-Map as well. assert(inst->uri_map); store_state s; s.store = store; - s.callback_data = callback_data; + s.callback_data = handle; s.inst = inst; - s.string_data_type = inst->uri_map->uri_to_id(inst->uri_map, NULL, "http://lv2plug.in/ns/ext/atom#String"); + s.string_data_type = inst->uri_map->uri_to_id(inst->uri_map->callback_data, NULL, "http://lv2plug.in/ns/ext/atom#String"); inst->send_configures(&s); } - static void cb_persist_restore(LV2_Handle Instance, LV2_Persist_Retrieve_Function retrieve, void *callback_data) + static void cb_state_restore(LV2_Handle Instance, + LV2_State_Retrieve_Function retrieve, LV2_State_Handle callback_data, + uint32_t flags, const LV2_Feature *const * features) { instance *const inst = (instance *)Instance; inst->impl_restore(retrieve, callback_data); diff --git a/plugins/ladspa_effect/calf/src/calf/metadata.h b/plugins/ladspa_effect/calf/src/calf/metadata.h index d49594e8e..5ffcea625 100644 --- a/plugins/ladspa_effect/calf/src/calf/metadata.h +++ b/plugins/ladspa_effect/calf/src/calf/metadata.h @@ -184,14 +184,15 @@ struct multibandcompressor_metadata: public plugin_metadata PLUGIN_NAME_ID_LABEL("sidechaingate", "sidechaingate", "Sidechain Gate") }; +/// Markus's limiter - metadata +struct limiter_metadata: public plugin_metadata +{ + 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, + STEREO_VU_METER_PARAMS, + param_limit, param_attack, param_release, + param_att, + param_asc, param_asc_led, + param_count }; + PLUGIN_NAME_ID_LABEL("limiter", "limiter", "Limiter") +}; + +/// Markus's multibandlimiter - metadata +struct multibandlimiter_metadata: public plugin_metadata +{ + 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, + STEREO_VU_METER_PARAMS, + param_freq0, param_freq1, param_freq2, + param_sep0, param_sep1, param_sep2, + param_q0, param_q1, param_q2, + param_mode, + param_limit, param_attack, param_release, param_minrel, + param_att0, param_att1, param_att2, param_att3, + param_weight0, param_weight1, param_weight2, param_weight3, + param_release0, param_release1, param_release2, param_release3, + param_solo0, param_solo1, param_solo2, param_solo3, + param_effrelease0, param_effrelease1, param_effrelease2, param_effrelease3, + param_asc, param_asc_led, + param_count }; + PLUGIN_NAME_ID_LABEL("multiband_limiter", "multibandlimiter", "Multiband Limiter") +}; + /// Markus's 5-band EQ - metadata struct equalizer5band_metadata: public plugin_metadata { @@ -322,6 +357,31 @@ struct bassenhancer_metadata: public plugin_metadata param_freq, param_listen, param_count }; PLUGIN_NAME_ID_LABEL("bassenhancer", "bassenhancer", "Bass Enhancer") }; +/// Markus's Mono Module - metadata +struct stereo_metadata: public plugin_metadata +{ + enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true }; + enum { param_bypass, param_level_in, param_level_out, + STEREO_VU_METER_PARAMS, param_balance_in, param_balance_out, param_softclip, + param_mute_l, param_mute_r, param_phase_l, param_phase_r, + param_mode, param_slev, param_sbal, param_mlev, param_mpan, + param_widener, param_delay, + param_meter_phase, + param_count }; + PLUGIN_NAME_ID_LABEL("stereo", "stereo", "Stereo Tools") +}; +/// Markus's Mono Module - metadata +struct mono_metadata: public plugin_metadata +{ + enum { in_count = 1, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true }; + enum { param_bypass, param_level_in, param_level_out, + param_meter_in, param_meter_outL, param_meter_outR, param_clip_in,param_clip_outL, param_clip_outR, + param_balance_out, param_softclip, + param_mute_l, param_mute_r, param_phase_l, param_phase_r, + param_delay, + param_count }; + PLUGIN_NAME_ID_LABEL("mono", "mono", "Mono Input") +}; /// 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 diff --git a/plugins/ladspa_effect/calf/src/calf/modulelist.h b/plugins/ladspa_effect/calf/src/calf/modulelist.h index 85dead895..3e6d6f7f3 100644 --- a/plugins/ladspa_effect/calf/src/calf/modulelist.h +++ b/plugins/ladspa_effect/calf/src/calf/modulelist.h @@ -15,6 +15,8 @@ PER_MODULE_ITEM(deesser, false, "deesser") PER_MODULE_ITEM(gate, false, "gate") PER_MODULE_ITEM(sidechaingate, false, "sidechaingate") + PER_MODULE_ITEM(limiter, false, "limiter") + PER_MODULE_ITEM(multibandlimiter, false, "multibandlimiter") PER_MODULE_ITEM(pulsator, false, "pulsator") PER_MODULE_ITEM(equalizer5band, false, "eq5") PER_MODULE_ITEM(equalizer8band, false, "eq8") @@ -22,6 +24,8 @@ PER_MODULE_ITEM(saturator, false, "saturator") PER_MODULE_ITEM(exciter, false, "exciter") PER_MODULE_ITEM(bassenhancer, false, "bassenhancer") + PER_MODULE_ITEM(mono, false, "mono") + PER_MODULE_ITEM(stereo, false, "stereo") #ifdef ENABLE_EXPERIMENTAL PER_MODULE_ITEM(fluidsynth, true, "fluidsynth") PER_MODULE_ITEM(wavetable, true, "wavetable") diff --git a/plugins/ladspa_effect/calf/src/calf/modules.h b/plugins/ladspa_effect/calf/src/calf/modules.h index 19d67e2ca..fb9ba7790 100644 --- a/plugins/ladspa_effect/calf/src/calf/modules.h +++ b/plugins/ladspa_effect/calf/src/calf/modules.h @@ -100,9 +100,10 @@ public: , inertia_resonance(dsp::exponential_ramp(128), 20) , inertia_gain(dsp::exponential_ramp(128), 1.0) , timer(128) - { - is_active = false; - } + , is_active(false) + , last_generation(-1) + , last_calculated_generation(-2) + {} void calculate_filter() { @@ -195,6 +196,7 @@ public: : filter_module_with_inertia(ins, outs, params) { last_generation = 0; + old_mode = old_resonance = old_cutoff = -1; } void params_changed() { @@ -239,6 +241,63 @@ private: void adjust_gain_according_to_filter_mode(int velocity); }; + +#define MATH_E 2.718281828 +class mono_audio_module: + public audio_module +{ + typedef mono_audio_module AM; + uint32_t srate; + bool active; + + uint32_t clip_in, clip_outL, clip_outR; + float meter_in, meter_outL, meter_outR; + + float * buffer; + unsigned int pos; + unsigned int buffer_size; + + void softclip(float &s) { + int ph = s / fabs(s); + s = s > 0.63 ? ((0.63 + 0.36) * ph * (1 - pow(MATH_E, (1.f / 3) * (0.63 + s * ph)))) : s; + } +public: + mono_audio_module(); + void params_changed(); + void activate(); + void set_sample_rate(uint32_t sr); + void deactivate(); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); }; +class stereo_audio_module: + public audio_module +{ + typedef stereo_audio_module AM; + float LL, LR, RL, RR; + uint32_t srate; + bool active; + + uint32_t clip_inL, clip_inR, clip_outL, clip_outR; + float meter_inL, meter_inR, meter_outL, meter_outR, meter_phase; + + float * buffer; + unsigned int pos; + unsigned int buffer_size; + + void softclip(float &s) { + int ph = s / fabs(s); + s = s > 0.63 ? ((0.63 + 0.36) * ph * (1 - pow(MATH_E, (1.f / 3) * (0.63 + s * ph)))) : s; + } +public: + stereo_audio_module(); + void params_changed(); + void activate(); + void set_sample_rate(uint32_t sr); + void deactivate(); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); +}; + + +}; #endif diff --git a/plugins/ladspa_effect/calf/src/calf/modules_comp.h b/plugins/ladspa_effect/calf/src/calf/modules_comp.h index 9f8923a60..538e18bde 100644 --- a/plugins/ladspa_effect/calf/src/calf/modules_comp.h +++ b/plugins/ladspa_effect/calf/src/calf/modules_comp.h @@ -165,12 +165,14 @@ class multibandcompressor_audio_module: public audio_module lpL0, lpR0, lpL1, lpR1, lpL2, lpR2, hpL0, hpR0, hpL1, hpR1, hpL2, hpR2; + dsp::biquad_d2 lpL[strips - 1][3], lpR[strips - 1][3], hpL[strips - 1][3], hpR[strips - 1][3]; float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1]; + int mode, mode_old; public: uint32_t srate; bool is_active; diff --git a/plugins/ladspa_effect/calf/src/calf/modules_limit.h b/plugins/ladspa_effect/calf/src/calf/modules_limit.h new file mode 100644 index 000000000..74bfe197c --- /dev/null +++ b/plugins/ladspa_effect/calf/src/calf/modules_limit.h @@ -0,0 +1,92 @@ +/* Calf DSP plugin pack + * Limiter related plugins + * + * Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02111-1307, USA. + */ +#ifndef CALF_MODULES_LIMIT_H +#define CALF_MODULES_LIMIT_H + +#include +#include +#include "biquad.h" +#include "inertia.h" +#include "audio_fx.h" +#include "giface.h" +#include "metadata.h" +#include "plugin_tools.h" + +namespace calf_plugins { + +/// Limiter by Markus Schmidt and Christian Holschuh +class limiter_audio_module: public audio_module, public line_graph_iface { +private: + typedef limiter_audio_module AM; + uint32_t clip_inL, clip_inR, clip_outL, clip_outR, asc_led; + int mode, mode_old; + float meter_inL, meter_inR, meter_outL, meter_outR; + dsp::lookahead_limiter limiter; +public: + uint32_t srate; + bool is_active; + limiter_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); +}; + +/// Multiband Limiter by Markus Schmidt and Christian Holschuh +class multibandlimiter_audio_module: public audio_module, public line_graph_iface { +private: + typedef multibandlimiter_audio_module AM; + static const int strips = 4; + uint32_t clip_inL, clip_inR, clip_outL, clip_outR, asc_led; + int mode, mode_old; + bool solo[strips]; + bool no_solo; + float meter_inL, meter_inR, meter_outL, meter_outR; + dsp::lookahead_limiter strip[strips]; + dsp::lookahead_limiter broadband; + dsp::biquad_d2 lpL[strips - 1][3], lpR[strips - 1][3], hpL[strips - 1][3], hpR[strips - 1][3]; + float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1]; + unsigned int pos; + unsigned int buffer_size; + unsigned int overall_buffer_size; + float __attack; + float *buffer; + int channels; + float striprel[strips]; + float weight[strips]; + bool _sanitize; +public: + uint32_t srate; + bool is_active; + multibandlimiter_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); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; +}; + +}; + +#endif diff --git a/plugins/ladspa_effect/calf/src/calf/osctlnet.h b/plugins/ladspa_effect/calf/src/calf/osctlnet.h deleted file mode 100644 index df4c9c7ab..000000000 --- a/plugins/ladspa_effect/calf/src/calf/osctlnet.h +++ /dev/null @@ -1,2 +0,0 @@ -#include - diff --git a/plugins/ladspa_effect/calf/src/calf/primitives.h b/plugins/ladspa_effect/calf/src/calf/primitives.h index efc820feb..cbc7758e2 100644 --- a/plugins/ladspa_effect/calf/src/calf/primitives.h +++ b/plugins/ladspa_effect/calf/src/calf/primitives.h @@ -407,6 +407,16 @@ inline void sanitize(float &value) value = 0.f; } +/** + * Force already-denormal float value to zero + */ +inline void sanitize_denormal(float& value) +{ + if (((*(unsigned int *) &value) & 0x7f800000) == 0) { + value = 0; + } +} + /** * Force "small enough" double value to zero */ diff --git a/plugins/ladspa_effect/calf/src/giface.cpp b/plugins/ladspa_effect/calf/src/giface.cpp index 9d2f3109e..5f28e7aa0 100644 --- a/plugins/ladspa_effect/calf/src/giface.cpp +++ b/plugins/ladspa_effect/calf/src/giface.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include using namespace std; @@ -385,106 +384,6 @@ uint32_t mod_matrix_metadata::get_table_rows() const /////////////////////////////////////////////////////////////////////////////////////// #if USE_EXEC_GUI -struct osc_cairo_control: public cairo_iface -{ - osctl::osc_inline_typed_strstream &os; - - osc_cairo_control(osctl::osc_inline_typed_strstream &_os) : os(_os) {} - virtual void set_source_rgba(float r, float g, float b, float a = 1.f) - { - os << (uint32_t)LGI_SET_RGBA << r << g << b << a; - } - virtual void set_line_width(float width) - { - os << (uint32_t)LGI_SET_WIDTH << width; - } -}; - -static void serialize_graphs(osctl::osc_inline_typed_strstream &os, const line_graph_iface *graph, std::vector ¶ms) -{ - osc_cairo_control cairoctl(os); - for (size_t i = 0; i < params.size(); i++) - { - int index = params[i]; - os << (uint32_t)LGI_GRAPH; - os << (uint32_t)index; - for (int j = 0; ; j++) - { - float data[128]; - if (graph->get_graph(index, j, data, 128, &cairoctl)) - { - os << (uint32_t)LGI_SUBGRAPH; - os << (uint32_t)128; - for (int p = 0; p < 128; p++) - os << data[p]; - } - else - break; - } - for (int j = 0; ; j++) - { - float x, y; - int size = 3; - if (graph->get_dot(index, j, x, y, size, &cairoctl)) - os << (uint32_t)LGI_DOT << x << y << (uint32_t)size; - else - break; - } - for (int j = 0; ; j++) - { - float pos = 0; - bool vertical = false; - string legend; - if (graph->get_gridline(index, j, pos, vertical, legend, &cairoctl)) - os << (uint32_t)LGI_LEGEND << pos << (uint32_t)(vertical ? 1 : 0) << legend; - else - break; - } - os << (uint32_t)LGI_END_ITEM; - } - os << (uint32_t)LGI_END; -} - -calf_plugins::dssi_feedback_sender::dssi_feedback_sender(const char *URI, const line_graph_iface *_graph) -{ - graph = _graph; - is_client_shared = false; - client = new osctl::osc_client; - client->bind("0.0.0.0", 0); - client->set_url(URI); -} - -calf_plugins::dssi_feedback_sender::dssi_feedback_sender(osctl::osc_client *_client, const line_graph_iface *_graph) -{ - graph = _graph; - client = _client; - is_client_shared = true; -} - -void calf_plugins::dssi_feedback_sender::add_graphs(const calf_plugins::parameter_properties *props, int num_params) -{ - for (int i = 0; i < num_params; i++) - { - if (props[i].flags & PF_PROP_GRAPH) - indices.push_back(i); - } -} - -void calf_plugins::dssi_feedback_sender::update() -{ - if (graph) - { - osctl::osc_inline_typed_strstream os; - serialize_graphs(os, graph, indices); - client->send("/lineGraph", os); - } -} - -calf_plugins::dssi_feedback_sender::~dssi_feedback_sender() -{ - if (!is_client_shared) - delete client; -} table_via_configure::table_via_configure() { diff --git a/plugins/ladspa_effect/calf/src/metadata.cpp b/plugins/ladspa_effect/calf/src/metadata.cpp index f376d7779..b7172fb81 100644 --- a/plugins/ladspa_effect/calf/src/metadata.cpp +++ b/plugins/ladspa_effect/calf/src/metadata.cpp @@ -297,6 +297,7 @@ CALF_PLUGIN_INFO(sidechaincompressor) = { 0x8517, "Sidechaincompressor", "Calf S CALF_PORT_NAMES(multibandcompressor) = {"In L", "In R", "Out L", "Out R"}; const char *multibandcompressor_detection_names[] = { "RMS", "Peak" }; +const char *multibandcompressor_filter_choices[] = { "12dB", "36dB"}; CALF_PORT_PROPS(multibandcompressor) = { { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, @@ -311,7 +312,7 @@ CALF_PORT_PROPS(multibandcompressor) = { { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB-OutL" }, { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" }, - { 100, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq0", "Split 1/2" }, + { 120, 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" }, @@ -319,61 +320,62 @@ CALF_PORT_PROPS(multibandcompressor) = { { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep1", "S2" }, { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep2", "S3" }, - { 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q1" }, - { 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q2" }, - { 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q3" }, + { 0.7762471166286917, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q1" }, + { 0.7762471166286917, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q2" }, + { 0.7762471166286917, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q3" }, + { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_filter_choices, "mode", "Filter Mode" }, - { 0.0625, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold0", "Threshold 1" }, - { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio0", "Ratio 1" }, - { 50, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack0", "Attack 1" }, - { 100, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release0", "Release 1" }, + { 0.25, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold0", "Threshold 1" }, + { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio0", "Ratio 1" }, + { 150, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack0", "Attack 1" }, + { 300, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release0", "Release 1" }, { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup0", "Makeup 1" }, { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee0", "Knee 1" }, - { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection0", "Detection 1" }, - { 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 1" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection0", "Detection 1" }, + { 1, 0.0625, 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 1" }, { 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" }, { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass0", "Bypass 1" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute0", "Mute 1" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "solo0", "Solo 1" }, - { 0.03125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold1", "Threshold 2" }, - { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio1", "Ratio 2" }, - { 25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack1", "Attack 2" }, - { 50, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release1", "Release 2" }, + { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold1", "Threshold 2" }, + { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio1", "Ratio 2" }, + { 100, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack1", "Attack 2" }, + { 200, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release1", "Release 2" }, { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup1", "Makeup 2" }, { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee1", "Knee 2" }, - { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection1", "Detection 2" }, - { 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 2" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection1", "Detection 2" }, + { 1, 0.0625, 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 2" }, { 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 2" }, { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass1", "Bypass 2" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute1", "Mute 2" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "solo1", "Solo 2" }, - { 0.015625, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold2", "Threshold 3" }, - { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio2", "Ratio 3" }, - { 12.5, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack2", "Attack 3" }, - { 25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release2", "Release 3" }, + { 0.0625, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold2", "Threshold 3" }, + { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio2", "Ratio 3" }, + { 50, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack2", "Attack 3" }, + { 100, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release2", "Release 3" }, { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup2", "Makeup 3" }, { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee2", "Knee 3" }, - { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection2", "Detection 3" }, - { 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 3" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection2", "Detection 3" }, + { 1, 0.0625, 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 3" }, { 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 3" }, { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass2", "Bypass 3" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute2", "Mute 3" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "solo2", "Solo 3" }, - { 0.0078125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold3", "Threshold 4" }, - { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio3", "Ratio 4" }, - { 6.25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack3", "Attack 4" }, - { 12.5, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release3", "Release 4" }, + { 0.03125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold3", "Threshold 4" }, + { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio3", "Ratio 4" }, + { 25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack3", "Attack 4" }, + { 50, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release3", "Release 4" }, { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup3", "Makeup 4" }, { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee3", "Knee 4" }, - { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection3", "Detection 4" }, - { 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 4" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection3", "Detection 4" }, + { 1, 0.0625, 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 4" }, { 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 4" }, { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass3", "Bypass 4" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute3", "Mute 4" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "solo3", "Solo 4" }, {} }; @@ -390,7 +392,7 @@ const char *deesser_mode_names[] = { "Wide", "Split" }; CALF_PORT_PROPS(deesser) = { { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, { 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, "detected", "Detected" }, - { 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", "Gain Reduction" }, + { 0, 0.0625, 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", "Gain Reduction" }, { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "detected_led", "Active" }, { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "Out" }, { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, deesser_detection_names, "detection", "Detection" }, @@ -489,6 +491,108 @@ CALF_PORT_PROPS(sidechaingate) = { CALF_PLUGIN_INFO(sidechaingate) = { 0x8504, "Sidechaingate", "Calf Sidechain Gate", "Markus Schmidt / Damien Zammit / Thor Harald Johansen", calf_plugins::calf_copyright_info, "ExpanderPlugin" }; +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(limiter) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(limiter) = { + { 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_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inL", "0dB-InL" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inR", "0dB-InR" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB-OutL" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" }, + + { 1, 0.0625, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "limit", "Limit" }, + { 5, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Lookahead" }, + { 50, 1, 1000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" }, + + { 1, 0.125, 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, "att", "Attenuation" }, + + { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "asc", "ASC" }, + + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "asc_led", "asc active" }, + + {} +}; + +CALF_PLUGIN_INFO(limiter) = { 0x8521, "Limiter", "Calf Limiter", "Christian Holschuh / Markus Schmidt", calf_plugins::calf_copyright_info, "LimiterPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(multibandlimiter) = {"In L", "In R", "Out L", "Out R"}; +const char *multibandlimiter_filter_choices[] = { "12dB", "36dB"}; + +CALF_PORT_PROPS(multibandlimiter) = { + { 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_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inL", "0dB-InL" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inR", "0dB-InR" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB-OutL" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" }, + + { 100, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq0", "Split 1/2" }, + { 750, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq1", "Split 2/3" }, + { 5000, 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", "S1" }, + { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep1", "S2" }, + { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep2", "S3" }, + + { 0.7762471166286917, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q1" }, + { 0.7762471166286917, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q2" }, + { 0.7762471166286917, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q3" }, + + { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandlimiter_filter_choices, "mode", "Filter Mode" }, + + { 1, 0.0625, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "limit", "Limit" }, + { 4, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Lookahead" }, + { 30, 1, 1000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "minrel", "Min Release" }, + + { 1, 0.125, 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, "att0", "Low" }, + { 1, 0.125, 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, "att1", "LMid" }, + { 1, 0.125, 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, "att2", "HMid" }, + { 1, 0.125, 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, "att3", "Hi" }, + + { 0.2f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "weight0", "Weight 1" }, + { -0.2f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "weight1", "Weight 2" }, + { 0.2f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "weight2", "Weight 3" }, + { -0.2f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "weight3", "Weight 4" }, + + { 0.5f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "release0", "Release 1" }, + { 0.2f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "release1", "Release 2" }, + { -0.2f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "release2", "Release 3" }, + { -0.5f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "release3", "Release 4" }, + + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "solo0", "Solo 1" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "solo1", "Solo 2" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "solo2", "Solo 3" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "solo3", "Solo 4" }, + + { 1, 0.f, 1000, 0, PF_FLOAT | PF_UNIT_MSEC | PF_PROP_OUTPUT, NULL, "effrelease0", "Effectively Release 1" }, + { 1, 0.f, 1000, 0, PF_FLOAT | PF_UNIT_MSEC | PF_PROP_OUTPUT, NULL, "effrelease1", "Effectively Release 2" }, + { 1, 0.f, 1000, 0, PF_FLOAT | PF_UNIT_MSEC | PF_PROP_OUTPUT, NULL, "effrelease2", "Effectively Release 3" }, + { 1, 0.f, 1000, 0, PF_FLOAT | PF_UNIT_MSEC | PF_PROP_OUTPUT, NULL, "effrelease3", "Effectively Release 4" }, + + { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "asc", "ASC" }, + + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "asc_led", "asc active" }, + + {} +}; + +CALF_PLUGIN_INFO(multibandlimiter) = { 0x8520, "Multibandlimiter", "Calf Multiband Limiter", "Markus Schmidt / Christian Holschuh", calf_plugins::calf_copyright_info, "LimiterPlugin" }; //////////////////////////////////////////////////////////////////////////// // A few macros to make @@ -690,6 +794,79 @@ CALF_PORT_PROPS(bassenhancer) = { CALF_PLUGIN_INFO(bassenhancer) = { 0x8532, "BassEnhancer", "Calf Bass Enhancer", "Markus Schmidt / Krzysztof Foltman", calf_plugins::calf_copyright_info, "DistortionPlugin" }; +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(mono) = {"In", "Out L", "Out R"}; +CALF_PORT_PROPS(mono) = { + { 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_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_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_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB-In" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB-OutL" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" }, + + { 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "balance_out", "Balance" }, + + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "softclip", "Softclip" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mutel", "Mute L" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "muter", "Mute R" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "phasel", "Phase L" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "phaser", "Phase R" }, + + { 0.f, -20.f, 20.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "delay", "Delay" }, + {} +}; + +CALF_PLUGIN_INFO(mono) = { 0x8589, "MonoInput", "Calf Mono Input", "Markus Schmidt", calf_plugins::calf_copyright_info, "Utility" }; + + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(stereo) = {"In L", "In R", "Out L", "Out R"}; +const char *stereo_mode_names[] = { "LR ▸ LR (Stereo Default)", "LR ▸ MS (Stereo to Mid-Side)", "MS ▸ LR (Mid-Side to Stereo)", "LR ▸ LL (Mono Left Channel)", "LR ▸ RR (Mono Right Channel)", "LR ▸ L+R (Mono Sum L+R)", "LR ▸ RL (Stereo Flip Channels)" }; +CALF_PORT_PROPS(stereo) = { + { 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_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inL", "0dB-InL" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inR", "0dB-InR" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB-OutL" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" }, + + { 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "balance_in", "Balance In" }, + { 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "balance_out", "Balance Out" }, + + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "softclip", "Softclip" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mutel", "Mute L" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "muter", "Mute R" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "phasel", "Phase L" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "phaser", "Phase R" }, + + { 0, 0, 6, 0, PF_ENUM | PF_CTL_COMBO, stereo_mode_names, "mode", "Mode" }, + + { 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "slev", "S Level" }, + { 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sbal", "S Balance" }, + { 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "mlev", "M Level" }, + { 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "mpan", "M Panorama" }, + + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "widener", "Widener" }, + { 0.f, -20.f, 20.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "delay", "Delay" }, + + { 0.f, 0.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_COEF | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_phase", "Phase Correlation" }, + + {} +}; + +CALF_PLUGIN_INFO(stereo) = { 0x8588, "StereoTools", "Calf Stereo Tools", "Markus Schmidt", calf_plugins::calf_copyright_info, "Utility" }; + + //////////////////////////////////////////////////////////////////////////// CALF_PORT_NAMES(monosynth) = { diff --git a/plugins/ladspa_effect/calf/src/modules.cpp b/plugins/ladspa_effect/calf/src/modules.cpp index c10e0e048..ba06f0201 100644 --- a/plugins/ladspa_effect/calf/src/modules.cpp +++ b/plugins/ladspa_effect/calf/src/modules.cpp @@ -445,3 +445,353 @@ bool filterclavier_audio_module::get_graph(int index, int subindex, float *data, return false; } + +/////////////////////////////////////////////////////////////////////////////////////////////// + +stereo_audio_module::stereo_audio_module() { + active = false; + 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 stereo_audio_module::activate() { + active = true; +} + +void stereo_audio_module::deactivate() { + active = false; +} + +void stereo_audio_module::params_changed() { + float slev = 2 * *params[param_slev]; // stereo level ( -2 -> 2 ) + float sbal = 1 + *params[param_sbal]; // stereo balance ( 0 -> 2 ) + float mlev = 2 * *params[param_mlev]; // mono level ( -2 -> 2 ) + float mpan = 1 + *params[param_mpan]; // mono pan ( 0 -> 2 ) + + switch((int)*params[param_mode]) + { + case 0: + default: + //LR->LR + LL = (mlev * (2.f - mpan) + slev * (2.f - sbal)); + LR = (mlev * mpan - slev * sbal); + RL = (mlev * (2.f - mpan) - slev * (2.f - sbal)); + RR = (mlev * mpan + slev * sbal); + break; + case 1: + //LR->MS + LL = (2.f - mpan) * (2.f - sbal); + LR = mpan * (2.f - sbal) * -1; + RL = (2.f - mpan) * sbal; + RR = mpan * sbal; + break; + case 2: + //MS->LR + LL = mlev * (2.f - sbal); + LR = mlev * mpan; + RL = slev * (2.f - sbal); + RR = slev * sbal * -1; + break; + case 3: + case 4: + case 5: + case 6: + //LR->LL + LL = 0.f; + LR = 0.f; + RL = 0.f; + RR = 0.f; + break; + } +} + +uint32_t stereo_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { + for(uint32_t i = offset; i < offset + numsamples; i++) { + if(*params[param_bypass] > 0.5) { + outs[0][i] = ins[0][i]; + outs[1][i] = ins[1][i]; + 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 { + // 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 = 0.f; + meter_inR = 0.f; + meter_outL = 0.f; + meter_outR = 0.f; + + float L = ins[0][i]; + float R = ins[1][i]; + + // levels in + L *= *params[param_level_in]; + R *= *params[param_level_in]; + + // balance in + L *= (1.f - std::max(0.f, *params[param_balance_in])); + R *= (1.f + std::min(0.f, *params[param_balance_in])); + + // copy / flip / mono ... + switch((int)*params[param_mode]) + { + case 0: + default: + // LR > LR + break; + case 1: + // LR > MS + break; + case 2: + // MS > LR + break; + case 3: + // LR > LL + R = L; + break; + case 4: + // LR > RR + L = R; + break; + case 5: + // LR > L+R + L = (L + R) / 2; + R = L; + break; + case 6: + // LR > RL + float tmp = L; + L = R; + R = tmp; + break; + } + + // softclip + if(*params[param_softclip]) { + int ph; + ph = L / fabs(L); + L = L > 0.63 ? ph * (0.63 + 0.36 * (1 - pow(MATH_E, (1.f / 3) * (0.63 + L * ph)))) : L; + ph = R / fabs(R); + R = R > 0.63 ? ph * (0.63 + 0.36 * (1 - pow(MATH_E, (1.f / 3) * (0.63 + R * ph)))) : R; + } + + // GUI stuff + if(L > meter_inL) meter_inL = L; + if(R > meter_inR) meter_inR = R; + if(L > 1.f) clip_inL = srate >> 3; + if(R > 1.f) clip_inR = srate >> 3; + + // mute + L *= (1 - floor(*params[param_mute_l] + 0.5)); + R *= (1 - floor(*params[param_mute_r] + 0.5)); + + // phase + L *= (2 * (1 - floor(*params[param_phase_l] + 0.5))) - 1; + R *= (2 * (1 - floor(*params[param_phase_r] + 0.5))) - 1; + + // LR/MS + L += LL*L + RL*R; + R += RR*R + LR*L; + + // widener + L += *params[param_widener] * R * -1; + R += *params[param_widener] * L * -1; + + // delay + buffer[pos] = L; + buffer[pos + 1] = R; + + int nbuf = srate * (fabs(*params[param_delay]) / 1000.f); + nbuf -= nbuf % 2; + if(*params[param_delay] > 0.f) { + R = buffer[(pos - (int)nbuf + 1 + buffer_size) % buffer_size]; + } else if (*params[param_delay] < 0.f) { + L = buffer[(pos - (int)nbuf + buffer_size) % buffer_size]; + } + + pos = (pos + 2) % buffer_size; + + // balance out + L *= (1.f - std::max(0.f, *params[param_balance_out])); + R *= (1.f + std::min(0.f, *params[param_balance_out])); + + // level + L *= *params[param_level_out]; + R *= *params[param_level_out]; + + //output + outs[0][i] = L; + outs[1][i] = R; + + // clip LED's + if(L > 1.f) clip_outL = srate >> 3; + if(R > 1.f) clip_outR = srate >> 3; + if(L > meter_outL) meter_outL = L; + if(R > meter_outR) meter_outR = R; + + // phase meter + if(fabs(L) > 0.001 and fabs(R) > 0.001) { + meter_phase = fabs(fabs(L+R) > 0.000000001 ? sin(fabs((L-R)/(L+R))) : 0.f); + } else { + meter_phase = 0.f; + } + } + } + // draw meters + SET_IF_CONNECTED(clip_inL); + SET_IF_CONNECTED(clip_inR); + SET_IF_CONNECTED(clip_outL); + SET_IF_CONNECTED(clip_outR); + SET_IF_CONNECTED(meter_inL); + SET_IF_CONNECTED(meter_inR); + SET_IF_CONNECTED(meter_outL); + SET_IF_CONNECTED(meter_outR); + SET_IF_CONNECTED(meter_phase); + return outputs_mask; +} + +void stereo_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + // rebuild buffer + buffer_size = (int)(srate * 0.05 * 2.f); // buffer size attack rate multiplied by 2 channels + buffer = (float*) calloc(buffer_size, sizeof(float)); + memset(buffer, 0, buffer_size * sizeof(float)); // reset buffer to zero + pos = 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +mono_audio_module::mono_audio_module() { + active = false; + clip_in = 0.f; + clip_outL = 0.f; + clip_outR = 0.f; + meter_in = 0.f; + meter_outL = 0.f; + meter_outR = 0.f; +} + +void mono_audio_module::activate() { + active = true; +} + +void mono_audio_module::deactivate() { + active = false; +} + +void mono_audio_module::params_changed() { + +} + +uint32_t mono_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { + for(uint32_t i = offset; i < offset + numsamples; i++) { + if(*params[param_bypass] > 0.5) { + outs[0][i] = ins[0][i]; + outs[1][i] = ins[0][i]; + clip_in = 0.f; + clip_outL = 0.f; + clip_outR = 0.f; + meter_in = 0.f; + meter_outL = 0.f; + meter_outR = 0.f; + } else { + // let meters fall a bit + clip_in -= std::min(clip_in, numsamples); + clip_outL -= std::min(clip_outL, numsamples); + clip_outR -= std::min(clip_outR, numsamples); + meter_in = 0.f; + meter_outL = 0.f; + meter_outR = 0.f; + + float L = ins[0][i]; + + // levels in + L *= *params[param_level_in]; + + // softclip + if(*params[param_softclip]) { + int ph = L / fabs(L); + L = L > 0.63 ? ph * (0.63 + 0.36 * (1 - pow(MATH_E, (1.f / 3) * (0.63 + L * ph)))) : L; + } + + // GUI stuff + if(L > meter_in) meter_in = L; + if(L > 1.f) clip_in = srate >> 3; + + float R = L; + + // mute + L *= (1 - floor(*params[param_mute_l] + 0.5)); + R *= (1 - floor(*params[param_mute_r] + 0.5)); + + // phase + L *= (2 * (1 - floor(*params[param_phase_l] + 0.5))) - 1; + R *= (2 * (1 - floor(*params[param_phase_r] + 0.5))) - 1; + + // delay + buffer[pos] = L; + buffer[pos + 1] = R; + + int nbuf = srate * (fabs(*params[param_delay]) / 1000.f); + nbuf -= nbuf % 2; + if(*params[param_delay] > 0.f) { + R = buffer[(pos - (int)nbuf + 1 + buffer_size) % buffer_size]; + } else if (*params[param_delay] < 0.f) { + L = buffer[(pos - (int)nbuf + buffer_size) % buffer_size]; + } + + pos = (pos + 2) % buffer_size; + + // balance out + L *= (1.f - std::max(0.f, *params[param_balance_out])); + R *= (1.f + std::min(0.f, *params[param_balance_out])); + + // level + L *= *params[param_level_out]; + R *= *params[param_level_out]; + + //output + outs[0][i] = L; + outs[1][i] = R; + + // clip LED's + if(L > 1.f) clip_outL = srate >> 3; + if(R > 1.f) clip_outR = srate >> 3; + if(L > meter_outL) meter_outL = L; + if(R > meter_outR) meter_outR = R; + } + } + // draw meters + SET_IF_CONNECTED(clip_in); + SET_IF_CONNECTED(clip_outL); + SET_IF_CONNECTED(clip_outR); + SET_IF_CONNECTED(meter_in); + SET_IF_CONNECTED(meter_outL); + SET_IF_CONNECTED(meter_outR); + return outputs_mask; +} + +void mono_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + // rebuild buffer + buffer_size = (int)srate * 0.05 * 2; // delay buffer size multiplied by 2 channels + buffer = (float*) calloc(buffer_size, sizeof(float)); + memset(buffer, 0, buffer_size * sizeof(float)); // reset buffer to zero + pos = 0; +} diff --git a/plugins/ladspa_effect/calf/src/modules_comp.cpp b/plugins/ladspa_effect/calf/src/modules_comp.cpp index 4c683b2f7..0ee6842e1 100644 --- a/plugins/ladspa_effect/calf/src/modules_comp.cpp +++ b/plugins/ladspa_effect/calf/src/modules_comp.cpp @@ -28,7 +28,7 @@ using namespace calf_plugins; #define SET_IF_CONNECTED(name) if (params[AM::param_##name] != NULL) *params[AM::param_##name] = name; -/// Multibandcompressor by Markus Schmidt +/// Multiband Compressor by Markus Schmidt /// /// This module splits the signal in four different bands /// and sends them through multiple filters (implemented by @@ -50,6 +50,12 @@ multibandcompressor_audio_module::multibandcompressor_audio_module() meter_inR = 0.f; meter_outL = 0.f; meter_outR = 0.f; + for(int i = 0; i < strips - 1; i ++) { + freq_old[i] = -1; + sep_old[i] = -1; + q_old[i] = -1; + } + mode_old = -1; } void multibandcompressor_audio_module::activate() @@ -75,39 +81,77 @@ void multibandcompressor_audio_module::deactivate() void multibandcompressor_audio_module::params_changed() { + // determine mute/solo states + solo[0] = *params[param_solo0] > 0.f ? true : false; + solo[1] = *params[param_solo1] > 0.f ? true : false; + solo[2] = *params[param_solo2] > 0.f ? true : false; + solo[3] = *params[param_solo3] > 0.f ? true : false; + no_solo = (*params[param_solo0] > 0.f || + *params[param_solo1] > 0.f || + *params[param_solo2] > 0.f || + *params[param_solo3] > 0.f) ? false : true; + int i; + int j1; + switch(mode) { + case 0: + default: + j1 = 0; + break; + case 1: + j1 = 2; + break; + } // 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.copy_coeffs(lpL0); - hpL0.set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate); - hpR0.copy_coeffs(hpL0); + if(*params[param_freq0] != freq_old[0] or *params[param_sep0] != sep_old[0] or *params[param_q0] != q_old[0] or *params[param_mode] != mode_old) { + lpL[0][0].set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate); + hpL[0][0].set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate); + lpR[0][0].copy_coeffs(lpL[0][0]); + hpR[0][0].copy_coeffs(hpL[0][0]); + for(i = 1; i <= j1; i++) { + lpL[0][i].copy_coeffs(lpL[0][0]); + hpL[0][i].copy_coeffs(hpL[0][0]); + lpR[0][i].copy_coeffs(lpL[0][0]); + hpR[0][i].copy_coeffs(hpL[0][0]); + } freq_old[0] = *params[param_freq0]; sep_old[0] = *params[param_sep0]; q_old[0] = *params[param_q0]; } - 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.copy_coeffs(lpL1); - hpL1.set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate); - hpR1.copy_coeffs(hpL1); + if(*params[param_freq1] != freq_old[1] or *params[param_sep1] != sep_old[1] or *params[param_q1] != q_old[1] or *params[param_mode] != mode_old) { + lpL[1][0].set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate); + hpL[1][0].set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate); + lpR[1][0].copy_coeffs(lpL[1][0]); + hpR[1][0].copy_coeffs(hpL[1][0]); + for(i = 1; i <= j1; i++) { + lpL[1][i].copy_coeffs(lpL[1][0]); + hpL[1][i].copy_coeffs(hpL[1][0]); + lpR[1][i].copy_coeffs(lpL[1][0]); + hpR[1][i].copy_coeffs(hpL[1][0]); + } freq_old[1] = *params[param_freq1]; sep_old[1] = *params[param_sep1]; q_old[1] = *params[param_q1]; } - 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.copy_coeffs(lpL2); - hpL2.set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate); - hpR2.copy_coeffs(hpL2); + if(*params[param_freq2] != freq_old[2] or *params[param_sep2] != sep_old[2] or *params[param_q2] != q_old[2] or *params[param_mode] != mode_old) { + lpL[2][0].set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate); + hpL[2][0].set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate); + lpR[2][0].copy_coeffs(lpL[2][0]); + hpR[2][0].copy_coeffs(hpL[2][0]); + for(i = 1; i <= j1; i++) { + lpL[2][i].copy_coeffs(lpL[2][0]); + hpL[2][i].copy_coeffs(hpL[2][0]); + lpR[2][i].copy_coeffs(lpL[2][0]); + hpR[2][i].copy_coeffs(hpL[2][0]); + } freq_old[2] = *params[param_freq2]; sep_old[2] = *params[param_sep2]; q_old[2] = *params[param_q2]; } // set the params of all strips - strip[0].set_params(*params[param_attack0], *params[param_release0], *params[param_threshold0], *params[param_ratio0], *params[param_knee0], *params[param_makeup0], *params[param_detection0], 1.f, *params[param_bypass0], *params[param_mute0]); - strip[1].set_params(*params[param_attack1], *params[param_release1], *params[param_threshold1], *params[param_ratio1], *params[param_knee1], *params[param_makeup1], *params[param_detection1], 1.f, *params[param_bypass1], *params[param_mute1]); - strip[2].set_params(*params[param_attack2], *params[param_release2], *params[param_threshold2], *params[param_ratio2], *params[param_knee2], *params[param_makeup2], *params[param_detection2], 1.f, *params[param_bypass2], *params[param_mute2]); - strip[3].set_params(*params[param_attack3], *params[param_release3], *params[param_threshold3], *params[param_ratio3], *params[param_knee3], *params[param_makeup3], *params[param_detection3], 1.f, *params[param_bypass3], *params[param_mute3]); + strip[0].set_params(*params[param_attack0], *params[param_release0], *params[param_threshold0], *params[param_ratio0], *params[param_knee0], *params[param_makeup0], *params[param_detection0], 1.f, *params[param_bypass0], !(solo[0] || no_solo)); + strip[1].set_params(*params[param_attack1], *params[param_release1], *params[param_threshold1], *params[param_ratio1], *params[param_knee1], *params[param_makeup1], *params[param_detection1], 1.f, *params[param_bypass1], !(solo[1] || no_solo)); + strip[2].set_params(*params[param_attack2], *params[param_release2], *params[param_threshold2], *params[param_ratio2], *params[param_knee2], *params[param_makeup2], *params[param_detection2], 1.f, *params[param_bypass2], !(solo[2] || no_solo)); + strip[3].set_params(*params[param_attack3], *params[param_release3], *params[param_threshold3], *params[param_ratio3], *params[param_knee3], *params[param_makeup3], *params[param_detection3], 1.f, *params[param_bypass3], !(solo[3] || no_solo)); } void multibandcompressor_audio_module::set_sample_rate(uint32_t sr) @@ -156,12 +200,6 @@ uint32_t multibandcompressor_audio_module::process(uint32_t offset, uint32_t num } 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); @@ -181,47 +219,37 @@ uint32_t multibandcompressor_audio_module::process(uint32_t offset, uint32_t num // out vars float outL = 0.f; float outR = 0.f; + int j1; for (int i = 0; i < strips; i ++) { // cycle trough strips - if (!mute[i]) { + if (solo[i] || no_solo) { // strip unmuted float left = inL; float right = inR; // send trough filters - switch (i) { + switch(mode) { case 0: - left = lpL0.process(left); - right = lpR0.process(right); - lpL0.sanitize(); - lpR0.sanitize(); + default: + j1 = 0; 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(); + j1 = 2; break; } + for (int j = 0; j <= j1; j++){ + if(i + 1 < strips) { + left = lpL[i][j].process(left); + right = lpR[i][j].process(right); + lpL[i][j].sanitize(); + lpR[i][j].sanitize(); + } + if(i - 1 >= 0) { + left = hpL[i - 1][j].process(left); + right = hpR[i - 1][j].process(right); + hpL[i - 1][j].sanitize(); + hpR[i - 1][j].sanitize(); + } + } // process gain reduction strip[i].process(left, right); // sum up output @@ -237,8 +265,16 @@ uint32_t multibandcompressor_audio_module::process(uint32_t offset, uint32_t num // even out filters gain reduction // 3dB - levelled manually (based on default sep and q settings) - outL *= 1.414213562; - outR *= 1.414213562; + switch(mode) { + case 0: + outL *= 1.414213562; + outR *= 1.414213562; + break; + case 1: + outL *= 0.88; + outR *= 0.88; + break; + } // out level outL *= *params[param_level_out]; @@ -496,6 +532,10 @@ sidechaincompressor_audio_module::sidechaincompressor_audio_module() f2_freq_old1 = 0.f; f1_level_old1 = 0.f; f2_level_old1 = 0.f; + f1_freq_old = 0.f; + f2_freq_old = 0.f; + f1_level_old = 0.f; + f2_level_old = 0.f; sc_mode_old1 = WIDEBAND; meters.reset(); } @@ -869,6 +909,13 @@ deesser_audio_module::deesser_audio_module() f1_level_old1 = 0.f; f2_level_old1 = 0.f; f2_q_old1 = 0.f; + f1_freq_old = 0.f; + f2_freq_old = 0.f; + f1_level_old = 0.f; + f2_level_old = 0.f; + f2_q_old = 0.f; + detected_led = 0; + clip_led = 0; } void deesser_audio_module::activate() @@ -1605,6 +1652,17 @@ gain_reduction_audio_module::gain_reduction_audio_module() old_detection = 0.f; old_bypass = 0.f; old_mute = 0.f; + linSlope = 0.f; + attack = 0.f; + release = 0.f; + detection = -1; + stereo_link = -1; + threshold = -1; + ratio = -1; + knee = -1; + makeup = -1; + bypass = -1; + mute = -1; } void gain_reduction_audio_module::activate() @@ -1617,7 +1675,7 @@ void gain_reduction_audio_module::activate() l = r = 0.f; float byp = bypass; bypass = 0.0; - process(l, r); + process(l, r, 0, 0); bypass = byp; } @@ -1650,14 +1708,16 @@ void gain_reduction_audio_module::process(float &left, float &right, const float if(bypass < 0.5f) { // this routine is mainly copied from thor's compressor module // greatest sounding compressor I've heard! - bool rms = detection == 0; - bool average = stereo_link == 0; + bool rms = (detection == 0); + bool average = (stereo_link == 0); 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 absample = average ? (fabs(*det_left) + fabs(*det_right)) * 0.5f : std::max(fabs(*det_left), fabs(*det_right)); if(rms) absample *= absample; - + + dsp::sanitize(linSlope); + linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff); float gain = 1.f; if(linSlope > 0.f) { @@ -1767,7 +1827,7 @@ bool gain_reduction_audio_module::get_dot(int subindex, float &x, float &y, int if(bypass > 0.5f or mute > 0.f) { return false; } else { - bool rms = detection == 0; + 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)); @@ -1831,7 +1891,15 @@ expander_audio_module::expander_audio_module() is_active = false; srate = 0; last_generation = 0; - + range = -1.f; + threshold = -1.f; + ratio = -1.f; + knee = -1.f; + makeup = -1.f; + detection = -1.f; + bypass = -1.f; + mute = -1.f; + stereo_link = -1.f; old_range = 0.f; old_threshold = 0.f; old_ratio = 0.f; @@ -1842,6 +1910,8 @@ expander_audio_module::expander_audio_module() old_mute = 0.f; old_trigger = 0.f; old_stereo_link = 0.f; + linSlope = -1; + linKneeStop = 0; } void expander_audio_module::activate() @@ -1865,7 +1935,7 @@ void expander_audio_module::deactivate() void expander_audio_module::update_curve() { - bool rms = detection == 0; + bool rms = (detection == 0); float linThreshold = threshold; if (rms) linThreshold = linThreshold * linThreshold; @@ -1891,11 +1961,13 @@ void expander_audio_module::process(float &left, float &right, const float *det_ } if(bypass < 0.5f) { // this routine is mainly copied from Damien's expander module based on Thor's compressor - bool rms = detection == 0; - bool average = stereo_link == 0; + bool rms = (detection == 0); + bool average = (stereo_link == 0); float absample = average ? (fabs(*det_left) + fabs(*det_right)) * 0.5f : std::max(fabs(*det_left), fabs(*det_right)); if(rms) absample *= absample; - + + dsp::sanitize(linSlope); + linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff); float gain = 1.f; if(linSlope > 0.f) { @@ -1910,7 +1982,7 @@ void expander_audio_module::process(float &left, float &right, const float *det_ } float expander_audio_module::output_level(float slope) const { - bool rms = detection == 0; + bool rms = (detection == 0); return slope * output_gain(rms ? slope*slope : slope, rms) * makeup; } @@ -2001,7 +2073,7 @@ bool expander_audio_module::get_dot(int subindex, float &x, float &y, int &size, if(bypass > 0.5f or mute > 0.f) { return false; } else { - bool rms = detection == 0; + 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)); diff --git a/plugins/ladspa_effect/calf/src/modules_dist.cpp b/plugins/ladspa_effect/calf/src/modules_dist.cpp index 049e94818..559e78500 100644 --- a/plugins/ladspa_effect/calf/src/modules_dist.cpp +++ b/plugins/ladspa_effect/calf/src/modules_dist.cpp @@ -37,6 +37,12 @@ saturator_audio_module::saturator_audio_module() is_active = false; srate = 0; meter_drive = 0.f; + lp_pre_freq_old = -1; + hp_pre_freq_old = -1; + lp_post_freq_old = -1; + hp_post_freq_old = -1; + p_freq_old = -1; + p_level_old = -1; } void saturator_audio_module::activate() diff --git a/plugins/ladspa_effect/calf/src/modules_limit.cpp b/plugins/ladspa_effect/calf/src/modules_limit.cpp new file mode 100644 index 000000000..05f217645 --- /dev/null +++ b/plugins/ladspa_effect/calf/src/modules_limit.cpp @@ -0,0 +1,646 @@ +/* Calf DSP plugin pack + * Limiter related plugins + * + * Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include + +using namespace dsp; +using namespace calf_plugins; + +#define SET_IF_CONNECTED(name) if (params[AM::param_##name] != NULL) *params[AM::param_##name] = name; + +/// Limiter by Markus Schmidt and Christian Holschuh +/// +/// This module provides the lookahead limiter as a simple audio module +/// with choosable lookahead and release time. +/////////////////////////////////////////////////////////////////////////////////////////////// + +limiter_audio_module::limiter_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; + asc_led = 0.f; +} + +void limiter_audio_module::activate() +{ + is_active = true; + // set all filters and strips + params_changed(); + limiter.activate(); +} + +void limiter_audio_module::deactivate() +{ + is_active = false; + limiter.deactivate(); +} + +void limiter_audio_module::params_changed() +{ + limiter.set_params(*params[param_limit], *params[param_attack], *params[param_release], 1.f, *params[param_asc], true); +} + +void limiter_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + limiter.set_sample_rate(srate); +} + +uint32_t limiter_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; + asc_led = 0.f; + } else { + // 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 = 0.f; + meter_inR = 0.f; + meter_outL = 0.f; + meter_outR = 0.f; + asc_led -= std::min(asc_led, numsamples); + + 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 = inL; + float outR = inR; + + // process gain reduction + float fickdich[0]; + limiter.process(outL, outR, fickdich); + if(limiter.get_arc()) + asc_led = srate >> 3; + + // autolevel + outL /= *params[param_limit]; + outR /= *params[param_limit]; + + // 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; + } + // set 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 (no bypass) + + // draw meters + SET_IF_CONNECTED(clip_inL); + SET_IF_CONNECTED(clip_inR); + SET_IF_CONNECTED(clip_outL); + SET_IF_CONNECTED(clip_outR); + SET_IF_CONNECTED(meter_inL); + SET_IF_CONNECTED(meter_inR); + SET_IF_CONNECTED(meter_outL); + SET_IF_CONNECTED(meter_outR); + + if (params[param_asc_led] != NULL) *params[param_asc_led] = asc_led; + + if (*params[param_att]) { + if(bypass) + *params[param_att] = 1.f; + else + *params[param_att] = limiter.get_attenuation(); + } + + // whatever has to be returned x) + return outputs_mask; +} + +/// Multiband Limiter by Markus Schmidt and Christian Holschuh +/// +/// This module splits the signal in four different bands +/// and sends them through multiple filters (implemented by +/// Krzysztof). They are processed by a lookahead limiter module afterwards +/// and summed up to the final output again. +/////////////////////////////////////////////////////////////////////////////////////////////// + +multibandlimiter_audio_module::multibandlimiter_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; + asc_led = 0.f; + __attack = -1.f; + channels = 2; + buffer_size = 0; + overall_buffer_size = 0; + _sanitize = false; + for(int i = 0; i < strips - 1; i ++) { + freq_old[i] = -1; + sep_old[i] = -1; + q_old[i] = -1; + } + mode_old = 0; +} + +void multibandlimiter_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].set_multi(true); + strip[j].id = j; + } + broadband.activate(); + pos = 0; +} + +void multibandlimiter_audio_module::deactivate() +{ + is_active = false; + // deactivate all strips + for (int j = 0; j < strips; j ++) { + strip[j].deactivate(); + } + broadband.deactivate(); +} + +void multibandlimiter_audio_module::params_changed() +{ + // determine mute/solo states + solo[0] = *params[param_solo0] > 0.f ? true : false; + solo[1] = *params[param_solo1] > 0.f ? true : false; + solo[2] = *params[param_solo2] > 0.f ? true : false; + solo[3] = *params[param_solo3] > 0.f ? true : false; + no_solo = (*params[param_solo0] > 0.f || + *params[param_solo1] > 0.f || + *params[param_solo2] > 0.f || + *params[param_solo3] > 0.f) ? false : true; + + mode_old = mode; + mode = *params[param_mode]; + int i; + int j1; + switch(mode) { + case 0: + default: + j1 = 0; + break; + case 1: + j1 = 2; + break; + } + // 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] or *params[param_mode] != mode_old) { + lpL[0][0].set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate); + hpL[0][0].set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate); + lpR[0][0].copy_coeffs(lpL[0][0]); + hpR[0][0].copy_coeffs(hpL[0][0]); + for(i = 1; i <= j1; i++) { + lpL[0][i].copy_coeffs(lpL[0][0]); + hpL[0][i].copy_coeffs(hpL[0][0]); + lpR[0][i].copy_coeffs(lpL[0][0]); + hpR[0][i].copy_coeffs(hpL[0][0]); + } + freq_old[0] = *params[param_freq0]; + sep_old[0] = *params[param_sep0]; + q_old[0] = *params[param_q0]; + } + if(*params[param_freq1] != freq_old[1] or *params[param_sep1] != sep_old[1] or *params[param_q1] != q_old[1] or *params[param_mode] != mode_old) { + lpL[1][0].set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate); + hpL[1][0].set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate); + lpR[1][0].copy_coeffs(lpL[1][0]); + hpR[1][0].copy_coeffs(hpL[1][0]); + for(i = 1; i <= j1; i++) { + lpL[1][i].copy_coeffs(lpL[1][0]); + hpL[1][i].copy_coeffs(hpL[1][0]); + lpR[1][i].copy_coeffs(lpL[1][0]); + hpR[1][i].copy_coeffs(hpL[1][0]); + } + freq_old[1] = *params[param_freq1]; + sep_old[1] = *params[param_sep1]; + q_old[1] = *params[param_q1]; + } + if(*params[param_freq2] != freq_old[2] or *params[param_sep2] != sep_old[2] or *params[param_q2] != q_old[2] or *params[param_mode] != mode_old) { + lpL[2][0].set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate); + hpL[2][0].set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate); + lpR[2][0].copy_coeffs(lpL[2][0]); + hpR[2][0].copy_coeffs(hpL[2][0]); + for(i = 1; i <= j1; i++) { + lpL[2][i].copy_coeffs(lpL[2][0]); + hpL[2][i].copy_coeffs(hpL[2][0]); + lpR[2][i].copy_coeffs(lpL[2][0]); + hpR[2][i].copy_coeffs(hpL[2][0]); + } + freq_old[2] = *params[param_freq2]; + sep_old[2] = *params[param_sep2]; + q_old[2] = *params[param_q2]; + } + // set the params of all strips + float rel; + + rel = *params[param_release] * pow(0.25, *params[param_release0] * -1); + rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / 30), rel) : rel; + weight[0] = pow(0.25, *params[param_weight0] * -1); + strip[0].set_params(*params[param_limit], *params[param_attack], rel, weight[0], *params[param_asc], true); + *params[param_effrelease0] = rel; + rel = *params[param_release] * pow(0.25, *params[param_release1] * -1); + rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq0]), rel) : rel; + weight[1] = pow(0.25, *params[param_weight1] * -1); + strip[1].set_params(*params[param_limit], *params[param_attack], rel, weight[1], *params[param_asc]); + *params[param_effrelease1] = rel; + rel = *params[param_release] * pow(0.25, *params[param_release2] * -1); + rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq1]), rel) : rel; + weight[2] = pow(0.25, *params[param_weight2] * -1); + strip[2].set_params(*params[param_limit], *params[param_attack], rel, weight[2], *params[param_asc]); + *params[param_effrelease2] = rel; + rel = *params[param_release] * pow(0.25, *params[param_release3] * -1); + rel = (*params[param_minrel] > 0.5) ? std::max(2500 * (1.f / *params[param_freq2]), rel) : rel; + weight[3] = pow(0.25, *params[param_weight3] * -1); + strip[3].set_params(*params[param_limit], *params[param_attack], rel, weight[3], *params[param_asc]); + *params[param_effrelease3] = rel; + broadband.set_params(*params[param_limit], *params[param_attack], rel, 1.f, *params[param_asc]); + // rebuild multiband buffer + if( *params[param_attack] != __attack) { + int bs = (int)(srate * (*params[param_attack] / 1000.f) * channels); + buffer_size = bs - bs % channels; // buffer size attack rate + __attack = *params[param_attack]; + _sanitize = true; + pos = 0; + } +} + +void multibandlimiter_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + // rebuild buffer + overall_buffer_size = (int)(srate * (100.f / 1000.f) * channels) + channels; // buffer size max attack rate + buffer = (float*) calloc(overall_buffer_size, sizeof(float)); + memset(buffer, 0, overall_buffer_size * sizeof(float)); // reset buffer to zero + pos = 0; + // set srate of all strips + for (int j = 0; j < strips; j ++) { + strip[j].set_sample_rate(srate); + } + broadband.set_sample_rate(srate); +} + +#define BYPASSED_COMPRESSION(index) \ + if(params[param_att##index] != NULL) \ + *params[param_att##index] = 1.0; \ + +#define ACTIVE_COMPRESSION(index) \ + if(params[param_att##index] != NULL) \ + *params[param_att##index] = strip[index].get_attenuation(); \ + +uint32_t multibandlimiter_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; + float batt = 0.f; + 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; + asc_led = 0.f; + } else { + // process all strips + + // 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); + asc_led -= std::min(asc_led, numsamples); + meter_inL = 0.f; + meter_inR = 0.f; + meter_outL = 0.f; + meter_outR = 0.f; + float _tmpL[channels]; + float _tmpR[channels]; + while(offset < numsamples) { + float inL = 0.f; + float inR = 0.f; + // cycle through samples + if(!_sanitize) { + inL = ins[0][offset]; + inR = ins[1][offset]; + } + // in level + inR *= *params[param_level_in]; + inL *= *params[param_level_in]; + // even out filters gain reduction + // 3dB - levelled manually (based on default sep and q settings) + switch(mode) { + case 0: + inL *= 1.414213562; + inR *= 1.414213562; + break; + case 1: + inL *= 0.88; + inR *= 0.88; + break; + } + // out vars + float outL = 0.f; + float outR = 0.f; + int j1; + float left; + float right; + float sum_left = 0.f; + float sum_right = 0.f; + bool asc_active = false; + for (int i = 0; i < strips; i++) { + left = inL; + right = inR; + // send trough filters + switch(mode) { + // how many filter passes? (12/36dB) + case 0: + default: + j1 = 0; + break; + case 1: + j1 = 2; + break; + } + for (int j = 0; j <= j1; j++){ + if(i + 1 < strips) { + // do lowpass on all bands except most high + left = lpL[i][j].process(left); + right = lpR[i][j].process(right); + lpL[i][j].sanitize(); + lpR[i][j].sanitize(); + } + if(i - 1 >= 0) { + // do highpass on all bands except most low + left = hpL[i - 1][j].process(left); + right = hpR[i - 1][j].process(right); + hpL[i - 1][j].sanitize(); + hpR[i - 1][j].sanitize(); + } + } + + // remember filtered values for limiting + // (we need multiband_coeff before we can call the limiter bands) + _tmpL[i] = left; + _tmpR[i] = right; + + // sum up for multiband coefficient + sum_left += ((fabs(left) > *params[param_limit]) ? *params[param_limit] * (fabs(left) / left) : left) * weight[i]; + sum_right += ((fabs(right) > *params[param_limit]) ? *params[param_limit] * (fabs(right) / right) : right) * weight[i]; + } // process single strip with filter + + // write multiband coefficient to buffer + buffer[pos] = std::min(*params[param_limit] / std::max(fabs(sum_left), fabs(sum_right)), 1.0); + + for (int i = 0; i < strips; i++) { + // process gain reduction + strip[i].process(_tmpL[i], _tmpR[i], buffer); + // sum up output of limiters + if (solo[i] || no_solo) { + outL += _tmpL[i]; + outR += _tmpR[i]; + } + asc_active = asc_active || strip[i].get_arc(); + } // process single strip again for limiter + float fickdich[0]; + broadband.process(outL, outR, fickdich); + batt = broadband.get_attenuation(); + + // autolevel + outL /= *params[param_limit]; + outR /= *params[param_limit]; + + // 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(ins[0][offset] * *params[param_level_in] > 1.f) { + clip_inL = srate >> 3; + } + if(ins[1][offset] * *params[param_level_in] > 1.f) { + clip_inR = srate >> 3; + } + if(outL > 1.f) { + clip_outL = srate >> 3; + } + if(outR > 1.f) { + clip_outR = srate >> 3; + } + // set up in / out meters + if(ins[0][offset] * *params[param_level_in] > meter_inL) { + meter_inL = ins[0][offset] * *params[param_level_in]; + } + if(ins[1][offset] * *params[param_level_in] > meter_inR) { + meter_inR = ins[1][offset] * *params[param_level_in]; + } + if(outL > meter_outL) { + meter_outL = outL; + } + if(outR > meter_outR) { + meter_outR = outR; + } + if(asc_active) { + asc_led = srate >> 3; + } + // next sample + ++offset; + pos = (pos + channels) % buffer_size; + if(pos == 0) _sanitize = false; + } // cycle trough samples + + } // process all strips (no bypass) + + // draw meters + SET_IF_CONNECTED(clip_inL); + SET_IF_CONNECTED(clip_inR); + SET_IF_CONNECTED(clip_outL); + SET_IF_CONNECTED(clip_outR); + SET_IF_CONNECTED(meter_inL); + SET_IF_CONNECTED(meter_inR); + SET_IF_CONNECTED(meter_outL); + SET_IF_CONNECTED(meter_outR); + + if (params[param_asc_led] != NULL) *params[param_asc_led] = asc_led; + + // draw strip meters + if(bypass > 0.5f) { + if(params[param_att0] != NULL) *params[param_att0] = 1.0; + if(params[param_att1] != NULL) *params[param_att1] = 1.0; + if(params[param_att2] != NULL) *params[param_att2] = 1.0; + if(params[param_att3] != NULL) *params[param_att3] = 1.0; + + } else { + if(params[param_att0] != NULL) *params[param_att0] = strip[0].get_attenuation() * batt; + if(params[param_att1] != NULL) *params[param_att1] = strip[1].get_attenuation() * batt; + if(params[param_att2] != NULL) *params[param_att2] = strip[2].get_attenuation() * batt; + if(params[param_att3] != NULL) *params[param_att3] = strip[3].get_attenuation() * batt; + } + // whatever has to be returned x) + return outputs_mask; +} + +bool multibandlimiter_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + if (!is_active or subindex > 3) + return false; + float ret; + double freq; + int j1; + for (int i = 0; i < points; i++) + { + ret = 1.f; + freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points); + switch(mode) { + case 0: + default: + j1 = 0; + break; + case 1: + j1 = 2; + break; + } + for(int j = 0; j <= j1; j ++) { + switch(subindex) { + case 0: + ret *= lpL[0][j].freq_gain(freq, (float)srate); + break; + case 1: + ret *= hpL[0][j].freq_gain(freq, (float)srate); + ret *= lpL[1][j].freq_gain(freq, (float)srate); + break; + case 2: + ret *= hpL[1][j].freq_gain(freq, (float)srate); + ret *= lpL[2][j].freq_gain(freq, (float)srate); + break; + case 3: + ret *= hpL[2][j].freq_gain(freq, (float)srate); + break; + } + } + data[i] = dB_grid(ret); + } + if (*params[param_bypass] > 0.5f) + 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 multibandlimiter_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const +{ + if (!is_active) { + return false; + } else { + vertical = (subindex & 1) != 0; + return get_freq_gridline(subindex, pos, vertical, legend, context); + } +} + diff --git a/plugins/ladspa_effect/calf/src/monosynth.cpp b/plugins/ladspa_effect/calf/src/monosynth.cpp index 5398d8fc1..1eea9dc97 100644 --- a/plugins/ladspa_effect/calf/src/monosynth.cpp +++ b/plugins/ladspa_effect/calf/src/monosynth.cpp @@ -51,6 +51,12 @@ void monosynth_audio_module::activate() { last_pwshift1 = last_pwshift2 = 0; last_stretch1 = 65536; queue_note_on_and_off = false; + prev_wave1 = -1; + prev_wave2 = -1; + wave1 = -1; + wave2 = -1; + queue_note_on = -1; + last_filter_type = -1; } waveform_family *monosynth_audio_module::waves; @@ -352,8 +358,6 @@ void monosynth_audio_module::delayed_note_on() velocity = queue_vel; ampctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2amp]; fltctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2filter]; - set_frequency(); - lookup_waveforms(); bool starting = false; if (!running) @@ -408,6 +412,8 @@ void monosynth_audio_module::delayed_note_on() queue_note_on = -1; float modsrc[modsrc_count] = { 1, velocity, inertia_pressure.get_last(), modwheel_value, envelope1.value, envelope2.value, 0.5+0.5*lfo1.last, 0.5+0.5*lfo2.last}; calculate_modmatrix(moddest, moddest_count, modsrc); + set_frequency(); + lookup_waveforms(); if (queue_note_on_and_off) { @@ -467,7 +473,6 @@ void monosynth_audio_module::calculate_step() if (fabs(*params[par_lfopitch]) > small_value()) lfo_bend = pow(2.0f, *params[par_lfopitch] * lfov1 * (1.f / 1200.0f)); inertia_pitchbend.step(); - set_frequency(); envelope1.advance(); envelope2.advance(); float env1 = envelope1.value, env2 = envelope2.value; @@ -478,6 +483,7 @@ void monosynth_audio_module::calculate_step() float modsrc[modsrc_count] = { 1, velocity, inertia_pressure.get(), modwheel_value, env1, env2, 0.5+0.5*lfov1, 0.5+0.5*lfov2}; calculate_modmatrix(moddest, moddest_count, modsrc); + set_frequency(); inertia_cutoff.set_inertia(*params[par_cutoff]); cutoff = inertia_cutoff.get() * pow(2.0f, (lfov1 * *params[par_lfofilter] + env1 * fltctl * *params[par_env1tocutoff] + env2 * fltctl * *params[par_env2tocutoff] + moddest[moddest_cutoff]) * (1.f / 1200.f)); if (*params[par_keyfollow] > 0.01f) diff --git a/plugins/ladspa_effect/calf/src/plugin.cpp b/plugins/ladspa_effect/calf/src/plugin.cpp index 2f78bc967..b5300196d 100644 --- a/plugins/ladspa_effect/calf/src/plugin.cpp +++ b/plugins/ladspa_effect/calf/src/plugin.cpp @@ -19,461 +19,18 @@ * Boston, MA 02110-1301 USA */ #include -#include #include #include #include +#include #include #include #include #include #include #include -#include using namespace calf_plugins; -using namespace osctl; - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if USE_LADSPA - -ladspa_instance::ladspa_instance(audio_module_iface *_module, ladspa_plugin_metadata_set *_ladspa, int sample_rate) -{ - module = _module; - metadata = module->get_metadata_iface(); - ladspa = _ladspa; - - module->get_port_arrays(ins, outs, params); - - activate_flag = true; -#if USE_DSSI - feedback_sender = NULL; -#endif - - module->set_sample_rate(sample_rate); - module->post_instantiate(); -} - -float ladspa_instance::get_param_value(int param_no) -{ - // XXXKF hack - if (param_no >= ladspa->param_count) - return 0; - return *params[param_no]; -} - -void ladspa_instance::set_param_value(int param_no, float value) -{ - // XXXKF hack - if (param_no >= ladspa->param_count) - return; - *params[param_no] = value; -} - -bool ladspa_instance::activate_preset(int bank, int program) -{ - return false; -} - -/// LADSPA run function - does set sample rate / activate logic when it's run first time after activation -void ladspa_instance::run(unsigned long SampleCount) -{ - if (activate_flag) - { - module->activate(); - activate_flag = false; - } - module->params_changed(); - module->process_slice(0, SampleCount); -} - -#if USE_DSSI - -void ladspa_instance::run_synth(unsigned long SampleCount, snd_seq_event_t *Events, unsigned long EventCount) -{ - if (activate_flag) - { - module->activate(); - activate_flag = false; - } - module->params_changed(); - - uint32_t offset = 0; - for (uint32_t e = 0; e < EventCount; e++) - { - uint32_t timestamp = Events[e].time.tick; - if (timestamp != offset) - module->process_slice(offset, timestamp); - process_dssi_event(Events[e]); - offset = timestamp; - } - if (offset != SampleCount) - module->process_slice(offset, SampleCount); -} - -#endif - -char *ladspa_instance::configure(const char *key, const char *value) -{ -#if USE_DSSI_GUI - if (!strcmp(key, "OSC:FEEDBACK_URI")) - { - const line_graph_iface *lgi = dynamic_cast(metadata); - //if (!lgi) - // return NULL; - if (*value) - { - if (feedback_sender) { - delete feedback_sender; - feedback_sender = NULL; - } - feedback_sender = new dssi_feedback_sender(value, lgi); - feedback_sender->add_graphs(metadata->get_param_props(0), metadata->get_param_count()); - } - else - { - if (feedback_sender) { - delete feedback_sender; - feedback_sender = NULL; - } - } - return NULL; - } - else - if (!strcmp(key, "OSC:UPDATE")) - { - if (feedback_sender) - feedback_sender->update(); - return NULL; - } - else - if (!strcmp(key, "OSC:SEND_STATUS")) - { - if (!feedback_sender) - return NULL; - struct status_gatherer: public send_updates_iface - { - osc_inline_typed_strstream str; - void send_status(const char *key, const char *value) - { - str << key << value; - } - } sg; - int serial = atoi(value); - serial = module->send_status_updates(&sg, serial); - sg.str << (uint32_t)serial; - feedback_sender->client->send("/status_data", sg.str); - return NULL; - } - else -#endif - if (!strcmp(key, "ExecCommand")) - { - if (*value) - { - execute(atoi(value)); - } - return NULL; - } - return module->configure(key, value); -} - -template -ladspa_plugin_metadata_set ladspa_wrapper::output; - -#if USE_DSSI - -/// Utility function: handle MIDI event (only handles a subset in this version) -void ladspa_instance::process_dssi_event(snd_seq_event_t &event) -{ - switch(event.type) { - case SND_SEQ_EVENT_NOTEON: - module->note_on(event.data.note.channel, event.data.note.note, event.data.note.velocity); - break; - case SND_SEQ_EVENT_NOTEOFF: - module->note_off(event.data.note.channel, event.data.note.note, event.data.note.velocity); - break; - case SND_SEQ_EVENT_PGMCHANGE: - module->program_change(event.data.control.channel, event.data.control.value); - break; - case SND_SEQ_EVENT_CONTROLLER: - module->control_change(event.data.control.channel, event.data.control.param, event.data.control.value); - break; - case SND_SEQ_EVENT_PITCHBEND: - module->pitch_bend(event.data.control.channel, event.data.control.value); - break; - case SND_SEQ_EVENT_CHANPRESS: - module->channel_pressure(event.data.control.channel, event.data.control.value); - break; - } -} -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// LADSPA callbacks - -/// LADSPA activate function (note that at this moment the ports are not set) -static void cb_activate(LADSPA_Handle Instance) -{ - ((ladspa_instance *)(Instance))->activate_flag = true; -} - -/// LADSPA run function - does set sample rate / activate logic when it's run first time after activation -static void cb_run(LADSPA_Handle Instance, unsigned long SampleCount) { - ((ladspa_instance *)(Instance))->run(SampleCount); -} - -/// LADSPA port connection function -static void cb_connect(LADSPA_Handle Instance, unsigned long port, LADSPA_Data *DataLocation) -{ - ladspa_instance *const mod = (ladspa_instance *)Instance; - - int first_out = mod->ladspa->input_count; - int first_param = first_out + mod->ladspa->output_count; - int ladspa_port_count = first_param + mod->ladspa->param_count; - - if ((int)port < first_out) - mod->ins[port] = DataLocation; - else if ((int)port < first_param) - mod->outs[port - first_out] = DataLocation; - else if ((int)port < ladspa_port_count) { - int i = port - first_param; - mod->params[i] = DataLocation; - *mod->params[i] = mod->metadata->get_param_props(i)->def_value; - } -} - - -/// LADSPA deactivate function -static void cb_deactivate(LADSPA_Handle Instance) { - ((ladspa_instance *)(Instance))->module->deactivate(); -} - -/// LADSPA cleanup (delete instance) function -static void cb_cleanup(LADSPA_Handle Instance) { - delete ((ladspa_instance *)(Instance)); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// DSSI callbacks - -#if USE_DSSI -/// DSSI "run synth" function, same as run() except it allows for event delivery -static void cb_run_synth(LADSPA_Handle Instance, unsigned long SampleCount, - snd_seq_event_t *Events, unsigned long EventCount) { - ((ladspa_instance *)(Instance))->run_synth(SampleCount, Events, EventCount); -} - -/// DSSI configure function (named properties) -static char *cb_configure(LADSPA_Handle Instance, - const char *Key, - const char *Value) -{ - return ((ladspa_instance *)(Instance))->configure(Key, Value); -} - -/// DSSI get program descriptor function; for 0, it returns the default program (from parameter properties table), for others, it uses global or user preset -static const DSSI_Program_Descriptor *cb_get_program(LADSPA_Handle Instance, unsigned long index) -{ - ladspa_plugin_metadata_set *ladspa = ((ladspa_instance *)(Instance))->ladspa; - if (index > ladspa->presets->size()) - return NULL; - if (index) - return &(*ladspa->preset_descs)[index - 1]; - return &ladspa->dssi_default_program; -} - -/// DSSI select program function; for 0, it sets the defaults, for others, it sets global or user preset -static void cb_select_program(LADSPA_Handle Instance, unsigned long Bank, unsigned long Program) -{ - ladspa_instance *mod = (ladspa_instance *)Instance; - ladspa_plugin_metadata_set *ladspa = mod->ladspa; - unsigned int no = (Bank << 7) + Program - 1; - // printf("no = %d presets = %p:%d\n", no, presets, presets->size()); - if (no == -1U) { - int rpc = ladspa->param_count; - for (int i =0 ; i < rpc; i++) - *mod->params[i] = mod->metadata->get_param_props(i)->def_value; - return; - } - if (no >= ladspa->presets->size()) - return; - plugin_preset &p = (*ladspa->presets)[no]; - // printf("activating preset %s\n", p.name.c_str()); - p.activate(mod); -} - -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -ladspa_plugin_metadata_set::ladspa_plugin_metadata_set() -{ - metadata = NULL; - memset(&descriptor, 0, sizeof(descriptor)); - -#if USE_DSSI - presets = NULL; - preset_descs = NULL; - memset(&descriptor_for_dssi, 0, sizeof(descriptor_for_dssi)); - memset(&dssi_descriptor, 0, sizeof(dssi_descriptor)); -#endif -} - -void ladspa_plugin_metadata_set::prepare(const plugin_metadata_iface *md, LADSPA_Handle (*cb_instantiate)(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate)) -{ - metadata = md; - - input_count = md->get_input_count(); - output_count = md->get_output_count(); - param_count = md->get_param_count(); // XXXKF ladspa_instance::real_param_count(); - - const ladspa_plugin_info &plugin_info = md->get_plugin_info(); - descriptor.UniqueID = plugin_info.unique_id; - descriptor.Label = plugin_info.label; - descriptor.Name = strdup((std::string(plugin_info.name) + " LADSPA").c_str()); - descriptor.Maker = plugin_info.maker; - descriptor.Copyright = plugin_info.copyright; - descriptor.Properties = md->is_rt_capable() ? LADSPA_PROPERTY_HARD_RT_CAPABLE : 0; - descriptor.PortCount = input_count + output_count + param_count; - descriptor.PortNames = new char *[descriptor.PortCount]; - descriptor.PortDescriptors = new LADSPA_PortDescriptor[descriptor.PortCount]; - descriptor.PortRangeHints = new LADSPA_PortRangeHint[descriptor.PortCount]; - int i; - for (i = 0; i < input_count + output_count; i++) - { - LADSPA_PortRangeHint &prh = ((LADSPA_PortRangeHint *)descriptor.PortRangeHints)[i]; - ((int *)descriptor.PortDescriptors)[i] = i < input_count ? LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO - : LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; - prh.HintDescriptor = 0; - ((const char **)descriptor.PortNames)[i] = md->get_port_names()[i]; - } - for (; i < input_count + output_count + param_count; i++) - { - LADSPA_PortRangeHint &prh = ((LADSPA_PortRangeHint *)descriptor.PortRangeHints)[i]; - const parameter_properties &pp = *md->get_param_props(i - input_count - output_count); - ((int *)descriptor.PortDescriptors)[i] = - LADSPA_PORT_CONTROL | (pp.flags & PF_PROP_OUTPUT ? LADSPA_PORT_OUTPUT : LADSPA_PORT_INPUT); - prh.HintDescriptor = LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW; - ((const char **)descriptor.PortNames)[i] = pp.name; - prh.LowerBound = pp.min; - prh.UpperBound = pp.max; - switch(pp.flags & PF_TYPEMASK) { - case PF_BOOL: - prh.HintDescriptor |= LADSPA_HINT_TOGGLED; - prh.HintDescriptor &= ~(LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW); - break; - case PF_INT: - case PF_ENUM: - prh.HintDescriptor |= LADSPA_HINT_INTEGER; - break; - default: { - int defpt = (int)(100 * (pp.def_value - pp.min) / (pp.max - pp.min)); - if ((pp.flags & PF_SCALEMASK) == PF_SCALE_LOG) - defpt = (int)(100 * log(pp.def_value / pp.min) / log(pp.max / pp.min)); - if (defpt < 12) - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM; - else if (defpt < 37) - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_LOW; - else if (defpt < 63) - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MIDDLE; - else if (defpt < 88) - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_HIGH; - else - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM; - } - } - if (pp.def_value == 0 || pp.def_value == 1 || pp.def_value == 100 || pp.def_value == 440 ) { - prh.HintDescriptor &= ~LADSPA_HINT_DEFAULT_MASK; - if (pp.def_value == 1) - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_1; - else if (pp.def_value == 100) - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_100; - else if (pp.def_value == 440) - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_440; - else - prh.HintDescriptor |= LADSPA_HINT_DEFAULT_0; - } - switch(pp.flags & PF_SCALEMASK) { - case PF_SCALE_LOG: - prh.HintDescriptor |= LADSPA_HINT_LOGARITHMIC; - break; - } - } - descriptor.ImplementationData = this; - descriptor.instantiate = cb_instantiate; - descriptor.connect_port = cb_connect; - descriptor.activate = cb_activate; - descriptor.run = cb_run; - descriptor.run_adding = NULL; - descriptor.set_run_adding_gain = NULL; - descriptor.deactivate = cb_deactivate; - descriptor.cleanup = cb_cleanup; - prepare_dssi(); -} - -void ladspa_plugin_metadata_set::prepare_dssi() -{ -#if USE_DSSI - const ladspa_plugin_info &plugin_info = metadata->get_plugin_info(); - memcpy(&descriptor_for_dssi, &descriptor, sizeof(descriptor)); - descriptor_for_dssi.Name = strdup((std::string(plugin_info.name) + " DSSI").c_str()); - memset(&dssi_descriptor, 0, sizeof(dssi_descriptor)); - dssi_descriptor.DSSI_API_Version = 1; - dssi_descriptor.LADSPA_Plugin = &descriptor_for_dssi; - dssi_descriptor.configure = cb_configure; - dssi_descriptor.get_program = cb_get_program; - dssi_descriptor.select_program = cb_select_program; - if (metadata->get_midi()) - dssi_descriptor.run_synth = cb_run_synth; - - presets = new std::vector; - preset_descs = new std::vector; - - preset_list plist_tmp, plist; - plist.load_defaults(true); - plist_tmp.load_defaults(false); - plist.presets.insert(plist.presets.end(), plist_tmp.presets.begin(), plist_tmp.presets.end()); - - // XXXKF this assumes that plugin name in preset is case-insensitive equal to plugin label - // if I forget about this, I'll be in a deep trouble - dssi_default_program.Bank = 0; - dssi_default_program.Program = 0; - dssi_default_program.Name = "default"; - - int pos = 1; - for (unsigned int i = 0; i < plist.presets.size(); i++) - { - plugin_preset &pp = plist.presets[i]; - if (strcasecmp(pp.plugin.c_str(), descriptor.Label)) - continue; - DSSI_Program_Descriptor pd; - pd.Bank = pos >> 7; - pd.Program = pos++; - pd.Name = pp.name.c_str(); - preset_descs->push_back(pd); - presets->push_back(pp); - } -#endif -} - -ladspa_plugin_metadata_set::~ladspa_plugin_metadata_set() -{ - delete []descriptor.PortNames; - delete []descriptor.PortDescriptors; - delete []descriptor.PortRangeHints; -#if USE_DSSI - if (presets) - presets->clear(); - if (preset_descs) - preset_descs->clear(); - delete presets; - delete preset_descs; -#endif -} - -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -481,7 +38,7 @@ ladspa_plugin_metadata_set::~ladspa_plugin_metadata_set() // instantiate descriptor templates template LV2_Descriptor calf_plugins::lv2_wrapper::descriptor; template LV2_Calf_Descriptor calf_plugins::lv2_wrapper::calf_descriptor; -template LV2_Persist calf_plugins::lv2_wrapper::persist; +template LV2_State_Interface calf_plugins::lv2_wrapper::state_iface; extern "C" { @@ -496,33 +53,6 @@ const LV2_Descriptor *lv2_descriptor(uint32_t index) #endif -#if USE_LADSPA -extern "C" { - -const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index) -{ - #define PER_MODULE_ITEM(name, isSynth, jackname) if (!isSynth && !(Index--)) return &ladspa_wrapper::get().descriptor; - #include - return NULL; -} - -}; - -#if USE_DSSI -extern "C" { - -const DSSI_Descriptor *dssi_descriptor(unsigned long Index) -{ - #define PER_MODULE_ITEM(name, isSynth, jackname) if (!(Index--)) return &calf_plugins::ladspa_wrapper::get().dssi_descriptor; - #include - return NULL; -} - -}; -#endif - -#endif - #if USE_JACK extern "C" {