Prototype LV2 extension for plugins to provide Midnams
authorRobin Gareus <robin@gareus.org>
Sat, 29 Oct 2016 17:21:48 +0000 (19:21 +0200)
committerRobin Gareus <robin@gareus.org>
Sat, 29 Oct 2016 17:57:43 +0000 (19:57 +0200)
libs/ardour/ardour/lv2_extensions.h
libs/ardour/ardour/lv2_plugin.h
libs/ardour/ardour/plugin.h
libs/ardour/lv2_plugin.cc

index 64fc3bc615cf13e69a934e419cc7b008715427b3..f38ac8122aeca6146c1109abb17000abde782fe6 100644 (file)
@@ -171,4 +171,42 @@ typedef struct _LV2_License_Interface {
    @}
 */
 
+/**
+   @defgroup midnam MIDI Naming
+
+   @{
+*/
+
+
+#define LV2_MIDNAM_URI "http://ardour.org/lv2/midnam"
+#define LV2_MIDNAM_PREFIX LV2_MIDNAM_URI "#"
+#define LV2_MIDNAM__interface LV2_MIDNAM_PREFIX "interface"
+#define LV2_MIDNAM__update LV2_MIDNAM_PREFIX "update"
+
+typedef void* LV2_Midnam_Handle;
+
+/** a LV2 Feature provided by the Host to the plugin */
+typedef struct {
+       /** Opaque host data */
+       LV2_Midnam_Handle handle;
+       /** Request from run() that the host should re-read the midnam */
+       void (*update)(LV2_Midnam_Handle handle);
+} LV2_Midnam;
+
+typedef struct {
+       /** query midnam document. The plugin
+        * is expected to return an allocated
+        * null-terminated XML text, which is
+        * safe for the host to pass to free().
+        *
+        * The midnam <Model> must be unique and
+        * specific for the given plugin-instance.
+        */
+       char* (*midnam)(LV2_Handle instance);
+       char* (*model)(LV2_Handle instance);
+} LV2_Midnam_Interface;
+
+/**
+   @}
+*/
 #endif
index a1e38fda32f6fd5e3024338525826e35a8f3a3c5..202ddbb2401a4cba328c5c42fd618c24016f06f7 100644 (file)
@@ -278,6 +278,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
 
 #ifdef LV2_EXTENDED
        const LV2_Inline_Display_Interface* _display_interface;
+       const LV2_Midnam_Interface* _midname_interface;
 #endif
 
        typedef struct {
@@ -294,6 +295,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
        LV2_Feature    _def_state_feature;
 #ifdef LV2_EXTENDED
        LV2_Feature    _queue_draw_feature;
+       LV2_Feature    _midnam_feature;
 #endif
 
        // Options passed to plugin
@@ -321,6 +323,10 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
 #ifdef LV2_EXTENDED
        bool has_inline_display ();
        Plugin::Display_Image_Surface* render_inline_display (uint32_t, uint32_t);
+
+       bool has_midnam ();
+       bool read_midnam ();
+       std::string midnam_model ();
 #endif
 
        void latency_compute_run ();
index 612091191e54c95558f9a13e56e77cca6084997c..7d35ac7c2ed4a1b92096db8a7f80e3efac70ef39 100644 (file)
@@ -166,6 +166,11 @@ class LIBARDOUR_API Plugin : public PBD::StatefulDestructible, public Latent
        virtual Display_Image_Surface* render_inline_display (uint32_t, uint32_t) { return NULL; }
        PBD::Signal0<void> QueueDraw;
 
+       virtual bool has_midnam () { return false; }
+       virtual bool read_midnam () { return false; }
+       virtual std::string midnam_model () { return ""; }
+       PBD::Signal0<void> UpdateMidnam;
+
        struct PresetRecord {
            PresetRecord () : valid (false) {}
            PresetRecord (const std::string& u, const std::string& l, bool s = true) : uri (u), label (l), user (s), valid (true)  {}
index 91ab6b43a4ec0bac328c4630eff574690aea0cdf..7248dfeaa1d71ed6287beec6508f62a6e90ba958 100644 (file)
@@ -45,6 +45,7 @@
 #include "ardour/audioengine.h"
 #include "ardour/debug.h"
 #include "ardour/lv2_plugin.h"
+#include "ardour/midi_patch_manager.h"
 #include "ardour/session.h"
 #include "ardour/tempo.h"
 #include "ardour/types.h"
@@ -223,6 +224,13 @@ queue_draw (LV2_Inline_Display_Handle handle)
        LV2Plugin* plugin = (LV2Plugin*)handle;
        plugin->QueueDraw(); /* EMIT SIGNAL */
 }
+
+static void
+midnam_update (LV2_Midnam_Handle handle)
+{
+       LV2Plugin* plugin = (LV2Plugin*)handle;
+       plugin->UpdateMidnam (); /* EMIT SIGNAL */
+}
 #endif
 
 /* log extension */
@@ -280,6 +288,7 @@ struct LV2Plugin::Impl {
 #endif
 #ifdef LV2_EXTENDED
               , queue_draw(0)
+              , midnam(0)
 #endif
        {}
 
@@ -307,6 +316,7 @@ struct LV2Plugin::Impl {
 #endif
 #ifdef LV2_EXTENDED
        LV2_Inline_Display*          queue_draw;
+       LV2_Midnam*                  midnam;
 #endif
 };
 
@@ -399,7 +409,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        lilv_node_free(state_uri);
        lilv_node_free(state_iface_uri);
 
-       _features    = (LV2_Feature**)calloc(12, sizeof(LV2_Feature*));
+       _features    = (LV2_Feature**)calloc(13, sizeof(LV2_Feature*));
        _features[0] = &_instance_access_feature;
        _features[1] = &_data_access_feature;
        _features[2] = &_make_path_feature;
@@ -425,6 +435,15 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        _queue_draw_feature.URI  = LV2_INLINEDISPLAY__queue_draw;
        _queue_draw_feature.data = _impl->queue_draw;
        _features[n_features++]  = &_queue_draw_feature;
+
+       _impl->midnam = (LV2_Midnam*)
+               malloc (sizeof(LV2_Midnam));
+       _impl->midnam->handle = this;
+       _impl->midnam->update = midnam_update;
+
+       _midnam_feature.URI  = LV2_MIDNAM__update;
+       _midnam_feature.data = _impl->midnam;
+       _features[n_features++]  = &_midnam_feature;
 #endif
 
 #ifdef HAVE_LV2_1_2_0
@@ -521,6 +540,16 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
 #ifdef LV2_EXTENDED
        _display_interface = (const LV2_Inline_Display_Interface*)
                extension_data (LV2_INLINEDISPLAY__interface);
+
+       _midname_interface = (const LV2_Midnam_Interface*)
+               extension_data (LV2_MIDNAM__interface);
+       if (_midname_interface) {
+               if (read_midnam ()) {
+                       printf ("READ MIDNAM FROM PLUGIN\n");
+               } else {
+                       printf ("**FAILED TO ** READ MIDNAM FROM PLUGIN\n");
+               }
+       }
 #endif
 
        if (lilv_plugin_has_feature(plugin, _world.lv2_inPlaceBroken)) {
@@ -840,6 +869,15 @@ LV2Plugin::~LV2Plugin ()
        deactivate();
        cleanup();
 
+#ifdef LV2_EXTENDED
+       if (has_midnam ()) {
+               std::stringstream ss;
+               ss << (void*)this;
+               ss << unique_id();
+               MIDI::Name::MidiPatchManager::instance().remove_custom_midnam (ss.str());
+       }
+#endif
+
        lilv_instance_free(_impl->instance);
        lilv_state_free(_impl->state);
        lilv_node_free(_impl->name);
@@ -849,6 +887,7 @@ LV2Plugin::~LV2Plugin ()
 #endif
 #ifdef LV2_EXTENDED
        free(_impl->queue_draw);
+       free(_impl->midnam);
 #endif
 
        free(_features);
@@ -930,6 +969,43 @@ LV2Plugin::render_inline_display (uint32_t w, uint32_t h) {
        }
        return NULL;
 }
+
+bool
+LV2Plugin::has_midnam () {
+       return _midname_interface ? true : false;
+}
+
+bool
+LV2Plugin::read_midnam () {
+       bool rv = false;
+       if (!_midname_interface) {
+               return rv;
+       }
+       char* midnam = _midname_interface->midnam ((void*)_impl->instance->lv2_handle);
+       if (midnam) {
+               std::stringstream ss;
+               ss << (void*)this;
+               ss << unique_id();
+               MIDI::Name::MidiPatchManager::instance().remove_custom_midnam (ss.str());
+               rv = MIDI::Name::MidiPatchManager::instance().add_custom_midnam (ss.str(), midnam);
+       }
+       free (midnam);
+       return rv;
+}
+
+std::string
+LV2Plugin::midnam_model () {
+       std::string rv;
+       if (!_midname_interface) {
+               return rv;
+       }
+       char* model = _midname_interface->model ((void*)_impl->instance->lv2_handle);
+       if (model) {
+               rv = model;
+       }
+       free (model);
+       return rv;
+}
 #endif
 
 string