Fix LV2 state:StateChanged URI
[ardour.git] / libs / ardour / lv2_plugin.cc
index e45270ebcb6326e6baabb87883c494b35b151893..a7f8bfb20965f4e4a4c00bd8bba138040439edf8 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"
@@ -109,6 +110,8 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
+bool LV2Plugin::force_state_save = false;
+
 class LV2World : boost::noncopyable {
 public:
        LV2World ();
@@ -166,6 +169,7 @@ public:
        LilvNode* bufz_powerOf2BlockLength;
        LilvNode* bufz_fixedBlockLength;
        LilvNode* bufz_nominalBlockLength;
+       LilvNode* bufz_coarseBlockLength;
 #endif
 
 #ifdef HAVE_LV2_1_10_0
@@ -220,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 */
@@ -277,6 +288,7 @@ struct LV2Plugin::Impl {
 #endif
 #ifdef LV2_EXTENDED
               , queue_draw(0)
+              , midnam(0)
 #endif
        {}
 
@@ -304,6 +316,7 @@ struct LV2Plugin::Impl {
 #endif
 #ifdef LV2_EXTENDED
        LV2_Inline_Display*          queue_draw;
+       LV2_Midnam*                  midnam;
 #endif
 };
 
@@ -396,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;
@@ -422,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
@@ -518,6 +540,12 @@ 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) {
+               read_midnam ();
+       }
 #endif
 
        if (lilv_plugin_has_feature(plugin, _world.lv2_inPlaceBroken)) {
@@ -545,9 +573,15 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        lilv_nodes_free(required_features);
 #endif
 
-#ifdef LV2_EXTENDED
        LilvNodes* optional_features = lilv_plugin_get_optional_features (plugin);
+#ifdef HAVE_LV2_1_2_0
+       if (lilv_nodes_contains (optional_features, _world.bufz_coarseBlockLength)) {
+               _no_sample_accurate_ctrl = true;
+       }
+#endif
+#ifdef LV2_EXTENDED
        if (lilv_nodes_contains (optional_features, _world.lv2_noSampleAccurateCtrl)) {
+               /* deprecated 2016-Sep-18 in favor of bufz_coarseBlockLength */
                _no_sample_accurate_ctrl = true;
        }
        if (lilv_nodes_contains (optional_features, _world.auto_can_write_automatation)) {
@@ -831,6 +865,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);
@@ -840,6 +883,7 @@ LV2Plugin::~LV2Plugin ()
 #endif
 #ifdef LV2_EXTENDED
        free(_impl->queue_draw);
+       free(_impl->midnam);
 #endif
 
        free(_features);
@@ -921,6 +965,49 @@ 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();
+               rv = MIDI::Name::MidiPatchManager::instance().update_custom_midnam (ss.str(), midnam);
+       }
+#ifndef NDEBUG
+       if (rv) {
+               info << string_compose(_("LV2: update midnam for plugin '%1'"), name ()) << endmsg;
+       } else {
+               warning << string_compose(_("LV2: Failed to parse midnam of plugin '%1'"), name ()) << endmsg;
+       }
+#endif
+       _midname_interface->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;
+       }
+       _midname_interface->free (model);
+       return rv;
+}
 #endif
 
 string
@@ -1241,7 +1328,7 @@ LV2Plugin::add_state(XMLNode* root) const
                        0,
                        NULL);
 
-               if (!_plugin_state_dir.empty()
+               if (!_plugin_state_dir.empty() || force_state_save
                    || !_impl->state
                    || !lilv_state_equals(state, _impl->state)) {
                        lilv_state_save(_world.world,
@@ -1252,13 +1339,19 @@ LV2Plugin::add_state(XMLNode* root) const
                                        new_dir.c_str(),
                                        "state.ttl");
 
-                       if (_plugin_state_dir.empty()) {
+                       if (force_state_save) {
+                               // archive or save-as
+                               lilv_state_free(state);
+                               --_state_version;
+                       }
+                       else if (_plugin_state_dir.empty()) {
                                // normal session save
                                lilv_state_free(_impl->state);
                                _impl->state = state;
                        } else {
                                // template save (dedicated state-dir)
                                lilv_state_free(state);
+                               --_state_version;
                        }
                } else {
                        // State is identical, decrement version and nuke directory
@@ -2678,6 +2771,17 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                        }
                                }
 #endif
+                               // Intercept state dirty message
+                               if (_has_state_interface /* && (flags & PORT_DIRTYMSG)*/) {
+                                       LV2_Atom* atom = (LV2_Atom*)(data - sizeof(LV2_Atom));
+                                       if (atom->type == _uri_map.urids.atom_Blank ||
+                                           atom->type == _uri_map.urids.atom_Object) {
+                                               LV2_Atom_Object* obj = (LV2_Atom_Object*)atom;
+                                               if (obj->body.otype == _uri_map.urids.state_StateChanged) {
+                                                       _session.set_dirty ();
+                                               }
+                                       }
+                               }
 
                                // Intercept patch change messages to emit PropertyChanged signal
                                if ((flags & PORT_PATCHMSG)) {
@@ -2784,9 +2888,17 @@ LV2Plugin::parameter_is_input(uint32_t param) const
 uint32_t
 LV2Plugin::designated_bypass_port ()
 {
-#ifdef LV2_EXTENDED
        const LilvPort* port = NULL;
-       LilvNode* designation = lilv_new_uri (_world.world, LV2_PROCESSING_URI__enable);
+       LilvNode* designation = lilv_new_uri (_world.world, LV2_CORE_PREFIX "enabled");
+       port = lilv_plugin_get_port_by_designation (
+                       _impl->plugin, _world.lv2_InputPort, designation);
+       lilv_node_free(designation);
+       if (port) {
+               return lilv_port_get_index (_impl->plugin, port);
+       }
+#ifdef LV2_EXTENDED
+       /* deprecated on 2016-Sep-18 in favor of lv2:enabled */
+       designation = lilv_new_uri (_world.world, LV2_PROCESSING_URI__enable);
        port = lilv_plugin_get_port_by_designation (
                        _impl->plugin, _world.lv2_InputPort, designation);
        lilv_node_free(designation);
@@ -2988,7 +3100,7 @@ LV2World::LV2World()
        patch_writable     = lilv_new_uri(world, LV2_PATCH__writable);
        patch_Message      = lilv_new_uri(world, LV2_PATCH__Message);
 #ifdef LV2_EXTENDED
-       lv2_noSampleAccurateCtrl    = lilv_new_uri(world, "http://ardour.org/lv2/ext#noSampleAccurateControls");
+       lv2_noSampleAccurateCtrl    = lilv_new_uri(world, "http://ardour.org/lv2/ext#noSampleAccurateControls"); // deprecated 2016-09-18
        auto_can_write_automatation = lilv_new_uri(world, LV2_AUTOMATE_URI__can_write);
        auto_automation_control     = lilv_new_uri(world, LV2_AUTOMATE_URI__control);
        auto_automation_controlled  = lilv_new_uri(world, LV2_AUTOMATE_URI__controlled);
@@ -2998,6 +3110,7 @@ LV2World::LV2World()
        bufz_powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
        bufz_fixedBlockLength    = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
        bufz_nominalBlockLength  = lilv_new_uri(world, "http://lv2plug.in/ns/ext/buf-size#nominalBlockLength");
+       bufz_coarseBlockLength   = lilv_new_uri(world, "http://lv2plug.in/ns/ext/buf-size#coarseBlockLength");
 #endif
 
 }
@@ -3008,6 +3121,7 @@ LV2World::~LV2World()
                return;
        }
 #ifdef HAVE_LV2_1_2_0
+       lilv_node_free(bufz_coarseBlockLength);
        lilv_node_free(bufz_nominalBlockLength);
        lilv_node_free(bufz_fixedBlockLength);
        lilv_node_free(bufz_powerOf2BlockLength);