Merge branch 'calf-updates'
* calf-updates: CALF: rebased to CALF master branch Moved CALF headers to proper location
This commit is contained in:
@@ -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 "")
|
||||
|
||||
@@ -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 <ladspa.h>
|
||||
#if USE_DSSI
|
||||
#include <dssi.h>
|
||||
#endif
|
||||
#include "giface.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
template<class Module>
|
||||
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<class Module>
|
||||
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<Module>();
|
||||
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<const line_graph_iface *>(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<line_graph_iface *>(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<class Module>
|
||||
struct ladspa_wrapper
|
||||
{
|
||||
typedef ladspa_instance<Module> 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<plugin_preset> *presets;
|
||||
static std::vector<DSSI_Program_Descriptor> *preset_descs;
|
||||
#endif
|
||||
|
||||
ladspa_wrapper()
|
||||
{
|
||||
int ins = Module::in_count;
|
||||
int outs = Module::out_count;
|
||||
int params = ladspa_instance<Module>::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<plugin_preset>;
|
||||
preset_descs = new std::vector<DSSI_Program_Descriptor>;
|
||||
|
||||
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<Module>::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<Module>::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; i<Module::out_count; i++) {
|
||||
if ((mask & (1 << i)) == 0) {
|
||||
dsp::zero(module->outs[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
|
||||
@@ -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 <calf/lv2_event.h>
|
||||
#include <calf/lv2_uri_map.h>
|
||||
|
||||
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 T>
|
||||
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 T>
|
||||
class midi_mixin: public virtual event_mixin<T>
|
||||
{
|
||||
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<T>::map_uris();
|
||||
}
|
||||
};
|
||||
|
||||
/// A mixin for adding the URI map and MIDI event type retrieval to small plugins
|
||||
template<class T>
|
||||
class message_mixin: public virtual event_mixin<T>
|
||||
{
|
||||
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<T>::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 Iter1, class Iter2>
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
532
plugins/ladspa_effect/calf/src/audio_fx.cpp
Normal file
532
plugins/ladspa_effect/calf/src/audio_fx.cpp
Normal file
@@ -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 <calf/audio_fx.h>
|
||||
#include <calf/giface.h>
|
||||
|
||||
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<float>(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<nsamples; i++) {
|
||||
cnt++;
|
||||
if (cnt == 32)
|
||||
control_step();
|
||||
float in = *buf_in++;
|
||||
float fd = in + state * fb;
|
||||
for (int j = 0; j < stages; j++)
|
||||
fd = stage1.process_ap(fd, x1[j], y1[j]);
|
||||
state = fd;
|
||||
|
||||
float sdry = in * gs_dry.get();
|
||||
float swet = fd * gs_wet.get();
|
||||
*buf_out++ = sdry + swet;
|
||||
}
|
||||
}
|
||||
|
||||
float simple_phaser::freq_gain(float freq, float sr) const
|
||||
{
|
||||
typedef std::complex<double> 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<float> *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<int, 14, 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;
|
||||
}
|
||||
|
||||
@@ -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 <complex>
|
||||
#include <iostream>
|
||||
#include <calf/biquad.h>
|
||||
#include <calf/onepole.h>
|
||||
#include "primitives.h"
|
||||
#include "biquad.h"
|
||||
#include "delay.h"
|
||||
#include "fixed_point.h"
|
||||
#include "inertia.h"
|
||||
#include "onepole.h"
|
||||
#include <complex>
|
||||
|
||||
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<int MaxStages>
|
||||
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<float, float> 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<float>(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<nsamples; i++) {
|
||||
cnt++;
|
||||
if (cnt == 32)
|
||||
control_step();
|
||||
float in = *buf_in++;
|
||||
float fd = in + state * fb;
|
||||
for (int j = 0; j < stages; j++)
|
||||
fd = stage1.process_ap(fd, x1[j], y1[j]);
|
||||
state = fd;
|
||||
|
||||
float sdry = in * gs_dry.get();
|
||||
float swet = fd * gs_wet.get();
|
||||
*buf_out++ = sdry + swet;
|
||||
}
|
||||
}
|
||||
float freq_gain(float freq, float sr) const
|
||||
{
|
||||
typedef std::complex<double> 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 T>
|
||||
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<unsigned int, 25> phase, dphase;
|
||||
sine_table<int, 128, 10000> sine;
|
||||
onepole<T> lp_left, lp_right;
|
||||
T old_left, old_right;
|
||||
onepole<float> 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<int, 14, 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<float> *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
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
@@ -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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <config.h>
|
||||
#include "primitives.h"
|
||||
#include <complex>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <complex>
|
||||
#include "primitives.h"
|
||||
#include "preset.h"
|
||||
#include <vector>
|
||||
|
||||
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_metadata_iface *> plugin_vector;
|
||||
typedef std::vector<const plugin_metadata_iface *> 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 Metadata>
|
||||
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<Metadata::out_count; i++) {
|
||||
if ((mask & (1 << i)) == 0) {
|
||||
dsp::zero(outs[i] + offset, nsamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// utility function: call process, and if it returned zeros in output masks, zero out the relevant output port buffers
|
||||
void process_slice(uint32_t offset, uint32_t end)
|
||||
{
|
||||
while(offset < end)
|
||||
{
|
||||
uint32_t newend = std::min(offset + MAX_SAMPLE_RUN, end);
|
||||
uint32_t out_mask = process(offset, newend - offset, -1, -1);
|
||||
zero_by_mask(out_mask, offset, newend - offset);
|
||||
offset = newend;
|
||||
}
|
||||
}
|
||||
/// @return line_graph_iface if any
|
||||
virtual const line_graph_iface *get_line_graph_iface() const { return dynamic_cast<const line_graph_iface *>(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<int> 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 Metadata>
|
||||
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> 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<const line_graph_iface *>(this); }
|
||||
const table_edit_iface *get_table_edit_iface() const { return dynamic_cast<const table_edit_iface *>(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<int> &ports) const { impl->get_message_context_parameters(ports); }
|
||||
};
|
||||
|
||||
#define CALF_PORT_NAMES(name) template<> const char *::plugin_metadata<name##_metadata>::port_names[]
|
||||
#define CALF_PORT_PROPS(name) template<> parameter_properties plugin_metadata<name##_metadata>::param_props[]
|
||||
#define CALF_PLUGIN_INFO(name) template<> calf_plugins::ladspa_plugin_info plugin_metadata<name##_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
|
||||
130
plugins/ladspa_effect/calf/src/calf/ladspa_wrap.h
Normal file
130
plugins/ladspa_effect/calf/src/calf/ladspa_wrap.h
Normal file
@@ -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 <string.h>
|
||||
#include <ladspa.h>
|
||||
#if USE_DSSI
|
||||
#include <dssi.h>
|
||||
#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<plugin_preset> *presets;
|
||||
std::vector<DSSI_Program_Descriptor> *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<class Module>
|
||||
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
|
||||
30
plugins/ladspa_effect/calf/src/calf/lv2helpers.h
Normal file
30
plugins/ladspa_effect/calf/src/calf/lv2helpers.h
Normal file
@@ -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 <calf/lv2_event.h>
|
||||
#include <calf/lv2_uri_map.h>
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -33,12 +33,14 @@
|
||||
#include <calf/lv2_progress.h>
|
||||
#include <calf/lv2_string_port.h>
|
||||
#include <calf/lv2_uri_map.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
template<class Module>
|
||||
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<int> 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<const line_graph_iface *>(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<class Module>
|
||||
struct lv2_wrapper
|
||||
{
|
||||
typedef lv2_instance<Module> 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; i<Module::out_count; i++) {
|
||||
if ((mask & (1 << i)) == 0) {
|
||||
dsp::zero(module->outs[i] + offset, nsamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
static plugin_ctl_iface *cb_get_pci(LV2_Handle Instance)
|
||||
{
|
||||
return static_cast<plugin_ctl_iface *>(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;
|
||||
@@ -70,7 +70,7 @@ struct reverb_metadata: public plugin_metadata<reverb_metadata>
|
||||
|
||||
struct vintage_delay_metadata: public plugin_metadata<vintage_delay_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<monosynth_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<monosynth_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<monosynth_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<pulsator_metadata>
|
||||
PLUGIN_NAME_ID_LABEL("pulsator", "pulsator", "Pulsator")
|
||||
};
|
||||
|
||||
/// Markus's Saturator - metadata
|
||||
struct saturator_metadata: public plugin_metadata<saturator_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<exciter_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<bassenhancer_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<gate_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<organ_metadata
|
||||
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
|
||||
PLUGIN_NAME_ID_LABEL("organ", "organ", "Organ")
|
||||
plugin_command_info *get_commands();
|
||||
const char **get_default_configure_vars();
|
||||
};
|
||||
|
||||
/// FluidSynth - metadata
|
||||
struct fluidsynth_metadata: public plugin_metadata<fluidsynth_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
|
||||
@@ -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")
|
||||
245
plugins/ladspa_effect/calf/src/calf/modules.h
Normal file
245
plugins/ladspa_effect/calf/src/calf/modules.h
Normal file
@@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
#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<reverb_metadata>
|
||||
{
|
||||
public:
|
||||
dsp::reverb reverb;
|
||||
dsp::simple_delay<16384, dsp::stereo_sample<float> > pre_delay;
|
||||
dsp::onepole<float> 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<vintage_delay_metadata>
|
||||
{
|
||||
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<float> 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<typename FilterClass, typename Metadata>
|
||||
class filter_module_with_inertia: public audio_module<Metadata>, 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<Metadata>::ins;
|
||||
using audio_module<Metadata>::outs;
|
||||
using audio_module<Metadata>::params;
|
||||
|
||||
dsp::inertia<dsp::exponential_ramp> 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<dsp::biquad_filter_module, filter_metadata>,
|
||||
public frequency_response_line_graph
|
||||
{
|
||||
mutable float old_cutoff, old_resonance, old_mode;
|
||||
public:
|
||||
filter_audio_module()
|
||||
: filter_module_with_inertia<dsp::biquad_filter_module, filter_metadata>(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<dsp::biquad_filter_module, filterclavier_metadata>,
|
||||
public frequency_response_line_graph
|
||||
{
|
||||
using audio_module<filterclavier_metadata>::ins;
|
||||
using audio_module<filterclavier_metadata>::outs;
|
||||
using audio_module<filterclavier_metadata>::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
|
||||
249
plugins/ladspa_effect/calf/src/calf/modules_comp.h
Normal file
249
plugins/ladspa_effect/calf/src/calf/modules_comp.h
Normal file
@@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
#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<compressor_metadata>, 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<double> 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<sidechaincompressor_metadata>, 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<float> f1L, f1R, f2L, f2R;
|
||||
public:
|
||||
typedef std::complex<double> 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<multibandcompressor_metadata>, 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<float> lpL0, lpR0, lpL1, lpR1, lpL2, lpR2, hpL0, hpR0, hpL1, hpR1, hpL2, hpR2;
|
||||
float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1];
|
||||
public:
|
||||
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<deesser_metadata>, 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<float> 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<gate_metadata>, 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<float> 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
|
||||
@@ -22,7 +22,6 @@
|
||||
#define __CALF_MODULES_DEV_H
|
||||
|
||||
#include <calf/metadata.h>
|
||||
#include <calf/modules.h>
|
||||
|
||||
#if ENABLE_EXPERIMENTAL
|
||||
#include <fluidsynth.h>
|
||||
@@ -35,11 +34,6 @@ namespace calf_plugins {
|
||||
/// Tiny wrapper for fluidsynth
|
||||
class fluidsynth_audio_module: public audio_module<fluidsynth_metadata>
|
||||
{
|
||||
public:
|
||||
float *ins[in_count];
|
||||
float *outs[out_count];
|
||||
float *params[param_count];
|
||||
|
||||
protected:
|
||||
/// Current sample rate
|
||||
uint32_t srate;
|
||||
96
plugins/ladspa_effect/calf/src/calf/modules_dist.h
Normal file
96
plugins/ladspa_effect/calf/src/calf/modules_dist.h
Normal file
@@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
#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<saturator_metadata> {
|
||||
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<float> lp[2][4], hp[2][4];
|
||||
dsp::biquad_d2<float> 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<exciter_metadata> {
|
||||
private:
|
||||
float freq_old;
|
||||
uint32_t clip_in, clip_out;
|
||||
float meter_in, meter_out, meter_drive;
|
||||
dsp::biquad_d2<float> 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<bassenhancer_metadata> {
|
||||
private:
|
||||
float freq_old;
|
||||
uint32_t clip_in, clip_out;
|
||||
float meter_in, meter_out, meter_drive;
|
||||
dsp::biquad_d2<float> 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
|
||||
89
plugins/ladspa_effect/calf/src/calf/modules_eq.h
Normal file
89
plugins/ladspa_effect/calf/src/calf/modules_eq.h
Normal file
@@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
#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 BaseClass, bool has_lphp>
|
||||
class equalizerNband_audio_module: public audio_module<BaseClass>, public frequency_response_line_graph {
|
||||
public:
|
||||
typedef audio_module<BaseClass> 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<float> hp[3][2], lp[3][2];
|
||||
dsp::biquad_d2<float> lsL, lsR, hsL, hsR;
|
||||
dsp::biquad_d2<float> pL[PeakBands], pR[PeakBands];
|
||||
|
||||
inline void process_hplp(float &left, float &right);
|
||||
public:
|
||||
typedef std::complex<double> 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_metadata, false> equalizer5band_audio_module;
|
||||
typedef equalizerNband_audio_module<equalizer8band_metadata, true> equalizer8band_audio_module;
|
||||
typedef equalizerNband_audio_module<equalizer12band_metadata, true> equalizer12band_audio_module;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
190
plugins/ladspa_effect/calf/src/calf/modules_mod.h
Normal file
190
plugins/ladspa_effect/calf/src/calf/modules_mod.h
Normal file
@@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
#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<flanger_metadata>, public frequency_response_line_graph
|
||||
{
|
||||
public:
|
||||
dsp::simple_flanger<float, 2048> 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<phaser_metadata>, 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<rotary_speaker_metadata>
|
||||
{
|
||||
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<float> 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<multichorus_metadata>, public frequency_response_line_graph
|
||||
{
|
||||
public:
|
||||
uint32_t srate;
|
||||
dsp::multichorus<float, dsp::sine_multi_lfo<float, 8>, dsp::filter_sum<dsp::biquad_d2<>, 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<pulsator_metadata>, 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
|
||||
@@ -21,7 +21,6 @@
|
||||
#ifndef __CALF_MODULES_SYNTHS_H
|
||||
#define __CALF_MODULES_SYNTHS_H
|
||||
|
||||
#include <assert.h>
|
||||
#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<monosynth_metadata>, 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<MONOSYNTH_WAVE_BITS> *waves;
|
||||
dsp::waveform_oscillator<MONOSYNTH_WAVE_BITS> 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<organ_metadata>, 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
|
||||
@@ -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<float, ORGAN_WAVE_SIZE, 1> 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<organ_voice> *v = new block_voice<organ_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<organ_metadata>, 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); }
|
||||
};
|
||||
|
||||
};
|
||||
@@ -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 <map>
|
||||
@@ -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;
|
||||
@@ -293,6 +293,11 @@ template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator <<(osc_stream<Buffer, TypeBuffer> &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<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &s, uint32_t &val)
|
||||
{
|
||||
#if 0
|
||||
s.read(&val, 4);
|
||||
val = htonl(val);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -307,6 +316,10 @@ template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &s, int32_t &val)
|
||||
{
|
||||
#if 0
|
||||
s.read(&val, 4);
|
||||
val = htonl(val);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -314,6 +327,11 @@ template<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator <<(osc_stream<Buffer, TypeBuffer> &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<class Buffer, class TypeBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
operator >>(osc_stream<Buffer, TypeBuffer> &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<class Buffer, class TypeBuffer, class DestBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
read_buffer_from_osc_stream(osc_stream<Buffer, TypeBuffer> &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<class Buffer, class TypeBuffer, class SrcBuffer>
|
||||
inline osc_stream<Buffer, TypeBuffer> &
|
||||
write_buffer_to_osc_stream(osc_stream<Buffer, TypeBuffer> &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<Buffer, TypeBuffer> &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<class OscStream>
|
||||
struct osc_message_sink
|
||||
0
plugins/ladspa_effect/calf/src/calf/osctlnet.h
Normal file
0
plugins/ladspa_effect/calf/src/calf/osctlnet.h
Normal file
@@ -22,10 +22,6 @@
|
||||
#define __CALF_PRESET_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <ostream>
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
|
||||
@@ -21,12 +21,13 @@
|
||||
#ifndef __CALF_PRIMITIVES_H
|
||||
#define __CALF_PRIMITIVES_H
|
||||
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
|
||||
namespace dsp {
|
||||
|
||||
@@ -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 <assert.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <stdint.h>
|
||||
#include <bitset>
|
||||
#include <list>
|
||||
#include <stack>
|
||||
#include <bitset>
|
||||
#include "primitives.h"
|
||||
#include "audio_fx.h"
|
||||
|
||||
namespace dsp {
|
||||
|
||||
@@ -93,12 +93,13 @@ public:
|
||||
};
|
||||
|
||||
/// Exception-safe temporary assignment
|
||||
template<class T>
|
||||
template<class T, class Tref = T&>
|
||||
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 () {}
|
||||
};
|
||||
@@ -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 <assert.h>
|
||||
#include <memory.h>
|
||||
#include <config.h>
|
||||
#include <limits.h>
|
||||
#include <calf/giface.h>
|
||||
#include <stdio.h>
|
||||
#include <calf/osctlnet.h>
|
||||
#include <calf/utils.h>
|
||||
|
||||
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<int> ¶ms)
|
||||
static void serialize_graphs(osctl::osc_inline_typed_strstream &os, const line_graph_iface *graph, std::vector<int> ¶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
|
||||
|
||||
1018
plugins/ladspa_effect/calf/src/metadata.cpp
Normal file
1018
plugins/ladspa_effect/calf/src/metadata.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -18,9 +18,10 @@
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <sstream>
|
||||
#include <calf/modmatrix.h>
|
||||
#include <calf/utils.h>
|
||||
#include <memory.h>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace dsp;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
738
plugins/ladspa_effect/calf/src/modules_dist.cpp
Normal file
738
plugins/ladspa_effect/calf/src/modules_dist.cpp
Normal file
@@ -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 <limits.h>
|
||||
#include <memory.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_dist.h>
|
||||
|
||||
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;
|
||||
}
|
||||
381
plugins/ladspa_effect/calf/src/modules_eq.cpp
Normal file
381
plugins/ladspa_effect/calf/src/modules_eq.cpp
Normal file
@@ -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 <limits.h>
|
||||
#include <memory.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_eq.h>
|
||||
|
||||
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<class BaseClass, bool has_lphp>
|
||||
equalizerNband_audio_module<BaseClass, has_lphp>::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<class BaseClass, bool has_lphp>
|
||||
void equalizerNband_audio_module<BaseClass, has_lphp>::activate()
|
||||
{
|
||||
is_active = true;
|
||||
// set all filters
|
||||
params_changed();
|
||||
}
|
||||
|
||||
template<class BaseClass, bool has_lphp>
|
||||
void equalizerNband_audio_module<BaseClass, has_lphp>::deactivate()
|
||||
{
|
||||
is_active = false;
|
||||
}
|
||||
|
||||
static inline void copy_lphp(biquad_d2<float> 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<class BaseClass, bool has_lphp>
|
||||
void equalizerNband_audio_module<BaseClass, has_lphp>::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<class BaseClass, bool has_lphp>
|
||||
inline void equalizerNband_audio_module<BaseClass, has_lphp>::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<class BaseClass, bool has_lphp>
|
||||
uint32_t equalizerNband_audio_module<BaseClass, has_lphp>::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<class BaseClass, bool has_lphp>
|
||||
bool equalizerNband_audio_module<BaseClass, has_lphp>::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<class BaseClass, bool has_lphp>
|
||||
bool equalizerNband_audio_module<BaseClass, has_lphp>::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<class BaseClass, bool has_lphp>
|
||||
int equalizerNband_audio_module<BaseClass, has_lphp>::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<float> &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<class BaseClass, bool use_hplp>
|
||||
float equalizerNband_audio_module<BaseClass, use_hplp>::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<equalizer5band_metadata, false>;
|
||||
template class equalizerNband_audio_module<equalizer8band_metadata, true>;
|
||||
template class equalizerNband_audio_module<equalizer12band_metadata, true>;
|
||||
|
||||
736
plugins/ladspa_effect/calf/src/modules_mod.cpp
Normal file
736
plugins/ladspa_effect/calf/src/modules_mod.cpp
Normal file
@@ -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 <limits.h>
|
||||
#include <memory.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_mod.h>
|
||||
|
||||
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<float, 8> &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<float, 8> &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;
|
||||
}
|
||||
@@ -18,12 +18,6 @@
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
#include <complex>
|
||||
#if USE_JACK
|
||||
#include <jack/jack.h>
|
||||
#endif
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_synths.h>
|
||||
|
||||
@@ -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_WAVE_BITS> *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<float>())
|
||||
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<float>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,10 @@
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
#include <complex>
|
||||
#if USE_JACK
|
||||
#include <jack/jack.h>
|
||||
#endif
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_synths.h>
|
||||
#include <calf/organ.h>
|
||||
#include <iostream>
|
||||
|
||||
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<ORGAN_WAVE_BITS> blSrc, bandlimiter<ORGAN_BIG_W
|
||||
|
||||
#define LARGE_WAVEFORM_PROGRESS() do { if (reporter) { progress += 100; reporter->report_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<organ_voice> *v = new block_voice<organ_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));
|
||||
|
||||
@@ -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 <config.h>
|
||||
#include <calf/ladspa_wrap.h>
|
||||
#include <calf/lv2wrap.h>
|
||||
#include <calf/modules.h>
|
||||
#include <calf/modules_comp.h>
|
||||
#include <calf/modules_dev.h>
|
||||
#include <calf/modules_dist.h>
|
||||
#include <calf/modules_eq.h>
|
||||
#include <calf/modules_mod.h>
|
||||
#include <calf/modules_synths.h>
|
||||
#include <calf/organ.h>
|
||||
#include <calf/osctlnet.h>
|
||||
|
||||
using namespace calf_plugins;
|
||||
using namespace osctl;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if USE_LADSPA
|
||||
template<class Module>
|
||||
LADSPA_Descriptor ladspa_wrapper<Module>::descriptor;
|
||||
|
||||
template<class Module>
|
||||
LADSPA_Descriptor ladspa_wrapper<Module>::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<class Module>
|
||||
DSSI_Descriptor ladspa_wrapper<Module>::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<class Module>
|
||||
DSSI_Program_Descriptor ladspa_wrapper<Module>::dssi_default_program;
|
||||
|
||||
template<class Module>
|
||||
std::vector<plugin_preset> *ladspa_wrapper<Module>::presets;
|
||||
|
||||
template<class Module>
|
||||
std::vector<DSSI_Program_Descriptor> *ladspa_wrapper<Module>::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<const line_graph_iface *>(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<class Module>
|
||||
ladspa_plugin_metadata_set ladspa_wrapper<Module>::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<Module>::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<plugin_preset>;
|
||||
preset_descs = new std::vector<DSSI_Program_Descriptor>;
|
||||
|
||||
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 <calf/modulelist.h>
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,12 +18,6 @@
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
#if USE_JACK
|
||||
#include <jack/jack.h>
|
||||
#endif
|
||||
#include <calf/giface.h>
|
||||
#include <calf/synth.h>
|
||||
|
||||
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<int> 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);
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <config.h>
|
||||
#include <calf/osctl.h>
|
||||
#include <calf/utils.h>
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user