diff --git a/plugins/ladspa_effect/calf/CMakeLists.txt b/plugins/ladspa_effect/calf/CMakeLists.txt index 22a75d7fe..fb4e10cec 100644 --- a/plugins/ladspa_effect/calf/CMakeLists.txt +++ b/plugins/ladspa_effect/calf/CMakeLists.txt @@ -1,6 +1,6 @@ FILE(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) ADD_LIBRARY(calf MODULE ${SOURCES}) -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/calf) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src) INSTALL(TARGETS calf LIBRARY DESTINATION ${PLUGIN_DIR}/ladspa) ADD_DEFINITIONS(-DUSE_LADSPA=1) SET_TARGET_PROPERTIES(calf PROPERTIES PREFIX "") diff --git a/plugins/ladspa_effect/calf/calf/ladspa_wrap.h b/plugins/ladspa_effect/calf/calf/ladspa_wrap.h deleted file mode 100644 index 2f98dcf83..000000000 --- a/plugins/ladspa_effect/calf/calf/ladspa_wrap.h +++ /dev/null @@ -1,516 +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 -#if USE_DSSI -#include -#endif -#include "giface.h" - -namespace calf_plugins { - -template -inline int calc_real_param_count() -{ - for (int i=0; i < Module::param_count; i++) - { - if ((Module::param_props[i].flags & PF_TYPEMASK) >= PF_STRING) - return i; - } - return Module::param_count; -} - -/// A template implementing plugin_ctl_iface for a given plugin -template -struct ladspa_instance: public Module, public plugin_ctl_iface -{ - bool activate_flag; -#if USE_DSSI - dssi_feedback_sender *feedback_sender; -#endif - - static int real_param_count() - { - static int _real_param_count = calc_real_param_count(); - return _real_param_count; - } - ladspa_instance() - { - for (int i=0; i < Module::in_count; i++) - Module::ins[i] = NULL; - for (int i=0; i < Module::out_count; i++) - Module::outs[i] = NULL; - int rpc = real_param_count(); - for (int i=0; i < rpc; i++) - Module::params[i] = NULL; - activate_flag = true; -#if USE_DSSI - feedback_sender = NULL; -#endif - } - virtual parameter_properties *get_param_props(int param_no) - { - return &Module::param_props[param_no]; - } - virtual float get_param_value(int param_no) - { - // XXXKF hack - if (param_no >= real_param_count()) - return 0; - return *Module::params[param_no]; - } - virtual void set_param_value(int param_no, float value) - { - // XXXKF hack - if (param_no >= real_param_count()) - return; - *Module::params[param_no] = value; - } - virtual int get_param_count() - { - return real_param_count(); - } - virtual int get_param_port_offset() - { - return Module::in_count + Module::out_count; - } - virtual const char *get_gui_xml() { - return Module::get_gui_xml(); - } - virtual const line_graph_iface *get_line_graph_iface() const - { - return dynamic_cast(this); - } - virtual bool activate_preset(int bank, int program) { - return false; - } - virtual const char *get_name() - { - return Module::get_name(); - } - virtual const char *get_id() - { - return Module::get_id(); - } - virtual const char *get_label() - { - return Module::get_label(); - } - virtual char *configure(const char *key, const char *value) - { -#if USE_DSSI - if (!strcmp(key, "OSC:FEEDBACK_URI")) - { - line_graph_iface *lgi = dynamic_cast(this); - if (!lgi) - return NULL; - if (*value) - { - if (feedback_sender) { - delete feedback_sender; - feedback_sender = NULL; - } - feedback_sender = new dssi_feedback_sender(value, lgi, get_param_props(0), 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 -#endif - if (!strcmp(key, "ExecCommand")) - { - if (*value) - { - execute(atoi(value)); - } - return NULL; - } - return Module::configure(key, value); - } - virtual int get_input_count() { return Module::in_count; } - virtual int get_output_count() { return Module::out_count; } - virtual bool get_midi() { return Module::support_midi; } - 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); - } -}; - -/// A wrapper class for plugin class object (there is only one ladspa_wrapper for many instances of the same plugin) -template -struct ladspa_wrapper -{ - typedef ladspa_instance instance; - - /// LADSPA descriptor - static LADSPA_Descriptor descriptor; - /// LADSPA descriptor for DSSI (uses a different name for the plugin, otherwise same as descriptor) - static LADSPA_Descriptor descriptor_for_dssi; -#if USE_DSSI - /// Extended DSSI descriptor (points to descriptor_for_dssi for things like name/label/port info etc.) - static DSSI_Descriptor dssi_descriptor; - static DSSI_Program_Descriptor dssi_default_program; - - static std::vector *presets; - static std::vector *preset_descs; -#endif - - ladspa_wrapper() - { - int ins = Module::in_count; - int outs = Module::out_count; - int params = ladspa_instance::real_param_count(); - ladspa_plugin_info &plugin_info = Module::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 = Module::rt_capable ? LADSPA_PROPERTY_HARD_RT_CAPABLE : 0; - descriptor.PortCount = ins + outs + params; - 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 < ins + outs; i++) - { - LADSPA_PortRangeHint &prh = ((LADSPA_PortRangeHint *)descriptor.PortRangeHints)[i]; - ((int *)descriptor.PortDescriptors)[i] = i < ins ? LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO - : i < ins + outs ? LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO - : LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; - prh.HintDescriptor = 0; - ((const char **)descriptor.PortNames)[i] = Module::port_names[i]; - } - for (; i < ins + outs + params; i++) - { - LADSPA_PortRangeHint &prh = ((LADSPA_PortRangeHint *)descriptor.PortRangeHints)[i]; - parameter_properties &pp = Module::param_props[i - ins - outs]; - ((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; -#if USE_DSSI - 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 (Module::support_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); - } - // printf("presets = %p:%d name = %s\n", presets, presets->size(), descriptor.Label); - -#endif - } - - ~ladspa_wrapper() - { - delete []descriptor.PortNames; - delete []descriptor.PortDescriptors; - delete []descriptor.PortRangeHints; -#if USE_DSSI - presets->clear(); - preset_descs->clear(); - delete presets; - delete preset_descs; -#endif - } - - /// LADSPA instantiation function (create a plugin instance) - static LADSPA_Handle cb_instantiate(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate) - { - instance *mod = new instance(); - mod->set_sample_rate(sample_rate); - mod->post_instantiate(); - return mod; - } - -#if USE_DSSI - /// 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) { - if (index > presets->size()) - return NULL; - if (index) - return &(*preset_descs)[index - 1]; - return &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) { - instance *mod = (instance *)Instance; - unsigned int no = (Bank << 7) + Program - 1; - // printf("no = %d presets = %p:%d\n", no, presets, presets->size()); - if (no == -1U) { - int rpc = ladspa_instance::real_param_count(); - for (int i =0 ; i < rpc; i++) - *mod->params[i] = Module::param_props[i].def_value; - return; - } - if (no >= presets->size()) - return; - plugin_preset &p = (*presets)[no]; - // printf("activating preset %s\n", p.name.c_str()); - p.activate(mod); - } - -#endif - - /// LADSPA port connection function - static void cb_connect(LADSPA_Handle Instance, unsigned long port, LADSPA_Data *DataLocation) { - unsigned long ins = Module::in_count; - unsigned long outs = Module::out_count; - unsigned long params = ladspa_instance::real_param_count(); - instance *const mod = (instance *)Instance; - if (port < ins) - mod->ins[port] = DataLocation; - else if (port < ins + outs) - mod->outs[port - ins] = DataLocation; - else if (port < ins + outs + params) { - int i = port - ins - outs; - mod->params[i] = DataLocation; - *mod->params[i] = Module::param_props[i].def_value; - } - } - - /// LADSPA activate function (note that at this moment the ports are not set) - static void cb_activate(LADSPA_Handle Instance) { - instance *const mod = (instance *)Instance; - mod->activate_flag = true; - } - - /// utility function: zero port values if mask is 0 - static inline void zero_by_mask(Module *module, uint32_t mask, uint32_t offset, uint32_t nsamples) - { - for (int i=0; iouts[i] + offset, nsamples); - } - } - } - - /// 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) { - instance *const mod = (instance *)Instance; - if (mod->activate_flag) - { - mod->activate(); - mod->activate_flag = false; - } - mod->params_changed(); - process_slice(mod, 0, SampleCount); - } - - /// utility function: call process, and if it returned zeros in output masks, zero out the relevant output port buffers - static inline void process_slice(Module *mod, uint32_t offset, uint32_t end) - { - while(offset < end) - { - uint32_t newend = std::min(offset + MAX_SAMPLE_RUN, end); - uint32_t out_mask = mod->process(offset, newend - offset, -1, -1); - zero_by_mask(mod, out_mask, offset, newend - offset); - offset = newend; - } - } - -#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) { - instance *const mod = (instance *)Instance; - if (mod->activate_flag) - { - mod->activate(); - mod->activate_flag = false; - } - mod->params_changed(); - - uint32_t offset = 0; - for (uint32_t e = 0; e < EventCount; e++) - { - uint32_t timestamp = Events[e].time.tick; - if (timestamp != offset) - process_slice(mod, offset, timestamp); - process_dssi_event(mod, Events[e]); - offset = timestamp; - } - if (offset != SampleCount) - process_slice(mod, offset, SampleCount); - } - - /// DSSI configure function (named properties) - static char *cb_configure(LADSPA_Handle Instance, - const char *Key, - const char *Value) - { - instance *const mod = (instance *)Instance; - return mod->configure(Key, Value); - } - - /// Utility function: handle MIDI event (only handles a subset in this version) - static void process_dssi_event(Module *module, snd_seq_event_t &event) - { - switch(event.type) { - case SND_SEQ_EVENT_NOTEON: - module->note_on(event.data.note.note, event.data.note.velocity); - break; - case SND_SEQ_EVENT_NOTEOFF: - module->note_off(event.data.note.note, event.data.note.velocity); - break; - case SND_SEQ_EVENT_PGMCHANGE: - module->program_change(event.data.control.value); - break; - case SND_SEQ_EVENT_CONTROLLER: - module->control_change(event.data.control.param, event.data.control.value); - break; - case SND_SEQ_EVENT_PITCHBEND: - module->pitch_bend(event.data.control.value); - break; - } - } -#endif - - /// LADSPA deactivate function - static void cb_deactivate(LADSPA_Handle Instance) { - instance *const mod = (instance *)Instance; - mod->deactivate(); - } - - /// LADSPA cleanup (delete instance) function - static void cb_cleanup(LADSPA_Handle Instance) { - instance *const mod = (instance *)Instance; - delete mod; - } - - /// Get a wrapper singleton - used to prevent initialization order problems which were present in older versions - static ladspa_wrapper &get() { - static ladspa_wrapper instance; - return instance; - } -}; - -}; - -#endif - -#endif diff --git a/plugins/ladspa_effect/calf/calf/lv2helpers.h b/plugins/ladspa_effect/calf/calf/lv2helpers.h deleted file mode 100644 index c5a2452c3..000000000 --- a/plugins/ladspa_effect/calf/calf/lv2helpers.h +++ /dev/null @@ -1,281 +0,0 @@ -/* Calf DSP Library - * LV2-related helper classes and functions - * - * Copyright (C) 2001-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_LV2HELPERS_H -#define CALF_LV2HELPERS_H - -#if USE_LV2 - -#include -#include - -class uri_map_access -{ -public: - /// URI map feature pointer (previously in a mixin, but polymorphic ports made it necessary for most plugins) - LV2_URI_Map_Feature *uri_map; - - uri_map_access() - : uri_map(NULL) - {} - - /// Map an URI through an URI map - uint32_t map_uri(const char *ns, const char *URI) - { - if (uri_map) - return uri_map->uri_to_id(uri_map->callback_data, ns, URI); - return 0; - } - /// Called on instantiation for every LV2 feature sent by a host - void use_feature(const char *URI, void *data) { - if (!strcmp(URI, LV2_URI_MAP_URI)) - { - uri_map = (LV2_URI_Map_Feature *)data; - map_uris(); - } - } - virtual void map_uris() - { - } - virtual ~uri_map_access() {} -}; - -/// A mixin for adding the event feature and URI map to the small plugin -template -class event_mixin: public T -{ -public: - /// Event feature pointer - LV2_Event_Feature *event_feature; - virtual void use_feature(const char *URI, void *data) { - if (!strcmp(URI, LV2_EVENT_URI)) - { - event_feature = (LV2_Event_Feature *)data; - } - T::use_feature(URI, data); - } - /// Create a reference - inline void ref_event(LV2_Event *event) { event_feature->lv2_event_ref(event_feature->callback_data, event); } - /// Destroy a reference - inline void unref_event(LV2_Event *event) { event_feature->lv2_event_unref(event_feature->callback_data, event); } -}; - -/// A mixin for adding the URI map and MIDI event type retrieval to small plugins -template -class midi_mixin: public virtual event_mixin -{ -public: - /// MIDI event ID, as resolved using the URI map feature - uint32_t midi_event_type; - virtual void map_uris() { - midi_event_type = this->map_uri("http://lv2plug.in/ns/ext/event", "http://lv2plug.in/ns/ext/midi#MidiEvent"); - printf("MIDI event type = %d\n", midi_event_type); - event_mixin::map_uris(); - } -}; - -/// A mixin for adding the URI map and MIDI event type retrieval to small plugins -template -class message_mixin: public virtual event_mixin -{ -public: - /// MIDI event ID, as resolved using the URI map feature - uint32_t message_event_type; - virtual void map_uris() { - message_event_type = this->map_uri("http://lv2plug.in/ns/ext/event", "http://lv2plug.in/ns/dev/msg#MessageEvent"); - printf("Message event type = %d\n", message_event_type); - event_mixin::map_uris(); - } -}; - -/// LV2 event structure + payload as 0-length array for easy access -struct lv2_event: public LV2_Event -{ - uint8_t data[]; - inline lv2_event &operator=(const lv2_event &src) { - *(LV2_Event *)this = (const LV2_Event &)src; - memcpy(data, src.data, src.size); - return *this; - } - /// Returns a 64-bit timestamp for easy and inefficient comparison - inline uint64_t timestamp() const { - return ((uint64_t)frames << 32) | subframes; - } -private: - /// forbid default constructor - this object cannot be constructed, only obtained via cast from LV2_Event* (or &) to lv2_event* (or &) - lv2_event() {} - /// forbid copy constructor - see default constructor - lv2_event(const lv2_event &) {} -}; - -/// A read-only iterator-like object for reading from event buffers -class event_port_read_iterator -{ -protected: - const LV2_Event_Buffer *buffer; - uint32_t offset; -public: - /// Default constructor creating a useless iterator you can assign to - event_port_read_iterator() - : buffer(NULL) - , offset(0) - { - } - - /// Create an iterator based on specified buffer and index/offset values - event_port_read_iterator(const LV2_Event_Buffer *_buffer, uint32_t _offset = 0) - : buffer(_buffer) - , offset(0) - { - } - - /// Are any data left to be read? - inline operator bool() const { - return offset < buffer->size; - } - - /// Read pointer - inline const lv2_event &operator*() const { - return *(const lv2_event *)(buffer->data + offset); - } - /// Pointer to member - inline const lv2_event *operator->() const { - return &**this; - } - - /// Move to the next element - inline event_port_read_iterator operator++() { - offset += ((**this).size + 19) &~7; - return *this; - } - - /// Move to the next element - inline event_port_read_iterator operator++(int) { - event_port_read_iterator old = *this; - offset += ((**this).size + 19) &~7; - return old; - } -}; - -/// A write-only iterator-like object for writing to event buffers -class event_port_write_iterator -{ -protected: - LV2_Event_Buffer *buffer; -public: - /// Default constructor creating a useless iterator you can assign to - event_port_write_iterator() - : buffer(NULL) - { - } - - /// Create a write iterator based on specified buffer and index/offset values - event_port_write_iterator(LV2_Event_Buffer *_buffer) - : buffer(_buffer) - { - } - - /// @return the remaining buffer space - inline uint32_t space_left() const { - return buffer->capacity - buffer->size; - } - /// @return write pointer - inline lv2_event &operator*() { - return *(lv2_event *)(buffer->data + buffer->size); - } - /// Pointer to member - inline lv2_event *operator->() { - return &**this; - } - /// Move to the next element after the current one has been written (must be called after each write) - inline event_port_write_iterator operator++() { - buffer->size += ((**this).size + 19) &~7; - buffer->event_count ++; - return *this; - } - /// Move to the next element after the current one has been written - inline lv2_event *operator++(int) { - lv2_event *ptr = &**this; - buffer->size += ((**this).size + 19) &~7; - buffer->event_count ++; - return ptr; - } -}; - -template -class event_port_merge_iterator -{ -public: - Iter1 first; - Iter2 second; -public: - event_port_merge_iterator() {} - event_port_merge_iterator(const Iter1 &_first, const Iter2 &_second) - : first(_first) - , second(_second) - { - } - /// @retval true if any of the iterators have any data left - inline operator bool() const { - return ((bool)first) || ((bool)second); - } - inline bool select_first() const - { - if (!(bool)second) - return true; - if (!(bool)first) - return false; - return first->timestamp() < second->timestamp(); - } - /// Returns the earliest of (*first, *second) - inline const lv2_event &operator*() const { - if (select_first()) - { - assert((bool)first); - return *first; - } - assert((bool)second); - return *second; - } - /// Pointer to member - inline const lv2_event *operator->() const { - return &**this; - } - /// Prefix increment - inline event_port_merge_iterator operator++() { - if (select_first()) - first++; - else - second++; - return *this; - } - /// Postfix increment - inline event_port_merge_iterator operator++(int) { - event_port_merge_iterator ptr = *this; - if (select_first()) - first++; - else - second++; - return ptr; - } -}; - -#endif -#endif diff --git a/plugins/ladspa_effect/calf/calf/modules.h b/plugins/ladspa_effect/calf/calf/modules.h deleted file mode 100644 index 6bce138e3..000000000 --- a/plugins/ladspa_effect/calf/calf/modules.h +++ /dev/null @@ -1,1199 +0,0 @@ -/* Calf DSP Library - * Example audio modules - * - * Copyright (C) 2001-2007 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_MODULES_H -#define __CALF_MODULES_H - -#include -#include -#include "biquad.h" -#include "inertia.h" -#include "audio_fx.h" -#include "multichorus.h" -#include "giface.h" -#include "metadata.h" -#include "loudness.h" -#include "primitives.h" - -namespace calf_plugins { - -using namespace dsp; - -struct ladspa_plugin_info; - -#if 0 -class amp_audio_module: public null_audio_module -{ -public: - enum { in_count = 2, out_count = 2, param_count = 1, support_midi = false, require_midi = false, rt_capable = true }; - float *ins[2]; - float *outs[2]; - float *params[1]; - uint32_t srate; - static parameter_properties param_props[]; - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { - if (!inputs_mask) - return 0; - float gain = *params[0]; - numsamples += offset; - for (uint32_t i = offset; i < numsamples; i++) { - outs[0][i] = ins[0][i] * gain; - outs[1][i] = ins[1][i] * gain; - } - return inputs_mask; - } -}; -#endif - -class frequency_response_line_graph: public line_graph_iface -{ -public: - bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; - virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; -}; - -class flanger_audio_module: public audio_module, public frequency_response_line_graph -{ -public: - dsp::simple_flanger left, right; - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool clear_reset; - float last_r_phase; - bool is_active; -public: - flanger_audio_module() { - is_active = false; - } - void set_sample_rate(uint32_t sr); - void params_changed() { - float dry = *params[par_dryamount]; - float wet = *params[par_amount]; - float rate = *params[par_rate]; // 0.01*pow(1000.0f,*params[par_rate]); - float min_delay = *params[par_delay] / 1000.0; - float mod_depth = *params[par_depth] / 1000.0; - float fb = *params[par_fb]; - left.set_dry(dry); right.set_dry(dry); - left.set_wet(wet); right.set_wet(wet); - left.set_rate(rate); right.set_rate(rate); - left.set_min_delay(min_delay); right.set_min_delay(min_delay); - left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth); - left.set_fb(fb); right.set_fb(fb); - float r_phase = *params[par_stereo] * (1.f / 360.f); - clear_reset = false; - if (*params[par_reset] >= 0.5) { - clear_reset = true; - left.reset_phase(0.f); - right.reset_phase(r_phase); - } else { - if (fabs(r_phase - last_r_phase) > 0.0001f) { - right.phase = left.phase; - right.inc_phase(r_phase); - last_r_phase = r_phase; - } - } - } - void params_reset() - { - if (clear_reset) { - *params[par_reset] = 0.f; - clear_reset = false; - } - } - void activate(); - void deactivate(); - uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) { - left.process(outs[0] + offset, ins[0] + offset, nsamples); - right.process(outs[1] + offset, ins[1] + offset, nsamples); - return outputs_mask; // XXXKF allow some delay after input going blank - } - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - float freq_gain(int subindex, float freq, float srate) const; -}; - -class phaser_audio_module: public audio_module, public frequency_response_line_graph -{ -public: - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool clear_reset; - float last_r_phase; - dsp::simple_phaser<12> left, right; - bool is_active; -public: - phaser_audio_module() { - is_active = false; - } - void params_changed() { - float dry = *params[par_dryamount]; - float wet = *params[par_amount]; - float rate = *params[par_rate]; // 0.01*pow(1000.0f,*params[par_rate]); - float base_frq = *params[par_freq]; - float mod_depth = *params[par_depth]; - float fb = *params[par_fb]; - int stages = (int)*params[par_stages]; - left.set_dry(dry); right.set_dry(dry); - left.set_wet(wet); right.set_wet(wet); - left.set_rate(rate); right.set_rate(rate); - left.set_base_frq(base_frq); right.set_base_frq(base_frq); - left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth); - left.set_fb(fb); right.set_fb(fb); - left.set_stages(stages); right.set_stages(stages); - float r_phase = *params[par_stereo] * (1.f / 360.f); - clear_reset = false; - if (*params[par_reset] >= 0.5) { - clear_reset = true; - left.reset_phase(0.f); - right.reset_phase(r_phase); - } else { - if (fabs(r_phase - last_r_phase) > 0.0001f) { - right.phase = left.phase; - right.inc_phase(r_phase); - last_r_phase = r_phase; - } - } - } - void params_reset() - { - if (clear_reset) { - *params[par_reset] = 0.f; - clear_reset = false; - } - } - void activate(); - void set_sample_rate(uint32_t sr); - void deactivate(); - uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) { - left.process(outs[0] + offset, ins[0] + offset, nsamples); - right.process(outs[1] + offset, ins[1] + offset, nsamples); - return outputs_mask; // XXXKF allow some delay after input going blank - } - 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; - float freq_gain(int subindex, float freq, float srate) const; -}; - -class reverb_audio_module: public audio_module -{ -public: - dsp::reverb reverb; - dsp::simple_delay<16384, stereo_sample > pre_delay; - dsp::onepole left_lo, right_lo, left_hi, right_hi; - uint32_t srate; - gain_smoothing amount, dryamount; - int predelay_amt; - float meter_wet, meter_out; - uint32_t clip; - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - - void params_changed() { - //reverb.set_time(0.5*pow(8.0f, *params[par_decay])); - //reverb.set_cutoff(2000*pow(10.0f, *params[par_hfdamp])); - reverb.set_type_and_diffusion(fastf2i_drm(*params[par_roomsize]), *params[par_diffusion]); - reverb.set_time(*params[par_decay]); - reverb.set_cutoff(*params[par_hfdamp]); - amount.set_inertia(*params[par_amount]); - dryamount.set_inertia(*params[par_dry]); - left_lo.set_lp(dsp::clip(*params[par_treblecut], 20.f, (float)(srate * 0.49f)), srate); - left_hi.set_hp(dsp::clip(*params[par_basscut], 20.f, (float)(srate * 0.49f)), srate); - right_lo.copy_coeffs(left_lo); - right_hi.copy_coeffs(left_hi); - predelay_amt = (int) (srate * (*params[par_predelay]) * (1.0f / 1000.0f) + 1); - } - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { - numsamples += offset; - clip -= std::min(clip, numsamples); - for (uint32_t i = offset; i < numsamples; i++) { - float dry = dryamount.get(); - float wet = amount.get(); - stereo_sample s(ins[0][i], ins[1][i]); - stereo_sample s2 = pre_delay.process(s, predelay_amt); - - float rl = s2.left, rr = s2.right; - rl = left_lo.process(left_hi.process(rl)); - rr = right_lo.process(right_hi.process(rr)); - reverb.process(rl, rr); - outs[0][i] = dry*s.left + wet*rl; - outs[1][i] = dry*s.right + wet*rr; - meter_wet = std::max(fabs(wet*rl), fabs(wet*rr)); - meter_out = std::max(fabs(outs[0][i]), fabs(outs[1][i])); - if(outs[0][i] > 1.f or outs[1][i] > 1.f) { - clip = srate >> 3; - } - } - reverb.extra_sanitize(); - left_lo.sanitize(); - left_hi.sanitize(); - right_lo.sanitize(); - right_hi.sanitize(); - if(params[par_meter_wet] != NULL) { - *params[par_meter_wet] = meter_wet; - } - if(params[par_meter_out] != NULL) { - *params[par_meter_out] = meter_out; - } - if(params[par_clip] != NULL) { - *params[par_clip] = clip; - } - return outputs_mask; - } - void activate(); - void set_sample_rate(uint32_t sr); - void deactivate(); -}; - -class vintage_delay_audio_module: public audio_module -{ -public: - // 1MB of delay memory per channel... uh, RAM is cheap - enum { MAX_DELAY = 262144, ADDR_MASK = MAX_DELAY - 1 }; - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - float buffers[2][MAX_DELAY]; - int bufptr, deltime_l, deltime_r, mixmode, medium, old_medium; - /// number of table entries written (value is only important when it is less than MAX_DELAY, which means that the buffer hasn't been totally filled yet) - int age; - - gain_smoothing amt_left, amt_right, fb_left, fb_right; - float dry; - - dsp::biquad_d2 biquad_left[2], biquad_right[2]; - - uint32_t srate; - - vintage_delay_audio_module() - { - old_medium = -1; - for (int i = 0; i < MAX_DELAY; i++) { - buffers[0][i] = 0.f; - buffers[1][i] = 0.f; - } - } - - void params_changed() - { - float unit = 60.0 * srate / (*params[par_bpm] * *params[par_divide]); - deltime_l = dsp::fastf2i_drm(unit * *params[par_time_l]); - deltime_r = dsp::fastf2i_drm(unit * *params[par_time_r]); - amt_left.set_inertia(*params[par_amount]); amt_right.set_inertia(*params[par_amount]); - float fb = *params[par_feedback]; - dry = *params[par_dryamount]; - mixmode = dsp::fastf2i_drm(*params[par_mixmode]); - medium = dsp::fastf2i_drm(*params[par_medium]); - if (mixmode == 0) - { - fb_left.set_inertia(fb); - fb_right.set_inertia(pow(fb, *params[par_time_r] / *params[par_time_l])); - } else { - fb_left.set_inertia(fb); - fb_right.set_inertia(fb); - } - if (medium != old_medium) - calc_filters(); - } - void activate() { - bufptr = 0; - age = 0; - } - void deactivate() { - } - void set_sample_rate(uint32_t sr) { - srate = sr; - old_medium = -1; - amt_left.set_sample_rate(sr); amt_right.set_sample_rate(sr); - fb_left.set_sample_rate(sr); fb_right.set_sample_rate(sr); - } - void calc_filters() - { - // parameters are heavily influenced by gordonjcp and his tape delay unit - // although, don't blame him if it sounds bad - I've messed with them too :) - biquad_left[0].set_lp_rbj(6000, 0.707, srate); - biquad_left[1].set_bp_rbj(4500, 0.250, srate); - biquad_right[0].copy_coeffs(biquad_left[0]); - biquad_right[1].copy_coeffs(biquad_left[1]); - } - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { - uint32_t ostate = 3; // XXXKF optimize! - uint32_t end = offset + numsamples; - int v = mixmode ? 1 : 0; - int orig_bufptr = bufptr; - for(uint32_t i = offset; i < end; i++) - { - float out_left, out_right, del_left, del_right; - // if the buffer hasn't been cleared yet (after activation), pretend we've read zeros - - if (deltime_l >= age) { - del_left = ins[0][i]; - out_left = dry * del_left; - amt_left.step(); - fb_left.step(); - } - else - { - float in_left = buffers[v][(bufptr - deltime_l) & ADDR_MASK]; - dsp::sanitize(in_left); - out_left = dry * ins[0][i] + in_left * amt_left.get(); - del_left = ins[0][i] + in_left * fb_left.get(); - } - if (deltime_r >= age) { - del_right = ins[1][i]; - out_right = dry * del_right; - amt_right.step(); - fb_right.step(); - } - else - { - float in_right = buffers[1 - v][(bufptr - deltime_r) & ADDR_MASK]; - dsp::sanitize(in_right); - out_right = dry * ins[1][i] + in_right * amt_right.get(); - del_right = ins[1][i] + in_right * fb_right.get(); - } - - age++; - outs[0][i] = out_left; outs[1][i] = out_right; buffers[0][bufptr] = del_left; buffers[1][bufptr] = del_right; - bufptr = (bufptr + 1) & (MAX_DELAY - 1); - } - if (age >= MAX_DELAY) - age = MAX_DELAY; - if (medium > 0) { - bufptr = orig_bufptr; - if (medium == 2) - { - for(uint32_t i = offset; i < end; i++) - { - buffers[0][bufptr] = biquad_left[0].process_lp(biquad_left[1].process(buffers[0][bufptr])); - buffers[1][bufptr] = biquad_right[0].process_lp(biquad_right[1].process(buffers[1][bufptr])); - bufptr = (bufptr + 1) & (MAX_DELAY - 1); - } - biquad_left[0].sanitize();biquad_right[0].sanitize(); - } else { - for(uint32_t i = offset; i < end; i++) - { - buffers[0][bufptr] = biquad_left[1].process(buffers[0][bufptr]); - buffers[1][bufptr] = biquad_right[1].process(buffers[1][bufptr]); - bufptr = (bufptr + 1) & (MAX_DELAY - 1); - } - } - biquad_left[1].sanitize();biquad_right[1].sanitize(); - - } - return ostate; - } -}; - -class rotary_speaker_audio_module: public audio_module -{ -public: - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - /// Current phases and phase deltas for bass and treble rotors - uint32_t phase_l, dphase_l, phase_h, dphase_h; - dsp::simple_delay<1024, float> delay; - dsp::biquad_d2 crossover1l, crossover1r, crossover2l, crossover2r; - dsp::simple_delay<8, float> phaseshift; - uint32_t srate; - int vibrato_mode; - /// Current CC1 (Modulation) value, normalized to [0, 1] - float mwhl_value; - /// Current CC64 (Hold) value, normalized to [0, 1] - float hold_value; - /// Current rotation speed for bass rotor - automatic mode - float aspeed_l; - /// Current rotation speed for treble rotor - automatic mode - float aspeed_h; - /// Desired speed (0=slow, 1=fast) - automatic mode - float dspeed; - /// Current rotation speed for bass rotor - manual mode - float maspeed_l; - /// Current rotation speed for treble rotor - manual mode - float maspeed_h; - - int meter_l, meter_h; - - rotary_speaker_audio_module(); - void set_sample_rate(uint32_t sr); - void setup(); - void activate(); - void deactivate(); - - void params_changed() { - set_vibrato(); - } - void set_vibrato() - { - vibrato_mode = fastf2i_drm(*params[par_speed]); - // manual vibrato - do not recalculate speeds as they're not used anyway - if (vibrato_mode == 5) - return; - if (!vibrato_mode) - dspeed = -1; - else { - float speed = vibrato_mode - 1; - if (vibrato_mode == 3) - speed = hold_value; - if (vibrato_mode == 4) - speed = mwhl_value; - dspeed = (speed < 0.5f) ? 0 : 1; - } - update_speed(); - } - /// Convert RPM speed to delta-phase - inline uint32_t rpm2dphase(float rpm) - { - return (uint32_t)((rpm / (60.0 * srate)) * (1 << 30)) << 2; - } - /// Set delta-phase variables based on current calculated (and interpolated) RPM speed - void update_speed() - { - float speed_h = aspeed_h >= 0 ? (48 + (400-48) * aspeed_h) : (48 * (1 + aspeed_h)); - float speed_l = aspeed_l >= 0 ? 40 + (342-40) * aspeed_l : (40 * (1 + aspeed_l)); - dphase_h = rpm2dphase(speed_h); - dphase_l = rpm2dphase(speed_l); - } - void update_speed_manual(float delta) - { - float ts = *params[par_treblespeed]; - float bs = *params[par_bassspeed]; - incr_towards(maspeed_h, ts, delta * 200, delta * 200); - incr_towards(maspeed_l, bs, delta * 200, delta * 200); - dphase_h = rpm2dphase(maspeed_h); - dphase_l = rpm2dphase(maspeed_l); - } - /// map a ramp [int] to a sinusoid-like function [0, 65536] - static inline int pseudo_sine_scl(int counter) - { - // premature optimization is a root of all evil; it can be done with integers only - but later :) - double v = counter * (1.0 / (65536.0 * 32768.0)); - return (int) (32768 + 32768 * (v - v*v*v) * (1.0 / 0.3849)); - } - /// Increase or decrease aspeed towards raspeed, with required negative and positive rate - inline bool incr_towards(float &aspeed, float raspeed, float delta_decc, float delta_acc) - { - if (aspeed < raspeed) { - aspeed = std::min(raspeed, aspeed + delta_acc); - return true; - } - else if (aspeed > raspeed) - { - aspeed = std::max(raspeed, aspeed - delta_decc); - return true; - } - return false; - } - uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) - { - int shift = (int)(300000 * (*params[par_shift])), pdelta = (int)(300000 * (*params[par_spacing])); - int md = (int)(100 * (*params[par_moddepth])); - float mix = 0.5 * (1.0 - *params[par_micdistance]); - float mix2 = *params[par_reflection]; - float mix3 = mix2 * mix2; - for (unsigned int i = 0; i < nsamples; i++) { - float in_l = ins[0][i + offset], in_r = ins[1][i + offset]; - float in_mono = 0.5f * (in_l + in_r); - - int xl = pseudo_sine_scl(phase_l), yl = pseudo_sine_scl(phase_l + 0x40000000); - int xh = pseudo_sine_scl(phase_h), yh = pseudo_sine_scl(phase_h + 0x40000000); - // printf("%d %d %d\n", shift, pdelta, shift + pdelta + 20 * xl); - meter_l = xl; - meter_h = xh; - // float out_hi_l = in_mono - delay.get_interp_1616(shift + md * xh) + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) - delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh); - // float out_hi_r = in_mono + delay.get_interp_1616(shift + md * 65536 - md * yh) - delay.get_interp_1616(shift + pdelta + md * xh) + delay.get_interp_1616(shift + pdelta + pdelta + md * yh); - float out_hi_l = in_mono + delay.get_interp_1616(shift + md * xh) - mix2 * delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) + mix3 * delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh); - float out_hi_r = in_mono + delay.get_interp_1616(shift + md * 65536 - md * yh) - mix2 * delay.get_interp_1616(shift + pdelta + md * xh) + mix3 * delay.get_interp_1616(shift + pdelta + pdelta + md * yh); - - float out_lo_l = in_mono + delay.get_interp_1616(shift + md * xl); // + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yl); - float out_lo_r = in_mono + delay.get_interp_1616(shift + md * yl); // - delay.get_interp_1616(shift + pdelta + md * yl); - - out_hi_l = crossover2l.process(out_hi_l); // sanitize(out_hi_l); - out_hi_r = crossover2r.process(out_hi_r); // sanitize(out_hi_r); - out_lo_l = crossover1l.process(out_lo_l); // sanitize(out_lo_l); - out_lo_r = crossover1r.process(out_lo_r); // sanitize(out_lo_r); - - float out_l = out_hi_l + out_lo_l; - float out_r = out_hi_r + out_lo_r; - - float mic_l = out_l + mix * (out_r - out_l); - float mic_r = out_r + mix * (out_l - out_r); - - outs[0][i + offset] = mic_l * 0.5f; - outs[1][i + offset] = mic_r * 0.5f; - delay.put(in_mono); - phase_l += dphase_l; - phase_h += dphase_h; - } - crossover1l.sanitize(); - crossover1r.sanitize(); - crossover2l.sanitize(); - crossover2r.sanitize(); - float delta = nsamples * 1.0 / srate; - if (vibrato_mode == 5) - update_speed_manual(delta); - else - { - bool u1 = incr_towards(aspeed_l, dspeed, delta * 0.2, delta * 0.14); - bool u2 = incr_towards(aspeed_h, dspeed, delta, delta * 0.5); - if (u1 || u2) - set_vibrato(); - } - if(params[par_meter_l] != NULL) { - *params[par_meter_l] = (float)meter_l / 65536.0; - } - if(params[par_meter_h] != NULL) { - *params[par_meter_h] = (float)meter_h / 65536.0; - } - return outputs_mask; - } - virtual void control_change(int ctl, int val); -}; - -template -class filter_module_with_inertia: public FilterClass -{ -public: - typedef filter_module_with_inertia inertia_filter_module; - - float *ins[Metadata::in_count]; - float *outs[Metadata::out_count]; - float *params[Metadata::param_count]; - - inertia inertia_cutoff, inertia_resonance, inertia_gain; - once_per_n timer; - bool is_active; - mutable volatile int last_generation, last_calculated_generation; - - filter_module_with_inertia() - : inertia_cutoff(exponential_ramp(128), 20) - , inertia_resonance(exponential_ramp(128), 20) - , inertia_gain(exponential_ramp(128), 1.0) - , timer(128) - { - is_active = false; - } - - void calculate_filter() - { - float freq = inertia_cutoff.get_last(); - // printf("freq=%g inr.cnt=%d timer.left=%d\n", freq, inertia_cutoff.count, timer.left); - // XXXKF this is resonance of a single stage, obviously for three stages, resonant gain will be different - float q = inertia_resonance.get_last(); - int mode = dsp::fastf2i_drm(*params[Metadata::par_mode]); - // printf("freq = %f q = %f mode = %d\n", freq, q, mode); - - int inertia = dsp::fastf2i_drm(*params[Metadata::par_inertia]); - if (inertia != inertia_cutoff.ramp.length()) { - inertia_cutoff.ramp.set_length(inertia); - inertia_resonance.ramp.set_length(inertia); - inertia_gain.ramp.set_length(inertia); - } - - FilterClass::calculate_filter(freq, q, mode, inertia_gain.get_last()); - } - - virtual void params_changed() - { - calculate_filter(); - } - - void on_timer() - { - int gen = last_generation; - inertia_cutoff.step(); - inertia_resonance.step(); - inertia_gain.step(); - calculate_filter(); - last_calculated_generation = gen; - } - - void activate() - { - params_changed(); - FilterClass::filter_activate(); - timer = once_per_n(FilterClass::srate / 1000); - timer.start(); - is_active = true; - } - - void set_sample_rate(uint32_t sr) - { - FilterClass::srate = sr; - } - - - void deactivate() - { - is_active = false; - } - - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { -// printf("sr=%d cutoff=%f res=%f mode=%f\n", FilterClass::srate, *params[Metadata::par_cutoff], *params[Metadata::par_resonance], *params[Metadata::par_mode]); - uint32_t ostate = 0; - numsamples += offset; - while(offset < numsamples) { - uint32_t numnow = numsamples - offset; - // if inertia's inactive, we can calculate the whole buffer at once - if (inertia_cutoff.active() || inertia_resonance.active() || inertia_gain.active()) - numnow = timer.get(numnow); - - if (outputs_mask & 1) { - ostate |= FilterClass::process_channel(0, ins[0] + offset, outs[0] + offset, numnow, inputs_mask & 1); - } - if (outputs_mask & 2) { - ostate |= FilterClass::process_channel(1, ins[1] + offset, outs[1] + offset, numnow, inputs_mask & 2); - } - - if (timer.elapsed()) { - on_timer(); - } - offset += numnow; - } - return ostate; - } -}; - -/// biquad filter module -class filter_audio_module: - public audio_module, - public filter_module_with_inertia, - public frequency_response_line_graph -{ - mutable float old_cutoff, old_resonance, old_mode; -public: - filter_audio_module() - { - last_generation = 0; - } - void params_changed() - { - inertia_cutoff.set_inertia(*params[par_cutoff]); - inertia_resonance.set_inertia(*params[par_resonance]); - inertia_filter_module::params_changed(); - } - - void activate() - { - inertia_filter_module::activate(); - } - - void set_sample_rate(uint32_t sr) - { - inertia_filter_module::set_sample_rate(sr); - } - - - void deactivate() - { - inertia_filter_module::deactivate(); - } - - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; -}; - -/// A multitap stereo chorus thing - processing -class multichorus_audio_module: public audio_module, public frequency_response_line_graph -{ -public: - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - dsp::multichorus, filter_sum, dsp::biquad_d2<> >, 4096> left, right; - float last_r_phase; - float cutoff; - bool is_active; - -public: - multichorus_audio_module() - { - is_active = false; - last_r_phase = -1; - } - - void params_changed() - { - // delicious copy-pasta from flanger module - it'd be better to keep it common or something - float dry = *params[par_dryamount]; - float wet = *params[par_amount]; - float rate = *params[par_rate]; - float min_delay = *params[par_delay] / 1000.0; - float mod_depth = *params[par_depth] / 1000.0; - float overlap = *params[par_overlap]; - left.set_dry(dry); right.set_dry(dry); - left.set_wet(wet); right.set_wet(wet); - left.set_rate(rate); right.set_rate(rate); - left.set_min_delay(min_delay); right.set_min_delay(min_delay); - left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth); - int voices = (int)*params[par_voices]; - left.lfo.set_voices(voices); right.lfo.set_voices(voices); - left.lfo.set_overlap(overlap);right.lfo.set_overlap(overlap); - float vphase = *params[par_vphase] * (1.f / 360.f); - left.lfo.vphase = right.lfo.vphase = vphase * (4096 / std::max(voices - 1, 1)); - float r_phase = *params[par_stereo] * (1.f / 360.f); - if (fabs(r_phase - last_r_phase) > 0.0001f) { - right.lfo.phase = left.lfo.phase; - right.lfo.phase += chorus_phase(r_phase * 4096); - last_r_phase = r_phase; - } - left.post.f1.set_bp_rbj(*params[par_freq], *params[par_q], srate); - left.post.f2.set_bp_rbj(*params[par_freq2], *params[par_q], srate); - right.post.f1.copy_coeffs(left.post.f1); - right.post.f2.copy_coeffs(left.post.f2); - } - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { - left.process(outs[0] + offset, ins[0] + offset, numsamples); - right.process(outs[1] + offset, ins[1] + offset, numsamples); - return outputs_mask; // XXXKF allow some delay after input going blank - } - void activate(); - void deactivate(); - void set_sample_rate(uint32_t sr); - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - float freq_gain(int subindex, float freq, float srate) const; - bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; - bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; -}; - -class gain_reduction_audio_module { -private: - float linSlope, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop; - float compressedKneeStop, adjKneeStart, thres; - float attack, release, threshold, ratio, knee, makeup, detection, stereo_link, bypass, mute, meter_out, meter_comp; - mutable float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_mute, old_detection, old_stereo_link; - mutable volatile int last_generation; - uint32_t srate; - bool is_active; - inline float output_level(float slope) const; - inline float output_gain(float linSlope, bool rms) const; -public: - gain_reduction_audio_module(); - void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu); - void update_curve(); - void process(float &left, float &right, float det_left = NULL, float det_right = NULL); - void activate(); - void deactivate(); - int id; - void set_sample_rate(uint32_t sr); - float get_output_level(); - float get_comp_level(); - virtual bool get_graph(int subindex, float *data, int points, cairo_iface *context) const; - virtual bool get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context) const; - virtual bool get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; - virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; -}; - -/// Compressor by Thor -class compressor_audio_module: public audio_module, public line_graph_iface { -private: - uint32_t clip_in, clip_out; - float meter_in, meter_out; - gain_reduction_audio_module compressor; -public: - typedef std::complex cfloat; - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool is_active; - mutable volatile int last_generation, last_calculated_generation; - compressor_audio_module(); - void activate(); - void deactivate(); - void params_changed(); - void set_sample_rate(uint32_t sr); - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; - bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; - int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; -}; - -/// Sidecain Compressor by Markus Schmidt (based on Thor's compressor and Krzysztof's filters) -class sidechaincompressor_audio_module: public audio_module, public frequency_response_line_graph { -private: - enum CalfScModes { - WIDEBAND, - DEESSER_WIDE, - DEESSER_SPLIT, - DERUMBLER_WIDE, - DERUMBLER_SPLIT, - WEIGHTED_1, - WEIGHTED_2, - WEIGHTED_3, - BANDPASS_1, - BANDPASS_2 - }; - mutable float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old; - mutable float f1_freq_old1, f2_freq_old1, f1_level_old1, f2_level_old1; - CalfScModes sc_mode; - mutable CalfScModes sc_mode_old, sc_mode_old1; - float f1_active, f2_active; - uint32_t clip_in, clip_out; - float meter_in, meter_out; - gain_reduction_audio_module compressor; - biquad_d2 f1L, f1R, f2L, f2R; -public: - typedef std::complex cfloat; - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool is_active; - mutable volatile int last_generation, last_calculated_generation; - sidechaincompressor_audio_module(); - void activate(); - void deactivate(); - void params_changed(); - inline cfloat h_z(const cfloat &z) const { - switch (sc_mode) { - default: - case WIDEBAND: - return false; - break; - case DEESSER_WIDE: - case DERUMBLER_WIDE: - case WEIGHTED_1: - case WEIGHTED_2: - case WEIGHTED_3: - case BANDPASS_2: - return f1L.h_z(z) * f2L.h_z(z); - break; - case DEESSER_SPLIT: - return f2L.h_z(z); - break; - case DERUMBLER_SPLIT: - case BANDPASS_1: - return f1L.h_z(z); - break; - } - - } - float freq_gain(int index, double freq, uint32_t sr) const - { - typedef std::complex cfloat; - freq *= 2.0 * M_PI / sr; - cfloat z = 1.0 / exp(cfloat(0.0, freq)); - - return std::abs(h_z(z)); - } - void set_sample_rate(uint32_t sr); - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; - bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; - int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; -}; - -/// Multibandcompressor by Markus Schmidt -class multibandcompressor_audio_module: public audio_module, public line_graph_iface { -private: - typedef multibandcompressor_audio_module AM; - static const int strips = 4; - bool mute[strips]; - uint32_t clip_inL, clip_inR, clip_outL, clip_outR; - float meter_inL, meter_inR, meter_outL, meter_outR; - gain_reduction_audio_module strip[strips]; - dsp::biquad_d2 lpL0, lpR0, lpL1, lpR1, lpL2, lpR2, hpL0, hpR0, hpL1, hpR1, hpL2, hpR2; - float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1]; -public: - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool is_active; - multibandcompressor_audio_module(); - void activate(); - void deactivate(); - void params_changed(); - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); - void set_sample_rate(uint32_t sr); - const gain_reduction_audio_module *get_strip_by_param_index(int index) const; - virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; - virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; - virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; -}; - -/// Deesser by Markus Schmidt (based on Thor's compressor and Krzysztof's filters) -class deesser_audio_module: public audio_module, public frequency_response_line_graph { -private: - enum CalfDeessModes { - WIDE, - SPLIT - }; - mutable float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old, f2_q_old; - mutable float f1_freq_old1, f2_freq_old1, f1_level_old1, f2_level_old1, f2_q_old1; - uint32_t detected_led; - float detected, clip_out; - uint32_t clip_led; - gain_reduction_audio_module compressor; - biquad_d2 hpL, hpR, lpL, lpR, pL, pR; -public: - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool is_active; - mutable volatile int last_generation, last_calculated_generation; - deesser_audio_module(); - void activate(); - void deactivate(); - void params_changed(); - float freq_gain(int index, double freq, uint32_t sr) const - { - return hpL.freq_gain(freq, sr) * pL.freq_gain(freq, sr); - } - void set_sample_rate(uint32_t sr); - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; - int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; -}; - -/// Equalizer N Band by Markus Schmidt (based on Krzysztof's filters) -template -class equalizerNband_audio_module: public audio_module, public frequency_response_line_graph { -public: - typedef audio_module AM; - using AM::in_count; - using AM::out_count; - using AM::param_count; - using AM::PeakBands; -private: - enum { graph_param_count = BaseClass::last_graph_param - BaseClass::first_graph_param + 1, params_per_band = AM::param_p2_active - AM::param_p1_active }; - float hp_mode_old, hp_freq_old; - float lp_mode_old, lp_freq_old; - float ls_level_old, ls_freq_old; - float hs_level_old, hs_freq_old; - float p_level_old[PeakBands], p_freq_old[PeakBands], p_q_old[PeakBands]; - mutable float old_params_for_graph[graph_param_count]; - uint32_t clip_inL, clip_outL, clip_inR, clip_outR; - float meter_inL, meter_outL, meter_inR, meter_outR; - CalfEqMode hp_mode, lp_mode; - biquad_d2 hp[3][2], lp[3][2]; - biquad_d2 lsL, lsR, hsL, hsR; - biquad_d2 pL[PeakBands], pR[PeakBands]; - - inline void process_hplp(float &left, float &right); -public: - typedef std::complex cfloat; - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool is_active; - mutable volatile int last_generation, last_calculated_generation; - equalizerNband_audio_module(); - void activate(); - void deactivate(); - - void params_changed(); - float freq_gain(int index, double freq, uint32_t sr) const; - void set_sample_rate(uint32_t sr) - { - srate = sr; - } - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; - int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; -}; - -typedef equalizerNband_audio_module equalizer5band_audio_module; -typedef equalizerNband_audio_module equalizer8band_audio_module; -typedef equalizerNband_audio_module equalizer12band_audio_module; - -/// LFO by Markus -class lfo_audio_module { -private: - float phase, freq, offset, amount; - int mode; - uint32_t srate; - bool is_active; -public: - lfo_audio_module(); - void set_params(float f, int m, float o, uint32_t sr, float amount = 1.f); - float get_value(); - void advance(uint32_t count); - void set_phase(float ph); - void activate(); - void deactivate(); - float get_value_from_phase(float ph, float off) const; - virtual bool get_graph(float *data, int points, cairo_iface *context) const; - virtual bool get_dot(float &x, float &y, int &size, cairo_iface *context) const; -}; - -/// Pulsator by Markus Schmidt -class pulsator_audio_module: public audio_module, public frequency_response_line_graph { -private: - uint32_t clip_inL, clip_inR, clip_outL, clip_outR; - float meter_inL, meter_inR, meter_outL, meter_outR; - float offset_old; - int mode_old; - bool clear_reset; - lfo_audio_module lfoL, lfoR; -public: - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - uint32_t srate; - bool is_active; - pulsator_audio_module(); - void activate(); - void deactivate(); - void params_changed(); - void set_sample_rate(uint32_t sr); - void params_reset() - { - if (clear_reset) { - *params[param_reset] = 0.f; - clear_reset = false; - } - } - uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; - bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; -}; - -/// Filterclavier --- MIDI controlled filter by Hans Baier -class filterclavier_audio_module: - public audio_module, - public filter_module_with_inertia, - public frequency_response_line_graph -{ - const float min_gain; - const float max_gain; - - int last_note; - int last_velocity; - -public: - filterclavier_audio_module() - : - min_gain(1.0), - max_gain(32.0), - last_note(-1), - last_velocity(-1) {} - - void params_changed() - { - inertia_filter_module::inertia_cutoff.set_inertia( - note_to_hz(last_note + *params[par_transpose], *params[par_detune])); - - float min_resonance = param_props[par_max_resonance].min; - inertia_filter_module::inertia_resonance.set_inertia( - (float(last_velocity) / 127.0) - // 0.001: see below - * (*params[par_max_resonance] - min_resonance + 0.001) - + min_resonance); - - adjust_gain_according_to_filter_mode(last_velocity); - - inertia_filter_module::calculate_filter(); - } - - void activate() - { - inertia_filter_module::activate(); - } - - void set_sample_rate(uint32_t sr) - { - inertia_filter_module::set_sample_rate(sr); - } - - - void deactivate() - { - inertia_filter_module::deactivate(); - } - - /// MIDI control - virtual void note_on(int note, int vel) - { - last_note = note; - last_velocity = vel; - inertia_filter_module::inertia_cutoff.set_inertia( - note_to_hz(note + *params[par_transpose], *params[par_detune])); - - float min_resonance = param_props[par_max_resonance].min; - inertia_filter_module::inertia_resonance.set_inertia( - (float(vel) / 127.0) - // 0.001: if the difference is equal to zero (which happens - // when the max_resonance knom is at minimum position - // then the filter gain doesnt seem to snap to zero on most note offs - * (*params[par_max_resonance] - min_resonance + 0.001) - + min_resonance); - - adjust_gain_according_to_filter_mode(vel); - - inertia_filter_module::calculate_filter(); - } - - virtual void note_off(int note, int vel) - { - if (note == last_note) { - inertia_filter_module::inertia_resonance.set_inertia(param_props[par_max_resonance].min); - inertia_filter_module::inertia_gain.set_inertia(min_gain); - inertia_filter_module::calculate_filter(); - last_velocity = 0; - } - } - - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; - -private: - void adjust_gain_according_to_filter_mode(int velocity) { - int mode = dsp::fastf2i_drm(*params[par_mode]); - - // for bandpasses: boost gain for velocities > 0 - if ( (mode_6db_bp <= mode) && (mode <= mode_18db_bp) ) { - // gain for velocity 0: 1.0 - // gain for velocity 127: 32.0 - float mode_max_gain = max_gain; - // max_gain is right for mode_6db_bp - if (mode == mode_12db_bp) - mode_max_gain /= 6.0; - if (mode == mode_18db_bp) - mode_max_gain /= 10.5; - - inertia_filter_module::inertia_gain.set_now( - (float(velocity) / 127.0) * (mode_max_gain - min_gain) + min_gain); - } else { - inertia_filter_module::inertia_gain.set_now(min_gain); - } - } -}; - -extern std::string get_builtin_modules_rdf(); - -}; - -#include "modules_synths.h" - -#endif diff --git a/plugins/ladspa_effect/calf/src/audio_fx.cpp b/plugins/ladspa_effect/calf/src/audio_fx.cpp new file mode 100644 index 000000000..54d6b77df --- /dev/null +++ b/plugins/ladspa_effect/calf/src/audio_fx.cpp @@ -0,0 +1,532 @@ +/* Calf DSP Library + * Reusable audio effect classes - implementation. + * + * 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 + +using namespace calf_plugins; +using namespace dsp; + +simple_phaser::simple_phaser(int _max_stages, float *x1vals, float *y1vals) +{ + max_stages = _max_stages; + x1 = x1vals; + y1 = y1vals; + + set_base_frq(1000); + set_mod_depth(1000); + set_fb(0); + state = 0; + cnt = 0; + stages = 0; + set_stages(_max_stages); +} + +void simple_phaser::set_stages(int _stages) +{ + if (_stages > stages) + { + assert(_stages <= max_stages); + if (_stages > max_stages) + _stages = max_stages; + for (int i = stages; i < _stages; i++) + { + x1[i] = x1[stages-1]; + y1[i] = y1[stages-1]; + } + } + stages = _stages; +} + +void simple_phaser::reset() +{ + cnt = 0; + state = 0; + phase.set(0); + for (int i = 0; i < max_stages; i++) + x1[i] = y1[i] = 0; + control_step(); +} + +void simple_phaser::control_step() +{ + cnt = 0; + int v = phase.get() + 0x40000000; + int sign = v >> 31; + v ^= sign; + // triangle wave, range from 0 to INT_MAX + double vf = (double)((v >> 16) * (1.0 / 16384.0) - 1); + + float freq = base_frq * pow(2.0, vf * mod_depth / 1200.0); + freq = dsp::clip(freq, 10.0, 0.49 * sample_rate); + stage1.set_ap_w(freq * (M_PI / 2.0) * odsr); + phase += dphase * 32; + for (int i = 0; i < stages; i++) + { + dsp::sanitize(x1[i]); + dsp::sanitize(y1[i]); + } + dsp::sanitize(state); +} + +void simple_phaser::process(float *buf_out, float *buf_in, int nsamples) +{ + for (int i=0; i cfloat; + freq *= 2.0 * M_PI / sr; + cfloat z = 1.0 / exp(cfloat(0.0, freq)); // z^-1 + + cfloat p = cfloat(1.0); + cfloat stg = stage1.h_z(z); + + for (int i = 0; i < stages; i++) + p = p * stg; + + p = p / (cfloat(1.0) - cfloat(fb) * p); + return std::abs(cfloat(gs_dry.get_last()) + cfloat(gs_wet.get_last()) * p); +} + +/////////////////////////////////////////////////////////////////////////////////// + +void biquad_filter_module::calculate_filter(float freq, float q, int mode, float gain) +{ + if (mode <= mode_36db_lp) { + order = mode + 1; + left[0].set_lp_rbj(freq, pow(q, 1.0 / order), srate, gain); + } else if ( mode_12db_hp <= mode && mode <= mode_36db_hp ) { + order = mode - mode_12db_hp + 1; + left[0].set_hp_rbj(freq, pow(q, 1.0 / order), srate, gain); + } else if ( mode_6db_bp <= mode && mode <= mode_18db_bp ) { + order = mode - mode_6db_bp + 1; + left[0].set_bp_rbj(freq, pow(q, 1.0 / order), srate, gain); + } else { // mode_6db_br <= mode <= mode_18db_br + order = mode - mode_6db_br + 1; + left[0].set_br_rbj(freq, order * 0.1 * q, srate, gain); + } + + right[0].copy_coeffs(left[0]); + for (int i = 1; i < order; i++) { + left[i].copy_coeffs(left[0]); + right[i].copy_coeffs(left[0]); + } +} + +void biquad_filter_module::filter_activate() +{ + for (int i=0; i < order; i++) { + left[i].reset(); + right[i].reset(); + } +} + +void biquad_filter_module::sanitize() +{ + for (int i=0; i < order; i++) { + left[i].sanitize(); + right[i].sanitize(); + } +} + +int biquad_filter_module::process_channel(uint16_t channel_no, const float *in, float *out, uint32_t numsamples, int inmask) { + dsp::biquad_d1 *filter; + switch (channel_no) { + case 0: + filter = left; + break; + + case 1: + filter = right; + break; + + default: + assert(false); + return 0; + } + + if (inmask) { + switch(order) { + case 1: + for (uint32_t i = 0; i < numsamples; i++) + out[i] = filter[0].process(in[i]); + break; + case 2: + for (uint32_t i = 0; i < numsamples; i++) + out[i] = filter[1].process(filter[0].process(in[i])); + break; + case 3: + for (uint32_t i = 0; i < numsamples; i++) + out[i] = filter[2].process(filter[1].process(filter[0].process(in[i]))); + break; + } + } else { + if (filter[order - 1].empty()) + return 0; + switch(order) { + case 1: + for (uint32_t i = 0; i < numsamples; i++) + out[i] = filter[0].process_zeroin(); + break; + case 2: + if (filter[0].empty()) + for (uint32_t i = 0; i < numsamples; i++) + out[i] = filter[1].process_zeroin(); + else + for (uint32_t i = 0; i < numsamples; i++) + out[i] = filter[1].process(filter[0].process_zeroin()); + break; + case 3: + if (filter[1].empty()) + for (uint32_t i = 0; i < numsamples; i++) + out[i] = filter[2].process_zeroin(); + else + for (uint32_t i = 0; i < numsamples; i++) + out[i] = filter[2].process(filter[1].process(filter[0].process_zeroin())); + break; + } + } + for (int i = 0; i < order; i++) + filter[i].sanitize(); + return filter[order - 1].empty() ? 0 : inmask; +} + +float biquad_filter_module::freq_gain(int subindex, float freq, float srate) const +{ + float level = 1.0; + for (int j = 0; j < order; j++) + level *= left[j].freq_gain(freq, srate); + return level; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +void reverb::update_times() +{ + switch(type) + { + case 0: + tl[0] = 397 << 16, tr[0] = 383 << 16; + tl[1] = 457 << 16, tr[1] = 429 << 16; + tl[2] = 549 << 16, tr[2] = 631 << 16; + tl[3] = 649 << 16, tr[3] = 756 << 16; + tl[4] = 773 << 16, tr[4] = 803 << 16; + tl[5] = 877 << 16, tr[5] = 901 << 16; + break; + case 1: + tl[0] = 697 << 16, tr[0] = 783 << 16; + tl[1] = 957 << 16, tr[1] = 929 << 16; + tl[2] = 649 << 16, tr[2] = 531 << 16; + tl[3] = 1049 << 16, tr[3] = 1177 << 16; + tl[4] = 473 << 16, tr[4] = 501 << 16; + tl[5] = 587 << 16, tr[5] = 681 << 16; + break; + case 2: + default: + tl[0] = 697 << 16, tr[0] = 783 << 16; + tl[1] = 957 << 16, tr[1] = 929 << 16; + tl[2] = 649 << 16, tr[2] = 531 << 16; + tl[3] = 1249 << 16, tr[3] = 1377 << 16; + tl[4] = 1573 << 16, tr[4] = 1671 << 16; + tl[5] = 1877 << 16, tr[5] = 1781 << 16; + break; + case 3: + tl[0] = 1097 << 16, tr[0] = 1087 << 16; + tl[1] = 1057 << 16, tr[1] = 1031 << 16; + tl[2] = 1049 << 16, tr[2] = 1039 << 16; + tl[3] = 1083 << 16, tr[3] = 1055 << 16; + tl[4] = 1075 << 16, tr[4] = 1099 << 16; + tl[5] = 1003 << 16, tr[5] = 1073 << 16; + break; + case 4: + tl[0] = 197 << 16, tr[0] = 133 << 16; + tl[1] = 357 << 16, tr[1] = 229 << 16; + tl[2] = 549 << 16, tr[2] = 431 << 16; + tl[3] = 949 << 16, tr[3] = 1277 << 16; + tl[4] = 1173 << 16, tr[4] = 1671 << 16; + tl[5] = 1477 << 16, tr[5] = 1881 << 16; + break; + case 5: + tl[0] = 197 << 16, tr[0] = 133 << 16; + tl[1] = 257 << 16, tr[1] = 179 << 16; + tl[2] = 549 << 16, tr[2] = 431 << 16; + tl[3] = 619 << 16, tr[3] = 497 << 16; + tl[4] = 1173 << 16, tr[4] = 1371 << 16; + tl[5] = 1577 << 16, tr[5] = 1881 << 16; + break; + } + + float fDec=1000 + 2400.f * diffusion; + for (int i = 0 ; i < 6; i++) { + ldec[i]=exp(-float(tl[i] >> 16) / fDec), + rdec[i]=exp(-float(tr[i] >> 16) / fDec); + } +} + +void reverb::reset() +{ + apL1.reset();apR1.reset(); + apL2.reset();apR2.reset(); + apL3.reset();apR3.reset(); + apL4.reset();apR4.reset(); + apL5.reset();apR5.reset(); + apL6.reset();apR6.reset(); + lp_left.reset();lp_right.reset(); + old_left = 0; old_right = 0; +} + +void reverb::process(float &left, float &right) +{ + unsigned int ipart = phase.ipart(); + + // the interpolated LFO might be an overkill here + int lfo = phase.lerp_by_fract_int(sine.data[ipart], sine.data[ipart+1]) >> 2; + phase += dphase; + + left += old_right; + left = apL1.process_allpass_comb_lerp16(left, tl[0] - 45*lfo, ldec[0]); + left = apL2.process_allpass_comb_lerp16(left, tl[1] + 47*lfo, ldec[1]); + float out_left = left; + left = apL3.process_allpass_comb_lerp16(left, tl[2] + 54*lfo, ldec[2]); + left = apL4.process_allpass_comb_lerp16(left, tl[3] - 69*lfo, ldec[3]); + left = apL5.process_allpass_comb_lerp16(left, tl[4] + 69*lfo, ldec[4]); + left = apL6.process_allpass_comb_lerp16(left, tl[5] - 46*lfo, ldec[5]); + old_left = lp_left.process(left * fb); + sanitize(old_left); + + right += old_left; + right = apR1.process_allpass_comb_lerp16(right, tr[0] - 45*lfo, rdec[0]); + right = apR2.process_allpass_comb_lerp16(right, tr[1] + 47*lfo, rdec[1]); + float out_right = right; + right = apR3.process_allpass_comb_lerp16(right, tr[2] + 54*lfo, rdec[2]); + right = apR4.process_allpass_comb_lerp16(right, tr[3] - 69*lfo, rdec[3]); + right = apR5.process_allpass_comb_lerp16(right, tr[4] + 69*lfo, rdec[4]); + right = apR6.process_allpass_comb_lerp16(right, tr[5] - 46*lfo, rdec[5]); + old_right = lp_right.process(right * fb); + sanitize(old_right); + + left = out_left, right = out_right; +} + +/// Distortion Module by Tom Szilagyi +/// +/// This module provides a blendable saturation stage +/////////////////////////////////////////////////////////////////////////////////////////////// + +tap_distortion::tap_distortion() +{ + is_active = false; + srate = 0; + meter = 0.f; +} + +void tap_distortion::activate() +{ + is_active = true; + set_params(0.f, 0.f); +} +void tap_distortion::deactivate() +{ + is_active = false; +} + +void tap_distortion::set_params(float blend, float drive) +{ + // set distortion coeffs + if ((drive_old != drive) || (blend_old != blend)) { + rdrive = 12.0f / drive; + rbdr = rdrive / (10.5f - blend) * 780.0f / 33.0f; + kpa = D(2.0f * (rdrive*rdrive) - 1.0f) + 1.0f; + kpb = (2.0f - kpa) / 2.0f; + ap = ((rdrive*rdrive) - kpa + 1.0f) / 2.0f; + kc = kpa / D(2.0f * D(2.0f * (rdrive*rdrive) - 1.0f) - 2.0f * rdrive*rdrive); + + srct = (0.1f * srate) / (0.1f * srate + 1.0f); + sq = kc*kc + 1.0f; + knb = -1.0f * rbdr / D(sq); + kna = 2.0f * kc * rbdr / D(sq); + an = rbdr*rbdr / sq; + imr = 2.0f * knb + D(2.0f * kna + 4.0f * an - 1.0f); + pwrq = 2.0f / (imr + 1.0f); + + drive_old = drive; + blend_old = blend; + } +} + +void tap_distortion::set_sample_rate(uint32_t sr) +{ + srate = sr; +} + +float tap_distortion::process(float in) +{ + meter = 0.f; + float out = 0.f; + float proc = in; + float med; + if (proc >= 0.0f) { + med = (D(ap + proc * (kpa - proc)) + kpb) * pwrq; + } else { + med = (D(an - proc * (kna + proc)) + knb) * pwrq * -1.0f; + } + proc = srct * (med - prev_med + prev_out); + prev_med = M(med); + prev_out = M(proc); + out = proc; + meter = proc; + return out; +} + +float tap_distortion::get_distortion_level() +{ + return meter; +} + +//////////////////////////////////////////////////////////////////////////////// + +simple_lfo::simple_lfo() +{ + is_active = false; + phase = 0.f; +} + +void simple_lfo::activate() +{ + is_active = true; + phase = 0.f; +} + +void simple_lfo::deactivate() +{ + is_active = false; +} + +float simple_lfo::get_value() +{ + return get_value_from_phase(phase, offset) * amount; +} + +float simple_lfo::get_value_from_phase(float ph, float off) const +{ + float val = 0.f; + float phs = ph + off; + if (phs >= 1.0) + phs = fmod(phs, 1.f); + switch (mode) { + default: + case 0: + // sine + val = sin((phs * 360.f) * M_PI / 180); + break; + case 1: + // triangle + if(phs > 0.75) + val = (phs - 0.75) * 4 - 1; + else if(phs > 0.5) + val = (phs - 0.5) * 4 * -1; + else if(phs > 0.25) + val = 1 - (phs - 0.25) * 4; + else + val = phs * 4; + break; + case 2: + // square + val = (phs < 0.5) ? -1 : +1; + break; + case 3: + // saw up + val = phs * 2.f - 1; + break; + case 4: + // saw down + val = 1 - phs * 2.f; + break; + } + return val; +} + +void simple_lfo::advance(uint32_t count) +{ + //this function walks from 0.f to 1.f and starts all over again + phase += count * freq * (1.0 / srate); + if (phase >= 1.0) + phase = fmod(phase, 1.f); +} + +void simple_lfo::set_phase(float ph) +{ + //set the phase from outsinde + phase = fabs(ph); + if (phase >= 1.0) + phase = fmod(phase, 1.f); +} + +void simple_lfo::set_params(float f, int m, float o, uint32_t sr, float a) +{ + // freq: a value in Hz + // mode: sine=0, triangle=1, square=2, saw_up=3, saw_down=4 + // offset: value between 0.f and 1.f to offset the lfo in time + freq = f; + mode = m; + offset = o; + srate = sr; + amount = a; +} + +bool simple_lfo::get_graph(float *data, int points, cairo_iface *context) const +{ + if (!is_active) + return false; + for (int i = 0; i < points; i++) { + float ph = (float)i / (float)points; + data[i] = get_value_from_phase(ph, offset) * amount; + } + return true; +} + +bool simple_lfo::get_dot(float &x, float &y, int &size, cairo_iface *context) const +{ + if (!is_active) + return false; + float phs = phase + offset; + if (phs >= 1.0) + phs = fmod(phs, 1.f); + x = phase; + y = get_value_from_phase(phase, offset) * amount; + return true; +} + diff --git a/plugins/ladspa_effect/calf/calf/audio_fx.h b/plugins/ladspa_effect/calf/src/calf/audio_fx.h similarity index 55% rename from plugins/ladspa_effect/calf/calf/audio_fx.h rename to plugins/ladspa_effect/calf/src/calf/audio_fx.h index bf61f9498..b9e5012fe 100644 --- a/plugins/ladspa_effect/calf/calf/audio_fx.h +++ b/plugins/ladspa_effect/calf/src/calf/audio_fx.h @@ -1,7 +1,7 @@ /* Calf DSP Library * Reusable audio effect classes. * - * Copyright (C) 2001-2007 Krzysztof Foltman + * 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 @@ -18,17 +18,19 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#ifndef __CALF_AUDIOFX_H -#define __CALF_AUDIOFX_H +#ifndef CALF_AUDIOFX_H +#define CALF_AUDIOFX_H -#include -#include -#include -#include -#include "primitives.h" +#include "biquad.h" #include "delay.h" #include "fixed_point.h" #include "inertia.h" +#include "onepole.h" +#include + +namespace calf_plugins { + struct cairo_iface; +}; namespace dsp { #if 0 @@ -95,26 +97,17 @@ public: * A monophonic phaser. If you want stereo, combine two :) * Also, gave up on using template args for signal type. */ -template class simple_phaser: public modulation_effect { protected: float base_frq, mod_depth, fb; float state; - int cnt, stages; + int cnt, stages, max_stages; dsp::onepole stage1; - float x1[MaxStages], y1[MaxStages]; + float *x1, *y1; public: - simple_phaser() - { - set_base_frq(1000); - set_mod_depth(1000); - set_fb(0); - state = 0; - cnt = 0; - stages = 0; - set_stages(6); - } + simple_phaser(int _max_stages, float *x1vals, float *y1vals); + float get_base_frq() const { return base_frq; } @@ -124,93 +117,30 @@ public: int get_stages() const { return stages; } - void set_stages(int _stages) { - if (_stages > stages) - { - for (int i = stages; i < _stages; i++) - { - x1[i] = x1[stages-1]; - y1[i] = y1[stages-1]; - } - } - stages = _stages; - } + void set_stages(int _stages); + float get_mod_depth() const { return mod_depth; } void set_mod_depth(float _mod_depth) { mod_depth = _mod_depth; } + float get_fb() const { return fb; } void set_fb(float fb) { this->fb = fb; } + virtual void setup(int sample_rate) { modulation_effect::setup(sample_rate); reset(); } - void reset() - { - cnt = 0; - state = 0; - phase.set(0); - for (int i = 0; i < MaxStages; i++) - x1[i] = y1[i] = 0; - control_step(); - } - inline void control_step() - { - cnt = 0; - int v = phase.get() + 0x40000000; - int sign = v >> 31; - v ^= sign; - // triangle wave, range from 0 to INT_MAX - double vf = (double)((v >> 16) * (1.0 / 16384.0) - 1); - - float freq = base_frq * pow(2.0, vf * mod_depth / 1200.0); - freq = dsp::clip(freq, 10.0, 0.49 * sample_rate); - stage1.set_ap_w(freq * (M_PI / 2.0) * odsr); - phase += dphase * 32; - for (int i = 0; i < stages; i++) - { - dsp::sanitize(x1[i]); - dsp::sanitize(y1[i]); - } - dsp::sanitize(state); - } - void process(float *buf_out, float *buf_in, int nsamples) { - for (int i=0; i cfloat; - freq *= 2.0 * M_PI / sr; - cfloat z = 1.0 / exp(cfloat(0.0, freq)); // z^-1 - - cfloat p = cfloat(1.0); - cfloat stg = stage1.h_z(z); - - for (int i = 0; i < stages; i++) - p = p * stg; - - p = p / (cfloat(1.0) - cfloat(fb) * p); - return std::abs(cfloat(gs_dry.get_last()) + cfloat(gs_wet.get_last()) * p); - } + void reset(); + void control_step(); + void process(float *buf_out, float *buf_in, int nsamples); + float freq_gain(float freq, float sr) const; }; /** @@ -410,15 +340,14 @@ public: * Just started implementing it, so there is no control over many * parameters. */ -template class reverb: public audio_effect { - simple_delay<2048, T> apL1, apL2, apL3, apL4, apL5, apL6; - simple_delay<2048, T> apR1, apR2, apR3, apR4, apR5, apR6; + simple_delay<2048, float> apL1, apL2, apL3, apL4, apL5, apL6; + simple_delay<2048, float> apR1, apR2, apR3, apR4, apR5, apR6; fixed_point phase, dphase; sine_table sine; - onepole lp_left, lp_right; - T old_left, old_right; + onepole lp_left, lp_right; + float old_left, old_right; int type; float time, fb, cutoff, diffusion; int tl[6], tr[6]; @@ -443,67 +372,7 @@ public: dphase = 0.5*128/sr; update_times(); } - void update_times() - { - switch(type) - { - case 0: - tl[0] = 397 << 16, tr[0] = 383 << 16; - tl[1] = 457 << 16, tr[1] = 429 << 16; - tl[2] = 549 << 16, tr[2] = 631 << 16; - tl[3] = 649 << 16, tr[3] = 756 << 16; - tl[4] = 773 << 16, tr[4] = 803 << 16; - tl[5] = 877 << 16, tr[5] = 901 << 16; - break; - case 1: - tl[0] = 697 << 16, tr[0] = 783 << 16; - tl[1] = 957 << 16, tr[1] = 929 << 16; - tl[2] = 649 << 16, tr[2] = 531 << 16; - tl[3] = 1049 << 16, tr[3] = 1177 << 16; - tl[4] = 473 << 16, tr[4] = 501 << 16; - tl[5] = 587 << 16, tr[5] = 681 << 16; - break; - case 2: - default: - tl[0] = 697 << 16, tr[0] = 783 << 16; - tl[1] = 957 << 16, tr[1] = 929 << 16; - tl[2] = 649 << 16, tr[2] = 531 << 16; - tl[3] = 1249 << 16, tr[3] = 1377 << 16; - tl[4] = 1573 << 16, tr[4] = 1671 << 16; - tl[5] = 1877 << 16, tr[5] = 1781 << 16; - break; - case 3: - tl[0] = 1097 << 16, tr[0] = 1087 << 16; - tl[1] = 1057 << 16, tr[1] = 1031 << 16; - tl[2] = 1049 << 16, tr[2] = 1039 << 16; - tl[3] = 1083 << 16, tr[3] = 1055 << 16; - tl[4] = 1075 << 16, tr[4] = 1099 << 16; - tl[5] = 1003 << 16, tr[5] = 1073 << 16; - break; - case 4: - tl[0] = 197 << 16, tr[0] = 133 << 16; - tl[1] = 357 << 16, tr[1] = 229 << 16; - tl[2] = 549 << 16, tr[2] = 431 << 16; - tl[3] = 949 << 16, tr[3] = 1277 << 16; - tl[4] = 1173 << 16, tr[4] = 1671 << 16; - tl[5] = 1477 << 16, tr[5] = 1881 << 16; - break; - case 5: - tl[0] = 197 << 16, tr[0] = 133 << 16; - tl[1] = 257 << 16, tr[1] = 179 << 16; - tl[2] = 549 << 16, tr[2] = 431 << 16; - tl[3] = 619 << 16, tr[3] = 497 << 16; - tl[4] = 1173 << 16, tr[4] = 1371 << 16; - tl[5] = 1577 << 16, tr[5] = 1881 << 16; - break; - } - - float fDec=1000 + 2400.f * diffusion; - for (int i = 0 ; i < 6; i++) { - ldec[i]=exp(-float(tl[i] >> 16) / fDec), - rdec[i]=exp(-float(tr[i] >> 16) / fDec); - } - } + void update_times(); float get_time() const { return time; } @@ -547,49 +416,8 @@ public: lp_left.set_lp(cutoff,sr); lp_right.set_lp(cutoff,sr); } - void reset() - { - apL1.reset();apR1.reset(); - apL2.reset();apR2.reset(); - apL3.reset();apR3.reset(); - apL4.reset();apR4.reset(); - apL5.reset();apR5.reset(); - apL6.reset();apR6.reset(); - lp_left.reset();lp_right.reset(); - old_left = 0; old_right = 0; - } - void process(T &left, T &right) - { - unsigned int ipart = phase.ipart(); - - // the interpolated LFO might be an overkill here - int lfo = phase.lerp_by_fract_int(sine.data[ipart], sine.data[ipart+1]) >> 2; - phase += dphase; - - left += old_right; - left = apL1.process_allpass_comb_lerp16(left, tl[0] - 45*lfo, ldec[0]); - left = apL2.process_allpass_comb_lerp16(left, tl[1] + 47*lfo, ldec[1]); - float out_left = left; - left = apL3.process_allpass_comb_lerp16(left, tl[2] + 54*lfo, ldec[2]); - left = apL4.process_allpass_comb_lerp16(left, tl[3] - 69*lfo, ldec[3]); - left = apL5.process_allpass_comb_lerp16(left, tl[4] + 69*lfo, ldec[4]); - left = apL6.process_allpass_comb_lerp16(left, tl[5] - 46*lfo, ldec[5]); - old_left = lp_left.process(left * fb); - sanitize(old_left); - - right += old_left; - right = apR1.process_allpass_comb_lerp16(right, tr[0] - 45*lfo, rdec[0]); - right = apR2.process_allpass_comb_lerp16(right, tr[1] + 47*lfo, rdec[1]); - float out_right = right; - right = apR3.process_allpass_comb_lerp16(right, tr[2] + 54*lfo, rdec[2]); - right = apR4.process_allpass_comb_lerp16(right, tr[3] - 69*lfo, rdec[3]); - right = apR5.process_allpass_comb_lerp16(right, tr[4] + 69*lfo, rdec[4]); - right = apR6.process_allpass_comb_lerp16(right, tr[5] - 46*lfo, rdec[5]); - old_right = lp_right.process(right * fb); - sanitize(old_right); - - left = out_left, right = out_right; - } + void reset(); + void process(float &left, float &right); void extra_sanitize() { lp_left.sanitize(); @@ -603,7 +431,7 @@ public: virtual void calculate_filter(float freq, float q, int mode, float gain = 1.0) = 0; virtual void filter_activate() = 0; virtual void sanitize() = 0; - virtual int process_channel(uint16_t channel_no, float *in, float *out, uint32_t numsamples, int inmask) = 0; + virtual int process_channel(uint16_t channel_no, const float *in, float *out, uint32_t numsamples, int inmask) = 0; virtual float freq_gain(int subindex, float freq, float srate) const = 0; virtual ~filter_module_iface() {} @@ -627,116 +455,18 @@ public: }; public: - biquad_filter_module() : order(0) {} - - void calculate_filter(float freq, float q, int mode, float gain = 1.0) - { - if (mode <= mode_36db_lp) { - order = mode + 1; - left[0].set_lp_rbj(freq, pow(q, 1.0 / order), srate, gain); - } else if ( mode_12db_hp <= mode && mode <= mode_36db_hp ) { - order = mode - mode_12db_hp + 1; - left[0].set_hp_rbj(freq, pow(q, 1.0 / order), srate, gain); - } else if ( mode_6db_bp <= mode && mode <= mode_18db_bp ) { - order = mode - mode_6db_bp + 1; - left[0].set_bp_rbj(freq, pow(q, 1.0 / order), srate, gain); - } else { // mode_6db_br <= mode <= mode_18db_br - order = mode - mode_6db_br + 1; - left[0].set_br_rbj(freq, order * 0.1 * q, srate, gain); - } - - right[0].copy_coeffs(left[0]); - for (int i = 1; i < order; i++) { - left[i].copy_coeffs(left[0]); - right[i].copy_coeffs(left[0]); - } - } - - void filter_activate() - { - for (int i=0; i < order; i++) { - left[i].reset(); - right[i].reset(); - } - } - - void sanitize() - { - for (int i=0; i < order; i++) { - left[i].sanitize(); - right[i].sanitize(); - } - } - - inline int process_channel(uint16_t channel_no, float *in, float *out, uint32_t numsamples, int inmask) { - dsp::biquad_d1 *filter; - switch (channel_no) { - case 0: - filter = left; - break; - - case 1: - filter = right; - break; - - default: - assert(false); - return 0; - } - - if (inmask) { - switch(order) { - case 1: - for (uint32_t i = 0; i < numsamples; i++) - out[i] = filter[0].process(in[i]); - break; - case 2: - for (uint32_t i = 0; i < numsamples; i++) - out[i] = filter[1].process(filter[0].process(in[i])); - break; - case 3: - for (uint32_t i = 0; i < numsamples; i++) - out[i] = filter[2].process(filter[1].process(filter[0].process(in[i]))); - break; - } - } else { - if (filter[order - 1].empty()) - return 0; - switch(order) { - case 1: - for (uint32_t i = 0; i < numsamples; i++) - out[i] = filter[0].process_zeroin(); - break; - case 2: - if (filter[0].empty()) - for (uint32_t i = 0; i < numsamples; i++) - out[i] = filter[1].process_zeroin(); - else - for (uint32_t i = 0; i < numsamples; i++) - out[i] = filter[1].process(filter[0].process_zeroin()); - break; - case 3: - if (filter[1].empty()) - for (uint32_t i = 0; i < numsamples; i++) - out[i] = filter[2].process_zeroin(); - else - for (uint32_t i = 0; i < numsamples; i++) - out[i] = filter[2].process(filter[1].process(filter[0].process_zeroin())); - break; - } - } - for (int i = 0; i < order; i++) - filter[i].sanitize(); - return filter[order - 1].empty() ? 0 : inmask; - } - - float freq_gain(int subindex, float freq, float srate) const - { - float level = 1.0; - for (int j = 0; j < order; j++) - level *= left[j].freq_gain(freq, srate); - return level; - } + biquad_filter_module() + : order(0) {} + /// Calculate filter coefficients based on parameters - cutoff/center frequency, q, filter type, output gain + void calculate_filter(float freq, float q, int mode, float gain = 1.0); + /// Reset filter state + void filter_activate(); + /// Remove denormals + void sanitize(); + /// Process a single channel (float buffer) of data + int process_channel(uint16_t channel_no, const float *in, float *out, uint32_t numsamples, int inmask); + /// Determine gain (|H(z)|) for a given frequency + float freq_gain(int subindex, float freq, float srate) const; }; class two_band_eq @@ -782,6 +512,59 @@ public: } }; +/// Tom Szilagyi's distortion code, used with permission +/// KF: I'm not 100% sure how this is supposed to work, but it does. +/// I'm planning to rewrite it using more modular approach when I have more time. +class tap_distortion { +private: + float blend_old, drive_old; + float meter; + float rdrive, rbdr, kpa, kpb, kna, knb, ap, an, imr, kc, srct, sq, pwrq; + float prev_med, prev_out; +public: + uint32_t srate; + bool is_active; + tap_distortion(); + void activate(); + void deactivate(); + void set_params(float blend, float drive); + void set_sample_rate(uint32_t sr); + float process(float in); + float get_distortion_level(); + static inline float M(float x) + { + return (fabs(x) > 0.000000001f) ? x : 0.0f; + } + + static inline float D(float x) + { + x = fabs(x); + return (x > 0.000000001f) ? sqrtf(x) : 0.0f; + } +}; + +/// LFO module by Markus +/// This module provides simple LFO's (sine=0, triangle=1, square=2, saw_up=3, saw_down=4) +/// get_value() returns a value between -1 and 1 +class simple_lfo { +private: + float phase, freq, offset, amount; + int mode; + uint32_t srate; + bool is_active; +public: + simple_lfo(); + void set_params(float f, int m, float o, uint32_t sr, float amount = 1.f); + float get_value(); + void advance(uint32_t count); + void set_phase(float ph); + void activate(); + void deactivate(); + float get_value_from_phase(float ph, float off) const; + bool get_graph(float *data, int points, calf_plugins::cairo_iface *context) const; + bool get_dot(float &x, float &y, int &size, calf_plugins::cairo_iface *context) const; +}; + #if 0 { to keep editor happy #endif diff --git a/plugins/ladspa_effect/calf/calf/biquad.h b/plugins/ladspa_effect/calf/src/calf/biquad.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/biquad.h rename to plugins/ladspa_effect/calf/src/calf/biquad.h diff --git a/plugins/ladspa_effect/calf/calf/buffer.h b/plugins/ladspa_effect/calf/src/calf/buffer.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/buffer.h rename to plugins/ladspa_effect/calf/src/calf/buffer.h diff --git a/plugins/ladspa_effect/calf/calf/delay.h b/plugins/ladspa_effect/calf/src/calf/delay.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/delay.h rename to plugins/ladspa_effect/calf/src/calf/delay.h diff --git a/plugins/ladspa_effect/calf/calf/envelope.h b/plugins/ladspa_effect/calf/src/calf/envelope.h similarity index 97% rename from plugins/ladspa_effect/calf/calf/envelope.h rename to plugins/ladspa_effect/calf/src/calf/envelope.h index 8a8fce13e..94f87ed22 100644 --- a/plugins/ladspa_effect/calf/calf/envelope.h +++ b/plugins/ladspa_effect/calf/src/calf/envelope.h @@ -197,6 +197,14 @@ public: { return old_value + (value - old_value) * pos; } + inline float get_amp_value() + { + if (state == RELEASE && sustain > 0 && value < sustain) + { + return value * value * value / (sustain * sustain); + } + return value; + } }; }; diff --git a/plugins/ladspa_effect/calf/calf/fft.h b/plugins/ladspa_effect/calf/src/calf/fft.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/fft.h rename to plugins/ladspa_effect/calf/src/calf/fft.h diff --git a/plugins/ladspa_effect/calf/calf/fixed_point.h b/plugins/ladspa_effect/calf/src/calf/fixed_point.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/fixed_point.h rename to plugins/ladspa_effect/calf/src/calf/fixed_point.h diff --git a/plugins/ladspa_effect/calf/calf/giface.h b/plugins/ladspa_effect/calf/src/calf/giface.h similarity index 76% rename from plugins/ladspa_effect/calf/calf/giface.h rename to plugins/ladspa_effect/calf/src/calf/giface.h index e6c0736b3..08954c695 100644 --- a/plugins/ladspa_effect/calf/calf/giface.h +++ b/plugins/ladspa_effect/calf/src/calf/giface.h @@ -1,7 +1,7 @@ /* Calf DSP Library * Common plugin interface definitions (shared between LADSPA/LV2/DSSI/standalone). * - * Copyright (C) 2007 Krzysztof Foltman + * Copyright (C) 2007-2010 Krzysztof Foltman * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,17 +18,15 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02111-1307, USA. */ -#ifndef __CALF_GIFACE_H -#define __CALF_GIFACE_H +#ifndef CALF_GIFACE_H +#define CALF_GIFACE_H -#include -#include -#include +#include +#include "primitives.h" +#include #include #include -#include -#include "primitives.h" -#include "preset.h" +#include namespace osctl { struct osc_client; @@ -235,7 +233,7 @@ struct table_edit_iface virtual uint32_t get_table_rows(int param) const = 0; /// retrieve data item from the plugin - virtual std::string get_cell(int param, int row, int column) const { return calf_utils::i2s(row)+":"+calf_utils::i2s(column); } + virtual std::string get_cell(int param, int row, int column) const; /// set data item to the plugin virtual void set_cell(int param, int row, int column, const std::string &src, std::string &error) const { error.clear(); } @@ -319,14 +317,12 @@ struct plugin_metadata_iface virtual bool requires_midi() const =0; /// @return port offset of first control (parameter) port (= number of audio inputs + number of audio outputs in all existing plugins as for 1 Aug 2008) virtual int get_param_port_offset() const = 0; - /// @return line_graph_iface if any - virtual const line_graph_iface *get_line_graph_iface() const = 0; /// @return table_edit_iface if any virtual const table_edit_iface *get_table_edit_iface() const = 0; /// @return NULL-terminated list of menu commands virtual plugin_command_info *get_commands() const { return NULL; } /// @return description structure for given parameter - virtual parameter_properties *get_param_props(int param_no) const = 0; + virtual const parameter_properties *get_param_props(int param_no) const = 0; /// @return retrieve names of audio ports (@note control ports are named in parameter_properties, not here) virtual const char **get_port_names() const = 0; /// @return description structure for the plugin @@ -347,7 +343,7 @@ struct plugin_metadata_iface }; /// Interface for host-GUI-plugin interaction (should be really split in two, but ... meh) -struct plugin_ctl_iface: public virtual plugin_metadata_iface +struct plugin_ctl_iface { /// @return value of given parameter virtual float get_param_value(int param_no) = 0; @@ -360,7 +356,7 @@ struct plugin_ctl_iface: public virtual plugin_metadata_iface /// Execute menu command with given number virtual void execute(int cmd_no)=0; /// Set a configure variable on a plugin - virtual char *configure(const char *key, const char *value) { return NULL; } + virtual char *configure(const char *key, const char *value) = 0; /// Send all configure variables set within a plugin to given destination (which may be limited to only those that plugin understands) virtual void send_configures(send_configure_iface *)=0; /// Restore all state (parameters and configure vars) to default values - implemented in giface.cpp @@ -370,7 +366,11 @@ struct plugin_ctl_iface: public virtual plugin_metadata_iface virtual bool blobcall(const char *command, const std::string &request, std::string &result) { result = "Call not supported"; return false; } /// Update status variables changed since last_serial /// @return new last_serial - virtual int send_status_updates(send_updates_iface *sui, int last_serial) { return last_serial; } + virtual int send_status_updates(send_updates_iface *sui, int last_serial) = 0; + /// Return metadata object + virtual const plugin_metadata_iface *get_metadata_iface() const = 0; + /// @return line_graph_iface if any + virtual const line_graph_iface *get_line_graph_iface() const = 0; /// Do-nothing destructor to silence compiler warning virtual ~plugin_ctl_iface() {} }; @@ -381,7 +381,7 @@ struct plugin_list_info_iface; class plugin_registry { public: - typedef std::vector plugin_vector; + typedef std::vector plugin_vector; private: plugin_vector plugins; plugin_registry(); @@ -393,71 +393,169 @@ public: const plugin_vector &get_all() { return plugins; } /// Get single plugin metadata object by URI const plugin_metadata_iface *get_by_uri(const char *URI); + /// Get single plugin metadata object by URI + const plugin_metadata_iface *get_by_id(const char *id, bool case_sensitive = false); }; /// Load and strdup a text file with GUI definition extern const char *load_gui_xml(const std::string &plugin_id); -/// Empty implementations for plugin functions. Note, that functions aren't virtual, because they're called via the particular -/// subclass (flanger_audio_module etc) via template wrappers (ladspa_wrapper<> etc), not via base class pointer/reference +/// Interface to audio processing plugins (the real things, not only metadata) +struct audio_module_iface +{ + /// Handle MIDI Note On + virtual void note_on(int note, int velocity) = 0; + /// Handle MIDI Note Off + virtual void note_off(int note, int velocity) = 0; + /// Handle MIDI Program Change + virtual void program_change(int program) = 0; + /// Handle MIDI Control Change + virtual void control_change(int controller, int value) = 0; + /// Handle MIDI Pitch Bend + /// @param value pitch bend value (-8192 to 8191, defined as in MIDI ie. 8191 = 200 ct by default) + virtual void pitch_bend(int value) = 0; + /// Handle MIDI Channel Pressure + /// @param value channel pressure (0 to 127) + virtual void channel_pressure(int value) = 0; + /// Called when params are changed (before processing) + virtual void params_changed() = 0; + /// LADSPA-esque activate function, except it is called after ports are connected, not before + virtual void activate() = 0; + /// LADSPA-esque deactivate function + virtual void deactivate() = 0; + /// Set sample rate for the plugin + virtual void set_sample_rate(uint32_t sr) = 0; + /// Execute menu command with given number + virtual void execute(int cmd_no) = 0; + /// DSSI configure call + virtual char *configure(const char *key, const char *value) = 0; + /// Send all understood configure vars (none by default) + virtual void send_configures(send_configure_iface *sci) = 0; + /// Send all supported status vars (none by default) + virtual int send_status_updates(send_updates_iface *sui, int last_serial) = 0; + /// Reset parameter values for epp:trigger type parameters (ones activated by oneshot push button instead of check box) + virtual void params_reset() = 0; + /// Called after instantiating (after all the feature pointers are set - including interfaces like progress_report_iface) + virtual void post_instantiate() = 0; + /// Return the arrays of port buffer pointers + virtual void get_port_arrays(float **&ins_ptrs, float **&outs_ptrs, float **¶ms_ptrs) = 0; + /// Return metadata object + virtual const plugin_metadata_iface *get_metadata_iface() const = 0; + /// Set the progress report interface to communicate progress to + virtual void set_progress_report_iface(progress_report_iface *iface) = 0; + /// Clear a part of output buffers that have 0s at mask + virtual void process_slice(uint32_t offset, uint32_t end) = 0; + /// The audio processing loop + virtual uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) = 0; + /// Message port processing function + virtual uint32_t message_run(const void *valid_ports, void *output_ports) = 0; + /// @return line_graph_iface if any + virtual const line_graph_iface *get_line_graph_iface() const = 0; + virtual ~audio_module_iface() {} +}; + +/// Empty implementations for plugin functions. template -class audio_module: public Metadata +class audio_module: public Metadata, public audio_module_iface { public: typedef Metadata metadata_type; + using Metadata::in_count; + using Metadata::out_count; + using Metadata::param_count; + float *ins[Metadata::in_count]; + float *outs[Metadata::out_count]; + float *params[Metadata::param_count]; progress_report_iface *progress_report; audio_module() { progress_report = NULL; + memset(ins, 0, sizeof(ins)); + memset(outs, 0, sizeof(outs)); + memset(params, 0, sizeof(params)); } /// Handle MIDI Note On - inline void note_on(int note, int velocity) {} + void note_on(int note, int velocity) {} /// Handle MIDI Note Off - inline void note_off(int note, int velocity) {} + void note_off(int note, int velocity) {} /// Handle MIDI Program Change - inline void program_change(int program) {} + void program_change(int program) {} /// Handle MIDI Control Change - inline void control_change(int controller, int value) {} + void control_change(int controller, int value) {} /// Handle MIDI Pitch Bend /// @param value pitch bend value (-8192 to 8191, defined as in MIDI ie. 8191 = 200 ct by default) - inline void pitch_bend(int value) {} + void pitch_bend(int value) {} /// Handle MIDI Channel Pressure /// @param value channel pressure (0 to 127) - inline void channel_pressure(int value) {} + void channel_pressure(int value) {} /// Called when params are changed (before processing) - inline void params_changed() {} + void params_changed() {} /// LADSPA-esque activate function, except it is called after ports are connected, not before - inline void activate() {} + void activate() {} /// LADSPA-esque deactivate function - inline void deactivate() {} + void deactivate() {} /// Set sample rate for the plugin - inline void set_sample_rate(uint32_t sr) { } + void set_sample_rate(uint32_t sr) { } /// Execute menu command with given number - inline void execute(int cmd_no) {} + void execute(int cmd_no) {} /// DSSI configure call virtual char *configure(const char *key, const char *value) { return NULL; } /// Send all understood configure vars (none by default) - inline void send_configures(send_configure_iface *sci) {} + void send_configures(send_configure_iface *sci) {} /// Send all supported status vars (none by default) - inline int send_status_updates(send_updates_iface *sui, int last_serial) { return last_serial; } + int send_status_updates(send_updates_iface *sui, int last_serial) { return last_serial; } /// Reset parameter values for epp:trigger type parameters (ones activated by oneshot push button instead of check box) - inline void params_reset() {} + void params_reset() {} /// Called after instantiating (after all the feature pointers are set - including interfaces like progress_report_iface) - inline void post_instantiate() {} + void post_instantiate() {} /// Handle 'message context' port message /// @arg output_ports pointer to bit array of output port "changed" flags, note that 0 = first audio input, not first parameter (use input_count + output_count) - inline uint32_t message_run(const void *valid_ports, void *output_ports) { + uint32_t message_run(const void *valid_ports, void *output_ports) { fprintf(stderr, "ERROR: message run not implemented\n"); return 0; } + /// Return the array of input port pointers + virtual void get_port_arrays(float **&ins_ptrs, float **&outs_ptrs, float **¶ms_ptrs) + { + ins_ptrs = ins; + outs_ptrs = outs; + params_ptrs = params; + } + /// Return metadata object + virtual const plugin_metadata_iface *get_metadata_iface() const { return this; } + /// Set the progress report interface to communicate progress to + virtual void set_progress_report_iface(progress_report_iface *iface) { progress_report = iface; } + + /// utility function: zero port values if mask is 0 + inline void zero_by_mask(uint32_t mask, uint32_t offset, uint32_t nsamples) + { + for (int i=0; i(this); } }; -extern bool check_for_message_context_ports(parameter_properties *parameters, int count); -extern bool check_for_string_ports(parameter_properties *parameters, int count); +extern bool check_for_message_context_ports(const parameter_properties *parameters, int count); +extern bool check_for_string_ports(const parameter_properties *parameters, int count); -#if USE_DSSI +#if USE_EXEC_GUI || USE_DSSI enum line_graph_item { @@ -476,16 +574,19 @@ struct dssi_feedback_sender { /// OSC client object used to send updates osctl::osc_client *client; - /// Background thread handle - pthread_t bg_thread; + /// Is client shared with something else? + bool is_client_shared; /// Quit flag (used to terminate the thread) bool quit; /// Indices of graphs to send std::vector indices; /// Source for the graph data (interface to marshal) - calf_plugins::line_graph_iface *graph; + const calf_plugins::line_graph_iface *graph; - dssi_feedback_sender(const char *URI, line_graph_iface *_graph, calf_plugins::parameter_properties *props, int num_params); + /// Create using a new client + dssi_feedback_sender(const char *URI, const line_graph_iface *_graph); + dssi_feedback_sender(osctl::osc_client *_client, const line_graph_iface *_graph); + void add_graphs(const calf_plugins::parameter_properties *props, int num_params); void update(); ~dssi_feedback_sender(); }; @@ -493,12 +594,13 @@ struct dssi_feedback_sender /// Metadata base class template, to provide default versions of interface functions template -class plugin_metadata: public virtual plugin_metadata_iface +class plugin_metadata: public plugin_metadata_iface { public: static const char *port_names[]; static parameter_properties param_props[]; static ladspa_plugin_info plugin_info; + typedef plugin_metadata metadata_class; // These below are stock implementations based on enums and static members in Metadata classes // they may be overridden to provide more interesting functionality @@ -514,12 +616,11 @@ public: bool get_midi() const { return Metadata::support_midi; } bool requires_midi() const { return Metadata::require_midi; } bool is_rt_capable() const { return Metadata::rt_capable; } - const line_graph_iface *get_line_graph_iface() const { return dynamic_cast(this); } const table_edit_iface *get_table_edit_iface() const { return dynamic_cast(this); } int get_param_port_offset() const { return Metadata::in_count + Metadata::out_count; } const char *get_gui_xml() const { static const char *data_ptr = calf_plugins::load_gui_xml(get_id()); return data_ptr; } plugin_command_info *get_commands() const { return NULL; } - parameter_properties *get_param_props(int param_no) const { return ¶m_props[param_no]; } + const parameter_properties *get_param_props(int param_no) const { return ¶m_props[param_no]; } const char **get_port_names() const { return port_names; } bool is_cv(int param_no) const { return true; } bool is_noisy(int param_no) const { return false; } @@ -534,42 +635,6 @@ public: } }; -/// A class for delegating metadata implementation to a "remote" metadata class. -/// Used for GUI wrappers that cannot have a dependency on actual classes, -/// and which instead take an "external" metadata object pointer, obtained -/// through get_all_plugins. -class plugin_metadata_proxy: public virtual plugin_metadata_iface -{ -public: - const plugin_metadata_iface *impl; -public: - plugin_metadata_proxy(const plugin_metadata_iface *_impl) { impl = _impl; } - const char *get_name() const { return impl->get_name(); } - const char *get_id() const { return impl->get_id(); } - const char *get_label() const { return impl->get_label(); } - int get_input_count() const { return impl->get_input_count(); } - int get_output_count() const { return impl->get_output_count(); } - int get_inputs_optional() const { return impl->get_inputs_optional(); } - int get_outputs_optional() const { return impl->get_outputs_optional(); } - int get_param_count() const { return impl->get_param_count(); } - bool get_midi() const { return impl->get_midi(); } - bool requires_midi() const { return impl->requires_midi(); } - bool is_rt_capable() const { return impl->is_rt_capable(); } - const line_graph_iface *get_line_graph_iface() const { return impl->get_line_graph_iface(); } - const table_edit_iface *get_table_edit_iface() const { return impl->get_table_edit_iface(); } - int get_param_port_offset() const { return impl->get_param_port_offset(); } - const char *get_gui_xml() const { return impl->get_gui_xml(); } - plugin_command_info *get_commands() const { return impl->get_commands(); } - parameter_properties *get_param_props(int param_no) const { return impl->get_param_props(param_no); } - const char **get_port_names() const { return impl->get_port_names(); } - bool is_cv(int param_no) const { return impl->is_cv(param_no); } - bool is_noisy(int param_no) const { return impl->is_noisy(param_no); } - const ladspa_plugin_info &get_plugin_info() const { return impl->get_plugin_info(); } - bool requires_message_context() const { return impl->requires_message_context(); } - bool requires_string_ports() const { return impl->requires_string_ports(); } - void get_message_context_parameters(std::vector &ports) const { impl->get_message_context_parameters(ports); } -}; - #define CALF_PORT_NAMES(name) template<> const char *::plugin_metadata::port_names[] #define CALF_PORT_PROPS(name) template<> parameter_properties plugin_metadata::param_props[] #define CALF_PLUGIN_INFO(name) template<> calf_plugins::ladspa_plugin_info plugin_metadata::plugin_info @@ -606,9 +671,24 @@ static inline float dB_grid_inv(float pos) return pow(256.0, pos - 0.4); } +/// Line graph interface implementation for frequency response graphs +class frequency_response_line_graph: public line_graph_iface +{ +public: + bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; + virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + /// set drawing color based on channel index (0 or 1) void set_channel_color(cairo_iface *context, int channel); +struct preset_access_iface +{ + virtual void store_preset() = 0; + virtual void activate_preset(int preset, bool builtin) = 0; + virtual ~preset_access_iface() {} +}; + }; #endif diff --git a/plugins/ladspa_effect/calf/calf/inertia.h b/plugins/ladspa_effect/calf/src/calf/inertia.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/inertia.h rename to plugins/ladspa_effect/calf/src/calf/inertia.h diff --git a/plugins/ladspa_effect/calf/src/calf/ladspa_wrap.h b/plugins/ladspa_effect/calf/src/calf/ladspa_wrap.h new file mode 100644 index 000000000..68009b8cb --- /dev/null +++ b/plugins/ladspa_effect/calf/src/calf/ladspa_wrap.h @@ -0,0 +1,130 @@ +/* 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, real_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/calf/loudness.h b/plugins/ladspa_effect/calf/src/calf/loudness.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/loudness.h rename to plugins/ladspa_effect/calf/src/calf/loudness.h diff --git a/plugins/ladspa_effect/calf/calf/lv2_external_ui.h b/plugins/ladspa_effect/calf/src/calf/lv2_external_ui.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/lv2_external_ui.h rename to plugins/ladspa_effect/calf/src/calf/lv2_external_ui.h diff --git a/plugins/ladspa_effect/calf/src/calf/lv2helpers.h b/plugins/ladspa_effect/calf/src/calf/lv2helpers.h new file mode 100644 index 000000000..21e6cfc00 --- /dev/null +++ b/plugins/ladspa_effect/calf/src/calf/lv2helpers.h @@ -0,0 +1,30 @@ +/* Calf DSP Library + * LV2-related helper classes and functions + * + * Copyright (C) 2001-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_LV2HELPERS_H +#define CALF_LV2HELPERS_H + +#if USE_LV2 + +#include +#include + +#endif +#endif diff --git a/plugins/ladspa_effect/calf/calf/lv2wrap.h b/plugins/ladspa_effect/calf/src/calf/lv2wrap.h similarity index 56% rename from plugins/ladspa_effect/calf/calf/lv2wrap.h rename to plugins/ladspa_effect/calf/src/calf/lv2wrap.h index fcbff1023..6a9bc40d0 100644 --- a/plugins/ladspa_effect/calf/calf/lv2wrap.h +++ b/plugins/ladspa_effect/calf/src/calf/lv2wrap.h @@ -33,12 +33,14 @@ #include #include #include +#include namespace calf_plugins { -template -struct lv2_instance: public plugin_ctl_iface, public progress_report_iface, public Module +struct lv2_instance: public plugin_ctl_iface, public progress_report_iface { + const plugin_metadata_iface *metadata; + audio_module_iface *module; bool set_srate; int srate_to_set; LV2_MIDI *midi_data; @@ -48,121 +50,120 @@ struct lv2_instance: public plugin_ctl_iface, public progress_report_iface, publ uint32_t midi_event_type; std::vector message_params; LV2_Progress *progress_report_feature; - lv2_instance() + float **ins, **outs, **params; + int out_count; + lv2_instance(audio_module_iface *_module) { - for (int i=0; i < Module::in_count; i++) - Module::ins[i] = NULL; - for (int i=0; i < Module::out_count; i++) - Module::outs[i] = NULL; - for (int i=0; i < Module::param_count; i++) - Module::params[i] = NULL; + module = _module; + module->get_port_arrays(ins, outs, params); + metadata = module->get_metadata_iface(); + metadata->get_message_context_parameters(message_params); + out_count = metadata->get_output_count(); + uri_map = NULL; midi_data = NULL; event_data = NULL; - midi_event_type = 0xFFFFFFFF; - set_srate = true; - srate_to_set = 44100; - get_message_context_parameters(message_params); progress_report_feature = NULL; + midi_event_type = 0xFFFFFFFF; + + srate_to_set = 44100; + set_srate = true; // printf("message params %d\n", (int)message_params.size()); } /// This, and not Module::post_instantiate, is actually called by lv2_wrapper class void post_instantiate() { if (progress_report_feature) - Module::progress_report = this; - Module::post_instantiate(); - } - virtual parameter_properties *get_param_props(int param_no) - { - return &Module::param_props[param_no]; - } - virtual float get_param_value(int param_no) - { - return *Module::params[param_no]; - } - virtual void set_param_value(int param_no, float value) - { - *Module::params[param_no] = value; - } - virtual int get_param_count() - { - return Module::param_count; - } - virtual int get_param_port_offset() - { - return Module::in_count + Module::out_count; - } - virtual const char *get_gui_xml() { - return Module::get_gui_xml(); - } - virtual const line_graph_iface *get_line_graph_iface() const - { - return dynamic_cast(this); + module->set_progress_report_iface(this); + module->post_instantiate(); } virtual bool activate_preset(int bank, int program) { return false; } - virtual const char *get_name() const - { - return Module::get_name(); - } - virtual const char *get_id() const - { - return Module::get_id(); - } - virtual const char *get_label() const - { - return Module::get_label(); - } - virtual int get_input_count() const { return Module::in_count; } - virtual int get_output_count() const { return Module::out_count; } - virtual bool get_midi() const { return Module::support_midi; } virtual float get_level(unsigned int port) { return 0.f; } virtual void execute(int cmd_no) { - Module::execute(cmd_no); + module->execute(cmd_no); } virtual void report_progress(float percentage, const std::string &message) { if (progress_report_feature) (*progress_report_feature->progress)(progress_report_feature->context, percentage, !message.empty() ? message.c_str() : NULL); } void send_configures(send_configure_iface *sci) { - Module::send_configures(sci); + module->send_configures(sci); } uint32_t impl_message_run(const void *valid_inputs, void *output_ports) { + uint8_t *vi = (uint8_t *)valid_inputs; + int ofs = metadata->get_param_port_offset(); for (unsigned int i = 0; i < message_params.size(); i++) { int pn = message_params[i]; - parameter_properties &pp = *get_param_props(pn); - if ((pp.flags & PF_TYPEMASK) == PF_STRING - && (((LV2_String_Data *)Module::params[pn])->flags & LV2_STRING_DATA_CHANGED_FLAG)) { + const parameter_properties &pp = *metadata->get_param_props(pn); + int ppn = pn + ofs; + if ((pp.flags & PF_TYPEMASK) == PF_STRING && (vi[ppn >> 3] & (1 << (ppn & 7))) + && (((LV2_String_Data *)params[pn])->flags & LV2_STRING_DATA_CHANGED_FLAG)) { printf("Calling configure on %s\n", pp.short_name); - configure(pp.short_name, ((LV2_String_Data *)Module::params[pn])->data); + configure(pp.short_name, ((LV2_String_Data *)params[pn])->data); } } - return Module::message_run(valid_inputs, output_ports); + return module->message_run(valid_inputs, output_ports); } char *configure(const char *key, const char *value) { // disambiguation - the plugin_ctl_iface version is just a stub, so don't use it - return Module::configure(key, value); + return module->configure(key, value); } -#if 0 - // the default implementation should be fine - virtual void clear_preset() { - // This is never called in practice, at least for now - // However, it will change when presets are implemented - for (int i=0; i < Module::param_count; i++) - *Module::params[i] = Module::param_props[i].def_value; - /* - const char **p = Module::get_default_configure_vars(); - if (p) - { - for(; p[0]; p += 2) - configure(p[0], p[1]); + + void process_events(uint32_t &offset) { + struct LV2_Midi_Event: public LV2_Event { + unsigned char data[1]; + }; + unsigned char *data = (unsigned char *)(event_data->data); + for (uint32_t i = 0; i < event_data->event_count; i++) { + LV2_Midi_Event *item = (LV2_Midi_Event *)data; + uint32_t ts = item->frames; + // printf("Event: timestamp %d subframes %d type %d vs %d\n", item->frames, item->subframes, item->type, mod->midi_event_type); + if (ts > offset) + { + module->process_slice(offset, ts); + offset = ts; + } + if (item->type == midi_event_type) + { + // printf("Midi message %x %x %x %x %d\n", item->data[0], item->data[1], item->data[2], item->data[3], item->size); + switch(item->data[0] >> 4) + { + case 8: module->note_off(item->data[1], item->data[2]); break; + case 9: module->note_on(item->data[1], item->data[2]); break; + case 11: module->control_change(item->data[1], item->data[2]); break; + case 12: module->program_change(item->data[1]); break; + case 13: module->channel_pressure(item->data[1]); break; + case 14: module->pitch_bend(item->data[1] + 128 * item->data[2] - 8192); break; + } + } + else + if (item->type == 0 && event_feature) + event_feature->lv2_event_unref(event_feature->callback_data, item); + // printf("timestamp %f item size %d first byte %x\n", item->timestamp, item->size, item->data[0]); + data += ((sizeof(LV2_Event) + item->size + 7))&~7; } - */ } -#endif + + virtual float get_param_value(int param_no) + { + // XXXKF hack + if (param_no >= metadata->get_param_count()) + return 0; + return (*params)[param_no]; + } + virtual void set_param_value(int param_no, float value) + { + // XXXKF hack + if (param_no >= metadata->get_param_count()) + return; + *params[param_no] = value; + } + virtual const plugin_metadata_iface *get_metadata_iface() const { return metadata; } + virtual const line_graph_iface *get_line_graph_iface() const { return module->get_line_graph_iface(); } + virtual int send_status_updates(send_updates_iface *sui, int last_serial) { return module->send_status_updates(sui, last_serial); } }; struct LV2_Calf_Descriptor { @@ -172,7 +173,7 @@ struct LV2_Calf_Descriptor { template struct lv2_wrapper { - typedef lv2_instance instance; + typedef lv2_instance instance; static LV2_Descriptor descriptor; static LV2_Calf_Descriptor calf_descriptor; static LV2MessageContext message_context; @@ -196,10 +197,11 @@ struct lv2_wrapper } static void cb_connect(LV2_Handle Instance, uint32_t port, void *DataLocation) { - unsigned long ins = Module::in_count; - unsigned long outs = Module::out_count; - unsigned long params = Module::param_count; instance *const mod = (instance *)Instance; + const plugin_metadata_iface *md = mod->metadata; + unsigned long ins = md->get_input_count(); + unsigned long outs = md->get_output_count(); + unsigned long params = md->get_param_count(); if (port < ins) mod->ins[port] = (float *)DataLocation; else if (port < ins + outs) @@ -208,7 +210,7 @@ struct lv2_wrapper int i = port - ins - outs; mod->params[i] = (float *)DataLocation; } - else if (Module::support_midi && port == ins + outs + params) { + else if (md->get_midi() && port == ins + outs + params) { mod->event_data = (LV2_Event_Buffer *)DataLocation; } } @@ -220,12 +222,12 @@ struct lv2_wrapper static void cb_deactivate(LV2_Handle Instance) { instance *const mod = (instance *)Instance; - mod->deactivate(); + mod->module->deactivate(); } static LV2_Handle cb_instantiate(const LV2_Descriptor * Descriptor, double sample_rate, const char *bundle_path, const LV2_Feature *const *features) { - instance *mod = new instance(); + instance *mod = new instance(new Module); // XXXKF some people use fractional sample rates; we respect them ;-) mod->srate_to_set = (uint32_t)sample_rate; mod->set_srate = true; @@ -252,79 +254,30 @@ struct lv2_wrapper mod->post_instantiate(); return mod; } - static inline void zero_by_mask(Module *module, uint32_t mask, uint32_t offset, uint32_t nsamples) - { - for (int i=0; iouts[i] + offset, nsamples); - } - } - } static plugin_ctl_iface *cb_get_pci(LV2_Handle Instance) { return static_cast(Instance); } - static inline void process_slice(Module *mod, uint32_t offset, uint32_t end) - { - while(offset < end) - { - uint32_t newend = std::min(offset + MAX_SAMPLE_RUN, end); - uint32_t out_mask = mod->process(offset, newend - offset, -1, -1); - zero_by_mask(mod, out_mask, offset, newend - offset); - offset = newend; - } - } - static uint32_t cb_message_run(LV2_Handle Instance, const void *valid_inputs, void *outputs_written) { instance *mod = (instance *)Instance; return mod->impl_message_run(valid_inputs, outputs_written); } static void cb_run(LV2_Handle Instance, uint32_t SampleCount) { - instance *const mod = (instance *)Instance; - if (mod->set_srate) { - mod->set_sample_rate(mod->srate_to_set); + instance *const inst = (instance *)Instance; + audio_module_iface *mod = inst->module; + if (inst->set_srate) { + mod->set_sample_rate(inst->srate_to_set); mod->activate(); - mod->set_srate = false; + inst->set_srate = false; } mod->params_changed(); uint32_t offset = 0; - if (mod->event_data) + if (inst->event_data) { - // printf("Event data: count %d\n", mod->event_data->event_count); - struct LV2_Midi_Event: public LV2_Event { - unsigned char data[1]; - }; - unsigned char *data = (unsigned char *)(mod->event_data->data); - for (uint32_t i = 0; i < mod->event_data->event_count; i++) { - LV2_Midi_Event *item = (LV2_Midi_Event *)data; - uint32_t ts = item->frames; - // printf("Event: timestamp %d subframes %d type %d vs %d\n", item->frames, item->subframes, item->type, mod->midi_event_type); - if (ts > offset) - { - process_slice(mod, offset, ts); - offset = ts; - } - if (item->type == mod->midi_event_type) - { - // printf("Midi message %x %x %x %x %d\n", item->data[0], item->data[1], item->data[2], item->data[3], item->size); - switch(item->data[0] >> 4) - { - case 8: mod->note_off(item->data[1], item->data[2]); break; - case 9: mod->note_on(item->data[1], item->data[2]); break; - case 11: mod->control_change(item->data[1], item->data[2]); break; - case 12: mod->program_change(item->data[1]); break; - case 14: mod->pitch_bend(item->data[1] + 128 * item->data[2] - 8192); break; - } - } - else - if (item->type == 0 && mod->event_feature) - mod->event_feature->lv2_event_unref(mod->event_feature->callback_data, item); - // printf("timestamp %f item size %d first byte %x\n", item->timestamp, item->size, item->data[0]); - data += ((sizeof(LV2_Event) + item->size + 7))&~7; - } + inst->process_events(offset); } - process_slice(mod, offset, SampleCount); + inst->module->process_slice(offset, SampleCount); } static void cb_cleanup(LV2_Handle Instance) { instance *const mod = (instance *)Instance; diff --git a/plugins/ladspa_effect/calf/calf/metadata.h b/plugins/ladspa_effect/calf/src/calf/metadata.h similarity index 87% rename from plugins/ladspa_effect/calf/calf/metadata.h rename to plugins/ladspa_effect/calf/src/calf/metadata.h index 22d9f22a5..6e3f94cf2 100644 --- a/plugins/ladspa_effect/calf/calf/metadata.h +++ b/plugins/ladspa_effect/calf/src/calf/metadata.h @@ -70,7 +70,7 @@ struct reverb_metadata: public plugin_metadata struct vintage_delay_metadata: public plugin_metadata { - enum { par_bpm, par_divide, par_time_l, par_time_r, par_feedback, par_amount, par_mixmode, par_medium, par_dryamount, param_count }; + enum { par_bpm, par_divide, par_time_l, par_time_r, par_feedback, par_amount, par_mixmode, par_medium, par_dryamount, par_width, param_count }; enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, support_midi = false, require_midi = false }; PLUGIN_NAME_ID_LABEL("vintage_delay", "vintagedelay", "Vintage Delay") }; @@ -103,9 +103,15 @@ struct monosynth_metadata: public plugin_metadata { enum { wave_saw, wave_sqr, wave_pulse, wave_sine, wave_triangle, wave_varistep, wave_skewsaw, wave_skewsqr, wave_test1, wave_test2, wave_test3, wave_test4, wave_test5, wave_test6, wave_test7, wave_test8, wave_count }; enum { flt_lp12, flt_lp24, flt_2lp12, flt_hp12, flt_lpbr, flt_hpbr, flt_bp6, flt_2bp6 }; - enum { par_wave1, par_wave2, par_pw1, par_pw2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_envmod, par_envtores, par_envtoamp, par_attack, par_decay, par_sustain, par_fade, par_release, + enum { par_wave1, par_wave2, par_pw1, par_pw2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_env1tocutoff, par_env1tores, par_env1toamp, + par_env1attack, par_env1decay, par_env1sustain, par_env1fade, par_env1release, par_keyfollow, par_legato, par_portamento, par_vel2filter, par_vel2amp, par_master, par_pwhlrange, par_lforate, par_lfodelay, par_lfofilter, par_lfopitch, par_lfopw, par_mwhl_lfo, par_scaledetune, + par_env2tocutoff, par_env2tores, par_env2toamp, + par_env2attack, par_env2decay, par_env2sustain, par_env2fade, par_env2release, + par_stretch1, + par_lfo1trig, par_lfo2trig, + par_lfo2rate, par_lfo2delay, param_count }; enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true }; enum { step_size = 64, step_shift = 6 }; @@ -115,7 +121,9 @@ struct monosynth_metadata: public plugin_metadata modsrc_pressure, modsrc_modwheel, modsrc_env1, + modsrc_env2, modsrc_lfo1, + modsrc_lfo2, modsrc_count, }; enum { @@ -128,6 +136,7 @@ struct monosynth_metadata: public plugin_metadata moddest_o2detune, moddest_o1pw, moddest_o2pw, + moddest_o1stretch, moddest_count, }; PLUGIN_NAME_ID_LABEL("monosynth", "monosynth", "Monosynth") @@ -257,6 +266,44 @@ struct pulsator_metadata: public plugin_metadata PLUGIN_NAME_ID_LABEL("pulsator", "pulsator", "Pulsator") }; +/// Markus's Saturator - metadata +struct saturator_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, param_mix, param_meter_in, + param_meter_out, param_clip_in, param_clip_out, param_drive, param_blend, param_meter_drive, + param_lp_pre_freq, param_hp_pre_freq, param_lp_post_freq, param_hp_post_freq, + param_p_freq, param_p_level, param_p_q, param_count }; + PLUGIN_NAME_ID_LABEL("saturator", "saturator", "Saturator") +}; +/// Markus's Exciter - metadata +struct exciter_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, param_amount, param_meter_in, + param_meter_out, param_clip_in, param_clip_out, param_drive, param_blend, param_meter_drive, + param_freq, param_listen, param_count }; + PLUGIN_NAME_ID_LABEL("exciter", "exciter", "Exciter") +}; +/// Markus's Bass Enhancer - metadata +struct bassenhancer_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, param_amount, param_meter_in, + param_meter_out, param_clip_in, param_clip_out, param_drive, param_blend, param_meter_drive, + param_freq, param_listen, param_count }; + PLUGIN_NAME_ID_LABEL("bassenhancer", "bassenhancer", "Bass Enhancer") +}; + +/// Damien's gate - metadata +struct gate_metadata: public plugin_metadata +{ + enum { in_count = 3, out_count = 2, ins_optional = 1, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true }; + enum { param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_aweighting, param_gating, param_peak, param_clip, param_bypass, param_range, param_mono, param_trigger, // param_freq, param_bw, + param_count }; + PLUGIN_NAME_ID_LABEL("gate", "gate", "Gate") +}; + /// Organ - enums for parameter IDs etc. (this mess is caused by organ split between plugin and generic class - which was /// a bad design decision and should be sorted out some day) XXXKF @todo struct organ_enums @@ -346,16 +393,14 @@ struct organ_metadata: public organ_enums, public plugin_metadata { - enum { par_master, par_soundfont, par_interpolation, par_reverb, par_chorus, param_count }; + enum { par_master, par_interpolation, par_reverb, par_chorus, par_soundfont, par_preset_key_set, param_count }; enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = false }; PLUGIN_NAME_ID_LABEL("fluidsynth", "fluidsynth", "Fluidsynth") - const char **get_default_configure_vars(); }; /// Wavetable - metadata diff --git a/plugins/ladspa_effect/calf/calf/modmatrix.h b/plugins/ladspa_effect/calf/src/calf/modmatrix.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/modmatrix.h rename to plugins/ladspa_effect/calf/src/calf/modmatrix.h diff --git a/plugins/ladspa_effect/calf/calf/modulelist.h b/plugins/ladspa_effect/calf/src/calf/modulelist.h similarity index 85% rename from plugins/ladspa_effect/calf/calf/modulelist.h rename to plugins/ladspa_effect/calf/src/calf/modulelist.h index dabd2c355..baaa5d90f 100644 --- a/plugins/ladspa_effect/calf/calf/modulelist.h +++ b/plugins/ladspa_effect/calf/src/calf/modulelist.h @@ -17,6 +17,10 @@ PER_MODULE_ITEM(equalizer5band, false, "eq5") PER_MODULE_ITEM(equalizer8band, false, "eq8") PER_MODULE_ITEM(equalizer12band, false, "eq12") + PER_MODULE_ITEM(saturator, false, "saturator") + PER_MODULE_ITEM(exciter, false, "exciter") + PER_MODULE_ITEM(bassenhancer, false, "bassenhancer") + PER_MODULE_ITEM(gate, false, "gate") #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 new file mode 100644 index 000000000..d20421879 --- /dev/null +++ b/plugins/ladspa_effect/calf/src/calf/modules.h @@ -0,0 +1,245 @@ +/* Calf DSP plugin pack + * Assorted 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_H +#define CALF_MODULES_H + +#include +#include +#include "biquad.h" +#include "inertia.h" +#include "audio_fx.h" +#include "giface.h" +#include "metadata.h" +#include "loudness.h" +#include "primitives.h" + +namespace calf_plugins { + +struct ladspa_plugin_info; + +class reverb_audio_module: public audio_module +{ +public: + dsp::reverb reverb; + dsp::simple_delay<16384, dsp::stereo_sample > pre_delay; + dsp::onepole left_lo, right_lo, left_hi, right_hi; + uint32_t srate; + dsp::gain_smoothing amount, dryamount; + int predelay_amt; + float meter_wet, meter_out; + uint32_t clip; + + void params_changed(); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + void activate(); + void set_sample_rate(uint32_t sr); + void deactivate(); +}; + +class vintage_delay_audio_module: public audio_module +{ +public: + // 1MB of delay memory per channel... uh, RAM is cheap + enum { MAX_DELAY = 262144, ADDR_MASK = MAX_DELAY - 1 }; + enum { MIXMODE_STEREO, MIXMODE_PINGPONG, MIXMODE_LR, MIXMODE_RL }; + float buffers[2][MAX_DELAY]; + int bufptr, deltime_l, deltime_r, mixmode, medium, old_medium; + /// number of table entries written (value is only important when it is less than MAX_DELAY, which means that the buffer hasn't been totally filled yet) + int age; + + dsp::gain_smoothing amt_left, amt_right, fb_left, fb_right, dry, chmix; + + dsp::biquad_d2 biquad_left[2], biquad_right[2]; + + uint32_t srate; + + vintage_delay_audio_module(); + + void params_changed(); + void activate(); + void deactivate(); + void set_sample_rate(uint32_t sr); + void calc_filters(); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); +}; + +template +class filter_module_with_inertia: public audio_module, public FilterClass +{ +public: + /// These are pointers to the ins, outs, params arrays in the main class + typedef filter_module_with_inertia inertia_filter_module; + using audio_module::ins; + using audio_module::outs; + using audio_module::params; + + dsp::inertia inertia_cutoff, inertia_resonance, inertia_gain; + dsp::once_per_n timer; + bool is_active; + mutable volatile int last_generation, last_calculated_generation; + + filter_module_with_inertia(float **ins, float **outs, float **params) + : inertia_cutoff(dsp::exponential_ramp(128), 20) + , inertia_resonance(dsp::exponential_ramp(128), 20) + , inertia_gain(dsp::exponential_ramp(128), 1.0) + , timer(128) + { + is_active = false; + } + + void calculate_filter() + { + float freq = inertia_cutoff.get_last(); + // printf("freq=%g inr.cnt=%d timer.left=%d\n", freq, inertia_cutoff.count, timer.left); + // XXXKF this is resonance of a single stage, obviously for three stages, resonant gain will be different + float q = inertia_resonance.get_last(); + int mode = dsp::fastf2i_drm(*params[Metadata::par_mode]); + // printf("freq = %f q = %f mode = %d\n", freq, q, mode); + + int inertia = dsp::fastf2i_drm(*params[Metadata::par_inertia]); + if (inertia != inertia_cutoff.ramp.length()) { + inertia_cutoff.ramp.set_length(inertia); + inertia_resonance.ramp.set_length(inertia); + inertia_gain.ramp.set_length(inertia); + } + + FilterClass::calculate_filter(freq, q, mode, inertia_gain.get_last()); + } + + virtual void params_changed() + { + calculate_filter(); + } + + void on_timer() + { + int gen = last_generation; + inertia_cutoff.step(); + inertia_resonance.step(); + inertia_gain.step(); + calculate_filter(); + last_calculated_generation = gen; + } + + void activate() + { + params_changed(); + FilterClass::filter_activate(); + timer = dsp::once_per_n(FilterClass::srate / 1000); + timer.start(); + is_active = true; + } + + void set_sample_rate(uint32_t sr) + { + FilterClass::srate = sr; + } + + + void deactivate() + { + is_active = false; + } + + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { +// printf("sr=%d cutoff=%f res=%f mode=%f\n", FilterClass::srate, *params[Metadata::par_cutoff], *params[Metadata::par_resonance], *params[Metadata::par_mode]); + uint32_t ostate = 0; + numsamples += offset; + while(offset < numsamples) { + uint32_t numnow = numsamples - offset; + // if inertia's inactive, we can calculate the whole buffer at once + if (inertia_cutoff.active() || inertia_resonance.active() || inertia_gain.active()) + numnow = timer.get(numnow); + + if (outputs_mask & 1) { + ostate |= FilterClass::process_channel(0, ins[0] + offset, outs[0] + offset, numnow, inputs_mask & 1); + } + if (outputs_mask & 2) { + ostate |= FilterClass::process_channel(1, ins[1] + offset, outs[1] + offset, numnow, inputs_mask & 2); + } + + if (timer.elapsed()) { + on_timer(); + } + offset += numnow; + } + return ostate; + } +}; + +/// biquad filter module +class filter_audio_module: + public filter_module_with_inertia, + public frequency_response_line_graph +{ + mutable float old_cutoff, old_resonance, old_mode; +public: + filter_audio_module() + : filter_module_with_inertia(ins, outs, params) + { + last_generation = 0; + } + void params_changed() + { + inertia_cutoff.set_inertia(*params[par_cutoff]); + inertia_resonance.set_inertia(*params[par_resonance]); + inertia_filter_module::params_changed(); + } + + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + +/// Filterclavier --- MIDI controlled filter by Hans Baier +class filterclavier_audio_module: + public filter_module_with_inertia, + public frequency_response_line_graph +{ + using audio_module::ins; + using audio_module::outs; + using audio_module::params; + + const float min_gain; + const float max_gain; + + int last_note; + int last_velocity; + +public: + filterclavier_audio_module(); + void params_changed(); + void activate(); + void set_sample_rate(uint32_t sr); + void deactivate(); + + /// MIDI control + virtual void note_on(int note, int vel); + virtual void note_off(int note, int vel); + + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + +private: + void adjust_gain_according_to_filter_mode(int velocity); +}; + +}; + +#endif diff --git a/plugins/ladspa_effect/calf/src/calf/modules_comp.h b/plugins/ladspa_effect/calf/src/calf/modules_comp.h new file mode 100644 index 000000000..1c85820ec --- /dev/null +++ b/plugins/ladspa_effect/calf/src/calf/modules_comp.h @@ -0,0 +1,249 @@ +/* Calf DSP plugin pack + * Compression 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_COMP_H +#define CALF_MODULES_COMP_H + +#include +#include +#include "biquad.h" +#include "inertia.h" +#include "audio_fx.h" +#include "giface.h" +#include "loudness.h" +#include "metadata.h" + +namespace calf_plugins { + +/// Not a true _audio_module style class, just pretends to be one! +class gain_reduction_audio_module +{ +private: + float linSlope, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop; + float compressedKneeStop, adjKneeStart, thres; + float attack, release, threshold, ratio, knee, makeup, detection, stereo_link, bypass, mute, meter_out, meter_comp; + mutable float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_mute, old_detection, old_stereo_link; + mutable volatile int last_generation; + uint32_t srate; + bool is_active; + inline float output_level(float slope) const; + inline float output_gain(float linSlope, bool rms) const; +public: + gain_reduction_audio_module(); + void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float stl, float byp, float mu); + void update_curve(); + void process(float &left, float &right, const float *det_left = NULL, const float *det_right = NULL); + void activate(); + void deactivate(); + int id; + void set_sample_rate(uint32_t sr); + float get_output_level(); + float get_comp_level(); + bool get_graph(int subindex, float *data, int points, cairo_iface *context) const; + bool get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context) const; + bool get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; + int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + +/// Compressor by Thor +class compressor_audio_module: public audio_module, public line_graph_iface { +private: + typedef compressor_audio_module AM; + uint32_t clip_in, clip_out; + float meter_in, meter_out; + gain_reduction_audio_module compressor; +public: + typedef std::complex cfloat; + uint32_t srate; + bool is_active; + mutable volatile int last_generation, last_calculated_generation; + compressor_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + void set_sample_rate(uint32_t sr); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; + bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; + int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + +/// Sidecain Compressor by Markus Schmidt (based on Thor's compressor and Krzysztof's filters) +class sidechaincompressor_audio_module: public audio_module, public frequency_response_line_graph { +private: + typedef sidechaincompressor_audio_module AM; + enum CalfScModes { + WIDEBAND, + DEESSER_WIDE, + DEESSER_SPLIT, + DERUMBLER_WIDE, + DERUMBLER_SPLIT, + WEIGHTED_1, + WEIGHTED_2, + WEIGHTED_3, + BANDPASS_1, + BANDPASS_2 + }; + mutable float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old; + mutable float f1_freq_old1, f2_freq_old1, f1_level_old1, f2_level_old1; + CalfScModes sc_mode; + mutable CalfScModes sc_mode_old, sc_mode_old1; + float f1_active, f2_active; + uint32_t clip_in, clip_out; + float meter_in, meter_out; + gain_reduction_audio_module compressor; + dsp::biquad_d2 f1L, f1R, f2L, f2R; +public: + typedef std::complex cfloat; + uint32_t srate; + bool is_active; + mutable volatile int last_generation, last_calculated_generation; + sidechaincompressor_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + cfloat h_z(const cfloat &z) const; + float freq_gain(int index, double freq, uint32_t sr) const; + void set_sample_rate(uint32_t sr); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; + bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; + int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + +/// Multibandcompressor by Markus Schmidt +class multibandcompressor_audio_module: public audio_module, public line_graph_iface { +private: + typedef multibandcompressor_audio_module AM; + static const int strips = 4; + bool mute[strips]; + uint32_t clip_inL, clip_inR, clip_outL, clip_outR; + float meter_inL, meter_inR, meter_outL, meter_outR; + gain_reduction_audio_module strip[strips]; + dsp::biquad_d2 lpL0, lpR0, lpL1, lpR1, lpL2, lpR2, hpL0, hpR0, hpL1, hpR1, hpL2, hpR2; + float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1]; +public: + uint32_t srate; + bool is_active; + multibandcompressor_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + void set_sample_rate(uint32_t sr); + const gain_reduction_audio_module *get_strip_by_param_index(int index) const; + virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; + virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; + virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + +/// Deesser by Markus Schmidt (based on Thor's compressor and Krzysztof's filters) +class deesser_audio_module: public audio_module, public frequency_response_line_graph { +private: + enum CalfDeessModes { + WIDE, + SPLIT + }; + mutable float f1_freq_old, f2_freq_old, f1_level_old, f2_level_old, f2_q_old; + mutable float f1_freq_old1, f2_freq_old1, f1_level_old1, f2_level_old1, f2_q_old1; + uint32_t detected_led; + float detected, clip_out; + uint32_t clip_led; + gain_reduction_audio_module compressor; + dsp::biquad_d2 hpL, hpR, lpL, lpR, pL, pR; +public: + uint32_t srate; + bool is_active; + mutable volatile int last_generation, last_calculated_generation; + deesser_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + float freq_gain(int index, double freq, uint32_t sr) const + { + return hpL.freq_gain(freq, sr) * pL.freq_gain(freq, sr); + } + void set_sample_rate(uint32_t sr); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; + int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + + +class gate_audio_module: public audio_module, public line_graph_iface { +private: + float linSlope, peak, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop, linKneeStop, threshold, ratio, knee, makeup, compressedKneeStop, adjKneeStart, range; + mutable float old_threshold, old_ratio, old_knee, old_makeup, old_bypass, old_range, old_trigger, old_mono; + mutable volatile int last_generation; + uint32_t clip; + dsp::aweighter awL, awR; + dsp::biquad_d2 bpL, bpR; +public: + uint32_t srate; + bool is_active; + gate_audio_module(); + void activate(); + void deactivate(); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + + inline float output_level(float slope) const { + bool rms = *params[param_detection] == 0; + return slope * output_gain(rms ? slope*slope : slope, rms) * makeup; + } + + inline float output_gain(float linSlope, bool rms) const { + if(linSlope < linKneeStop) { + float slope = log(linSlope); + + //float tratio = rms ? sqrt(ratio) : ratio; + float tratio = ratio; + float gain = 0.f; + float delta = 0.f; + if(IS_FAKE_INFINITY(ratio)) + tratio = 1000.f; + gain = (slope-threshold) * tratio + threshold; + delta = tratio; + + if(knee > 1.f && slope > kneeStart ) { + gain = dsp::hermite_interpolation(slope, kneeStart, kneeStop, ((kneeStart - threshold) * tratio + threshold), kneeStop, delta,1.f); + } + return std::max(range, expf(gain-slope)); + } + + + return 1.f; + } + + void set_sample_rate(uint32_t sr); + + virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; + virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; + virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + + +}; + +#endif diff --git a/plugins/ladspa_effect/calf/calf/modules_dev.h b/plugins/ladspa_effect/calf/src/calf/modules_dev.h similarity index 96% rename from plugins/ladspa_effect/calf/calf/modules_dev.h rename to plugins/ladspa_effect/calf/src/calf/modules_dev.h index 9861d1495..727e5ec73 100644 --- a/plugins/ladspa_effect/calf/calf/modules_dev.h +++ b/plugins/ladspa_effect/calf/src/calf/modules_dev.h @@ -22,7 +22,6 @@ #define __CALF_MODULES_DEV_H #include -#include #if ENABLE_EXPERIMENTAL #include @@ -35,11 +34,6 @@ namespace calf_plugins { /// Tiny wrapper for fluidsynth class fluidsynth_audio_module: public audio_module { -public: - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - protected: /// Current sample rate uint32_t srate; diff --git a/plugins/ladspa_effect/calf/src/calf/modules_dist.h b/plugins/ladspa_effect/calf/src/calf/modules_dist.h new file mode 100644 index 000000000..6c49c372d --- /dev/null +++ b/plugins/ladspa_effect/calf/src/calf/modules_dist.h @@ -0,0 +1,96 @@ +/* Calf DSP plugin pack + * Distortion 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_DIST_H +#define CALF_MODULES_DIST_H + +#include +#include +#include "biquad.h" +#include "inertia.h" +#include "audio_fx.h" +#include "giface.h" +#include "metadata.h" + +namespace calf_plugins { + +/// Saturator by Markus Schmidt (based on Krzysztof's filters and Tom's distortion algorythm) +class saturator_audio_module: public audio_module { +private: + float hp_pre_freq_old, lp_pre_freq_old; + float hp_post_freq_old, lp_post_freq_old; + float p_level_old, p_freq_old, p_q_old; + uint32_t clip_in, clip_out; + float meter_in, meter_out, meter_drive; + dsp::biquad_d2 lp[2][4], hp[2][4]; + dsp::biquad_d2 p[2]; + dsp::tap_distortion dist[2]; +public: + uint32_t srate; + bool is_active; + saturator_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + void set_sample_rate(uint32_t sr); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); +}; + +/// Exciter by Markus Schmidt (based on Krzysztof's filters and Tom's distortion algorythm) +class exciter_audio_module: public audio_module { +private: + float freq_old; + uint32_t clip_in, clip_out; + float meter_in, meter_out, meter_drive; + dsp::biquad_d2 hp[2][4]; + dsp::tap_distortion dist[2]; +public: + uint32_t srate; + bool is_active; + exciter_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + void set_sample_rate(uint32_t sr); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); +}; + +/// Bass Enhancer by Markus Schmidt (based on Krzysztof's filters and Tom's distortion algorythm) +class bassenhancer_audio_module: public audio_module { +private: + float freq_old; + uint32_t clip_in, clip_out; + float meter_in, meter_out, meter_drive; + dsp::biquad_d2 lp[2][4]; + dsp::tap_distortion dist[2]; +public: + uint32_t srate; + bool is_active; + bassenhancer_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + void set_sample_rate(uint32_t sr); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); +}; + +}; + +#endif diff --git a/plugins/ladspa_effect/calf/src/calf/modules_eq.h b/plugins/ladspa_effect/calf/src/calf/modules_eq.h new file mode 100644 index 000000000..14cad3ce8 --- /dev/null +++ b/plugins/ladspa_effect/calf/src/calf/modules_eq.h @@ -0,0 +1,89 @@ +/* Calf DSP plugin pack + * Equalization 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_EQ_H +#define CALF_MODULES_EQ_H + +#include +#include +#include "biquad.h" +#include "inertia.h" +#include "audio_fx.h" +#include "giface.h" +#include "metadata.h" + +namespace calf_plugins { + +/// Equalizer N Band by Markus Schmidt (based on Krzysztof's filters) +template +class equalizerNband_audio_module: public audio_module, public frequency_response_line_graph { +public: + typedef audio_module AM; + using AM::ins; + using AM::outs; + using AM::params; + using AM::in_count; + using AM::out_count; + using AM::param_count; + using AM::PeakBands; +private: + enum { graph_param_count = BaseClass::last_graph_param - BaseClass::first_graph_param + 1, params_per_band = AM::param_p2_active - AM::param_p1_active }; + float hp_mode_old, hp_freq_old; + float lp_mode_old, lp_freq_old; + float ls_level_old, ls_freq_old; + float hs_level_old, hs_freq_old; + float p_level_old[PeakBands], p_freq_old[PeakBands], p_q_old[PeakBands]; + mutable float old_params_for_graph[graph_param_count]; + uint32_t clip_inL, clip_outL, clip_inR, clip_outR; + float meter_inL, meter_outL, meter_inR, meter_outR; + CalfEqMode hp_mode, lp_mode; + dsp::biquad_d2 hp[3][2], lp[3][2]; + dsp::biquad_d2 lsL, lsR, hsL, hsR; + dsp::biquad_d2 pL[PeakBands], pR[PeakBands]; + + inline void process_hplp(float &left, float &right); +public: + typedef std::complex cfloat; + uint32_t srate; + bool is_active; + mutable volatile int last_generation, last_calculated_generation; + equalizerNband_audio_module(); + void activate(); + void deactivate(); + + void params_changed(); + float freq_gain(int index, double freq, uint32_t sr) const; + void set_sample_rate(uint32_t sr) + { + srate = sr; + } + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; + int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const; +}; + +typedef equalizerNband_audio_module equalizer5band_audio_module; +typedef equalizerNband_audio_module equalizer8band_audio_module; +typedef equalizerNband_audio_module equalizer12band_audio_module; + +}; + +#endif diff --git a/plugins/ladspa_effect/calf/src/calf/modules_mod.h b/plugins/ladspa_effect/calf/src/calf/modules_mod.h new file mode 100644 index 000000000..78244913b --- /dev/null +++ b/plugins/ladspa_effect/calf/src/calf/modules_mod.h @@ -0,0 +1,190 @@ +/* Calf DSP plugin pack + * Modulation effect 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_MOD_H +#define CALF_MODULES_MOD_H + +#include +#include +#include "biquad.h" +#include "inertia.h" +#include "audio_fx.h" +#include "giface.h" +#include "metadata.h" +#include "multichorus.h" + +namespace calf_plugins { + +class flanger_audio_module: public audio_module, public frequency_response_line_graph +{ +public: + dsp::simple_flanger left, right; + uint32_t srate; + bool clear_reset; + float last_r_phase; + bool is_active; +public: + flanger_audio_module() { + is_active = false; + } + void set_sample_rate(uint32_t sr); + void params_changed(); + void params_reset(); + void activate(); + void deactivate(); + uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) { + left.process(outs[0] + offset, ins[0] + offset, nsamples); + right.process(outs[1] + offset, ins[1] + offset, nsamples); + return outputs_mask; // XXXKF allow some delay after input going blank + } + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + float freq_gain(int subindex, float freq, float srate) const; +}; + +class phaser_audio_module: public audio_module, public frequency_response_line_graph +{ +public: + enum { MaxStages = 12 }; + uint32_t srate; + bool clear_reset; + float last_r_phase; + dsp::simple_phaser left, right; + float x1vals[2][MaxStages], y1vals[2][MaxStages]; + bool is_active; +public: + phaser_audio_module(); + void params_changed(); + void params_reset(); + void activate(); + void set_sample_rate(uint32_t sr); + void deactivate(); + uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) { + left.process(outs[0] + offset, ins[0] + offset, nsamples); + right.process(outs[1] + offset, ins[1] + offset, nsamples); + return outputs_mask; // XXXKF allow some delay after input going blank + } + 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; + float freq_gain(int subindex, float freq, float srate) const; +}; + +class rotary_speaker_audio_module: public audio_module +{ +public: + /// Current phases and phase deltas for bass and treble rotors + uint32_t phase_l, dphase_l, phase_h, dphase_h; + dsp::simple_delay<1024, float> delay; + dsp::biquad_d2 crossover1l, crossover1r, crossover2l, crossover2r; + dsp::simple_delay<8, float> phaseshift; + uint32_t srate; + int vibrato_mode; + /// Current CC1 (Modulation) value, normalized to [0, 1] + float mwhl_value; + /// Current CC64 (Hold) value, normalized to [0, 1] + float hold_value; + /// Current rotation speed for bass rotor - automatic mode + float aspeed_l; + /// Current rotation speed for treble rotor - automatic mode + float aspeed_h; + /// Desired speed (0=slow, 1=fast) - automatic mode + float dspeed; + /// Current rotation speed for bass rotor - manual mode + float maspeed_l; + /// Current rotation speed for treble rotor - manual mode + float maspeed_h; + + int meter_l, meter_h; + + rotary_speaker_audio_module(); + void set_sample_rate(uint32_t sr); + void setup(); + void activate(); + void deactivate(); + + void params_changed(); + void set_vibrato(); + /// Convert RPM speed to delta-phase + uint32_t rpm2dphase(float rpm); + /// Set delta-phase variables based on current calculated (and interpolated) RPM speed + void update_speed(); + void update_speed_manual(float delta); + /// Increase or decrease aspeed towards raspeed, with required negative and positive rate + bool incr_towards(float &aspeed, float raspeed, float delta_decc, float delta_acc); + uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask); + virtual void control_change(int ctl, int val); +}; + +/// A multitap stereo chorus thing +class multichorus_audio_module: public audio_module, public frequency_response_line_graph +{ +public: + uint32_t srate; + dsp::multichorus, dsp::filter_sum, dsp::biquad_d2<> >, 4096> left, right; + float last_r_phase; + float cutoff; + bool is_active; + +public: + multichorus_audio_module(); + void params_changed(); + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + void activate(); + void deactivate(); + void set_sample_rate(uint32_t sr); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + float freq_gain(int subindex, float freq, float srate) const; + bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const; + bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const; +}; + +/// Pulsator by Markus Schmidt +class pulsator_audio_module: public audio_module, public frequency_response_line_graph { +private: + typedef pulsator_audio_module AM; + uint32_t clip_inL, clip_inR, clip_outL, clip_outR; + float meter_inL, meter_inR, meter_outL, meter_outR; + float offset_old; + int mode_old; + bool clear_reset; + dsp::simple_lfo lfoL, lfoR; +public: + uint32_t srate; + bool is_active; + pulsator_audio_module(); + void activate(); + void deactivate(); + void params_changed(); + void set_sample_rate(uint32_t sr); + void params_reset() + { + if (clear_reset) { + *params[param_reset] = 0.f; + clear_reset = false; + } + } + uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + bool get_dot(int index, int subindex, float &x, float &y, int &size, 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/calf/modules_synths.h b/plugins/ladspa_effect/calf/src/calf/modules_synths.h similarity index 67% rename from plugins/ladspa_effect/calf/calf/modules_synths.h rename to plugins/ladspa_effect/calf/src/calf/modules_synths.h index d57f61f7b..3b7ca83a3 100644 --- a/plugins/ladspa_effect/calf/calf/modules_synths.h +++ b/plugins/ladspa_effect/calf/src/calf/modules_synths.h @@ -21,7 +21,6 @@ #ifndef __CALF_MODULES_SYNTHS_H #define __CALF_MODULES_SYNTHS_H -#include #include "biquad.h" #include "onepole.h" #include "audio_fx.h" @@ -29,8 +28,8 @@ #include "osc.h" #include "synth.h" #include "envelope.h" -#include "organ.h" #include "modmatrix.h" +#include "metadata.h" namespace calf_plugins { @@ -42,13 +41,10 @@ class monosynth_audio_module: public audio_module, public li { public: enum { mod_matrix_slots = 10 }; - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; uint32_t srate, crate; static dsp::waveform_family *waves; dsp::waveform_oscillator osc1, osc2; - dsp::triangle_lfo lfo; + dsp::triangle_lfo lfo1, lfo2; bool running, stopping, gate, force_fadeout; int last_key; @@ -66,16 +62,20 @@ public: /// Last used waveform number - OSC2 int prev_wave2; int filter_type, last_filter_type; - float freq, start_freq, target_freq, cutoff, decay_factor, fgain, fgain_delta, separation; + float freq, start_freq, target_freq, cutoff, fgain, fgain_delta, separation; float detune, xpose, xfade, ampctl, fltctl, queue_vel; - float odcr, porta_time, lfo_bend, lfo_clock, last_lfov, modwheel_value; + float odcr, porta_time, lfo_bend, lfo1_clock, lfo2_clock, modwheel_value; + /// Delay counter for LFOs + float lfo_clock; /// Last value of phase shift for pulse width emulation for OSC1 int32_t last_pwshift1; /// Last value of phase shift for pulse width emulation for OSC2 int32_t last_pwshift2; + /// Last value of stretch for osc sync emulation for OSC1 + int32_t last_stretch1; int queue_note_on, stop_count, modwheel_value_int; int legato; - dsp::adsr envelope; + dsp::adsr envelope1, envelope2; dsp::keystack stack; dsp::gain_smoothing master; /// Smoothed cutoff value @@ -149,82 +149,6 @@ public: uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask); }; -struct organ_audio_module: public audio_module, public dsp::drawbar_organ, public line_graph_iface -{ -public: - using drawbar_organ::note_on; - using drawbar_organ::note_off; - using drawbar_organ::control_change; - enum { param_count = drawbar_organ::param_count}; - float *ins[in_count]; - float *outs[out_count]; - float *params[param_count]; - dsp::organ_parameters par_values; - uint32_t srate; - bool panic_flag; - /// Value for configure variable map_curve - std::string var_map_curve; - - organ_audio_module() - : drawbar_organ(&par_values) - { - var_map_curve = "2\n0 1\n1 1\n"; // XXXKF hacky bugfix - } - - void post_instantiate() - { - dsp::organ_voice_base::precalculate_waves(progress_report); - } - - void set_sample_rate(uint32_t sr) { - srate = sr; - } - void params_changed() { - for (int i = 0; i < param_count - var_count; i++) - ((float *)&par_values)[i] = *params[i]; - - unsigned int old_poly = polyphony_limit; - polyphony_limit = dsp::clip(dsp::fastf2i_drm(*params[par_polyphony]), 1, 32); - if (polyphony_limit < old_poly) - trim_voices(); - - update_params(); - } - inline void pitch_bend(int amt) - { - drawbar_organ::pitch_bend(amt); - } - void activate() { - setup(srate); - panic_flag = false; - } - void deactivate(); - uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) { - float *o[2] = { outs[0] + offset, outs[1] + offset }; - if (panic_flag) - { - control_change(120, 0); // stop all sounds - control_change(121, 0); // reset all controllers - panic_flag = false; - } - render_separate(o, nsamples); - return 3; - } - /// No CV inputs for now - bool is_cv(int param_no) { return false; } - /// Practically all the stuff here is noisy - bool is_noisy(int param_no) { return true; } - void execute(int cmd_no); - bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context); - - char *configure(const char *key, const char *value); - void send_configures(send_configure_iface *); - uint32_t message_run(const void *valid_inputs, void *output_ports) { - // silence a default printf (which is kind of a warning about unhandled message_run) - return 0; - } -}; - }; #if ENABLE_EXPERIMENTAL diff --git a/plugins/ladspa_effect/calf/calf/multichorus.h b/plugins/ladspa_effect/calf/src/calf/multichorus.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/multichorus.h rename to plugins/ladspa_effect/calf/src/calf/multichorus.h diff --git a/plugins/ladspa_effect/calf/calf/onepole.h b/plugins/ladspa_effect/calf/src/calf/onepole.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/onepole.h rename to plugins/ladspa_effect/calf/src/calf/onepole.h diff --git a/plugins/ladspa_effect/calf/calf/organ.h b/plugins/ladspa_effect/calf/src/calf/organ.h similarity index 72% rename from plugins/ladspa_effect/calf/calf/organ.h rename to plugins/ladspa_effect/calf/src/calf/organ.h index 8a9b31666..efb39137b 100644 --- a/plugins/ladspa_effect/calf/calf/organ.h +++ b/plugins/ladspa_effect/calf/src/calf/organ.h @@ -22,9 +22,11 @@ #ifndef __CALF_ORGAN_H #define __CALF_ORGAN_H -#include "synth.h" +#include "audio_fx.h" #include "envelope.h" #include "metadata.h" +#include "osc.h" +#include "synth.h" #define ORGAN_KEYTRACK_POINTS 4 @@ -133,7 +135,6 @@ protected: static small_wave_family (*waves)[wave_count_small]; static big_wave_family (*big_waves)[wave_count_big]; - // dsp::sine_table sine_wave; int note; dsp::decay amp; /// percussion FM carrier amplitude envelope @@ -165,24 +166,12 @@ public: return (*big_waves)[wave]; } static void precalculate_waves(calf_plugins::progress_report_iface *reporter); - void update_pitch() - { - float phase = dsp::midi_note_to_phase(note, 100 * parameters->global_transpose + parameters->global_detune, sample_rate_ref); - dpphase.set((long int) (phase * parameters->percussion_harmonic * parameters->pitch_bend)); - moddphase.set((long int) (phase * parameters->percussion_fm_harmonic * parameters->pitch_bend)); - } + void update_pitch(); // this doesn't really have a voice interface void render_percussion_to(float (*buf)[2], int nsamples); void perc_note_on(int note, int vel); void perc_note_off(int note, int vel); - void perc_reset() - { - pphase = 0; - modphase = 0; - dpphase = 0; - moddphase = 0; - note = -1; - } + void perc_reset(); }; class organ_vibrato @@ -224,57 +213,11 @@ public: inertia_pitchbend.set_now(1); } - void reset() { - inertia_pitchbend.ramp.set_length(sample_rate / (BlockSize * 30)); // 1/30s - vibrato.reset(); - phase = 0; - for (int i = 0; i < FilterCount; i++) - { - filterL[i].reset(); - filterR[i].reset(); - } - } - - void note_on(int note, int vel) { - stolen = false; - finishing = false; - perc_released = false; - released = false; - reset(); - this->note = note; - const float sf = 0.001f; - for (int i = 0; i < EnvCount; i++) - { - organ_parameters::organ_env_parameters &p = parameters->envs[i]; - envs[i].set(sf * p.attack, sf * p.decay, p.sustain, sf * p.release, sample_rate / BlockSize); - envs[i].note_on(); - } - update_pitch(); - velocity = vel * 1.0 / 127.0; - amp.set(1.0f); - perc_note_on(note, vel); - } - - void note_off(int /* vel */) { - // reset age to 0 (because decay will turn from exponential to linear, necessary because of error cumulation prevention) - perc_released = true; - if (pamp.get_active()) - { - pamp.reinit(); - } - rel_age_const = pamp.get() * ((1.0/44100.0)/0.03); - for (int i = 0; i < EnvCount; i++) - envs[i].note_off(); - } - + void reset(); + void note_on(int note, int vel); + void note_off(int /* vel */); virtual float get_priority() { return stolen ? 20000 : (perc_released ? 1 : (sostenuto ? 200 : 100)); } - - virtual void steal() { - perc_released = true; - finishing = true; - stolen = true; - } - + virtual void steal(); void render_block(); virtual int get_current_note() { @@ -325,48 +268,63 @@ struct drawbar_organ: public dsp::basic_synth, public calf_plugins::organ_enums , percussion(_parameters) { } void render_separate(float *output[], int nsamples); - dsp::voice *alloc_voice() { - block_voice *v = new block_voice(); - v->parameters = parameters; - return v; - } - virtual void percussion_note_on(int note, int vel) { - percussion.perc_note_on(note, vel); - } + dsp::voice *alloc_voice(); + virtual void percussion_note_on(int note, int vel); virtual void params_changed() = 0; - virtual void setup(int sr) { - basic_synth::setup(sr); - percussion.setup(sr); - parameters->cutoff = 0; - params_changed(); - global_vibrato.reset(); - } + virtual void setup(int sr); void update_params(); void control_change(int controller, int value) { -#if 0 - if (controller == 11) - { - parameters->cutoff = value / 64.0 - 1; - } -#endif dsp::basic_synth::control_change(controller, value); } void pitch_bend(int amt); - virtual bool check_percussion() { - switch(dsp::fastf2i_drm(parameters->percussion_trigger)) - { - case organ_voice_base::perctrig_first: - return active_voices.empty(); - case organ_voice_base::perctrig_each: - default: - return true; - case organ_voice_base::perctrig_eachplus: - return !percussion.get_noticable(); - case organ_voice_base::perctrig_polyphonic: - return false; - } + virtual bool check_percussion(); +}; + +}; + +namespace calf_plugins { + +struct organ_audio_module: public audio_module, public dsp::drawbar_organ, public line_graph_iface +{ +public: + using drawbar_organ::note_on; + using drawbar_organ::note_off; + using drawbar_organ::control_change; + enum { param_count = drawbar_organ::param_count}; + dsp::organ_parameters par_values; + uint32_t srate; + bool panic_flag; + /// Value for configure variable map_curve + std::string var_map_curve; + + organ_audio_module(); + + void post_instantiate(); + + void set_sample_rate(uint32_t sr) { + srate = sr; } + void params_changed(); + + void activate(); + void deactivate(); + uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask); + /// No CV inputs for now + bool is_cv(int param_no) { return false; } + /// Practically all the stuff here is noisy + bool is_noisy(int param_no) { return true; } + void execute(int cmd_no); + bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const; + char *configure(const char *key, const char *value); + void send_configures(send_configure_iface *); + uint32_t message_run(const void *valid_inputs, void *output_ports); +public: + // overrides + virtual void note_on(int note, int velocity) { dsp::drawbar_organ::note_on(note, velocity); } + virtual void note_off(int note, int velocity) { dsp::drawbar_organ::note_off(note, velocity); } + virtual void control_change(int controller, int value) { dsp::drawbar_organ::control_change(controller, value); } + virtual void pitch_bend(int value) { dsp::drawbar_organ::pitch_bend(value); } }; }; diff --git a/plugins/ladspa_effect/calf/calf/osc.h b/plugins/ladspa_effect/calf/src/calf/osc.h similarity index 90% rename from plugins/ladspa_effect/calf/calf/osc.h rename to plugins/ladspa_effect/calf/src/calf/osc.h index ba01a2f38..779f1c009 100644 --- a/plugins/ladspa_effect/calf/calf/osc.h +++ b/plugins/ladspa_effect/calf/src/calf/osc.h @@ -19,8 +19,8 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __CALF_OSC_H -#define __CALF_OSC_H +#ifndef CALF_OSC_H +#define CALF_OSC_H #include "fft.h" #include @@ -245,12 +245,12 @@ struct waveform_oscillator: public simple_oscillator { waveform = NULL; } + + /// Get the value from single oscillator at current position inline float get() { uint32_t wpos = phase >> (32 - SIZE_BITS); - float value = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SCALE - 1)) * (1.0f / SCALE)); - phase += phasedelta; - return value; + return dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SCALE - 1)) * (1.0f / SCALE)); } /// Add/substract two phase-shifted values inline float get_phaseshifted(uint32_t shift, float mix) @@ -259,9 +259,23 @@ struct waveform_oscillator: public simple_oscillator float value1 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SCALE - 1)) * (1.0f / SCALE)); wpos = (phase + shift) >> (32 - SIZE_BITS); float value2 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], ((phase + shift) & (SCALE - 1)) * (1.0f / SCALE)); - float value = value1 + mix * value2; + return value1 + mix * value2; + } + /// Get the value of a hard synced osc (65536 = 1:1 ratio) + inline float get_phasedist(uint32_t sync, uint32_t shift, float mix) + { + uint32_t phase_mod = (uint64_t(phase) * sync >> 16); + + uint32_t wpos = phase_mod >> (32 - SIZE_BITS); + float value1 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SCALE - 1)) * (1.0f / SCALE)); + wpos = (phase_mod + shift) >> (32 - SIZE_BITS); + float value2 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], ((phase + shift) & (SCALE - 1)) * (1.0f / SCALE)); + return value1 + mix * value2; + } + /// One step + inline void advance() + { phase += phasedelta; - return value; } }; @@ -270,6 +284,18 @@ struct waveform_oscillator: public simple_oscillator */ struct triangle_lfo: public simple_oscillator { + /// Previous value (not stored here, but may be used by calling code) + float last; + + triangle_lfo() + { + reset(); + } + void reset() + { + simple_oscillator::reset(); + last = 0; + } inline float get() { uint32_t phase2 = phase; diff --git a/plugins/ladspa_effect/calf/calf/osctl.h b/plugins/ladspa_effect/calf/src/calf/osctl.h similarity index 89% rename from plugins/ladspa_effect/calf/calf/osctl.h rename to plugins/ladspa_effect/calf/src/calf/osctl.h index ff7a2fff2..2b500174f 100644 --- a/plugins/ladspa_effect/calf/calf/osctl.h +++ b/plugins/ladspa_effect/calf/src/calf/osctl.h @@ -293,6 +293,11 @@ template inline osc_stream & operator <<(osc_stream &s, uint32_t val) { +#if 0 + val = htonl(val); + s.write(&val, 4); + s.write_type(osc_i32); +#endif return s; } @@ -300,6 +305,10 @@ template inline osc_stream & operator >>(osc_stream &s, uint32_t &val) { +#if 0 + s.read(&val, 4); + val = htonl(val); +#endif return s; } @@ -307,6 +316,10 @@ template inline osc_stream & operator >>(osc_stream &s, int32_t &val) { +#if 0 + s.read(&val, 4); + val = htonl(val); +#endif return s; } @@ -314,6 +327,11 @@ template inline osc_stream & operator <<(osc_stream &s, float val) { + union { float v; uint32_t i; } val2; + val2.v = val; + val2.i = htonl(val2.i); + s.write(&val2.i, 4); + s.write_type(osc_f32); return s; } @@ -321,6 +339,10 @@ template inline osc_stream & operator >>(osc_stream &s, float &val) { + union { float v; uint32_t i; } val2; + s.read(&val2.i, 4); + val2.i = htonl(val2.i); + val = val2.v; return s; } @@ -358,6 +380,21 @@ template inline osc_stream & read_buffer_from_osc_stream(osc_stream &s, DestBuffer &buf) { +#if 0 + uint32_t nlen = 0; + s.read(&nlen, 4); + uint32_t len = htonl(nlen); + // write length in network order + for (uint32_t i = 0; i < len; i += 1024) + { + uint8_t tmp[1024]; + uint32_t part = std::min((uint32_t)1024, len - i); + s.read(tmp, part); + buf.write(tmp, part); + } + // pad + s.read(&nlen, 4 - (len & 3)); +#endif return s; } @@ -365,6 +402,21 @@ template inline osc_stream & write_buffer_to_osc_stream(osc_stream &s, SrcBuffer &buf) { +#if 0 + uint32_t len = buf.read_left(); + uint32_t nlen = ntohl(len); + s.write(&nlen, 4); + // write length in network order + for (uint32_t i = 0; i < len; i += 1024) + { + uint8_t tmp[1024]; + uint32_t part = std::min((uint32_t)1024, len - i); + buf.read(tmp, part); + s.write(tmp, part); + } + s.pad(); + s.write_type(osc_blob); +#endif return s; } @@ -397,7 +449,7 @@ operator <<(osc_stream &s, string_buffer &str) } // XXXKF: I don't support reading binary blobs yet -#if 0 + struct osc_net_bad_address: public std::exception { std::string addr, error_msg; @@ -426,12 +478,19 @@ struct osc_net_exception: public std::exception struct osc_net_dns_exception: public std::exception { +#if 0 int net_errno; std::string command, error_msg; + osc_net_dns_exception(const char *cmd, int _errno = h_errno) + { + command = cmd; + net_errno = _errno; + error_msg = "OSC error in "+command+": "+hstrerror(_errno); + } virtual const char *what() const throw() { return error_msg.c_str(); } virtual ~osc_net_dns_exception() throw () {} -}; #endif +}; template struct osc_message_sink diff --git a/plugins/ladspa_effect/calf/src/calf/osctlnet.h b/plugins/ladspa_effect/calf/src/calf/osctlnet.h new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/ladspa_effect/calf/calf/preset.h b/plugins/ladspa_effect/calf/src/calf/preset.h similarity index 98% rename from plugins/ladspa_effect/calf/calf/preset.h rename to plugins/ladspa_effect/calf/src/calf/preset.h index c74a8fe0d..c6b93a722 100644 --- a/plugins/ladspa_effect/calf/calf/preset.h +++ b/plugins/ladspa_effect/calf/src/calf/preset.h @@ -22,10 +22,6 @@ #define __CALF_PRESET_H #include -#include -#include -#include -#include #include #include "utils.h" diff --git a/plugins/ladspa_effect/calf/calf/primitives.h b/plugins/ladspa_effect/calf/src/calf/primitives.h similarity index 99% rename from plugins/ladspa_effect/calf/calf/primitives.h rename to plugins/ladspa_effect/calf/src/calf/primitives.h index 79cbe3f96..efc820feb 100644 --- a/plugins/ladspa_effect/calf/calf/primitives.h +++ b/plugins/ladspa_effect/calf/src/calf/primitives.h @@ -21,12 +21,13 @@ #ifndef __CALF_PRIMITIVES_H #define __CALF_PRIMITIVES_H -#include -#include -#include -#include +#include #include #include +#include +#include +#include +#include namespace dsp { diff --git a/plugins/ladspa_effect/calf/calf/synth.h b/plugins/ladspa_effect/calf/src/calf/synth.h similarity index 98% rename from plugins/ladspa_effect/calf/calf/synth.h rename to plugins/ladspa_effect/calf/src/calf/synth.h index dc5c8ebae..85fb35404 100644 --- a/plugins/ladspa_effect/calf/calf/synth.h +++ b/plugins/ladspa_effect/calf/src/calf/synth.h @@ -19,14 +19,16 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02111-1307, USA. */ -#ifndef __CALF_SYNTH_H -#define __CALF_SYNTH_H +#ifndef CALF_SYNTH_H +#define CALF_SYNTH_H +#include +#include +#include +#include +#include #include #include -#include -#include "primitives.h" -#include "audio_fx.h" namespace dsp { diff --git a/plugins/ladspa_effect/calf/calf/utils.h b/plugins/ladspa_effect/calf/src/calf/utils.h similarity index 90% rename from plugins/ladspa_effect/calf/calf/utils.h rename to plugins/ladspa_effect/calf/src/calf/utils.h index ecb9105de..3dd83de60 100644 --- a/plugins/ladspa_effect/calf/calf/utils.h +++ b/plugins/ladspa_effect/calf/src/calf/utils.h @@ -93,12 +93,13 @@ public: }; /// Exception-safe temporary assignment -template +template class scope_assign { - T &data, old_value; + Tref data; + T old_value; public: - scope_assign(T &_data, T new_value) + scope_assign(Tref _data, T new_value) : data(_data), old_value(_data) { data = new_value; @@ -124,8 +125,8 @@ struct file_exception: public std::exception const char *text; std::string message, filename, container; public: - file_exception(const std::string &f) : message(strerror(errno)), filename(f), container(filename + ":" + message) { text = container.c_str(); } - file_exception(const std::string &f, const std::string &t) : message(t), filename(f), container(filename + ":" + message) { text = container.c_str(); } + file_exception(const std::string &f); + file_exception(const std::string &f, const std::string &t); virtual const char *what() const throw () { return text; } virtual ~file_exception() throw () {} }; diff --git a/plugins/ladspa_effect/calf/calf/waveshaping.h b/plugins/ladspa_effect/calf/src/calf/waveshaping.h similarity index 100% rename from plugins/ladspa_effect/calf/calf/waveshaping.h rename to plugins/ladspa_effect/calf/src/calf/waveshaping.h diff --git a/plugins/ladspa_effect/calf/src/giface.cpp b/plugins/ladspa_effect/calf/src/giface.cpp index e9984e84f..481feab46 100644 --- a/plugins/ladspa_effect/calf/src/giface.cpp +++ b/plugins/ladspa_effect/calf/src/giface.cpp @@ -1,7 +1,7 @@ /* Calf DSP Library - * Module wrapper methods. + * Implementation of various helpers for the plugin interface. * - * Copyright (C) 2001-2007 Krzysztof Foltman + * Copyright (C) 2001-2010 Krzysztof Foltman * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,10 +18,12 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#include -#include +#include +#include #include -#include +#include +#include + using namespace std; using namespace calf_utils; using namespace calf_plugins; @@ -187,10 +189,10 @@ std::string parameter_properties::to_string(float value) const } void calf_plugins::plugin_ctl_iface::clear_preset() { - int param_count = get_param_count(); + int param_count = get_metadata_iface()->get_param_count(); for (int i=0; i < param_count; i++) { - parameter_properties &pp = *get_param_props(i); + const parameter_properties &pp = *get_metadata_iface()->get_param_props(i); if ((pp.flags & PF_TYPEMASK) == PF_STRING) { configure(pp.short_name, pp.choices ? pp.choices[0] : ""); @@ -213,7 +215,7 @@ const char *calf_plugins::load_gui_xml(const std::string &plugin_id) #endif } -bool calf_plugins::check_for_message_context_ports(parameter_properties *parameters, int count) +bool calf_plugins::check_for_message_context_ports(const parameter_properties *parameters, int count) { for (int i = count - 1; i >= 0; i--) { @@ -223,7 +225,7 @@ bool calf_plugins::check_for_message_context_ports(parameter_properties *paramet return false; } -bool calf_plugins::check_for_string_ports(parameter_properties *parameters, int count) +bool calf_plugins::check_for_string_ports(const parameter_properties *parameters, int count) { for (int i = count - 1; i >= 0; i--) { @@ -292,6 +294,21 @@ void calf_plugins::set_channel_color(cairo_iface *context, int channel) context->set_line_width(1.5); } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool frequency_response_line_graph::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const +{ + return get_freq_gridline(subindex, pos, vertical, legend, context); +} + +int frequency_response_line_graph::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const +{ + subindex_graph = 0; + subindex_dot = 0; + subindex_gridline = generation ? INT_MAX : 0; + return 1; +} + /////////////////////////////////////////////////////////////////////////////////////// calf_plugins::plugin_registry &calf_plugins::plugin_registry::instance() @@ -314,9 +331,27 @@ const plugin_metadata_iface *calf_plugins::plugin_registry::get_by_uri(const cha return NULL; } +const plugin_metadata_iface *calf_plugins::plugin_registry::get_by_id(const char *id, bool case_sensitive) +{ + typedef int (*comparator)(const char *, const char *); + comparator comp = case_sensitive ? strcmp : strcasecmp; + for (unsigned int i = 0; i < plugins.size(); i++) + { + if (!comp(plugins[i]->get_id(), id)) + return plugins[i]; + } + return NULL; +} /////////////////////////////////////////////////////////////////////////////////////// -#if USE_DSSI +std::string table_edit_iface::get_cell(int param, int row, int column) const +{ + return calf_utils::i2s(row)+":"+calf_utils::i2s(column); +} + +/////////////////////////////////////////////////////////////////////////////////////// + +#if USE_EXEC_GUI struct osc_cairo_control: public cairo_iface { osctl::osc_inline_typed_strstream &os; @@ -332,9 +367,8 @@ struct osc_cairo_control: public cairo_iface } }; -static void send_graph_via_osc(osctl::osc_client &client, const std::string &address, line_graph_iface *graph, std::vector ¶ms) +static void serialize_graphs(osctl::osc_inline_typed_strstream &os, const line_graph_iface *graph, std::vector ¶ms) { - osctl::osc_inline_typed_strstream os; osc_cairo_control cairoctl(os); for (size_t i = 0; i < params.size(); i++) { @@ -376,15 +410,26 @@ static void send_graph_via_osc(osctl::osc_client &client, const std::string &add os << (uint32_t)LGI_END_ITEM; } os << (uint32_t)LGI_END; - client.send(address, os); } -calf_plugins::dssi_feedback_sender::dssi_feedback_sender(const char *URI, line_graph_iface *_graph, calf_plugins::parameter_properties *props, int num_params) +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) @@ -394,14 +439,18 @@ calf_plugins::dssi_feedback_sender::dssi_feedback_sender(const char *URI, line_g void calf_plugins::dssi_feedback_sender::update() { - send_graph_via_osc(*client, "/lineGraph", graph, indices); + 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() { - // this would not be received by GUI's main loop because it's already been terminated - // client->send("/iQuit"); - delete client; + if (!is_client_shared) + delete client; } #endif diff --git a/plugins/ladspa_effect/calf/src/metadata.cpp b/plugins/ladspa_effect/calf/src/metadata.cpp new file mode 100644 index 000000000..ca44b234a --- /dev/null +++ b/plugins/ladspa_effect/calf/src/metadata.cpp @@ -0,0 +1,1018 @@ +/* Calf DSP Library + * Example audio modules - parameters and LADSPA wrapper instantiation + * + * Copyright (C) 2001-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 02110-1301 USA + */ +#include +#include +#include +#include + +using namespace dsp; +using namespace calf_plugins; + +const char *calf_plugins::calf_copyright_info = "(C) 2001-2009 Krzysztof Foltman, Thor Harald Johanssen, Markus Schmidt and others; license: LGPL"; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(flanger) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(flanger) = { + { 0.1, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC | PF_PROP_GRAPH, NULL, "min_delay", "Min delay" }, + { 0.5, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "mod_depth", "Mod depth" }, + { 0.25, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "mod_rate", "Mod rate" }, + { 0.90, -0.99, 0.99, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "feedback", "Feedback" }, + { 0, 0, 360, 9, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "stereo", "Stereo phase" }, + { 0, 0, 1, 2, PF_BOOL | PF_CTL_BUTTON , NULL, "reset", "Reset" }, + { 1, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" }, + { 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, +}; + +CALF_PLUGIN_INFO(flanger) = { 0x847d, "Flanger", "Calf Flanger", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "FlangerPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(phaser) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(phaser) = { + { 1000, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "base_freq", "Center Freq" }, + { 4000, 0, 10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "mod_depth", "Mod depth" }, + { 0.25, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "mod_rate", "Mod rate" }, + { 0.25, -0.99, 0.99, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "feedback", "Feedback" }, + { 6, 1, 12, 12, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "stages", "# Stages" }, + { 180, 0, 360, 9, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "stereo", "Stereo phase" }, + { 0, 0, 1, 2, PF_BOOL | PF_CTL_BUTTON , NULL, "reset", "Reset" }, + { 1, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" }, + { 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, +}; + +CALF_PLUGIN_INFO(phaser) = { 0x8484, "Phaser", "Calf Phaser", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "PhaserPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(reverb) = {"In L", "In R", "Out L", "Out R"}; + +const char *reverb_room_sizes[] = { "Small", "Medium", "Large", "Tunnel-like", "Large/smooth", "Experimental" }; + +CALF_PORT_PROPS(reverb) = { + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip", "0dB" }, + { 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_wet", "Wet amount" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, + { 1.5, 0.4, 15.0, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_SEC, NULL, "decay_time", "Decay time" }, + { 5000, 2000,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hf_damp", "High Frq Damp" }, + { 2, 0, 5, 0, PF_ENUM | PF_CTL_COMBO , reverb_room_sizes, "room_size", "Room size", }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "diffusion", "Diffusion" }, + { 0.25, 0, 2, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Wet Amount" }, + { 1.0, 0, 2, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, + { 0, 0, 50, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "predelay", "Pre Delay" }, + { 300, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "bass_cut", "Bass Cut" }, + { 5000, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "treble_cut", "Treble Cut" }, +}; + +CALF_PLUGIN_INFO(reverb) = { 0x847e, "Reverb", "Calf Reverb", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "ReverbPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(filter) = {"In L", "In R", "Out L", "Out R"}; + +const char *filter_choices[] = { + "12dB/oct Lowpass", + "24dB/oct Lowpass", + "36dB/oct Lowpass", + "12dB/oct Highpass", + "24dB/oct Highpass", + "36dB/oct Highpass", + "6dB/oct Bandpass", + "12dB/oct Bandpass", + "18dB/oct Bandpass", + "6dB/oct Bandreject", + "12dB/oct Bandreject", + "18dB/oct Bandreject", +}; + +CALF_PORT_PROPS(filter) = { + { 2000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq", "Frequency" }, + { 0.707, 0.707, 32, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "res", "Resonance" }, + { biquad_filter_module::mode_12db_lp, + biquad_filter_module::mode_12db_lp, + biquad_filter_module::mode_count - 1, + 1, PF_ENUM | PF_CTL_COMBO, filter_choices, "mode", "Mode" }, + { 20, 5, 100, 20, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "inertia", "Inertia"}, +}; + +CALF_PLUGIN_INFO(filter) = { 0x847f, "Filter", "Calf Filter", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "FilterPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(filterclavier) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(filterclavier) = { + { 0, -48, 48, 48*2+1, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "transpose", "Transpose" }, + { 0, -100, 100, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune", "Detune" }, + { 32, 0.707, 32, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "maxres", "Max. Resonance" }, + { biquad_filter_module::mode_6db_bp, + biquad_filter_module::mode_12db_lp, + biquad_filter_module::mode_count - 1, + 1, PF_ENUM | PF_CTL_COMBO | PF_PROP_GRAPH, filter_choices, "mode", "Mode" }, + { 20, 1, 2000, 20, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "inertia", "Portamento time"} +}; + +CALF_PLUGIN_INFO(filterclavier) = { 0x849f, "Filterclavier", "Calf Filterclavier", "Krzysztof Foltman / Hans Baier", calf_plugins::calf_copyright_info, "FilterclavierPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(vintage_delay) = {"In L", "In R", "Out L", "Out R"}; + +const char *vintage_delay_mixmodes[] = { + "Stereo", + "Ping-Pong", + "L then R", + "R then L", +}; + +const char *vintage_delay_fbmodes[] = { + "Plain", + "Tape", + "Old Tape", +}; + +CALF_PORT_PROPS(vintage_delay) = { + { 120, 30, 300, 1, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_BPM, NULL, "bpm", "Tempo" }, + { 4, 1, 16, 1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "subdiv", "Subdivide"}, + { 3, 1, 16, 1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_l", "Time L"}, + { 5, 1, 16, 1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_r", "Time R"}, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "feedback", "Feedback" }, + { 0.25, 0, 4, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" }, + { 1, 0, 3, 0, PF_ENUM | PF_CTL_COMBO, vintage_delay_mixmodes, "mix_mode", "Mix mode" }, + { 1, 0, 2, 0, PF_ENUM | PF_CTL_COMBO, vintage_delay_fbmodes, "medium", "Medium" }, + { 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, + { 1.0, -1, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "width", "Stereo Width" }, +}; + +CALF_PLUGIN_INFO(vintage_delay) = { 0x8482, "VintageDelay", "Calf Vintage Delay", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "DelayPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(rotary_speaker) = {"In L", "In R", "Out L", "Out R"}; + +const char *rotary_speaker_speed_names[] = { "Off", "Chorale", "Tremolo", "HoldPedal", "ModWheel", "Manual" }; + +CALF_PORT_PROPS(rotary_speaker) = { + { 5, 0, 5, 1.01, PF_ENUM | PF_CTL_COMBO, rotary_speaker_speed_names, "vib_speed", "Speed Mode" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "spacing", "Tap Spacing" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "shift", "Tap Offset" }, + { 0.10, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "mod_depth", "Mod Depth" }, + { 36, 10, 600, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_LOG | PF_UNIT_RPM, NULL, "treble_speed", "Treble Motor" }, + { 30, 10, 600, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_LOG | PF_UNIT_RPM, NULL, "bass_speed", "Bass Motor" }, + { 0.7, 0, 1, 101, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "mic_distance", "Mic Distance" }, + { 0.3, 0, 1, 101, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "reflection", "Reflection" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_l", "Low rotor" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_h", "High rotor" }, +}; + +CALF_PLUGIN_INFO(rotary_speaker) = { 0x8483, "RotarySpeaker", "Calf Rotary Speaker", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SimulationPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(multichorus) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(multichorus) = { + { 5, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC | PF_PROP_GRAPH, NULL, "min_delay", "Min delay" }, + { 6, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC| PF_PROP_GRAPH, NULL, "mod_depth", "Mod depth" }, + { 0.5, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ| PF_PROP_GRAPH, NULL, "mod_rate", "Modulation rate" }, + { 180, 0, 360, 91, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "stereo", "Stereo phase" }, + { 4, 1, 8, 8, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "voices", "Voices"}, + { 64, 0, 360, 91, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "vphase", "Inter-voice phase" }, + { 2, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" }, + { 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, + { 100, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq", "Center Frq 1" }, + { 5000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq2", "Center Frq 2" }, + { 0.125, 0.125, 8, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "q", "Q" }, + { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "overlap", "Overlap" }, +}; + +CALF_PLUGIN_INFO(multichorus) = { 0x8501, "MultiChorus", "Calf MultiChorus", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "ChorusPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(compressor) = {"In L", "In R", "Out L", "Out R"}; + +const char *compressor_detection_names[] = { "RMS", "Peak" }; +const char *compressor_stereo_link_names[] = { "Average", "Maximum" }; + +CALF_PORT_PROPS(compressor) = { + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB-In" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB-Out" }, + { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" }, + { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" }, + { 20, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" }, + { 250, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" }, + { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" }, + { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, compressor_detection_names, "detection", "Detection" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, compressor_stereo_link_names, "stereo_link", "Stereo Link" }, + { 0, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression", "Reduction" }, +}; + +CALF_PLUGIN_INFO(compressor) = { 0x8502, "Compressor", "Calf Compressor", "Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(sidechaincompressor) = {"In L", "In R", "Out L", "Out R"}; + +const char *sidechaincompressor_detection_names[] = { "RMS", "Peak" }; +const char *sidechaincompressor_stereo_link_names[] = { "Average", "Maximum" }; +const char *sidechaincompressor_mode_names[] = {"Wideband (F1:off / F2:off)", + "Deesser wide (F1:Bell / F2:HP)", + "Deesser split (F1:off / F2:HP)", + "Derumbler wide (F1:LP / F2:Bell)", + "Derumbler split (F1:LP / F2:off)", + "Weighted #1 (F1:Shelf / F2:Shelf)", + "Weighted #2 (F1:Shelf / F2:Bell)", + "Weighted #3 (F1:Bell / F2:Shelf)", + "Bandpass #1 (F1:BP / F2:off)", + "Bandpass #2 (F1:HP / F2:LP)"}; +const char *sidechaincompressor_filter_choices[] = { "12dB", "24dB", "36dB"}; + + +CALF_PORT_PROPS(sidechaincompressor) = { + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB-In" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB-Out" }, + { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" }, + { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" }, + { 20, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" }, + { 250, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" }, + { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" }, + { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_detection_names, "detection", "Detection" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_stereo_link_names, "stereo_link", "Stereo Link" }, + { 0, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression", "Gain Reduction" }, + { 0, 0, 9, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_mode_names, "sc_mode", "Sidechain Mode" }, + { 250, 10,18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "f1_freq", "F1 Freq" }, + { 4500, 10,18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "f2_freq", "F2 Freq" }, + { 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f1_level", "F1 Level" }, + { 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f2_level", "F2 Level" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "sc_listen", "S/C-Listen" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f1_active", "F1 Active" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f2_active", "F2 Active" }, +}; + +CALF_PLUGIN_INFO(sidechaincompressor) = { 0x8517, "Sidechaincompressor", "Calf Sidechain Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(multibandcompressor) = {"In L", "In R", "Out L", "Out R"}; + +const char *multibandcompressor_detection_names[] = { "RMS", "Peak" }; + +CALF_PORT_PROPS(multibandcompressor) = { + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" }, + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inL", "Input L" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inR", "Input R" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outL", "Output L" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outR", "Output R" }, + { 0, 0, 1, 0, PF_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" }, + { 1000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq1", "Split 2/3" }, + { 6000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq2", "Split 3/4" }, + + { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep0", "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.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.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" }, + { 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_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.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" }, + { 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_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.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" }, + { 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_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.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" }, + { 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_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" }, +}; + +CALF_PLUGIN_INFO(multibandcompressor) = { 0x8516, "Multibandcompressor", "Calf Multiband Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(deesser) = {"In L", "In R", "Out L", "Out R"}; + +const char *deesser_detection_names[] = { "RMS", "Peak" }; +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, 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" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, deesser_mode_names, "mode", "Mode" }, + { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" }, + { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" }, + { 15, 1, 100, 1, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "laxity", "Laxity" }, + { 1, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup" }, + + { 6000, 10, 18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "f1_freq", "Split" }, + { 4500, 10, 18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "f2_freq", "Peak" }, + { 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f1_level", "Gain" }, + { 4, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f2_level", "Level" }, + { 1, 0.1, 100,1, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "f2_q", "Peak Q" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "sc_listen", "S/C-Listen" }, +}; + +CALF_PLUGIN_INFO(deesser) = { 0x8515, "Deesser", "Calf Deesser", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; + +//////////////////////////////////////////////////////////////////////////// +// A few macros to make + +#define BYPASS_AND_LEVEL_PARAMS \ + { 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 Gain" }, \ + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output Gain" }, + +#define METERING_PARAMS \ + { 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", "Meter-InL" }, \ + { 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", "Meter-InR" }, \ + { 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", "Meter-OutL" }, \ + { 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", "Meter-OutR" }, \ + { 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" }, + +#define LPHP_PARAMS \ + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "hp_active", "HP Active" }, \ + { 30, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_freq", "HP Freq" }, \ + { 1, 0, 2, 0, PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "hp_mode", "HP Mode" }, \ + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "lp_active", "LP Active" }, \ + { 18000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_freq", "LP Freq" }, \ + { 1, 0, 2, 0, PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "lp_mode", "LP Mode" }, \ + +#define SHELF_PARAMS \ + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "ls_active", "LS Active" }, \ + { 1, 0.015625, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "ls_level", "Level L" }, \ + { 200, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "ls_freq", "Freq L" }, \ + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "hs_active", "HS Active" }, \ + { 1, 0.015625, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "hs_level", "Level H" }, \ + { 4000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hs_freq", "Freq H" }, + +#define EQ_BAND_PARAMS(band, frequency) \ + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "p" #band "_active", "F" #band " Active" }, \ + { 1, 0.015625, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "p" #band "_level", "Level " #band }, \ + { frequency, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "p" #band "_freq", "Freq " #band }, \ + { 1, 0.1, 100, 1, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "p" #band "_q", "Q " #band }, + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(equalizer5band) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(equalizer5band) = { + BYPASS_AND_LEVEL_PARAMS + METERING_PARAMS + SHELF_PARAMS + EQ_BAND_PARAMS(1, 250) + EQ_BAND_PARAMS(2, 1000) + EQ_BAND_PARAMS(3, 2500) +}; + +CALF_PLUGIN_INFO(equalizer5band) = { 0x8511, "Equalizer5Band", "Calf Equalizer 5 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" }; + +////////////////////////////////////////////////////////////////////////////// + + +CALF_PORT_NAMES(equalizer8band) = {"In L", "In R", "Out L", "Out R"}; +const char *rolloff_mode_names[] = {"12dB/oct", "24dB/oct", "36dB/oct"}; + +CALF_PORT_PROPS(equalizer8band) = { + BYPASS_AND_LEVEL_PARAMS + METERING_PARAMS + LPHP_PARAMS + SHELF_PARAMS + EQ_BAND_PARAMS(1, 250) + EQ_BAND_PARAMS(2, 1000) + EQ_BAND_PARAMS(3, 2500) + EQ_BAND_PARAMS(4, 5000) +}; + +CALF_PLUGIN_INFO(equalizer8band) = { 0x8512, "Equalizer8Band", "Calf Equalizer 8 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(equalizer12band) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(equalizer12band) = { + BYPASS_AND_LEVEL_PARAMS + METERING_PARAMS + LPHP_PARAMS + SHELF_PARAMS + EQ_BAND_PARAMS(1, 60) + EQ_BAND_PARAMS(2, 120) + EQ_BAND_PARAMS(3, 250) + EQ_BAND_PARAMS(4, 500) + EQ_BAND_PARAMS(5, 1000) + EQ_BAND_PARAMS(6, 2500) + EQ_BAND_PARAMS(7, 4000) + EQ_BAND_PARAMS(8, 6000) +}; + +CALF_PLUGIN_INFO(equalizer12band) = { 0x8513, "Equalizer12Band", "Calf Equalizer 12 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(pulsator) = {"In L", "In R", "Out L", "Out R"}; + +const char *pulsator_mode_names[] = { "Sine", "Triangle", "Square", "Saw up", "Saw down" }; + +CALF_PORT_PROPS(pulsator) = { + BYPASS_AND_LEVEL_PARAMS + METERING_PARAMS + { 0, 0, 4, 0, PF_ENUM | PF_CTL_COMBO, pulsator_mode_names, "mode", "Mode" }, + { 1, 0.01, 100, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Frequency" }, + { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "amount", "Modulation" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "offset", "Offset L/R" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mono", "Mono-in" }, + { 0, 0, 1, 2, PF_BOOL | PF_CTL_BUTTON , NULL, "reset", "Reset" }, +}; + +CALF_PLUGIN_INFO(pulsator) = { 0x8514, "Pulsator", "Calf Pulsator", "Markus Schmidt", calf_plugins::calf_copyright_info, "ModulationPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(saturator) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(saturator) = { + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, + { 1, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Activation" }, + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Master" }, + { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "mix", "Mix" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" }, + + { 5, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "drive", "Saturation" }, + { 10, -10, 10, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_COEF, NULL, "blend", "Blend" }, + { 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_drive", "Drive" }, + + { 20000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_pre_freq", "Lowpass" }, + { 10, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_pre_freq", "Highpass" }, + + { 20000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_post_freq", "Lowpass" }, + { 10, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_post_freq", "Highpass" }, + + { 2000, 80, 8000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "p_freq", "Tone" }, + { 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "p_level", "Amount" }, + { 1, 0.1, 10, 1, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "p_q", "Gradient" }, +}; + +CALF_PLUGIN_INFO(saturator) = { 0x8530, "Saturator", "Calf Saturator", "Markus Schmidt / Krzysztof Foltman", calf_plugins::calf_copyright_info, "DistortionPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(exciter) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(exciter) = { + { 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" }, + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" }, + + { 8.5, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "drive", "Harmonics" }, + { 0, -10, 10, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_COEF, NULL, "blend", "Blend harmonics" }, + { 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_drive", "Harmonics level" }, + + { 6000, 2000, 12000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Scope" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "listen", "Listen" }, +}; + +CALF_PLUGIN_INFO(exciter) = { 0x8531, "Exciter", "Calf Exciter", "Markus Schmidt / Krzysztof Foltman", calf_plugins::calf_copyright_info, "DistortionPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(bassenhancer) = {"In L", "In R", "Out L", "Out R"}; + +CALF_PORT_PROPS(bassenhancer) = { + { 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" }, + { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB" }, + { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" }, + + { 8.5, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "drive", "Harmonics" }, + { 0, -10, 10, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_COEF, NULL, "blend", "Blend harmonics" }, + { 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_drive", "Harmonics level" }, + + { 120, 10, 250, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Scope" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "listen", "Listen" }, +}; + +CALF_PLUGIN_INFO(bassenhancer) = { 0x8532, "BassEnhancer", "Calf Bass Enhancer", "Markus Schmidt / Krzysztof Foltman", calf_plugins::calf_copyright_info, "DistortionPlugin" }; + + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(gate) = {"In L", "In R", "In Trigger", "Out L", "Out R"}; + +const char *gate_detection_names[] = { "RMS", "Peak" }; +const char *gate_stereo_link_names[] = { "Average", "Maximum" }; +const char *gate_weighting_names[] = { "Normal", "A-weighted", "Deesser (low)", "Deesser (med)", "Deesser (high)" }; + +CALF_PORT_PROPS(gate) = { + { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" }, + { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" }, + { 20, 1, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" }, + { 250, 1, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" }, + { 1, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" }, + { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, gate_detection_names, "detection", "Detection" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, gate_stereo_link_names, "stereo_link", "Stereo Link" }, + { 0, 0, 4, 0, PF_ENUM | PF_CTL_COMBO, gate_weighting_names, "aweighting", "Weighting" }, + { 0, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "gating", "Gating" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "peak", "Peak Output" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip", "0dBFS" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, + { 0.01, 0.000015849, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "range", "Max Gain Reduction" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mono", "Mono (L only)" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "trigger", "Sidechain (Mono In)" }, + +}; + +CALF_PLUGIN_INFO(gate) = { 0x8503, "Gate", "Calf Gate", "Damien Zammit / Thor Harald Johansen", calf_plugins::calf_copyright_info, "ExpanderPlugin" }; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PORT_NAMES(monosynth) = { + "Out L", "Out R", +}; + +const char *monosynth_waveform_names[] = { "Sawtooth", "Square", "Pulse", "Sine", "Triangle", "Varistep", "Skewed Saw", "Skewed Square", + "Smooth Brass", "Bass", "Dark FM", "Multiwave", "Bell FM", "Dark Pad", "DCO Saw", "DCO Maze" }; +const char *monosynth_mode_names[] = { "0\xC2\xB0 : 0\xC2\xB0", "0\xC2\xB0 : 180\xC2\xB0", "0\xC2\xB0 : 90\xC2\xB0", "90\xC2\xB0 : 90\xC2\xB0", "90\xC2\xB0 : 270\xC2\xB0", "Random" }; +const char *monosynth_legato_names[] = { "Retrig", "Legato", "Fng Retrig", "Fng Legato" }; +const char *monosynth_lfotrig_names[] = { "Retrig", "Free" }; + +const char *monosynth_filter_choices[] = { + "12dB/oct Lowpass", + "24dB/oct Lowpass", + "2x12dB/oct Lowpass", + "12dB/oct Highpass", + "Lowpass+Notch", + "Highpass+Notch", + "6dB/oct Bandpass", + "2x6dB/oct Bandpass", +}; + +CALF_PLUGIN_INFO(monosynth) = { 0x8480, "Monosynth", "Calf Monosynth", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" }; + +CALF_PORT_PROPS(monosynth) = { + { monosynth_metadata::wave_saw, 0, monosynth_metadata::wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO | PF_PROP_GRAPH, monosynth_waveform_names, "o1_wave", "Osc1 Wave" }, + { monosynth_metadata::wave_sqr, 0, monosynth_metadata::wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO | PF_PROP_GRAPH, monosynth_waveform_names, "o2_wave", "Osc2 Wave" }, + + { 0, -1, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "o1_pw", "Osc1 PW" }, + { 0, -1, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "o2_pw", "Osc2 PW" }, + + { 10, 0, 100, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o12_detune", "O1<>2 Detune" }, + { 12, -24, 24, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o2_xpose", "Osc 2 transpose" }, + { 0, 0, 5, 0, PF_ENUM | PF_CTL_COMBO, monosynth_mode_names, "phase_mode", "Phase mode" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "o12_mix", "O1<>2 Mix" }, + { 1, 0, 7, 0, PF_ENUM | PF_CTL_COMBO | PF_PROP_GRAPH, monosynth_filter_choices, "filter", "Filter" }, + { 33, 10,16000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "cutoff", "Cutoff" }, + { 3, 0.7, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "res", "Resonance" }, + { 0, -2400, 2400, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "filter_sep", "Separation" }, + { 8000, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "env2cutoff", "Env->Cutoff" }, + { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2res", "Env->Res" }, + { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "env2amp", "Env->Amp" }, + + { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr_a", "EG1 Attack" }, + { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr_d", "EG1 Decay" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_s", "EG1 Sustain" }, + { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr_f", "EG1 Fade" }, + { 100, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr_r", "EG1 Release" }, + + { 0, 0, 2, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "key_follow", "Key Follow" }, + { 0, 0, 3, 0, PF_ENUM | PF_CTL_COMBO, monosynth_legato_names, "legato", "Legato Mode" }, + { 1, 1, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "portamento", "Portamento" }, + + { 0.5, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2filter", "Vel->Filter" }, + { 0, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2amp", "Vel->Amp" }, + + { 0.5, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_PROP_OUTPUT_GAIN, NULL, "master", "Volume" }, + + { 200, 0, 2400, 25, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "pbend_range", "PBend Range" }, + + { 5, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lfo_rate", "LFO1 Rate" }, + { 0.5, 0, 5, 0, PF_FLOAT | PF_SCALE_QUAD | PF_CTL_KNOB | PF_UNIT_SEC, NULL, "lfo_delay", "LFO1 Delay" }, + { 0, -4800, 4800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "lfo2filter", "LFO1->Filter" }, + { 100, 0, 1200, 0, PF_FLOAT | PF_SCALE_QUAD | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "lfo2pitch", "LFO1->Pitch" }, + { 0, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "lfo2pw", "LFO1->PW" }, + { 1, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "mwhl2lfo", "ModWheel->LFO1" }, + + { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "scale_detune", "Scale Detune" }, + + { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "adsr2_cutoff", "EG2->Cutoff" }, + { 0.3, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "adsr2_res", "EG2->Res" }, + { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "adsr2_amp", "EG2->Amp" }, + + { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr2_a", "EG2 Attack" }, + { 100, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr2_d", "EG2 Decay" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_s", "EG2 Sustain" }, + { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr2_f", "EG2 Fade" }, + { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr2_r", "Release" }, + + { 1, 1, 16, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "o1_stretch", "Osc1 Stretch" }, + + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, monosynth_lfotrig_names, "lfo1_trig", "LFO1 Trigger Mode" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, monosynth_lfotrig_names, "lfo2_trig", "LFO2 Trigger Mode" }, + { 5, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lfo2_rate", "LFO1 Rate" }, + { 0.5, 0.1, 5, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_SEC, NULL, "lfo2_delay", "LFO1 Delay" }, +}; + +//////////////////////////////////////////////////////////////////////////// + +CALF_PLUGIN_INFO(organ) = { 0x8481, "Organ", "Calf Organ", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" }; + +plugin_command_info *organ_metadata::get_commands() +{ + static plugin_command_info cmds[] = { + { "cmd_panic", "Panic!", "Stop all sounds and reset all controllers" }, + { NULL } + }; + return cmds; +} + +CALF_PORT_NAMES(organ) = {"Out L", "Out R"}; + +const char *organ_percussion_trigger_names[] = { "First note", "Each note", "Each, no retrig", "Polyphonic" }; + +const char *organ_wave_names[] = { + "Sin", + "S0", "S00", "S000", + "SSaw", "SSqr", "SPls", + "Saw", "Sqr", "Pls", + "S(", "Sq(", "S+", "Clvg", + "Bell", "Bell2", + "W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8", "W9", + "DSaw", "DSqr", "DPls", + "P:SynStr","P:WideStr","P:Sine","P:Bell","P:Space","P:Voice","P:Hiss","P:Chant", +}; + +const char *organ_routing_names[] = { "Out", "Flt 1", "Flt 2" }; + +const char *organ_ampctl_names[] = { "None", "Direct", "Flt 1", "Flt 2", "All" }; + +const char *organ_vibrato_mode_names[] = { "None", "Direct", "Flt 1", "Flt 2", "Voice", "Global" }; + +const char *organ_filter_type_names[] = { "12dB/oct LP", "12dB/oct HP" }; + +const char *organ_filter_send_names[] = { "Output", "Filter 2" }; + +const char *organ_init_map_curve = "2\n0 1\n1 1\n"; + +CALF_PORT_PROPS(organ) = { + { 8, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l1", "16'" }, + { 8, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l2", "5 1/3'" }, + { 8, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l3", "8'" }, + { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l4", "4'" }, + { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l5", "2 2/3'" }, + { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l6", "2'" }, + { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l7", "1 3/5'" }, + { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l8", "1 1/3'" }, + { 8, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l9", "1'" }, + + { 1, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f1", "Freq 1" }, + { 3, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f2", "Freq 2" }, + { 2, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f3", "Freq 3" }, + { 4, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f4", "Freq 4" }, + { 6, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f5", "Freq 5" }, + { 8, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f6", "Freq 6" }, + { 10, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f7", "Freq 7" }, + { 12, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f8", "Freq 8" }, + { 16, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f9", "Freq 9" }, + + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w1", "Wave 1" }, + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w2", "Wave 2" }, + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w3", "Wave 3" }, + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w4", "Wave 4" }, + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w5", "Wave 5" }, + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w6", "Wave 6" }, + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w7", "Wave 7" }, + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w8", "Wave 8" }, + { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w9", "Wave 9" }, + + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune1", "Detune 1" }, + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune2", "Detune 2" }, + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune3", "Detune 3" }, + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune4", "Detune 4" }, + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune5", "Detune 5" }, + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune6", "Detune 6" }, + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune7", "Detune 7" }, + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune8", "Detune 8" }, + { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune9", "Detune 9" }, + + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase1", "Phase 1" }, + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase2", "Phase 2" }, + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase3", "Phase 3" }, + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase4", "Phase 4" }, + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase5", "Phase 5" }, + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase6", "Phase 6" }, + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase7", "Phase 7" }, + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase8", "Phase 8" }, + { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase9", "Phase 9" }, + + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan1", "Pan 1" }, + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan2", "Pan 2" }, + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan3", "Pan 3" }, + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan4", "Pan 4" }, + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan5", "Pan 5" }, + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan6", "Pan 6" }, + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan7", "Pan 7" }, + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan8", "Pan 8" }, + { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan9", "Pan 9" }, + + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing1", "Routing 1" }, + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing2", "Routing 2" }, + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing3", "Routing 3" }, + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing4", "Routing 4" }, + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing5", "Routing 5" }, + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing6", "Routing 6" }, + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing7", "Routing 7" }, + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing8", "Routing 8" }, + { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing9", "Routing 9" }, + + { 96, 0, 127, 128, PF_INT | PF_CTL_KNOB | PF_UNIT_NOTE, NULL, "foldnote", "Foldover" }, + + { 200, 10, 3000, 100, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "perc_decay", "P: Carrier Decay" }, + { 0.25, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "perc_level", "P: Level" }, + { 0, 0, organ_enums::wave_count_small - 1, 1, PF_ENUM | PF_CTL_COMBO, organ_wave_names, "perc_waveform", "P: Carrier Wave" }, + { 6, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "perc_harmonic", "P: Carrier Frq" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "perc_vel2amp", "P: Vel->Amp" }, + + { 200, 10, 3000, 100, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "perc_fm_decay", "P: Modulator Decay" }, + { 0, 0, 4, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "perc_fm_depth", "P: FM Depth" }, + { 0, 0, organ_enums::wave_count_small - 1, 1, PF_ENUM | PF_CTL_COMBO, organ_wave_names, "perc_fm_waveform", "P: Modulator Wave" }, + { 6, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "perc_fm_harmonic", "P: Modulator Frq" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "perc_vel2fm", "P: Vel->FM" }, + + { 0, 0, organ_enums::perctrig_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_percussion_trigger_names, "perc_trigger", "P: Trigger" }, + { 90, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "perc_stereo", "P: Stereo Phase" }, + + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, organ_filter_send_names, "filter_chain", "Filter 1 To" }, + { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, organ_filter_type_names, "filter1_type", "Filter 1 Type" }, + { 0.1, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_PROP_OUTPUT_GAIN | PF_PROP_GRAPH, NULL, "master", "Volume" }, + + { 2000, 20, 20000, 100, PF_FLOAT | PF_SCALE_LOG | PF_UNIT_HZ | PF_CTL_KNOB, NULL, "f1_cutoff", "F1 Cutoff" }, + { 2, 0.7, 8, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL, "f1_res", "F1 Res" }, + { 8000, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f1_env1", "F1 Env1" }, + { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f1_env2", "F1 Env2" }, + { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f1_env3", "F1 Env3" }, + { 0, 0, 2, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "f1_keyf", "F1 KeyFollow" }, + + { 2000, 20, 20000, 100, PF_FLOAT | PF_SCALE_LOG | PF_UNIT_HZ | PF_CTL_KNOB, NULL, "f2_cutoff", "F2 Cutoff" }, + { 2, 0.7, 8, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL, "f2_res", "F2 Res" }, + { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f2_env1", "F2 Env1" }, + { 8000, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f2_env2", "F2 Env2" }, + { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f2_env3", "F2 Env3" }, + { 0, 0, 2, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "f2_keyf", "F2 KeyFollow" }, + + { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_a", "EG1 Attack" }, + { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_d", "EG1 Decay" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_s", "EG1 Sustain" }, + { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_r", "EG1 Release" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_v", "EG1 VelMod" }, + { 0, 0, organ_enums::ampctl_count - 1, + 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "eg1_amp_ctl", "EG1 To Amp"}, + + { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_a", "EG2 Attack" }, + { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_d", "EG2 Decay" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_s", "EG2 Sustain" }, + { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_r", "EG2 Release" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_v", "EG2 VelMod" }, + { 0, 0, organ_enums::ampctl_count - 1, + 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "eg2_amp_ctl", "EG2 To Amp"}, + + { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_a", "EG3 Attack" }, + { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_d", "EG3 Decay" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr3_s", "EG3 Sustain" }, + { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_r", "EG3 Release" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr3_v", "EG3 VelMod" }, + { 0, 0, organ_enums::ampctl_count - 1, + 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "eg3_amp_ctl", "EG3 To Amp"}, + + { 6.6, 0.01, 80, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "vib_rate", "Vib Rate" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "vib_amt", "Vib Mod Amt" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "vib_wet", "Vib Wet" }, + { 180, 0, 360, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "vib_phase", "Vib Stereo" }, + { organ_enums::lfomode_global, 0, organ_enums::lfomode_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_vibrato_mode_names, "vib_mode", "Vib Mode" }, +// { 0, 0, organ_enums::ampctl_count - 1, +// 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "vel_amp_ctl", "Vel To Amp"}, + + { -12, -24, 24, 49, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "transpose", "Transpose" }, + { 0, -100, 100, 201, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune", "Detune" }, + + { 16, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "polyphony", "Polyphony" }, + + { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "quad_env", "Quadratic AmpEnv" }, + + { 200, 0, 2400, 25, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "pbend_range", "PBend Range" }, + + { 80, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "bass_freq", "Bass Freq" }, + { 1, 0.1, 10, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "bass_gain", "Bass Gain" }, + { 12000, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "treble_freq", "Treble Freq" }, + { 1, 0.1, 10, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "treble_gain", "Treble Gain" }, + + { 0, 0, 0, 0, PF_STRING | PF_PROP_MSGCONTEXT, &organ_init_map_curve, "map_curve", "Key mapping curve" }, +}; + +//////////////////////////////////////////////////////////////////////////// + +const char *fluidsynth_init_soundfont = ""; +const char *fluidsynth_init_presetkeyset = ""; + +const char *fluidsynth_interpolation_names[] = { "None (zero-hold)", "Linear", "Cubic", "7-point" }; + +CALF_PORT_NAMES(fluidsynth) = { + "Out L", "Out R", +}; + +CALF_PLUGIN_INFO(fluidsynth) = { 0x8700, "Fluidsynth", "Calf Fluidsynth", "FluidSynth Team / Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" }; + +CALF_PORT_PROPS(fluidsynth) = { + { 0.5, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_PROP_OUTPUT_GAIN, NULL, "master", "Volume" }, + { 2, 0, 3, 0, PF_ENUM | PF_CTL_COMBO, fluidsynth_interpolation_names, "interpolation", "Interpolation" }, + { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "reverb", "Reverb" }, + { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "chorus", "Chorus" }, + { 0, 0, 0, 0, PF_STRING | PF_PROP_MSGCONTEXT, &fluidsynth_init_soundfont, "soundfont", "Soundfont" }, + { 0, 0, 0, 0, PF_STRING | PF_PROP_MSGCONTEXT, &fluidsynth_init_presetkeyset, "preset_key_set", "Set Preset" }, +}; + +//////////////////////////////////////////////////////////////////////////// + +const char *wavetable_names[] = { + "Shiny1", + "Shiny2", + "Rezo", + "Metal", + "Bell", + "Blah", + "Pluck", + "Stretch", + "Stretch 2", + "Hard Sync", + "Hard Sync 2", + "Soft Sync", + "Bell 2", + "Bell 3", + "Tine", + "Tine 2", + "Clav", + "Clav 2", + "Gtr", + "Gtr 2", + "Gtr 3", + "Gtr 4", + "Gtr 5", + "Reed", + "Reed 2", + "Silver", + "Brass", + "Multi", + "Multi 2", +}; + +const char *wavetable_init_soundfont = ""; + +CALF_PORT_NAMES(wavetable) = { + "Out L", "Out R", +}; + +CALF_PLUGIN_INFO(wavetable) = { 0x8701, "Wavetable", "Calf Wavetable", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" }; + +CALF_PORT_PROPS(wavetable) = { + { wavetable_metadata::wt_count - 1, 0, wavetable_metadata::wt_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, wavetable_names, "o1wave", "Osc1 Wave" }, + { 0.2, -1, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "o1offset", "Osc1 Ctl"}, + { 0, -48, 48, 48*2+1, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o1trans", "Osc1 Transpose" }, + { 6, -100, 100, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o1detune", "Osc1 Detune" }, + { 0.1, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "o1level", "Osc1 Level" }, + + { 0, 0, wavetable_metadata::wt_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, wavetable_names, "o2wave", "Osc2 Wave" }, + { 0.4, -1, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "o2offset", "Osc2 Ctl"}, + { 0, -48, 48, 48*2+1, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o2trans", "Osc2 Transpose" }, + { -6, -100, 100, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o2detune", "Osc2 Detune" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "o2level", "Osc2 Level" }, + + { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_a", "EG1 Attack" }, + { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_d", "EG1 Decay" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_s", "EG1 Sustain" }, + { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_f", "EG1 Fade" }, + { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_r", "EG1 Release" }, + { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_v", "EG1 VelMod" }, + + { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_a", "EG2 Attack" }, + { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_d", "EG2 Decay" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_s", "EG2 Sustain" }, + { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_f", "EG2 Fade" }, + { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_r", "EG2 Release" }, + { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_v", "EG2 VelMod" }, + + { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_a", "EG3 Attack" }, + { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_d", "EG3 Decay" }, + { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr3_s", "EG3 Sustain" }, + { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_f", "EG3 Fade" }, + { 50, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_r", "EG3 Release" }, + { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr3_v", "EG3 VelMod" }, + + { 200, 0, 2400, 25, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "pbend_range", "PBend Range" }, +}; + +//////////////////////////////////////////////////////////////////////////// + +calf_plugins::plugin_registry::plugin_registry() +{ + #define PER_MODULE_ITEM(name, isSynth, jackname) plugins.push_back((new name##_metadata)); + #include +} + diff --git a/plugins/ladspa_effect/calf/src/modmatrix.cpp b/plugins/ladspa_effect/calf/src/modmatrix.cpp index c3bb4f762..2ef798aca 100644 --- a/plugins/ladspa_effect/calf/src/modmatrix.cpp +++ b/plugins/ladspa_effect/calf/src/modmatrix.cpp @@ -18,9 +18,10 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#include -#include #include +#include +#include +#include using namespace std; using namespace dsp; diff --git a/plugins/ladspa_effect/calf/src/modules.cpp b/plugins/ladspa_effect/calf/src/modules.cpp index ce74d5a17..fdfab11cc 100644 --- a/plugins/ladspa_effect/calf/src/modules.cpp +++ b/plugins/ladspa_effect/calf/src/modules.cpp @@ -1,7 +1,7 @@ -/* Calf DSP Library - * Example audio modules - parameters and LADSPA wrapper instantiation +/* Calf DSP plugin pack + * Assorted plugins * - * Copyright (C) 2001-2008 Krzysztof Foltman + * Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,881 +18,428 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#include +#include #include -#if USE_JACK -#include -#endif #include -#include -#include +#include +#include using namespace dsp; using namespace calf_plugins; -const char *calf_plugins::calf_copyright_info = "(C) 2001-2009 Krzysztof Foltman, Thor Harald Johanssen, Markus Schmidt and others; license: LGPL"; +#define SET_IF_CONNECTED(name) if (params[AM::param_##name] != NULL) *params[AM::param_##name] = name; -//////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// -CALF_PORT_NAMES(flanger) = {"In L", "In R", "Out L", "Out R"}; - -CALF_PORT_PROPS(flanger) = { - { 0.1, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC | PF_PROP_GRAPH, NULL, "min_delay", "Min delay" }, - { 0.5, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "mod_depth", "Mod depth" }, - { 0.25, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "mod_rate", "Mod rate" }, - { 0.90, -0.99, 0.99, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "feedback", "Feedback" }, - { 0, 0, 360, 9, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "stereo", "Stereo phase" }, - { 0, 0, 1, 2, PF_BOOL | PF_CTL_BUTTON , NULL, "reset", "Reset" }, - { 1, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" }, - { 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, -}; - -CALF_PLUGIN_INFO(flanger) = { 0x847d, "Flanger", "Calf Flanger", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "FlangerPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(phaser) = {"In L", "In R", "Out L", "Out R"}; - -CALF_PORT_PROPS(phaser) = { - { 1000, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "base_freq", "Center Freq" }, - { 4000, 0, 10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "mod_depth", "Mod depth" }, - { 0.25, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "mod_rate", "Mod rate" }, - { 0.25, -0.99, 0.99, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "feedback", "Feedback" }, - { 6, 1, 12, 12, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "stages", "# Stages" }, - { 180, 0, 360, 9, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "stereo", "Stereo phase" }, - { 0, 0, 1, 2, PF_BOOL | PF_CTL_BUTTON , NULL, "reset", "Reset" }, - { 1, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" }, - { 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, -}; - -CALF_PLUGIN_INFO(phaser) = { 0x8484, "Phaser", "Calf Phaser", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "PhaserPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(reverb) = {"In L", "In R", "Out L", "Out R"}; - -const char *reverb_room_sizes[] = { "Small", "Medium", "Large", "Tunnel-like", "Large/smooth", "Experimental" }; - -CALF_PORT_PROPS(reverb) = { - { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip", "0dB" }, - { 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_wet", "Wet amount" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, - { 1.5, 0.4, 15.0, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_SEC, NULL, "decay_time", "Decay time" }, - { 5000, 2000,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hf_damp", "High Frq Damp" }, - { 2, 0, 5, 0, PF_ENUM | PF_CTL_COMBO , reverb_room_sizes, "room_size", "Room size", }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "diffusion", "Diffusion" }, - { 0.25, 0, 2, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Wet Amount" }, - { 1.0, 0, 2, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, - { 0, 0, 50, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "predelay", "Pre Delay" }, - { 300, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "bass_cut", "Bass Cut" }, - { 5000, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "treble_cut", "Treble Cut" }, -}; - -CALF_PLUGIN_INFO(reverb) = { 0x847e, "Reverb", "Calf Reverb", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "ReverbPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(filter) = {"In L", "In R", "Out L", "Out R"}; - -const char *filter_choices[] = { - "12dB/oct Lowpass", - "24dB/oct Lowpass", - "36dB/oct Lowpass", - "12dB/oct Highpass", - "24dB/oct Highpass", - "36dB/oct Highpass", - "6dB/oct Bandpass", - "12dB/oct Bandpass", - "18dB/oct Bandpass", - "6dB/oct Bandreject", - "12dB/oct Bandreject", - "18dB/oct Bandreject", -}; - -CALF_PORT_PROPS(filter) = { - { 2000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq", "Frequency" }, - { 0.707, 0.707, 32, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "res", "Resonance" }, - { biquad_filter_module::mode_12db_lp, - biquad_filter_module::mode_12db_lp, - biquad_filter_module::mode_count - 1, - 1, PF_ENUM | PF_CTL_COMBO, filter_choices, "mode", "Mode" }, - { 20, 5, 100, 20, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "inertia", "Inertia"}, -}; - -CALF_PLUGIN_INFO(filter) = { 0x847f, "Filter", "Calf Filter", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "FilterPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(filterclavier) = {"In L", "In R", "Out L", "Out R"}; - -CALF_PORT_PROPS(filterclavier) = { - { 0, -48, 48, 48*2+1, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "transpose", "Transpose" }, - { 0, -100, 100, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune", "Detune" }, - { 32, 0.707, 32, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "maxres", "Max. Resonance" }, - { biquad_filter_module::mode_6db_bp, - biquad_filter_module::mode_12db_lp, - biquad_filter_module::mode_count - 1, - 1, PF_ENUM | PF_CTL_COMBO | PF_PROP_GRAPH, filter_choices, "mode", "Mode" }, - { 20, 1, 2000, 20, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "inertia", "Portamento time"} -}; - -CALF_PLUGIN_INFO(filterclavier) = { 0x849f, "Filterclavier", "Calf Filterclavier", "Krzysztof Foltman / Hans Baier", calf_plugins::calf_copyright_info, "FilterclavierPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(vintage_delay) = {"In L", "In R", "Out L", "Out R"}; - -const char *vintage_delay_mixmodes[] = { - "Stereo", - "Ping-Pong", -}; - -const char *vintage_delay_fbmodes[] = { - "Plain", - "Tape", - "Old Tape", -}; - -CALF_PORT_PROPS(vintage_delay) = { - { 120, 30, 300, 1, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_BPM, NULL, "bpm", "Tempo" }, - { 4, 1, 16, 1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "subdiv", "Subdivide"}, - { 3, 1, 16, 1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_l", "Time L"}, - { 5, 1, 16, 1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_r", "Time R"}, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "feedback", "Feedback" }, - { 0.25, 0, 4, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" }, - { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, vintage_delay_mixmodes, "mix_mode", "Mix mode" }, - { 1, 0, 2, 0, PF_ENUM | PF_CTL_COMBO, vintage_delay_fbmodes, "medium", "Medium" }, - { 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, -}; - -CALF_PLUGIN_INFO(vintage_delay) = { 0x8482, "VintageDelay", "Calf Vintage Delay", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "DelayPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(rotary_speaker) = {"In L", "In R", "Out L", "Out R"}; - -const char *rotary_speaker_speed_names[] = { "Off", "Chorale", "Tremolo", "HoldPedal", "ModWheel", "Manual" }; - -CALF_PORT_PROPS(rotary_speaker) = { - { 5, 0, 5, 1.01, PF_ENUM | PF_CTL_COMBO, rotary_speaker_speed_names, "vib_speed", "Speed Mode" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "spacing", "Tap Spacing" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "shift", "Tap Offset" }, - { 0.10, 0, 1, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "mod_depth", "Mod Depth" }, - { 36, 10, 600, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_LOG | PF_UNIT_RPM, NULL, "treble_speed", "Treble Motor" }, - { 30, 10, 600, 0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_LOG | PF_UNIT_RPM, NULL, "bass_speed", "Bass Motor" }, - { 0.7, 0, 1, 101, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "mic_distance", "Mic Distance" }, - { 0.3, 0, 1, 101, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "reflection", "Reflection" }, - { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_l", "Low rotor" }, - { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_h", "High rotor" }, -}; - -CALF_PLUGIN_INFO(rotary_speaker) = { 0x8483, "RotarySpeaker", "Calf Rotary Speaker", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SimulationPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(multichorus) = {"In L", "In R", "Out L", "Out R"}; - -CALF_PORT_PROPS(multichorus) = { - { 5, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC | PF_PROP_GRAPH, NULL, "min_delay", "Min delay" }, - { 6, 0.1, 10, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC| PF_PROP_GRAPH, NULL, "mod_depth", "Mod depth" }, - { 0.5, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ| PF_PROP_GRAPH, NULL, "mod_rate", "Modulation rate" }, - { 180, 0, 360, 91, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "stereo", "Stereo phase" }, - { 4, 1, 8, 8, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "voices", "Voices"}, - { 64, 0, 360, 91, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "vphase", "Inter-voice phase" }, - { 2, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" }, - { 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" }, - { 100, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq", "Center Frq 1" }, - { 5000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq2", "Center Frq 2" }, - { 0.125, 0.125, 8, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "q", "Q" }, - { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "overlap", "Overlap" }, -}; - -CALF_PLUGIN_INFO(multichorus) = { 0x8501, "MultiChorus", "Calf MultiChorus", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "ChorusPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(compressor) = {"In L", "In R", "Out L", "Out R"}; - -const char *compressor_detection_names[] = { "RMS", "Peak" }; -const char *compressor_stereo_link_names[] = { "Average", "Maximum" }; - -CALF_PORT_PROPS(compressor) = { - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, - { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB-In" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB-Out" }, - { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" }, - { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" }, - { 20, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" }, - { 250, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" }, - { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" }, - { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" }, - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, compressor_detection_names, "detection", "Detection" }, - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, compressor_stereo_link_names, "stereo_link", "Stereo Link" }, - { 0, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression", "Reduction" }, -}; - -CALF_PLUGIN_INFO(compressor) = { 0x8502, "Compressor", "Calf Compressor", "Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(sidechaincompressor) = {"In L", "In R", "Out L", "Out R"}; - -const char *sidechaincompressor_detection_names[] = { "RMS", "Peak" }; -const char *sidechaincompressor_stereo_link_names[] = { "Average", "Maximum" }; -const char *sidechaincompressor_mode_names[] = {"Wideband (F1:off / F2:off)", - "Deesser wide (F1:Bell / F2:HP)", - "Deesser split (F1:off / F2:HP)", - "Derumbler wide (F1:LP / F2:Bell)", - "Derumbler split (F1:LP / F2:off)", - "Weighted #1 (F1:Shelf / F2:Shelf)", - "Weighted #2 (F1:Shelf / F2:Bell)", - "Weighted #3 (F1:Bell / F2:Shelf)", - "Bandpass #1 (F1:BP / F2:off)", - "Bandpass #2 (F1:HP / F2:LP)"}; -const char *sidechaincompressor_filter_choices[] = { "12dB", "24dB", "36dB"}; - - -CALF_PORT_PROPS(sidechaincompressor) = { - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, - { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB-In" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB-Out" }, - { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" }, - { 2, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" }, - { 20, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack", "Attack" }, - { 250, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release", "Release" }, - { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup Gain" }, - { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee", "Knee" }, - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_detection_names, "detection", "Detection" }, - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_stereo_link_names, "stereo_link", "Stereo Link" }, - { 0, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression", "Gain Reduction" }, - { 0, 0, 9, 0, PF_ENUM | PF_CTL_COMBO, sidechaincompressor_mode_names, "sc_mode", "Sidechain Mode" }, - { 250, 10,18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "f1_freq", "F1 Freq" }, - { 4500, 10,18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "f2_freq", "F2 Freq" }, - { 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f1_level", "F1 Level" }, - { 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f2_level", "F2 Level" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "sc_listen", "S/C-Listen" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f1_active", "F1 Active" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f2_active", "F2 Active" }, -}; - -CALF_PLUGIN_INFO(sidechaincompressor) = { 0x8517, "Sidechaincompressor", "Calf Sidechain Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(multibandcompressor) = {"In L", "In R", "Out L", "Out R"}; - -const char *multibandcompressor_detection_names[] = { "RMS", "Peak" }; - -CALF_PORT_PROPS(multibandcompressor) = { - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, - { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" }, - { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inL", "Input L" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inR", "Input R" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outL", "Output L" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outR", "Output R" }, - { 0, 0, 1, 0, PF_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" }, - { 1000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq1", "Split 2/3" }, - { 6000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq2", "Split 3/4" }, - - { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep0", "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.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.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" }, - { 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_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.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" }, - { 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_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.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" }, - { 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_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.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" }, - { 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_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" }, -}; - -CALF_PLUGIN_INFO(multibandcompressor) = { 0x8516, "Multibandcompressor", "Calf Multiband Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(deesser) = {"In L", "In R", "Out L", "Out R"}; - -const char *deesser_detection_names[] = { "RMS", "Peak" }; -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, 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" }, - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, deesser_mode_names, "mode", "Mode" }, - { 0.125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold", "Threshold" }, - { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio", "Ratio" }, - { 15, 1, 100, 1, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "laxity", "Laxity" }, - { 1, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup", "Makeup" }, - - { 6000, 10, 18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "f1_freq", "Split" }, - { 4500, 10, 18000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "f2_freq", "Peak" }, - { 1, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f1_level", "Gain" }, - { 4, 0.0625, 16, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "f2_level", "Level" }, - { 1, 0.1, 100,1, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "f2_q", "Peak Q" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "sc_listen", "S/C-Listen" }, -}; - -CALF_PLUGIN_INFO(deesser) = { 0x8515, "Deesser", "Calf Deesser", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" }; - -//////////////////////////////////////////////////////////////////////////// -// A few macros to make - -#define BYPASS_AND_LEVEL_PARAMS \ - { 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 Gain" }, \ - { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output Gain" }, - -#define METERING_PARAMS \ - { 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", "Meter-InL" }, \ - { 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", "Meter-InR" }, \ - { 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", "Meter-OutL" }, \ - { 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", "Meter-OutR" }, \ - { 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" }, - -#define LPHP_PARAMS \ - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "hp_active", "HP Active" }, \ - { 30, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_freq", "HP Freq" }, \ - { 1, 0, 2, 0, PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "hp_mode", "HP Mode" }, \ - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "lp_active", "LP Active" }, \ - { 18000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_freq", "LP Freq" }, \ - { 1, 0, 2, 0, PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "lp_mode", "LP Mode" }, \ - -#define SHELF_PARAMS \ - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "ls_active", "LS Active" }, \ - { 1, 0.015625, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "ls_level", "Level L" }, \ - { 200, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "ls_freq", "Freq L" }, \ - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "hs_active", "HS Active" }, \ - { 1, 0.015625, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "hs_level", "Level H" }, \ - { 4000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hs_freq", "Freq H" }, - -#define EQ_BAND_PARAMS(band, frequency) \ - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "p" #band "_active", "F" #band " Active" }, \ - { 1, 0.015625, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "p" #band "_level", "Level " #band }, \ - { frequency, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "p" #band "_freq", "Freq " #band }, \ - { 1, 0.1, 100, 1, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "p" #band "_q", "Q " #band }, - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(equalizer5band) = {"In L", "In R", "Out L", "Out R"}; - -CALF_PORT_PROPS(equalizer5band) = { - BYPASS_AND_LEVEL_PARAMS - METERING_PARAMS - SHELF_PARAMS - EQ_BAND_PARAMS(1, 250) - EQ_BAND_PARAMS(2, 1000) - EQ_BAND_PARAMS(3, 2500) -}; - -CALF_PLUGIN_INFO(equalizer5band) = { 0x8511, "Equalizer5Band", "Calf Equalizer 5 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" }; - -////////////////////////////////////////////////////////////////////////////// - - -CALF_PORT_NAMES(equalizer8band) = {"In L", "In R", "Out L", "Out R"}; -const char *rolloff_mode_names[] = {"12dB/oct", "24dB/oct", "36dB/oct"}; - -CALF_PORT_PROPS(equalizer8band) = { - BYPASS_AND_LEVEL_PARAMS - METERING_PARAMS - LPHP_PARAMS - SHELF_PARAMS - EQ_BAND_PARAMS(1, 250) - EQ_BAND_PARAMS(2, 1000) - EQ_BAND_PARAMS(3, 2500) - EQ_BAND_PARAMS(4, 5000) -}; - -CALF_PLUGIN_INFO(equalizer8band) = { 0x8512, "Equalizer8Band", "Calf Equalizer 8 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(equalizer12band) = {"In L", "In R", "Out L", "Out R"}; - -CALF_PORT_PROPS(equalizer12band) = { - BYPASS_AND_LEVEL_PARAMS - METERING_PARAMS - LPHP_PARAMS - SHELF_PARAMS - EQ_BAND_PARAMS(1, 60) - EQ_BAND_PARAMS(2, 120) - EQ_BAND_PARAMS(3, 250) - EQ_BAND_PARAMS(4, 500) - EQ_BAND_PARAMS(5, 1000) - EQ_BAND_PARAMS(6, 2500) - EQ_BAND_PARAMS(7, 4000) - EQ_BAND_PARAMS(8, 6000) -}; - -CALF_PLUGIN_INFO(equalizer12band) = { 0x8513, "Equalizer12Band", "Calf Equalizer 12 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(pulsator) = {"In L", "In R", "Out L", "Out R"}; - -const char *pulsator_mode_names[] = { "Sine", "Triangle", "Square", "Saw up", "Saw down" }; - -CALF_PORT_PROPS(pulsator) = { - BYPASS_AND_LEVEL_PARAMS - METERING_PARAMS - { 0, 0, 4, 0, PF_ENUM | PF_CTL_COMBO, pulsator_mode_names, "mode", "Mode" }, - { 1, 0.01, 100, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Frequency" }, - { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "amount", "Modulation" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "offset", "Offset L/R" }, - { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mono", "Mono-in" }, - { 0, 0, 1, 2, PF_BOOL | PF_CTL_BUTTON , NULL, "reset", "Reset" }, -}; - -CALF_PLUGIN_INFO(pulsator) = { 0x8514, "Pulsator", "Calf Pulsator", "Markus Schmidt", calf_plugins::calf_copyright_info, "ModulationPlugin" }; - -//////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////// - -CALF_PORT_NAMES(monosynth) = { - "Out L", "Out R", -}; - -const char *monosynth_waveform_names[] = { "Sawtooth", "Square", "Pulse", "Sine", "Triangle", "Varistep", "Skewed Saw", "Skewed Square", - "Smooth Brass", "Bass", "Dark FM", "Multiwave", "Bell FM", "Dark Pad", "DCO Saw", "DCO Maze" }; -const char *monosynth_mode_names[] = { "0 : 0", "0 : 180", "0 : 90", "90 : 90", "90 : 270", "Random" }; -const char *monosynth_legato_names[] = { "Retrig", "Legato", "Fng Retrig", "Fng Legato" }; - -const char *monosynth_filter_choices[] = { - "12dB/oct Lowpass", - "24dB/oct Lowpass", - "2x12dB/oct Lowpass", - "12dB/oct Highpass", - "Lowpass+Notch", - "Highpass+Notch", - "6dB/oct Bandpass", - "2x6dB/oct Bandpass", -}; - -CALF_PLUGIN_INFO(monosynth) = { 0x8480, "Monosynth", "Calf Monosynth", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" }; - -CALF_PORT_PROPS(monosynth) = { - { monosynth_metadata::wave_saw, 0, monosynth_metadata::wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO | PF_PROP_GRAPH, monosynth_waveform_names, "o1_wave", "Osc1 Wave" }, - { monosynth_metadata::wave_sqr, 0, monosynth_metadata::wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO | PF_PROP_GRAPH, monosynth_waveform_names, "o2_wave", "Osc2 Wave" }, - - { 0, -1, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "o1_pw", "Osc1 PW" }, - { 0, -1, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "o2_pw", "Osc2 PW" }, - - { 10, 0, 100, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o12_detune", "O1<>2 Detune" }, - { 12, -24, 24, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o2_xpose", "Osc 2 transpose" }, - { 0, 0, 5, 0, PF_ENUM | PF_CTL_COMBO, monosynth_mode_names, "phase_mode", "Phase mode" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "o12_mix", "O1<>2 Mix" }, - { 1, 0, 7, 0, PF_ENUM | PF_CTL_COMBO | PF_PROP_GRAPH, monosynth_filter_choices, "filter", "Filter" }, - { 33, 10,16000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "cutoff", "Cutoff" }, - { 2, 0.7, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "res", "Resonance" }, - { 0, -2400, 2400, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "filter_sep", "Separation" }, - { 8000, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "env2cutoff", "Env->Cutoff" }, - { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2res", "Env->Res" }, - { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2amp", "Env->Amp" }, - - { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr_a", "Attack" }, - { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr_d", "Decay" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_s", "Sustain" }, - { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr_f", "Fade" }, - { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_FADER | PF_UNIT_MSEC, NULL, "adsr_r", "Release" }, - - { 0, 0, 2, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "key_follow", "Key Follow" }, - { 0, 0, 3, 0, PF_ENUM | PF_CTL_COMBO, monosynth_legato_names, "legato", "Legato Mode" }, - { 1, 1, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "portamento", "Portamento" }, - - { 0.5, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2filter", "Vel->Filter" }, - { 0, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2amp", "Vel->Amp" }, - - { 0.5, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_PROP_OUTPUT_GAIN, NULL, "master", "Volume" }, - - { 200, 0, 2400, 25, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "pbend_range", "PBend Range" }, - - { 5, 0.01, 20, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lfo_rate", "LFO Rate" }, - { 0.5, 0.1, 5, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_SEC, NULL, "lfo_delay", "LFO Delay" }, - { 0, -4800, 4800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "lfo2filter", "LFO->Filter" }, - { 100, 0, 1200, 0, PF_FLOAT | PF_SCALE_QUAD | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "lfo2pitch", "LFO->Pitch" }, - { 0, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "lfo2pw", "LFO->PW" }, - { 1, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "mwhl2lfo", "ModWheel->LFO" }, - - { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "scale_detune", "Scale Detune" }, -}; - -//////////////////////////////////////////////////////////////////////////// - -CALF_PLUGIN_INFO(organ) = { 0x8481, "Organ", "Calf Organ", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" }; - -const char **organ_metadata::get_default_configure_vars() +void reverb_audio_module::activate() { - static const char *data[] = { "map_curve", "2\n0 1\n1 1\n", NULL }; - return data; + reverb.reset(); } -plugin_command_info *organ_metadata::get_commands() +void reverb_audio_module::deactivate() { - static plugin_command_info cmds[] = { - { "cmd_panic", "Panic!", "Stop all sounds and reset all controllers" }, - { NULL } - }; - return cmds; } -CALF_PORT_NAMES(organ) = {"Out L", "Out R"}; - -const char *organ_percussion_trigger_names[] = { "First note", "Each note", "Each, no retrig", "Polyphonic" }; - -const char *organ_wave_names[] = { - "Sin", - "S0", "S00", "S000", - "SSaw", "SSqr", "SPls", - "Saw", "Sqr", "Pls", - "S(", "Sq(", "S+", "Clvg", - "Bell", "Bell2", - "W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8", "W9", - "DSaw", "DSqr", "DPls", - "P:SynStr","P:WideStr","P:Sine","P:Bell","P:Space","P:Voice","P:Hiss","P:Chant", -}; - -const char *organ_routing_names[] = { "Out", "Flt 1", "Flt 2" }; - -const char *organ_ampctl_names[] = { "None", "Direct", "Flt 1", "Flt 2", "All" }; - -const char *organ_vibrato_mode_names[] = { "None", "Direct", "Flt 1", "Flt 2", "Voice", "Global" }; - -const char *organ_filter_type_names[] = { "12dB/oct LP", "12dB/oct HP" }; - -const char *organ_filter_send_names[] = { "Output", "Filter 2" }; - -const char *organ_init_map_curve = "2\n0 1\n1 1\n"; - -CALF_PORT_PROPS(organ) = { - { 8, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l1", "16'" }, - { 8, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l2", "5 1/3'" }, - { 8, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l3", "8'" }, - { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l4", "4'" }, - { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l5", "2 2/3'" }, - { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l6", "2'" }, - { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l7", "1 3/5'" }, - { 0, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l8", "1 1/3'" }, - { 8, 0, 8, 80, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "l9", "1'" }, - - { 1, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f1", "Freq 1" }, - { 3, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f2", "Freq 2" }, - { 2, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f3", "Freq 3" }, - { 4, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f4", "Freq 4" }, - { 6, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f5", "Freq 5" }, - { 8, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f6", "Freq 6" }, - { 10, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f7", "Freq 7" }, - { 12, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f8", "Freq 8" }, - { 16, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "f9", "Freq 9" }, - - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w1", "Wave 1" }, - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w2", "Wave 2" }, - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w3", "Wave 3" }, - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w4", "Wave 4" }, - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w5", "Wave 5" }, - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w6", "Wave 6" }, - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w7", "Wave 7" }, - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w8", "Wave 8" }, - { 0, 0, organ_enums::wave_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_wave_names, "w9", "Wave 9" }, - - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune1", "Detune 1" }, - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune2", "Detune 2" }, - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune3", "Detune 3" }, - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune4", "Detune 4" }, - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune5", "Detune 5" }, - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune6", "Detune 6" }, - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune7", "Detune 7" }, - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune8", "Detune 8" }, - { 0, -100,100, 401, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune9", "Detune 9" }, - - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase1", "Phase 1" }, - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase2", "Phase 2" }, - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase3", "Phase 3" }, - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase4", "Phase 4" }, - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase5", "Phase 5" }, - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase6", "Phase 6" }, - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase7", "Phase 7" }, - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase8", "Phase 8" }, - { 0, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "phase9", "Phase 9" }, - - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan1", "Pan 1" }, - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan2", "Pan 2" }, - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan3", "Pan 3" }, - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan4", "Pan 4" }, - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan5", "Pan 5" }, - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan6", "Pan 6" }, - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan7", "Pan 7" }, - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan8", "Pan 8" }, - { 0, -1, 1, 201, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "pan9", "Pan 9" }, - - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing1", "Routing 1" }, - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing2", "Routing 2" }, - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing3", "Routing 3" }, - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing4", "Routing 4" }, - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing5", "Routing 5" }, - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing6", "Routing 6" }, - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing7", "Routing 7" }, - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing8", "Routing 8" }, - { 0, 0, 2, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, organ_routing_names, "routing9", "Routing 9" }, - - { 96, 0, 127, 128, PF_INT | PF_CTL_KNOB | PF_UNIT_NOTE, NULL, "foldnote", "Foldover" }, - - { 200, 10, 3000, 100, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "perc_decay", "P: Carrier Decay" }, - { 0.25, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "perc_level", "P: Level" }, - { 0, 0, organ_enums::wave_count_small - 1, 1, PF_ENUM | PF_CTL_COMBO, organ_wave_names, "perc_waveform", "P: Carrier Wave" }, - { 6, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "perc_harmonic", "P: Carrier Frq" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "perc_vel2amp", "P: Vel->Amp" }, - - { 200, 10, 3000, 100, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "perc_fm_decay", "P: Modulator Decay" }, - { 0, 0, 4, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "perc_fm_depth", "P: FM Depth" }, - { 0, 0, organ_enums::wave_count_small - 1, 1, PF_ENUM | PF_CTL_COMBO, organ_wave_names, "perc_fm_waveform", "P: Modulator Wave" }, - { 6, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "perc_fm_harmonic", "P: Modulator Frq" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "perc_vel2fm", "P: Vel->FM" }, - - { 0, 0, organ_enums::perctrig_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_percussion_trigger_names, "perc_trigger", "P: Trigger" }, - { 90, 0,360, 361, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "perc_stereo", "P: Stereo Phase" }, - - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, organ_filter_send_names, "filter_chain", "Filter 1 To" }, - { 0, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, organ_filter_type_names, "filter1_type", "Filter 1 Type" }, - { 0.1, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_PROP_OUTPUT_GAIN | PF_PROP_GRAPH, NULL, "master", "Volume" }, - - { 2000, 20, 20000, 100, PF_FLOAT | PF_SCALE_LOG | PF_UNIT_HZ | PF_CTL_KNOB, NULL, "f1_cutoff", "F1 Cutoff" }, - { 2, 0.7, 8, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL, "f1_res", "F1 Res" }, - { 8000, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f1_env1", "F1 Env1" }, - { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f1_env2", "F1 Env2" }, - { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f1_env3", "F1 Env3" }, - { 0, 0, 2, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "f1_keyf", "F1 KeyFollow" }, - - { 2000, 20, 20000, 100, PF_FLOAT | PF_SCALE_LOG | PF_UNIT_HZ | PF_CTL_KNOB, NULL, "f2_cutoff", "F2 Cutoff" }, - { 2, 0.7, 8, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL, "f2_res", "F2 Res" }, - { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f2_env1", "F2 Env1" }, - { 8000, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f2_env2", "F2 Env2" }, - { 0, -10800,10800, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "f2_env3", "F2 Env3" }, - { 0, 0, 2, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "f2_keyf", "F2 KeyFollow" }, - - { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_a", "EG1 Attack" }, - { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_d", "EG1 Decay" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_s", "EG1 Sustain" }, - { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_r", "EG1 Release" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_v", "EG1 VelMod" }, - { 0, 0, organ_enums::ampctl_count - 1, - 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "eg1_amp_ctl", "EG1 To Amp"}, - - { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_a", "EG2 Attack" }, - { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_d", "EG2 Decay" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_s", "EG2 Sustain" }, - { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_r", "EG2 Release" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_v", "EG2 VelMod" }, - { 0, 0, organ_enums::ampctl_count - 1, - 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "eg2_amp_ctl", "EG2 To Amp"}, - - { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_a", "EG3 Attack" }, - { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_d", "EG3 Decay" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr3_s", "EG3 Sustain" }, - { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_r", "EG3 Release" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr3_v", "EG3 VelMod" }, - { 0, 0, organ_enums::ampctl_count - 1, - 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "eg3_amp_ctl", "EG3 To Amp"}, - - { 6.6, 0.01, 80, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "vib_rate", "Vib Rate" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "vib_amt", "Vib Mod Amt" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "vib_wet", "Vib Wet" }, - { 180, 0, 360, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "vib_phase", "Vib Stereo" }, - { organ_enums::lfomode_global, 0, organ_enums::lfomode_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_vibrato_mode_names, "vib_mode", "Vib Mode" }, -// { 0, 0, organ_enums::ampctl_count - 1, -// 0, PF_INT | PF_CTL_COMBO, organ_ampctl_names, "vel_amp_ctl", "Vel To Amp"}, - - { -12, -24, 24, 49, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "transpose", "Transpose" }, - { 0, -100, 100, 201, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "detune", "Detune" }, - - { 16, 1, 32, 32, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL, "polyphony", "Polyphony" }, - - { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "quad_env", "Quadratic AmpEnv" }, - - { 200, 0, 2400, 25, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "pbend_range", "PBend Range" }, - - { 80, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "bass_freq", "Bass Freq" }, - { 1, 0.1, 10, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "bass_gain", "Bass Gain" }, - { 12000, 20, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "treble_freq", "Treble Freq" }, - { 1, 0.1, 10, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "treble_gain", "Treble Gain" }, - - { 0, 0, 0, 0, PF_STRING | PF_PROP_MSGCONTEXT, &organ_init_map_curve, "map_curve", "Key mapping curve" }, -}; - -//////////////////////////////////////////////////////////////////////////// - -const char *fluidsynth_init_soundfont = ""; - -const char *fluidsynth_interpolation_names[] = { "None (zero-hold)", "Linear", "Cubic", "7-point" }; - -CALF_PORT_NAMES(fluidsynth) = { - "Out L", "Out R", -}; - -CALF_PLUGIN_INFO(fluidsynth) = { 0x8700, "Fluidsynth", "Calf Fluidsynth", "FluidSynth Team / Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" }; - -CALF_PORT_PROPS(fluidsynth) = { - { 0.5, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_PROP_OUTPUT_GAIN, NULL, "master", "Volume" }, - { 0, 0, 0, 0, PF_STRING | PF_PROP_MSGCONTEXT, &fluidsynth_init_soundfont, "soundfont", "Soundfont" }, - { 2, 0, 3, 0, PF_ENUM | PF_CTL_COMBO, fluidsynth_interpolation_names, "interpolation", "Interpolation" }, - { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "reverb", "Reverb" }, - { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "chorus", "Chorus" }, -}; - -//////////////////////////////////////////////////////////////////////////// - -const char *wavetable_names[] = { - "Shiny1", - "Shiny2", - "Rezo", - "Metal", - "Bell", - "Blah", - "Pluck", - "Stretch", - "Stretch 2", - "Hard Sync", - "Hard Sync 2", - "Soft Sync", - "Bell 2", - "Bell 3", - "Tine", - "Tine 2", - "Clav", - "Clav 2", - "Gtr", - "Gtr 2", - "Gtr 3", - "Gtr 4", - "Gtr 5", - "Reed", - "Reed 2", - "Silver", - "Brass", - "Multi", - "Multi 2", -}; - -const char *wavetable_init_soundfont = ""; - -CALF_PORT_NAMES(wavetable) = { - "Out L", "Out R", -}; - -CALF_PLUGIN_INFO(wavetable) = { 0x8701, "Wavetable", "Calf Wavetable", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" }; - -CALF_PORT_PROPS(wavetable) = { - { wavetable_metadata::wt_count - 1, 0, wavetable_metadata::wt_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, wavetable_names, "o1wave", "Osc1 Wave" }, - { 0.2, -1, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "o1offset", "Osc1 Ctl"}, - { 0, -48, 48, 48*2+1, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o1trans", "Osc1 Transpose" }, - { 6, -100, 100, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o1detune", "Osc1 Detune" }, - { 0.1, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "o1level", "Osc1 Level" }, - - { 0, 0, wavetable_metadata::wt_count - 1, 0, PF_ENUM | PF_SCALE_LINEAR | PF_CTL_COMBO, wavetable_names, "o2wave", "Osc2 Wave" }, - { 0.4, -1, 1, 0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "o2offset", "Osc2 Ctl"}, - { 0, -48, 48, 48*2+1, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o2trans", "Osc2 Transpose" }, - { -6, -100, 100, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o2detune", "Osc2 Detune" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "o2level", "Osc2 Level" }, - - { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_a", "EG1 Attack" }, - { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_d", "EG1 Decay" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_s", "EG1 Sustain" }, - { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_f", "EG1 Fade" }, - { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_r", "EG1 Release" }, - { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_v", "EG1 VelMod" }, - - { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_a", "EG2 Attack" }, - { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_d", "EG2 Decay" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_s", "EG2 Sustain" }, - { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_f", "EG2 Fade" }, - { 50, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr2_r", "EG2 Release" }, - { 1, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr2_v", "EG2 VelMod" }, - - { 1, 1,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_a", "EG3 Attack" }, - { 350, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_d", "EG3 Decay" }, - { 0.5, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr3_s", "EG3 Sustain" }, - { 0, -10000,10000, 21, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_f", "EG3 Fade" }, - { 50, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr3_r", "EG3 Release" }, - { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr3_v", "EG3 VelMod" }, - - { 200, 0, 2400, 25, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "pbend_range", "PBend Range" }, -}; - -//////////////////////////////////////////////////////////////////////////// - -calf_plugins::plugin_registry::plugin_registry() +void reverb_audio_module::set_sample_rate(uint32_t sr) { - #define PER_MODULE_ITEM(name, isSynth, jackname) plugins.push_back(new name##_metadata); - #define PER_SMALL_MODULE_ITEM(...) - #include + srate = sr; + reverb.setup(sr); + amount.set_sample_rate(sr); +} + +void reverb_audio_module::params_changed() +{ + reverb.set_type_and_diffusion(fastf2i_drm(*params[par_roomsize]), *params[par_diffusion]); + reverb.set_time(*params[par_decay]); + reverb.set_cutoff(*params[par_hfdamp]); + amount.set_inertia(*params[par_amount]); + dryamount.set_inertia(*params[par_dry]); + left_lo.set_lp(dsp::clip(*params[par_treblecut], 20.f, (float)(srate * 0.49f)), srate); + left_hi.set_hp(dsp::clip(*params[par_basscut], 20.f, (float)(srate * 0.49f)), srate); + right_lo.copy_coeffs(left_lo); + right_hi.copy_coeffs(left_hi); + predelay_amt = (int) (srate * (*params[par_predelay]) * (1.0f / 1000.0f) + 1); +} + +uint32_t reverb_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) +{ + numsamples += offset; + clip -= std::min(clip, numsamples); + for (uint32_t i = offset; i < numsamples; i++) { + float dry = dryamount.get(); + float wet = amount.get(); + stereo_sample s(ins[0][i], ins[1][i]); + stereo_sample s2 = pre_delay.process(s, predelay_amt); + + float rl = s2.left, rr = s2.right; + rl = left_lo.process(left_hi.process(rl)); + rr = right_lo.process(right_hi.process(rr)); + reverb.process(rl, rr); + outs[0][i] = dry*s.left + wet*rl; + outs[1][i] = dry*s.right + wet*rr; + meter_wet = std::max(fabs(wet*rl), fabs(wet*rr)); + meter_out = std::max(fabs(outs[0][i]), fabs(outs[1][i])); + if(outs[0][i] > 1.f or outs[1][i] > 1.f) { + clip = srate >> 3; + } + } + reverb.extra_sanitize(); + left_lo.sanitize(); + left_hi.sanitize(); + right_lo.sanitize(); + right_hi.sanitize(); + if(params[par_meter_wet] != NULL) { + *params[par_meter_wet] = meter_wet; + } + if(params[par_meter_out] != NULL) { + *params[par_meter_out] = meter_out; + } + if(params[par_clip] != NULL) { + *params[par_clip] = clip; + } + return outputs_mask; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +vintage_delay_audio_module::vintage_delay_audio_module() +{ + old_medium = -1; + for (int i = 0; i < MAX_DELAY; i++) { + buffers[0][i] = 0.f; + buffers[1][i] = 0.f; + } +} + +void vintage_delay_audio_module::params_changed() +{ + float unit = 60.0 * srate / (*params[par_bpm] * *params[par_divide]); + deltime_l = dsp::fastf2i_drm(unit * *params[par_time_l]); + deltime_r = dsp::fastf2i_drm(unit * *params[par_time_r]); + int deltime_fb = deltime_l + deltime_r; + float fb = *params[par_feedback]; + dry.set_inertia(*params[par_dryamount]); + mixmode = dsp::fastf2i_drm(*params[par_mixmode]); + medium = dsp::fastf2i_drm(*params[par_medium]); + switch(mixmode) + { + case MIXMODE_STEREO: + fb_left.set_inertia(fb); + fb_right.set_inertia(pow(fb, *params[par_time_r] / *params[par_time_l])); + amt_left.set_inertia(*params[par_amount]); + amt_right.set_inertia(*params[par_amount]); + break; + case MIXMODE_PINGPONG: + fb_left.set_inertia(fb); + fb_right.set_inertia(fb); + amt_left.set_inertia(*params[par_amount]); + amt_right.set_inertia(*params[par_amount]); + break; + case MIXMODE_LR: + fb_left.set_inertia(fb); + fb_right.set_inertia(fb); + amt_left.set_inertia(*params[par_amount]); // L is straight 'amount' + amt_right.set_inertia(*params[par_amount] * pow(fb, 1.0 * deltime_r / deltime_fb)); // R is amount with feedback based dampening as if it ran through R/FB*100% of delay line's dampening + // deltime_l <<< deltime_r -> pow() = fb -> full delay line worth of dampening + // deltime_l >>> deltime_r -> pow() = 1 -> no dampening + break; + case MIXMODE_RL: + fb_left.set_inertia(fb); + fb_right.set_inertia(fb); + amt_left.set_inertia(*params[par_amount] * pow(fb, 1.0 * deltime_l / deltime_fb)); + amt_right.set_inertia(*params[par_amount]); + break; + } + chmix.set_inertia((1 - *params[par_width]) * 0.5); + if (medium != old_medium) + calc_filters(); +} + +void vintage_delay_audio_module::activate() +{ + bufptr = 0; + age = 0; +} + +void vintage_delay_audio_module::deactivate() +{ +} + +void vintage_delay_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + old_medium = -1; + amt_left.set_sample_rate(sr); amt_right.set_sample_rate(sr); + fb_left.set_sample_rate(sr); fb_right.set_sample_rate(sr); +} + +void vintage_delay_audio_module::calc_filters() +{ + // parameters are heavily influenced by gordonjcp and his tape delay unit + // although, don't blame him if it sounds bad - I've messed with them too :) + biquad_left[0].set_lp_rbj(6000, 0.707, srate); + biquad_left[1].set_bp_rbj(4500, 0.250, srate); + biquad_right[0].copy_coeffs(biquad_left[0]); + biquad_right[1].copy_coeffs(biquad_left[1]); +} + +/// Single delay line with feedback at the same tap +static inline void delayline_impl(int age, int deltime, float dry_value, const float &delayed_value, float &out, float &del, gain_smoothing &amt, gain_smoothing &fb) +{ + // if the buffer hasn't been cleared yet (after activation), pretend we've read zeros + if (age <= deltime) { + out = 0; + amt.step(); + fb.step(); + } + else + { + float delayed = delayed_value; // avoid dereferencing the pointer in 'then' branch of the if() + dsp::sanitize(delayed); + out = delayed * amt.get(); + del = dry_value + delayed * fb.get(); + } +} + +/// Single delay line with tap output +static inline void delayline2_impl(int age, int deltime, float dry_value, const float &delayed_value, const float &delayed_value_for_fb, float &out, float &del, gain_smoothing &amt, gain_smoothing &fb) +{ + if (age <= deltime) { + out = 0; + amt.step(); + fb.step(); + } + else + { + out = delayed_value * amt.get(); + del = dry_value + delayed_value_for_fb * fb.get(); + dsp::sanitize(out); + dsp::sanitize(del); + } +} + +static inline void delay_mix(float dry_left, float dry_right, float &out_left, float &out_right, float dry, float chmix) +{ + float tmp_left = lerp(out_left, out_right, chmix); + float tmp_right = lerp(out_right, out_left, chmix); + out_left = dry_left * dry + tmp_left; + out_right = dry_right * dry + tmp_right; +} + +uint32_t vintage_delay_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) +{ + uint32_t ostate = 3; // XXXKF optimize! + uint32_t end = offset + numsamples; + int orig_bufptr = bufptr; + float out_left, out_right, del_left, del_right; + + switch(mixmode) + { + case MIXMODE_STEREO: + case MIXMODE_PINGPONG: + { + int v = mixmode == MIXMODE_PINGPONG ? 1 : 0; + for(uint32_t i = offset; i < end; i++) + { + delayline_impl(age, deltime_l, ins[0][i], buffers[v][(bufptr - deltime_l) & ADDR_MASK], out_left, del_left, amt_left, fb_left); + delayline_impl(age, deltime_r, ins[1][i], buffers[1 - v][(bufptr - deltime_r) & ADDR_MASK], out_right, del_right, amt_right, fb_right); + delay_mix(ins[0][i], ins[1][i], out_left, out_right, dry.get(), chmix.get()); + + age++; + outs[0][i] = out_left; outs[1][i] = out_right; buffers[0][bufptr] = del_left; buffers[1][bufptr] = del_right; + bufptr = (bufptr + 1) & (MAX_DELAY - 1); + } + } + break; + + case MIXMODE_LR: + case MIXMODE_RL: + { + int v = mixmode == MIXMODE_RL ? 1 : 0; + int deltime_fb = deltime_l + deltime_r; + int deltime_l_corr = mixmode == MIXMODE_RL ? deltime_fb : deltime_l; + int deltime_r_corr = mixmode == MIXMODE_LR ? deltime_fb : deltime_r; + + for(uint32_t i = offset; i < end; i++) + { + delayline2_impl(age, deltime_l, ins[0][i], buffers[v][(bufptr - deltime_l_corr) & ADDR_MASK], buffers[v][(bufptr - deltime_fb) & ADDR_MASK], out_left, del_left, amt_left, fb_left); + delayline2_impl(age, deltime_r, ins[1][i], buffers[1 - v][(bufptr - deltime_r_corr) & ADDR_MASK], buffers[1-v][(bufptr - deltime_fb) & ADDR_MASK], out_right, del_right, amt_right, fb_right); + delay_mix(ins[0][i], ins[1][i], out_left, out_right, dry.get(), chmix.get()); + + age++; + outs[0][i] = out_left; outs[1][i] = out_right; buffers[0][bufptr] = del_left; buffers[1][bufptr] = del_right; + bufptr = (bufptr + 1) & (MAX_DELAY - 1); + } + } + } + if (age >= MAX_DELAY) + age = MAX_DELAY; + if (medium > 0) { + bufptr = orig_bufptr; + if (medium == 2) + { + for(uint32_t i = offset; i < end; i++) + { + buffers[0][bufptr] = biquad_left[0].process_lp(biquad_left[1].process(buffers[0][bufptr])); + buffers[1][bufptr] = biquad_right[0].process_lp(biquad_right[1].process(buffers[1][bufptr])); + bufptr = (bufptr + 1) & (MAX_DELAY - 1); + } + biquad_left[0].sanitize();biquad_right[0].sanitize(); + } else { + for(uint32_t i = offset; i < end; i++) + { + buffers[0][bufptr] = biquad_left[1].process(buffers[0][bufptr]); + buffers[1][bufptr] = biquad_right[1].process(buffers[1][bufptr]); + bufptr = (bufptr + 1) & (MAX_DELAY - 1); + } + } + biquad_left[1].sanitize();biquad_right[1].sanitize(); + + } + return ostate; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +bool filter_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + if (!is_active) + return false; + if (index == par_cutoff && !subindex) { + context->set_line_width(1.5); + return ::get_graph(*this, subindex, data, points); + } + return false; +} + +int filter_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const +{ + if (fabs(inertia_cutoff.get_last() - old_cutoff) + 100 * fabs(inertia_resonance.get_last() - old_resonance) + fabs(*params[par_mode] - old_mode) > 0.1f) + { + old_cutoff = inertia_cutoff.get_last(); + old_resonance = inertia_resonance.get_last(); + old_mode = *params[par_mode]; + last_generation++; + subindex_graph = 0; + subindex_dot = INT_MAX; + subindex_gridline = INT_MAX; + } + else { + subindex_graph = 0; + subindex_dot = subindex_gridline = generation ? INT_MAX : 0; + } + if (generation == last_calculated_generation) + subindex_graph = INT_MAX; + return last_generation; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////// + +filterclavier_audio_module::filterclavier_audio_module() +: filter_module_with_inertia(ins, outs, params) +, min_gain(1.0) +, max_gain(32.0) +, last_note(-1) +, last_velocity(-1) +{ +} + +void filterclavier_audio_module::params_changed() +{ + inertia_filter_module::inertia_cutoff.set_inertia( + note_to_hz(last_note + *params[par_transpose], *params[par_detune])); + + float min_resonance = param_props[par_max_resonance].min; + inertia_filter_module::inertia_resonance.set_inertia( + (float(last_velocity) / 127.0) + // 0.001: see below + * (*params[par_max_resonance] - min_resonance + 0.001) + + min_resonance); + + adjust_gain_according_to_filter_mode(last_velocity); + + inertia_filter_module::calculate_filter(); +} + +void filterclavier_audio_module::activate() +{ + inertia_filter_module::activate(); +} + +void filterclavier_audio_module::set_sample_rate(uint32_t sr) +{ + inertia_filter_module::set_sample_rate(sr); +} + +void filterclavier_audio_module::deactivate() +{ + inertia_filter_module::deactivate(); +} + + +void filterclavier_audio_module::note_on(int note, int vel) +{ + last_note = note; + last_velocity = vel; + inertia_filter_module::inertia_cutoff.set_inertia( + note_to_hz(note + *params[par_transpose], *params[par_detune])); + + float min_resonance = param_props[par_max_resonance].min; + inertia_filter_module::inertia_resonance.set_inertia( + (float(vel) / 127.0) + // 0.001: if the difference is equal to zero (which happens + // when the max_resonance knom is at minimum position + // then the filter gain doesnt seem to snap to zero on most note offs + * (*params[par_max_resonance] - min_resonance + 0.001) + + min_resonance); + + adjust_gain_according_to_filter_mode(vel); + + inertia_filter_module::calculate_filter(); +} + +void filterclavier_audio_module::note_off(int note, int vel) +{ + if (note == last_note) { + inertia_filter_module::inertia_resonance.set_inertia(param_props[par_max_resonance].min); + inertia_filter_module::inertia_gain.set_inertia(min_gain); + inertia_filter_module::calculate_filter(); + last_velocity = 0; + } +} + +void filterclavier_audio_module::adjust_gain_according_to_filter_mode(int velocity) +{ + int mode = dsp::fastf2i_drm(*params[par_mode]); + + // for bandpasses: boost gain for velocities > 0 + if ( (mode_6db_bp <= mode) && (mode <= mode_18db_bp) ) { + // gain for velocity 0: 1.0 + // gain for velocity 127: 32.0 + float mode_max_gain = max_gain; + // max_gain is right for mode_6db_bp + if (mode == mode_12db_bp) + mode_max_gain /= 6.0; + if (mode == mode_18db_bp) + mode_max_gain /= 10.5; + + inertia_filter_module::inertia_gain.set_now( + (float(velocity) / 127.0) * (mode_max_gain - min_gain) + min_gain); + } else { + inertia_filter_module::inertia_gain.set_now(min_gain); + } +} + +bool filterclavier_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + if (!is_active || index != par_mode) { + return false; + } + if (!subindex) { + context->set_line_width(1.5); + return ::get_graph(*this, subindex, data, points); + } + return false; } diff --git a/plugins/ladspa_effect/calf/src/modules_dsp.cpp b/plugins/ladspa_effect/calf/src/modules_comp.cpp similarity index 59% rename from plugins/ladspa_effect/calf/src/modules_dsp.cpp rename to plugins/ladspa_effect/calf/src/modules_comp.cpp index 66eba417d..a5d58e2e5 100644 --- a/plugins/ladspa_effect/calf/src/modules_dsp.cpp +++ b/plugins/ladspa_effect/calf/src/modules_comp.cpp @@ -1,7 +1,7 @@ -/* Calf DSP Library - * Example audio modules - DSP code +/* Calf DSP plugin pack + * Compression related plugins * - * Copyright (C) 2001-2008 Krzysztof Foltman + * 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 @@ -18,334 +18,16 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#include #include #include -#if USE_JACK -#include -#endif #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; -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool frequency_response_line_graph::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const -{ - return get_freq_gridline(subindex, pos, vertical, legend, context); -} - -int frequency_response_line_graph::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const -{ - subindex_graph = 0; - subindex_dot = 0; - subindex_gridline = generation ? INT_MAX : 0; - return 1; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void flanger_audio_module::activate() { - left.reset(); - right.reset(); - last_r_phase = *params[par_stereo] * (1.f / 360.f); - left.reset_phase(0.f); - right.reset_phase(last_r_phase); - is_active = true; -} - -void flanger_audio_module::set_sample_rate(uint32_t sr) { - srate = sr; - left.setup(sr); - right.setup(sr); -} - -void flanger_audio_module::deactivate() { - is_active = false; -} - -bool flanger_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const -{ - if (!is_active) - return false; - if (index == par_delay && subindex < 2) - { - set_channel_color(context, subindex); - return ::get_graph(*this, subindex, data, points); - } - return false; -} - -float flanger_audio_module::freq_gain(int subindex, float freq, float srate) const -{ - return (subindex ? right : left).freq_gain(freq, srate); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -void phaser_audio_module::set_sample_rate(uint32_t sr) -{ - srate = sr; - left.setup(sr); - right.setup(sr); -} - -void phaser_audio_module::activate() -{ - is_active = true; - left.reset(); - right.reset(); - last_r_phase = *params[par_stereo] * (1.f / 360.f); - left.reset_phase(0.f); - right.reset_phase(last_r_phase); -} - -void phaser_audio_module::deactivate() -{ - is_active = false; -} - -bool phaser_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const -{ - if (!is_active) - return false; - if (subindex < 2) - { - set_channel_color(context, subindex); - return ::get_graph(*this, subindex, data, points); - } - return false; -} - -float phaser_audio_module::freq_gain(int subindex, float freq, float srate) const -{ - return (subindex ? right : left).freq_gain(freq, srate); -} - -bool phaser_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const -{ - return get_freq_gridline(subindex, pos, vertical, legend, context); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -void reverb_audio_module::activate() -{ - reverb.reset(); -} - -void reverb_audio_module::deactivate() -{ -} - -void reverb_audio_module::set_sample_rate(uint32_t sr) -{ - srate = sr; - reverb.setup(sr); - amount.set_sample_rate(sr); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -bool filter_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const -{ - if (!is_active) - return false; - if (index == par_cutoff && !subindex) { - context->set_line_width(1.5); - return ::get_graph(*this, subindex, data, points); - } - return false; -} - -int filter_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const -{ - if (fabs(inertia_cutoff.get_last() - old_cutoff) + 100 * fabs(inertia_resonance.get_last() - old_resonance) + fabs(*params[par_mode] - old_mode) > 0.1f) - { - old_cutoff = inertia_cutoff.get_last(); - old_resonance = inertia_resonance.get_last(); - old_mode = *params[par_mode]; - last_generation++; - subindex_graph = 0; - subindex_dot = INT_MAX; - subindex_gridline = INT_MAX; - } - else { - subindex_graph = 0; - subindex_dot = subindex_gridline = generation ? INT_MAX : 0; - } - if (generation == last_calculated_generation) - subindex_graph = INT_MAX; - return last_generation; -} - - -/////////////////////////////////////////////////////////////////////////////////////////////// - -bool filterclavier_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const -{ - if (!is_active || index != par_mode) { - return false; - } - if (!subindex) { - context->set_line_width(1.5); - return ::get_graph(*this, subindex, data, points); - } - return false; -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -rotary_speaker_audio_module::rotary_speaker_audio_module() -{ - mwhl_value = hold_value = 0.f; - phase_h = phase_l = 0.f; - aspeed_l = 1.f; - aspeed_h = 1.f; - dspeed = 0.f; -} - -void rotary_speaker_audio_module::set_sample_rate(uint32_t sr) -{ - srate = sr; - setup(); -} - -void rotary_speaker_audio_module::setup() -{ - crossover1l.set_lp_rbj(800.f, 0.7, (float)srate); - crossover1r.set_lp_rbj(800.f, 0.7, (float)srate); - crossover2l.set_hp_rbj(800.f, 0.7, (float)srate); - crossover2r.set_hp_rbj(800.f, 0.7, (float)srate); -} - -void rotary_speaker_audio_module::activate() -{ - phase_h = phase_l = 0.f; - maspeed_h = maspeed_l = 0.f; - setup(); -} - -void rotary_speaker_audio_module::deactivate() -{ -} - -void rotary_speaker_audio_module::control_change(int ctl, int val) -{ - if (vibrato_mode == 3 && ctl == 64) - { - hold_value = val / 127.f; - set_vibrato(); - return; - } - if (vibrato_mode == 4 && ctl == 1) - { - mwhl_value = val / 127.f; - set_vibrato(); - return; - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -void multichorus_audio_module::activate() -{ - is_active = true; - params_changed(); -} - -void multichorus_audio_module::deactivate() -{ - is_active = false; -} - -void multichorus_audio_module::set_sample_rate(uint32_t sr) { - srate = sr; - left.setup(sr); - right.setup(sr); -} - -bool multichorus_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const -{ - if (!is_active) - return false; - int nvoices = (int)*params[par_voices]; - if (index == par_delay && subindex < 3) - { - if (subindex < 2) - set_channel_color(context, subindex); - else { - context->set_source_rgba(0.35, 0.4, 0.2); - context->set_line_width(1.0); - } - return ::get_graph(*this, subindex, data, points); - } - if (index == par_rate && subindex < nvoices) { - const sine_multi_lfo &lfo = left.lfo; - for (int i = 0; i < points; i++) { - float phase = i * 2 * M_PI / points; - // original -65536 to 65535 value - float orig = subindex * lfo.voice_offset + ((lfo.voice_depth >> (30-13)) * 65536.0 * (0.95 * sin(phase) + 1)/ 8192.0) - 65536; - // scale to -1..1 - data[i] = orig / 65536.0; - } - return true; - } - return false; -} - -bool multichorus_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const -{ - int voice = subindex >> 1; - int nvoices = (int)*params[par_voices]; - if ((index != par_rate && index != par_depth) || voice >= nvoices) - return false; - - float unit = (1 - *params[par_overlap]); - float scw = 1 + unit * (nvoices - 1); - set_channel_color(context, subindex); - const sine_multi_lfo &lfo = (subindex & 1 ? right : left).lfo; - if (index == par_rate) - { - x = (double)(lfo.phase + lfo.vphase * voice) / 4096.0; - y = 0.95 * sin(x * 2 * M_PI); - y = (voice * unit + (y + 1) / 2) / scw * 2 - 1; - } - else - { - double ph = (double)(lfo.phase + lfo.vphase * voice) / 4096.0; - x = 0.5 + 0.5 * sin(ph * 2 * M_PI); - y = subindex & 1 ? -0.75 : 0.75; - x = (voice * unit + x) / scw; - } - return true; -} - -bool multichorus_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const -{ - if (index == par_rate && !subindex) - { - pos = 0; - vertical = false; - return true; - } - if (index == par_delay) - return get_freq_gridline(subindex, pos, vertical, legend, context); - return false; -} - -float multichorus_audio_module::freq_gain(int subindex, float freq, float srate) const -{ - if (subindex == 2) - return *params[par_amount] * left.post.freq_gain(freq, srate); - return (subindex ? right : left).freq_gain(freq, srate); -} - /// Multibandcompressor by Markus Schmidt /// /// This module splits the signal in four different bands @@ -733,6 +415,8 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, clip_in -= std::min(clip_in, numsamples); clip_out -= std::min(clip_out, numsamples); + compressor.update_curve(); + while(offset < numsamples) { // cycle through samples float outL = 0.f; @@ -745,10 +429,8 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, float leftAC = inL; float rightAC = inR; - float leftSC = inL; - float rightSC = inR; - compressor.process(leftAC, rightAC, leftSC, rightSC); + compressor.process(leftAC, rightAC); outL = leftAC; outR = rightAC; @@ -773,18 +455,10 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, } // cycle trough samples } // draw meters - if(params[param_clip_in] != NULL) { - *params[param_clip_in] = clip_in; - } - if(params[param_clip_out] != NULL) { - *params[param_clip_out] = clip_out; - } - if(params[param_meter_in] != NULL) { - *params[param_meter_in] = meter_in; - } - if(params[param_meter_out] != NULL) { - *params[param_meter_out] = meter_out; - } + SET_IF_CONNECTED(clip_in) + SET_IF_CONNECTED(clip_out) + SET_IF_CONNECTED(meter_in) + SET_IF_CONNECTED(meter_out) // draw strip meter if(bypass > 0.5f) { if(params[param_compression] != NULL) { @@ -857,6 +531,40 @@ void sidechaincompressor_audio_module::deactivate() compressor.deactivate(); } +sidechaincompressor_audio_module::cfloat sidechaincompressor_audio_module::h_z(const cfloat &z) const +{ + switch (sc_mode) { + default: + case WIDEBAND: + return false; + break; + case DEESSER_WIDE: + case DERUMBLER_WIDE: + case WEIGHTED_1: + case WEIGHTED_2: + case WEIGHTED_3: + case BANDPASS_2: + return f1L.h_z(z) * f2L.h_z(z); + break; + case DEESSER_SPLIT: + return f2L.h_z(z); + break; + case DERUMBLER_SPLIT: + case BANDPASS_1: + return f1L.h_z(z); + break; + } +} + +float sidechaincompressor_audio_module::freq_gain(int index, double freq, uint32_t sr) const +{ + typedef std::complex cfloat; + freq *= 2.0 * M_PI / sr; + cfloat z = 1.0 / exp(cfloat(0.0, freq)); + + return std::abs(h_z(z)); +} + void sidechaincompressor_audio_module::params_changed() { // set the params of all filters @@ -991,6 +699,7 @@ uint32_t sidechaincompressor_audio_module::process(uint32_t offset, uint32_t num clip_in -= std::min(clip_in, numsamples); clip_out -= std::min(clip_out, numsamples); + compressor.update_curve(); while(offset < numsamples) { // cycle through samples @@ -1013,7 +722,7 @@ uint32_t sidechaincompressor_audio_module::process(uint32_t offset, uint32_t num switch ((int)*params[param_sc_mode]) { default: case WIDEBAND: - compressor.process(leftAC, rightAC, leftSC, rightSC); + compressor.process(leftAC, rightAC); break; case DEESSER_WIDE: case DERUMBLER_WIDE: @@ -1025,14 +734,14 @@ uint32_t sidechaincompressor_audio_module::process(uint32_t offset, uint32_t num rightSC = f2R.process(f1R.process(rightSC)); leftMC = leftSC; rightMC = rightSC; - compressor.process(leftAC, rightAC, leftSC, rightSC); + compressor.process(leftAC, rightAC, &leftSC, &rightSC); break; case DEESSER_SPLIT: leftSC = f2L.process(leftSC); rightSC = f2R.process(rightSC); leftMC = leftSC; rightMC = rightSC; - compressor.process(leftSC, rightSC, leftSC, rightSC); + compressor.process(leftSC, rightSC, &leftSC, &rightSC); leftAC = f1L.process(leftAC); rightAC = f1R.process(rightAC); leftAC += leftSC; @@ -1043,7 +752,7 @@ uint32_t sidechaincompressor_audio_module::process(uint32_t offset, uint32_t num rightSC = f1R.process(rightSC); leftMC = leftSC; rightMC = rightSC; - compressor.process(leftSC, rightSC, leftSC, rightSC); + compressor.process(leftSC, rightSC); leftAC = f2L.process(leftAC); rightAC = f2R.process(rightAC); leftAC += leftSC; @@ -1054,7 +763,7 @@ uint32_t sidechaincompressor_audio_module::process(uint32_t offset, uint32_t num rightSC = f1R.process(rightSC); leftMC = leftSC; rightMC = rightSC; - compressor.process(leftAC, rightAC, leftSC, rightSC); + compressor.process(leftAC, rightAC, &leftSC, &rightSC); break; } @@ -1091,18 +800,10 @@ uint32_t sidechaincompressor_audio_module::process(uint32_t offset, uint32_t num } // draw meters - if(params[param_clip_in] != NULL) { - *params[param_clip_in] = clip_in; - } - if(params[param_clip_out] != NULL) { - *params[param_clip_out] = clip_out; - } - if(params[param_meter_in] != NULL) { - *params[param_meter_in] = meter_in; - } - if(params[param_meter_out] != NULL) { - *params[param_meter_out] = meter_out; - } + SET_IF_CONNECTED(clip_in) + SET_IF_CONNECTED(clip_out) + SET_IF_CONNECTED(meter_in) + SET_IF_CONNECTED(meter_out) // draw strip meter if(bypass > 0.5f) { if(params[param_compression] != NULL) { @@ -1266,6 +967,7 @@ uint32_t deesser_audio_module::process(uint32_t offset, uint32_t numsamples, uin detected_led -= std::min(detected_led, numsamples); clip_led -= std::min(clip_led, numsamples); + compressor.update_curve(); while(offset < numsamples) { // cycle through samples @@ -1292,14 +994,14 @@ uint32_t deesser_audio_module::process(uint32_t offset, uint32_t numsamples, uin switch ((int)*params[param_mode]) { default: case WIDE: - compressor.process(leftAC, rightAC, leftSC, rightSC); + compressor.process(leftAC, rightAC, &leftSC, &rightSC); break; case SPLIT: hpL.sanitize(); hpR.sanitize(); leftRC = hpL.process(leftRC); rightRC = hpR.process(rightRC); - compressor.process(leftRC, rightRC, leftSC, rightSC); + compressor.process(leftRC, rightRC, &leftSC, &rightSC); leftAC = lpL.process(leftAC); rightAC = lpR.process(rightAC); leftAC += leftRC; @@ -1460,13 +1162,13 @@ void gain_reduction_audio_module::update_curve() compressedKneeStop = (kneeStop - thres) / ratio + thres; } -void gain_reduction_audio_module::process(float &left, float &right, float det_left, float det_right) +void gain_reduction_audio_module::process(float &left, float &right, const float *det_left, const float *det_right) { if(!det_left) { - det_left = left; + det_left = &left; } if(!det_right) { - det_right = right; + det_right = &right; } float gain = 1.f; if(bypass < 0.5f) { @@ -1476,9 +1178,8 @@ void gain_reduction_audio_module::process(float &left, float &right, float det_l 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)); - update_curve(); - float absample = average ? (fabs(det_left) + fabs(det_right)) * 0.5f : std::max(fabs(det_left), fabs(det_right)); + float absample = average ? (fabs(*det_left) + fabs(*det_right)) * 0.5f : std::max(fabs(*det_left), fabs(*det_right)); if(rms) absample *= absample; linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff); @@ -1642,701 +1343,250 @@ int gain_reduction_audio_module::get_changed_offsets(int generation, int &subind return last_generation; } -/// Equalizer 12 Band by Markus Schmidt -/// -/// This module is based on Krzysztof's filters. It provides a couple -/// of different chained filters. + + /////////////////////////////////////////////////////////////////////////////////////////////// -template -equalizerNband_audio_module::equalizerNband_audio_module() +gate_audio_module::gate_audio_module() { is_active = false; srate = 0; last_generation = 0; - clip_inL = clip_inR = clip_outL = clip_outR = 0.f; - meter_inL = meter_inR = meter_outL = meter_outR = 0.f; } -template -void equalizerNband_audio_module::activate() +void gate_audio_module::activate() { is_active = true; - // set all filters - params_changed(); + linSlope = 0.f; + peak = 0.f; + clip = 0.f; } -template -void equalizerNband_audio_module::deactivate() +void gate_audio_module::deactivate() { is_active = false; } -static inline void copy_lphp(biquad_d2 filters[3][2]) +void gate_audio_module::set_sample_rate(uint32_t sr) { - for (int i = 0; i < 3; i++) - for (int j = 0; j < 2; j++) - if (i || j) - filters[i][j].copy_coeffs(filters[0][0]); + srate = sr; + awL.set(sr); + awR.set(sr); } -template -void equalizerNband_audio_module::params_changed() -{ - // set the params of all filters - - // lp/hp first (if available) - if (has_lphp) - { - hp_mode = (CalfEqMode)(int)*params[AM::param_hp_mode]; - lp_mode = (CalfEqMode)(int)*params[AM::param_lp_mode]; - - float hpfreq = *params[AM::param_hp_freq], lpfreq = *params[AM::param_lp_freq]; - - if(hpfreq != hp_freq_old) { - hp[0][0].set_hp_rbj(hpfreq, 0.707, (float)srate, 1.0); - copy_lphp(hp); - hp_freq_old = hpfreq; - } - if(lpfreq != lp_freq_old) { - lp[0][0].set_lp_rbj(lpfreq, 0.707, (float)srate, 1.0); - copy_lphp(lp); - lp_freq_old = lpfreq; - } - } - - // then shelves - float hsfreq = *params[AM::param_hs_freq], hslevel = *params[AM::param_hs_level]; - float lsfreq = *params[AM::param_ls_freq], lslevel = *params[AM::param_ls_level]; - - if(lsfreq != ls_freq_old or lslevel != ls_level_old) { - lsL.set_lowshelf_rbj(lsfreq, 0.707, lslevel, (float)srate); - lsR.copy_coeffs(lsL); - ls_level_old = lslevel; - ls_freq_old = lsfreq; - } - if(hsfreq != hs_freq_old or hslevel != hs_level_old) { - hsL.set_highshelf_rbj(hsfreq, 0.707, hslevel, (float)srate); - hsR.copy_coeffs(hsL); - hs_level_old = hslevel; - hs_freq_old = hsfreq; - } - for (int i = 0; i < AM::PeakBands; i++) - { - int offset = i * params_per_band; - float freq = *params[AM::param_p1_freq + offset]; - float level = *params[AM::param_p1_level + offset]; - float q = *params[AM::param_p1_q + offset]; - if(freq != p_freq_old[i] or level != p_level_old[i] or q != p_q_old[i]) { - pL[i].set_peakeq_rbj(freq, q, level, (float)srate); - pR[i].copy_coeffs(pL[i]); - p_freq_old[i] = freq; - p_level_old[i] = level; - p_q_old[i] = q; - } - } -} - -template -inline void equalizerNband_audio_module::process_hplp(float &left, float &right) -{ - if (!has_lphp) - return; - if (*params[AM::param_lp_active] > 0.f) - { - switch(lp_mode) - { - case MODE12DB: - left = lp[0][0].process(left); - right = lp[0][1].process(right); - break; - case MODE24DB: - left = lp[1][0].process(lp[0][0].process(left)); - right = lp[1][1].process(lp[0][1].process(right)); - break; - case MODE36DB: - left = lp[2][0].process(lp[1][0].process(lp[0][0].process(left))); - right = lp[2][1].process(lp[1][1].process(lp[0][1].process(right))); - break; - } - } - if (*params[AM::param_hp_active] > 0.f) - { - switch(hp_mode) - { - case MODE12DB: - left = hp[0][0].process(left); - right = hp[0][1].process(right); - break; - case MODE24DB: - left = hp[1][0].process(hp[0][0].process(left)); - right = hp[1][1].process(hp[0][1].process(right)); - break; - case MODE36DB: - left = hp[2][0].process(hp[1][0].process(hp[0][0].process(left))); - right = hp[2][1].process(hp[1][1].process(hp[0][1].process(right))); - break; - } - } -} - -template -uint32_t equalizerNband_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) -{ - bool bypass = *params[AM::param_bypass] > 0.f; - 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 = clip_inR = clip_outL = clip_outR = 0.f; - meter_inL = meter_inR = meter_outL = meter_outR = 0.f; - } else { - - 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; - - // process - while(offset < numsamples) { - // cycle through samples - float outL = 0.f; - float outR = 0.f; - float inL = ins[0][offset]; - float inR = ins[1][offset]; - // in level - inR *= *params[AM::param_level_in]; - inL *= *params[AM::param_level_in]; - - float procL = inL; - float procR = inR; - - // all filters in chain - process_hplp(procL, procR); - if(*params[AM::param_ls_active] > 0.f) { - procL = lsL.process(procL); - procR = lsR.process(procR); - } - if(*params[AM::param_hs_active] > 0.f) { - procL = hsL.process(procL); - procR = hsR.process(procR); - } - for (int i = 0; i < AM::PeakBands; i++) - { - if(*params[AM::param_p1_active + i * params_per_band] > 0.f) { - procL = pL[i].process(procL); - procR = pR[i].process(procR); - } - } - - outL = procL * *params[AM::param_level_out]; - outR = procR * *params[AM::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 - // clean up - for(int i = 0; i < 3; ++i) { - hp[i][0].sanitize(); - hp[i][1].sanitize(); - lp[i][0].sanitize(); - lp[i][1].sanitize(); - } - lsL.sanitize(); - hsR.sanitize(); - for(int i = 0; i < AM::PeakBands; ++i) { - pL[i].sanitize(); - pR[i].sanitize(); - } - } - // 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) - // whatever has to be returned x) - return outputs_mask; -} - -#undef SET_IF_CONNECTED - -template -bool equalizerNband_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +bool gate_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const { if (!is_active) return false; - if (index == AM::param_p1_freq && !subindex) { + if (subindex > 1) // 1 + return false; + for (int i = 0; i < points; i++) + { + float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1)); + float output = output_level(input); + if (subindex == 0) + data[i] = dB_grid(input); + else + data[i] = dB_grid(output); + } + if (subindex == (*params[param_bypass] > 0.f ? 1 : 0)) + context->set_source_rgba(0.35, 0.4, 0.2, 0.3); + else { + context->set_source_rgba(0.35, 0.4, 0.2, 1); context->set_line_width(1.5); - return ::get_graph(*this, subindex, data, points); + } + return true; +} + +bool gate_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const +{ + if (!is_active) + return false; + if (!subindex) + { + bool rms = *params[param_detection] == 0; + float det = rms ? sqrt(detected) : detected; + x = 0.5 + 0.5 * dB_grid(det); + y = dB_grid(*params[param_bypass] > 0.f ? det : output_level(det)); + return *params[param_bypass] > 0.f ? false : true; } return false; } -template -bool equalizerNband_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const +bool gate_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 { - return get_freq_gridline(subindex, pos, vertical, legend, context); - } -} - -template -int equalizerNband_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const -{ - if (!is_active) { - return false; - } else { - bool changed = false; - for (int i = 0; i < graph_param_count && !changed; i++) - { - if (*params[AM::first_graph_param + i] != old_params_for_graph[i]) - changed = true; - } - if (changed) - { - for (int i = 0; i < graph_param_count; i++) - old_params_for_graph[i] = *params[AM::first_graph_param + i]; - - last_generation++; - subindex_graph = 0; - subindex_dot = INT_MAX; - subindex_gridline = INT_MAX; + bool tmp; + vertical = (subindex & 1) != 0; + bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false); + if (result && vertical) { + if ((subindex & 4) && !legend.empty()) { + legend = ""; } else { - subindex_graph = 0; - subindex_dot = subindex_gridline = generation ? INT_MAX : 0; + size_t pos = legend.find(" dB"); + if (pos != std::string::npos) + legend.erase(pos); } - if (generation == last_calculated_generation) - subindex_graph = INT_MAX; - return last_generation; + pos = 0.5 + 0.5 * pos; } - return false; + return result; } -static inline float adjusted_lphp_gain(const float *const *params, int param_active, int param_mode, const biquad_d2 &filter, float freq, float srate) +uint32_t gate_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) { - if(*params[param_active] > 0.f) { - float gain = filter.freq_gain(freq, srate); - switch((int)*params[param_mode]) { - case MODE12DB: - return gain; - case MODE24DB: - return gain * gain; - case MODE36DB: - return gain * gain * gain; - } - } - return 1; -} + bool bypass = *params[param_bypass] > 0.f; -template -float equalizerNband_audio_module::freq_gain(int index, double freq, uint32_t sr) const -{ - float ret = 1.f; - if (use_hplp) - { - ret *= adjusted_lphp_gain(params, AM::param_hp_active, AM::param_hp_mode, hp[0][0], freq, (float)sr); - ret *= adjusted_lphp_gain(params, AM::param_lp_active, AM::param_lp_mode, lp[0][0], freq, (float)sr); - } - ret *= (*params[AM::param_ls_active] > 0.f) ? lsL.freq_gain(freq, sr) : 1; - ret *= (*params[AM::param_hs_active] > 0.f) ? hsL.freq_gain(freq, sr) : 1; - for (int i = 0; i < PeakBands; i++) - ret *= (*params[AM::param_p1_active + i * params_per_band] > 0.f) ? pL[i].freq_gain(freq, (float)sr) : 1; - return ret; -} - -template class equalizerNband_audio_module; -template class equalizerNband_audio_module; -template class equalizerNband_audio_module; - -/// LFO module by Markus -/// This module provides simple LFO's (sine=0, triangle=1, square=2, saw_up=3, saw_down=4) -/// get_value() returns a value between -1 and 1 -//////////////////////////////////////////////////////////////////////////////// -lfo_audio_module::lfo_audio_module() -{ - is_active = false; - phase = 0.f; -} - -void lfo_audio_module::activate() -{ - is_active = true; - phase = 0.f; -} - -void lfo_audio_module::deactivate() -{ - is_active = false; -} - -float lfo_audio_module::get_value() -{ - return get_value_from_phase(phase, offset) * amount; -} - -float lfo_audio_module::get_value_from_phase(float ph, float off) const -{ - float val = 0.f; - float phs = ph + off; - if (phs >= 1.0) - phs = fmod(phs, 1.f); - switch (mode) { - default: - case 0: - // sine - val = sin((phs * 360.f) * M_PI / 180); - break; - case 1: - // triangle - if(phs > 0.75) - val = (phs - 0.75) * 4 - 1; - else if(phs > 0.5) - val = (phs - 0.5) * 4 * -1; - else if(phs > 0.25) - val = 1 - (phs - 0.25) * 4; - else - val = phs * 4; - break; - case 2: - // square - val = (phs < 0.5) ? -1 : +1; - break; - case 3: - // saw up - val = phs * 2.f - 1; - break; - case 4: - // saw down - val = 1 - phs * 2.f; - break; - } - return val; -} - -void lfo_audio_module::advance(uint32_t count) -{ - //this function walks from 0.f to 1.f and starts all over again - phase += count * freq * (1.0 / srate); - if (phase >= 1.0) - phase = fmod(phase, 1.f); -} - -void lfo_audio_module::set_phase(float ph) -{ - //set the phase from outsinde - phase = fabs(ph); - if (phase >= 1.0) - phase = fmod(phase, 1.f); -} - -void lfo_audio_module::set_params(float f, int m, float o, uint32_t sr, float a) -{ - // freq: a value in Hz - // mode: sine=0, triangle=1, square=2, saw_up=3, saw_down=4 - // offset: value between 0.f and 1.f to offset the lfo in time - freq = f; - mode = m; - offset = o; - srate = sr; - amount = a; -} - -bool lfo_audio_module::get_graph(float *data, int points, cairo_iface *context) const -{ - if (!is_active) - return false; - for (int i = 0; i < points; i++) { - float ph = (float)i / (float)points; - data[i] = get_value_from_phase(ph, offset) * amount; - } - return true; -} - -bool lfo_audio_module::get_dot(float &x, float &y, int &size, cairo_iface *context) const -{ - if (!is_active) - return false; - float phs = phase + offset; - if (phs >= 1.0) - phs = fmod(phs, 1.f); - x = phase; - y = get_value_from_phase(phase, offset) * amount; - return true; -} - -/// Pulsator by Markus Schmidt -/// -/// This module provides a couple -/// of different LFO's for modulating the level of a signal. -/////////////////////////////////////////////////////////////////////////////////////////////// - -pulsator_audio_module::pulsator_audio_module() -{ - is_active = false; - srate = 0; -// last_generation = 0; - 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 pulsator_audio_module::activate() -{ - is_active = true; - lfoL.activate(); - lfoR.activate(); - params_changed(); -} -void pulsator_audio_module::deactivate() -{ - is_active = false; - lfoL.deactivate(); - lfoR.deactivate(); -} - -void pulsator_audio_module::params_changed() -{ - lfoL.set_params(*params[param_freq], *params[param_mode], 0.f, srate, *params[param_amount]); - lfoR.set_params(*params[param_freq], *params[param_mode], *params[param_offset], srate, *params[param_amount]); - clear_reset = false; - if (*params[param_reset] >= 0.5) { - clear_reset = true; - lfoL.set_phase(0.f); - lfoR.set_phase(0.f); - } -} - -void pulsator_audio_module::set_sample_rate(uint32_t sr) -{ - srate = sr; -} - -uint32_t pulsator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) -{ - bool bypass = *params[param_bypass] > 0.5f; - uint32_t samples = numsamples + offset; if(bypass) { - // everything bypassed - while(offset < samples) { - 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; - - // LFO's should go on - lfoL.advance(numsamples); - lfoR.advance(numsamples); - - } else { - - 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; - - // process - while(offset < samples) { - // cycle through samples - float outL = 0.f; - float outR = 0.f; - float inL = ins[0][offset]; - float inR = ins[1][offset]; - // in level - inR *= *params[param_level_in]; - inL *= *params[param_level_in]; - - if(*params[param_mono] > 0.5) { - inL = (inL + inR) * 0.5; - inR = inL; - } - float procL = inL; - float procR = inR; - - procL *= (lfoL.get_value() * 0.5 + *params[param_amount] / 2); - procR *= (lfoR.get_value() * 0.5 + *params[param_amount] / 2); - - outL = procL + inL * (1 - *params[param_amount]); - outR = procR + inR * (1 - *params[param_amount]); - - 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; - - // advance lfo's - lfoL.advance(1); - lfoR.advance(1); - } // cycle trough samples - } - // draw meters - if(params[param_clip_inL] != NULL) { - *params[param_clip_inL] = clip_inL; - } - if(params[param_clip_inR] != NULL) { - *params[param_clip_inR] = clip_inR; - } - if(params[param_clip_outL] != NULL) { - *params[param_clip_outL] = clip_outL; - } - if(params[param_clip_outR] != NULL) { - *params[param_clip_outR] = clip_outR; - } - - if(params[param_meter_inL] != NULL) { - *params[param_meter_inL] = meter_inL; - } - if(params[param_meter_inR] != NULL) { - *params[param_meter_inR] = meter_inR; - } - if(params[param_meter_outL] != NULL) { - *params[param_meter_outL] = meter_outL; - } - if(params[param_meter_outR] != NULL) { - *params[param_meter_outR] = meter_outR; - } - // whatever has to be returned x) - return outputs_mask; -} + int count = numsamples * sizeof(float); + memcpy(outs[0], ins[0], count); + memcpy(outs[1], ins[1], count); -bool pulsator_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const -{ - if (!is_active) { - return false; - } else if(index == param_freq) { - if(subindex == 0) { - context->set_source_rgba(0.35, 0.4, 0.2, 1); - return lfoL.get_graph(data, points, context); + if(params[param_gating] != NULL) { + *params[param_gating] = 1.f; } - if(subindex == 1) { - context->set_source_rgba(0.35, 0.4, 0.2, 0.5); - return lfoR.get_graph(data, points, context); - } - } - return false; -} -bool pulsator_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const -{ - if (!is_active) { - return false; - } else if(index == param_freq) { - if(subindex == 0) { - context->set_source_rgba(0.35, 0.4, 0.2, 1); - return lfoL.get_dot(x, y, size, context); + if(params[param_clip] != NULL) { + *params[param_clip] = 0.f; } - if(subindex == 1) { - context->set_source_rgba(0.35, 0.4, 0.2, 0.5); - return lfoR.get_dot(x, y, size, context); - } - return false; - } - return false; -} -bool pulsator_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const -{ - if (index == param_freq && !subindex) + if(params[param_peak] != NULL) { + *params[param_peak] = 0.f; + } + + return inputs_mask; + } + + bool rms = *params[param_detection] == 0; + bool average = *params[param_stereo_link] == 0; + int aweighting = fastf2i_drm(*params[param_aweighting]); + float linThreshold = *params[param_threshold]; + if (rms) + linThreshold = linThreshold * linThreshold; + ratio = *params[param_ratio]; + float attack = *params[param_attack]; + float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f)); + float release = *params[param_release]; + float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f)); + makeup = *params[param_makeup]; + knee = *params[param_knee]; + + range = *params[param_range]; + + float linKneeSqrt = sqrt(knee); + linKneeStart = linThreshold / linKneeSqrt; + adjKneeStart = linKneeStart*linKneeStart; + linKneeStop = linThreshold * linKneeSqrt; + + threshold = log(linThreshold); + kneeStart = log(linKneeStart); + kneeStop = log(linKneeStop); + compressedKneeStop = (kneeStop - threshold) / ratio + threshold; + + if (aweighting >= 2) { - pos = 0; - vertical = false; - return true; + bpL.set_highshelf_rbj(5000, 0.707, 10 << (aweighting - 2), srate); + bpR.copy_coeffs(bpL); + bpL.sanitize(); + bpR.sanitize(); } - return false; + + numsamples += offset; + + float gating = 1.f; + + peak -= peak * 5.f * numsamples / srate; + + clip -= std::min(clip, numsamples); + float left; + float right; + + while(offset < numsamples) { + if(*params[param_trigger]) { + left = ins[2][offset]; // Use sidechain to trigger input + right = left; // (mono sidechain) + } else { + left = ins[0][offset]; + right = ins[1][offset]; + } + + if(aweighting == 1) { + left = awL.process(left); + right = awR.process(right); + } + else if(aweighting >= 2) { + left = bpL.process(left); + right = bpR.process(right); + } + + float absample = average ? (fabs(left) + fabs(right)) * 0.5f : std::max(fabs(left), fabs(right)); + if(rms) absample *= absample; + + linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff); + + float gain = 1.f; + + if(linSlope > 0.f) { + gain = output_gain(linSlope, rms); + } + + gating = gain; + gain *= makeup; + + float outL = ins[0][offset] * gain; + float outR = ins[1][offset] * gain; + + outs[0][offset] = outL; + outs[1][offset] = outR; + + ++offset; + + float maxLR = std::max(fabs(outL), fabs(outR)); + + if(maxLR > 1.f) clip = srate >> 3; /* blink clip LED for 125 ms */ + + if(maxLR > peak) { + peak = maxLR; + } + } + + detected = linSlope; + + if(params[param_gating] != NULL) { + *params[param_gating] = gating; + } + + if(params[param_clip] != NULL) { + *params[param_clip] = clip; + } + + if(params[param_peak] != NULL) { + *params[param_peak] = peak; + } + + return inputs_mask; +} + +int gate_audio_module::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const +{ + subindex_graph = 0; + subindex_dot = 0; + subindex_gridline = generation ? INT_MAX : 0; + + if (fabs(range-old_range) + fabs(threshold-old_threshold) + fabs(ratio - old_ratio) + fabs(knee - old_knee) + fabs( makeup - old_makeup) + fabs( *params[param_bypass] - old_bypass) > 0.01f) + { + old_range = range; + old_threshold = threshold; + old_ratio = ratio; + old_knee = knee; + old_makeup = makeup; + old_bypass = *params[param_bypass]; + old_trigger = *params[param_trigger]; + old_mono = *params[param_mono]; + last_generation++; + } + old_trigger = *params[param_trigger]; + + if (generation == last_generation) + subindex_graph = 2; + return last_generation; } diff --git a/plugins/ladspa_effect/calf/src/modules_dist.cpp b/plugins/ladspa_effect/calf/src/modules_dist.cpp new file mode 100644 index 000000000..aba40fc74 --- /dev/null +++ b/plugins/ladspa_effect/calf/src/modules_dist.cpp @@ -0,0 +1,738 @@ +/* Calf DSP plugin pack + * Distortion 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; + +/// Saturator Band by Markus Schmidt +/// +/// This module is based on Krzysztof's filters and Tom Szilagyi's distortion routine. +/// It provides a blendable saturation stage followed by a highpass, a lowpass and a peak filter +/////////////////////////////////////////////////////////////////////////////////////////////// + +saturator_audio_module::saturator_audio_module() +{ + is_active = false; + srate = 0; + clip_in = 0.f; + clip_out = 0.f; + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; +} + +void saturator_audio_module::activate() +{ + is_active = true; + // set all filters + params_changed(); +} +void saturator_audio_module::deactivate() +{ + is_active = false; +} + +void saturator_audio_module::params_changed() +{ + // set the params of all filters + if(*params[param_lp_pre_freq] != lp_pre_freq_old) { + lp[0][0].set_lp_rbj(*params[param_lp_pre_freq], 0.707, (float)srate); + if(in_count > 1 && out_count > 1) + lp[1][0].copy_coeffs(lp[0][0]); + lp[0][1].copy_coeffs(lp[0][0]); + if(in_count > 1 && out_count > 1) + lp[1][1].copy_coeffs(lp[0][0]); + lp_pre_freq_old = *params[param_lp_pre_freq]; + } + if(*params[param_hp_pre_freq] != hp_pre_freq_old) { + hp[0][0].set_hp_rbj(*params[param_hp_pre_freq], 0.707, (float)srate); + if(in_count > 1 && out_count > 1) + hp[1][0].copy_coeffs(hp[0][0]); + hp[0][1].copy_coeffs(hp[0][0]); + if(in_count > 1 && out_count > 1) + hp[1][1].copy_coeffs(hp[0][0]); + hp_pre_freq_old = *params[param_hp_pre_freq]; + } + if(*params[param_lp_post_freq] != lp_post_freq_old) { + lp[0][2].set_lp_rbj(*params[param_lp_post_freq], 0.707, (float)srate); + if(in_count > 1 && out_count > 1) + lp[1][2].copy_coeffs(lp[0][2]); + lp[0][3].copy_coeffs(lp[0][2]); + if(in_count > 1 && out_count > 1) + lp[1][3].copy_coeffs(lp[0][2]); + lp_post_freq_old = *params[param_lp_post_freq]; + } + if(*params[param_hp_post_freq] != hp_post_freq_old) { + hp[0][2].set_hp_rbj(*params[param_hp_post_freq], 0.707, (float)srate); + if(in_count > 1 && out_count > 1) + hp[1][2].copy_coeffs(hp[0][2]); + hp[0][3].copy_coeffs(hp[0][2]); + if(in_count > 1 && out_count > 1) + hp[1][3].copy_coeffs(hp[0][2]); + hp_post_freq_old = *params[param_hp_post_freq]; + } + if(*params[param_p_freq] != p_freq_old or *params[param_p_level] != p_level_old or *params[param_p_q] != p_q_old) { + p[0].set_peakeq_rbj((float)*params[param_p_freq], (float)*params[param_p_q], (float)*params[param_p_level], (float)srate); + if(in_count > 1 && out_count > 1) + p[1].copy_coeffs(p[0]); + p_freq_old = *params[param_p_freq]; + p_level_old = *params[param_p_level]; + p_q_old = *params[param_p_q]; + } + // set distortion + dist[0].set_params(*params[param_blend], *params[param_drive]); + if(in_count > 1 && out_count > 1) + dist[1].set_params(*params[param_blend], *params[param_drive]); +} + +void saturator_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + dist[0].set_sample_rate(sr); + if(in_count > 1 && out_count > 1) + dist[1].set_sample_rate(sr); +} + +uint32_t saturator_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) { + if(in_count > 1 && out_count > 1) { + outs[0][offset] = ins[0][offset]; + outs[1][offset] = ins[1][offset]; + } else if(in_count > 1) { + outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2; + } else if(out_count > 1) { + outs[0][offset] = ins[0][offset]; + outs[1][offset] = ins[0][offset]; + } else { + outs[0][offset] = ins[0][offset]; + } + ++offset; + } + // displays, too + clip_in = 0.f; + clip_out = 0.f; + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; + } else { + + clip_in -= std::min(clip_in, numsamples); + clip_out -= std::min(clip_out, numsamples); + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; + float in_avg[2] = {0.f, 0.f}; + float out_avg[2] = {0.f, 0.f}; + float tube_avg = 0.f; + // process + while(offset < numsamples) { + // cycle through samples + float out[2], in[2] = {0.f, 0.f}; + float maxIn, maxOut = 0.f; + int c = 0; + + if(in_count > 1 && out_count > 1) { + // stereo in/stereo out + // handle full stereo + in[0] = ins[0][offset]; + in[1] = ins[1][offset]; + c = 2; + } else { + // in and/or out mono + // handle mono + in[0] = ins[0][offset]; + in[1] = in[0]; + c = 1; + } + + float proc[2]; + proc[0] = in[0] * *params[param_level_in]; + proc[1] = in[1] * *params[param_level_in]; + + for (int i = 0; i < c; ++i) { + // all pre filters in chain + proc[i] = lp[i][1].process(lp[i][0].process(proc[i])); + proc[i] = hp[i][1].process(hp[i][0].process(proc[i])); + + // get average for display purposes before... + in_avg[i] += fabs(pow(proc[i], 2.f)); + + // ...saturate... + proc[i] = dist[i].process(proc[i]); + + // ...and get average after... + out_avg[i] += fabs(pow(proc[i], 2.f)); + + // tone control + proc[i] = p[i].process(proc[i]); + + // all post filters in chain + proc[i] = lp[i][2].process(lp[i][3].process(proc[i])); + proc[i] = hp[i][2].process(hp[i][3].process(proc[i])); + + //subtract gain + proc[i] /= *params[param_level_in]; + } + + if(in_count > 1 && out_count > 1) { + // full stereo + out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out]; + outs[0][offset] = out[0]; + out[1] = ((proc[1] * *params[param_mix]) + in[1] * (1 - *params[param_mix])) * *params[param_level_out]; + outs[1][offset] = out[1]; + maxIn = std::max(fabs(in[0]), fabs(in[1])); + maxOut = std::max(fabs(out[0]), fabs(out[1])); + } else if(out_count > 1) { + // mono -> pseudo stereo + out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out]; + outs[0][offset] = out[0]; + out[1] = out[0]; + outs[1][offset] = out[1]; + maxOut = fabs(out[0]); + maxIn = fabs(in[0]); + } else { + // stereo -> mono + // or full mono + out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out]; + outs[0][offset] = out[0]; + maxIn = fabs(in[0]); + maxOut = fabs(out[0]); + } + + if(maxIn > 1.f) { + clip_in = srate >> 3; + } + if(maxOut > 1.f) { + clip_out = srate >> 3; + } + // set up in / out meters + if(maxIn > meter_in) { + meter_in = maxIn; + } + if(maxOut > meter_out) { + meter_out = maxOut; + } + + // next sample + ++offset; + } // cycle trough samples + + tube_avg = (sqrt(std::max(out_avg[0], out_avg[1])) / numsamples) - (sqrt(std::max(in_avg[0], in_avg[1])) / numsamples); + meter_drive = (5.0f * fabs(tube_avg) * (float(*params[param_blend]) + 30.0f)); + // printf("out:%.6f in: %.6f avg: %.6f drv: %.3f\n", sqrt(std::max(out_avg[0], out_avg[1])) / numsamples, sqrt(std::max(in_avg[0], in_avg[1])) / numsamples, tube_avg, meter_drive); + // clean up + lp[0][0].sanitize(); + lp[1][0].sanitize(); + lp[0][1].sanitize(); + lp[1][1].sanitize(); + lp[0][2].sanitize(); + lp[1][2].sanitize(); + lp[0][3].sanitize(); + lp[1][3].sanitize(); + hp[0][0].sanitize(); + hp[1][0].sanitize(); + hp[0][1].sanitize(); + hp[1][1].sanitize(); + hp[0][2].sanitize(); + hp[1][2].sanitize(); + hp[0][3].sanitize(); + hp[1][3].sanitize(); + p[0].sanitize(); + p[1].sanitize(); + } + // draw meters + if(params[param_clip_in] != NULL) { + *params[param_clip_in] = clip_in; + } + if(params[param_clip_out] != NULL) { + *params[param_clip_out] = clip_out; + } + + if(params[param_meter_in] != NULL) { + *params[param_meter_in] = meter_in; + } + if(params[param_meter_out] != NULL) { + *params[param_meter_out] = meter_out; + } + if(params[param_meter_drive] != NULL) { + *params[param_meter_drive] = meter_drive; + } + // whatever has to be returned x) + return outputs_mask; +} + +/// Exciter by Markus Schmidt +/// +/// This module is based on Krzysztof's filters and Tom Szilagyi's distortion routine. +/// It provides a blendable saturation stage followed by a highpass, a lowpass and a peak filter +/////////////////////////////////////////////////////////////////////////////////////////////// + +exciter_audio_module::exciter_audio_module() +{ + is_active = false; + srate = 0; + clip_in = 0.f; + clip_out = 0.f; + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; +} + +void exciter_audio_module::activate() +{ + is_active = true; + // set all filters + params_changed(); +} + +void exciter_audio_module::deactivate() +{ + is_active = false; +} + +void exciter_audio_module::params_changed() +{ + // set the params of all filters + if(*params[param_freq] != freq_old) { + hp[0][0].set_hp_rbj(*params[param_freq], 0.707, (float)srate); + hp[0][1].copy_coeffs(hp[0][0]); + hp[0][2].copy_coeffs(hp[0][0]); + hp[0][3].copy_coeffs(hp[0][0]); + if(in_count > 1 && out_count > 1) { + hp[1][0].copy_coeffs(hp[0][0]); + hp[1][1].copy_coeffs(hp[0][0]); + hp[1][2].copy_coeffs(hp[0][0]); + hp[1][3].copy_coeffs(hp[0][0]); + } + freq_old = *params[param_freq]; + } + // set distortion + dist[0].set_params(*params[param_blend], *params[param_drive]); + if(in_count > 1 && out_count > 1) + dist[1].set_params(*params[param_blend], *params[param_drive]); +} + +void exciter_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + dist[0].set_sample_rate(sr); + if(in_count > 1 && out_count > 1) + dist[1].set_sample_rate(sr); +} + +uint32_t exciter_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) { + if(in_count > 1 && out_count > 1) { + outs[0][offset] = ins[0][offset]; + outs[1][offset] = ins[1][offset]; + } else if(in_count > 1) { + outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2; + } else if(out_count > 1) { + outs[0][offset] = ins[0][offset]; + outs[1][offset] = ins[0][offset]; + } else { + outs[0][offset] = ins[0][offset]; + } + ++offset; + } + // displays, too + clip_in = 0.f; + clip_out = 0.f; + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; + } else { + + clip_in -= std::min(clip_in, numsamples); + clip_out -= std::min(clip_out, numsamples); + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; + + // process + while(offset < numsamples) { + // cycle through samples + float out[2], in[2] = {0.f, 0.f}; + float maxIn, maxOut, maxDrive = 0.f; + int c = 0; + + if(in_count > 1 && out_count > 1) { + // stereo in/stereo out + // handle full stereo + in[0] = ins[0][offset]; + in[0] *= *params[param_level_in]; + in[1] = ins[1][offset]; + in[1] *= *params[param_level_in]; + c = 2; + } else { + // in and/or out mono + // handle mono + in[0] = ins[0][offset]; + in[0] *= *params[param_level_in]; + in[1] = in[0]; + c = 1; + } + + float proc[2]; + proc[0] = in[0]; + proc[1] = in[1]; + + for (int i = 0; i < c; ++i) { + // all pre filters in chain + proc[i] = hp[i][1].process(hp[i][0].process(proc[i])); + + // saturate + proc[i] = dist[i].process(proc[i]); + + // all post filters in chain + proc[i] = hp[i][2].process(hp[i][3].process(proc[i])); + } + + if(in_count > 1 && out_count > 1) { + // full stereo + if(*params[param_listen] > 0.f) + out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; + else + out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + outs[0][offset] = out[0]; + if(*params[param_listen] > 0.f) + out[1] = proc[1] * *params[param_amount] * *params[param_level_out]; + else + out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out]; + outs[1][offset] = out[1]; + maxIn = std::max(fabs(in[0]), fabs(in[1])); + maxOut = std::max(fabs(out[0]), fabs(out[1])); + maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount], + dist[1].get_distortion_level() * *params[param_amount]); + } else if(out_count > 1) { + // mono -> pseudo stereo + if(*params[param_listen] > 0.f) + out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; + else + out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + outs[0][offset] = out[0]; + out[1] = out[0]; + outs[1][offset] = out[1]; + maxOut = fabs(out[0]); + maxIn = fabs(in[0]); + maxDrive = dist[0].get_distortion_level() * *params[param_amount]; + } else { + // stereo -> mono + // or full mono + if(*params[param_listen] > 0.f) + out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; + else + out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + outs[0][offset] = out[0]; + maxIn = fabs(in[0]); + maxOut = fabs(out[0]); + maxDrive = dist[0].get_distortion_level() * *params[param_amount]; + } + + if(maxIn > 1.f) { + clip_in = srate >> 3; + } + if(maxOut > 1.f) { + clip_out = srate >> 3; + } + // set up in / out meters + if(maxIn > meter_in) { + meter_in = maxIn; + } + if(maxOut > meter_out) { + meter_out = maxOut; + } + if(maxDrive > meter_drive) { + meter_drive = maxDrive; + } + + // next sample + ++offset; + } // cycle trough samples + // clean up + hp[0][0].sanitize(); + hp[1][0].sanitize(); + hp[0][1].sanitize(); + hp[1][1].sanitize(); + hp[0][2].sanitize(); + hp[1][2].sanitize(); + hp[0][3].sanitize(); + hp[1][3].sanitize(); + } + // draw meters + if(params[param_clip_in] != NULL) { + *params[param_clip_in] = clip_in; + } + if(params[param_clip_out] != NULL) { + *params[param_clip_out] = clip_out; + } + + if(params[param_meter_in] != NULL) { + *params[param_meter_in] = meter_in; + } + if(params[param_meter_out] != NULL) { + *params[param_meter_out] = meter_out; + } + if(params[param_meter_drive] != NULL) { + *params[param_meter_drive] = meter_drive; + } + // whatever has to be returned x) + return outputs_mask; +} + +/// Bass Enhancer by Markus Schmidt +/// +/// This module is based on Krzysztof's filters and Tom's distortion routine. +/// It sends the signal through a lowpass, saturates it and sends it through a lowpass again +/////////////////////////////////////////////////////////////////////////////////////////////// + +bassenhancer_audio_module::bassenhancer_audio_module() +{ + is_active = false; + srate = 0; + clip_in = 0.f; + clip_out = 0.f; + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; +} + +void bassenhancer_audio_module::activate() +{ + is_active = true; + // set all filters + params_changed(); +} +void bassenhancer_audio_module::deactivate() +{ + is_active = false; +} + +void bassenhancer_audio_module::params_changed() +{ + // set the params of all filters + if(*params[param_freq] != freq_old) { + lp[0][0].set_lp_rbj(*params[param_freq], 0.707, (float)srate); + lp[0][1].copy_coeffs(lp[0][0]); + lp[0][2].copy_coeffs(lp[0][0]); + lp[0][3].copy_coeffs(lp[0][0]); + if(in_count > 1 && out_count > 1) { + lp[1][0].copy_coeffs(lp[0][0]); + lp[1][1].copy_coeffs(lp[0][0]); + lp[1][2].copy_coeffs(lp[0][0]); + lp[1][3].copy_coeffs(lp[0][0]); + } + freq_old = *params[param_freq]; + } + // set distortion + dist[0].set_params(*params[param_blend], *params[param_drive]); + if(in_count > 1 && out_count > 1) + dist[1].set_params(*params[param_blend], *params[param_drive]); +} + +void bassenhancer_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + dist[0].set_sample_rate(sr); + if(in_count > 1 && out_count > 1) + dist[1].set_sample_rate(sr); +} + +uint32_t bassenhancer_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) { + if(in_count > 1 && out_count > 1) { + outs[0][offset] = ins[0][offset]; + outs[1][offset] = ins[1][offset]; + } else if(in_count > 1) { + outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2; + } else if(out_count > 1) { + outs[0][offset] = ins[0][offset]; + outs[1][offset] = ins[0][offset]; + } else { + outs[0][offset] = ins[0][offset]; + } + ++offset; + } + // displays, too + clip_in = 0.f; + clip_out = 0.f; + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; + } else { + + clip_in -= std::min(clip_in, numsamples); + clip_out -= std::min(clip_out, numsamples); + meter_in = 0.f; + meter_out = 0.f; + meter_drive = 0.f; + + // process + while(offset < numsamples) { + // cycle through samples + float out[2], in[2] = {0.f, 0.f}; + float maxIn, maxOut, maxDrive = 0.f; + int c = 0; + + if(in_count > 1 && out_count > 1) { + // stereo in/stereo out + // handle full stereo + in[0] = ins[0][offset]; + in[0] *= *params[param_level_in]; + in[1] = ins[1][offset]; + in[1] *= *params[param_level_in]; + c = 2; + } else { + // in and/or out mono + // handle mono + in[0] = ins[0][offset]; + in[0] *= *params[param_level_in]; + in[1] = in[0]; + c = 1; + } + + float proc[2]; + proc[0] = in[0]; + proc[1] = in[1]; + + for (int i = 0; i < c; ++i) { + // all pre filters in chain + proc[i] = lp[i][1].process(lp[i][0].process(proc[i])); + + // saturate + proc[i] = dist[i].process(proc[i]); + + // all post filters in chain + proc[i] = lp[i][2].process(lp[i][3].process(proc[i])); + } + + if(in_count > 1 && out_count > 1) { + // full stereo + if(*params[param_listen] > 0.f) + out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; + else + out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + outs[0][offset] = out[0]; + if(*params[param_listen] > 0.f) + out[1] = proc[1] * *params[param_amount] * *params[param_level_out]; + else + out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out]; + outs[1][offset] = out[1]; + maxIn = std::max(fabs(in[0]), fabs(in[1])); + maxOut = std::max(fabs(out[0]), fabs(out[1])); + maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount], + dist[1].get_distortion_level() * *params[param_amount]); + } else if(out_count > 1) { + // mono -> pseudo stereo + if(*params[param_listen] > 0.f) + out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; + else + out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + outs[0][offset] = out[0]; + out[1] = out[0]; + outs[1][offset] = out[1]; + maxOut = fabs(out[0]); + maxIn = fabs(in[0]); + maxDrive = dist[0].get_distortion_level() * *params[param_amount]; + } else { + // stereo -> mono + // or full mono + if(*params[param_listen] > 0.f) + out[0] = proc[0] * *params[param_amount] * *params[param_level_out]; + else + out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out]; + outs[0][offset] = out[0]; + maxIn = fabs(in[0]); + maxOut = fabs(out[0]); + maxDrive = dist[0].get_distortion_level() * *params[param_amount]; + } + + if(maxIn > 1.f) { + clip_in = srate >> 3; + } + if(maxOut > 1.f) { + clip_out = srate >> 3; + } + // set up in / out meters + if(maxIn > meter_in) { + meter_in = maxIn; + } + if(maxOut > meter_out) { + meter_out = maxOut; + } + if(maxDrive > meter_drive) { + meter_drive = maxDrive; + } + + // next sample + ++offset; + } // cycle trough samples + // clean up + lp[0][0].sanitize(); + lp[1][0].sanitize(); + lp[0][1].sanitize(); + lp[1][1].sanitize(); + lp[0][2].sanitize(); + lp[1][2].sanitize(); + lp[0][3].sanitize(); + lp[1][3].sanitize(); + } + // draw meters + if(params[param_clip_in] != NULL) { + *params[param_clip_in] = clip_in; + } + if(params[param_clip_out] != NULL) { + *params[param_clip_out] = clip_out; + } + + if(params[param_meter_in] != NULL) { + *params[param_meter_in] = meter_in; + } + if(params[param_meter_out] != NULL) { + *params[param_meter_out] = meter_out; + } + if(params[param_meter_drive] != NULL) { + *params[param_meter_drive] = meter_drive; + } + // whatever has to be returned x) + return outputs_mask; +} diff --git a/plugins/ladspa_effect/calf/src/modules_eq.cpp b/plugins/ladspa_effect/calf/src/modules_eq.cpp new file mode 100644 index 000000000..d4ea0bcc4 --- /dev/null +++ b/plugins/ladspa_effect/calf/src/modules_eq.cpp @@ -0,0 +1,381 @@ +/* Calf DSP plugin pack + * Equalization 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; + +/// Equalizer 12 Band by Markus Schmidt +/// +/// This module is based on Krzysztof's filters. It provides a couple +/// of different chained filters. +/////////////////////////////////////////////////////////////////////////////////////////////// + +template +equalizerNband_audio_module::equalizerNband_audio_module() +{ + is_active = false; + srate = 0; + last_generation = 0; + clip_inL = clip_inR = clip_outL = clip_outR = 0.f; + meter_inL = meter_inR = meter_outL = meter_outR = 0.f; +} + +template +void equalizerNband_audio_module::activate() +{ + is_active = true; + // set all filters + params_changed(); +} + +template +void equalizerNband_audio_module::deactivate() +{ + is_active = false; +} + +static inline void copy_lphp(biquad_d2 filters[3][2]) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + if (i || j) + filters[i][j].copy_coeffs(filters[0][0]); +} + +template +void equalizerNband_audio_module::params_changed() +{ + // set the params of all filters + + // lp/hp first (if available) + if (has_lphp) + { + hp_mode = (CalfEqMode)(int)*params[AM::param_hp_mode]; + lp_mode = (CalfEqMode)(int)*params[AM::param_lp_mode]; + + float hpfreq = *params[AM::param_hp_freq], lpfreq = *params[AM::param_lp_freq]; + + if(hpfreq != hp_freq_old) { + hp[0][0].set_hp_rbj(hpfreq, 0.707, (float)srate, 1.0); + copy_lphp(hp); + hp_freq_old = hpfreq; + } + if(lpfreq != lp_freq_old) { + lp[0][0].set_lp_rbj(lpfreq, 0.707, (float)srate, 1.0); + copy_lphp(lp); + lp_freq_old = lpfreq; + } + } + + // then shelves + float hsfreq = *params[AM::param_hs_freq], hslevel = *params[AM::param_hs_level]; + float lsfreq = *params[AM::param_ls_freq], lslevel = *params[AM::param_ls_level]; + + if(lsfreq != ls_freq_old or lslevel != ls_level_old) { + lsL.set_lowshelf_rbj(lsfreq, 0.707, lslevel, (float)srate); + lsR.copy_coeffs(lsL); + ls_level_old = lslevel; + ls_freq_old = lsfreq; + } + if(hsfreq != hs_freq_old or hslevel != hs_level_old) { + hsL.set_highshelf_rbj(hsfreq, 0.707, hslevel, (float)srate); + hsR.copy_coeffs(hsL); + hs_level_old = hslevel; + hs_freq_old = hsfreq; + } + for (int i = 0; i < AM::PeakBands; i++) + { + int offset = i * params_per_band; + float freq = *params[AM::param_p1_freq + offset]; + float level = *params[AM::param_p1_level + offset]; + float q = *params[AM::param_p1_q + offset]; + if(freq != p_freq_old[i] or level != p_level_old[i] or q != p_q_old[i]) { + pL[i].set_peakeq_rbj(freq, q, level, (float)srate); + pR[i].copy_coeffs(pL[i]); + p_freq_old[i] = freq; + p_level_old[i] = level; + p_q_old[i] = q; + } + } +} + +template +inline void equalizerNband_audio_module::process_hplp(float &left, float &right) +{ + if (!has_lphp) + return; + if (*params[AM::param_lp_active] > 0.f) + { + switch(lp_mode) + { + case MODE12DB: + left = lp[0][0].process(left); + right = lp[0][1].process(right); + break; + case MODE24DB: + left = lp[1][0].process(lp[0][0].process(left)); + right = lp[1][1].process(lp[0][1].process(right)); + break; + case MODE36DB: + left = lp[2][0].process(lp[1][0].process(lp[0][0].process(left))); + right = lp[2][1].process(lp[1][1].process(lp[0][1].process(right))); + break; + } + } + if (*params[AM::param_hp_active] > 0.f) + { + switch(hp_mode) + { + case MODE12DB: + left = hp[0][0].process(left); + right = hp[0][1].process(right); + break; + case MODE24DB: + left = hp[1][0].process(hp[0][0].process(left)); + right = hp[1][1].process(hp[0][1].process(right)); + break; + case MODE36DB: + left = hp[2][0].process(hp[1][0].process(hp[0][0].process(left))); + right = hp[2][1].process(hp[1][1].process(hp[0][1].process(right))); + break; + } + } +} + +template +uint32_t equalizerNband_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) +{ + bool bypass = *params[AM::param_bypass] > 0.f; + 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 = clip_inR = clip_outL = clip_outR = 0.f; + meter_inL = meter_inR = meter_outL = meter_outR = 0.f; + } else { + + 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; + + // process + while(offset < numsamples) { + // cycle through samples + float outL = 0.f; + float outR = 0.f; + float inL = ins[0][offset]; + float inR = ins[1][offset]; + // in level + inR *= *params[AM::param_level_in]; + inL *= *params[AM::param_level_in]; + + float procL = inL; + float procR = inR; + + // all filters in chain + process_hplp(procL, procR); + if(*params[AM::param_ls_active] > 0.f) { + procL = lsL.process(procL); + procR = lsR.process(procR); + } + if(*params[AM::param_hs_active] > 0.f) { + procL = hsL.process(procL); + procR = hsR.process(procR); + } + for (int i = 0; i < AM::PeakBands; i++) + { + if(*params[AM::param_p1_active + i * params_per_band] > 0.f) { + procL = pL[i].process(procL); + procR = pR[i].process(procR); + } + } + + outL = procL * *params[AM::param_level_out]; + outR = procR * *params[AM::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 + // clean up + for(int i = 0; i < 3; ++i) { + hp[i][0].sanitize(); + hp[i][1].sanitize(); + lp[i][0].sanitize(); + lp[i][1].sanitize(); + } + lsL.sanitize(); + hsR.sanitize(); + for(int i = 0; i < AM::PeakBands; ++i) { + pL[i].sanitize(); + pR[i].sanitize(); + } + } + // 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) + // whatever has to be returned x) + return outputs_mask; +} + +template +bool equalizerNband_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + if (!is_active) + return false; + if (index == AM::param_p1_freq && !subindex) { + context->set_line_width(1.5); + return ::get_graph(*this, subindex, data, points); + } + return false; +} + +template +bool equalizerNband_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 { + return get_freq_gridline(subindex, pos, vertical, legend, context); + } +} + +template +int equalizerNband_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const +{ + if (!is_active) { + return false; + } else { + bool changed = false; + for (int i = 0; i < graph_param_count && !changed; i++) + { + if (*params[AM::first_graph_param + i] != old_params_for_graph[i]) + changed = true; + } + if (changed) + { + for (int i = 0; i < graph_param_count; i++) + old_params_for_graph[i] = *params[AM::first_graph_param + i]; + + last_generation++; + subindex_graph = 0; + subindex_dot = INT_MAX; + subindex_gridline = INT_MAX; + } + else { + subindex_graph = 0; + subindex_dot = subindex_gridline = generation ? INT_MAX : 0; + } + if (generation == last_calculated_generation) + subindex_graph = INT_MAX; + return last_generation; + } + return false; +} + +static inline float adjusted_lphp_gain(const float *const *params, int param_active, int param_mode, const biquad_d2 &filter, float freq, float srate) +{ + if(*params[param_active] > 0.f) { + float gain = filter.freq_gain(freq, srate); + switch((int)*params[param_mode]) { + case MODE12DB: + return gain; + case MODE24DB: + return gain * gain; + case MODE36DB: + return gain * gain * gain; + } + } + return 1; +} + +template +float equalizerNband_audio_module::freq_gain(int index, double freq, uint32_t sr) const +{ + float ret = 1.f; + if (use_hplp) + { + ret *= adjusted_lphp_gain(params, AM::param_hp_active, AM::param_hp_mode, hp[0][0], freq, (float)sr); + ret *= adjusted_lphp_gain(params, AM::param_lp_active, AM::param_lp_mode, lp[0][0], freq, (float)sr); + } + ret *= (*params[AM::param_ls_active] > 0.f) ? lsL.freq_gain(freq, sr) : 1; + ret *= (*params[AM::param_hs_active] > 0.f) ? hsL.freq_gain(freq, sr) : 1; + for (int i = 0; i < PeakBands; i++) + ret *= (*params[AM::param_p1_active + i * params_per_band] > 0.f) ? pL[i].freq_gain(freq, (float)sr) : 1; + return ret; +} + +template class equalizerNband_audio_module; +template class equalizerNband_audio_module; +template class equalizerNband_audio_module; + diff --git a/plugins/ladspa_effect/calf/src/modules_mod.cpp b/plugins/ladspa_effect/calf/src/modules_mod.cpp new file mode 100644 index 000000000..f9716c21a --- /dev/null +++ b/plugins/ladspa_effect/calf/src/modules_mod.cpp @@ -0,0 +1,736 @@ +/* Calf DSP plugin pack + * Modulation effect 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; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void flanger_audio_module::activate() { + left.reset(); + right.reset(); + last_r_phase = *params[par_stereo] * (1.f / 360.f); + left.reset_phase(0.f); + right.reset_phase(last_r_phase); + is_active = true; +} + +void flanger_audio_module::set_sample_rate(uint32_t sr) { + srate = sr; + left.setup(sr); + right.setup(sr); +} + +void flanger_audio_module::deactivate() { + is_active = false; +} + +bool flanger_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + if (!is_active) + return false; + if (index == par_delay && subindex < 2) + { + set_channel_color(context, subindex); + return ::get_graph(*this, subindex, data, points); + } + return false; +} + +float flanger_audio_module::freq_gain(int subindex, float freq, float srate) const +{ + return (subindex ? right : left).freq_gain(freq, srate); +} + +void flanger_audio_module::params_changed() +{ + float dry = *params[par_dryamount]; + float wet = *params[par_amount]; + float rate = *params[par_rate]; // 0.01*pow(1000.0f,*params[par_rate]); + float min_delay = *params[par_delay] / 1000.0; + float mod_depth = *params[par_depth] / 1000.0; + float fb = *params[par_fb]; + left.set_dry(dry); right.set_dry(dry); + left.set_wet(wet); right.set_wet(wet); + left.set_rate(rate); right.set_rate(rate); + left.set_min_delay(min_delay); right.set_min_delay(min_delay); + left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth); + left.set_fb(fb); right.set_fb(fb); + float r_phase = *params[par_stereo] * (1.f / 360.f); + clear_reset = false; + if (*params[par_reset] >= 0.5) { + clear_reset = true; + left.reset_phase(0.f); + right.reset_phase(r_phase); + } else { + if (fabs(r_phase - last_r_phase) > 0.0001f) { + right.phase = left.phase; + right.inc_phase(r_phase); + last_r_phase = r_phase; + } + } +} + +void flanger_audio_module::params_reset() +{ + if (clear_reset) { + *params[par_reset] = 0.f; + clear_reset = false; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +phaser_audio_module::phaser_audio_module() +: left(MaxStages, x1vals[0], y1vals[0]) +, right(MaxStages, x1vals[1], y1vals[1]) +{ + is_active = false; +} + +void phaser_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + left.setup(sr); + right.setup(sr); +} + +void phaser_audio_module::activate() +{ + is_active = true; + left.reset(); + right.reset(); + last_r_phase = *params[par_stereo] * (1.f / 360.f); + left.reset_phase(0.f); + right.reset_phase(last_r_phase); +} + +void phaser_audio_module::deactivate() +{ + is_active = false; +} + +bool phaser_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + if (!is_active) + return false; + if (subindex < 2) + { + set_channel_color(context, subindex); + return ::get_graph(*this, subindex, data, points); + } + return false; +} + +float phaser_audio_module::freq_gain(int subindex, float freq, float srate) const +{ + return (subindex ? right : left).freq_gain(freq, srate); +} + +bool phaser_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const +{ + return get_freq_gridline(subindex, pos, vertical, legend, context); +} + +void phaser_audio_module::params_changed() +{ + float dry = *params[par_dryamount]; + float wet = *params[par_amount]; + float rate = *params[par_rate]; // 0.01*pow(1000.0f,*params[par_rate]); + float base_frq = *params[par_freq]; + float mod_depth = *params[par_depth]; + float fb = *params[par_fb]; + int stages = (int)*params[par_stages]; + left.set_dry(dry); right.set_dry(dry); + left.set_wet(wet); right.set_wet(wet); + left.set_rate(rate); right.set_rate(rate); + left.set_base_frq(base_frq); right.set_base_frq(base_frq); + left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth); + left.set_fb(fb); right.set_fb(fb); + left.set_stages(stages); right.set_stages(stages); + float r_phase = *params[par_stereo] * (1.f / 360.f); + clear_reset = false; + if (*params[par_reset] >= 0.5) { + clear_reset = true; + left.reset_phase(0.f); + right.reset_phase(r_phase); + } else { + if (fabs(r_phase - last_r_phase) > 0.0001f) { + right.phase = left.phase; + right.inc_phase(r_phase); + last_r_phase = r_phase; + } + } +} + +void phaser_audio_module::params_reset() +{ + if (clear_reset) { + *params[par_reset] = 0.f; + clear_reset = false; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +rotary_speaker_audio_module::rotary_speaker_audio_module() +{ + mwhl_value = hold_value = 0.f; + phase_h = phase_l = 0.f; + aspeed_l = 1.f; + aspeed_h = 1.f; + dspeed = 0.f; +} + +void rotary_speaker_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; + setup(); +} + +void rotary_speaker_audio_module::setup() +{ + crossover1l.set_lp_rbj(800.f, 0.7, (float)srate); + crossover1r.set_lp_rbj(800.f, 0.7, (float)srate); + crossover2l.set_hp_rbj(800.f, 0.7, (float)srate); + crossover2r.set_hp_rbj(800.f, 0.7, (float)srate); +} + +void rotary_speaker_audio_module::activate() +{ + phase_h = phase_l = 0.f; + maspeed_h = maspeed_l = 0.f; + setup(); +} + +void rotary_speaker_audio_module::deactivate() +{ +} + +void rotary_speaker_audio_module::control_change(int ctl, int val) +{ + if (vibrato_mode == 3 && ctl == 64) + { + hold_value = val / 127.f; + set_vibrato(); + return; + } + if (vibrato_mode == 4 && ctl == 1) + { + mwhl_value = val / 127.f; + set_vibrato(); + return; + } +} + +void rotary_speaker_audio_module::params_changed() +{ + set_vibrato(); +} + +void rotary_speaker_audio_module::set_vibrato() +{ + vibrato_mode = fastf2i_drm(*params[par_speed]); + // manual vibrato - do not recalculate speeds as they're not used anyway + if (vibrato_mode == 5) + return; + if (!vibrato_mode) + dspeed = -1; + else { + float speed = vibrato_mode - 1; + if (vibrato_mode == 3) + speed = hold_value; + if (vibrato_mode == 4) + speed = mwhl_value; + dspeed = (speed < 0.5f) ? 0 : 1; + } + update_speed(); +} + +/// Convert RPM speed to delta-phase +uint32_t rotary_speaker_audio_module::rpm2dphase(float rpm) +{ + return (uint32_t)((rpm / (60.0 * srate)) * (1 << 30)) << 2; +} + +/// Set delta-phase variables based on current calculated (and interpolated) RPM speed +void rotary_speaker_audio_module::update_speed() +{ + float speed_h = aspeed_h >= 0 ? (48 + (400-48) * aspeed_h) : (48 * (1 + aspeed_h)); + float speed_l = aspeed_l >= 0 ? 40 + (342-40) * aspeed_l : (40 * (1 + aspeed_l)); + dphase_h = rpm2dphase(speed_h); + dphase_l = rpm2dphase(speed_l); +} + +void rotary_speaker_audio_module::update_speed_manual(float delta) +{ + float ts = *params[par_treblespeed]; + float bs = *params[par_bassspeed]; + incr_towards(maspeed_h, ts, delta * 200, delta * 200); + incr_towards(maspeed_l, bs, delta * 200, delta * 200); + dphase_h = rpm2dphase(maspeed_h); + dphase_l = rpm2dphase(maspeed_l); +} + +/// map a ramp [int] to a sinusoid-like function [0, 65536] +static inline int pseudo_sine_scl(int counter) +{ + // premature optimization is a root of all evil; it can be done with integers only - but later :) + double v = counter * (1.0 / (65536.0 * 32768.0)); + return (int) (32768 + 32768 * (v - v*v*v) * (1.0 / 0.3849)); +} + +/// Increase or decrease aspeed towards raspeed, with required negative and positive rate +inline bool rotary_speaker_audio_module::incr_towards(float &aspeed, float raspeed, float delta_decc, float delta_acc) +{ + if (aspeed < raspeed) { + aspeed = std::min(raspeed, aspeed + delta_acc); + return true; + } + else if (aspeed > raspeed) + { + aspeed = std::max(raspeed, aspeed - delta_decc); + return true; + } + return false; +} + +uint32_t rotary_speaker_audio_module::process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) +{ + int shift = (int)(300000 * (*params[par_shift])), pdelta = (int)(300000 * (*params[par_spacing])); + int md = (int)(100 * (*params[par_moddepth])); + float mix = 0.5 * (1.0 - *params[par_micdistance]); + float mix2 = *params[par_reflection]; + float mix3 = mix2 * mix2; + for (unsigned int i = 0; i < nsamples; i++) { + float in_l = ins[0][i + offset], in_r = ins[1][i + offset]; + float in_mono = 0.5f * (in_l + in_r); + + int xl = pseudo_sine_scl(phase_l), yl = pseudo_sine_scl(phase_l + 0x40000000); + int xh = pseudo_sine_scl(phase_h), yh = pseudo_sine_scl(phase_h + 0x40000000); + // printf("%d %d %d\n", shift, pdelta, shift + pdelta + 20 * xl); + meter_l = xl; + meter_h = xh; + // float out_hi_l = in_mono - delay.get_interp_1616(shift + md * xh) + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) - delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh); + // float out_hi_r = in_mono + delay.get_interp_1616(shift + md * 65536 - md * yh) - delay.get_interp_1616(shift + pdelta + md * xh) + delay.get_interp_1616(shift + pdelta + pdelta + md * yh); + float out_hi_l = in_mono + delay.get_interp_1616(shift + md * xh) - mix2 * delay.get_interp_1616(shift + md * 65536 + pdelta - md * yh) + mix3 * delay.get_interp_1616(shift + md * 65536 + pdelta + pdelta - md * xh); + float out_hi_r = in_mono + delay.get_interp_1616(shift + md * 65536 - md * yh) - mix2 * delay.get_interp_1616(shift + pdelta + md * xh) + mix3 * delay.get_interp_1616(shift + pdelta + pdelta + md * yh); + + float out_lo_l = in_mono + delay.get_interp_1616(shift + md * xl); // + delay.get_interp_1616(shift + md * 65536 + pdelta - md * yl); + float out_lo_r = in_mono + delay.get_interp_1616(shift + md * yl); // - delay.get_interp_1616(shift + pdelta + md * yl); + + out_hi_l = crossover2l.process(out_hi_l); // sanitize(out_hi_l); + out_hi_r = crossover2r.process(out_hi_r); // sanitize(out_hi_r); + out_lo_l = crossover1l.process(out_lo_l); // sanitize(out_lo_l); + out_lo_r = crossover1r.process(out_lo_r); // sanitize(out_lo_r); + + float out_l = out_hi_l + out_lo_l; + float out_r = out_hi_r + out_lo_r; + + float mic_l = out_l + mix * (out_r - out_l); + float mic_r = out_r + mix * (out_l - out_r); + + outs[0][i + offset] = mic_l * 0.5f; + outs[1][i + offset] = mic_r * 0.5f; + delay.put(in_mono); + phase_l += dphase_l; + phase_h += dphase_h; + } + crossover1l.sanitize(); + crossover1r.sanitize(); + crossover2l.sanitize(); + crossover2r.sanitize(); + float delta = nsamples * 1.0 / srate; + if (vibrato_mode == 5) + update_speed_manual(delta); + else + { + bool u1 = incr_towards(aspeed_l, dspeed, delta * 0.2, delta * 0.14); + bool u2 = incr_towards(aspeed_h, dspeed, delta, delta * 0.5); + if (u1 || u2) + set_vibrato(); + } + if(params[par_meter_l] != NULL) { + *params[par_meter_l] = (float)meter_l / 65536.0; + } + if(params[par_meter_h] != NULL) { + *params[par_meter_h] = (float)meter_h / 65536.0; + } + return outputs_mask; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +multichorus_audio_module::multichorus_audio_module() +{ + is_active = false; + last_r_phase = -1; +} + +void multichorus_audio_module::activate() +{ + is_active = true; + params_changed(); +} + +void multichorus_audio_module::deactivate() +{ + is_active = false; +} + +void multichorus_audio_module::set_sample_rate(uint32_t sr) { + srate = sr; + left.setup(sr); + right.setup(sr); +} + +bool multichorus_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + if (!is_active) + return false; + int nvoices = (int)*params[par_voices]; + if (index == par_delay && subindex < 3) + { + if (subindex < 2) + set_channel_color(context, subindex); + else { + context->set_source_rgba(0.35, 0.4, 0.2); + context->set_line_width(1.0); + } + return ::get_graph(*this, subindex, data, points); + } + if (index == par_rate && subindex < nvoices) { + const sine_multi_lfo &lfo = left.lfo; + for (int i = 0; i < points; i++) { + float phase = i * 2 * M_PI / points; + // original -65536 to 65535 value + float orig = subindex * lfo.voice_offset + ((lfo.voice_depth >> (30-13)) * 65536.0 * (0.95 * sin(phase) + 1)/ 8192.0) - 65536; + // scale to -1..1 + data[i] = orig / 65536.0; + } + return true; + } + return false; +} + +bool multichorus_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const +{ + int voice = subindex >> 1; + int nvoices = (int)*params[par_voices]; + if ((index != par_rate && index != par_depth) || voice >= nvoices) + return false; + + float unit = (1 - *params[par_overlap]); + float scw = 1 + unit * (nvoices - 1); + set_channel_color(context, subindex); + const sine_multi_lfo &lfo = (subindex & 1 ? right : left).lfo; + if (index == par_rate) + { + x = (double)(lfo.phase + lfo.vphase * voice) / 4096.0; + y = 0.95 * sin(x * 2 * M_PI); + y = (voice * unit + (y + 1) / 2) / scw * 2 - 1; + } + else + { + double ph = (double)(lfo.phase + lfo.vphase * voice) / 4096.0; + x = 0.5 + 0.5 * sin(ph * 2 * M_PI); + y = subindex & 1 ? -0.75 : 0.75; + x = (voice * unit + x) / scw; + } + return true; +} + +bool multichorus_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const +{ + if (index == par_rate && !subindex) + { + pos = 0; + vertical = false; + return true; + } + if (index == par_delay) + return get_freq_gridline(subindex, pos, vertical, legend, context); + return false; +} + +float multichorus_audio_module::freq_gain(int subindex, float freq, float srate) const +{ + if (subindex == 2) + return *params[par_amount] * left.post.freq_gain(freq, srate); + return (subindex ? right : left).freq_gain(freq, srate); +} + +void multichorus_audio_module::params_changed() +{ + // delicious copy-pasta from flanger module - it'd be better to keep it common or something + float dry = *params[par_dryamount]; + float wet = *params[par_amount]; + float rate = *params[par_rate]; + float min_delay = *params[par_delay] / 1000.0; + float mod_depth = *params[par_depth] / 1000.0; + float overlap = *params[par_overlap]; + left.set_dry(dry); right.set_dry(dry); + left.set_wet(wet); right.set_wet(wet); + left.set_rate(rate); right.set_rate(rate); + left.set_min_delay(min_delay); right.set_min_delay(min_delay); + left.set_mod_depth(mod_depth); right.set_mod_depth(mod_depth); + int voices = (int)*params[par_voices]; + left.lfo.set_voices(voices); right.lfo.set_voices(voices); + left.lfo.set_overlap(overlap);right.lfo.set_overlap(overlap); + float vphase = *params[par_vphase] * (1.f / 360.f); + left.lfo.vphase = right.lfo.vphase = vphase * (4096 / std::max(voices - 1, 1)); + float r_phase = *params[par_stereo] * (1.f / 360.f); + if (fabs(r_phase - last_r_phase) > 0.0001f) { + right.lfo.phase = left.lfo.phase; + right.lfo.phase += chorus_phase(r_phase * 4096); + last_r_phase = r_phase; + } + left.post.f1.set_bp_rbj(*params[par_freq], *params[par_q], srate); + left.post.f2.set_bp_rbj(*params[par_freq2], *params[par_q], srate); + right.post.f1.copy_coeffs(left.post.f1); + right.post.f2.copy_coeffs(left.post.f2); +} + +uint32_t multichorus_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) +{ + left.process(outs[0] + offset, ins[0] + offset, numsamples); + right.process(outs[1] + offset, ins[1] + offset, numsamples); + return outputs_mask; // XXXKF allow some delay after input going blank +} + +/// Pulsator by Markus Schmidt +/// +/// This module provides a couple +/// of different LFO's for modulating the level of a signal. +/////////////////////////////////////////////////////////////////////////////////////////////// + +pulsator_audio_module::pulsator_audio_module() +{ + is_active = false; + srate = 0; +// last_generation = 0; + 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 pulsator_audio_module::activate() +{ + is_active = true; + lfoL.activate(); + lfoR.activate(); + params_changed(); +} +void pulsator_audio_module::deactivate() +{ + is_active = false; + lfoL.deactivate(); + lfoR.deactivate(); +} + +void pulsator_audio_module::params_changed() +{ + lfoL.set_params(*params[param_freq], *params[param_mode], 0.f, srate, *params[param_amount]); + lfoR.set_params(*params[param_freq], *params[param_mode], *params[param_offset], srate, *params[param_amount]); + clear_reset = false; + if (*params[param_reset] >= 0.5) { + clear_reset = true; + lfoL.set_phase(0.f); + lfoR.set_phase(0.f); + } +} + +void pulsator_audio_module::set_sample_rate(uint32_t sr) +{ + srate = sr; +} + +uint32_t pulsator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) +{ + bool bypass = *params[param_bypass] > 0.5f; + uint32_t samples = numsamples + offset; + if(bypass) { + // everything bypassed + while(offset < samples) { + 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; + + // LFO's should go on + lfoL.advance(numsamples); + lfoR.advance(numsamples); + + } else { + + 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; + + // process + while(offset < samples) { + // cycle through samples + float outL = 0.f; + float outR = 0.f; + float inL = ins[0][offset]; + float inR = ins[1][offset]; + // in level + inR *= *params[param_level_in]; + inL *= *params[param_level_in]; + + if(*params[param_mono] > 0.5) { + inL = (inL + inR) * 0.5; + inR = inL; + } + float procL = inL; + float procR = inR; + + procL *= (lfoL.get_value() * 0.5 + *params[param_amount] / 2); + procR *= (lfoR.get_value() * 0.5 + *params[param_amount] / 2); + + outL = procL + inL * (1 - *params[param_amount]); + outR = procR + inR * (1 - *params[param_amount]); + + 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; + + // advance lfo's + lfoL.advance(1); + lfoR.advance(1); + } // cycle trough samples + } + // 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) + // whatever has to be returned x) + return outputs_mask; +} + +bool pulsator_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const +{ + if (!is_active) { + return false; + } else if(index == param_freq) { + if(subindex == 0) { + context->set_source_rgba(0.35, 0.4, 0.2, 1); + return lfoL.get_graph(data, points, context); + } + if(subindex == 1) { + context->set_source_rgba(0.35, 0.4, 0.2, 0.5); + return lfoR.get_graph(data, points, context); + } + } + return false; +} + +bool pulsator_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const +{ + if (!is_active) { + return false; + } else if(index == param_freq) { + if(subindex == 0) { + context->set_source_rgba(0.35, 0.4, 0.2, 1); + return lfoL.get_dot(x, y, size, context); + } + if(subindex == 1) { + context->set_source_rgba(0.35, 0.4, 0.2, 0.5); + return lfoR.get_dot(x, y, size, context); + } + return false; + } + return false; +} + +bool pulsator_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const +{ + if (index == param_freq && !subindex) + { + pos = 0; + vertical = false; + return true; + } + return false; +} diff --git a/plugins/ladspa_effect/calf/src/monosynth.cpp b/plugins/ladspa_effect/calf/src/monosynth.cpp index 6d76134ad..a2d124843 100644 --- a/plugins/ladspa_effect/calf/src/monosynth.cpp +++ b/plugins/ladspa_effect/calf/src/monosynth.cpp @@ -18,12 +18,6 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#include -#include -#include -#if USE_JACK -#include -#endif #include #include @@ -38,8 +32,10 @@ static const char *monosynth_mod_src_names[] = { "Velocity", "Pressure", "ModWheel", - "Envelope", - "LFO", + "Envelope 1", + "Envelope 2", + "LFO 1", + "LFO 2", NULL }; @@ -53,6 +49,7 @@ static const char *monosynth_mod_dest_names[] = { "O2: Detune [ct]", "O1: PW (%)", "O2: PW (%)", + "O1: Stretch", NULL }; @@ -79,6 +76,7 @@ void monosynth_audio_module::activate() { filter2.reset(); stack.clear(); last_pwshift1 = last_pwshift2 = 0; + last_stretch1 = 65536; } waveform_family *monosynth_audio_module::waves; @@ -226,7 +224,12 @@ bool monosynth_audio_module::get_graph(int index, int subindex, float *data, int wave = wave_saw; float *waveform = waves[wave].original; for (int i = 0; i < points; i++) - data[i] = (sign * waveform[i * S / points] + waveform[(i * S / points + shift) & (S - 1)]) / (sign == -1 ? 1 : 2); + { + int pos = i * S / points; + if (index == par_wave1) + pos = int(pos * 1.0 * last_stretch1 / 65536.0 ) % S; + data[i] = (sign * waveform[pos] + waveform[(pos + shift) & (S - 1)]) / (sign == -1 ? 1 : 2); + } return true; } if (index == par_filtertype) { @@ -252,19 +255,24 @@ bool monosynth_audio_module::get_graph(int index, int subindex, float *data, int return get_static_graph(index, subindex, *params[index], data, points, context); } -void monosynth_audio_module::calculate_buffer_oscs(float lfo) +void monosynth_audio_module::calculate_buffer_oscs(float lfo1) { int flag1 = (wave1 == wave_sqr); int flag2 = (wave2 == wave_sqr); + int32_t shift1 = last_pwshift1; int32_t shift2 = last_pwshift2; - int32_t shift_target1 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw1] + lfo * *params[par_lfopw] + 0.01f * moddest[moddest_o1pw])); - int32_t shift_target2 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw2] + lfo * *params[par_lfopw] + 0.01f * moddest[moddest_o2pw])); + int32_t stretch1 = last_stretch1; + int32_t shift_target1 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw1] + lfo1 * *params[par_lfopw] + 0.01f * moddest[moddest_o1pw])); + int32_t shift_target2 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw2] + lfo1 * *params[par_lfopw] + 0.01f * moddest[moddest_o2pw])); + int32_t stretch_target1 = (int32_t)(65536 * dsp::clip(*params[par_stretch1] + 0.01f * moddest[moddest_o1stretch], 1.f, 16.f)); int32_t shift_delta1 = ((shift_target1 >> 1) - (last_pwshift1 >> 1)) >> (step_shift - 1); int32_t shift_delta2 = ((shift_target2 >> 1) - (last_pwshift2 >> 1)) >> (step_shift - 1); - last_lfov = lfo; + int32_t stretch_delta1 = ((stretch_target1 >> 1) - (last_stretch1 >> 1)) >> (step_shift - 1); last_pwshift1 = shift_target1; last_pwshift2 = shift_target2; + last_stretch1 = stretch_target1; + lookup_waveforms(); shift1 += (flag1 << 31); shift2 += (flag2 << 31); @@ -276,12 +284,13 @@ void monosynth_audio_module::calculate_buffer_oscs(float lfo) for (uint32_t i = 0; i < step_size; i++) { - float osc1val = osc1.get_phaseshifted(shift1, mix1); - float osc2val = osc2.get_phaseshifted(shift2, mix2); - float wave = osc1val + (osc2val - osc1val) * cur_xfade; - buffer[i] = wave; + //buffer[i] = lerp(osc1.get_phaseshifted(shift1, mix1), osc2.get_phaseshifted(shift2, mix2), cur_xfade); + buffer[i] = lerp(osc1.get_phasedist(stretch1, shift1, mix1), osc2.get_phaseshifted(shift2, mix2), cur_xfade); + osc1.advance(); + osc2.advance(); shift1 += shift_delta1; shift2 += shift_delta2; + stretch1 += stretch_delta1; cur_xfade += xfade_step; } last_xfade = new_xfade; @@ -329,7 +338,7 @@ void monosynth_audio_module::calculate_buffer_stereo() void monosynth_audio_module::lookup_waveforms() { - osc1.waveform = waves[wave1 == wave_sqr ? wave_saw : wave1].get_level(osc1.phasedelta); + osc1.waveform = waves[wave1 == wave_sqr ? wave_saw : wave1].get_level((uint32_t)(((uint64_t)osc1.phasedelta) * last_stretch1 >> 16)); osc2.waveform = waves[wave2 == wave_sqr ? wave_saw : wave2].get_level(osc2.phasedelta); if (!osc1.waveform) osc1.waveform = silence; if (!osc2.waveform) osc2.waveform = silence; @@ -349,7 +358,6 @@ void monosynth_audio_module::delayed_note_on() fltctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2filter]; set_frequency(); lookup_waveforms(); - lfo_clock = 0.f; if (!running) { @@ -360,7 +368,16 @@ void monosynth_audio_module::delayed_note_on() osc2.reset(); filter.reset(); filter2.reset(); - lfo.reset(); + if (*params[par_lfo1trig] <= 0) + { + lfo1.reset(); + lfo1_clock = 0.f; + } + if (*params[par_lfo2trig] <= 0) + { + lfo2.reset(); + lfo2_clock = 0.f; + } switch((int)*params[par_oscmode]) { case 1: @@ -384,19 +401,22 @@ void monosynth_audio_module::delayed_note_on() default: break; } - envelope.note_on(); + envelope1.note_on(); + envelope2.note_on(); running = true; } if (legato >= 2 && !gate) porta_time = -1.f; gate = true; stopping = false; - if (!(legato & 1) || envelope.released()) { - envelope.note_on(); + if (!(legato & 1) || (envelope1.released() && envelope2.released())) { + envelope1.note_on(); + envelope2.note_on(); } - envelope.advance(); + envelope1.advance(); + envelope2.advance(); queue_note_on = -1; - float modsrc[modsrc_count] = { 1, velocity, inertia_pressure.get_last(), modwheel_value, 0, 0.5+0.5*last_lfov}; + float modsrc[modsrc_count] = { 1, velocity, inertia_pressure.get_last(), modwheel_value, 0, 0.5+0.5*lfo1.last, 0.5+0.5*lfo2.last}; calculate_modmatrix(moddest, moddest_count, modsrc); } @@ -421,10 +441,12 @@ void monosynth_audio_module::calculate_step() dsp::zero(buffer, step_size); if (is_stereo_filter()) dsp::zero(buffer2, step_size); - envelope.advance(); + envelope1.advance(); + envelope2.advance(); return; } - lfo.set_freq(*params[par_lforate], crate); + lfo1.set_freq(*params[par_lforate], crate); + lfo2.set_freq(*params[par_lfo2rate], crate); float porta_total_time = *params[par_portamento] * 0.001f; if (porta_total_time >= 0.00101f && porta_time >= 0) { @@ -439,30 +461,34 @@ void monosynth_audio_module::calculate_step() porta_time += odcr; } } - float lfov = lfo.get() * std::min(1.0f, lfo_clock / *params[par_lfodelay]); - lfov = lfov * dsp::lerp(1.f, modwheel_value, *params[par_mwhl_lfo]); + float lfov1 = lfo1.get() * std::min(1.0f, lfo_clock / *params[par_lfodelay]); + lfov1 = lfov1 * dsp::lerp(1.f, modwheel_value, *params[par_mwhl_lfo]); + float lfov2 = lfo2.get() * std::min(1.0f, lfo_clock / *params[par_lfo2delay]); lfo_clock += odcr; if (fabs(*params[par_lfopitch]) > small_value()) - lfo_bend = pow(2.0f, *params[par_lfopitch] * lfov * (1.f / 1200.0f)); + lfo_bend = pow(2.0f, *params[par_lfopitch] * lfov1 * (1.f / 1200.0f)); inertia_pitchbend.step(); set_frequency(); - envelope.advance(); - float env = envelope.value; + envelope1.advance(); + envelope2.advance(); + float env1 = envelope1.value, env2 = envelope2.value; + float aenv1 = envelope1.get_amp_value(), aenv2 = envelope2.get_amp_value(); // mod matrix // this should be optimized heavily; I think I'll do it when MIDI in Ardour 3 gets stable :> - float modsrc[modsrc_count] = { 1, velocity, inertia_pressure.get(), modwheel_value, env, 0.5+0.5*lfov}; + 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); inertia_cutoff.set_inertia(*params[par_cutoff]); - cutoff = inertia_cutoff.get() * pow(2.0f, (lfov * *params[par_lfofilter] + env * fltctl * *params[par_envmod] + moddest[moddest_cutoff]) * (1.f / 1200.f)); + 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) cutoff *= pow(freq / 264.f, *params[par_keyfollow]); cutoff = dsp::clip(cutoff , 10.f, 18000.f); float resonance = *params[par_resonance]; - float e2r = *params[par_envtores]; - float e2a = *params[par_envtoamp]; - resonance = resonance * (1 - e2r) + (0.7 + (resonance - 0.7) * env * env) * e2r + moddest[moddest_resonance]; + float e2r1 = *params[par_env1tores]; + resonance = resonance * (1 - e2r1) + (0.7 + (resonance - 0.7) * env1 * env1) * e2r1; + float e2r2 = *params[par_env2tores]; + resonance = resonance * (1 - e2r2) + (0.7 + (resonance - 0.7) * env2 * env2) * e2r2 + moddest[moddest_resonance]; float cutoff2 = dsp::clip(cutoff * separation, 10.f, 18000.f); float newfgain = 0.f; if (filter_type != last_filter_type) @@ -514,13 +540,18 @@ void monosynth_audio_module::calculate_step() newfgain = ampctl; break; } - float aenv = env; - if (*params[par_envtoamp] > 0.f) - newfgain *= 1.0 - (1.0 - aenv) * e2a; + float e2a1 = *params[par_env1toamp]; + float e2a2 = *params[par_env2toamp]; + if (e2a1 > 0.f) + newfgain *= 1.0 - (1.0 - aenv1) * e2a1; + if (e2a2 > 0.f) + newfgain *= 1.0 - (1.0 - aenv2) * e2a2; if (moddest[moddest_attenuation] != 0.f) newfgain *= dsp::clip(1 - moddest[moddest_attenuation] * moddest[moddest_attenuation], 0.f, 1.f); fgain_delta = (newfgain - fgain) * (1.0 / step_size); - calculate_buffer_oscs(lfov); + calculate_buffer_oscs(lfov1); + lfo1.last = lfov1; + lfo2.last = lfov2; switch(filter_type) { case flt_lp24: @@ -538,7 +569,8 @@ void monosynth_audio_module::calculate_step() calculate_buffer_stereo(); break; } - if ((envelope.state == adsr::STOP && !gate) || force_fadeout || (envelope.state == adsr::RELEASE && *params[par_envtoamp] <= 0.f)) + bool no_amp_env = *params[par_env1toamp] <= 0.f && *params[par_env2toamp] <= 0.f; + if ((envelope1.state == adsr::STOP && envelope2.state == adsr::STOP && !gate) || force_fadeout || (envelope1.state == adsr::RELEASE && no_amp_env) || (envelope2.state == adsr::RELEASE && no_amp_env)) { enum { ramp = step_size * 4 }; for (int i = 0; i < step_size; i++) @@ -573,14 +605,16 @@ void monosynth_audio_module::note_off(int note, int vel) porta_time = 0; set_frequency(); if (!(legato & 1)) { - envelope.note_on(); + envelope1.note_on(); + envelope2.note_on(); stopping = false; running = true; } return; } gate = false; - envelope.note_off(); + envelope1.note_off(); + envelope2.note_off(); } } @@ -607,7 +641,8 @@ void monosynth_audio_module::control_change(int controller, int value) case 123: // all notes off gate = false; queue_note_on = -1; - envelope.note_off(); + envelope1.note_off(); + envelope2.note_off(); stack.clear(); break; } @@ -618,7 +653,8 @@ void monosynth_audio_module::deactivate() gate = false; running = false; stopping = false; - envelope.reset(); + envelope1.reset(); + envelope2.reset(); stack.clear(); } @@ -640,9 +676,9 @@ void monosynth_audio_module::set_frequency() void monosynth_audio_module::params_changed() { float sf = 0.001f; - envelope.set(*params[par_attack] * sf, *params[par_decay] * sf, std::min(0.999f, *params[par_sustain]), *params[par_release] * sf, srate / step_size, *params[par_fade] * sf); + envelope1.set(*params[par_env1attack] * sf, *params[par_env1decay] * sf, std::min(0.999f, *params[par_env1sustain]), *params[par_env1release] * sf, srate / step_size, *params[par_env1fade] * sf); + envelope2.set(*params[par_env2attack] * sf, *params[par_env2decay] * sf, std::min(0.999f, *params[par_env2sustain]), *params[par_env2release] * sf, srate / step_size, *params[par_env2fade] * sf); filter_type = dsp::fastf2i_drm(*params[par_filtertype]); - decay_factor = odcr * 1000.0 / *params[par_decay]; separation = pow(2.0, *params[par_cutoffsep] / 1200.0); wave1 = dsp::clip(dsp::fastf2i_drm(*params[par_wave1]), 0, (int)wave_count - 1); wave2 = dsp::clip(dsp::fastf2i_drm(*params[par_wave2]), 0, (int)wave_count - 1); @@ -661,7 +697,10 @@ uint32_t monosynth_audio_module::process(uint32_t offset, uint32_t nsamples, uin { if (!running && queue_note_on == -1) { for (uint32_t i = 0; i < nsamples / step_size; i++) - envelope.advance(); + { + envelope1.advance(); + envelope2.advance(); + } return 0; } uint32_t op = offset; @@ -671,7 +710,8 @@ uint32_t monosynth_audio_module::process(uint32_t offset, uint32_t nsamples, uin if (running || queue_note_on != -1) calculate_step(); else { - envelope.advance(); + envelope1.advance(); + envelope2.advance(); dsp::zero(buffer, step_size); } } diff --git a/plugins/ladspa_effect/calf/src/organ.cpp b/plugins/ladspa_effect/calf/src/organ.cpp index 3d1b7eed1..b28cbaaa1 100644 --- a/plugins/ladspa_effect/calf/src/organ.cpp +++ b/plugins/ladspa_effect/calf/src/organ.cpp @@ -18,15 +18,10 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ +#include -#include -#include -#include -#if USE_JACK -#include -#endif #include -#include +#include #include using namespace std; @@ -35,7 +30,50 @@ using namespace calf_plugins; ////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool organ_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) +organ_audio_module::organ_audio_module() +: drawbar_organ(&par_values) +{ + var_map_curve = "2\n0 1\n1 1\n"; // XXXKF hacky bugfix +} + +void organ_audio_module::activate() +{ + setup(srate); + panic_flag = false; +} + +void organ_audio_module::post_instantiate() +{ + dsp::organ_voice_base::precalculate_waves(progress_report); +} + + +uint32_t organ_audio_module::process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) +{ + float *o[2] = { outs[0] + offset, outs[1] + offset }; + if (panic_flag) + { + control_change(120, 0); // stop all sounds + control_change(121, 0); // reset all controllers + panic_flag = false; + } + render_separate(o, nsamples); + return 3; +} + +void organ_audio_module::params_changed() { + for (int i = 0; i < param_count - var_count; i++) + ((float *)&par_values)[i] = *params[i]; + + unsigned int old_poly = polyphony_limit; + polyphony_limit = dsp::clip(dsp::fastf2i_drm(*params[par_polyphony]), 1, 32); + if (polyphony_limit < old_poly) + trim_voices(); + + update_params(); +} + +bool organ_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const { if (index == par_master) { organ_voice_base::precalculate_waves(progress_report); @@ -74,6 +112,13 @@ bool organ_audio_module::get_graph(int index, int subindex, float *data, int poi return false; } +uint32_t organ_audio_module::message_run(const void *valid_inputs, void *output_ports) +{ + // silence a default printf (which is kind of a warning about unhandled message_run) + return 0; +} + + //////////////////////////////////////////////////////////////////////////// organ_voice_base::small_wave_family (*organ_voice_base::waves)[organ_voice_base::wave_count_small]; @@ -192,6 +237,12 @@ static void padsynth(bandlimiter blSrc, bandlimiterreport_progress(floor(progress / totalwaves), "Precalculating large waveforms"); } } while(0) +void organ_voice_base::update_pitch() +{ + float phase = dsp::midi_note_to_phase(note, 100 * parameters->global_transpose + parameters->global_detune, sample_rate_ref); + dpphase.set((long int) (phase * parameters->percussion_harmonic * parameters->pitch_bend)); + moddphase.set((long int) (phase * parameters->percussion_fm_harmonic * parameters->pitch_bend)); +} void organ_voice_base::precalculate_waves(progress_report_iface *reporter) { @@ -502,6 +553,17 @@ void organ_voice_base::render_percussion_to(float (*buf)[2], int nsamples) } } +void organ_voice_base::perc_reset() +{ + pphase = 0; + modphase = 0; + dpphase = 0; + moddphase = 0; + note = -1; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// + void organ_vibrato::reset() { for (int i = 0; i < VibratoSize; i++) @@ -549,6 +611,8 @@ void organ_vibrato::process(organ_parameters *parameters, float (*data)[2], unsi } } +////////////////////////////////////////////////////////////////////////////////////////////////////// + void organ_voice::update_pitch() { organ_voice_base::update_pitch(); @@ -730,8 +794,64 @@ void organ_voice::render_block() { if (use_percussion()) render_percussion_to(output_buffer, BlockSize); + } +void organ_voice::note_on(int note, int vel) +{ + stolen = false; + finishing = false; + perc_released = false; + released = false; + reset(); + this->note = note; + const float sf = 0.001f; + for (int i = 0; i < EnvCount; i++) + { + organ_parameters::organ_env_parameters &p = parameters->envs[i]; + envs[i].set(sf * p.attack, sf * p.decay, p.sustain, sf * p.release, sample_rate / BlockSize); + envs[i].note_on(); + } + update_pitch(); + velocity = vel * 1.0 / 127.0; + amp.set(1.0f); + perc_note_on(note, vel); +} + +void organ_voice::note_off(int /* vel */) +{ + // reset age to 0 (because decay will turn from exponential to linear, necessary because of error cumulation prevention) + perc_released = true; + if (pamp.get_active()) + { + pamp.reinit(); + } + rel_age_const = pamp.get() * ((1.0/44100.0)/0.03); + for (int i = 0; i < EnvCount; i++) + envs[i].note_off(); +} + +void organ_voice::steal() +{ + perc_released = true; + finishing = true; + stolen = true; +} + +void organ_voice::reset() +{ + inertia_pitchbend.ramp.set_length(sample_rate / (BlockSize * 30)); // 1/30s + vibrato.reset(); + phase = 0; + for (int i = 0; i < FilterCount; i++) + { + filterL[i].reset(); + filterR[i].reset(); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + void drawbar_organ::update_params() { parameters->perc_decay_const = dsp::decay::calc_exp_constant(1.0 / 1024.0, 0.001 * parameters->percussion_time * sample_rate); @@ -745,6 +865,42 @@ void drawbar_organ::update_params() parameters->foldvalue = (int)(dphase); } +dsp::voice *drawbar_organ::alloc_voice() +{ + block_voice *v = new block_voice(); + v->parameters = parameters; + return v; +} + +void drawbar_organ::percussion_note_on(int note, int vel) +{ + percussion.perc_note_on(note, vel); +} + +void drawbar_organ::setup(int sr) +{ + basic_synth::setup(sr); + percussion.setup(sr); + parameters->cutoff = 0; + params_changed(); + global_vibrato.reset(); +} + +bool drawbar_organ::check_percussion() { + switch(dsp::fastf2i_drm(parameters->percussion_trigger)) + { + case organ_voice_base::perctrig_first: + return active_voices.empty(); + case organ_voice_base::perctrig_each: + default: + return true; + case organ_voice_base::perctrig_eachplus: + return !percussion.get_noticable(); + case organ_voice_base::perctrig_polyphonic: + return false; + } +} + void drawbar_organ::pitch_bend(int amt) { parameters->pitch_bend = pow(2.0, (amt * parameters->pitch_bend_range) / (1200.0 * 8192.0)); diff --git a/plugins/ladspa_effect/calf/src/plugin.cpp b/plugins/ladspa_effect/calf/src/plugin.cpp index 2467d5348..9a4b97615 100644 --- a/plugins/ladspa_effect/calf/src/plugin.cpp +++ b/plugins/ladspa_effect/calf/src/plugin.cpp @@ -1,7 +1,7 @@ -/* Calf DSP Library - * Example audio modules - LADSPA/DSSI/LV2 wrapper instantiation +/* Calf DSP plugin pack + * LADSPA/DSSI/LV2 wrapper instantiation for all plugins * - * Copyright (C) 2001-2008 Krzysztof Foltman + * Copyright (C) 2001-2010 Krzysztof Foltman * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,35 +18,467 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ +#include #include #include #include +#include #include +#include +#include +#include +#include +#include +#include using namespace calf_plugins; +using namespace osctl; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if USE_LADSPA -template -LADSPA_Descriptor ladspa_wrapper::descriptor; -template -LADSPA_Descriptor ladspa_wrapper::descriptor_for_dssi; +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->real_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->real_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 -template -DSSI_Descriptor ladspa_wrapper::dssi_descriptor; +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); +} -template -DSSI_Program_Descriptor ladspa_wrapper::dssi_default_program; - -template -std::vector *ladspa_wrapper::presets; - -template -std::vector *ladspa_wrapper::preset_descs; #endif + +char *ladspa_instance::configure(const char *key, const char *value) +{ +#if USE_DSSI + 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.note, event.data.note.velocity); + break; + case SND_SEQ_EVENT_NOTEOFF: + module->note_off(event.data.note.note, event.data.note.velocity); + break; + case SND_SEQ_EVENT_PGMCHANGE: + module->program_change(event.data.control.value); + break; + case SND_SEQ_EVENT_CONTROLLER: + module->control_change(event.data.control.param, event.data.control.value); + break; + case SND_SEQ_EVENT_PITCHBEND: + module->pitch_bend(event.data.control.value); + break; + case SND_SEQ_EVENT_CHANPRESS: + module->channel_pressure(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->real_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->real_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(); + real_param_count = 0; + while(real_param_count < md->get_param_count() && (metadata->get_param_props(real_param_count)->flags & PF_TYPEMASK) < PF_STRING) + 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 + real_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 + real_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 + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if USE_LV2 // instantiate descriptor templates @@ -94,3 +526,17 @@ const DSSI_Descriptor *dssi_descriptor(unsigned long Index) #endif +#if USE_JACK + +extern "C" { + +audio_module_iface *create_calf_plugin_by_name(const char *effect_name) +{ + #define PER_MODULE_ITEM(name, isSynth, jackname) if (!strcasecmp(effect_name, jackname)) return new name##_audio_module; + #include + return NULL; +} + +} + +#endif diff --git a/plugins/ladspa_effect/calf/src/synth.cpp b/plugins/ladspa_effect/calf/src/synth.cpp index 633650e31..fcda18b22 100644 --- a/plugins/ladspa_effect/calf/src/synth.cpp +++ b/plugins/ladspa_effect/calf/src/synth.cpp @@ -18,12 +18,6 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#include -#include -#if USE_JACK -#include -#endif -#include #include using namespace dsp; @@ -176,8 +170,6 @@ void basic_synth::control_change(int ctl, int val) } } if (ctl == 123 || ctl == 120) { // all notes off, all sounds off - vector notes; - notes.reserve(128); if (ctl == 120) { // for "all sounds off", automatically release hold and sostenuto pedal control_change(66, 0); control_change(64, 0); diff --git a/plugins/ladspa_effect/calf/src/utils.cpp b/plugins/ladspa_effect/calf/src/utils.cpp index 837698732..d661c914f 100644 --- a/plugins/ladspa_effect/calf/src/utils.cpp +++ b/plugins/ladspa_effect/calf/src/utils.cpp @@ -17,10 +17,10 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#include -#include +#include #include #include +#include #include using namespace std; @@ -134,4 +134,22 @@ std::string indent(const std::string &src, const std::string &indent) return dest; } +////////////////////////////////////////////////////////////////////////////////// + +file_exception::file_exception(const std::string &f) +: message(strerror(errno)) +, filename(f) +, container(filename + ":" + message) +{ + text = container.c_str(); +} + +file_exception::file_exception(const std::string &f, const std::string &t) +: message(t) +, filename(f) +, container(filename + ":" + message) +{ + text = container.c_str(); +} + }