[SCM] calf/master: Remove excessive pseudo-cleverness messing code up.

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:40:02 UTC 2013


The following commit has been merged in the master branch:
commit 6ef2125741302c26aa45a0b14dcfb37ccc34ccaf
Author: Krzysztof Foltman <wdev at foltman.com>
Date:   Tue Apr 6 00:41:48 2010 +0100

    Remove excessive pseudo-cleverness messing code up.
    
    Change the DSP interface to rely on abstract base class instead of templates
    with inlining.  This reduces performance a bit further, but also makes it
    possible to decouple the modules from each other and significantly reduce
    build times.  Even without decoupling, there is some compile speed gain.
    
    The plugin API has been divided into 3 different interfaces:
    plugin_metadata_iface (discovery and information), plugin_ctl_iface (remote
    control from UIs) and audio_module_iface (actual processing).  This new
    design removes the need for virtual base classes and convoluted class
    hierarchy in some places.  This should allow for further clean-ups.
    
    A new audio_module template has been added to make it easier for all the
    plugins to implement the audio_module_iface.  This is a lightweight template
    and should make it easier to add more shared features like metering, while
    reducing code duplication between different wrappers (LADSPA, LV2, JACK
    host).
    
    Some code has been moved from the ladspa_wrap.h header to plugin.cpp, but
    this alone does not give any speed gain, as the header is only included in
    one place (plugin.cpp).  However, most of the common code in ladspa_wrapper
    template has been refactored into a non-template class
    ladspa_plugin_metadata_set, and that should save some time by not generating
    multiple copies of the methods where one copy is sufficient.
    
    The main_win.h header mistakenly included jackhost.h - which was only
    necessary for the declaration of a field that hasn't been used at all,
    probably since introduction of main_window_iface.

diff --git a/src/calf/audio_fx.h b/src/calf/audio_fx.h
index 9c204ce..6c8ad10 100644
--- a/src/calf/audio_fx.h
+++ b/src/calf/audio_fx.h
@@ -555,7 +555,8 @@ public:
     };
     
 public:
-    biquad_filter_module() : order(0) {}
+    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
diff --git a/src/calf/giface.h b/src/calf/giface.h
index 9913ddf..d63cd41 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -347,7 +347,7 @@ struct plugin_metadata_iface
 };
 
 /// Interface for host-GUI-plugin interaction (should be really split in two, but ... meh)
-struct plugin_ctl_iface: public virtual plugin_metadata_iface
+struct plugin_ctl_iface
 {
     /// @return value of given parameter
     virtual float get_param_value(int param_no) = 0;
@@ -371,6 +371,8 @@ struct plugin_ctl_iface: public virtual plugin_metadata_iface
     /// 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; }
+    /// Return metadata object
+    virtual const plugin_metadata_iface *get_metadata_iface() const = 0;
     /// Do-nothing destructor to silence compiler warning
     virtual ~plugin_ctl_iface() {}
 };
@@ -400,60 +402,152 @@ public:
 /// 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;
+    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;
+        }
+    }
 };
 
 extern bool check_for_message_context_ports(const parameter_properties *parameters, int count);
@@ -498,12 +592,13 @@ struct dssi_feedback_sender
 
 /// Metadata base class template, to provide default versions of interface functions
 template<class Metadata>
-class plugin_metadata: public virtual plugin_metadata_iface
+class plugin_metadata: public plugin_metadata_iface
 {    
 public:
     static const char *port_names[];
     static parameter_properties param_props[];
     static ladspa_plugin_info plugin_info;
+    typedef plugin_metadata<Metadata> metadata_class;
 
     // These below are stock implementations based on enums and static members in Metadata classes
     // they may be overridden to provide more interesting functionality
@@ -537,14 +632,13 @@ public:
                 ports.push_back(i);
         }
     }
-    const plugin_metadata_iface *get_metadata_iface_ptr() const { return static_cast<const Metadata *>(this); }
 };
 
 /// 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
+class plugin_metadata_proxy: public plugin_metadata_iface
 {
 public:
     const plugin_metadata_iface *impl;
diff --git a/src/calf/gui.h b/src/calf/gui.h
index a81af18..c4a8d88 100644
--- a/src/calf/gui.h
+++ b/src/calf/gui.h
@@ -189,7 +189,7 @@ public:
 
 inline const parameter_properties &param_control::get_props() 
 { 
-    return  *gui->plugin->get_param_props(param_no);
+    return  *gui->plugin->get_metadata_iface()->get_param_props(param_no);
 }
 
 class null_audio_module;
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index 88e47ed..8fd8acf 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -130,9 +130,11 @@ public:
     port midi_port;
     std::string name;
     std::string instance_name;
+    int in_count, out_count;
+    const plugin_metadata_iface *metadata;
     virtual port *get_inputs()=0;
     virtual port *get_outputs()=0;
-    virtual port *get_midi_port() { return get_midi() ? &midi_port : NULL; }
+    virtual port *get_midi_port() { return get_metadata_iface()->get_midi() ? &midi_port : NULL; }
     virtual float *get_params()=0;
     virtual void init_module()=0;
     virtual void cache_ports()=0;
@@ -147,7 +149,7 @@ public:
     }
     
     void set_params(const float *params) {
-        memcpy(get_params(), params, get_param_count() * sizeof(float));
+        memcpy(get_params(), params, get_metadata_iface()->get_param_count() * sizeof(float));
         changed = true;
     }
 
@@ -166,43 +168,50 @@ public:
 };
 
 template<class Module>
-class jack_host: public jack_host_base, public Module {
+class jack_host: public jack_host_base {
 public:
-    using Module::in_count;
-    using Module::out_count;
-    using Module::param_count;
-    using Module::progress_report;
-
-    port inputs[in_count], outputs[out_count];
-    vumeter input_vus[in_count], output_vus[out_count];
-    float param_values[param_count];
+    float **ins, **outs, **params;
+    std::vector<port> inputs, outputs;
+    std::vector<vumeter> input_vus, output_vus;
+    float *param_values;
     float midi_meter;
+    audio_module_iface *iface;
     
-    jack_host(const std::string &_name, const std::string &_instance_name, calf_plugins::progress_report_iface *_priface)
-    : jack_host_base(_name, _instance_name)
+    jack_host(audio_module_iface *_iface, const std::string &_name, const std::string &_instance_name, calf_plugins::progress_report_iface *_priface)
+    : jack_host_base(_name, _instance_name), iface(_iface)
     {
-        for (int i = 0; i < Module::param_count; i++) {
-            Module::params[i] = &param_values[i];
+        iface->get_port_arrays(ins, outs, params);
+        metadata = iface->get_metadata_iface();
+        in_count = metadata->get_input_count();
+        out_count = metadata->get_output_count();
+        inputs.resize(in_count);
+        outputs.resize(out_count);
+        input_vus.resize(in_count);
+        output_vus.resize(out_count);
+        param_values = new float[metadata->get_param_count()];
+        for (int i = 0; i < metadata->get_param_count(); i++) {
+            params[i] = &param_values[i];
         }
         clear_preset();
         midi_meter = 0;
-        progress_report = _priface;
-        Module::post_instantiate();
+        iface->set_progress_report_iface(_priface);
+        iface->post_instantiate();
     }
     
     ~jack_host()
     {
+        delete []param_values;
         if (client)
             close();
     }
     
     virtual void init_module() {
-        Module::set_sample_rate(client->sample_rate);
-        Module::activate();
-        Module::params_changed();
+        iface->set_sample_rate(client->sample_rate);
+        iface->activate();
+        iface->params_changed();
     }
 
-    virtual const parameter_properties* get_param_props(int param_no) { return Module::param_props + param_no; }
+    virtual const parameter_properties* get_param_props(int param_no) { return metadata->get_param_props(param_no); }
     
     void handle_event(uint8_t *buffer, uint32_t size)
     {
@@ -210,26 +219,26 @@ public:
         switch(buffer[0] >> 4)
         {
         case 8:
-            Module::note_off(buffer[1], buffer[2]);
+            iface->note_off(buffer[1], buffer[2]);
             break;
         case 9:
             if (!buffer[2])
-                Module::note_off(buffer[1], 0);
+                iface->note_off(buffer[1], 0);
             else
-                Module::note_on(buffer[1], buffer[2]);
+                iface->note_on(buffer[1], buffer[2]);
             break;
         case 11:
-            Module::control_change(buffer[1], buffer[2]);
+            iface->control_change(buffer[1], buffer[2]);
             break;
         case 12:
-            Module::program_change(buffer[1]);
+            iface->program_change(buffer[1]);
             break;
         case 13:
-            Module::channel_pressure(buffer[1]);
+            iface->channel_pressure(buffer[1]);
             break;
         case 14:
             value = buffer[1] + 128 * buffer[2] - 8192;
-            Module::pitch_bend(value);
+            iface->pitch_bend(value);
             break;
         }
     }
@@ -238,15 +247,15 @@ public:
         if (!len)
             return;
         for (int i = 0; i < in_count; i++)
-            input_vus[i].update(Module::ins[i] + time, len);
-        unsigned int mask = Module::process(time, len, -1, -1);
+            input_vus[i].update(ins[i] + time, len);
+        unsigned int mask = iface->process(time, len, -1, -1);
         for (int i = 0; i < out_count; i++)
         {
             if (!(mask & (1 << i))) {
-                dsp::zero(Module::outs[i] + time, len);
+                dsp::zero(outs[i] + time, len);
                 output_vus[i].update_zeros(len);
             } else
-                output_vus[i].update(Module::outs[i] + time, len);
+                output_vus[i].update(outs[i] + time, len);
         }
         // decay linearly for 0.1s
         float new_meter = midi_meter - len / (0.1 * client->sample_rate);
@@ -255,30 +264,30 @@ public:
         midi_meter = new_meter;
     }
     virtual float get_level(unsigned int port) { 
-        if (port < in_count)
+        if (port < (unsigned)in_count)
             return input_vus[port].level;
         port -= in_count;
-        if (port < out_count)
+        if (port < (unsigned)out_count)
             return output_vus[port].level;
         port -= out_count;
-        if (port == 0 && Module::support_midi)
+        if (port == 0 && metadata->get_midi())
             return midi_meter;
         return 0.f;
     }
     int process(jack_nframes_t nframes)
     {
         for (int i=0; i<in_count; i++) {
-            Module::ins[i] = inputs[i].data = (float *)jack_port_get_buffer(inputs[i].handle, nframes);
+            ins[i] = inputs[i].data = (float *)jack_port_get_buffer(inputs[i].handle, nframes);
         }
-        if (Module::support_midi)
+        if (metadata->get_midi())
             midi_port.data = (float *)jack_port_get_buffer(midi_port.handle, nframes);
         if (changed) {
-            Module::params_changed();
+            iface->params_changed();
             changed = false;
         }
 
         unsigned int time = 0;
-        if (Module::support_midi)
+        if (metadata->get_midi())
         {
             jack_midi_event_t event;
 #ifdef OLD_JACK
@@ -303,24 +312,19 @@ public:
             }
         }
         process_part(time, nframes - time);
-        Module::params_reset();
+        iface->params_reset();
         return 0;
     }
     
     void cache_ports()
     {
         for (int i=0; i<out_count; i++) {
-            Module::outs[i] = outputs[i].data = (float *)jack_port_get_buffer(outputs[i].handle, 0);
+            outs[i] = outputs[i].data = (float *)jack_port_get_buffer(outputs[i].handle, 0);
         }
     }
     
-    virtual void zero_io() {
-        memset(inputs, 0, sizeof(inputs));
-        memset(outputs, 0, sizeof(outputs));
-    }
-    
-    virtual port *get_inputs() { return inputs; }
-    virtual port *get_outputs() { return outputs; }
+    virtual port *get_inputs() { return &inputs[0]; }
+    virtual port *get_outputs() { return &outputs[0]; }
     virtual float *get_params() { return param_values; }
     virtual bool activate_preset(int bank, int program) { return false; }
     virtual float get_param_value(int param_no) {
@@ -331,16 +335,20 @@ public:
         changed = true;
     }
     virtual void execute(int cmd_no) {
-        Module::execute(cmd_no);
+        iface->execute(cmd_no);
     }
     virtual char *configure(const char *key, const char *value) { 
-        return Module::configure(key, value);
+        return iface->configure(key, value);
     }
     virtual void send_configures(send_configure_iface *sci) {
-        Module::send_configures(sci);
+        iface->send_configures(sci);
     }
     virtual int send_status_updates(send_updates_iface *sui, int last_serial) { 
-        return Module::send_status_updates(sui, last_serial);
+        return iface->send_status_updates(sui, last_serial);
+    }
+    virtual const plugin_metadata_iface *get_metadata_iface() const
+    {
+        return iface->get_metadata_iface();
     }
 };
 
diff --git a/src/calf/ladspa_wrap.h b/src/calf/ladspa_wrap.h
index f2a71b8..6625a1f 100644
--- a/src/calf/ladspa_wrap.h
+++ b/src/calf/ladspa_wrap.h
@@ -31,482 +31,91 @@
 
 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;
-}
-
+struct ladspa_plugin_metadata_set;
 /// A template implementing plugin_ctl_iface for a given plugin
-template<class Module>
-struct ladspa_instance: public Module, public plugin_ctl_iface
+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
     
-    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 const parameter_properties *get_param_props(int param_no)
-    {
-        return &Module::param_props[param_no];
-    }
-    virtual float get_param_value(int param_no)
-    {
-        // XXXKF hack
-        if (param_no >= real_param_count())
-            return 0;
-        return *Module::params[param_no];
-    }
-    virtual void set_param_value(int param_no, float value)
-    {
-        // XXXKF hack
-        if (param_no >= real_param_count())
-            return;
-        *Module::params[param_no] = value;
-    }
-    virtual int get_param_count()
-    {
-        return real_param_count();
-    }
-    virtual int get_param_port_offset() 
-    {
-        return Module::in_count + Module::out_count;
-    }
-    virtual const char *get_gui_xml() {
-        return Module::get_gui_xml();
-    }
-    virtual const line_graph_iface *get_line_graph_iface() const
-    {
-        return dynamic_cast<const line_graph_iface *>(this);
-    }
-    virtual bool activate_preset(int bank, int program) { 
-        return false;
-    }
-    virtual const char *get_name()
-    {
-        return Module::get_name();
-    }
-    virtual const char *get_id()
-    {
-        return Module::get_id();
-    }
-    virtual const char *get_label()
-    {
-        return Module::get_label();
-    }
-    virtual char *configure(const char *key, const char *value)
-    {
-#if USE_DSSI
-        if (!strcmp(key, "OSC:FEEDBACK_URI"))
-        {
-            line_graph_iface *lgi = dynamic_cast<line_graph_iface *>(this);
-            if (!lgi)
-                return NULL;
-            if (*value)
-            {
-                if (feedback_sender) {
-                    delete feedback_sender;
-                    feedback_sender = NULL;
-                }
-                feedback_sender = new dssi_feedback_sender(value, lgi);
-                feedback_sender->add_graphs(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; }
+    ladspa_instance(audio_module_iface *_module, ladspa_plugin_metadata_set *_ladspa, int sample_rate);
+    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);
+        module->execute(cmd_no);
     }
     virtual void send_configures(send_configure_iface *sci) { 
-        Module::send_configures(sci);
+        module->send_configures(sci);
+    }
+    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;
     }
 };
 
-/// 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
+/// Set of metadata produced by LADSPA wrapper for LADSPA-related purposes
+struct ladspa_plugin_metadata_set
 {
-    typedef ladspa_instance<Module> instance;
-    
     /// LADSPA descriptor
-    static LADSPA_Descriptor descriptor;
+    LADSPA_Descriptor descriptor;
     /// LADSPA descriptor for DSSI (uses a different name for the plugin, otherwise same as descriptor)
-    static LADSPA_Descriptor descriptor_for_dssi;
+    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];
-            const 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
-    }
+    DSSI_Descriptor dssi_descriptor;
+    DSSI_Program_Descriptor dssi_default_program;
 
-    ~ladspa_wrapper()
-    {
-        delete []descriptor.PortNames;
-        delete []descriptor.PortDescriptors;
-        delete []descriptor.PortRangeHints;
-#if USE_DSSI
-        presets->clear();
-        preset_descs->clear();
-        delete presets;
-        delete preset_descs;
+    std::vector<plugin_preset> *presets;
+    std::vector<DSSI_Program_Descriptor> *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;
-    }
+    int input_count, output_count, param_count, real_param_count;
+    const plugin_metadata_iface *metadata;
     
-    /// 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_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();
+};
 
-    /// 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);
-    }
+/// 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;
     
-    /// 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)
+private:
+    ladspa_wrapper(const plugin_metadata_iface *md)
     {
-        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;
-        }
+        output.prepare(md, cb_instantiate);
     }
 
-#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)
+public:
+    /// LADSPA instantiation function (create a plugin instance)
+    static LADSPA_Handle cb_instantiate(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate)
     {
-        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();
+        return new ladspa_instance(new Module, &output, sample_rate);
     }
 
-    /// 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;
+    static ladspa_plugin_metadata_set &get() { 
+        static ladspa_wrapper instance(new typename Module::metadata_class);
+        return instance.output;
     }
 };
 
diff --git a/src/calf/lv2wrap.h b/src/calf/lv2wrap.h
index 604cc05..983c5f7 100644
--- a/src/calf/lv2wrap.h
+++ b/src/calf/lv2wrap.h
@@ -36,9 +36,10 @@
 
 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 +49,117 @@ 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;
+        progress_report_feature = NULL;
         midi_event_type = 0xFFFFFFFF;
-        set_srate = true;
+
         srate_to_set = 44100;
-        get_message_context_parameters(message_params);
-        progress_report_feature = NULL;
+        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 const parameter_properties *get_param_props(int param_no)
-    {
-        return &Module::param_props[param_no];
-    }
-    virtual float get_param_value(int param_no)
-    {
-        return *Module::params[param_no];
-    }
-    virtual void set_param_value(int param_no, float value)
-    {
-        *Module::params[param_no] = value;
-    }
-    virtual int get_param_count()
-    {
-        return Module::param_count;
-    }
-    virtual int get_param_port_offset() 
-    {
-        return Module::in_count + Module::out_count;
-    }
-    virtual const char *get_gui_xml() {
-        return Module::get_gui_xml();
-    }
-    virtual const line_graph_iface *get_line_graph_iface() const
-    {
-        return dynamic_cast<const line_graph_iface *>(this);
+            module->set_progress_report_iface(this);
+        module->post_instantiate();
     }
     virtual bool activate_preset(int bank, int program) { 
         return false;
     }
-    virtual const char *get_name() const
-    {
-        return Module::get_name();
-    }
-    virtual const char *get_id() const
-    {
-        return Module::get_id();
-    }
-    virtual const char *get_label() const
-    {
-        return Module::get_label();
-    }
-    virtual int get_input_count() const { return Module::in_count; }
-    virtual int get_output_count() const { return Module::out_count; }
-    virtual bool get_midi() const { return Module::support_midi; }
     virtual float get_level(unsigned int port) { return 0.f; }
     virtual void execute(int cmd_no) {
-        Module::execute(cmd_no);
+        module->execute(cmd_no);
     }
     virtual void report_progress(float percentage, const std::string &message) {
         if (progress_report_feature)
             (*progress_report_feature->progress)(progress_report_feature->context, percentage, !message.empty() ? message.c_str() : NULL);
     }
     void send_configures(send_configure_iface *sci) { 
-        Module::send_configures(sci);
+        module->send_configures(sci);
     }
     uint32_t impl_message_run(const void *valid_inputs, void *output_ports) {
         for (unsigned int i = 0; i < message_params.size(); i++)
         {
             int pn = message_params[i];
-            const parameter_properties &pp = *get_param_props(pn);
+            const parameter_properties &pp = *metadata->get_param_props(pn);
             if ((pp.flags & PF_TYPEMASK) == PF_STRING
-                && (((LV2_String_Data *)Module::params[pn])->flags & LV2_STRING_DATA_CHANGED_FLAG)) {
+                && (((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 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;
+    }
 };
 
 struct LV2_Calf_Descriptor {
@@ -172,7 +169,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 +193,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 +206,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 +218,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;
@@ -249,82 +247,33 @@ struct lv2_wrapper
             }
             features++;
         }
-        mod->post_instantiate();
+        mod->module->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;
diff --git a/src/calf/main_win.h b/src/calf/main_win.h
index abf9e4a..4056b59 100644
--- a/src/calf/main_win.h
+++ b/src/calf/main_win.h
@@ -27,7 +27,6 @@
 #include <vector>
 #include <gtk/gtk.h>
 #include <calf/gui.h>
-#include <calf/jackhost.h>
 #include "custom_ctl.h"
 
 namespace calf_plugins {
@@ -57,11 +56,6 @@ namespace calf_plugins {
         GtkWidget *strips_table;
         GtkUIManager *ui_mgr;
         GtkActionGroup *std_actions, *plugin_actions;
-#if USE_JACK
-        jack_client *client;
-#else
-        void *client_dummy;
-#endif
         std::map<plugin_ctl_iface *, plugin_strip *> plugins;
         std::set<std::string> conditions;
         std::vector<plugin_ctl_iface *> plugin_queue;
diff --git a/src/calf/modules.h b/src/calf/modules.h
index 5e76cdb..f35ae23 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -49,9 +49,6 @@ class flanger_audio_module: public audio_module<flanger_metadata>, public freque
 {
 public:
     dsp::simple_flanger<float, 2048> left, right;
-    float *ins[in_count]; 
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     bool clear_reset;
     float last_r_phase;
@@ -78,9 +75,6 @@ class phaser_audio_module: public audio_module<phaser_metadata>, public frequenc
 {
 public:
     enum { MaxStages = 12 };
-    float *ins[in_count]; 
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     bool clear_reset;
     float last_r_phase;
@@ -115,9 +109,6 @@ public:
     int predelay_amt;
     float meter_wet, meter_out;
     uint32_t clip;
-    float *ins[in_count]; 
-    float *outs[out_count];
-    float *params[param_count];
     
     void params_changed();
     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
@@ -131,9 +122,6 @@ 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 };
-    float *ins[in_count]; 
-    float *outs[out_count];
-    float *params[param_count];
     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)
@@ -159,9 +147,6 @@ public:
 class rotary_speaker_audio_module: public audio_module<rotary_speaker_metadata>
 {
 public:
-    float *ins[in_count]; 
-    float *outs[out_count];
-    float *params[param_count];
     /// 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;
@@ -206,21 +191,21 @@ public:
 };
 
 template<typename FilterClass, typename Metadata>
-class filter_module_with_inertia: public FilterClass
+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;
     
-    float *ins[Metadata::in_count]; 
-    float *outs[Metadata::out_count];
-    float *params[Metadata::param_count];
-
     inertia<exponential_ramp> inertia_cutoff, inertia_resonance, inertia_gain;
     once_per_n timer;
     bool is_active;    
     mutable volatile int last_generation, last_calculated_generation;
     
-    filter_module_with_inertia()
+    filter_module_with_inertia(float **ins, float **outs, float **params)
     : inertia_cutoff(exponential_ramp(128), 20)
     , inertia_resonance(exponential_ramp(128), 20)
     , inertia_gain(exponential_ramp(128), 1.0)
@@ -311,13 +296,13 @@ public:
 
 /// biquad filter module
 class filter_audio_module: 
-    public audio_module<filter_metadata>, 
     public filter_module_with_inertia<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<biquad_filter_module, filter_metadata>(ins, outs, params)
     {
         last_generation = 0;
     }
@@ -328,22 +313,6 @@ public:
         inertia_filter_module::params_changed(); 
     }
         
-    void activate()
-    {
-        inertia_filter_module::activate();
-    }
-    
-    void set_sample_rate(uint32_t sr)
-    {
-        inertia_filter_module::set_sample_rate(sr);
-    }
-
-    
-    void deactivate()
-    {
-        inertia_filter_module::deactivate();
-    }
-    
     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;
 };
@@ -352,9 +321,6 @@ public:
 class multichorus_audio_module: public audio_module<multichorus_metadata>, public frequency_response_line_graph
 {
 public:
-    float *ins[in_count]; 
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     dsp::multichorus<float, sine_multi_lfo<float, 8>, filter_sum<dsp::biquad_d2<>, dsp::biquad_d2<> >, 4096> left, right;
     float last_r_phase;
@@ -413,9 +379,6 @@ private:
     gain_reduction_audio_module compressor;
 public:
     typedef std::complex<double> cfloat;
-    float *ins[in_count];
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     bool is_active;
     mutable volatile int last_generation, last_calculated_generation;
@@ -458,9 +421,6 @@ private:
     biquad_d2<float> f1L, f1R, f2L, f2R;
 public:
     typedef std::complex<double> cfloat;
-    float *ins[in_count];
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     bool is_active;
     mutable volatile int last_generation, last_calculated_generation;
@@ -490,9 +450,6 @@ private:
     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:
-    float *ins[in_count];
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     bool is_active;
     multibandcompressor_audio_module();
@@ -523,9 +480,6 @@ private:
     gain_reduction_audio_module compressor;
     biquad_d2<float> hpL, hpR, lpL, lpR, pL, pR;
 public:
-    float *ins[in_count];
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     bool is_active;
     mutable volatile int last_generation, last_calculated_generation;
@@ -549,6 +503,9 @@ 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;
@@ -571,9 +528,6 @@ private:
     inline void process_hplp(float &left, float &right);
 public:
     typedef std::complex<double> cfloat;
-    float *ins[in_count];
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     bool is_active;
     mutable volatile int last_generation, last_calculated_generation;
@@ -628,9 +582,6 @@ private:
     bool clear_reset;
     lfo_audio_module lfoL, lfoR;
 public:
-    float *ins[in_count];
-    float *outs[out_count];
-    float *params[param_count];
     uint32_t srate;
     bool is_active;
     pulsator_audio_module();
@@ -653,10 +604,13 @@ public:
 
 /// Filterclavier --- MIDI controlled filter by Hans Baier
 class filterclavier_audio_module: 
-        public audio_module<filterclavier_metadata>, 
         public filter_module_with_inertia<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;
     
diff --git a/src/calf/modules_dev.h b/src/calf/modules_dev.h
index 9861d14..ac3471b 100644
--- a/src/calf/modules_dev.h
+++ b/src/calf/modules_dev.h
@@ -35,11 +35,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;
diff --git a/src/calf/modules_synths.h b/src/calf/modules_synths.h
index 06061df..42e8f83 100644
--- a/src/calf/modules_synths.h
+++ b/src/calf/modules_synths.h
@@ -42,9 +42,6 @@ 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;
diff --git a/src/calf/organ.h b/src/calf/organ.h
index c45b6b0..43dec49 100644
--- a/src/calf/organ.h
+++ b/src/calf/organ.h
@@ -291,9 +291,6 @@ public:
     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;
diff --git a/src/calf/wavetable.h b/src/calf/wavetable.h
index a553538..d861b44 100644
--- a/src/calf/wavetable.h
+++ b/src/calf/wavetable.h
@@ -102,9 +102,6 @@ protected:
 
 public:
     enum { mod_matrix_slots = 10 };
-    float *ins[in_count]; 
-    float *outs[out_count];
-    float *params[param_count];
     int16_t tables[wt_count][129][256]; // one dummy level for interpolation
     /// Rows of the modulation matrix
     dsp::modulation_entry mod_matrix_data[mod_matrix_slots];
diff --git a/src/dssigui.cpp b/src/dssigui.cpp
index d772f67..6ec00ff 100644
--- a/src/dssigui.cpp
+++ b/src/dssigui.cpp
@@ -212,6 +212,7 @@ struct plugin_proxy: public plugin_ctl_iface, public plugin_metadata_proxy, publ
     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;
     void update_cairo_context(cairo_iface *context, cairo_params &item) const;
+    virtual const plugin_metadata_iface *get_metadata_iface() const { return this; }
 };
 
 bool plugin_proxy::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
diff --git a/src/giface.cpp b/src/giface.cpp
index c9cdedc..997e1b7 100644
--- a/src/giface.cpp
+++ b/src/giface.cpp
@@ -189,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++)
     {
-        const 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] : "");
diff --git a/src/gui.cpp b/src/gui.cpp
index 8893461..11888ee 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -282,7 +282,7 @@ void plugin_gui::xml_element_start(const char *element, const char *attributes[]
                     param_no = it->second;
             }
             if (param_no != -1)
-                current_control->param_variable = plugin->get_param_props(param_no)->short_name;
+                current_control->param_variable = plugin->get_metadata_iface()->get_param_props(param_no)->short_name;
             current_control->create(this, param_no);
             current_control->set_std_properties();
             current_control->init_xml(element);
@@ -331,9 +331,9 @@ GtkWidget *plugin_gui::create_from_xml(plugin_ctl_iface *_plugin, const char *xm
     ignore_stack = 0;
     
     param_name_map.clear();
-    int size = plugin->get_param_count();
+    int size = plugin->get_metadata_iface()->get_param_count();
     for (int i = 0; i < size; i++)
-        param_name_map[plugin->get_param_props(i)->short_name] = i;
+        param_name_map[plugin->get_metadata_iface()->get_param_props(i)->short_name] = i;
     
     XML_SetUserData(parser, this);
     XML_SetElementHandler(parser, xml_element_start, xml_element_end);
@@ -424,7 +424,7 @@ void plugin_gui::on_idle()
     {
         if (params[i]->param_no != -1)
         {
-            const parameter_properties &props = *plugin->get_param_props(params[i]->param_no);
+            const parameter_properties &props = *plugin->get_metadata_iface()->get_param_props(params[i]->param_no);
             bool is_output = (props.flags & PF_PROP_OUTPUT) != 0;
             if (is_output) {
                 params[i]->set();
@@ -592,7 +592,7 @@ string plugin_gui_window::make_gui_preset_list(GtkActionGroup *grp, bool builtin
 string plugin_gui_window::make_gui_command_list(GtkActionGroup *grp)
 {
     string command_xml = command_pre_xml;
-    plugin_command_info *ci = gui->plugin->get_commands();
+    plugin_command_info *ci = gui->plugin->get_metadata_iface()->get_commands();
     if (!ci)
         return "";
     for(int i = 0; ci->name; i++, ci++)
@@ -671,7 +671,7 @@ void plugin_gui_window::create(plugin_ctl_iface *_jh, const char *title, const c
     // printf("size request %dx%d\n", req2.width, req2.height);
     
     GtkWidget *container;
-    const char *xml = _jh->get_gui_xml();
+    const char *xml = _jh->get_metadata_iface()->get_gui_xml();
     assert(xml);
     container = gui->create_from_xml(_jh, xml);
     
diff --git a/src/gui_controls.cpp b/src/gui_controls.cpp
index c2028a7..4e21b72 100644
--- a/src/gui_controls.cpp
+++ b/src/gui_controls.cpp
@@ -807,7 +807,7 @@ GtkWidget *line_graph_param_control::create(plugin_gui *_gui, int _param_no)
     widget->requisition.width = get_int("width", 40);
     widget->requisition.height = get_int("height", 40);
     calf_line_graph_set_square(clg, get_int("square", 0));
-    clg->source = gui->plugin->get_line_graph_iface();
+    clg->source = gui->plugin->get_metadata_iface()->get_line_graph_iface();
     clg->source_id = param_no;
     gtk_widget_set_name(GTK_WIDGET(widget), "Calf-LineGraph");
     return widget;
@@ -836,7 +836,7 @@ GtkWidget *listview_param_control::create(plugin_gui *_gui, int _param_no)
     gui = _gui;
     param_no = _param_no;
     
-    teif = gui->plugin->get_table_edit_iface();
+    teif = gui->plugin->get_metadata_iface()->get_table_edit_iface();
     const table_column_info *tci = teif->get_table_columns(param_no);
     assert(tci);
     cols = 0;
diff --git a/src/jackhost.cpp b/src/jackhost.cpp
index 2628dd8..dec3da7 100644
--- a/src/jackhost.cpp
+++ b/src/jackhost.cpp
@@ -56,7 +56,7 @@ static bool quit_cb(void *user_data);
 
 jack_host_base *calf_plugins::create_jack_host(const char *effect_name, const std::string &instance_name, calf_plugins::progress_report_iface *priface)
 {
-    #define PER_MODULE_ITEM(name, isSynth, jackname) if (!strcasecmp(effect_name, jackname)) return new jack_host<name##_audio_module>(effect_name, instance_name, priface);
+    #define PER_MODULE_ITEM(name, isSynth, jackname) if (!strcasecmp(effect_name, jackname)) return new jack_host<audio_module_iface>(new name##_audio_module, effect_name, instance_name, priface);
     #include <calf/modulelist.h>
     return NULL;
 }
@@ -80,7 +80,7 @@ void jack_host_base::create_ports() {
     static const char *suffixes[] = { "l", "r", "2l", "2r" };
     port *inputs = get_inputs();
     port *outputs = get_outputs();
-    int in_count = get_input_count(), out_count = get_output_count();
+    int in_count = metadata->get_input_count(), out_count = metadata->get_output_count();
     for (int i=0; i<in_count; i++) {
         sprintf(buf, "%s_in_%s", instance_name.c_str(), suffixes[i]);
         sprintf(buf2, client->input_name.c_str(), client->input_nr++);
@@ -91,7 +91,7 @@ void jack_host_base::create_ports() {
             throw text_exception("Could not create JACK input port");
         jack_port_set_alias(inputs[i].handle, (prefix + buf2).c_str());
     }
-    if (get_midi()) {
+    if (metadata->get_midi()) {
         sprintf(buf, "%s_midi_in", instance_name.c_str());
         sprintf(buf2, client->midi_name.c_str(), client->midi_nr++);
         midi_port.name = buf2;
@@ -114,7 +114,7 @@ void jack_host_base::create_ports() {
 
 void jack_host_base::close() {
     port *inputs = get_inputs(), *outputs = get_outputs();
-    int input_count = get_input_count(), output_count = get_output_count();
+    int input_count = metadata->get_input_count(), output_count = metadata->get_output_count();
     for (int i = 0; i < input_count; i++) {
         jack_port_unregister(client->client, inputs[i].handle);
         inputs[i].data = NULL;
@@ -123,7 +123,7 @@ void jack_host_base::close() {
         jack_port_unregister(client->client, outputs[i].handle);
         outputs[i].data = NULL;
     }
-    if (get_midi())
+    if (metadata->get_midi())
         jack_port_unregister(client->client, midi_port.handle);
     client = NULL;
 }
@@ -407,7 +407,7 @@ void host_session::remove_all_plugins()
 
 bool host_session::activate_preset(int plugin_no, const std::string &preset, bool builtin)
 {
-    string cur_plugin = plugins[plugin_no]->get_id();
+    string cur_plugin = plugins[plugin_no]->metadata->get_id();
     preset_vector &pvec = (builtin ? get_builtin_presets() : get_user_presets()).presets;
     for (unsigned int i = 0; i < pvec.size(); i++) {
         if (pvec[i].name == preset && pvec[i].plugin == cur_plugin)
@@ -435,7 +435,7 @@ void host_session::connect()
             if (chains.count(i)) {
                 if (!i)
                 {
-                    if (plugins[0]->get_output_count() < 2)
+                    if (plugins[0]->metadata->get_output_count() < 2)
                     {
                         fprintf(stderr, "Cannot connect input to plugin %s - incompatible ports\n", plugins[0]->name.c_str());
                     } else {
@@ -445,7 +445,7 @@ void host_session::connect()
                 }
                 else
                 {
-                    if (plugins[i - 1]->get_output_count() < 2 || plugins[i]->get_input_count() < 2)
+                    if (plugins[i - 1]->metadata->get_output_count() < 2 || plugins[i]->metadata->get_input_count() < 2)
                     {
                         fprintf(stderr, "Cannot connect plugins %s and %s - incompatible ports\n", plugins[i - 1]->name.c_str(), plugins[i]->name.c_str());
                     }
@@ -459,7 +459,7 @@ void host_session::connect()
         if (chains.count(plugins.size()) && plugins.size())
         {
             int last = plugins.size() - 1;
-            if (plugins[last]->get_output_count() < 2)
+            if (plugins[last]->metadata->get_output_count() < 2)
             {
                 fprintf(stderr, "Cannot connect plugin %s to output - incompatible ports\n", plugins[last]->name.c_str());
             } else {
@@ -470,7 +470,7 @@ void host_session::connect()
         if (autoconnect_midi != "") {
             for (unsigned int i = 0; i < plugins.size(); i++)
             {
-                if (plugins[i]->get_midi())
+                if (plugins[i]->metadata->get_midi())
                     client.connect(autoconnect_midi, cnp + plugins[i]->get_midi_port()->name);
             }
         }
@@ -482,7 +482,7 @@ void host_session::connect()
                 if (j + 1 == autoconnect_midi_index) {
                     for (unsigned int i = 0; i < plugins.size(); i++)
                     {
-                        if (plugins[i]->get_midi())
+                        if (plugins[i]->metadata->get_midi())
                             client.connect(ports[j], cnp + plugins[i]->get_midi_port()->name);
                     }
                     break;
@@ -566,14 +566,14 @@ char *host_session::save_file(const char *name)
     for (unsigned int i = 0; i < plugins.size(); i++) {
         jack_host_base *p = plugins[i];
         plugin_preset preset;
-        preset.plugin = p->get_id();
+        preset.plugin = p->metadata->get_id();
         preset.get_from(p);
         data += "<plugin";
         data += to_xml_attr("type", preset.plugin);
         data += to_xml_attr("instance-name", p->instance_name);
-        if (p->get_input_count())
+        if (p->metadata->get_input_count())
             data += to_xml_attr("input-index", p->get_inputs()[0].name.substr(i_name.length()));
-        if (p->get_output_count())
+        if (p->metadata->get_output_count())
             data += to_xml_attr("output-index", p->get_outputs()[0].name.substr(o_name.length()));
         if (p->get_midi_port())
             data += to_xml_attr("midi-index", p->get_midi_port()->name.substr(m_name.length()));
@@ -728,15 +728,15 @@ bool save_data_set_cb(lash_config_handle_t *handle, void *user_data)
         jack_host_base *p = sess->plugins[i];
         char ss[32];
         plugin_preset preset;
-        preset.plugin = p->get_id();
+        preset.plugin = p->metadata->get_id();
         preset.get_from(p);
         sprintf(ss, "Plugin%d", i);
         pstr = preset.to_xml();
         tmp.clear();
         tmp["instance_name"] = p->instance_name;
-        if (p->get_input_count())
+        if (p->metadata->get_input_count())
             tmp["input_name"] = p->get_inputs()[0].name.substr(i_name.length());
-        if (p->get_output_count())
+        if (p->metadata->get_output_count())
             tmp["output_name"] = p->get_outputs()[0].name.substr(o_name.length());
         if (p->get_midi_port())
             tmp["midi_name"] = p->get_midi_port()->name.substr(m_name.length());
diff --git a/src/lv2gui.cpp b/src/lv2gui.cpp
index 0522823..16f1b78 100644
--- a/src/lv2gui.cpp
+++ b/src/lv2gui.cpp
@@ -104,6 +104,7 @@ struct plugin_proxy_base
     
     /// Map an URI to an integer value using a given URI map
     uint32_t map_uri(const char *mapURI, const char *keyURI);
+
 };
 
 plugin_proxy_base::plugin_proxy_base(const plugin_metadata_iface *metadata, LV2UI_Write_Function wf, LV2UI_Controller c, const LV2_Feature* const* features)
@@ -190,7 +191,7 @@ uint32_t plugin_proxy_base::map_uri(const char *mapURI, const char *keyURI)
 const line_graph_iface *plugin_proxy_base::get_line_graph_iface() const
 {
     if (instance)
-        return instance->get_line_graph_iface();
+        return instance->get_metadata_iface()->get_line_graph_iface();
     return NULL;
 }
 
@@ -287,6 +288,7 @@ struct lv2_plugin_proxy: public plugin_ctl_iface, public plugin_metadata_proxy,
     void send_configures(send_configure_iface *sci) { 
         fprintf(stderr, "TODO: send_configures (non-control port configuration dump) not implemented in LV2 GUIs\n");
     }
+    virtual const plugin_metadata_iface *get_metadata_iface() const { return plugin_metadata; }
 };
 
 static gboolean plugin_on_idle(void *data)
@@ -345,13 +347,13 @@ void gui_port_event(LV2UI_Handle handle, uint32_t port, uint32_t buffer_size, ui
     lv2_plugin_proxy *proxy = dynamic_cast<lv2_plugin_proxy *>(gui->plugin);
     assert(proxy);
     float v = *(float *)buffer;
-    int param = port - gui->plugin->get_param_port_offset();
-    if (param >= gui->plugin->get_param_count())
+    int param = port - proxy->plugin_metadata->get_param_port_offset();
+    if (param >= proxy->plugin_metadata->get_param_count())
         return;
     if (proxy->is_string_param[param])
     {
         TempSendSetter _a_(proxy->sends[param], false);
-        gui->plugin->configure(gui->plugin->get_param_props(param)->short_name, ((LV2_String_Data *)buffer)->data);
+        gui->plugin->configure(proxy->plugin_metadata->get_param_props(param)->short_name, ((LV2_String_Data *)buffer)->data);
         return;
     }
     if (fabs(gui->plugin->get_param_value(param) - v) < 0.00001)
diff --git a/src/main_win.cpp b/src/main_win.cpp
index 5f7a8ca..352b53c 100644
--- a/src/main_win.cpp
+++ b/src/main_win.cpp
@@ -261,7 +261,8 @@ main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
     
     // title @ 1, 1
     char buf[128];
-    sprintf(buf, "<span size=\"15000\">%s</span>", plugin->get_label());
+    const plugin_metadata_iface *metadata = plugin->get_metadata_iface();
+    sprintf(buf, "<span size=\"15000\">%s</span>", metadata->get_label());
     GtkWidget *title = gtk_label_new(NULL);
     gtk_label_set_markup(GTK_LABEL(title), buf);
     gtk_table_attach(GTK_TABLE(strips_table), title, 1, 2, row, row + 1, ao, GTK_SHRINK, 20, 10);
@@ -291,7 +292,7 @@ main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
     gtk_widget_show(buttonBox);
     
     // midi box
-    if (plugin->get_midi()) {
+    if (metadata->get_midi()) {
         label = calf_led_new();
         GtkWidget *midiBox = gtk_vbox_new(FALSE, 1);
         gtk_box_pack_start(GTK_BOX(midiBox), GTK_WIDGET(gtk_label_new("MIDI")), TRUE, TRUE, 0);
@@ -312,9 +313,8 @@ main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
 
     for (int i = 0; i < 2; i++)
         strip->audio_in[i] = strip->audio_out[i] = NULL;
-    
-    
-    if (plugin->get_input_count() == 2) {
+        
+    if (metadata->get_input_count() == 2) {
         
         GtkWidget *inBox  = gtk_vbox_new(FALSE, 1);
         
@@ -338,7 +338,7 @@ main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
         gtk_widget_set_size_request(GTK_WIDGET(inBox), 160, -1);
     }
 
-    if (plugin->get_output_count() == 2) {
+    if (metadata->get_output_count() == 2) {
         
         GtkWidget *outBox  = gtk_vbox_new(FALSE, 1);
         
@@ -396,7 +396,7 @@ void main_window::update_strip(plugin_ctl_iface *plugin)
 void main_window::open_gui(plugin_ctl_iface *plugin)
 {
     plugin_gui_window *gui_win = new plugin_gui_window(this);
-    gui_win->create(plugin, (prefix + plugin->get_label()).c_str(), plugin->get_id());
+    gui_win->create(plugin, (prefix + plugin->get_metadata_iface()->get_label()).c_str(), plugin->get_metadata_iface()->get_id());
     gtk_widget_show_all(GTK_WIDGET(gui_win->toplevel));
     plugins[plugin]->gui_win = gui_win; 
 }
@@ -548,15 +548,15 @@ gboolean main_window::on_idle(void *data)
             plugin_ctl_iface *plugin = i->first;
             plugin_strip *strip = i->second;
             int idx = 0;
-            if (plugin->get_input_count() == 2) {
+            if (plugin->get_metadata_iface()->get_input_count() == 2) {
                 calf_vumeter_set_value(CALF_VUMETER(strip->audio_in[0]), LVL(plugin->get_level(idx++)));
                 calf_vumeter_set_value(CALF_VUMETER(strip->audio_in[1]), LVL(plugin->get_level(idx++)));
             }
-            if (plugin->get_output_count() == 2) {
+            if (plugin->get_metadata_iface()->get_output_count() == 2) {
                 calf_vumeter_set_value(CALF_VUMETER(strip->audio_out[0]), LVL(plugin->get_level(idx++)));
                 calf_vumeter_set_value(CALF_VUMETER(strip->audio_out[1]), LVL(plugin->get_level(idx++)));
             }
-            if (plugin->get_midi()) {
+            if (plugin->get_metadata_iface()->get_midi()) {
                 calf_led_set_value (CALF_LED (strip->midi_in), plugin->get_level(idx++));
             }
         }
diff --git a/src/modules.cpp b/src/modules.cpp
index 5cd2074..350e449 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -892,7 +892,7 @@ CALF_PORT_PROPS(wavetable) = {
 
 calf_plugins::plugin_registry::plugin_registry()
 {
-    #define PER_MODULE_ITEM(name, isSynth, jackname) plugins.push_back((new name##_metadata)->get_metadata_iface_ptr());
+    #define PER_MODULE_ITEM(name, isSynth, jackname) plugins.push_back((new name##_metadata));
     #include <calf/modulelist.h>
 }
 
diff --git a/src/modules_dsp.cpp b/src/modules_dsp.cpp
index dfaa18c..354807c 100644
--- a/src/modules_dsp.cpp
+++ b/src/modules_dsp.cpp
@@ -455,7 +455,8 @@ int filter_audio_module::get_changed_offsets(int index, int generation, int &sub
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 filterclavier_audio_module::filterclavier_audio_module() 
-: min_gain(1.0)
+: filter_module_with_inertia<biquad_filter_module, filterclavier_metadata>(ins, outs, params)
+, min_gain(1.0)
 , max_gain(32.0)
 , last_note(-1)
 , last_velocity(-1)
diff --git a/src/plugin.cpp b/src/plugin.cpp
index 12c2f0e..9069e6b 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -27,28 +27,425 @@
 
 using namespace calf_plugins;
 
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
 #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;
+#endif
 
-template<class Module>
-std::vector<plugin_preset> *ladspa_wrapper<Module>::presets;
+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
+#endif
+    if (!strcmp(key, "ExecCommand"))
+    {
+        if (*value)
+        {
+            execute(atoi(value));
+        }
+        return NULL;
+    }
+    return module->configure(key, value);
+}
 
 template<class Module>
-std::vector<DSSI_Program_Descriptor> *ladspa_wrapper<Module>::preset_descs;
+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;
+    }
+}
+#endif
+#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()
+{
+    presets = NULL;
+    preset_descs = NULL;
+    metadata = NULL;
+    memset(&descriptor, 0, sizeof(descriptor));
+    memset(&descriptor_for_dssi, 0, sizeof(descriptor_for_dssi));
+    memset(&dssi_descriptor, 0, sizeof(dssi_descriptor));
+}
+
+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 + 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
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 #if USE_LV2
 // instantiate descriptor templates
diff --git a/src/preset.cpp b/src/preset.cpp
index 3573591..2a95b07 100644
--- a/src/preset.cpp
+++ b/src/preset.cpp
@@ -80,14 +80,15 @@ void plugin_preset::activate(plugin_ctl_iface *plugin)
 {
     // First, clear everything to default values (in case some parameters or variables are missing)
     plugin->clear_preset();
+    const plugin_metadata_iface *metadata = plugin->get_metadata_iface();
 
     map<string, int> names;    
-    int count = plugin->get_param_count();
+    int count = metadata->get_param_count();
     // this is deliberately done in two separate loops - if you wonder why, just think for a while :)
     for (int i = 0; i < count; i++)
-        names[plugin->get_param_props(i)->name] = i;
+        names[metadata->get_param_props(i)->name] = i;
     for (int i = 0; i < count; i++)
-        names[plugin->get_param_props(i)->short_name] = i;
+        names[metadata->get_param_props(i)->short_name] = i;
     // no support for unnamed parameters... tough luck :)
     for (unsigned int i = 0; i < min(param_names.size(), values.size()); i++)
     {
@@ -108,11 +109,12 @@ void plugin_preset::activate(plugin_ctl_iface *plugin)
 
 void plugin_preset::get_from(plugin_ctl_iface *plugin)
 {
-    int count = plugin->get_param_count();
+    const plugin_metadata_iface *metadata = plugin->get_metadata_iface();
+    int count = metadata->get_param_count();
     for (int i = 0; i < count; i++) {
-        if ((plugin->get_param_props(i)->flags & PF_TYPEMASK) >= PF_STRING)
+        if ((metadata->get_param_props(i)->flags & PF_TYPEMASK) >= PF_STRING)
             continue;
-        param_names.push_back(plugin->get_param_props(i)->short_name);
+        param_names.push_back(metadata->get_param_props(i)->short_name);
         values.push_back(plugin->get_param_value(i));
     }
     struct store_obj: public send_configure_iface

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list