View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0004698 | ardour | bugs | public | 2012-02-08 18:14 | 2015-09-18 15:29 |
| Reporter | colinf | Assigned To | paul | ||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | closed | Resolution | fixed | ||
| Target Version | 3.0 | ||||
| Summary | 0004698: Adding LV2 plugin presets doesn't work. | ||||
| Description | Although clicking the 'Add' button in the top of LV2 plugin windows pops up the dialog to name a new preset, actually adding the preset appears to do nothing: the name doesn't appear in the drop-down preset list. | ||||
| Additional Information | I've tried with various LV2 plugins from Calf, Invada and drobilla's MDala, and this doesn't work for any I've tried, whether they have their own GUIs or use ardour's 'generic' plugin UI. I have pretty recent drobilla and lv2 svn, so maybe there's something not quite right there, but I thought I should report it here anyway in case anyone else sees the same thing. | ||||
| Tags | No tags attached. | ||||
|
|
As far as I can see, this is just not implemented yet, so I suppose it's really a missing feature rather than a bug. |
|
2012-05-22 11:22
|
lv2-save-preset-experimental.patch (4,069 bytes)
Index: libs/ardour/lv2_plugin.cc
===================================================================
--- libs/ardour/lv2_plugin.cc (revision 12363)
+++ libs/ardour/lv2_plugin.cc (working copy)
@@ -841,7 +841,6 @@
bool
LV2Plugin::load_preset(PresetRecord r)
{
- Plugin::load_preset(r);
std::map<std::string,uint32_t>::iterator it;
@@ -868,19 +867,99 @@
lilv_node_free(lv2_symbol);
lilv_node_free(lv2_port);
+ Plugin::load_preset(r);
+
return true;
}
+const void*
+ARDOUR::lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type)
+{
+ cerr << "get_port_value(" << port_symbol << ", ...) ... ";
+ LV2Plugin *plugin = (LV2Plugin *) user_data;
+
+ uint32_t index = plugin->port_index(port_symbol);
+ if (index != (uint32_t) -1) {
+ if (plugin->parameter_is_input(index) && plugin->parameter_is_control(index)) {
+ float *value;
+ *size = sizeof(float);
+ *type = plugin->_uri_map.uri_to_id(
+ NULL, LV2_ATOM__Float);
+ value = &plugin->_shadow_data[index];
+ cerr << "index="<< index << ",*size=" << *size << ",*type=" << *type << ",*value=" << *value << endl;
+
+ return value;
+ }
+ cerr << "port is not input control port! ";
+ }
+
+ cerr << "returning NULL!" << endl;
+ *size = *type = 0;
+ return NULL;
+}
+
+
std::string
-LV2Plugin::do_save_preset(string /*name*/)
+LV2Plugin::do_save_preset(string name)
{
- return "";
+ cerr << "LV2Plugin::do_save_preset(" << name << ")" << endl;
+
+ string pset_uri = uri();
+ pset_uri += "#";
+ pset_uri += name;
+
+ string save_dir = Glib::build_filename(
+ Glib::get_home_dir(),
+ Glib::build_filename(".lv2", "presets")
+ );
+
+ LilvState* state = lilv_state_new_from_instance(
+ _impl->plugin,
+ _impl->instance,
+ _uri_map.urid_map(),
+ scratch_dir().c_str(), // file_dir
+ NULL, // copy_dir
+ NULL, // link_dir
+ save_dir.c_str(), // save_dir
+ lv2plugin_get_port_value, // get_value
+ (void*) this, // user_data
+ LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE, // flags
+ _features // features
+ );
+
+ lilv_state_set_label(state, name.c_str());
+ lilv_state_save(
+ _world.world, // world
+ _uri_map.urid_map(), // map
+ _uri_map.urid_unmap(), // unmap
+ state, // state
+ pset_uri.c_str(), // uri
+ save_dir.c_str(), // dir
+ (name + ".ttl").c_str() // filename
+
+ );
+
+ lilv_state_free(state);
+ return pset_uri;
}
void
-LV2Plugin::do_remove_preset(string /*name*/)
-{}
+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"
+ )
+ );
+ unlink(preset_file.c_str());
+}
+
bool
LV2Plugin::has_editor() const
{
Index: libs/ardour/ardour/lv2_plugin.h
===================================================================
--- libs/ardour/ardour/lv2_plugin.h (revision 12363)
+++ libs/ardour/ardour/lv2_plugin.h (working copy)
@@ -24,6 +24,8 @@
#include <string>
#include <vector>
+#include <lilv/lilv.h>
+
#include "ardour/plugin.h"
#include "ardour/uri_map.h"
#include "ardour/worker.h"
@@ -31,6 +33,12 @@
namespace ARDOUR {
+const void* lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type);
+
+
class AudioEngine;
class Session;
@@ -162,6 +170,11 @@
float* _freewheel_control_port; ///< Special input set by ardour
float* _latency_control_port; ///< Special output set by ardour
PBD::ID _insert_id;
+
+ friend const void* lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type);
typedef enum {
PORT_INPUT = 1,
|
|
|
In the hope of learning a bit more about LV2, I've had a go at implementing this. I've managed to make it seem to more-or-less work, though sadly my understanding of how LV2 works hasn't really improved much in the process: it was mostly trial-and-error even getting to this point. Anyway, work-in-progress patch attached: drobilla will almost certainly be able to spot nineteen things wrong with it straight away, and there are also a few oddities that seem also to happen when saving & loading LADSPA plugin presets. So it's not ready to be applied, but here for safekeeping, in case my computer gets caught in any undesirable weather events or the like. |
|
2012-05-22 17:14
|
plugin-presets-allow-clear.patch (1,685 bytes)
Index: gtk2_ardour/plugin_ui.cc
===================================================================
--- gtk2_ardour/plugin_ui.cc (revision 12381)
+++ gtk2_ardour/plugin_ui.cc (working copy)
@@ -584,6 +584,9 @@
warning << string_compose(_("Plugin preset %1 not found"),
_preset_combo.get_active_text()) << endmsg;
}
+ } else {
+ // blank selected = no preset
+ plugin->clear_preset();
}
}
@@ -736,6 +739,8 @@
preset_labels.push_back (i->label);
}
+ preset_labels.push_back("");
+
set_popdown_strings (_preset_combo, preset_labels);
--_no_load_preset;
@@ -759,6 +764,7 @@
void
PlugUIBase::update_preset_modified ()
{
+
if (plugin->last_preset().uri.empty()) {
_preset_modified.set_text ("");
return;
Index: libs/ardour/ardour/plugin.h
===================================================================
--- libs/ardour/ardour/plugin.h (revision 12381)
+++ libs/ardour/ardour/plugin.h (working copy)
@@ -182,6 +182,7 @@
void remove_preset (std::string);
virtual bool load_preset (PresetRecord);
+ void clear_preset ();
const PresetRecord * preset_by_label (const std::string &);
const PresetRecord * preset_by_uri (const std::string &);
Index: libs/ardour/plugin.cc
===================================================================
--- libs/ardour/plugin.cc (revision 12381)
+++ libs/ardour/plugin.cc (working copy)
@@ -321,6 +321,16 @@
return true;
}
+void
+Plugin::clear_preset ()
+{
+ _last_preset.uri = "";
+ _last_preset.label = "";
+ _parameter_changed_since_last_preset = false;
+
+ PresetLoaded (); /* EMIT SIGNAL */
+}
+
/** @param val `plugin' value */
void
Plugin::set_parameter (uint32_t which, float val)
|
|
2012-05-22 17:14
|
lv2-save-preset.patch (4,571 bytes)
Index: gtk2_ardour/lv2_plugin_ui.cc
===================================================================
--- gtk2_ardour/lv2_plugin_ui.cc (revision 12381)
+++ gtk2_ardour/lv2_plugin_ui.cc (working copy)
@@ -268,6 +268,7 @@
_ardour_buttons_box->pack_end (save_button, false, false);
_ardour_buttons_box->pack_end (add_button, false, false);
_ardour_buttons_box->pack_end (_preset_combo, false, false);
+ _ardour_buttons_box->pack_end (_preset_modified, false, false);
_ardour_buttons_box->show_all();
pack_start(*_ardour_buttons_box, false, false);
Index: libs/ardour/ardour/lv2_plugin.h
===================================================================
--- libs/ardour/ardour/lv2_plugin.h (revision 12381)
+++ libs/ardour/ardour/lv2_plugin.h (working copy)
@@ -31,6 +31,13 @@
namespace ARDOUR {
+// a callback function for lilv_state_new_from_instance(). friend of LV2Plugin
+// so we can pass an LV2Plugin* in user_data and access its private members.
+const void* lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type);
+
class AudioEngine;
class Session;
@@ -163,6 +170,11 @@
float* _latency_control_port; ///< Special output set by ardour
PBD::ID _insert_id;
+ friend const void* lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type);
+
typedef enum {
PORT_INPUT = 1,
PORT_OUTPUT = 1 << 1,
Index: libs/ardour/lv2_plugin.cc
===================================================================
--- libs/ardour/lv2_plugin.cc (revision 12381)
+++ libs/ardour/lv2_plugin.cc (working copy)
@@ -841,7 +841,6 @@
bool
LV2Plugin::load_preset(PresetRecord r)
{
- Plugin::load_preset(r);
std::map<std::string,uint32_t>::iterator it;
@@ -868,19 +867,99 @@
lilv_node_free(lv2_symbol);
lilv_node_free(lv2_port);
+ Plugin::load_preset(r);
+
return true;
}
+const void*
+ARDOUR::lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type)
+{
+ cerr << "get_port_value(" << port_symbol << ", ...) ... ";
+ LV2Plugin *plugin = (LV2Plugin *) user_data;
+
+ uint32_t index = plugin->port_index(port_symbol);
+ if (index != (uint32_t) -1) {
+ if (plugin->parameter_is_input(index) && plugin->parameter_is_control(index)) {
+ float *value;
+ *size = sizeof(float);
+ *type = plugin->_uri_map.uri_to_id(
+ NULL, LV2_ATOM__Float);
+ value = &plugin->_shadow_data[index];
+ cerr << "index="<< index << ",*size=" << *size << ",*type=" << *type << ",*value=" << *value << endl;
+
+ return value;
+ }
+ cerr << "port is not input control port! ";
+ }
+
+ cerr << "returning NULL!" << endl;
+ *size = *type = 0;
+ return NULL;
+}
+
+
std::string
-LV2Plugin::do_save_preset(string /*name*/)
+LV2Plugin::do_save_preset(string name)
{
- return "";
+ cerr << "LV2Plugin::do_save_preset(" << name << ")" << endl;
+
+ string pset_uri = uri();
+ pset_uri += "#";
+ pset_uri += name;
+
+ string save_dir = Glib::build_filename(
+ Glib::get_home_dir(),
+ Glib::build_filename(".lv2", "presets")
+ );
+
+ LilvState* state = lilv_state_new_from_instance(
+ _impl->plugin,
+ _impl->instance,
+ _uri_map.urid_map(),
+ scratch_dir().c_str(), // file_dir
+ NULL, // copy_dir
+ NULL, // link_dir
+ save_dir.c_str(), // save_dir
+ lv2plugin_get_port_value, // get_value
+ (void*) this, // user_data
+ LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE, // flags
+ _features // features
+ );
+
+ lilv_state_set_label(state, name.c_str());
+ lilv_state_save(
+ _world.world, // world
+ _uri_map.urid_map(), // map
+ _uri_map.urid_unmap(), // unmap
+ state, // state
+ pset_uri.c_str(), // uri
+ save_dir.c_str(), // dir
+ (name + ".ttl").c_str() // filename
+
+ );
+
+ lilv_state_free(state);
+ return pset_uri;
}
void
-LV2Plugin::do_remove_preset(string /*name*/)
-{}
+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"
+ )
+ );
+ unlink(preset_file.c_str());
+}
+
bool
LV2Plugin::has_editor() const
{
|
|
|
A small update, and another patch. The update, 'lv2-save-preset.patch', is as before, but enables the display of '*' in the top pane of LV2 plugin windows when the settings have changed from the current preset. The other patch, 'plugin-presets-allow-clear.patch', adds an 'empty' preset to the preset drop-down list, so that plugins can be set back to the 'no preset' state rather than being stuck in the state of 'preset loaded and modified'. This should apply to all plugin types, though I've only tried it on LV2 and LADSPA. |
|
2012-05-28 12:13
|
lv2-save-preset-r12462.patch (4,573 bytes)
Index: libs/ardour/lv2_plugin.cc
===================================================================
--- libs/ardour/lv2_plugin.cc (revision 12462)
+++ libs/ardour/lv2_plugin.cc (working copy)
@@ -835,7 +835,6 @@
bool
LV2Plugin::load_preset(PresetRecord r)
{
- Plugin::load_preset(r);
std::map<std::string,uint32_t>::iterator it;
@@ -862,19 +861,98 @@
lilv_node_free(lv2_symbol);
lilv_node_free(lv2_port);
+ Plugin::load_preset(r);
+
return true;
}
+const void*
+ARDOUR::lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type)
+{
+ // cerr << "get_port_value(" << port_symbol << ", ...) ... ";
+ LV2Plugin *plugin = (LV2Plugin *) user_data;
+
+ uint32_t index = plugin->port_index(port_symbol);
+ if (index != (uint32_t) -1) {
+ if (plugin->parameter_is_input(index) && plugin->parameter_is_control(index)) {
+ float *value;
+ *size = sizeof(float);
+ *type = plugin->_uri_map.uri_to_id(LV2_ATOM__Float);
+ value = &plugin->_shadow_data[index];
+ // cerr << "index="<< index << ",*size=" << *size << ",*type=" << *type << ",*value=" << *value << endl;
+
+ return value;
+ }
+ // cerr << "port is not input control port! ";
+ }
+
+ // cerr << "returning NULL!" << endl;
+ *size = *type = 0;
+ return NULL;
+}
+
+
std::string
-LV2Plugin::do_save_preset(string /*name*/)
+LV2Plugin::do_save_preset(string name)
{
- return "";
+ // cerr << "LV2Plugin::do_save_preset(" << name << ")" << endl;
+
+ string pset_uri = uri();
+ pset_uri += "#";
+ pset_uri += name;
+
+ string save_dir = Glib::build_filename(
+ Glib::get_home_dir(),
+ Glib::build_filename(".lv2", "presets")
+ );
+
+ LilvState* state = lilv_state_new_from_instance(
+ _impl->plugin,
+ _impl->instance,
+ _uri_map.urid_map(),
+ scratch_dir().c_str(), // file_dir
+ NULL, // copy_dir
+ NULL, // link_dir
+ save_dir.c_str(), // save_dir
+ lv2plugin_get_port_value, // get_value
+ (void*) this, // user_data
+ LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE, // flags
+ _features // features
+ );
+
+ lilv_state_set_label(state, name.c_str());
+ lilv_state_save(
+ _world.world, // world
+ _uri_map.urid_map(), // map
+ _uri_map.urid_unmap(), // unmap
+ state, // state
+ pset_uri.c_str(), // uri
+ save_dir.c_str(), // dir
+ (name + ".ttl").c_str() // filename
+
+ );
+
+ lilv_state_free(state);
+ return pset_uri;
}
void
-LV2Plugin::do_remove_preset(string /*name*/)
-{}
+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"
+ )
+ );
+ unlink(preset_file.c_str());
+}
+
bool
LV2Plugin::has_editor() const
{
Index: libs/ardour/ardour/lv2_plugin.h
===================================================================
--- libs/ardour/ardour/lv2_plugin.h (revision 12462)
+++ libs/ardour/ardour/lv2_plugin.h (working copy)
@@ -31,6 +31,13 @@
namespace ARDOUR {
+// a callback function for lilv_state_new_from_instance(). friend of LV2Plugin
+// so we can pass an LV2Plugin* in user_data and access its private members.
+const void* lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type);
+
class AudioEngine;
class Session;
@@ -159,6 +166,11 @@
float* _latency_control_port; ///< Special output set by ardour
PBD::ID _insert_id;
+ friend const void* lv2plugin_get_port_value(const char* port_symbol,
+ void* user_data,
+ uint32_t* size,
+ uint32_t* type);
+
typedef enum {
PORT_INPUT = 1,
PORT_OUTPUT = 1 << 1,
Index: gtk2_ardour/lv2_plugin_ui.cc
===================================================================
--- gtk2_ardour/lv2_plugin_ui.cc (revision 12462)
+++ gtk2_ardour/lv2_plugin_ui.cc (working copy)
@@ -268,6 +268,7 @@
_ardour_buttons_box->pack_end (save_button, false, false);
_ardour_buttons_box->pack_end (add_button, false, false);
_ardour_buttons_box->pack_end (_preset_combo, false, false);
+ _ardour_buttons_box->pack_end (_preset_modified, false, false);
_ardour_buttons_box->show_all();
pack_start(*_ardour_buttons_box, false, false);
|
|
|
Updated patch to fix compilation after changes in r12462, in case anyone's interested. |
|
|
committed at or before 12787. very nice work, thanks as usual. |
|
|
stupid question (?) is this now iplemented? 14088 doesn't save lv2 presets. do i need to manually apply this patch? if so where? how? thansk. |
|
|
when a bug report has a note saying "committed a rev NNNN" it means that the patch or proposed change/fix was added to the source code repository already. it means that if you build Ardour directly from the repository, you will get the fix, and if not, it will show up in the next release. in your case, you appear to be reporting that you believe that the fix does not work. correct? |
|
|
The patch was committed last June, so saving LV2 presets should just work. There is a small issue still, which is that if you save a preset, it sometimes won't show up in the list of presets until you quit and restart Ardour 3. I should probably make a separate bug report about that. |
|
|
@paul yes: built 14088 with ./waf configure --lv2 --lxvst, ./waf, ./waf install (root) open ardour, new session, add tracks, open calf comp (also tried invada comp), then: change parameters, add preset, change params again. add new preset, go back to 1st preset and there appears to be no change. close/reopen plugin -same. @colinf: close/reopen A3 - presets gone. also tried: change plugin params, add preset, save preset - same. |
|
|
14104: saved lv2 presets are there after close/reopen A3. awesome. |
|
|
nothing was done to change this. |
|
|
thanks. have to figure out what I did different. |
|
|
Closing old issues reported by me: these have long since been fixed. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2012-02-08 18:14 | colinf | New Issue | |
| 2012-02-09 20:19 | cth103 | cost | => 0.00 |
| 2012-02-09 20:19 | cth103 | Target Version | => 3.0-beta3 |
| 2012-02-14 15:28 | colinf | Note Added: 0012797 | |
| 2012-02-14 17:20 | paul | Target Version | 3.0-beta3 => 3.0 beta4 |
| 2012-05-22 11:22 | colinf | File Added: lv2-save-preset-experimental.patch | |
| 2012-05-22 11:44 | colinf | Note Added: 0013274 | |
| 2012-05-22 17:14 | colinf | File Added: plugin-presets-allow-clear.patch | |
| 2012-05-22 17:14 | colinf | File Added: lv2-save-preset.patch | |
| 2012-05-22 17:22 | colinf | Note Added: 0013275 | |
| 2012-05-23 15:07 | cth103 | Target Version | 3.0 beta4 => 3.0 |
| 2012-05-28 12:13 | colinf | File Added: lv2-save-preset-r12462.patch | |
| 2012-05-28 12:14 | colinf | Note Added: 0013314 | |
| 2012-05-28 12:14 | colinf | Note Edited: 0013314 | |
| 2012-06-19 16:02 | paul | Note Added: 0013609 | |
| 2012-06-19 16:02 | paul | Status | new => resolved |
| 2012-06-19 16:02 | paul | Resolution | open => fixed |
| 2012-06-19 16:02 | paul | Assigned To | => paul |
| 2013-02-25 17:33 | tweed | Note Added: 0014660 | |
| 2013-02-25 17:51 | paul | Note Added: 0014661 | |
| 2013-02-25 18:02 | colinf | Note Added: 0014662 | |
| 2013-02-25 20:12 | tweed | Note Added: 0014663 | |
| 2013-02-26 20:27 | tweed | Note Added: 0014664 | |
| 2013-02-26 21:08 | paul | Note Added: 0014665 | |
| 2013-02-26 22:21 | tweed | Note Added: 0014666 | |
| 2015-09-18 15:29 | colinf | Note Added: 0017318 | |
| 2015-09-18 15:29 | colinf | Status | resolved => closed |