Merge branch 'calf-updates'

* calf-updates:
  CALF: rebased to CALF master branch
  Moved CALF headers to  proper location
This commit is contained in:
Tobias Doerffel
2010-05-21 17:08:39 +02:00
53 changed files with 6512 additions and 4741 deletions

View File

@@ -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 "")

View File

@@ -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

View File

@@ -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

View 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;
}

View File

@@ -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

View File

@@ -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;
}
};
};

View File

@@ -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 **&params_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 **&params_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 &param_props[param_no]; }
const parameter_properties *get_param_props(int param_no) const { return &param_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

View 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

View 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

View File

@@ -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;

View File

@@ -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

View File

@@ -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")

View 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

View 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

View File

@@ -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;

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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); }
};
};

View File

@@ -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;

View File

@@ -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

View 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"

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 () {}
};

View File

@@ -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> &params)
static void serialize_graphs(osctl::osc_inline_typed_strstream &os, const line_graph_iface *graph, std::vector<int> &params)
{
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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View 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;
}

View 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>;

View 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;
}

View File

@@ -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);
}
}

View File

@@ -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));

View File

@@ -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

View File

@@ -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);

View File

@@ -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();
}
}