Fix LV2 preset deletion and clash between plugins.
authorDavid Robillard <d@drobilla.net>
Sat, 7 Mar 2015 19:54:03 +0000 (14:54 -0500)
committerDavid Robillard <d@drobilla.net>
Sat, 7 Mar 2015 19:54:03 +0000 (14:54 -0500)
Before this, LV2 preset deletion in Ardour was doubly broken: the wrong file
was being removed, and removing the correct file would only result in a broken
preset.  This change uses a new version of Lilv which has a more sophisticated
mechanism for preset deletion.

Also, fix "clashing" presets saved with the same name for different plugins, by
prefixing the plugin name to the bundle (this is now a recommendation in the
LV2 preset specification).

gtk2_ardour/lv2_plugin_ui.cc
libs/ardour/lv2_plugin.cc
libs/ardour/wscript

index 8e57eeed6094985379f7ae7dd7bd438fcd302632..eb22a74e82ae2c21e2c334bc6842abf47168affb 100644 (file)
@@ -285,7 +285,7 @@ LV2PluginUI::lv2ui_instantiate(const std::string& title)
        const LilvUI*   ui     = (const LilvUI*)_lv2->c_ui();
        const LilvNode* bundle = lilv_ui_get_bundle_uri(ui);
        const LilvNode* binary = lilv_ui_get_binary_uri(ui);
-#ifdef HAVE_LILV_0_21_1
+#ifdef HAVE_LILV_0_21_3
        char* ui_bundle_path = lilv_file_uri_parse(lilv_node_as_uri(bundle), NULL);
        char* ui_binary_path = lilv_file_uri_parse(lilv_node_as_uri(binary), NULL);
 #else
index 7f744be3d6e89c63639ac0c7bcce3be6e98d9eb9..d98f9a9eccf961438d5aa22e002efbe899f24edb 100644 (file)
@@ -1074,11 +1074,13 @@ ARDOUR::lv2plugin_get_port_value(const char* port_symbol,
 std::string
 LV2Plugin::do_save_preset(string name)
 {
+       LilvNode*    plug_name = lilv_plugin_get_name(_impl->plugin);
+       const string prefix    = legalize_for_uri(lilv_node_as_string(plug_name));
        const string base_name = legalize_for_uri(name);
        const string file_name = base_name + ".ttl";
        const string bundle    = Glib::build_filename(
                Glib::get_home_dir(),
-               Glib::build_filename(".lv2", base_name + ".lv2"));
+               Glib::build_filename(".lv2", prefix + "_" + base_name + ".lv2"));
 
        LilvState* state = lilv_state_new_from_instance(
                _impl->plugin,
@@ -1110,7 +1112,7 @@ LV2Plugin::do_save_preset(string name)
        std::string uri = Glib::filename_to_uri(Glib::build_filename(bundle, file_name));
        LilvNode *node_bundle = lilv_new_uri(_world.world, Glib::filename_to_uri(Glib::build_filename(bundle, "/")).c_str());
        LilvNode *node_preset = lilv_new_uri(_world.world, uri.c_str());
-#ifdef HAVE_LILV_0_19_2
+#ifdef HAVE_LILV_0_21_3
        lilv_world_unload_resource(_world.world, node_preset);
        lilv_world_unload_bundle(_world.world, node_bundle);
 #endif
@@ -1118,20 +1120,41 @@ LV2Plugin::do_save_preset(string name)
        lilv_world_load_resource(_world.world, node_preset);
        lilv_node_free(node_bundle);
        lilv_node_free(node_preset);
+       lilv_node_free(plug_name);
        return uri;
 }
 
 void
 LV2Plugin::do_remove_preset(string name)
 {
-       string preset_file = Glib::build_filename(
-               Glib::get_home_dir(),
-               Glib::build_filename(
-                       Glib::build_filename(".lv2", "presets"),
-                       name + ".ttl"
-               )
-       );
-       ::g_unlink(preset_file.c_str());
+#ifdef HAVE_LILV_0_21_3
+       /* Look up preset record by label (FIXME: ick, label as ID) */
+       const PresetRecord* r = preset_by_label(name);
+       if (!r) {
+               return;
+       }
+
+       /* Load a LilvState for the preset. */
+       LilvWorld* world = _world.world;
+       LilvNode*  pset  = lilv_new_uri(world, r->uri.c_str());
+       LilvState* state = lilv_state_new_from_world(world, _uri_map.urid_map(), pset);
+       if (!state) {
+               lilv_node_free(pset);
+               return;
+       }
+
+       /* Delete it from the file system.  This will remove the preset file and the entry
+          from the manifest.  If this results in an empty manifest (i.e. the
+          preset is the only thing in the bundle), then the bundle is removed. */
+       lilv_state_delete(world, state);
+
+       lilv_state_free(state);
+       lilv_node_free(pset);
+#endif
+       /* Without lilv_state_delete(), we could delete the preset file, but this
+          would leave a broken bundle/manifest around, so the preset would still
+          be visible, but broken.  Naively deleting a bundle is too dangerous, so
+          we simply do not support preset deletion with older Lilv */
 }
 
 bool
index 293915cd74d92386cfac39d7b32ea3c1cd6ef413..82aa2085f83cbbbfccb3d7819c17d1d1bc14b8a8 100644 (file)
@@ -277,8 +277,8 @@ def configure(conf):
                           atleast_version='0.16.0', mandatory=False)
         autowaf.check_pkg(conf, 'lilv-0', uselib_store='LILV_0_19_2',
                           atleast_version='0.19.2', mandatory=False)
-        autowaf.check_pkg(conf, 'lilv-0', uselib_store='LILV_0_21_1',
-                          atleast_version='0.21.1', mandatory=False)
+        autowaf.check_pkg(conf, 'lilv-0', uselib_store='LILV_0_21_3',
+                          atleast_version='0.21.3', mandatory=False)
         autowaf.check_pkg(conf, 'suil-0', uselib_store='SUIL',
                           atleast_version='0.6.0', mandatory=False)
         conf.define ('LV2_SUPPORT', 1)