Merge branch 'master' into zynaddsubfx-master

This commit is contained in:
Tobias Doerffel
2010-07-25 17:28:26 +02:00
244 changed files with 9330 additions and 9909 deletions

View File

@@ -486,7 +486,7 @@ void AudioFileProcessorView::modelChanged()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return new audioFileProcessor(

View File

@@ -101,7 +101,7 @@ bool bassBoosterEffect::processAudioBuffer( sampleFrame * _buf,
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return( new bassBoosterEffect( _parent,

View File

@@ -575,7 +575,7 @@ void bitInvaderView::normalizeToggled( bool value )
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return( new bitInvader( static_cast<InstrumentTrack *>( _data ) ) );

View File

@@ -2,4 +2,6 @@ INCLUDE(BuildPlugin)
INCLUDE_DIRECTORIES(unrtf)
LINK_LIBRARIES(${ZIP_LIBRARIES})
BUILD_PLUGIN(flpimport FlpImport.cpp unrtf.cpp FlpImport.h)

View File

@@ -2031,7 +2031,7 @@ void FlpImport::processPluginParams( FL_Channel * _ch )
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return new FlpImport( QString::fromUtf8(

View File

@@ -253,7 +253,7 @@ void kickerInstrumentView::modelChanged()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return new kickerInstrument( static_cast<InstrumentTrack *>( _data ) );

View File

@@ -60,7 +60,7 @@ Plugin::Descriptor PLUGIN_EXPORT ladspabrowser_plugin_descriptor =
} ;
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return new ladspaBrowser;

View File

@@ -1,8 +1,8 @@
/*
* LadspaControls.cpp - model for LADSPA-plugin controls
* LadspaControls.cpp - model for LADSPA plugin controls
*
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* Copyright (c) 2008-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* This program is free software; you can redistribute it and/or
@@ -22,7 +22,6 @@
*
*/
#include <QtXml/QDomElement>
#include "LadspaEffect.h"
@@ -35,6 +34,10 @@ LadspaControls::LadspaControls( LadspaEffect * _eff ) :
m_noLink( false ),
m_stereoLinkModel( true, this )
{
connect( &m_stereoLinkModel, SIGNAL( dataChanged() ),
this, SLOT( updateLinkStatesFromGlobal() ) );
multi_proc_t controls = m_effect->getPortControls();
m_controlCount = controls.count();
@@ -163,7 +166,7 @@ void LadspaControls::linkPort( Uint16 _port, bool _state )
void LadspaControls::updateChannelLinkState()
void LadspaControls::updateLinkStatesFromGlobal()
{
if( m_stereoLinkModel.value() )
{
@@ -183,10 +186,10 @@ void LadspaControls::updateChannelLinkState()
m_controls[0][port]->setLink( false );
}
}
else
{
m_noLink = false;
}
// if global channel link state has changed, always ignore link
// status of individual ports in the future
m_noLink = false;
}

View File

@@ -1,8 +1,8 @@
/*
* ladspa_controls.h - model for LADSPA-plugin controls
* LadspaControls.h - model for LADSPA plugin controls
*
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* Copyright (c) 2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* This program is free software; you can redistribute it and/or
@@ -61,7 +61,7 @@ public:
protected slots:
void updateChannelLinkState();
void updateLinkStatesFromGlobal();
void linkPort( Uint16 _port, bool _state );

View File

@@ -577,7 +577,7 @@ sample_rate_t LadspaEffect::maxSamplerate( const QString & _name )
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return new LadspaEffect( _parent,

View File

@@ -1,8 +1,7 @@
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 "")
SET(INLINE_FLAGS "")
IF(NOT LMMS_BUILD_APPLE)

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 line_graph_iface *get_line_graph_iface()
{
return dynamic_cast<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

View File

@@ -1,101 +0,0 @@
#ifdef PER_MODULE_ITEM
PER_MODULE_ITEM(filter, false, "filter")
PER_MODULE_ITEM(filterclavier, false, "filterclavier")
PER_MODULE_ITEM(flanger, false, "flanger")
PER_MODULE_ITEM(reverb, false, "reverb")
PER_MODULE_ITEM(monosynth, true, "monosynth")
PER_MODULE_ITEM(vintage_delay, false, "vintagedelay")
PER_MODULE_ITEM(organ, true, "organ")
PER_MODULE_ITEM(rotary_speaker, false, "rotaryspeaker")
PER_MODULE_ITEM(phaser, false, "phaser")
PER_MODULE_ITEM(multichorus, false, "multichorus")
PER_MODULE_ITEM(compressor, false, "compressor")
PER_MODULE_ITEM(sidechaincompressor, false, "sidechaincompressor")
PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
PER_MODULE_ITEM(deesser, false, "deesser")
PER_MODULE_ITEM(equalizer5band, false, "equalizer5band")
PER_MODULE_ITEM(equalizer8band, false, "equalizer8band")
PER_MODULE_ITEM(equalizer12band, false, "equalizer12band")
#ifdef ENABLE_EXPERIMENTAL
PER_MODULE_ITEM(fluidsynth, true, "fluidsynth")
PER_MODULE_ITEM(wavetable, true, "wavetable")
#endif
#undef PER_MODULE_ITEM
#endif
#ifdef PER_SMALL_MODULE_ITEM
#ifdef ENABLE_EXPERIMENTAL
PER_SMALL_MODULE_ITEM(lp_filter, "lowpass12")
PER_SMALL_MODULE_ITEM(hp_filter, "highpass12")
PER_SMALL_MODULE_ITEM(bp_filter, "bandpass6")
PER_SMALL_MODULE_ITEM(br_filter, "notch6")
PER_SMALL_MODULE_ITEM(onepole_lp_filter, "lowpass6")
PER_SMALL_MODULE_ITEM(onepole_hp_filter, "highpass6")
PER_SMALL_MODULE_ITEM(onepole_ap_filter, "allpass")
PER_SMALL_MODULE_ITEM(min, "min")
PER_SMALL_MODULE_ITEM(max, "max")
PER_SMALL_MODULE_ITEM(minus, "minus")
PER_SMALL_MODULE_ITEM(mul, "mul")
PER_SMALL_MODULE_ITEM(neg, "neg")
PER_SMALL_MODULE_ITEM(min_c, "min_c")
PER_SMALL_MODULE_ITEM(max_c, "max_c")
PER_SMALL_MODULE_ITEM(minus_c, "minus_c")
PER_SMALL_MODULE_ITEM(mul_c, "mul_c")
PER_SMALL_MODULE_ITEM(neg_c, "neg_c")
PER_SMALL_MODULE_ITEM(level2edge_c, "level2edge_c")
PER_SMALL_MODULE_ITEM(map_lin2exp, "lin2exp")
PER_SMALL_MODULE_ITEM(square_osc, "square_osc")
PER_SMALL_MODULE_ITEM(saw_osc, "saw_osc")
PER_SMALL_MODULE_ITEM(square_lfo, "square_lfo")
PER_SMALL_MODULE_ITEM(saw_lfo, "saw_lfo")
PER_SMALL_MODULE_ITEM(pulse_lfo, "pulse_lfo")
PER_SMALL_MODULE_ITEM(print_a, "print_a")
PER_SMALL_MODULE_ITEM(print_c, "print_c")
PER_SMALL_MODULE_ITEM(print_e, "print_e")
PER_SMALL_MODULE_ITEM(print_em, "print_em")
PER_SMALL_MODULE_ITEM(copy_em, "copy_em")
PER_SMALL_MODULE_ITEM(notefilter_m, "notefilter_m")
PER_SMALL_MODULE_ITEM(ccfilter_m, "ccfilter_m")
PER_SMALL_MODULE_ITEM(pcfilter_m, "pcfilter_m")
PER_SMALL_MODULE_ITEM(pressurefilter_m, "pressurefilter_m")
PER_SMALL_MODULE_ITEM(pitchbendfilter_m, "pitchbendfilter_m")
PER_SMALL_MODULE_ITEM(systemfilter_m, "systemfilter_m")
PER_SMALL_MODULE_ITEM(channelfilter_m, "channelfilter_m")
PER_SMALL_MODULE_ITEM(keyfilter_m, "keyfilter_m")
PER_SMALL_MODULE_ITEM(setchannel_m, "setchannel_m")
PER_SMALL_MODULE_ITEM(key_less_than_m, "key_less_than_m")
PER_SMALL_MODULE_ITEM(channel_less_than_m, "channel_less_than_m")
PER_SMALL_MODULE_ITEM(transpose_m, "transpose_m")
PER_SMALL_MODULE_ITEM(eventmerge_e, "eventmerge_e")
PER_SMALL_MODULE_ITEM(quadpower_a, "quadpower_a")
PER_SMALL_MODULE_ITEM(quadpower_c, "quadpower_c")
PER_SMALL_MODULE_ITEM(crossfader2_a, "crossfader2_a")
PER_SMALL_MODULE_ITEM(crossfader2_c, "crossfader2_c")
PER_SMALL_MODULE_ITEM(linear_inertia_c, "linear_inertia_c")
PER_SMALL_MODULE_ITEM(exp_inertia_c, "exp_inertia_c")
PER_SMALL_MODULE_ITEM(sample_hold_edge_c, "sample_hold_edge_c")
PER_SMALL_MODULE_ITEM(sample_hold_level_c, "sample_hold_level_c")
PER_SMALL_MODULE_ITEM(bit_and_c, "bit_and_c")
PER_SMALL_MODULE_ITEM(bit_or_c, "bit_or_c")
PER_SMALL_MODULE_ITEM(bit_xor_c, "bit_xor_c")
PER_SMALL_MODULE_ITEM(logical_and_c, "logical_and_c")
PER_SMALL_MODULE_ITEM(logical_or_c, "logical_or_c")
PER_SMALL_MODULE_ITEM(logical_xor_c, "logical_xor_c")
PER_SMALL_MODULE_ITEM(logical_not_c, "logical_not_c")
PER_SMALL_MODULE_ITEM(flipflop_c, "flipflop_c")
PER_SMALL_MODULE_ITEM(schmitt_c, "schmitt_c")
PER_SMALL_MODULE_ITEM(between_c, "between_c")
PER_SMALL_MODULE_ITEM(less_c, "less_c")
PER_SMALL_MODULE_ITEM(clip_c, "clip_c")
PER_SMALL_MODULE_ITEM(trigger_a2c, "trigger_a2c")
PER_SMALL_MODULE_ITEM(timer_c, "timer_c")
PER_SMALL_MODULE_ITEM(prio_mux_c, "prio_mux_c")
PER_SMALL_MODULE_ITEM(prio_enc8_c, "prio_enc8_c")
PER_SMALL_MODULE_ITEM(ifthenelse_c, "ifthenelse_c")
PER_SMALL_MODULE_ITEM(counter_c, "counter_c")
PER_SMALL_MODULE_ITEM(mux4_c, "mux4_c")
PER_SMALL_MODULE_ITEM(mux8_c, "mux8_c")
PER_SMALL_MODULE_ITEM(mux16_c, "mux16_c")
PER_SMALL_MODULE_ITEM(msgread_e, "msgread_e")
#endif
#undef PER_SMALL_MODULE_ITEM
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,202 +0,0 @@
/* Calf DSP Library
* "Small" audio modules for modular synthesis
*
* Copyright (C) 2001-2007 Krzysztof Foltman
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02111-1307, USA.
*/
#ifndef __CALF_MODULES_SMALL_H
#define __CALF_MODULES_SMALL_H
#if USE_LV2
#include <lv2.h>
#include "plugininfo.h"
#include "lv2_polymorphic_port.h"
#include "lv2helpers.h"
namespace calf_plugins {
/// Empty implementations for plugin functions. Note, that some functions aren't virtual, because they're called via the particular
/// subclass via template wrappers (ladspa_small_wrapper<> etc), not via base class pointer/reference. On the other hand,
/// other functions are virtual when overhead is acceptable (instantiation time functions etc.)
class null_small_audio_module: public uri_map_access
{
public:
uint32_t srate;
double odsr;
uint32_t poly_type_control, poly_type_audio;
/// for polymorphic ports: "is audio" flags for first 32 ports (should be sufficient for most plugins)
uint32_t poly_port_types;
null_small_audio_module()
: srate((uint32_t)-1)
, odsr(0.)
, poly_type_control(0)
, poly_type_audio(0)
, poly_port_types(0)
{
}
/// Called when host changes type of the polymorphic port
inline void set_port_type(uint32_t port, uint32_t type, void *type_data) {
if (port >= 32)
return;
uint32_t port_mask = 1 << port;
if (type == poly_type_control)
poly_port_types &= ~port_mask;
else if (type == poly_type_audio)
poly_port_types |= port_mask;
on_port_types_changed();
}
/// Returns 1 for audio ports and 0 for control ports
inline unsigned int port_is_audio(unsigned int port) {
return (poly_port_types >> port) & 1;
}
/// Returns (unsigned)-1 for audio ports and 0 for control ports
inline unsigned int port_audio_mask(unsigned int port) {
return 0 - ((poly_port_types >> port) & 1);
}
/// Returns (unsigned)-1 for audio ports and 0 for control ports
static inline unsigned int port_audio_mask(unsigned int port, uint32_t poly_port_types) {
return 0 - ((poly_port_types >> port) & 1);
}
virtual void on_port_types_changed() {}
inline void set_bundle_path(const char *path) {}
/// Called to map all the necessary URIs
virtual void map_uris()
{
poly_type_control = map_uri(LV2_POLYMORPHIC_PORT_URI, "http://lv2plug.in/ns/lv2core#ControlPort");
poly_type_audio = map_uri(LV2_POLYMORPHIC_PORT_URI, "http://lv2plug.in/ns/lv2core#AudioPort");
}
/// Called on instantiation with the list of LV2 features called
virtual void use_features(const LV2_Feature *const *features) {
while(*features)
{
use_feature((*features)->URI, (*features)->data);
features++;
}
}
/// LADSPA-esque activate function, except it is called after ports are connected, not before
inline void activate() {}
/// LADSPA-esque deactivate function
inline void deactivate() {}
/// Set sample rate for the plugin
inline void set_sample_rate(uint32_t sr) { srate = sr; odsr = 1.0 / sr; }
static inline const void *ext_data(const char *URI) { return NULL; }
};
/// Templatized version useful when the number of inputs and outputs is small
template<unsigned int Inputs, unsigned int Outputs>
class small_audio_module_base: public null_small_audio_module
{
public:
enum { in_count = Inputs, out_count = Outputs };
/// Input pointers
float *ins[in_count];
/// Output pointers
float *outs[out_count];
};
template<class Module>
struct lv2_small_wrapper
{
typedef Module instance;
static LV2_Descriptor descriptor;
std::string uri;
static uint32_t poly_port_types;
lv2_small_wrapper(const char *id)
{
uri = "http://calf.sourceforge.net/small_plugins/" + std::string(id);
descriptor.URI = uri.c_str();
descriptor.instantiate = cb_instantiate;
descriptor.connect_port = cb_connect;
descriptor.activate = cb_activate;
descriptor.run = cb_run;
descriptor.deactivate = cb_deactivate;
descriptor.cleanup = cb_cleanup;
descriptor.extension_data = cb_ext_data;
plugin_port_type_grabber ptg(poly_port_types);
Module::plugin_info(&ptg);
}
static void cb_connect(LV2_Handle Instance, uint32_t port, void *DataLocation) {
unsigned long ins = Module::in_count;
unsigned long outs = Module::out_count;
instance *const mod = (instance *)Instance;
if (port < ins)
mod->ins[port] = (float *)DataLocation;
else if (port < ins + outs)
mod->outs[port - ins] = (float *)DataLocation;
}
static void cb_activate(LV2_Handle Instance) {
// Note the changed semantics (now more LV2-like)
instance *const mod = (instance *)Instance;
mod->activate();
}
static void cb_deactivate(LV2_Handle Instance) {
instance *const mod = (instance *)Instance;
mod->deactivate();
}
static uint32_t cb_set_type(LV2_Handle Instance, uint32_t port, uint32_t type, void *type_data)
{
instance *const mod = (instance *)Instance;
mod->set_port_type(port, type, type_data);
return 0;
}
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();
mod->poly_port_types = poly_port_types;
// XXXKF some people use fractional sample rates; we respect them ;-)
mod->set_bundle_path(bundle_path);
mod->use_features(features);
mod->set_sample_rate((uint32_t)sample_rate);
return mod;
}
static void cb_run(LV2_Handle Instance, uint32_t SampleCount) {
instance *const mod = (instance *)Instance;
mod->process(SampleCount);
}
static void cb_cleanup(LV2_Handle Instance) {
instance *const mod = (instance *)Instance;
delete mod;
}
static const void *cb_ext_data(const char *URI) {
return Module::ext_data(URI);
}
};
extern const LV2_Descriptor *lv2_small_descriptor(uint32_t index);
};
#endif
#endif

View File

@@ -1,105 +0,0 @@
/* Calf DSP Library
* Plugin introspection interface
*
* Copyright (C) 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_PLUGININFO_H
#define __CALF_PLUGININFO_H
#include <string>
namespace calf_plugins {
/// A sink to send information about an audio port
struct plain_port_info_iface
{
/// Called if it's an input port
virtual plain_port_info_iface& input() { return *this; }
/// Called if it's an output port
virtual plain_port_info_iface& output() { return *this; }
virtual plain_port_info_iface& lv2_ttl(const std::string &text) { return *this; }
virtual ~plain_port_info_iface() {}
};
/// A sink to send information about a control port (very incomplete, missing stuff: units, integer, boolean, toggled, notAutomatic, notGUI...)
struct control_port_info_iface
{
/// Called if it's an input port
virtual control_port_info_iface& input() { return *this; }
/// Called if it's an output port
virtual control_port_info_iface& output() { return *this; }
/// Called to mark the port as using linear range [from, to]
virtual control_port_info_iface& lin_range(double from, double to) { return *this; }
/// Called to mark the port as using log range [from, to]
virtual control_port_info_iface& log_range(double from, double to) { return *this; }
virtual control_port_info_iface& toggle() { return *this; }
virtual control_port_info_iface& trigger() { return *this; }
virtual control_port_info_iface& integer() { return *this; }
virtual control_port_info_iface& lv2_ttl(const std::string &text) { return *this; }
virtual control_port_info_iface& polymorphic() { return lv2_ttl("a poly:PolymorphicPort ;"); }
virtual control_port_info_iface& poly_audio() { return lv2_ttl("poly:supportsType lv2:AudioPort ;"); }
virtual ~control_port_info_iface() {}
};
/// A sink to send information about a plugin
struct plugin_info_iface
{
/// Set plugin names (ID, name and label)
virtual void names(const std::string &name, const std::string &label, const std::string &category, const std::string &microname = std::string()) {}
/// Add an audio port (returns a sink which accepts further description)
virtual plain_port_info_iface &audio_port(const std::string &id, const std::string &name, const std::string &microname = std::string("N/A"))=0;
/// Add an event port (returns a sink which accepts further description)
virtual plain_port_info_iface &event_port(const std::string &id, const std::string &name, const std::string &microname = std::string("N/A"))=0;
/// Add a control port (returns a sink which accepts further description)
virtual control_port_info_iface &control_port(const std::string &id, const std::string &name, double def_value, const std::string &microname = "N/A")=0;
/// Add arbitrary TTL clauses
virtual void lv2_ttl(const std::string &text) {}
/// Add small plugin GUI
virtual void has_gui() { lv2_ttl("uiext:ui <http://calf.sourceforge.net/small_plugins/gui/gtk2-gui> ;"); }
/// Called after plugin has reported all the information
virtual void finalize() {}
virtual ~plugin_info_iface() {}
};
struct plugin_port_type_grabber: public plugin_info_iface, public control_port_info_iface
{
uint32_t &target;
uint32_t index;
plain_port_info_iface pp;
control_port_info_iface cp;
plugin_port_type_grabber(uint32_t &_target) : target(_target), index(0) { target = 0; }
virtual plain_port_info_iface &audio_port(const std::string &id, const std::string &name, const std::string &microname = std::string("N/A")) { target |= (1 << index); index++; return pp; }
virtual plain_port_info_iface &event_port(const std::string &id, const std::string &name, const std::string &microname = std::string("N/A")) { index++; return pp; }
virtual control_port_info_iface &control_port(const std::string &id, const std::string &name, double def_value, const std::string &microname = "N/A") { index++; return cp; }
};
/// A sink to send information about plugins
struct plugin_list_info_iface
{
/// Add an empty plugin object and return the sink to be filled with information
virtual plugin_info_iface &plugin(const std::string &id) = 0;
virtual ~plugin_list_info_iface() {}
};
};
#endif

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
@@ -53,21 +55,21 @@ protected:
gain_smoothing gs_wet, gs_dry;
public:
fixed_point<unsigned int, 20> phase, dphase;
float get_rate() {
float get_rate() const {
return rate;
}
void set_rate(float rate) {
this->rate = rate;
dphase = rate/sample_rate*4096;
}
float get_wet() {
float get_wet() const {
return wet;
}
void set_wet(float wet) {
this->wet = wet;
gs_wet.set_inertia(wet);
}
float get_dry() {
float get_dry() const {
return dry;
}
void set_dry(float dry) {
@@ -95,122 +97,50 @@ 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);
}
float get_base_frq() {
simple_phaser(int _max_stages, float *x1vals, float *y1vals);
float get_base_frq() const {
return base_frq;
}
void set_base_frq(float _base_frq) {
base_frq = _base_frq;
}
int get_stages() {
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;
}
float get_mod_depth() {
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() {
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)
{
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;
};
/**
@@ -225,14 +155,14 @@ protected:
float min_delay, mod_depth;
sine_table<int, 4096, 65536> sine;
public:
float get_min_delay() {
float get_min_delay() const {
return min_delay;
}
void set_min_delay(float min_delay) {
this->min_delay = min_delay;
this->min_delay_samples = (int)(min_delay * 65536.0 * sample_rate);
}
float get_mod_depth() {
float get_mod_depth() const {
return mod_depth;
}
void set_mod_depth(float mod_depth) {
@@ -319,7 +249,7 @@ public:
set_rate(get_rate());
set_min_delay(get_min_delay());
}
float get_fb() {
float get_fb() const {
return fb;
}
void set_fb(float fb) {
@@ -386,7 +316,7 @@ public:
}
last_delay_pos = delay_pos;
}
float freq_gain(float freq, float sr)
float freq_gain(float freq, float sr) const
{
typedef std::complex<double> cfloat;
freq *= 2.0 * M_PI / sr;
@@ -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,68 +372,8 @@ 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);
}
}
float get_time() {
void update_times();
float get_time() const {
return time;
}
void set_time(float time) {
@@ -512,14 +381,14 @@ public:
// fb = pow(1.0f/4096.0f, (float)(1700/(time*sr)));
fb = 1.0 - 0.3 / (time * sr / 44100.0);
}
float get_type() {
float get_type() const {
return type;
}
void set_type(int type) {
this->type = type;
update_times();
}
float get_diffusion() {
float get_diffusion() const {
return diffusion;
}
void set_diffusion(float diffusion) {
@@ -531,7 +400,7 @@ public:
this->diffusion = diffusion;
update_times();
}
float get_fb()
float get_fb() const
{
return this->fb;
}
@@ -539,7 +408,7 @@ public:
{
this->fb = fb;
}
float get_cutoff() {
float get_cutoff() const {
return cutoff;
}
void set_cutoff(float cutoff) {
@@ -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,8 +431,8 @@ 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 float freq_gain(int subindex, float freq, float srate) = 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)
{
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

@@ -305,7 +305,7 @@ public:
/// Return the filter's gain at frequency freq
/// @param freq Frequency to look up
/// @param sr Filter sample rate (used to convert frequency to angular frequency)
float freq_gain(float freq, float sr)
float freq_gain(float freq, float sr) const
{
typedef std::complex<double> cfloat;
freq *= 2.0 * M_PI / sr;
@@ -316,7 +316,7 @@ public:
/// Return H(z) the filter's gain at frequency freq
/// @param z Z variable (e^jw)
cfloat h_z(const cfloat &z)
cfloat h_z(const cfloat &z) const
{
return (cfloat(a0) + double(a1) * z + double(a2) * z*z) / (cfloat(1.0) + double(b1) * z + double(b2) * z*z);
@@ -396,7 +396,7 @@ struct biquad_d1: public biquad_coeffs<Coeff>
dsp::zero(x2);
dsp::zero(y2);
}
inline bool empty() {
inline bool empty() const {
return (y1 == 0.f && y2 == 0.f);
}
@@ -448,7 +448,7 @@ struct biquad_d2: public biquad_coeffs<Coeff>
}
/// Is the filter state completely silent? (i.e. set to 0 by sanitize function)
inline bool empty() {
inline bool empty() const {
return (w1 == 0.f && w2 == 0.f);
}
@@ -575,6 +575,74 @@ struct biquad_d1_lerp: public biquad_coeffs<Coeff>
};
/// Compose two filters in series
template<class F1, class F2>
class filter_compose {
public:
typedef std::complex<float> cfloat;
F1 f1;
F2 f2;
public:
float process(float value) {
return f2.process(f1.process(value));
}
inline cfloat h_z(const cfloat &z) const {
return f1.h_z(z) * f2.h_z(z);
}
/// Return the filter's gain at frequency freq
/// @param freq Frequency to look up
/// @param sr Filter sample rate (used to convert frequency to angular frequency)
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));
return std::abs(h_z(z));
}
void sanitize() {
f1.sanitize();
f2.sanitize();
}
};
/// Compose two filters in parallel
template<class F1, class F2>
class filter_sum {
public:
typedef std::complex<double> cfloat;
F1 f1;
F2 f2;
public:
float process(float value) {
return f2.process(value) + f1.process(value);
}
inline cfloat h_z(const cfloat &z) const {
return f1.h_z(z) + f2.h_z(z);
}
/// Return the filter's gain at frequency freq
/// @param freq Frequency to look up
/// @param sr Filter sample rate (used to convert frequency to angular frequency)
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));
return std::abs(h_z(z));
}
void sanitize() {
f1.sanitize();
f2.sanitize();
}
};
};
#endif

View File

@@ -197,6 +197,82 @@ 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;
}
};
/// Simple linear fade out for note tails
struct fadeout
{
float value;
float step, step_orig;
bool done, undoing;
fadeout(int steps = 256)
{
step_orig = (float)(1.f / steps);
value = 1.f;
reset();
}
/// Prepare fade out
void reset()
{
value = 1.f;
step = -step_orig;
done = false;
undoing = false;
}
/// Fade back in with double speed (to prevent click on note restart)
void undo()
{
step = step_orig;
done = false;
undoing = true;
}
/// Reset if fully faded out; fade back in if in the middle of fading out
void reset_soft()
{
if (value <= 0.f || value >= 1.f)
reset();
else
undo();
}
void process(float *buffer, int len)
{
int i = 0;
if (!done)
{
for (; value > 0 && value <= 1.0 && i < len; i++)
{
buffer[i] *= value;
value += step;
}
if (value <= 0 || value > 1)
done = true;
}
if (done && value <= 0)
{
while (i < len)
buffer[i++] = 0.f;
}
if (done && undoing && value >= 1)
{
undoing = false;
done = false;
// prepare for the next fade-out
value = 1.f;
}
}
};
};

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,16 +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 "primitives.h"
#include "preset.h"
#include <vector>
namespace osctl {
struct osc_client;
@@ -167,17 +166,17 @@ struct line_graph_iface
/// @param context cairo context to adjust (for multicolour graphs etc.)
/// @retval true graph data was returned; subindex+1 graph may or may not be available
/// @retval false graph data was not returned; subindex+1 graph does not exist either
virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) { return false; }
virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const { return false; }
/// Obtain subindex'th dot of parameter 'index'
/// @param index parameter/dot number (usually tied to particular plugin control port)
/// @param subindex dot number (there may be multiple dots graphs for one parameter)
virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) { return false; }
virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const { return false; }
/// Obtain subindex'th dot of parameter 'index'
/// @param index parameter/dot number (usually tied to particular plugin control port)
/// @param subindex dot number (there may be multiple dots graphs for one parameter)
virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) { return false; }
virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const { return false; }
/// Obtain subindex'th static graph of parameter index (static graphs are only dependent on parameter value, not plugin state)
/// @param index parameter/graph number (usually tied to particular plugin control port)
@@ -188,7 +187,7 @@ struct line_graph_iface
/// @param context cairo context to adjust (for multicolour graphs etc.)
/// @retval true graph data was returned; subindex+1 graph may or may not be available
/// @retval false graph data was not returned; subindex+1 graph does not exist either
virtual bool get_static_graph(int index, int subindex, float value, float *data, int points, cairo_iface *context) { return false; }
virtual bool get_static_graph(int index, int subindex, float value, float *data, int points, cairo_iface *context) const { return false; }
/// Return which graphs need to be redrawn and which can be cached for later reuse
/// @param index Parameter/graph number (usually tied to particular plugin control port)
@@ -197,7 +196,7 @@ struct line_graph_iface
/// @param subindex_dot First dot that has to be redrawn
/// @param subindex_gridline First gridline/legend that has to be redrawn
/// @retval Current generation (to pass when calling the function next time); if different than passed generation value, call the function again to retrieve which graph offsets should be put into cache
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) { subindex_graph = subindex_dot = subindex_gridline = 0; return 0; }
virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) const { subindex_graph = subindex_dot = subindex_gridline = 0; return 0; }
/// Standard destructor to make compiler happy
virtual ~line_graph_iface() {}
@@ -228,22 +227,22 @@ struct table_column_info
struct table_edit_iface
{
/// retrieve the table layout for specific parameter
virtual const table_column_info *get_table_columns(int param) = 0;
virtual const table_column_info *get_table_columns(int param) const = 0;
/// return the current number of rows
virtual uint32_t get_table_rows(int param) = 0;
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) { 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) { error.clear(); }
virtual void set_cell(int param, int row, int column, const std::string &src, std::string &error) const { error.clear(); }
/// return a line graph interface for a specific parameter/column (unused for now)
virtual line_graph_iface *get_graph_iface(int param, int column) { return NULL; }
virtual const line_graph_iface *get_graph_iface(int param, int column) const { return NULL; }
/// return an editor name for a specific grid cell (unused for now - I don't even know how editors be implemented)
virtual const char *get_cell_editor(int param, int column) { return NULL; }
virtual const char *get_cell_editor(int param, int column) const { return NULL; }
virtual ~table_edit_iface() {}
};
@@ -293,56 +292,58 @@ struct ladspa_plugin_info
struct plugin_metadata_iface
{
/// @return plugin long name
virtual const char *get_name() = 0;
virtual const char *get_name() const = 0;
/// @return plugin LV2 label
virtual const char *get_id() = 0;
virtual const char *get_id() const = 0;
/// @return plugin human-readable label
virtual const char *get_label() = 0;
virtual const char *get_label() const = 0;
/// @return total number of parameters
virtual int get_param_count() = 0;
virtual int get_param_count() const = 0;
/// Return custom XML
virtual const char *get_gui_xml() = 0;
virtual const char *get_gui_xml() const = 0;
/// @return number of audio inputs
virtual int get_input_count()=0;
virtual int get_input_count() const =0;
/// @return number of audio outputs
virtual int get_output_count()=0;
virtual int get_output_count() const =0;
/// @return number of optional inputs
virtual int get_inputs_optional() const =0;
/// @return number of optional outputs
virtual int get_outputs_optional() const =0;
/// @return true if plugin can work in hard-realtime conditions
virtual bool is_rt_capable()=0;
virtual bool is_rt_capable() const =0;
/// @return true if plugin has MIDI input
virtual bool get_midi()=0;
virtual bool get_midi() const =0;
/// @return true if plugin has MIDI input
virtual bool requires_midi()=0;
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() = 0;
/// @return line_graph_iface if any
virtual line_graph_iface *get_line_graph_iface() = 0;
virtual int get_param_port_offset() const = 0;
/// @return table_edit_iface if any
virtual table_edit_iface *get_table_edit_iface() = 0;
virtual const table_edit_iface *get_table_edit_iface() const = 0;
/// @return NULL-terminated list of menu commands
virtual plugin_command_info *get_commands() { return NULL; }
virtual plugin_command_info *get_commands() const { return NULL; }
/// @return description structure for given parameter
virtual parameter_properties *get_param_props(int param_no) = 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() = 0;
virtual const char **get_port_names() const = 0;
/// @return description structure for the plugin
virtual const ladspa_plugin_info &get_plugin_info() = 0;
virtual const ladspa_plugin_info &get_plugin_info() const = 0;
/// is a given parameter a control voltage?
virtual bool is_cv(int param_no) = 0;
virtual bool is_cv(int param_no) const = 0;
/// is the given parameter non-interpolated?
virtual bool is_noisy(int param_no) = 0;
virtual bool is_noisy(int param_no) const = 0;
/// does the plugin require message context? (or DSSI configure) may be slow
virtual bool requires_message_context() = 0;
virtual bool requires_message_context() const = 0;
/// does the plugin require string port extension? (or DSSI configure) may be slow
virtual bool requires_string_ports() = 0;
virtual bool requires_string_ports() const = 0;
/// add all message context parameter numbers to the ports vector
virtual void get_message_context_parameters(std::vector<int> &ports) = 0;
virtual void get_message_context_parameters(std::vector<int> &ports) const = 0;
/// Do-nothing destructor to silence compiler warning
virtual ~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;
@@ -355,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
@@ -365,80 +366,196 @@ 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() {}
};
struct plugin_list_info_iface;
/// Get a list of all "large" (effect/synthesizer) plugins
extern void get_all_plugins(std::vector<plugin_metadata_iface *> &plugins);
/// Get a list of all "small" (module) plugins
extern void get_all_small_plugins(plugin_list_info_iface *plii);
/// A class to retrieve and query the list of Calf plugins
class plugin_registry
{
public:
typedef std::vector<const plugin_metadata_iface *> plugin_vector;
private:
plugin_vector plugins;
plugin_registry();
public:
/// Get the singleton object.
static plugin_registry &instance();
/// Get all plugin metadata objects
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
{
@@ -457,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();
};
@@ -474,38 +594,40 @@ 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
const char *get_name() { return Metadata::impl_get_name(); }
const char *get_id() { return Metadata::impl_get_id(); }
const char *get_label() { return Metadata::impl_get_label(); }
int get_input_count() { return Metadata::in_count; }
int get_output_count() { return Metadata::out_count; }
int get_param_count() { return Metadata::param_count; }
bool get_midi() { return Metadata::support_midi; }
bool requires_midi() { return Metadata::require_midi; }
bool is_rt_capable() { return Metadata::rt_capable; }
line_graph_iface *get_line_graph_iface() { return dynamic_cast<line_graph_iface *>(this); }
table_edit_iface *get_table_edit_iface() { return dynamic_cast<table_edit_iface *>(this); }
int get_param_port_offset() { return Metadata::in_count + Metadata::out_count; }
const char *get_gui_xml() { static const char *data_ptr = calf_plugins::load_gui_xml(get_id()); return data_ptr; }
plugin_command_info *get_commands() { return NULL; }
parameter_properties *get_param_props(int param_no) { return &param_props[param_no]; }
const char **get_port_names() { return port_names; }
bool is_cv(int param_no) { return true; }
bool is_noisy(int param_no) { return false; }
const ladspa_plugin_info &get_plugin_info() { return plugin_info; }
bool requires_message_context() { return check_for_message_context_ports(param_props, Metadata::param_count); }
bool requires_string_ports() { return check_for_string_ports(param_props, Metadata::param_count); }
void get_message_context_parameters(std::vector<int> &ports) {
const char *get_name() const { return Metadata::impl_get_name(); }
const char *get_id() const { return Metadata::impl_get_id(); }
const char *get_label() const { return Metadata::impl_get_label(); }
int get_input_count() const { return Metadata::in_count; }
int get_output_count() const { return Metadata::out_count; }
int get_inputs_optional() const { return Metadata::ins_optional; }
int get_outputs_optional() const { return Metadata::outs_optional; }
int get_param_count() const { return Metadata::param_count; }
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 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; }
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; }
const ladspa_plugin_info &get_plugin_info() const { return plugin_info; }
bool requires_message_context() const { return check_for_message_context_ports(param_props, Metadata::param_count); }
bool requires_string_ports() const { return check_for_string_ports(param_props, Metadata::param_count); }
void get_message_context_parameters(std::vector<int> &ports) const {
for (int i = 0; i < get_param_count(); ++i) {
if (get_param_props(i)->flags & PF_PROP_MSGCONTEXT)
ports.push_back(i);
@@ -513,40 +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:
plugin_metadata_iface *impl;
public:
plugin_metadata_proxy(plugin_metadata_iface *_impl) { impl = _impl; }
const char *get_name() { return impl->get_name(); }
const char *get_id() { return impl->get_id(); }
const char *get_label() { return impl->get_label(); }
int get_input_count() { return impl->get_input_count(); }
int get_output_count() { return impl->get_output_count(); }
int get_param_count() { return impl->get_param_count(); }
bool get_midi() { return impl->get_midi(); }
bool requires_midi() { return impl->requires_midi(); }
bool is_rt_capable() { return impl->is_rt_capable(); }
line_graph_iface *get_line_graph_iface() { return impl->get_line_graph_iface(); }
table_edit_iface *get_table_edit_iface() { return impl->get_table_edit_iface(); }
int get_param_port_offset() { return impl->get_param_port_offset(); }
const char *get_gui_xml() { return impl->get_gui_xml(); }
plugin_command_info *get_commands() { return impl->get_commands(); }
parameter_properties *get_param_props(int param_no) { return impl->get_param_props(param_no); }
const char **get_port_names() { return impl->get_port_names(); }
bool is_cv(int param_no) { return impl->is_cv(param_no); }
bool is_noisy(int param_no) { return impl->is_noisy(param_no); }
const ladspa_plugin_info &get_plugin_info() { return impl->get_plugin_info(); }
bool requires_message_context() { return impl->requires_message_context(); }
bool requires_string_ports() { return impl->requires_string_ports(); }
void get_message_context_parameters(std::vector<int> &ports) { 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
@@ -555,9 +643,52 @@ public:
static const char *impl_get_id() { return id; } \
static const char *impl_get_label() { return label; } \
extern const char *calf_copyright_info;
bool get_freq_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context, bool use_frequencies = true);
/// convert amplitude value to normalized grid-ish value (0dB = 0.5, 30dB = 1.0, -30 dB = 0.0, -60dB = -0.5, -90dB = -1.0)
static inline float dB_grid(float amp)
{
return log(amp) * (1.0 / log(256.0)) + 0.4;
}
template<class Fx>
static bool get_graph(Fx &fx, int subindex, float *data, int points)
{
for (int i = 0; i < points; i++)
{
typedef std::complex<double> cfloat;
double freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points);
data[i] = dB_grid(fx.freq_gain(subindex, freq, fx.srate));
}
return true;
}
/// convert normalized grid-ish value back to amplitude value
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

@@ -245,7 +245,7 @@ public:
}
void set_sample_rate(int sr)
{
ramp = linear_ramp(sr / 441);
ramp = linear_ramp(sr / 100);
}
// to change param, use set_inertia(value)
// to read param, use get()

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,101 @@
/* -*- Mode: C ; c-basic-offset: 2 -*- */
/*****************************************************************************
*
* This work is in public domain.
*
* This file 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.
*
* If you have questions, contact Nedko Arnaudov <nedko@arnaudov.name> or
* ask in #lad channel, FreeNode IRC network.
*
*****************************************************************************/
#ifndef LV2_EXTERNAL_UI_H__5AFE09A5_0FB7_47AF_924E_2AF0F8DE8873__INCLUDED
#define LV2_EXTERNAL_UI_H__5AFE09A5_0FB7_47AF_924E_2AF0F8DE8873__INCLUDED
/** UI extension suitable for out-of-process UIs */
#define LV2_EXTERNAL_UI_URI "http://lv2plug.in/ns/extensions/ui#external"
#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* Adjust editor indent */
#endif
/**
* When LV2_EXTERNAL_UI_URI UI is instantiated, the returned
* LV2UI_Widget handle must be cast to pointer to struct lv2_external_ui.
* UI is created in invisible state.
*/
struct lv2_external_ui
{
/**
* Host calls this function regulary. UI library implementing the
* callback may do IPC or redraw the UI.
*
* @param _this_ the UI context
*/
void (* run)(struct lv2_external_ui * _this_);
/**
* Host calls this function to make the plugin UI visible.
*
* @param _this_ the UI context
*/
void (* show)(struct lv2_external_ui * _this_);
/**
* Host calls this function to make the plugin UI invisible again.
*
* @param _this_ the UI context
*/
void (* hide)(struct lv2_external_ui * _this_);
};
#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr)
#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr)
#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr)
/**
* On UI instantiation, host must supply LV2_EXTERNAL_UI_URI
* feature. LV2_Feature::data must be pointer to struct lv2_external_ui_host. */
struct lv2_external_ui_host
{
/**
* Callback that plugin UI will call
* when UI (GUI window) is closed by user.
* This callback wil; be called during execution of lv2_external_ui::run()
* (i.e. not from background thread).
*
* After this callback is called, UI is defunct. Host must call
* LV2UI_Descriptor::cleanup(). If host wants to make the UI visible
* again UI must be reinstantiated.
*
* @param controller Host context associated with plugin UI, as
* supplied to LV2UI_Descriptor::instantiate()
*/
void (* ui_closed)(LV2UI_Controller controller);
/**
* Optional (may be NULL) "user friendly" identifier which the UI
* may display to allow a user to easily associate this particular
* UI instance with the correct plugin instance as it is represented
* by the host (e.g. "track 1" or "channel 4").
*
* If supplied by host, the string will be referenced only during
* LV2UI_Descriptor::instantiate()
*/
const char * plugin_human_id;
};
#if 0
{ /* Adjust editor indent */
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* #ifndef LV2_EXTERNAL_UI_H__5AFE09A5_0FB7_47AF_924E_2AF0F8DE8873__INCLUDED */

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 line_graph_iface *get_line_graph_iface()
{
return dynamic_cast<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()
{
return Module::get_name();
}
virtual const char *get_id()
{
return Module::get_id();
}
virtual const char *get_label()
{
return Module::get_label();
}
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);
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

@@ -31,21 +31,21 @@ struct flanger_metadata: public plugin_metadata<flanger_metadata>
{
public:
enum { par_delay, par_depth, par_rate, par_fb, par_stereo, par_reset, par_amount, par_dryamount, param_count };
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
PLUGIN_NAME_ID_LABEL("flanger", "flanger", "Flanger")
};
struct phaser_metadata: public plugin_metadata<phaser_metadata>
{
enum { par_freq, par_depth, par_rate, par_fb, par_stages, par_stereo, par_reset, par_amount, par_dryamount, param_count };
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
PLUGIN_NAME_ID_LABEL("phaser", "phaser", "Phaser")
};
struct filter_metadata: public plugin_metadata<filter_metadata>
{
enum { par_cutoff, par_resonance, par_mode, par_inertia, param_count };
enum { in_count = 2, out_count = 2, rt_capable = true, require_midi = false, support_midi = false };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, require_midi = false, support_midi = false };
PLUGIN_NAME_ID_LABEL("filter", "filter", "Filter")
/// do not export mode and inertia as CVs, as those are settings and not parameters
bool is_cv(int param_no) { return param_no != par_mode && param_no != par_inertia; }
@@ -55,7 +55,7 @@ struct filter_metadata: public plugin_metadata<filter_metadata>
struct filterclavier_metadata: public plugin_metadata<filterclavier_metadata>
{
enum { par_transpose, par_detune, par_max_resonance, par_mode, par_inertia, param_count };
enum { in_count = 2, out_count = 2, rt_capable = true, require_midi = true, support_midi = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, require_midi = true, support_midi = true };
PLUGIN_NAME_ID_LABEL("filterclavier", "filterclavier", "Filterclavier")
/// do not export mode and inertia as CVs, as those are settings and not parameters
bool is_cv(int param_no) { return param_no != par_mode && param_no != par_inertia; }
@@ -64,14 +64,14 @@ struct filterclavier_metadata: public plugin_metadata<filterclavier_metadata>
struct reverb_metadata: public plugin_metadata<reverb_metadata>
{
enum { par_clip, par_meter_wet, par_meter_out, par_decay, par_hfdamp, par_roomsize, par_diffusion, par_amount, par_dry, par_predelay, par_basscut, par_treblecut, param_count };
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
PLUGIN_NAME_ID_LABEL("reverb", "reverb", "Reverb")
};
struct vintage_delay_metadata: public plugin_metadata<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 { in_count = 2, out_count = 2, rt_capable = true, support_midi = false, require_midi = false };
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")
};
@@ -79,7 +79,7 @@ struct rotary_speaker_metadata: public plugin_metadata<rotary_speaker_metadata>
{
public:
enum { par_speed, par_spacing, par_shift, par_moddepth, par_treblespeed, par_bassspeed, par_micdistance, par_reflection, par_meter_l, par_meter_h, param_count };
enum { in_count = 2, out_count = 2, support_midi = true, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = false, rt_capable = true };
PLUGIN_NAME_ID_LABEL("rotary_speaker", "rotaryspeaker", "Rotary Speaker")
};
@@ -88,20 +88,32 @@ struct multichorus_metadata: public plugin_metadata<multichorus_metadata>
{
public:
enum { par_delay, par_depth, par_rate, par_stereo, par_voices, par_vphase, par_amount, par_dryamount, par_freq, par_freq2, par_q, par_overlap, param_count };
enum { in_count = 2, out_count = 2, rt_capable = true, support_midi = false, require_midi = false };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, rt_capable = true, support_midi = false, require_midi = false };
PLUGIN_NAME_ID_LABEL("multichorus", "multichorus", "Multi Chorus")
};
enum CalfEqMode {
MODE12DB,
MODE24DB,
MODE36DB
};
/// Monosynth - metadata
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_window1,
par_lfo1trig, par_lfo2trig,
par_lfo2rate, par_lfo2delay,
param_count };
enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = true };
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
enum { step_size = 64, step_shift = 6 };
enum {
modsrc_none,
@@ -109,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 {
@@ -122,24 +136,27 @@ 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")
};
/// Thor's compressor - metadata
/// Added some meters and stripped the weighting part
struct compressor_metadata: public plugin_metadata<compressor_metadata>
{
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_aweighting, param_compression, param_peak, param_clip, param_bypass, param_input,// param_freq, param_bw,
param_count };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_level_in, param_meter_in, param_meter_out, param_clip_in, param_clip_out,
param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_compression,
param_count };
PLUGIN_NAME_ID_LABEL("compressor", "compressor", "Compressor")
};
/// Markus's sidechain compressor - metadata
struct sidechaincompressor_metadata: public plugin_metadata<sidechaincompressor_metadata>
{
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_level_in, param_meter_in, param_meter_out, param_clip_in, param_clip_out,
param_threshold, param_ratio, param_attack, param_release, param_makeup, param_knee, param_detection, param_stereo_link, param_compression,
param_sc_mode, param_f1_freq, param_f2_freq, param_f1_level, param_f2_level,
@@ -150,7 +167,7 @@ struct sidechaincompressor_metadata: public plugin_metadata<sidechaincompressor_
/// Markus's multibandcompressor - metadata
struct multibandcompressor_metadata: public plugin_metadata<multibandcompressor_metadata>
{
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
param_meter_outL, param_meter_outR, param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR,
param_freq0, param_freq1, param_freq2,
@@ -171,7 +188,7 @@ struct multibandcompressor_metadata: public plugin_metadata<multibandcompressor_
/// Markus's deesser - metadata
struct deesser_metadata: public plugin_metadata<deesser_metadata>
{
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_detected, param_compression, param_detected_led, param_clip_out,
param_detection, param_mode,
param_threshold, param_ratio, param_laxity, param_makeup,
@@ -183,21 +200,25 @@ struct deesser_metadata: public plugin_metadata<deesser_metadata>
/// Markus's 5-band EQ - metadata
struct equalizer5band_metadata: public plugin_metadata<equalizer5band_metadata>
{
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_level_in, param_level_out, param_meter_in,
param_meter_out, param_clip_in, param_clip_out,
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
param_meter_outL, param_meter_outR, param_clip_inL, param_clip_outL, param_clip_inR, param_clip_outR,
param_ls_active, param_ls_level, param_ls_freq,
param_hs_active, param_hs_level, param_hs_freq,
param_p1_active, param_p1_level, param_p1_freq, param_p1_q,
param_p2_active, param_p2_level, param_p2_freq, param_p2_q,
param_p3_active, param_p3_level, param_p3_freq, param_p3_q,
param_count };
PLUGIN_NAME_ID_LABEL("equalizer5band", "equalizer5band", "Equalizer 5 Band")
// dummy parameter numbers, shouldn't be used EVER, they're only there to avoid pushing LP/HP filters to a separate class
// and potentially making inlining and optimization harder for the compiler
enum { param_lp_active = 0xDEADBEEF, param_hp_active, param_hp_mode, param_lp_mode, param_hp_freq, param_lp_freq };
enum { PeakBands = 3, first_graph_param = param_ls_active, last_graph_param = param_p3_q };
PLUGIN_NAME_ID_LABEL("equalizer5band", "eq5", "Equalizer 5 Band")
};
/// Markus's 8-band EQ - metadata
struct equalizer8band_metadata: public plugin_metadata<equalizer8band_metadata>
{
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
param_meter_outL, param_meter_outR, param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR,
param_hp_active, param_hp_freq, param_hp_mode,
@@ -209,12 +230,13 @@ struct equalizer8band_metadata: public plugin_metadata<equalizer8band_metadata>
param_p3_active, param_p3_level, param_p3_freq, param_p3_q,
param_p4_active, param_p4_level, param_p4_freq, param_p4_q,
param_count };
PLUGIN_NAME_ID_LABEL("equalizer8band", "equalizer8band", "Equalizer 8 Band")
enum { PeakBands = 4, first_graph_param = param_hp_active, last_graph_param = param_p4_q };
PLUGIN_NAME_ID_LABEL("equalizer8band", "eq8", "Equalizer 8 Band")
};
/// Markus's 12-band EQ - metadata
struct equalizer12band_metadata: public plugin_metadata<equalizer12band_metadata>
{
enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
param_meter_outL, param_meter_outR, param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR,
param_hp_active, param_hp_freq, param_hp_mode,
@@ -230,7 +252,56 @@ struct equalizer12band_metadata: public plugin_metadata<equalizer12band_metadata
param_p7_active, param_p7_level, param_p7_freq, param_p7_q,
param_p8_active, param_p8_level, param_p8_freq, param_p8_q,
param_count };
PLUGIN_NAME_ID_LABEL("equalizer12band", "equalizer12band", "Equalizer 12 Band")
enum { PeakBands = 8, first_graph_param = param_hp_active, last_graph_param = param_p8_q };
PLUGIN_NAME_ID_LABEL("equalizer12band", "eq12", "Equalizer 12 Band")
};
/// Markus's Pulsator - metadata
struct pulsator_metadata: public plugin_metadata<pulsator_metadata>
{
enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
param_meter_outL, param_meter_outR, param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR,
param_mode, param_freq, param_amount, param_offset, param_mono, param_reset, param_count };
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
@@ -319,19 +390,17 @@ struct organ_enums
/// Organ - metadata
struct organ_metadata: public organ_enums, public plugin_metadata<organ_metadata>
{
enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = true };
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
PLUGIN_NAME_ID_LABEL("organ", "organ", "Organ")
plugin_command_info *get_commands();
const char **get_default_configure_vars();
};
/// FluidSynth - metadata
struct fluidsynth_metadata: public plugin_metadata<fluidsynth_metadata>
{
enum { par_master, par_soundfont, par_interpolation, par_reverb, par_chorus, param_count };
enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = false };
enum { 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
@@ -399,7 +468,7 @@ struct wavetable_metadata: public plugin_metadata<wavetable_metadata>
par_eg3attack, par_eg3decay, par_eg3sustain, par_eg3fade, par_eg3release, par_eg3velscl,
par_pwhlrange,
param_count };
enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = true };
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
enum { step_size = 64 };
PLUGIN_NAME_ID_LABEL("wavetable", "wavetable", "Wavetable")
};

View File

@@ -84,10 +84,10 @@ protected:
mod_matrix(dsp::modulation_entry *_matrix, unsigned int _rows, const char **_src_names, const char **_dest_names);
public:
virtual const table_column_info *get_table_columns(int param);
virtual uint32_t get_table_rows(int param);
virtual std::string get_cell(int param, int row, int column);
virtual void set_cell(int param, int row, int column, const std::string &src, std::string &error);
virtual const table_column_info *get_table_columns(int param) const;
virtual uint32_t get_table_rows(int param) const;
virtual std::string get_cell(int param, int row, int column) const;
virtual void set_cell(int param, int row, int column, const std::string &src, std::string &error) const;
/// Process modulation matrix, calculate outputs from inputs
inline void calculate_modmatrix(float *moddest, int moddest_count, float *modsrc)

View File

@@ -0,0 +1,29 @@
#ifdef PER_MODULE_ITEM
PER_MODULE_ITEM(filter, false, "filter")
PER_MODULE_ITEM(filterclavier, false, "filterclavier")
PER_MODULE_ITEM(flanger, false, "flanger")
PER_MODULE_ITEM(reverb, false, "reverb")
PER_MODULE_ITEM(monosynth, true, "monosynth")
PER_MODULE_ITEM(vintage_delay, false, "vintagedelay")
PER_MODULE_ITEM(organ, true, "organ")
PER_MODULE_ITEM(rotary_speaker, false, "rotaryspeaker")
PER_MODULE_ITEM(phaser, false, "phaser")
PER_MODULE_ITEM(multichorus, false, "multichorus")
PER_MODULE_ITEM(compressor, false, "compressor")
PER_MODULE_ITEM(sidechaincompressor, false, "sidechaincompressor")
PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
PER_MODULE_ITEM(deesser, false, "deesser")
PER_MODULE_ITEM(pulsator, false, "pulsator")
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")
#endif
#undef PER_MODULE_ITEM
#endif

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,21 +41,26 @@ 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;
bool running, stopping, gate, force_fadeout;
dsp::triangle_lfo lfo1, lfo2;
dsp::biquad_d1_lerp<float> filter, filter2;
/// The step code is producing non-zero values
bool running;
/// This is the last non-zero buffer (set on calculate_step after fadeout is complete, the next calculate_step will zero running)
bool stopping;
/// A key is kept pressed
bool gate;
/// All notes off fadeout
bool force_fadeout;
/// Last triggered note
int last_key;
/// Output buffers, used to ensure updates are done every step_size regardless of process buffer size
float buffer[step_size], buffer2[step_size];
/// Read position within the buffers, on each '0' the buffers are being filled with new data by calculate_step
uint32_t output_pos;
dsp::onepole<float> phaseshifter;
dsp::biquad_d1_lerp<float> filter;
dsp::biquad_d1_lerp<float> filter2;
/// Waveform number - OSC1
int wave1;
/// Waveform number - OSC2
@@ -65,19 +69,40 @@ public:
int prev_wave1;
/// 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 detune, xpose, xfade, ampctl, fltctl, queue_vel;
float odcr, porta_time, lfo_bend, lfo_clock, last_lfov, modwheel_value;
/// Filter type
int filter_type;
/// Filter type on the last calculate_step
int last_filter_type;
float freq, start_freq, target_freq, cutoff, fgain, fgain_delta, separation;
float detune, xpose, xfade, ampctl, fltctl;
float odcr, porta_time, lfo_bend;
/// Modulation wheel position (0.f-1.f)
float 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;
int queue_note_on, stop_count, modwheel_value_int;
/// Last value of stretch for osc sync emulation for OSC1
int32_t last_stretch1;
/// Next note to play on the next calculate_step
int queue_note_on;
/// Velocity of the next note to play
float queue_vel;
/// Integer value for modwheel (0-16383, read from CC1 - MSBs and CC33 - LSBs)
int modwheel_value_int;
/// Legato mode (bitmask)
int legato;
dsp::adsr envelope;
/// Envelope Generators
dsp::adsr envelope1, envelope2;
dsp::keystack stack;
/// Smoothing for master volume
dsp::gain_smoothing master;
/// Fadeout for buffer 1
dsp::fadeout fadeout;
/// Fadeout for buffer 2
dsp::fadeout fadeout2;
/// Smoothed cutoff value
dsp::inertia<dsp::exponential_ramp> inertia_cutoff;
/// Smoothed pitch bend value
@@ -132,7 +157,7 @@ public:
/// Run two filters (one per channel) to produce stereo output samples.
void calculate_buffer_stereo();
/// Retrieve filter graph (which is 'live' so it cannot be generated by get_static_graph), or fall back to get_static_graph.
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context);
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
/// @retval true if the filter 1 is to be used for the left channel and filter 2 for the right channel
/// @retval false if filters are to be connected in series and sent (mono) to both channels
inline bool is_stereo_filter() const
@@ -140,91 +165,17 @@ public:
return filter_type == flt_2lp12 || filter_type == flt_2bp6;
}
/// No CV inputs for now
bool is_cv(int param_no) { return false; }
bool is_cv(int param_no) const { return false; }
/// Practically all the stuff here is noisy
bool is_noisy(int param_no) { return param_no != par_cutoff; }
bool is_noisy(int param_no) const { return param_no != par_cutoff; }
/// Calculate control signals and produce step_size samples of output.
void calculate_step();
/// Apply anti-click'n'pop fadeout (used at the end of the sound)
void apply_fadeout();
/// Main processing function
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

@@ -80,7 +80,7 @@ public:
voice_depth = (unsigned int)((1U << 30) * 1.0 * scaling);
}
/// Get LFO value for given voice, returns a values in range of [-65536, 65535] (or close)
inline int get_value(uint32_t voice) {
inline int get_value(uint32_t voice) const {
// find this voice's phase (= phase + voice * 360 degrees / number of voices)
chorus_phase voice_phase = phase + vphase * (int)voice;
// find table offset
@@ -178,7 +178,7 @@ public:
}
post.sanitize();
}
float freq_gain(float freq, float sr)
float freq_gain(float freq, float sr) const
{
typedef std::complex<double> cfloat;
freq *= 2.0 * M_PI / sr;

View File

@@ -144,7 +144,7 @@ public:
return out;
}
inline bool empty() {
inline bool empty() const {
return y1 == 0;
}
@@ -171,7 +171,7 @@ public:
/// Return the filter's gain at frequency freq
/// @param freq Frequency to look up
/// @param sr Filter sample rate (used to convert frequency to angular frequency)
float freq_gain(float freq, float sr)
float freq_gain(float freq, float sr) const
{
freq *= 2.0 * M_PI / sr;
cfloat z = 1.0 / exp(cfloat(0.0, freq));
@@ -181,7 +181,7 @@ public:
/// Return H(z) the filter's gain at frequency freq
/// @param z Z variable (e^jw)
cfloat h_z(const cfloat &z)
cfloat h_z(const cfloat &z) const
{
return (cfloat(a0) + double(a1) * z) / (cfloat(1.0) + double(b1) * z);
}

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

@@ -0,0 +1,2 @@
#include <calf/osctl.h>

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"
@@ -89,6 +85,26 @@ typedef std::vector<plugin_preset> preset_vector;
/// A single list of presets (usually there are two - @see get_builtin_presets(), get_user_presets() )
struct preset_list
{
/// Plugin list item
struct plugin_snapshot
{
/// Preset offset
int preset_offset;
/// Plugin type
std::string type;
/// Instance name
std::string instance_name;
/// Index of the first input port
int input_index;
/// Index of the first output port
int output_index;
/// Index of the first MIDI port
int midi_index;
/// Reset to initial values
void reset();
};
/// Parser states
enum parser_state
{
@@ -97,24 +113,33 @@ struct preset_list
PRESET, ///< Inside preset definition
VALUE, ///< Inside (empty) param tag
VAR, ///< Inside (non-empty) var tag
PLUGIN, ///< Inside plugin element (calfjackhost snapshots only)
RACK, ///< Inside rack element (calfjackhost snapshots only)
} state;
/// Contained presets (usually for all plugins)
preset_vector presets;
/// Temporary preset used during parsing process
plugin_preset parser_preset;
/// Temporary plugin desc used during parsing process
plugin_snapshot parser_plugin;
/// Preset number counters for DSSI (currently broken)
std::map<std::string, int> last_preset_ids;
/// The key used in current <var name="key"> tag (for state == VAR)
std::string current_key;
/// The file is loaded in rack mode (and rack/plugin elements are expected)
bool rack_mode;
/// List of plugin states for rack mode
std::vector<plugin_snapshot> plugins;
/// Return the name of the built-in or user-defined preset file
static std::string get_preset_filename(bool builtin);
/// Load default preset list (built-in or user-defined)
bool load_defaults(bool builtin);
void parse(const std::string &data);
/// Load preset list from an in-memory XML string
void parse(const std::string &data, bool in_rack_mode);
/// Load preset list from XML file
void load(const char *filename);
void load(const char *filename, bool in_rack_mode);
/// Save preset list as XML file
void save(const char *filename);
/// Append or replace a preset (replaces a preset with the same plugin and preset name)

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 () {}
};
@@ -147,6 +148,9 @@ extern std::string f2s(double value);
/// float-to-string-that-doesn't-resemble-an-int
extern std::string ff2s(double value);
/// Encode a key-value pair as XML attribute
std::string to_xml_attr(const std::string &key, const std::string &value);
/// Escape a string to be used in XML file
std::string xml_escape(const std::string &src);

View File

@@ -0,0 +1 @@
#define USE_LADSPA 1

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)
}
}
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--)
{
@@ -235,7 +237,121 @@ bool calf_plugins::check_for_string_ports(parameter_properties *parameters, int
return false;
}
#if USE_DSSI
bool calf_plugins::get_freq_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context, bool use_frequencies)
{
if (subindex < 0 )
return false;
if (use_frequencies)
{
if (subindex < 28)
{
vertical = true;
if (subindex == 9) legend = "100 Hz";
if (subindex == 18) legend = "1 kHz";
if (subindex == 27) legend = "10 kHz";
float freq = 100;
if (subindex < 9)
freq = 10 * (subindex + 1);
else if (subindex < 18)
freq = 100 * (subindex - 9 + 1);
else if (subindex < 27)
freq = 1000 * (subindex - 18 + 1);
else
freq = 10000 * (subindex - 27 + 1);
pos = log(freq / 20.0) / log(1000);
if (!legend.empty())
context->set_source_rgba(0, 0, 0, 0.2);
else
context->set_source_rgba(0, 0, 0, 0.1);
return true;
}
subindex -= 28;
}
if (subindex >= 32)
return false;
float gain = 16.0 / (1 << subindex);
pos = dB_grid(gain);
if (pos < -1)
return false;
if (subindex != 4)
context->set_source_rgba(0, 0, 0, subindex & 1 ? 0.1 : 0.2);
if (!(subindex & 1))
{
std::stringstream ss;
ss << (24 - 6 * subindex) << " dB";
legend = ss.str();
}
vertical = false;
return true;
}
void calf_plugins::set_channel_color(cairo_iface *context, int channel)
{
if (channel & 1)
context->set_source_rgba(0.35, 0.4, 0.2, 1);
else
context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
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()
{
static calf_plugins::plugin_registry registry;
return registry;
}
const plugin_metadata_iface *calf_plugins::plugin_registry::get_by_uri(const char *plugin_uri)
{
static const char prefix[] = "http://calf.sourceforge.net/plugins/";
if (strncmp(plugin_uri, prefix, sizeof(prefix) - 1))
return NULL;
const char *label = plugin_uri + sizeof(prefix) - 1;
for (unsigned int i = 0; i < plugins.size(); i++)
{
if (!strcmp(plugins[i]->get_plugin_info().label, label))
return plugins[i];
}
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;
}
///////////////////////////////////////////////////////////////////////////////////////
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;
@@ -251,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++)
{
@@ -295,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)
@@ -313,13 +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;
@@ -59,17 +60,17 @@ mod_matrix::mod_matrix(modulation_entry *_matrix, unsigned int _rows, const char
matrix[i].reset();
}
const table_column_info *mod_matrix::get_table_columns(int param)
const table_column_info *mod_matrix::get_table_columns(int param) const
{
return table_columns;
}
uint32_t mod_matrix::get_table_rows(int param)
uint32_t mod_matrix::get_table_rows(int param) const
{
return matrix_rows;
}
std::string mod_matrix::get_cell(int param, int row, int column)
std::string mod_matrix::get_cell(int param, int row, int column) const
{
assert(row >= 0 && row < (int)matrix_rows);
modulation_entry &slot = matrix[row];
@@ -90,7 +91,7 @@ std::string mod_matrix::get_cell(int param, int row, int column)
}
}
void mod_matrix::set_cell(int param, int row, int column, const std::string &src, std::string &error)
void mod_matrix::set_cell(int param, int row, int column, const std::string &src, std::string &error) const
{
assert(row >= 0 && row < (int)matrix_rows);
modulation_entry &slot = matrix[row];

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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
};
@@ -68,7 +65,6 @@ void monosynth_audio_module::activate() {
running = false;
output_pos = 0;
queue_note_on = -1;
stop_count = 0;
inertia_pitchbend.set_now(1.f);
lfo_bend = 1.0;
modwheel_value = 0.f;
@@ -79,6 +75,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;
@@ -204,7 +201,7 @@ void monosynth_audio_module::precalculate_waves(progress_report_iface *reporter)
}
bool monosynth_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
bool monosynth_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
{
monosynth_audio_module::precalculate_waves(NULL);
// printf("get_graph %d %p %d wave1=%d wave2=%d\n", index, data, points, wave1, wave2);
@@ -225,8 +222,25 @@ bool monosynth_audio_module::get_graph(int index, int subindex, float *data, int
if (wave == wave_sqr)
wave = wave_saw;
float *waveform = waves[wave].original;
float rnd_start = 1 - *params[par_window1] * 0.5f;
float scl = rnd_start < 1.0 ? 1.f / (1 - rnd_start) : 0.f;
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;
float r = 1;
if (index == par_wave1)
{
float ph = i * 1.0 / points;
if (ph < 0.5f)
ph = 1.f - ph;
ph = (ph - rnd_start) * scl;
if (ph < 0)
ph = 0;
r = 1.0 - ph * ph;
pos = int(pos * 1.0 * last_stretch1 / 65536.0 ) % S;
}
data[i] = r * (sign * waveform[pos] + waveform[(pos + shift) & (S - 1)]) / (sign == -1 ? 1 : 2);
}
return true;
}
if (index == par_filtertype) {
@@ -239,7 +253,7 @@ bool monosynth_audio_module::get_graph(int index, int subindex, float *data, int
typedef complex<double> cfloat;
double freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points);
dsp::biquad_d1_lerp<float> &f = subindex ? filter2 : filter;
const dsp::biquad_d1_lerp<float> &f = subindex ? filter2 : filter;
float level = f.freq_gain(freq, srate);
if (!is_stereo_filter())
level *= filter2.freq_gain(freq, srate);
@@ -252,19 +266,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);
@@ -274,14 +293,25 @@ void monosynth_audio_module::calculate_buffer_oscs(float lfo)
float cur_xfade = last_xfade;
float xfade_step = (new_xfade - cur_xfade) * (1.0 / step_size);
float rnd_start = 1 - *params[par_window1] * 0.5f;
float scl = rnd_start < 1.0 ? 1.f / (1 - rnd_start) : 0.f;
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);
float o1phase = osc1.phase / (65536.0 * 65536.0);
if (o1phase < 0.5)
o1phase = 1 - o1phase;
o1phase = (o1phase - rnd_start) * scl;
if (o1phase < 0)
o1phase = 0;
float r = 1.0 - o1phase * o1phase;
buffer[i] = lerp(r * 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;
@@ -320,16 +350,15 @@ void monosynth_audio_module::calculate_buffer_stereo()
for (uint32_t i = 0; i < step_size; i++)
{
float wave1 = buffer[i] * fgain;
float wave2 = phaseshifter.process_ap(wave1);
buffer[i] = fgain * filter.process(wave1);
buffer2[i] = fgain * filter2.process(wave2);
buffer2[i] = fgain * filter2.process(wave1);
fgain += fgain_delta;
}
}
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;
@@ -340,7 +369,8 @@ void monosynth_audio_module::lookup_waveforms()
void monosynth_audio_module::delayed_note_on()
{
force_fadeout = false;
stop_count = 0;
fadeout.reset_soft();
fadeout2.reset_soft();
porta_time = 0.f;
start_freq = freq;
target_freq = freq = 440 * pow(2.0, (queue_note_on - 69) / 12.0);
@@ -349,10 +379,11 @@ 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;
bool starting = false;
if (!running)
{
starting = true;
if (legato >= 2)
porta_time = -1.f;
last_xfade = xfade;
@@ -360,7 +391,10 @@ void monosynth_audio_module::delayed_note_on()
osc2.reset();
filter.reset();
filter2.reset();
lfo.reset();
if (*params[par_lfo1trig] <= 0)
lfo1.reset();
if (*params[par_lfo2trig] <= 0)
lfo2.reset();
switch((int)*params[par_oscmode])
{
case 1:
@@ -384,19 +418,20 @@ void monosynth_audio_module::delayed_note_on()
default:
break;
}
envelope.note_on();
running = true;
}
if (legato >= 2 && !gate)
porta_time = -1.f;
gate = true;
stopping = false;
if (!(legato & 1) || envelope.released()) {
envelope.note_on();
}
envelope.advance();
if (starting || !(legato & 1) || envelope1.released())
envelope1.note_on();
if (starting || !(legato & 1) || envelope2.released())
envelope2.note_on();
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, envelope1.value, envelope2.value, 0.5+0.5*lfo1.last, 0.5+0.5*lfo2.last};
calculate_modmatrix(moddest, moddest_count, modsrc);
}
@@ -404,27 +439,32 @@ void monosynth_audio_module::set_sample_rate(uint32_t sr) {
srate = sr;
crate = sr / step_size;
odcr = (float)(1.0 / crate);
phaseshifter.set_ap(1000.f, sr);
fgain = 0.f;
fgain_delta = 0.f;
inertia_cutoff.ramp.set_length(crate / 30); // 1/30s
inertia_pitchbend.ramp.set_length(crate / 30); // 1/30s
master.set_sample_rate(sr);
}
void monosynth_audio_module::calculate_step()
{
if (queue_note_on != -1)
delayed_note_on();
else if (stopping)
else
if (stopping || !running)
{
running = false;
dsp::zero(buffer, step_size);
if (is_stereo_filter())
dsp::zero(buffer2, step_size);
envelope.advance();
envelope1.advance();
envelope2.advance();
lfo1.get();
lfo2.get();
float modsrc[modsrc_count] = { 1, velocity, inertia_pressure.get_last(), modwheel_value, envelope1.value, envelope2.value, 0.5+0.5*lfo1.last, 0.5+0.5*lfo2.last};
calculate_modmatrix(moddest, moddest_count, modsrc);
last_stretch1 = (int32_t)(65536 * dsp::clip(*params[par_stretch1] + 0.01f * moddest[moddest_o1stretch], 1.f, 16.f));
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 +479,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 +558,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 *= aenv1;
if (e2a2 > 0.f)
newfgain *= aenv2;
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,17 +587,42 @@ 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))
apply_fadeout();
}
void monosynth_audio_module::apply_fadeout()
{
if (fadeout.undoing)
{
enum { ramp = step_size * 4 };
for (int i = 0; i < step_size; i++)
buffer[i] *= (ramp - i - stop_count) * (1.0f / ramp);
fadeout.process(buffer2, step_size);
if (is_stereo_filter())
for (int i = 0; i < step_size; i++)
buffer2[i] *= (ramp - i - stop_count) * (1.0f / ramp);
stop_count += step_size;
if (stop_count >= ramp)
stopping = true;
fadeout2.process(buffer2, step_size);
}
else
{
// stop the sound if the amplitude envelope is not running (if there's any)
bool aenv1_on = *params[par_env1toamp] > 0.f, aenv2_on = *params[par_env2toamp] > 0.f;
bool do_fadeout = force_fadeout;
// if there's no amplitude envelope at all, the fadeout starts at key release
if (!aenv1_on && !aenv2_on && !gate)
do_fadeout = true;
// if ENV1 modulates amplitude, the fadeout will start on ENV1 end too
if (aenv1_on && envelope1.state == adsr::STOP)
do_fadeout = true;
// if ENV2 modulates amplitude, the fadeout will start on ENV2 end too
if (aenv2_on && envelope2.state == adsr::STOP)
do_fadeout = true;
if (do_fadeout || fadeout.undoing || fadeout2.undoing)
{
fadeout.process(buffer, step_size);
if (is_stereo_filter())
fadeout2.process(buffer2, step_size);
if (fadeout.done)
stopping = true;
}
}
}
@@ -573,14 +647,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 +683,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 +695,8 @@ void monosynth_audio_module::deactivate()
gate = false;
running = false;
stopping = false;
envelope.reset();
envelope1.reset();
envelope2.reset();
stack.clear();
}
@@ -640,9 +718,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);
@@ -659,34 +737,33 @@ void monosynth_audio_module::params_changed()
uint32_t monosynth_audio_module::process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask)
{
if (!running && queue_note_on == -1) {
for (uint32_t i = 0; i < nsamples / step_size; i++)
envelope.advance();
return 0;
}
uint32_t op = offset;
uint32_t op_end = offset + nsamples;
int had_data = 0;
while(op < op_end) {
if (output_pos == 0) {
if (running || queue_note_on != -1)
calculate_step();
else {
envelope.advance();
dsp::zero(buffer, step_size);
}
}
if (output_pos == 0)
calculate_step();
if(op < op_end) {
uint32_t ip = output_pos;
uint32_t len = std::min(step_size - output_pos, op_end - op);
if (is_stereo_filter())
for(uint32_t i = 0 ; i < len; i++) {
float vol = master.get();
outs[0][op + i] = buffer[ip + i] * vol,
outs[1][op + i] = buffer2[ip + i] * vol;
}
else
for(uint32_t i = 0 ; i < len; i++)
outs[0][op + i] = outs[1][op + i] = buffer[ip + i] * master.get();
if (running)
{
had_data = 3;
if (is_stereo_filter())
for(uint32_t i = 0 ; i < len; i++) {
float vol = master.get();
outs[0][op + i] = buffer[ip + i] * vol;
outs[1][op + i] = buffer2[ip + i] * vol;
}
else
for(uint32_t i = 0 ; i < len; i++)
outs[0][op + i] = outs[1][op + i] = buffer[ip + i] * master.get();
}
else
{
dsp::zero(&outs[0][op], len);
dsp::zero(&outs[1][op], len);
}
op += len;
output_pos += len;
if (output_pos == step_size)
@@ -694,6 +771,6 @@ uint32_t monosynth_audio_module::process(uint32_t offset, uint32_t nsamples, uin
}
}
return 3;
return had_data;
}

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,36 +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_small.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
@@ -61,11 +492,7 @@ const LV2_Descriptor *lv2_descriptor(uint32_t index)
{
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!(index--)) return &lv2_wrapper<name##_audio_module>::get().descriptor;
#include <calf/modulelist.h>
#ifdef ENABLE_EXPERIMENTAL
return lv2_small_descriptor(index);
#else
return NULL;
#endif
}
};
@@ -99,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;
@@ -69,6 +69,11 @@ std::string xml_escape(const std::string &src)
return dest;
}
std::string to_xml_attr(const std::string &key, const std::string &value)
{
return " " + key + "=\"" + xml_escape(value) + "\"";
}
std::string load_file(const std::string &src)
{
std::string str;
@@ -129,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();
}
}

View File

@@ -977,7 +977,7 @@ void lb302SynthView::modelChanged()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{

View File

@@ -829,7 +829,7 @@ void lb303SynthView::modelChanged()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{

View File

@@ -59,7 +59,7 @@ Plugin::Descriptor PLUGIN_EXPORT lv2browser_plugin_descriptor =
} ;
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return new lv2Browser;

View File

@@ -569,7 +569,7 @@ void MidiImport::error()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return new MidiImport( QString::fromUtf8(

View File

@@ -563,7 +563,7 @@ void OscillatorObject::updateDetuning()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return( new organicInstrument( static_cast<InstrumentTrack *>( _data ) ) );

View File

@@ -732,7 +732,7 @@ void papuInstrumentView::modelChanged()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return( new papuInstrument(

View File

@@ -148,7 +148,7 @@ bool PeakControllerEffect::processAudioBuffer( sampleFrame * _buf,
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return new PeakControllerEffect( _parent,

View File

@@ -2,7 +2,7 @@
* sf2_player.cpp - a soundfont2 player using fluidSynth
*
* Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail/dot/com>
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2009-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -53,7 +53,7 @@ static const char * __supportedExts[] =
extern "C"
{
Plugin::Descriptor sf2player_plugin_descriptor =
Plugin::Descriptor PLUGIN_EXPORT sf2player_plugin_descriptor =
{
STRINGIFY( PLUGIN_NAME ),
"Sf2 Player",
@@ -636,6 +636,7 @@ void sf2Instrument::playNote( notePlayHandle * _n, sampleFrame * )
SF2PluginData * pluginData = static_cast<SF2PluginData *>(
_n->m_pluginData );
#ifdef SOMEONE_FIXED_PER_NOTE_PANNING
if( pluginData->fluidVoice &&
pluginData->lastPanning != _n->getPanning() )
{
@@ -650,6 +651,7 @@ void sf2Instrument::playNote( notePlayHandle * _n, sampleFrame * )
pluginData->lastPanning = _n->getPanning();
}
#endif
const float currentVelocity = _n->volumeLevel( tfp ) * 127;
if( pluginData->fluidVoice &&
@@ -1106,8 +1108,8 @@ void sf2InstrumentView::showPatchDialog()
extern "C"
{
// neccessary for getting instance out of shared lib
Plugin * lmms_plugin_main( Model *, void * _data )
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return new sf2Instrument( static_cast<InstrumentTrack *>( _data ) );
}

View File

@@ -815,7 +815,7 @@ void sidInstrumentView::modelChanged()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return( new sidInstrument(

View File

@@ -1,8 +1,8 @@
/*
* spectrum_analyzer.cpp - spectrum analyzer plugin
*
* Copyright (c) 2008-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* This program is free software; you can redistribute it and/or
@@ -82,6 +82,11 @@ bool spectrumAnalyzer::processAudioBuffer( sampleFrame * _buf,
return( false );
}
if( !m_saControls.isViewVisible() )
{
return true;
}
fpp_t f = 0;
if( _frames > FFT_BUFFER_SIZE )
{
@@ -163,7 +168,7 @@ bool spectrumAnalyzer::processAudioBuffer( sampleFrame * _buf,
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return( new spectrumAnalyzer( _parent,

View File

@@ -163,7 +163,7 @@ void stereoEnhancerEffect::clearMyBuffer()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return( new stereoEnhancerEffect( _parent,

View File

@@ -112,7 +112,7 @@ bool stereoMatrixEffect::processAudioBuffer( sampleFrame * _buf,
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return( new stereoMatrixEffect( _parent,

View File

@@ -2,7 +2,8 @@
* mallets.cpp - tuned instruments that one would bang upon
*
* Copyright (c) 2006-2008 Danny McRae <khjklujn/at/users.sourceforge.net>
*
* Copyright (c) 2009-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* This program is free software; you can redistribute it and/or
@@ -41,7 +42,7 @@
extern "C"
{
Plugin::Descriptor malletsstk_plugin_descriptor =
Plugin::Descriptor PLUGIN_EXPORT malletsstk_plugin_descriptor =
{
STRINGIFY( PLUGIN_NAME ),
"Mallets",
@@ -654,8 +655,8 @@ malletsSynth::malletsSynth( const StkFloat _pitch,
extern "C"
{
// neccessary for getting instance out of shared lib
Plugin * lmms_plugin_main( Model *, void * _data )
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return new malletsInstrument( static_cast<InstrumentTrack *>( _data ) );
}

View File

@@ -36,6 +36,12 @@
#include "note_play_handle.h"
#include "led_checkbox.h"
// As of Stk 4.4 all classes and types have been moved to the namespace "stk".
// However in older versions this namespace does not exist, therefore declare it
// so this plugin builds with all versions of Stk.
namespace stk { } ;
using namespace stk;
class malletsSynth
{

View File

@@ -865,7 +865,7 @@ void TripleOscillatorView::modelChanged()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return new TripleOscillator( static_cast<InstrumentTrack *>( _data ) );

View File

@@ -51,7 +51,7 @@ static const char * __supportedExts[] =
extern "C"
{
Plugin::Descriptor vestige_plugin_descriptor =
Plugin::Descriptor PLUGIN_EXPORT vestige_plugin_descriptor =
{
STRINGIFY( PLUGIN_NAME ),
"VeSTige",
@@ -360,6 +360,11 @@ void VestigeInstrumentView::openPlugin()
engine::getMixer()->lock();
m_vi->loadFile( ofd.selectedFiles()[0] );
engine::getMixer()->unlock();
if( m_vi->m_plugin && m_vi->m_plugin->pluginWidget() )
{
m_vi->m_plugin->pluginWidget()->setWindowIcon(
PLUGIN_NAME::getIconPixmap( "logo" ) );
}
}
}
@@ -448,8 +453,8 @@ void VestigeInstrumentView::paintEvent( QPaintEvent * )
extern "C"
{
// neccessary for getting instance out of shared lib
Plugin * lmms_plugin_main( Model *, void * _data )
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return new vestigeInstrument( static_cast<InstrumentTrack *>( _data ) );
}

View File

@@ -241,7 +241,7 @@ void vibed::loadSettings( const QDomElement & _this )
float * shp = 0;
base64::decode( _this.attribute( "graph" +
QString::number( i ) ),
(char * *) &shp,
&shp,
&size );
// TODO: check whether size == 128 * sizeof( float ),
// otherwise me might and up in a segfault
@@ -543,7 +543,7 @@ vibedView::vibedView( Instrument * _instrument,
m_stringSelector->setAccessibleName( tr( "String" ) );
m_stringSelector->setWhatsThis( tr(
"The String selector is used to choose which string the controls are "
"editting. A Vibed instrument can contain up to nine independently "
"editing. A Vibed instrument can contain up to nine independently "
"vibrating strings. The LED in the lower right corner of the "
"waveform editor indicates whether the selected string is active." ) );
@@ -779,7 +779,7 @@ void vibedView::displayHelp()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{
return( new vibed( static_cast<InstrumentTrack *>( _data ) ) );

View File

@@ -104,7 +104,7 @@ class RemoteVstPlugin;
RemoteVstPlugin * __plugin = NULL;
DWORD __GuiThreadID = NULL;
DWORD __GuiThreadID = 0;
@@ -813,7 +813,7 @@ void RemoteVstPlugin::saveChunkToFile( const std::string & _file )
void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
{
char buf[_len];
char * buf = NULL;
void * chunk = NULL;
// various plugins need this in order to not crash when setting
@@ -823,7 +823,8 @@ void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
// allocated buffer big enough?
if( _len > actualLen )
{
// no, manually try our local buffer
// no, then manually allocate a buffer
buf = new char[_len];
chunk = buf;
}
@@ -831,6 +832,8 @@ void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
read( fd, chunk, _len );
close( fd );
pluginDispatch( 24, 0, _len, chunk );
delete[] buf;
}

View File

@@ -2,7 +2,7 @@
* vst_base.cpp - VST-base-code to be used by any LMMS plugins dealing with VST-
* plugins
*
* Copyright (c) 2006-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2006-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -31,7 +31,7 @@
extern "C"
{
Plugin::Descriptor vstbase_plugin_descriptor =
Plugin::Descriptor PLUGIN_EXPORT vstbase_plugin_descriptor =
{
STRINGIFY( PLUGIN_NAME ),
"VST Base",

View File

@@ -1,7 +1,7 @@
/*
* VstEffect.cpp - class for handling VST effect plugins
*
* Copyright (c) 2006-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2006-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -35,7 +35,7 @@
extern "C"
{
Plugin::Descriptor vsteffect_plugin_descriptor =
Plugin::Descriptor PLUGIN_EXPORT vsteffect_plugin_descriptor =
{
STRINGIFY( PLUGIN_NAME ),
"VST Effect",
@@ -174,8 +174,8 @@ void VstEffect::closePlugin()
extern "C"
{
// neccessary for getting instance out of shared lib
Plugin * lmms_plugin_main( Model * _parent, void * _data )
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model * _parent, void * _data )
{
return new VstEffect( _parent,
static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>(

View File

@@ -88,12 +88,24 @@ ENDIF(LMMS_BUILD_WIN32)
BUILD_PLUGIN(zynaddsubfx ZynAddSubFx.cpp ZynAddSubFx.h MOCFILES ZynAddSubFx.h EMBEDDED_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.png)
TARGET_LINK_LIBRARIES(zynaddsubfx ZynAddSubFxCore)
IF(WIN32)
SET(WINRC "${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfxrc.obj")
ADD_CUSTOM_COMMAND(OUTPUT ${WINRC}
COMMAND ${WINDRES}
-I${CMAKE_CURRENT_SOURCE_DIR}
-o${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfxrc.obj
-i${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfx.rc
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfx.rc)
ENDIF(WIN32)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${PLUGIN_DIR}")
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
ADD_EXECUTABLE(RemoteZynAddSubFx RemoteZynAddSubFx.cpp ${ZYN_SRC_GUI})
ADD_EXECUTABLE(RemoteZynAddSubFx RemoteZynAddSubFx.cpp ${ZYN_SRC_GUI} ${WINRC})
INSTALL(TARGETS RemoteZynAddSubFx RUNTIME DESTINATION ${PLUGIN_DIR})
TARGET_LINK_LIBRARIES(RemoteZynAddSubFx -L${CMAKE_CURRENT_BINARY_DIR} -lZynAddSubFxCore ${CMAKE_CURRENT_BINARY_DIR}/fltk/bin/libfltk.a)
IF(LMMS_BUILD_LINUX)
SET(FONTCONFIG_LIBS -lfontconfig)
ENDIF(LMMS_BUILD_LINUX)
TARGET_LINK_LIBRARIES(RemoteZynAddSubFx -lpthread ${FONTCONFIG_LIBS} -L${CMAKE_CURRENT_BINARY_DIR} -lZynAddSubFxCore ${CMAKE_CURRENT_BINARY_DIR}/fltk/bin/libfltk.a)
ADD_DEPENDENCIES(RemoteZynAddSubFx ZynAddSubFxCore)
# link system libraries when on win32

View File

@@ -94,7 +94,7 @@
Programul incepe sa fie controlabil de Interfata
02 Aug 2002 - Inlaturat o eroare stupida care facea ca sa se seteze valorile EnvelopeParams la -1 (scria din Master:: prea mult)
03 Aug 2002 - Terminata interfata pentru ADnoteParameters.GlobalPars
Adaugat inca un parametru la lfo (continous LFO) care faca ca LFO-ul sa nu inceapa la fiecare NoteOn
Adaugat inca un parametru la lfo (continuous LFO) care faca ca LFO-ul sa nu inceapa la fiecare NoteOn
Corectat doua erori la ...[nvoice].AmpEnvelope si ...[nvoice].FreqEnvelope
Scrisa interfata pentru ADnoteParameters.VoicePars (fara FM+OSCIL...)
04 Aug 2002 - Scrisa interfata cu FM (fara Oscil)
@@ -680,8 +680,8 @@
- Corectata eroare care facea ca sa nu mearga MIDI
- LANSAT PE INTERNET - VERSIUNEA (2.0.0pre2 VST)
--------------------------------------------------------------------------------------------------
13 Aug 2004 - Inceput sa scriu modurile continous si discrete la PADnote
14 Aug 2004 - Terminat modul continous la PADnote
13 Aug 2004 - Inceput sa scriu modurile continuous si discrete la PADnote
14 Aug 2004 - Terminat modul continuous la PADnote
- Corectata o mica eroare la OscilGen care facea daca adaptive harmonics e activ si phase randomness>0 sa rezulte si aleatorism in amplitudinile armonicelor
- Inceput sa scriu Presets/Clipboard (Clipboardul, in stadiu actual va putea copia doar parametrii folositi si nu cei dezactivati)
- Merge partial partea de Copy in clipboard

View File

@@ -1,7 +1,7 @@
/*
* RemoteZynAddSubFx.cpp - ZynAddSubFx-embedding plugin
*
* Copyright (c) 2008-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
@@ -23,6 +23,10 @@
*/
#include <lmmsconfig.h>
#ifdef LMMS_BUILD_WIN32
#include <winsock2.h>
#endif
#include <queue>
#define BUILD_REMOTE_PLUGIN_CLIENT
@@ -130,10 +134,20 @@ public:
LocalZynAddSubFx::processAudio( _out );
}
static void * guiThread( void * _arg );
static void * guiThread( void * _arg )
{
RemoteZynAddSubFx * _this =
static_cast<RemoteZynAddSubFx *>( _arg );
_this->guiThread();
return NULL;
}
private:
void guiThread();
const int m_guiSleepTime;
pthread_t m_guiThreadHandle;
@@ -145,33 +159,38 @@ private:
void * RemoteZynAddSubFx::guiThread( void * _arg )
void RemoteZynAddSubFx::guiThread()
{
int e;
int exitProgram;
MasterUI * ui = NULL;
RemoteZynAddSubFx * _this = static_cast<RemoteZynAddSubFx *>( _arg );
Master * master = _this->m_master;
while( !_this->m_guiExit )
while( !m_guiExit )
{
if( ui )
{
Fl::wait( _this->m_guiSleepTime / 1000.0 );
Fl::wait( m_guiSleepTime / 1000.0 );
}
else
{
#ifdef LMMS_BUILD_WIN32
Sleep( _this->m_guiSleepTime );
Sleep( m_guiSleepTime );
#else
usleep( _this->m_guiSleepTime*1000 );
usleep( m_guiSleepTime*1000 );
#endif
}
pthread_mutex_lock( &_this->m_guiMutex );
while( _this->m_guiMessages.size() )
if( exitProgram == 1 )
{
RemotePluginClient::message m = _this->m_guiMessages.front();
_this->m_guiMessages.pop();
pthread_mutex_lock( &m_master->mutex );
sendMessage( IdHideUI );
exitProgram = 0;
pthread_mutex_unlock( &m_master->mutex );
}
pthread_mutex_lock( &m_guiMutex );
while( m_guiMessages.size() )
{
RemotePluginClient::message m = m_guiMessages.front();
m_guiMessages.pop();
switch( m.id )
{
case IdShowUI:
@@ -179,44 +198,28 @@ void * RemoteZynAddSubFx::guiThread( void * _arg )
if( !ui )
{
Fl::scheme( "plastic" );
ui = new MasterUI( master, &e );
ui = new MasterUI( m_master, &exitProgram );
}
ui->showUI();
ui->refresh_master_ui();
break;
case IdHideUI:
if( !ui ) break;
switch( config.cfg.UserInterfaceMode )
{
case 0:
ui->selectuiwindow->hide();
break;
case 1:
ui->masterwindow->hide();
break;
case 2:
ui->simplemasterwindow->hide();
break;
}
break;
case IdLoadSettingsFromFile:
{
_this->LocalZynAddSubFx::loadXML( m.getString() );
LocalZynAddSubFx::loadXML( m.getString() );
if( ui )
{
ui->refresh_master_ui();
}
pthread_mutex_lock( &master->mutex );
_this->sendMessage( IdLoadSettingsFromFile );
pthread_mutex_unlock( &master->mutex );
pthread_mutex_lock( &m_master->mutex );
sendMessage( IdLoadSettingsFromFile );
pthread_mutex_unlock( &m_master->mutex );
break;
}
case IdLoadPresetFromFile:
{
_this->LocalZynAddSubFx::loadPreset( m.getString(), ui ?
LocalZynAddSubFx::loadPreset( m.getString(), ui ?
ui->npartcounter->value()-1 : 0 );
if( ui )
{
@@ -224,9 +227,9 @@ void * RemoteZynAddSubFx::guiThread( void * _arg )
ui->updatepanel();
ui->refresh_master_ui();
}
pthread_mutex_lock( &master->mutex );
_this->sendMessage( IdLoadPresetFromFile );
pthread_mutex_unlock( &master->mutex );
pthread_mutex_lock( &m_master->mutex );
sendMessage( IdLoadPresetFromFile );
pthread_mutex_unlock( &m_master->mutex );
break;
}
@@ -234,13 +237,11 @@ void * RemoteZynAddSubFx::guiThread( void * _arg )
break;
}
}
pthread_mutex_unlock( &_this->m_guiMutex );
pthread_mutex_unlock( &m_guiMutex );
}
Fl::flush();
delete ui;
return NULL;
}

View File

@@ -69,6 +69,39 @@ Plugin::Descriptor PLUGIN_EXPORT zynaddsubfx_plugin_descriptor =
ZynAddSubFxRemotePlugin::ZynAddSubFxRemotePlugin() :
QObject(),
RemotePlugin( "RemoteZynAddSubFx", false )
{
}
ZynAddSubFxRemotePlugin::~ZynAddSubFxRemotePlugin()
{
}
bool ZynAddSubFxRemotePlugin::processMessage( const message & _m )
{
switch( _m.id )
{
case IdHideUI:
emit clickedCloseButton();
return true;
default:
break;
}
return RemotePlugin::processMessage( _m );
}
ZynAddSubFxInstrument::ZynAddSubFxInstrument(
InstrumentTrack * _instrumentTrack ) :
Instrument( _instrumentTrack, &zynaddsubfx_plugin_descriptor ),
@@ -277,7 +310,7 @@ void ZynAddSubFxInstrument::initPlugin()
if( m_hasGUI )
{
m_remotePlugin = new RemotePlugin( "RemoteZynAddSubFx", false );
m_remotePlugin = new ZynAddSubFxRemotePlugin();
m_remotePlugin->lock();
m_remotePlugin->waitForInitDone( false );
@@ -358,6 +391,12 @@ void ZynAddSubFxView::toggleUI()
ZynAddSubFxInstrument * model = castModel<ZynAddSubFxInstrument>();
model->m_hasGUI = m_toggleUIButton->isChecked();
model->reloadPlugin();
if( model->m_remotePlugin )
{
connect( model->m_remotePlugin, SIGNAL( clickedCloseButton() ),
m_toggleUIButton, SLOT( toggle() ) );
}
}
@@ -367,7 +406,7 @@ void ZynAddSubFxView::toggleUI()
extern "C"
{
// neccessary for getting instance out of shared lib
// necessary for getting instance out of shared lib
Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data )
{

View File

@@ -39,6 +39,24 @@ class ZynAddSubFxView;
class notePlayHandle;
class ZynAddSubFxRemotePlugin : public QObject, public RemotePlugin
{
Q_OBJECT
public:
ZynAddSubFxRemotePlugin();
virtual ~ZynAddSubFxRemotePlugin();
virtual bool processMessage( const message & _m );
signals:
void clickedCloseButton();
} ;
class ZynAddSubFxInstrument : public Instrument
{
Q_OBJECT
@@ -77,7 +95,7 @@ private:
bool m_hasGUI;
QMutex m_pluginMutex;
LocalZynAddSubFx * m_plugin;
RemotePlugin * m_remotePlugin;
ZynAddSubFxRemotePlugin * m_remotePlugin;
friend class ZynAddSubFxView;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -25,7 +25,7 @@ SET(LIBRARY_OUTPUT_PATH "${FLTK_BINARY_DIR}/bin" CACHE INTERNAL
OPTION(BUILD_SHARED_LIBS "Build FLTK as a shared library" OFF)
# Search for modules in the FLTK source dir first
SET(CMAKE_MODULE_PATH "${FLTK_SOURCE_DIR}/CMake")
SET(CMAKE_MODULE_PATH ${FLTK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH})
#-----------------------------------------------------------------------------
# Test for some required system information.

View File

@@ -34,6 +34,7 @@
# error "Never use <FL/win32.H> directly; include <FL/x.H> instead."
#endif // !Fl_X_H
#include <winsock2.h>
#include <windows.h>
// In some of the distributions, the gcc header files are missing some stuff:
#ifndef LPMINMAXINFO

View File

@@ -187,6 +187,7 @@ int Fl::awake(Fl_Awake_Handler func, void *data) {
See also: \ref advanced_multithreading
*/
#ifdef WIN32
# include <winsock2.h>
# include <windows.h>
# include <process.h>
# include <FL/x.H>

View File

@@ -284,7 +284,7 @@ load_fonts(Display *dpy,
}
/*********************************************************************/
/** Creates an array of XFontStruct acording to the comma separated **/
/** Creates an array of XFontStruct according to the comma separated **/
/** list of fonts. XLoad all fonts. **/
/*********************************************************************/
XUtf8FontStruct *

View File

@@ -33,7 +33,7 @@ LFOParams::LFOParams(char Pfreq_,
char PLFOtype_,
char Prandomness_,
char Pdelay_,
char Pcontinous_,
char Pcontinuous_,
char fel_):Presets()
{
switch(fel_) {
@@ -53,7 +53,7 @@ LFOParams::LFOParams(char Pfreq_,
DLFOtype = PLFOtype_;
Drandomness = Prandomness_;
Ddelay = Pdelay_;
Dcontinous = Pcontinous_;
Dcontinuous = Pcontinuous_;
fel = fel_;
time = 0;
@@ -71,7 +71,7 @@ void LFOParams::defaults()
PLFOtype = DLFOtype;
Prandomness = Drandomness;
Pdelay = Ddelay;
Pcontinous = Dcontinous;
Pcontinuous = Dcontinuous;
Pfreqrand = 0;
Pstretch = 64;
}
@@ -87,7 +87,7 @@ void LFOParams::add2XML(XMLwrapper *xml)
xml->addpar("randomness_frequency", Pfreqrand);
xml->addpar("delay", Pdelay);
xml->addpar("stretch", Pstretch);
xml->addparbool("continous", Pcontinous);
xml->addparbool("continuous", Pcontinuous);
}
void LFOParams::getfromXML(XMLwrapper *xml)
@@ -100,6 +100,6 @@ void LFOParams::getfromXML(XMLwrapper *xml)
Pfreqrand = xml->getpar127("randomness_frequency", Pfreqrand);
Pdelay = xml->getpar127("delay", Pdelay);
Pstretch = xml->getpar127("stretch", Pstretch);
Pcontinous = xml->getparbool("continous", Pcontinous);
Pcontinuous = xml->getparbool("continuous", Pcontinuous);
}

Some files were not shown because too many files have changed in this diff Show More