summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/plugin_ui.h2
-rw-r--r--gtk2_ardour/vst_pluginui.cc58
-rw-r--r--libs/ardour/ardour/ladspa_plugin.h10
-rw-r--r--libs/ardour/ardour/lv2_plugin.h2
-rw-r--r--libs/ardour/ardour/plugin.h42
-rw-r--r--libs/ardour/ardour/vst_plugin.h16
-rw-r--r--libs/ardour/ladspa_plugin.cc206
-rw-r--r--libs/ardour/lv2_plugin.cc10
-rw-r--r--libs/ardour/plugin.cc252
-rw-r--r--libs/ardour/vst_plugin.cc228
-rw-r--r--libs/fst/fst.h3
-rw-r--r--libs/fst/fstinfofile.c2
-rw-r--r--libs/fst/vstwin.c7
13 files changed, 522 insertions, 316 deletions
diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h
index edc7c609aa..0caed4ac95 100644
--- a/gtk2_ardour/plugin_ui.h
+++ b/gtk2_ardour/plugin_ui.h
@@ -324,8 +324,8 @@ class VSTPluginUI : public PlugUIBase, public Gtk::VBox
bool configure_handler (GdkEventConfigure*, Gtk::Socket*);
void save_plugin_setting ();
- void create_preset_store ();
void preset_chosen ();
+ void update_presets ();
};
#endif // VST_SUPPORT
diff --git a/gtk2_ardour/vst_pluginui.cc b/gtk2_ardour/vst_pluginui.cc
index 6c1b359fd4..72c73f7467 100644
--- a/gtk2_ardour/vst_pluginui.cc
+++ b/gtk2_ardour/vst_pluginui.cc
@@ -35,7 +35,14 @@ VSTPluginUI::VSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<
: PlugUIBase (pi),
vst (vp)
{
- create_preset_store ();
+ preset_model = ListStore::create (preset_columns);
+
+ CellRenderer* renderer = manage (new CellRendererText());
+ vst_preset_combo.pack_start (*renderer, true);
+ vst_preset_combo.add_attribute (*renderer, "text", 0);
+ vst_preset_combo.set_model (preset_model);
+
+ update_presets ();
fst_run_editor (vst->fst());
@@ -63,8 +70,19 @@ VSTPluginUI::~VSTPluginUI ()
void
VSTPluginUI::preset_chosen ()
{
- // we can't dispatch directly here, too many plugins only expects one GUI thread.
- vst->fst()->want_program = vst_preset_combo.get_active_row_number ();
+ int const r = vst_preset_combo.get_active_row_number ();
+
+ if (r < vst->first_user_preset_index()) {
+ /* This is a plugin-provided preset.
+ We can't dispatch directly here; too many plugins expects only one GUI thread.
+ */
+ vst->fst()->want_program = r;
+ } else {
+ /* This is a user preset. This method knows about the direct dispatch restriction, too */
+ TreeModel::iterator i = vst_preset_combo.get_active ();
+ plugin->load_preset ((*i)[preset_columns.name]);
+ }
+
socket.grab_focus ();
}
@@ -138,37 +156,23 @@ VSTPluginUI::configure_handler (GdkEventConfigure* ev, Gtk::Socket *socket)
}
void
-VSTPluginUI::create_preset_store ()
+VSTPluginUI::update_presets ()
{
- FST *fst = vst->fst();
- int vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
+ std::vector<Plugin::PresetRecord> presets = plugin->get_presets ();
- preset_model = ListStore::create (preset_columns);
-
- for (int i = 0; i < fst->plugin->numPrograms; ++i) {
- char buf[100];
- TreeModel::Row row = *(preset_model->append());
-
- snprintf (buf, 90, "preset %d", i);
+ preset_model->clear ();
- if (vst_version >= 2) {
- fst->plugin->dispatcher (fst->plugin, 29, i, 0, buf, 0.0);
- }
-
- row[preset_columns.name] = buf;
- row[preset_columns.number] = i;
+ int j = 0;
+ for (std::vector<Plugin::PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
+ TreeModel::Row row = *(preset_model->append ());
+ row[preset_columns.name] = i->label;
+ row[preset_columns.number] = j++;
}
- if (fst->plugin->numPrograms > 0) {
- fst->plugin->dispatcher( fst->plugin, effSetProgram, 0, 0, NULL, 0.0 );
+ if (presets.size() > 0) {
+ vst->fst()->plugin->dispatcher (vst->fst()->plugin, effSetProgram, 0, 0, NULL, 0);
}
- vst_preset_combo.set_model (preset_model);
-
- CellRenderer* renderer = manage (new CellRendererText());
- vst_preset_combo.pack_start (*renderer, true);
- vst_preset_combo.add_attribute (*renderer, "text", 0);
-
if (vst->fst()->current_program != -1) {
vst_preset_combo.set_active (vst->fst()->current_program);
} else {
diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h
index 4358de792e..7d561dd0a8 100644
--- a/libs/ardour/ardour/ladspa_plugin.h
+++ b/libs/ardour/ardour/ladspa_plugin.h
@@ -99,8 +99,9 @@ class LadspaPlugin : public ARDOUR::Plugin
XMLNode& get_state();
int set_state (const XMLNode&, int version);
- bool save_preset (std::string name);
- void remove_preset (std::string name);
+
+ std::vector<PresetRecord> get_presets ();
+ bool load_preset (const std::string& uri);
bool has_editor() const { return false; }
@@ -134,6 +135,11 @@ class LadspaPlugin : public ARDOUR::Plugin
void run_in_place (pframes_t nsamples);
void latency_compute_run ();
int set_state_2X (const XMLNode&, int version);
+ std::string do_save_preset (std::string name);
+ void do_remove_preset (std::string name);
+ std::string preset_envvar () const;
+ std::string preset_source (std::string) const;
+ bool write_preset_file (std::string);
};
class LadspaPluginInfo : public PluginInfo {
diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h
index bdaf1a153b..daf3cff4f7 100644
--- a/libs/ardour/ardour/lv2_plugin.h
+++ b/libs/ardour/ardour/lv2_plugin.h
@@ -153,6 +153,8 @@ class LV2Plugin : public ARDOUR::Plugin
void init (LV2World& world, SLV2Plugin plugin, framecnt_t rate);
void run (pframes_t nsamples);
void latency_compute_run ();
+ std::string do_save_preset (std::string);
+ void do_remove_preset (std::string);
};
diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h
index 170fb03e6c..828e532c6a 100644
--- a/libs/ardour/ardour/plugin.h
+++ b/libs/ardour/ardour/plugin.h
@@ -128,28 +128,32 @@ class Plugin : public PBD::StatefulDestructible, public Latent
virtual bool parameter_is_input(uint32_t) const = 0;
virtual bool parameter_is_output(uint32_t) const = 0;
- virtual bool save_preset (std::string) = 0;
- virtual void remove_preset (std::string) = 0;
- virtual bool load_preset (const std::string& uri);
+ bool save_preset (std::string);
+ void remove_preset (std::string);
+ virtual bool load_preset (const std::string& uri) = 0;
struct PresetRecord {
- PresetRecord(const std::string& u, const std::string& l) : uri(u), label(l) {}
+ PresetRecord (const std::string& u, const std::string& l) : uri(u), label(l) {}
std::string uri;
std::string label;
};
- virtual std::vector<PresetRecord> get_presets();
- virtual std::string current_preset() const { return std::string(); }
+ const PresetRecord * preset_by_label (const std::string &);
+ const PresetRecord * preset_by_uri (const std::string &);
- static PBD::Signal0<bool> PresetFileExists;
+ /** Return this plugin's presets; should add them to _presets */
+ virtual std::vector<PresetRecord> get_presets () = 0;
+ virtual std::string current_preset () const { return std::string(); }
- const PresetRecord* preset_by_label(const std::string& label);
- const PresetRecord* preset_by_uri(const std::string& uri);
+ /** Emitted when a preset is added or removed, respectively */
+ PBD::Signal0<void> PresetAdded;
+ PBD::Signal0<void> PresetRemoved;
+
+ /* XXX: no-one listens to this */
+ static PBD::Signal0<bool> PresetFileExists;
virtual bool has_editor() const = 0;
- PBD::Signal0<void> PresetAdded;
- PBD::Signal0<void> PresetRemoved;
PBD::Signal2<void,uint32_t,float> ParameterChanged;
/* NOTE: this block of virtual methods looks like the interface
@@ -183,23 +187,25 @@ class Plugin : public PBD::StatefulDestructible, public Latent
void set_cycles (uint32_t c) { _cycles = c; }
cycles_t cycles() const { return _cycles; }
- protected:
+protected:
+
friend class PluginInsert;
friend struct PluginInsert::PluginControl;
virtual void set_parameter (uint32_t which, float val) = 0;
- bool save_preset (std::string, std::string /* vst, ladspa etc. */);
- void remove_preset (std::string, std::string);
- bool write_preset_file (std::string, std::string);
- std::string preset_source (std::string, std::string) const;
- std::string preset_envvar () const;
+ /** Do the actual saving of the current plugin settings to a preset of the provided name.
+ * Should return a URI on success, or an empty string on failure.
+ */
+ virtual std::string do_save_preset (std::string) = 0;
+ /** Do the actual removal of a preset of the provided name */
+ virtual void do_remove_preset (std::string) = 0;
ARDOUR::AudioEngine& _engine;
ARDOUR::Session& _session;
PluginInfoPtr _info;
uint32_t _cycles;
- std::map<std::string,PresetRecord> presets;
+ std::map<std::string, PresetRecord> _presets;
};
PluginPtr find_plugin(ARDOUR::Session&, std::string unique_id, ARDOUR::PluginType);
diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h
index a72b625288..332872e9bd 100644
--- a/libs/ardour/ardour/vst_plugin.h
+++ b/libs/ardour/ardour/vst_plugin.h
@@ -80,19 +80,25 @@ class VSTPlugin : public ARDOUR::Plugin
bool parameter_is_output(uint32_t i) const { return false; }
bool load_preset (const std::string& preset_label);
- bool save_preset (std::string name);
- void remove_preset (std::string name);
+ virtual std::vector<PresetRecord> get_presets ();
+ int first_user_preset_index () const;
bool has_editor () const;
XMLNode& get_state();
int set_state (XMLNode const &, int);
- AEffect* plugin() const { return _plugin; }
- FST* fst() const { return _fst; }
+ AEffect * plugin () const { return _plugin; }
+ FST * fst () const { return _fst; }
+private:
- private:
+ void do_remove_preset (std::string name);
+ std::string do_save_preset (std::string name);
+ gchar* get_chunk (bool);
+ int set_chunk (gchar const *, bool);
+ XMLTree * presets_tree () const;
+
FSTHandle* handle;
FST* _fst;
AEffect* _plugin;
diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc
index 00454cea5e..54722488f6 100644
--- a/libs/ardour/ladspa_plugin.cc
+++ b/libs/ardour/ladspa_plugin.cc
@@ -366,18 +366,6 @@ LadspaPlugin::get_state()
return *root;
}
-bool
-LadspaPlugin::save_preset (string name)
-{
- return Plugin::save_preset (name, "ladspa");
-}
-
-void
-LadspaPlugin::remove_preset (string name)
-{
- return Plugin::remove_preset (name, "ladspa");
-}
-
int
LadspaPlugin::set_state (const XMLNode& node, int version)
{
@@ -717,3 +705,197 @@ LadspaPluginInfo::LadspaPluginInfo()
{
type = ARDOUR::LADSPA;
}
+
+
+vector<Plugin::PresetRecord>
+LadspaPlugin::get_presets ()
+{
+ vector<PresetRecord> result;
+ uint32_t id;
+ std::string unique (unique_id());
+
+ if (!isdigit (unique[0])) {
+ return result;
+ }
+
+ id = atol (unique.c_str());
+
+ lrdf_uris* set_uris = lrdf_get_setting_uris(id);
+
+ if (set_uris) {
+ for (uint32_t i = 0; i < (uint32_t) set_uris->count; ++i) {
+ if (char* label = lrdf_get_label(set_uris->items[i])) {
+ PresetRecord rec(set_uris->items[i], label);
+ result.push_back(rec);
+ _presets.insert (make_pair (set_uris->items[i], rec));
+ }
+ }
+ lrdf_free_uris(set_uris);
+ }
+
+ return result;
+}
+
+
+bool
+LadspaPlugin::load_preset (const string& preset_uri)
+{
+ lrdf_defaults* defs = lrdf_get_setting_values(preset_uri.c_str());
+
+ if (defs) {
+ for (uint32_t i = 0; i < (uint32_t) defs->count; ++i) {
+ // The defs->items[i].pid < defs->count check is to work around
+ // a bug in liblrdf that saves invalid values into the presets file.
+ if (((uint32_t) defs->items[i].pid < (uint32_t) defs->count) && parameter_is_input (defs->items[i].pid)) {
+ set_parameter(defs->items[i].pid, defs->items[i].value);
+ }
+ }
+ lrdf_free_setting_values(defs);
+ }
+
+ return true;
+}
+
+/* XXX: should be in liblrdf */
+static void
+lrdf_remove_preset (const char *source, const char *setting_uri)
+{
+ lrdf_statement p;
+ lrdf_statement *q;
+ lrdf_statement *i;
+ char setting_uri_copy[64];
+ char buf[64];
+
+ strncpy(setting_uri_copy, setting_uri, sizeof(setting_uri_copy));
+
+ p.subject = setting_uri_copy;
+ strncpy(buf, LADSPA_BASE "hasPortValue", sizeof(buf));
+ p.predicate = buf;
+ p.object = NULL;
+ q = lrdf_matches(&p);
+
+ p.predicate = NULL;
+ p.object = NULL;
+ for (i = q; i; i = i->next) {
+ p.subject = i->object;
+ lrdf_remove_matches(&p);
+ }
+
+ lrdf_free_statements(q);
+
+ p.subject = NULL;
+ strncpy(buf, LADSPA_BASE "hasSetting", sizeof(buf));
+ p.predicate = buf;
+ p.object = setting_uri_copy;
+ lrdf_remove_matches(&p);
+
+ p.subject = setting_uri_copy;
+ p.predicate = NULL;
+ p.object = NULL;
+ lrdf_remove_matches (&p);
+}
+
+void
+LadspaPlugin::do_remove_preset (string name)
+{
+ string const envvar = preset_envvar ();
+ if (envvar.empty()) {
+ warning << _("Could not locate HOME. Preset not removed.") << endmsg;
+ return;
+ }
+
+ Plugin::PresetRecord const * p = preset_by_label (name);
+ if (!p) {
+ return;
+ }
+
+ string const source = preset_source (envvar);
+ lrdf_remove_preset (source.c_str(), p->uri.c_str ());
+
+ write_preset_file (envvar);
+}
+
+string
+LadspaPlugin::preset_envvar () const
+{
+ char* envvar;
+ if ((envvar = getenv ("HOME")) == 0) {
+ return "";
+ }
+
+ return envvar;
+}
+
+string
+LadspaPlugin::preset_source (string envvar) const
+{
+ return string_compose ("file:%1/.ladspa/rdf/ardour-presets.n3", envvar);
+}
+
+bool
+LadspaPlugin::write_preset_file (string envvar)
+{
+ string path = string_compose("%1/.ladspa", envvar);
+ if (g_mkdir_with_parents (path.c_str(), 0775)) {
+ warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
+ return false;
+ }
+
+ path += "/rdf";
+ if (g_mkdir_with_parents (path.c_str(), 0775)) {
+ warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
+ return false;
+ }
+
+ string const source = preset_source (envvar);
+
+ if (lrdf_export_by_source (source.c_str(), source.substr(5).c_str())) {
+ warning << string_compose(_("Error saving presets file %1."), source) << endmsg;
+ return false;
+ }
+
+ return true;
+}
+
+string
+LadspaPlugin::do_save_preset (string name)
+{
+ lrdf_portvalue portvalues[parameter_count()];
+ lrdf_defaults defaults;
+ std::string unique (unique_id());
+
+ if (!isdigit (unique[0])) {
+ return false;
+ }
+
+ uint32_t const id = atol (unique.c_str());
+
+ defaults.count = parameter_count();
+ defaults.items = portvalues;
+
+ for (uint32_t i = 0; i < parameter_count(); ++i) {
+ if (parameter_is_input (i)) {
+ portvalues[i].pid = i;
+ portvalues[i].value = get_parameter(i);
+ }
+ }
+
+ string const envvar = preset_envvar ();
+ if (envvar.empty()) {
+ warning << _("Could not locate HOME. Preset not saved.") << endmsg;
+ return false;
+ }
+
+ string const source = preset_source (envvar);
+
+ char* uri_char = lrdf_add_preset (source.c_str(), name.c_str(), id, &defaults);
+ string uri (uri_char);
+ free (uri_char);
+
+ if (!write_preset_file (envvar)) {
+ return "";
+ }
+
+ return uri;
+}
+
diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc
index 082c2f1ba3..35cd9f4d1a 100644
--- a/libs/ardour/lv2_plugin.cc
+++ b/libs/ardour/lv2_plugin.cc
@@ -353,7 +353,7 @@ LV2Plugin::get_presets()
SLV2Value name = slv2_results_get_binding_value(presets, 1);
PresetRecord rec(slv2_value_as_string(uri), slv2_value_as_string(name));
result.push_back(rec);
- this->presets.insert(std::make_pair(slv2_value_as_string(uri), rec));
+ _presets.insert(std::make_pair(slv2_value_as_string(uri), rec));
}
slv2_results_free(presets);
return result;
@@ -380,14 +380,14 @@ LV2Plugin::load_preset(const string& uri)
return true;
}
-bool
-LV2Plugin::save_preset (string /*name*/)
+std::string
+LV2Plugin::do_save_preset (string /*name*/)
{
- return false;
+ return "";
}
void
-LV2Plugin::remove_preset (string /*name*/)
+LV2Plugin::do_remove_preset (string /*name*/)
{
return;
}
diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc
index 3bfb9e883f..98bc5f35ad 100644
--- a/libs/ardour/plugin.cc
+++ b/libs/ardour/plugin.cc
@@ -78,244 +78,34 @@ Plugin::Plugin (const Plugin& other)
, _session (other._session)
, _info (other._info)
, _cycles (0)
- , presets (other.presets)
{
+
}
Plugin::~Plugin ()
{
-}
-
-const Plugin::PresetRecord*
-Plugin::preset_by_label(const string& label)
-{
- // FIXME: O(n)
- for (map<string,PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
- if (i->second.label == label) {
- return &i->second;
- }
- }
- return NULL;
-}
-
-const Plugin::PresetRecord*
-Plugin::preset_by_uri(const string& uri)
-{
- map<string,PresetRecord>::const_iterator pr = presets.find(uri);
- if (pr != presets.end()) {
- return &pr->second;
- } else {
- return NULL;
- }
-}
-
-vector<Plugin::PresetRecord>
-Plugin::get_presets()
-{
- vector<PresetRecord> result;
- uint32_t id;
- std::string unique (unique_id());
-
- /* XXX problem: AU plugins don't have numeric ID's.
- Solution: they have a different method of providing presets.
- XXX sub-problem: implement it.
- */
-
- if (!isdigit (unique[0])) {
- return result;
- }
-
- id = atol (unique.c_str());
-
- lrdf_uris* set_uris = lrdf_get_setting_uris(id);
-
- if (set_uris) {
- for (uint32_t i = 0; i < (uint32_t) set_uris->count; ++i) {
- if (char* label = lrdf_get_label(set_uris->items[i])) {
- PresetRecord rec(set_uris->items[i], label);
- result.push_back(rec);
- presets.insert(std::make_pair(set_uris->items[i], rec));
- }
- }
- lrdf_free_uris(set_uris);
- }
-
- return result;
-}
-
-bool
-Plugin::load_preset(const string& preset_uri)
-{
- lrdf_defaults* defs = lrdf_get_setting_values(preset_uri.c_str());
-
- if (defs) {
- for (uint32_t i = 0; i < (uint32_t) defs->count; ++i) {
- // The defs->items[i].pid < defs->count check is to work around
- // a bug in liblrdf that saves invalid values into the presets file.
- if (((uint32_t) defs->items[i].pid < (uint32_t) defs->count) && parameter_is_input (defs->items[i].pid)) {
- set_parameter(defs->items[i].pid, defs->items[i].value);
- }
- }
- lrdf_free_setting_values(defs);
- }
-
- return true;
-}
-
-/* XXX: should be in liblrdf */
-static void
-lrdf_remove_preset (const char *source, const char *setting_uri)
-{
- lrdf_statement p;
- lrdf_statement *q;
- lrdf_statement *i;
- char setting_uri_copy[64];
- char buf[64];
- strncpy(setting_uri_copy, setting_uri, sizeof(setting_uri_copy));
-
- p.subject = setting_uri_copy;
- strncpy(buf, LADSPA_BASE "hasPortValue", sizeof(buf));
- p.predicate = buf;
- p.object = NULL;
- q = lrdf_matches(&p);
-
- p.predicate = NULL;
- p.object = NULL;
- for (i = q; i; i = i->next) {
- p.subject = i->object;
- lrdf_remove_matches(&p);
- }
-
- lrdf_free_statements(q);
-
- p.subject = NULL;
- strncpy(buf, LADSPA_BASE "hasSetting", sizeof(buf));
- p.predicate = buf;
- p.object = setting_uri_copy;
- lrdf_remove_matches(&p);
-
- p.subject = setting_uri_copy;
- p.predicate = NULL;
- p.object = NULL;
- lrdf_remove_matches (&p);
}
void
-Plugin::remove_preset (string name, string domain)
+Plugin::remove_preset (string name)
{
- string const envvar = preset_envvar ();
- if (envvar.empty()) {
- warning << _("Could not locate HOME. Preset not removed.") << endmsg;
- return;
- }
-
- Plugin::PresetRecord const * p = preset_by_label (name);
- if (!p) {
- return;
- }
-
- string const source = preset_source (envvar, domain);
- lrdf_remove_preset (source.c_str(), p->uri.c_str ());
-
- presets.erase (p->uri);
-
- write_preset_file (envvar, domain);
-
+ do_remove_preset (name);
+ _presets.erase (preset_by_label (name)->uri);
PresetRemoved (); /* EMIT SIGNAL */
}
-string
-Plugin::preset_envvar () const
-{
- char* envvar;
- if ((envvar = getenv ("HOME")) == 0) {
- return "";
- }
-
- return envvar;
-}
-
-string
-Plugin::preset_source (string envvar, string domain) const
-{
- return string_compose ("file:%1/.%2/rdf/ardour-presets.n3", envvar, domain);
-}
-
-bool
-Plugin::write_preset_file (string envvar, string domain)
-{
- string path = string_compose("%1/.%2", envvar, domain);
- if (g_mkdir_with_parents (path.c_str(), 0775)) {
- warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
- return false;
- }
-
- path += "/rdf";
- if (g_mkdir_with_parents (path.c_str(), 0775)) {
- warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
- return false;
- }
-
- string const source = preset_source (envvar, domain);
-
- if (lrdf_export_by_source (source.c_str(), source.substr(5).c_str())) {
- warning << string_compose(_("Error saving presets file %1."), source) << endmsg;
- return false;
- }
-
- return true;
-}
-
bool
-Plugin::save_preset (string name, string domain)
+Plugin::save_preset (string name)
{
- lrdf_portvalue portvalues[parameter_count()];
- lrdf_defaults defaults;
- uint32_t id;
- std::string unique (unique_id());
-
- /* XXX problem: AU plugins don't have numeric ID's.
- Solution: they have a different method of providing/saving presets.
- XXX sub-problem: implement it.
- */
+ string const uri = do_save_preset (name);
- if (!isdigit (unique[0])) {
- return false;
+ if (!uri.empty()) {
+ _presets.insert (make_pair (uri, PresetRecord (uri, name)));
+ PresetAdded (); /* EMIT SIGNAL */
}
-
- id = atol (unique.c_str());
-
- defaults.count = parameter_count();
- defaults.items = portvalues;
-
- for (uint32_t i = 0; i < parameter_count(); ++i) {
- if (parameter_is_input (i)) {
- portvalues[i].pid = i;
- portvalues[i].value = get_parameter(i);
- }
- }
-
- string const envvar = preset_envvar ();
- if (envvar.empty()) {
- warning << _("Could not locate HOME. Preset not saved.") << endmsg;
- return false;
- }
-
- string const source = preset_source (envvar, domain);
-
- char* uri = lrdf_add_preset (source.c_str(), name.c_str(), id, &defaults);
- /* XXX: why is the uri apparently kept as the key in the `presets' map and also in the PresetRecord? */
-
- presets.insert (make_pair (uri, PresetRecord (uri, name)));
- free (uri);
-
- bool const r = write_preset_file (envvar, domain);
-
- PresetAdded (); /* EMIT SIGNAL */
-
- return r;
+ return !uri.empty ();
}
PluginPtr
@@ -393,4 +183,26 @@ Plugin::input_streams () const
return ChanCount::ZERO;
}
+const Plugin::PresetRecord *
+Plugin::preset_by_label (const string& label)
+{
+ // FIXME: O(n)
+ for (map<string, PresetRecord>::const_iterator i = _presets.begin(); i != _presets.end(); ++i) {
+ if (i->second.label == label) {
+ return &i->second;
+ }
+ }
+
+ return 0;
+}
+const Plugin::PresetRecord *
+Plugin::preset_by_uri (const string& uri)
+{
+ map<string, PresetRecord>::const_iterator pr = _presets.find (uri);
+ if (pr != _presets.end()) {
+ return &pr->second;
+ } else {
+ return 0;
+ }
+}
diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc
index d01a70239a..333b7d893a 100644
--- a/libs/ardour/vst_plugin.cc
+++ b/libs/ardour/vst_plugin.cc
@@ -142,6 +142,37 @@ VSTPlugin::nth_parameter (uint32_t n, bool& ok) const
return n;
}
+/** Get VST chunk as base64-encoded data.
+ * @param single true for single program, false for all programs.
+ * @return 0-terminated base64-encoded data; must be passed to g_free () by caller.
+ */
+gchar *
+VSTPlugin::get_chunk (bool single)
+{
+ guchar* data;
+ int32_t data_size = _plugin->dispatcher (_plugin, 23 /* effGetChunk */, single ? 1 : 0, 0, &data, 0);
+ if (data_size == 0) {
+ return 0;
+ }
+
+ return g_base64_encode (data, data_size);
+}
+
+/** Set VST chunk from base64-encoded data.
+ * @param 0-terminated base64-encoded data.
+ * @param single true for single program, false for all programs.
+ * @return 0 on success, non-0 on failure
+ */
+int
+VSTPlugin::set_chunk (gchar const * data, bool single)
+{
+ gsize size = 0;
+ guchar* raw_data = g_base64_decode (data, &size);
+ int const r = _plugin->dispatcher (_plugin, 24 /* effSetChunk */, single ? 1 : 0, size, raw_data, 0);
+ g_free (raw_data);
+ return r;
+}
+
XMLNode&
VSTPlugin::get_state()
{
@@ -156,12 +187,8 @@ VSTPlugin::get_state()
if (_plugin->flags & 32 /* effFlagsProgramsChunks */) {
- /* fetch the current chunk */
-
- guchar* data;
- int32_t data_size;
-
- if ((data_size = _plugin->dispatcher (_plugin, 23 /* effGetChunk */, 0, 0, &data, false)) == 0) {
+ gchar* data = get_chunk (false);
+ if (data == 0) {
return *root;
}
@@ -169,9 +196,8 @@ VSTPlugin::get_state()
XMLNode* chunk_node = new XMLNode (X_("chunk"));
- gchar * encoded_data = g_base64_encode (data, data_size);
- chunk_node->add_content (encoded_data);
- g_free (encoded_data);
+ chunk_node->add_content (data);
+ g_free (data);
root->add_child_nocopy (*chunk_node);
@@ -220,11 +246,10 @@ VSTPlugin::set_state(const XMLNode& node, int)
for (n = child->children ().begin (); n != child->children ().end (); ++n) {
if ((*n)->is_content ()) {
- gsize chunk_size = 0;
- guchar * data = g_base64_decode ((*n)->content ().c_str (), &chunk_size);
- //cerr << "Dispatch setChunk for " << name() << endl;
- ret = _plugin->dispatcher (_plugin, 24 /* effSetChunk */, 0, chunk_size, data, 0);
- g_free (data);
+ /* XXX: this may be dubious for the same reasons that we delay
+ execution of load_preset.
+ */
+ ret = set_chunk ((*n)->content().c_str(), false);
}
}
@@ -331,33 +356,96 @@ bool
VSTPlugin::load_preset (const string& name)
{
if (_plugin->flags & 32 /* effFlagsProgramsChunks */) {
- error << _("no support for presets using chunks at this time")
- << endmsg;
+
+ XMLTree* t = presets_tree ();
+ if (t == 0) {
+ return false;
+ }
+
+ XMLNode* root = t->root ();
+
+ /* Load a user preset chunk from our XML file and send it via a circuitous route to the plugin */
+
+ for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
+ assert ((*i)->name() == X_("ChunkPreset"));
+
+ XMLProperty* uri = (*i)->property (X_("uri"));
+ XMLProperty* label = (*i)->property (X_("label"));
+
+ assert (uri);
+ assert (label);
+
+ if (label->value() == name) {
+
+ if (_fst->wanted_chunk) {
+ g_free (_fst->wanted_chunk);
+ }
+
+ for (XMLNodeList::const_iterator j = (*i)->children().begin(); j != (*i)->children().end(); ++j) {
+ if ((*j)->is_content ()) {
+ /* we can't dispatch directly here; too many plugins expect only one GUI thread */
+ gsize size = 0;
+ guchar* raw_data = g_base64_decode ((*j)->content().c_str(), &size);
+ _fst->wanted_chunk = raw_data;
+ _fst->wanted_chunk_size = size;
+ _fst->want_chunk = 1;
+ return true;
+ }
+ }
+ }
+ }
+
return false;
}
- return Plugin::load_preset (name);
+
+ return true;
}
-bool
-VSTPlugin::save_preset (string name)
+string
+VSTPlugin::do_save_preset (string name)
{
if (_plugin->flags & 32 /* effFlagsProgramsChunks */) {
- error << _("no support for presets using chunks at this time")
- << endmsg;
- return false;
+
+ XMLTree* t = presets_tree ();
+ if (t == 0) {
+ return "";
+ }
+
+ /* Add a chunk to our XML file of user presets */
+
+ XMLNode* p = new XMLNode (X_("ChunkPreset"));
+ /* XXX: use of _presets.size() + 1 for the unique ID here is dubious at best */
+ string const uri = string_compose (X_("VST:%1:%2"), unique_id (), _presets.size() + 1);
+ p->add_property (X_("uri"), uri);
+ p->add_property (X_("label"), name);
+ gchar* data = get_chunk (true);
+ p->add_content (string (data));
+ g_free (data);
+ t->root()->add_child_nocopy (*p);
+
+ sys::path f = ARDOUR::user_config_directory ();
+ f /= "presets";
+ f /= "vst";
+
+ t->write (f.to_string ());
+ delete t;
+ return uri;
}
- return Plugin::save_preset (name, "vst");
+
+ return "";
}
void
-VSTPlugin::remove_preset (string name)
+VSTPlugin::do_remove_preset (string name)
{
if (_plugin->flags & 32 /* effFlagsProgramsChunks */) {
+
+ /* XXX: TODO */
+
error << _("no support for presets using chunks at this time")
<< endmsg;
return;
}
- Plugin::remove_preset (name, "vst");
}
string
@@ -472,7 +560,7 @@ VSTPlugin::name () const
const char *
VSTPlugin::maker () const
{
- return "imadeit";
+ return _info->creator.c_str();
}
const char *
@@ -545,6 +633,94 @@ VSTPluginInfo::load (Session& session)
}
}
+vector<Plugin::PresetRecord>
+VSTPlugin::get_presets ()
+{
+ vector<PresetRecord> p;
+
+ /* Built-in presets */
+
+ int const vst_version = _plugin->dispatcher (_plugin, effGetVstVersion, 0, 0, NULL, 0);
+ for (int i = 0; i < _plugin->numPrograms; ++i) {
+ PresetRecord r (string_compose (X_("VST:%1:%2"), unique_id (), i), "");
+
+ if (vst_version >= 2) {
+ char buf[256];
+ _plugin->dispatcher (_plugin, 29, i, 0, buf, 0);
+ r.label = buf;
+ } else {
+ r.label = string_compose (_("Preset %1"), i);
+ }
+
+ p.push_back (r);
+ _presets.insert (make_pair (r.uri, r));
+ }
+
+ /* User presets from our XML file */
+
+ XMLTree* t = presets_tree ();
+
+ if (t) {
+ XMLNode* root = t->root ();
+ for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
+
+ assert ((*i)->name() == X_("ChunkPreset"));
+
+ XMLProperty* uri = (*i)->property (X_("uri"));
+ XMLProperty* label = (*i)->property (X_("label"));
+
+ assert (uri);
+ assert (label);
+
+ PresetRecord r (uri->value(), label->value());
+ p.push_back (r);
+ _presets.insert (make_pair (r.uri, r));
+ }
+ }
+
+ delete t;
+
+ return p;
+}
+
+/** @return XMLTree with our user presets; could be a new one if no existing
+ * one was found, or 0 if one was present but badly-formatted.
+ */
+XMLTree *
+VSTPlugin::presets_tree () const
+{
+ XMLTree* t = new XMLTree;
+
+ sys::path p = ARDOUR::user_config_directory ();
+ p /= "presets";
+
+ if (!is_directory (p)) {
+ create_directory (p);
+ }
+
+ p /= "vst";
+
+ if (!exists (p)) {
+ t->set_root (new XMLNode (X_("VSTPresets")));
+ return t;
+ }
+
+ t->set_filename (p.to_string ());
+ if (!t->read ()) {
+ delete t;
+ return 0;
+ }
+
+ return t;
+}
+
+/** @return Index of the first user preset in our lists */
+int
+VSTPlugin::first_user_preset_index () const
+{
+ return _plugin->numPrograms;
+}
+
VSTPluginInfo::VSTPluginInfo()
{
type = ARDOUR::VST;
diff --git a/libs/fst/fst.h b/libs/fst/fst.h
index 6ef5acf794..28ee49bd01 100644
--- a/libs/fst/fst.h
+++ b/libs/fst/fst.h
@@ -83,6 +83,9 @@ struct _FST
int vst_version;
int want_program;
+ int want_chunk;
+ unsigned char *wanted_chunk;
+ int wanted_chunk_size;
int current_program;
float *want_params;
float *set_params;
diff --git a/libs/fst/fstinfofile.c b/libs/fst/fstinfofile.c
index 2d7fb2fa6a..c7061cd6b8 100644
--- a/libs/fst/fstinfofile.c
+++ b/libs/fst/fstinfofile.c
@@ -14,6 +14,8 @@
#define FALSE 0
#define TRUE !FALSE
+extern char * strdup (const char *);
+
static char *read_string( FILE *fp ) {
char buf[MAX_STRING_LEN];
diff --git a/libs/fst/vstwin.c b/libs/fst/vstwin.c
index 09ca8f18d3..847ca19f1a 100644
--- a/libs/fst/vstwin.c
+++ b/libs/fst/vstwin.c
@@ -71,6 +71,7 @@ fst_new ()
pthread_cond_init (&fst->window_status_change, NULL);
pthread_cond_init (&fst->plugin_dispatcher_called, NULL);
fst->want_program = -1;
+ fst->want_chunk = 0;
fst->current_program = -1;
return fst;
}
@@ -178,6 +179,12 @@ again:
/* did it work? */
fst->current_program = fst->plugin->dispatcher (fst->plugin, 3, /* effGetProgram */ 0, 0, NULL, 0);
fst->want_program = -1;
+ printf("old-style leaves CP=%d\n", fst->current_program);
+ }
+
+ if (fst->want_chunk == 1) {
+ fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
+ fst->want_chunk = 0;
}
if(fst->dispatcher_wantcall) {