[SCM] calf/master: + Framework: new framework for small plugins (LV2 only); small plugins will not be available as LADSPA/DSSI/JACK from now on + Small plugins: multiply, subtract, negative, linear to exponential range plugins added (prototype quality code)
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:37:35 UTC 2013
The following commit has been merged in the master branch:
commit c157a45d03049ef24f4b21552bbe5c500f238063
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Wed Sep 17 23:14:14 2008 +0000
+ Framework: new framework for small plugins (LV2 only); small plugins will not be available as LADSPA/DSSI/JACK from now on
+ Small plugins: multiply, subtract, negative, linear to exponential range plugins added (prototype quality code)
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@288 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/src/calf/Makefile.am b/src/calf/Makefile.am
index a604aaa..19d9adb 100644
--- a/src/calf/Makefile.am
+++ b/src/calf/Makefile.am
@@ -5,5 +5,5 @@ calf_HEADERS = audio_fx.h benchmark.h biquad.h buffer.h custom_ctl.h \
delay.h fft.h fixed_point.h giface.h gui.h inertia.h \
jackhost.h lv2_event.h lv2_ui.h lv2_uri_map.h lv2-midiport.h lv2wrap.h \
main_win.h modules.h modules_dev.h modules_small.h modules_synths.h modulelist.h \
- onepole.h organ.h osc.h osctl.h osctlnet.h preset.h preset_gui.h primitives.h \
- synth.h utils.h wave.h
+ onepole.h organ.h osc.h osctl.h osctlnet.h plugininfo.h preset.h \
+ preset_gui.h primitives.h synth.h utils.h wave.h
diff --git a/src/calf/giface.h b/src/calf/giface.h
index 55004dd..d0eeb16 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -230,7 +230,10 @@ struct giface_plugin_info
bool (*is_noisy)(int param_no);
};
+struct plugin_list_info_iface;
+
extern void get_all_plugins(std::vector<giface_plugin_info> &plugins);
+extern void get_all_small_plugins(plugin_list_info_iface *plii);
#if USE_LADSPA
diff --git a/src/calf/lv2wrap.h b/src/calf/lv2wrap.h
index 04534e7..9c9c303 100644
--- a/src/calf/lv2wrap.h
+++ b/src/calf/lv2wrap.h
@@ -141,7 +141,6 @@ struct lv2_wrapper
}
static void cb_activate(LV2_Handle Instance) {
- // LV2 activate is practically useless because parameters aren't present
}
static void cb_deactivate(LV2_Handle Instance) {
@@ -248,7 +247,72 @@ struct lv2_wrapper
};
template<class Module>
-LV2_Descriptor lv2_wrapper<Module>::descriptor;
+struct lv2_small_wrapper
+{
+ typedef Module instance;
+ static LV2_Descriptor descriptor;
+ std::string uri;
+
+ 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;
+ }
+
+ 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 LV2_Handle cb_instantiate(const LV2_Descriptor * Descriptor, double sample_rate, const char *bundle_path, const LV2_Feature *const *features)
+ {
+ instance *mod = new instance();
+ // XXXKF some people use fractional sample rates; we respect them ;-)
+ mod->srate = (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 NULL;
+ }
+};
+
+#define PUT_DESCRIPTORS_HERE \
+ template<class Module> LV2_Descriptor lv2_small_wrapper<Module>::descriptor; \
+ template<class Module> LV2_Descriptor lv2_wrapper<Module>::descriptor;
};
diff --git a/src/calf/modulelist.h b/src/calf/modulelist.h
index 152c16b..9caee66 100644
--- a/src/calf/modulelist.h
+++ b/src/calf/modulelist.h
@@ -7,11 +7,19 @@
PER_MODULE_ITEM(rotary_speaker, false, "rotaryspeaker")
PER_MODULE_ITEM(phaser, false, "phaser")
#ifdef ENABLE_EXPERIMENTAL
- PER_MODULE_ITEM(small_lp_filter, false, "lowpass12")
- PER_MODULE_ITEM(small_hp_filter, false, "highpass12")
- PER_MODULE_ITEM(small_bp_filter, false, "bandpass6")
- PER_MODULE_ITEM(small_br_filter, false, "notch6")
- PER_MODULE_ITEM(small_onepole_lp_filter, false, "lowpass12")
- PER_MODULE_ITEM(small_onepole_hp_filter, false, "highpass12")
- PER_MODULE_ITEM(small_onepole_ap_filter, false, "allpass")
+ PER_SMALL_MODULE_ITEM(small_lp_filter)
+ PER_SMALL_MODULE_ITEM(small_hp_filter)
+ PER_SMALL_MODULE_ITEM(small_bp_filter)
+ PER_SMALL_MODULE_ITEM(small_br_filter)
+ PER_SMALL_MODULE_ITEM(small_onepole_lp_filter)
+ PER_SMALL_MODULE_ITEM(small_onepole_hp_filter)
+ PER_SMALL_MODULE_ITEM(small_onepole_ap_filter)
+ PER_SMALL_MODULE_ITEM(small_min)
+ PER_SMALL_MODULE_ITEM(small_max)
+ PER_SMALL_MODULE_ITEM(small_minus)
+ PER_SMALL_MODULE_ITEM(small_mul)
+ PER_SMALL_MODULE_ITEM(small_neg)
+ PER_SMALL_MODULE_ITEM(small_map_lin2exp)
#endif
+#undef PER_MODULE_ITEM
+#undef PER_SMALL_MODULE_ITEM
diff --git a/src/calf/modules.h b/src/calf/modules.h
index 097d3ea..ab77f99 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -35,12 +35,16 @@
#if USE_LV2
#define LV2_WRAPPER(mod) static synth::lv2_wrapper<mod##_audio_module> lv2_##mod(mod##_info);
+#define LV2_SMALL_WRAPPER(mod, name) static synth::lv2_small_wrapper<mod##_audio_module> lv2_##mod(name);
#else
-#define LV2_WRAPPER(mod)
+#define LV2_WRAPPER(...)
+#define LV2_SMALL_WRAPPER(...)
#endif
#define ALL_WRAPPERS(mod) LADSPA_WRAPPER(mod) LV2_WRAPPER(mod)
+#define SMALL_WRAPPERS(mod, name) LV2_SMALL_WRAPPER(mod, name)
+
namespace synth {
using namespace dsp;
diff --git a/src/calf/modules_small.h b/src/calf/modules_small.h
index ed024e0..d3a1cec 100644
--- a/src/calf/modules_small.h
+++ b/src/calf/modules_small.h
@@ -27,6 +27,7 @@
#include "audio_fx.h"
#include "giface.h"
#include "modules.h"
+#include "plugininfo.h"
namespace synth {
@@ -35,162 +36,282 @@ using namespace dsp;
class small_filter_audio_module: public null_audio_module
{
public:
- enum { par_cutoff, par_resonance, param_count };
- enum { in_count = 1, out_count = 1, rt_capable = true, support_midi = false };
+ enum { in_signal, in_cutoff, in_resonance, in_count };
+ enum { out_signal, out_count};
float *ins[in_count];
float *outs[out_count];
- float *params[param_count];
- static const char *port_names[];
+ static void port_info(plugin_info_iface *pii)
+ {
+ pii->audio_port("in", "In").input();
+ pii->control_port("cutoff", "Cutoff", 1000).input().log_range(20, 20000);
+ pii->control_port("res", "Resonance", 0.707).input().log_range(0.707, 20);
+ pii->audio_port("out", "Out").output();
+ }
dsp::biquad<float> filter;
uint32_t srate;
- static parameter_properties param_props[];
- /// do not export mode and inertia as CVs, as those are settings and not parameters
- void params_changed()
- {
- }
void activate() {
- params_changed();
filter.reset();
}
- void deactivate() {
- }
void set_sample_rate(uint32_t sr) {
srate = sr;
}
+ inline void process_inner(uint32_t count) {
+ for (uint32_t i = 0; i < count; i++)
+ outs[out_signal][i] = filter.process_d1(ins[in_signal][i]);
+ filter.sanitize_d1();
+ }
};
class small_lp_filter_audio_module: public small_filter_audio_module
{
public:
- uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
- filter.set_lp_rbj(*params[par_cutoff], *params[par_resonance], srate);
- for (uint32_t i = offset; i < offset + numsamples; i++)
- outs[0][i] = filter.process_d1(ins[0][i]);
- filter.sanitize_d1();
- return !filter.empty_d1();
+ inline void process(uint32_t count) {
+ filter.set_lp_rbj(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), *ins[in_resonance], srate);
+ process_inner(count);
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("lowpass12", "lowpass12", "12dB/oct RBJ Lowpass", "lv2:LowpassPlugin");
+ port_info(pii);
}
- static const char *get_id() { return "lowpass12"; }
- static const char *get_name() { return "lowpass12"; }
- static const char *get_label() { return "12dB/oct RBJ Lowpass"; }
};
class small_hp_filter_audio_module: public small_filter_audio_module
{
public:
- uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
- filter.set_lp_rbj(*params[par_cutoff], *params[par_resonance], srate);
- for (uint32_t i = offset; i < offset + numsamples; i++)
- outs[0][i] = filter.process_d1(ins[0][i]);
- filter.sanitize_d1();
- return !filter.empty_d1();
+ inline void process(uint32_t count) {
+ filter.set_hp_rbj(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), *ins[in_resonance], srate);
+ process_inner(count);
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("highpass12", "highpass12", "12dB/oct RBJ Highpass", "lv2:HighpassPlugin");
+ port_info(pii);
}
- static const char *get_id() { return "highpass12"; }
- static const char *get_name() { return "highpass12"; }
- static const char *get_label() { return "12dB/oct RBJ Highpass"; }
};
class small_bp_filter_audio_module: public small_filter_audio_module
{
public:
- uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
- filter.set_bp_rbj(*params[par_cutoff], *params[par_resonance], srate);
- for (uint32_t i = offset; i < offset + numsamples; i++)
- outs[0][i] = filter.process_d1(ins[0][i]);
- filter.sanitize_d1();
- return !filter.empty_d1();
+ inline void process(uint32_t count) {
+ filter.set_bp_rbj(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), *ins[in_resonance], srate);
+ process_inner(count);
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("bandpass6", "bandpass6", "6dB/oct RBJ Bandpass", "lv2:BandpassPlugin");
+ port_info(pii);
}
- static const char *get_id() { return "bandpass6"; }
- static const char *get_name() { return "bandpass6"; }
- static const char *get_label() { return "6dB/oct RBJ Bandpass"; }
};
class small_br_filter_audio_module: public small_filter_audio_module
{
public:
- uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
- filter.set_br_rbj(*params[par_cutoff], *params[par_resonance], srate);
- for (uint32_t i = offset; i < offset + numsamples; i++)
- outs[0][i] = filter.process_d1(ins[0][i]);
- filter.sanitize_d1();
- return !filter.empty_d1();
+ inline void process(uint32_t count) {
+ filter.set_br_rbj(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), *ins[in_resonance], srate);
+ process_inner(count);
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("notch6", "notch6", "6dB/oct RBJ Bandpass", "lv2:FilterPlugin");
+ port_info(pii);
}
- static const char *get_id() { return "notch6"; }
- static const char *get_name() { return "notch6"; }
- static const char *get_label() { return "6dB/oct RBJ Notch Filter"; }
};
class small_onepole_filter_audio_module: public null_audio_module
{
public:
- enum { par_cutoff, param_count };
- enum { in_count = 1, out_count = 1, rt_capable = true, support_midi = false };
+ enum { in_signal, in_cutoff, in_count };
+ enum { out_signal, out_count};
float *ins[in_count];
float *outs[out_count];
- float *params[param_count];
- static const char *port_names[];
dsp::onepole<float> filter;
uint32_t srate;
static parameter_properties param_props[];
- /// do not export mode and inertia as CVs, as those are settings and not parameters
- void params_changed()
+ static void port_info(plugin_info_iface *pii)
{
+ pii->audio_port("In", "in").input();
+ pii->control_port("Cutoff", "cutoff", 1000).input().log_range(20, 20000);
+ pii->audio_port("Out", "out").output();
}
+ /// do not export mode and inertia as CVs, as those are settings and not parameters
void activate() {
- params_changed();
filter.reset();
}
- void deactivate() {
- }
- void set_sample_rate(uint32_t sr) {
- srate = sr;
- }
};
class small_onepole_lp_filter_audio_module: public small_onepole_filter_audio_module
{
public:
- uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
- filter.set_lp(*params[par_cutoff], srate);
- for (uint32_t i = offset; i < offset + numsamples; i++)
+ void process(uint32_t count) {
+ filter.set_lp(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), srate);
+ for (uint32_t i = 0; i < count; i++)
outs[0][i] = filter.process_lp(ins[0][i]);
filter.sanitize();
- return !filter.empty();
}
- static const char *get_id() { return "lowpass6"; }
- static const char *get_name() { return "lowpass6"; }
- static const char *get_label() { return "6dB/oct Lowpass"; }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("lowpass6", "lowpass6", "6dB/oct Lowpass Filter", "lv2:LowpassPlugin");
+ port_info(pii);
+ }
};
class small_onepole_hp_filter_audio_module: public small_onepole_filter_audio_module
{
public:
- uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
- filter.set_hp(*params[par_cutoff], srate);
- for (uint32_t i = offset; i < offset + numsamples; i++)
+ void process(uint32_t count) {
+ filter.set_hp(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), srate);
+ for (uint32_t i = 0; i < count; i++)
outs[0][i] = filter.process_hp(ins[0][i]);
filter.sanitize();
- return !filter.empty();
}
- static const char *get_id() { return "highpass6"; }
- static const char *get_name() { return "highpass6"; }
- static const char *get_label() { return "6dB/oct Lowpass"; }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("highpass6", "highpass6", "6dB/oct Highpass Filter", "lv2:HighpassPlugin");
+ port_info(pii);
+ }
};
class small_onepole_ap_filter_audio_module: public small_onepole_filter_audio_module
{
public:
- uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
- filter.set_ap(*params[par_cutoff], srate);
- for (uint32_t i = offset; i < offset + numsamples; i++)
+ void process(uint32_t count) {
+ filter.set_ap(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), srate);
+ for (uint32_t i = 0; i < count; i++)
outs[0][i] = filter.process_ap(ins[0][i]);
filter.sanitize();
- return !filter.empty();
}
- static const char *get_id() { return "allpass6"; }
- static const char *get_name() { return "allpass6"; }
- static const char *get_label() { return "6dB/oct Lowpass"; }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("allpass", "allpass", "1-pole 1-zero Allpass Filter", "lv2:AllpassPlugin");
+ port_info(pii);
+ }
+};
+
+/// This works for 1 or 2 operands only...
+template<int Inputs>
+class audio_operator_audio_module: public null_audio_module
+{
+public:
+ enum { in_count = Inputs, out_count = 1 };
+ float *ins[in_count];
+ float *outs[out_count];
+ uint32_t srate;
+
+ static void port_info(plugin_info_iface *pii)
+ {
+ if (Inputs == 1)
+ pii->audio_port("in", "In").input();
+ else
+ {
+ pii->audio_port("in_1", "In 1").input();
+ pii->audio_port("in_2", "In 2").input();
+ }
+ pii->audio_port("out", "Out").output();
+ }
+ void set_sample_rate(uint32_t sr) {
+ srate = sr;
+ }
+};
+
+class small_min_audio_module: public audio_operator_audio_module<2>
+{
+public:
+ void process(uint32_t count) {
+ for (uint32_t i = 0; i < count; i++)
+ outs[0][i] = std::min(ins[0][i], ins[1][i]);
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("min", "min", "Function min", "lv2:UtilityPlugin");
+ port_info(pii);
+ }
+};
+
+class small_max_audio_module: public audio_operator_audio_module<2>
+{
+public:
+ void process(uint32_t count) {
+ for (uint32_t i = 0; i < count; i++)
+ outs[0][i] = std::max(ins[0][i], ins[1][i]);
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("max", "max", "Function max", "lv2:UtilityPlugin");
+ port_info(pii);
+ }
+};
+
+class small_minus_audio_module: public audio_operator_audio_module<2>
+{
+public:
+ void process(uint32_t count) {
+ for (uint32_t i = 0; i < count; i++)
+ outs[0][i] = ins[0][i] - ins[1][i];
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("minus", "minus", "Subtract", "lv2:UtilityPlugin");
+ port_info(pii);
+ }
+};
+
+class small_mul_audio_module: public audio_operator_audio_module<2>
+{
+public:
+ void process(uint32_t count) {
+ for (uint32_t i = 0; i < count; i++)
+ outs[0][i] = ins[0][i] * ins[1][i];
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("mul", "mul", "Multiply", "lv2:UtilityPlugin");
+ port_info(pii);
+ }
+};
+
+class small_neg_audio_module: public audio_operator_audio_module<1>
+{
+public:
+ void process(uint32_t count) {
+ for (uint32_t i = 0; i < count; i++)
+ outs[0][i] = -ins[0][i];
+ }
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("neg", "neg", "Negative value", "lv2:UtilityPlugin");
+ port_info(pii);
+ }
+};
+
+class small_map_lin2exp_audio_module: public null_audio_module
+{
+public:
+ enum { in_signal, in_from_min, in_from_max, in_to_min, in_to_max, in_count };
+ enum { out_signal, out_count };
+ float *ins[in_count];
+ float *outs[out_count];
+ uint32_t srate;
+
+ static void plugin_info(plugin_info_iface *pii)
+ {
+ pii->names("lin2exp", "lin2exp", "Lin-Exp Mapper", "lv2:UtilityPlugin");
+ pii->control_port("in", "In", 0.f).input();
+ pii->control_port("from_min", "Min (from)", 0).input();
+ pii->control_port("from_max", "Max (from)", 1).input();
+ pii->control_port("to_min", "Min (to)", 20).input();
+ pii->control_port("to_max", "Max (to)", 20000).input();
+ pii->control_port("out", "Out", 0.f).output();
+ }
+ void set_sample_rate(uint32_t sr) {
+ srate = sr;
+ }
+ void process(uint32_t count) {
+ float normalized = (*ins[in_signal] - *ins[in_from_min]) / (*ins[in_from_max] - *ins[in_from_min]);
+ *outs[out_signal] = *ins[in_to_min] * pow(*ins[in_to_max] / *ins[in_to_min], normalized);
+ }
};
};
diff --git a/src/calf/plugininfo.h b/src/calf/plugininfo.h
new file mode 100644
index 0000000..43f353d
--- /dev/null
+++ b/src/calf/plugininfo.h
@@ -0,0 +1,77 @@
+/* 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __CALF_PLUGININFO_H
+#define __CALF_PLUGININFO_H
+
+#include <string>
+
+namespace synth {
+
+/// A sink to send information about an audio port
+struct audio_port_info_iface
+{
+ /// Called if it's an input port
+ virtual audio_port_info_iface& input() { return *this; }
+ /// Called if it's an output port
+ virtual audio_port_info_iface& output() { return *this; }
+ virtual ~audio_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() {}
+};
+
+/// 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 &id, const std::string &name, const std::string &label, const std::string &category) {}
+ /// Add an audio port (returns a sink which accepts further description)
+ virtual audio_port_info_iface &audio_port(const std::string &id, const std::string &name)=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)=0;
+ /// Called after plugin has reported all the information
+ virtual void finalize() {}
+ virtual ~plugin_info_iface() {}
+};
+
+/// 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() = 0;
+ virtual ~plugin_list_info_iface() {}
+};
+
+};
+
+#endif
diff --git a/src/jackhost.cpp b/src/jackhost.cpp
index a08391b..35f1af8 100644
--- a/src/jackhost.cpp
+++ b/src/jackhost.cpp
@@ -67,12 +67,6 @@ jack_host_base *synth::create_jack_host(const char *effect_name)
else if (!strcasecmp(effect_name, "phaser"))
return new jack_host<phaser_audio_module>();
#ifdef ENABLE_EXPERIMENTAL
- else if (!strcasecmp(effect_name, "lowpass12"))
- return new jack_host<small_lp_filter_audio_module>();
- else if (!strcasecmp(effect_name, "highpass12"))
- return new jack_host<small_lp_filter_audio_module>();
- else if (!strcasecmp(effect_name, "bandpass6"))
- return new jack_host<small_lp_filter_audio_module>();
#endif
else
return NULL;
diff --git a/src/makerdf.cpp b/src/makerdf.cpp
index fc6ca13..36d6995 100644
--- a/src/makerdf.cpp
+++ b/src/makerdf.cpp
@@ -23,6 +23,7 @@
#include <config.h>
#include <calf/giface.h>
#include <calf/modules.h>
+#include <calf/plugininfo.h>
#if USE_LV2
#include <calf/lv2_event.h>
#endif
@@ -110,6 +111,8 @@ static const char *units[] = {
NULL // rotations per minute
};
+//////////////// To all haters: calm down, I'll rewrite it to use the new interface one day
+
static void add_ctl_port(string &ports, parameter_properties &pp, int pidx, giface_plugin_info *gpi, int param)
{
stringstream ss;
@@ -162,6 +165,137 @@ static void add_ctl_port(string &ports, parameter_properties &pp, int pidx, gifa
ports += ss.str();
}
+struct lv2_port_base {
+ virtual std::string to_string() = 0;
+ virtual ~lv2_port_base() {}
+};
+
+struct lv2_audio_port_info: public lv2_port_base, public audio_port_info_iface
+{
+ int index;
+ string symbol, name;
+ bool is_input;
+
+ lv2_audio_port_info(int _index, const std::string &_symbol, const std::string &_name)
+ : index(_index)
+ , symbol(_symbol)
+ , name(_name)
+ , is_input(true)
+ {
+ }
+ /// Called if it's an input port
+ virtual audio_port_info_iface& input() { is_input = true; return *this; }
+ /// Called if it's an output port
+ virtual audio_port_info_iface& output() { is_input = false; return *this; }
+
+ std::string to_string() {
+ stringstream ss;
+ const char *ind = " ";
+ ss << "[\n";
+ ss << ind << (is_input ? "a lv2:InputPort ;\n" : "a lv2:OutputPort ;\n");
+ ss << ind << "a lv2:AudioPort ;\n";
+ ss << ind << "lv2:index " << index << " ;\n";
+ ss << ind << "lv2:symbol \"" << symbol << "\" ;\n";
+ ss << ind << "lv2:name \"" << name << "\" ;\n";
+ ss << " ]\n";
+
+ return ss.str();
+ }
+};
+
+struct lv2_control_port_info: public lv2_port_base, public control_port_info_iface
+{
+ int index;
+ string symbol, name;
+ bool is_input, is_log, is_bool;
+ double min, max, def_value;
+ bool has_min, has_max;
+
+ lv2_control_port_info(int _index, const std::string &_symbol, const std::string &_name, double _default)
+ : index(_index)
+ , symbol(_symbol)
+ , name(_name)
+ , is_input(true)
+ , def_value(_default)
+ {
+ has_min = has_max = is_log = is_bool = false;
+
+ }
+ /// Called if it's an input port
+ virtual control_port_info_iface& input() { is_input = true; return *this; }
+ /// Called if it's an output port
+ virtual control_port_info_iface& output() { is_input = false; return *this; }
+ /// Called to mark the port as using linear range [from, to]
+ virtual control_port_info_iface& lin_range(double from, double to) { min = from, max = to, has_min = true, has_max = true, is_log = false; return *this; }
+ /// Called to mark the port as using log range [from, to]
+ virtual control_port_info_iface& log_range(double from, double to) { min = from, max = to, has_min = true, has_max = true, is_log = true; return *this; }
+
+ std::string to_string() {
+ stringstream ss;
+ const char *ind = " ";
+ ss << "[\n";
+ ss << ind << (is_input ? "a lv2:InputPort ;\n" : "a lv2:OutputPort ;\n");
+ ss << ind << "a lv2:ControlPort ;\n";
+ ss << ind << "lv2:index " << index << " ;\n";
+ ss << ind << "lv2:symbol \"" << symbol << "\" ;\n";
+ ss << ind << "lv2:name \"" << name << "\" ;\n";
+ if (is_input)
+ ss << ind << "lv2:default " << def_value << " ;\n";
+ if (has_min)
+ ss << ind << "lv2:minimum " << min << " ;\n";
+ if (has_max)
+ ss << ind << "lv2:maximum " << max << " ;\n";
+ ss << " ]\n";
+
+ return ss.str();
+ }
+};
+
+struct lv2_plugin_info: public plugin_info_iface
+{
+ /// Plugin id
+ std::string id;
+ /// Plugin name
+ std::string name;
+ /// Plugin label (short name)
+ std::string label;
+ /// Plugin class (category)
+ std::string category;
+ /// Vector of ports
+ vector<lv2_port_base *> ports;
+ /// Set plugin names (ID, name and label)
+ virtual void names(const std::string &_id, const std::string &_name, const std::string &_label, const std::string &_category) {
+ id = _id;
+ name = _name;
+ label = _label;
+ category = _category;
+ }
+ /// Add an audio port (returns a sink which accepts further description)
+ virtual audio_port_info_iface &audio_port(const std::string &id, const std::string &name) {
+ lv2_audio_port_info *port = new lv2_audio_port_info(ports.size(), id, name);
+ ports.push_back(port);
+ return *port;
+ }
+ /// 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) {
+ lv2_control_port_info *port = new lv2_control_port_info(ports.size(), id, name, def_value);
+ ports.push_back(port);
+ return *port;
+ }
+ /// Called after plugin has reported all the information
+ virtual void finalize() {
+ }
+};
+
+struct lv2_plugin_list: public plugin_list_info_iface, public vector<lv2_plugin_info *>
+{
+ virtual plugin_info_iface &plugin() {
+ lv2_plugin_info *pi = new lv2_plugin_info;
+ push_back(pi);
+ return *pi;
+ }
+};
+
void make_ttl(string path_prefix)
{
string header;
@@ -201,8 +335,10 @@ void make_ttl(string path_prefix)
}
classes["SynthesizerPlugin"] = "lv2:InstrumentPlugin";
+ string gui_header;
+
#if USE_LV2_GUI
- header += "<http://calf.sourceforge.net/plugins/gui/gtk2-gui>\n"
+ gui_header = "<http://calf.sourceforge.net/plugins/gui/gtk2-gui>\n"
" a uiext:GtkUI ;\n"
" uiext:binary <calflv2gui.so> ;\n"
" uiext:requiredFeature uiext:makeResident .\n"
@@ -213,7 +349,7 @@ void make_ttl(string path_prefix)
synth::giface_plugin_info &pi = plugins[i];
string uri = string("<http://calf.sourceforge.net/plugins/") + string(pi.info->label) + ">";
string ttl;
- ttl = "@prefix : " + uri + " .\n" + header;
+ ttl = "@prefix : " + uri + " .\n" + header + gui_header;
ttl += uri + " a lv2:Plugin ;\n";
@@ -257,6 +393,39 @@ void make_ttl(string path_prefix)
fprintf(f, "%s\n", ttl.c_str());
fclose(f);
}
+ lv2_plugin_list lpl;
+ synth::get_all_small_plugins(&lpl);
+ for (unsigned int i = 0; i < lpl.size(); i++)
+ {
+ lv2_plugin_info *pi = lpl[i];
+ // Copy-pasted code is the root of all evil, I know!
+ string uri = string("<http://calf.sourceforge.net/small_plugins/") + string(pi->id) + ">";
+ string ttl;
+ ttl = "@prefix : " + uri + " .\n" + header;
+
+ ttl += uri + " a lv2:Plugin ;\n";
+
+ if (!pi->category.empty())
+ ttl += " a " + pi->category+" ;\n";
+
+ ttl += " doap:name \""+string(pi->label)+"\" ;\n";
+ ttl += " doap:license <http://usefulinc.com/doap/licenses/lgpl> ;\n";
+
+ if (!pi->ports.empty())
+ {
+ ttl += " lv2:port ";
+ for (unsigned int i = 0; i < pi->ports.size(); i++)
+ {
+ if (i)
+ ttl += " ,\n ";
+ ttl += pi->ports[i]->to_string();
+ }
+ ttl += ".\n\n";
+ }
+ FILE *f = fopen((path_prefix+string(pi->id)+".ttl").c_str(), "w");
+ fprintf(f, "%s\n", ttl.c_str());
+ fclose(f);
+ }
}
void make_manifest()
@@ -274,7 +443,14 @@ void make_manifest()
+ string(plugins[i].info->label)
+ "> a lv2:Plugin ; lv2:binary <calf.so> ; rdfs:seeAlso <" + string(plugins[i].info->label) + ".ttl> .\n";
- printf("%s\n", ttl.c_str());
+ lv2_plugin_list lpl;
+ synth::get_all_small_plugins(&lpl);
+ for (unsigned int i = 0; i < lpl.size(); i++)
+ ttl += string("<http://calf.sourceforge.net/small_plugins/")
+ + string(lpl[i]->id)
+ + "> a lv2:Plugin ; lv2:binary <calf.so> ; rdfs:seeAlso <" + string(lpl[i]->id) + ".ttl> .\n";
+
+ printf("%s\n", ttl.c_str());
}
#else
void make_manifest()
diff --git a/src/modules.cpp b/src/modules.cpp
index 780334d..cee15f2 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -181,40 +181,22 @@ ALL_WRAPPERS(monosynth)
////////////////////////////////////////////////////////////////////////////
#ifdef ENABLE_EXPERIMENTAL
-////////////////////////////////////////////////////////////////////////////
-
-const char *synth::small_filter_audio_module::port_names[] = {"In", "Out"};
-
-parameter_properties synth::small_filter_audio_module::param_props[] = {
- { 2000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Frequency" },
- { 0.707, 0.707, 20, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "res", "Resonance" },
-};
-
-static synth::ladspa_info small_lp_filter_info = { 0x8490, "LP12", "12dB/oct LP Filter", "Krzysztof Foltman", copyright, "LowpassPlugin" };
-static synth::ladspa_info small_hp_filter_info = { 0x8491, "HP12", "12dB/oct HP Filter", "Krzysztof Foltman", copyright, "HighpassPlugin" };
-static synth::ladspa_info small_bp_filter_info = { 0x8492, "BP6", "6dB/oct BP Filter", "Krzysztof Foltman", copyright, "BandpassPlugin" };
-static synth::ladspa_info small_br_filter_info = { 0x8493, "Notch6", "6dB/oct Notch Filter", "Krzysztof Foltman", copyright, "FilterPlugin" };
-ALL_WRAPPERS(small_lp_filter)
-ALL_WRAPPERS(small_hp_filter)
-ALL_WRAPPERS(small_bp_filter)
-ALL_WRAPPERS(small_br_filter)
+SMALL_WRAPPERS(small_lp_filter, "lowpass12")
+SMALL_WRAPPERS(small_hp_filter, "highpass12")
+SMALL_WRAPPERS(small_bp_filter, "bandpass6")
+SMALL_WRAPPERS(small_br_filter, "notch6")
-////////////////////////////////////////////////////////////////////////////
+SMALL_WRAPPERS(small_onepole_lp_filter, "lowpass6")
+SMALL_WRAPPERS(small_onepole_hp_filter, "highpass6")
+SMALL_WRAPPERS(small_onepole_ap_filter, "allpass1")
-const char *synth::small_onepole_filter_audio_module::port_names[] = {"In", "Out"};
-
-parameter_properties synth::small_onepole_filter_audio_module::param_props[] = {
- { 2000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Frequency" },
-};
-
-static synth::ladspa_info small_onepole_lp_filter_info = { 0x8490, "LP6", "6dB/oct LP Filter", "Krzysztof Foltman", copyright, "LowpassPlugin" };
-static synth::ladspa_info small_onepole_hp_filter_info = { 0x8491, "HP6", "6dB/oct HP Filter", "Krzysztof Foltman", copyright, "HighpassPlugin" };
-static synth::ladspa_info small_onepole_ap_filter_info = { 0x8492, "AP", "1-pole 1-zero Allpass Filter", "Krzysztof Foltman", copyright, "AllpassPlugin" };
-
-ALL_WRAPPERS(small_onepole_lp_filter)
-ALL_WRAPPERS(small_onepole_hp_filter)
-ALL_WRAPPERS(small_onepole_ap_filter)
+SMALL_WRAPPERS(small_min, "min")
+SMALL_WRAPPERS(small_max, "max")
+SMALL_WRAPPERS(small_minus, "minus")
+SMALL_WRAPPERS(small_mul, "mul")
+SMALL_WRAPPERS(small_neg, "neg")
+SMALL_WRAPPERS(small_map_lin2exp, "lin2exp")
#endif
@@ -224,8 +206,8 @@ extern "C" {
const LV2_Descriptor *lv2_descriptor(uint32_t index)
{
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!(index--)) return &::lv2_##name.descriptor;
+ #define PER_SMALL_MODULE_ITEM(name) if (!(index--)) return &::lv2_##name.descriptor;
#include <calf/modulelist.h>
- #undef PER_MODULE_ITEM
return NULL;
}
@@ -238,8 +220,8 @@ extern "C" {
const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index)
{
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!isSynth && !(Index--)) return &::ladspa_##name.descriptor;
+ #define PER_SMALL_MODULE_ITEM(name)
#include <calf/modulelist.h>
- #undef PER_MODULE_ITEM
return NULL;
}
@@ -251,8 +233,8 @@ extern "C" {
const DSSI_Descriptor *dssi_descriptor(unsigned long Index)
{
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!(Index--)) return &::ladspa_##name.dssi_descriptor;
+ #define PER_SMALL_MODULE_ITEM(...)
#include <calf/modulelist.h>
- #undef PER_MODULE_ITEM
return NULL;
}
@@ -264,8 +246,8 @@ std::string synth::get_builtin_modules_rdf()
std::string rdf;
#define PER_MODULE_ITEM(name, isSynth, jackname) if (!isSynth) rdf += ::ladspa_##name.generate_rdf();
+ #define PER_SMALL_MODULE_ITEM(...)
#include <calf/modulelist.h>
- #undef PER_MODULE_ITEM
return rdf;
}
@@ -288,10 +270,19 @@ giface_plugin_info create_plugin_info(ladspa_info &info)
return pi;
}
-
void synth::get_all_plugins(std::vector<giface_plugin_info> &plugins)
{
#define PER_MODULE_ITEM(name, isSynth, jackname) plugins.push_back(create_plugin_info<name##_audio_module>(name##_info));
+ #define PER_SMALL_MODULE_ITEM(...)
#include <calf/modulelist.h>
- #undef PER_MODULE_ITEM
}
+
+void synth::get_all_small_plugins(plugin_list_info_iface *iface)
+{
+ #define PER_MODULE_ITEM(name, isSynth, jackname)
+ #define PER_SMALL_MODULE_ITEM(name) { plugin_info_iface *pii = &iface->plugin(); name##_audio_module::plugin_info(pii); pii->finalize(); }
+ #include <calf/modulelist.h>
+}
+
+// instantiate descriptor templates
+PUT_DESCRIPTORS_HERE
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list