[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