From: Carl Hetherington Date: Sun, 19 Dec 2010 23:11:01 +0000 (+0000) Subject: Clean up plugin preset handling a bit. X-Git-Tag: 3.0-alpha5~1030 X-Git-Url: https://main.carlh.net/gitweb/?a=commitdiff_plain;h=5f4bdb233a53932986e07fca1cd6c87d22c2886f;p=ardour.git Clean up plugin preset handling a bit. git-svn-id: svn://localhost/ardour2/branches/3.0@8301 d708f5d6-7413-0410-9779-e7cbd77b26cf --- diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc index f672af112e..9204912a36 100644 --- a/gtk2_ardour/generic_pluginui.cc +++ b/gtk2_ardour/generic_pluginui.cc @@ -92,7 +92,7 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol set_latency_label (); smaller_hbox->pack_start (latency_button, false, false, 10); - smaller_hbox->pack_start (preset_combo, false, false); + smaller_hbox->pack_start (_preset_box, false, false); smaller_hbox->pack_start (add_button, false, false); smaller_hbox->pack_start (save_button, false, false); smaller_hbox->pack_start (delete_button, false, false); @@ -425,7 +425,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrcombo->set_value_in_list(true, false); set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui)); control_ui->combo->signal_changed().connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui)); - mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::parameter_changed, this, control_ui), gui_context()); + mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed, this, control_ui), gui_context()); control_ui->pack_start(control_ui->label, true, true); control_ui->pack_start(*control_ui->combo, false, true); @@ -446,7 +446,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrcombo->set_value_in_list(true, false); set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui)); control_ui->combo->signal_changed().connect (sigc::bind (sigc::mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui)); - mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::parameter_changed, this, control_ui), gui_context()); + mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed, this, control_ui), gui_context()); control_ui->pack_start(control_ui->label, true, true); control_ui->pack_start(*control_ui->combo, false, true); @@ -557,7 +557,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrChanged.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::parameter_changed, this, control_ui), gui_context()); + mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed, this, control_ui), gui_context()); mcontrol->alist()->automation_state_changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::automation_state_changed, this, control_ui), gui_context()); input_controls.push_back (control_ui); @@ -609,7 +609,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrChanged.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::parameter_changed, this, control_ui), gui_context()); + mcontrol->Changed.connect (control_connections, invalidator (*this), boost::bind (&GenericPluginUI::ui_parameter_changed, this, control_ui), gui_context()); return control_ui; } @@ -672,7 +672,7 @@ GenericPluginUI::toggle_parameter_changed (ControlUI* cui) } void -GenericPluginUI::parameter_changed (ControlUI* cui) +GenericPluginUI::ui_parameter_changed (ControlUI* cui) { if (!cui->update_pending) { cui->update_pending = true; diff --git a/gtk2_ardour/lv2_plugin_ui.cc b/gtk2_ardour/lv2_plugin_ui.cc index 89d46846eb..f8924e5bec 100644 --- a/gtk2_ardour/lv2_plugin_ui.cc +++ b/gtk2_ardour/lv2_plugin_ui.cc @@ -55,7 +55,8 @@ void LV2PluginUI::on_external_ui_closed(LV2UI_Controller controller) void LV2PluginUI::parameter_changed (uint32_t port_index, float val) { - //cout << "parameter_changed" << endl; + PlugUIBase::parameter_changed (port_index, val); + if (val != _values[port_index]) { parameter_update(port_index, val); } @@ -199,8 +200,6 @@ LV2PluginUI::lv2ui_instantiate(const std::string& title) } } } - - _lv2->ParameterChanged.connect (parameter_connection, invalidator (*this), ui_bind (&LV2PluginUI::parameter_changed, this, _1, _2), gui_context()); } LV2PluginUI::~LV2PluginUI () diff --git a/gtk2_ardour/lv2_plugin_ui.h b/gtk2_ardour/lv2_plugin_ui.h index 817e1e825d..37234c59eb 100644 --- a/gtk2_ardour/lv2_plugin_ui.h +++ b/gtk2_ardour/lv2_plugin_ui.h @@ -59,6 +59,9 @@ class LV2PluginUI : public PlugUIBase, public Gtk::VBox int package (Gtk::Window&); private: + + void parameter_changed (uint32_t, float); + boost::shared_ptr _lv2; std::vector _output_ports; sigc::connection _screen_update_connection; @@ -83,7 +86,6 @@ class LV2PluginUI : public PlugUIBase, public Gtk::VBox void lv2ui_instantiate(const std::string& title); - void parameter_changed(uint32_t, float); void parameter_update(uint32_t, float); bool configure_handler (GdkEventConfigure*); void save_plugin_setting (); @@ -92,8 +94,6 @@ class LV2PluginUI : public PlugUIBase, public Gtk::VBox virtual bool on_window_show(const std::string& title); virtual void on_window_hide(); - - PBD::ScopedConnection parameter_connection; }; #endif // HAVE_SLV2 diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc index d18f81b2c4..9ad9e38f8e 100644 --- a/gtk2_ardour/plugin_ui.cc +++ b/gtk2_ardour/plugin_ui.cc @@ -217,7 +217,8 @@ PluginUIWindow::on_show () set_role("plugin_ui"); if (_pluginui) { - _pluginui->update_presets (); + _pluginui->update_preset_list (); + _pluginui->update_preset (); } if (_pluginui) { @@ -427,15 +428,17 @@ PlugUIBase::PlugUIBase (boost::shared_ptr pi) latency_gui (0), plugin_analysis_expander (_("Plugin analysis")) { - //preset_combo.set_use_arrows_always(true); - update_presets (); - update_sensitivity (); - - preset_combo.set_size_request (100, -1); - preset_combo.set_active_text (""); - preset_combo.signal_changed().connect(sigc::mem_fun(*this, &PlugUIBase::setting_selected)); - no_load_preset = false; + _preset_combo.set_size_request (100, -1); + _preset_modified.set_size_request (16, -1); + _preset_combo.signal_changed().connect(sigc::mem_fun(*this, &PlugUIBase::preset_selected)); + _no_load_preset = 0; + + _preset_box.pack_start (_preset_combo); + _preset_box.pack_start (_preset_modified); + update_preset_list (); + update_preset (); + add_button.set_name ("PluginAddButton"); add_button.signal_clicked().connect (sigc::mem_fun (*this, &PlugUIBase::add_plugin_setting)); @@ -471,8 +474,10 @@ PlugUIBase::PlugUIBase (boost::shared_ptr pi) insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PlugUIBase::plugin_going_away, this), gui_context()); - plugin->PresetAdded.connect (preset_added_connection, invalidator (*this), boost::bind (&PlugUIBase::update_presets, this), gui_context ()); - plugin->PresetRemoved.connect (preset_removed_connection, invalidator (*this), boost::bind (&PlugUIBase::update_presets, this), gui_context ()); + plugin->PresetAdded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ()); + plugin->PresetRemoved.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ()); + plugin->PresetLoaded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset, this), gui_context ()); + plugin->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::parameter_changed, this, _1, _2), gui_context ()); } PlugUIBase::~PlugUIBase() @@ -529,20 +534,19 @@ PlugUIBase::processor_active_changed (boost::weak_ptr weak_p) } void -PlugUIBase::setting_selected () +PlugUIBase::preset_selected () { - if (no_load_preset) { + if (_no_load_preset) { return; } - if (preset_combo.get_active_text().length() > 0) { - const Plugin::PresetRecord* pr = plugin->preset_by_label(preset_combo.get_active_text()); + if (_preset_combo.get_active_text().length() > 0) { + const Plugin::PresetRecord* pr = plugin->preset_by_label (_preset_combo.get_active_text()); if (pr) { - plugin->load_preset (pr->uri); - update_sensitivity (); + plugin->load_preset (*pr); } else { warning << string_compose(_("Plugin preset %1 not found"), - preset_combo.get_active_text()) << endmsg; + _preset_combo.get_active_text()) << endmsg; } } } @@ -562,8 +566,9 @@ PlugUIBase::add_plugin_setting () plugin->remove_preset (d.name ()); } - if (plugin->save_preset (d.name())) { - preset_combo.set_active_text (d.name()); + Plugin::PresetRecord const r = plugin->save_preset (d.name()); + if (!r.uri.empty ()) { + plugin->load_preset (r); } break; } @@ -572,23 +577,18 @@ PlugUIBase::add_plugin_setting () void PlugUIBase::save_plugin_setting () { - string const name = preset_combo.get_active_text (); + string const name = _preset_combo.get_active_text (); plugin->remove_preset (name); - plugin->save_preset (name); - preset_combo.set_active_text (name); + Plugin::PresetRecord const r = plugin->save_preset (name); + if (!r.uri.empty ()) { + plugin->load_preset (r); + } } void PlugUIBase::delete_plugin_setting () { - plugin->remove_preset (preset_combo.get_active_text ()); - - vector presets = plugin->get_presets(); - if (presets.empty ()) { - preset_combo.set_active_text (""); - } else { - preset_combo.set_active_text (presets.front().label); - } + plugin->remove_preset (_preset_combo.get_active_text ()); } void @@ -667,30 +667,61 @@ PlugUIBase::toggle_plugin_analysis() } void -PlugUIBase::update_presets () +PlugUIBase::update_preset_list () { vector preset_labels; vector presets = plugin->get_presets(); - no_load_preset = true; + ++_no_load_preset; for (vector::const_iterator i = presets.begin(); i != presets.end(); ++i) { - preset_labels.push_back(i->label); + preset_labels.push_back (i->label); } - set_popdown_strings (preset_combo, preset_labels); + set_popdown_strings (_preset_combo, preset_labels); - no_load_preset = false; + --_no_load_preset; +} + +void +PlugUIBase::update_preset () +{ + Plugin::PresetRecord p = plugin->last_preset(); + + ++_no_load_preset; + _preset_combo.set_active_text (p.label); + --_no_load_preset; - update_sensitivity (); + save_button.set_sensitive (!p.uri.empty() && p.user); + delete_button.set_sensitive (!p.uri.empty() && p.user); + + update_preset_modified (); } void -PlugUIBase::update_sensitivity () +PlugUIBase::update_preset_modified () { - bool const have_user_preset = - !preset_combo.get_model()->children().empty() && preset_combo.get_active_row_number() >= plugin->first_user_preset_index(); + if (plugin->last_preset().uri.empty()) { + _preset_modified.set_text (""); + return; + } - save_button.set_sensitive (have_user_preset); - delete_button.set_sensitive (have_user_preset); + bool const c = plugin->parameter_changed_since_last_preset (); + if (_preset_modified.get_text().empty() == c) { + _preset_modified.set_text (c ? "*" : ""); + } +} + +void +PlugUIBase::parameter_changed (uint32_t, float) +{ + update_preset_modified (); +} + +void +PlugUIBase::preset_added_or_removed () +{ + /* Update both the list and the currently-displayed preset */ + update_preset_list (); + update_preset (); } diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h index 99a4ce36e8..16ecc4bd15 100644 --- a/gtk2_ardour/plugin_ui.h +++ b/gtk2_ardour/plugin_ui.h @@ -72,7 +72,7 @@ namespace Gtkmm2ext { class LatencyGUI; class ArdourDialog; -class PlugUIBase : public virtual sigc::trackable +class PlugUIBase : public virtual sigc::trackable, public PBD::ScopedConnectionList { public: PlugUIBase (boost::shared_ptr); @@ -86,7 +86,8 @@ class PlugUIBase : public virtual sigc::trackable virtual void activate () {} virtual void deactivate () {} - virtual void update_presets (); + void update_preset_list (); + void update_preset (); void latency_button_clicked (); @@ -101,7 +102,9 @@ class PlugUIBase : public virtual sigc::trackable protected: boost::shared_ptr insert; boost::shared_ptr plugin; - Gtk::ComboBoxText preset_combo; + Gtk::HBox _preset_box; + Gtk::ComboBoxText _preset_combo; + Gtk::Label _preset_modified; Gtk::Button add_button; Gtk::Button save_button; Gtk::Button delete_button; @@ -119,9 +122,9 @@ class PlugUIBase : public virtual sigc::trackable Gtk::Image* focus_out_image; Gtk::Image* focus_in_image; - bool no_load_preset; + int _no_load_preset; - virtual void setting_selected (); + virtual void preset_selected (); void add_plugin_setting (); void save_plugin_setting (); void delete_plugin_setting (); @@ -130,7 +133,9 @@ class PlugUIBase : public virtual sigc::trackable void toggle_plugin_analysis (); void processor_active_changed (boost::weak_ptr p); void plugin_going_away (); - void update_sensitivity (); + virtual void parameter_changed (uint32_t, float); + void preset_added_or_removed (); + void update_preset_modified (); PBD::ScopedConnection death_connection; PBD::ScopedConnection active_connection; @@ -234,7 +239,7 @@ class GenericPluginUI : public PlugUIBase, public Gtk::VBox void build (); ControlUI* build_control_ui (guint32 port_index, boost::shared_ptr); std::vector setup_scale_values(guint32 port_index, ControlUI* cui); - void parameter_changed (ControlUI* cui); + void ui_parameter_changed (ControlUI* cui); void toggle_parameter_changed (ControlUI* cui); void update_control_display (ControlUI* cui); void control_port_toggled (ControlUI* cui); diff --git a/gtk2_ardour/vst_pluginui.cc b/gtk2_ardour/vst_pluginui.cc index be8a619e70..b6902445f3 100644 --- a/gtk2_ardour/vst_pluginui.cc +++ b/gtk2_ardour/vst_pluginui.cc @@ -35,8 +35,6 @@ VSTPluginUI::VSTPluginUI (boost::shared_ptr pi, boost::shared_ptr< : PlugUIBase (pi), vst (vp) { - update_presets (); - fst_run_editor (vst->fst()); preset_box.set_spacing (6); @@ -45,7 +43,7 @@ VSTPluginUI::VSTPluginUI (boost::shared_ptr pi, boost::shared_ptr< preset_box.pack_end (delete_button, false, false); preset_box.pack_end (save_button, false, false); preset_box.pack_end (add_button, false, false); - preset_box.pack_end (preset_combo, false, false); + preset_box.pack_end (_preset_box, false, false); bypass_button.set_active (!insert->active()); @@ -61,22 +59,10 @@ VSTPluginUI::~VSTPluginUI () } void -VSTPluginUI::setting_selected () +VSTPluginUI::preset_selected () { - int const r = 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 */ - plugin->load_preset (preset_combo.get_active_text()); - } - socket.grab_focus (); - update_sensitivity (); + PlugUIBase::preset_selected (); } int diff --git a/gtk2_ardour/vst_pluginui.h b/gtk2_ardour/vst_pluginui.h index 71452617f8..c8666a4da9 100644 --- a/gtk2_ardour/vst_pluginui.h +++ b/gtk2_ardour/vst_pluginui.h @@ -40,5 +40,5 @@ class VSTPluginUI : public PlugUIBase, public Gtk::VBox bool configure_handler (GdkEventConfigure*, Gtk::Socket*); void save_plugin_setting (); - void setting_selected (); + void preset_selected (); }; diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h index b00c23b1dc..abbfdbea3d 100644 --- a/libs/ardour/ardour/audio_unit.h +++ b/libs/ardour/ardour/audio_unit.h @@ -95,12 +95,10 @@ class AUPlugin : public ARDOUR::Plugin bool parameter_is_input (uint32_t) const; bool parameter_is_output (uint32_t) const; - XMLNode& get_state(); int set_state(const XMLNode& node, int); bool save_preset (std::string name); bool load_preset (const std::string& preset_label); - std::vector get_presets (); std::string current_preset() const; bool has_editor () const; @@ -143,6 +141,8 @@ class AUPlugin : public ARDOUR::Plugin static std::string maybe_fix_broken_au_id (const std::string&); private: + void find_presets (); + boost::shared_ptr comp; boost::shared_ptr unit; @@ -178,6 +178,7 @@ class AUPlugin : public ARDOUR::Plugin int set_input_format (AudioStreamBasicDescription&); int set_stream_format (int scope, uint32_t cnt, AudioStreamBasicDescription&); void discover_parameters (); + void add_state (XMLNode *) const; std::vector > parameter_map; uint32_t current_maxbuf; diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h index 7d561dd0a8..457921cf36 100644 --- a/libs/ardour/ardour/ladspa_plugin.h +++ b/libs/ardour/ardour/ladspa_plugin.h @@ -97,11 +97,9 @@ class LadspaPlugin : public ARDOUR::Plugin bool parameter_is_output(uint32_t) const; bool parameter_is_toggled(uint32_t) const; - XMLNode& get_state(); int set_state (const XMLNode&, int version); - std::vector get_presets (); - bool load_preset (const std::string& uri); + bool load_preset (PresetRecord); bool has_editor() const { return false; } @@ -131,6 +129,8 @@ class LadspaPlugin : public ARDOUR::Plugin uint32_t _index; bool _was_activated; + void find_presets (); + void init (void *mod, uint32_t index, framecnt_t rate); void run_in_place (pframes_t nsamples); void latency_compute_run (); @@ -140,6 +140,7 @@ class LadspaPlugin : public ARDOUR::Plugin std::string preset_envvar () const; std::string preset_source (std::string) const; bool write_preset_file (std::string); + void add_state (XMLNode *) const; }; class LadspaPluginInfo : public PluginInfo { diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h index c2b9ebc7bb..0920a01e6d 100644 --- a/libs/ardour/ardour/lv2_plugin.h +++ b/libs/ardour/ardour/lv2_plugin.h @@ -66,7 +66,7 @@ class LV2Plugin : public ARDOUR::Plugin bool is_external_ui() const; SLV2Port slv2_port(uint32_t i) { return slv2_plugin_get_port_by_index(_plugin, i); } - const char* port_symbol(uint32_t port); + const char* port_symbol (uint32_t port) const; const LV2_Feature* const* features() { return _features; } @@ -112,12 +112,11 @@ class LV2Plugin : public ARDOUR::Plugin static uint32_t midi_event_type() { return _midi_event_type; } - XMLNode& get_state(); int set_state(const XMLNode& node, int version); bool save_preset (std::string uri); void remove_preset (std::string uri); - bool load_preset (const std::string& uri); - virtual std::vector get_presets(); + bool load_preset (PresetRecord); + std::string current_preset () const; bool has_editor() const; @@ -167,6 +166,8 @@ class LV2Plugin : public ARDOUR::Plugin void latency_compute_run (); std::string do_save_preset (std::string); void do_remove_preset (std::string); + void find_presets (); + void add_state (XMLNode *) const; }; diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index ad002a926d..00ed6bdc94 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -99,6 +99,9 @@ class Plugin : public PBD::StatefulDestructible, public Latent bool max_unbound; }; + XMLNode& get_state (); + virtual int set_state (const XMLNode &, int version); + virtual std::string unique_id() const = 0; virtual const char * label() const = 0; virtual const char * name() const = 0; @@ -131,23 +134,40 @@ class Plugin : public PBD::StatefulDestructible, public Latent void realtime_handle_transport_stopped (); - 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 () : user (true) {} + PresetRecord (const std::string& u, const std::string& l, bool s = true) : uri (u), label (l), user (s) {} + + bool operator!= (PresetRecord const & a) const { + return uri != a.uri || label != a.label; + } + std::string uri; std::string label; + bool user; }; + PresetRecord save_preset (std::string); + void remove_preset (std::string); + + virtual bool load_preset (PresetRecord); + const PresetRecord * preset_by_label (const std::string &); const PresetRecord * preset_by_uri (const std::string &); - /** Return this plugin's presets; should add them to _presets */ - virtual std::vector get_presets () = 0; - virtual std::string current_preset () const { return std::string(); } + std::vector get_presets (); + /** @return Last preset to be requested; the settings may have + * been changed since; find out with parameter_changed_since_last_preset. + */ + PresetRecord last_preset () const { + return _last_preset; + } + + bool parameter_changed_since_last_preset () const { + return _parameter_changed_since_last_preset; + } + virtual int first_user_preset_index () const { return 0; } @@ -155,13 +175,14 @@ class Plugin : public PBD::StatefulDestructible, public Latent /** Emitted when a preset is added or removed, respectively */ PBD::Signal0 PresetAdded; PBD::Signal0 PresetRemoved; - - /* XXX: no-one listens to this */ - static PBD::Signal0 PresetFileExists; - virtual bool has_editor() const = 0; + /** Emitted when a preset has been loaded */ + PBD::Signal0 PresetLoaded; + + virtual bool has_editor () const = 0; - PBD::Signal2 ParameterChanged; + /** Emitted when any parameter changes */ + PBD::Signal2 ParameterChanged; /* NOTE: this block of virtual methods looks like the interface to a Processor, but Plugin does not inherit from Processor. @@ -199,7 +220,7 @@ protected: friend class PluginInsert; friend struct PluginInsert::PluginControl; - virtual void set_parameter (uint32_t which, float val) = 0; + virtual void set_parameter (uint32_t which, float val); /** 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. @@ -215,10 +236,19 @@ protected: std::map _presets; private: - + + /** Fill _presets with our presets */ + virtual void find_presets () = 0; + + /** Add state to an existing XMLNode */ + virtual void add_state (XMLNode *) const = 0; + + bool _have_presets; MidiStateTracker _tracker; BufferSet _pending_stop_events; bool _have_pending_stop_events; + PresetRecord _last_preset; + bool _parameter_changed_since_last_preset; }; 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 e9a2c4abdf..83bf58c4ac 100644 --- a/libs/ardour/ardour/vst_plugin.h +++ b/libs/ardour/ardour/vst_plugin.h @@ -78,13 +78,11 @@ class VSTPlugin : public ARDOUR::Plugin bool parameter_is_input(uint32_t i) const { return true; } bool parameter_is_output(uint32_t i) const { return false; } - bool load_preset (const std::string& preset_label); - virtual std::vector get_presets (); + bool load_preset (PresetRecord); int first_user_preset_index () const; bool has_editor () const; - XMLNode& get_state(); int set_state (XMLNode const &, int); AEffect * plugin () const { return _plugin; } @@ -94,10 +92,14 @@ private: void do_remove_preset (std::string name); std::string do_save_preset (std::string name); - gchar* get_chunk (bool); + gchar* get_chunk (bool) const; int set_chunk (gchar const *, bool); XMLTree * presets_tree () const; std::string presets_file () const; + void find_presets (); + bool load_user_preset (PresetRecord); + bool load_plugin_preset (PresetRecord); + void add_state (XMLNode *) const; FSTHandle* handle; FST* _fst; diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc index 2e47a0bd48..54342c7f91 100644 --- a/libs/ardour/audio_unit.cc +++ b/libs/ardour/audio_unit.cc @@ -162,16 +162,10 @@ save_property_list (CFPropertyListRef propertyList, Glib::ustring path) fd = open (path.c_str(), O_WRONLY|O_CREAT|O_EXCL, 0664); while (fd < 0) { if (errno == EEXIST) { - /* tell any UI's that this file already exists and ask them what to do */ - bool overwrite = Plugin::PresetFileExists(); // EMIT SIGNAL - if (overwrite) { - fd = open (path.c_str(), O_WRONLY, 0664); - continue; - } else { - return 0; - } + error << string_compose (_("Preset file %1 exists; not overwriting"), path); + } else { + error << string_compose (_("Cannot open preset file %1 (%2)"), path, strerror (errno)) << endmsg; } - error << string_compose (_("Cannot open preset file %1 (%2)"), path, strerror (errno)) << endmsg; CFRelease (xmlData); return -1; } @@ -767,24 +761,28 @@ AUPlugin::signal_latency () const void AUPlugin::set_parameter (uint32_t which, float val) { - if (which < descriptors.size()) { - const AUParameterDescriptor& d (descriptors[which]); - TRACE_API ("set parameter %d in scope %d element %d to %f\n", d.id, d.scope, d.element, val); - unit->SetParameter (d.id, d.scope, d.element, val); - - /* tell the world what we did */ - - AudioUnitEvent theEvent; - - theEvent.mEventType = kAudioUnitEvent_ParameterValueChange; - theEvent.mArgument.mParameter.mAudioUnit = unit->AU(); - theEvent.mArgument.mParameter.mParameterID = d.id; - theEvent.mArgument.mParameter.mScope = d.scope; - theEvent.mArgument.mParameter.mElement = d.element; - - TRACE_API ("notify about parameter change\n"); - AUEventListenerNotify (NULL, NULL, &theEvent); + if (which >= descriptors.size()) { + return; } + + const AUParameterDescriptor& d (descriptors[which]); + TRACE_API ("set parameter %d in scope %d element %d to %f\n", d.id, d.scope, d.element, val); + unit->SetParameter (d.id, d.scope, d.element, val); + + /* tell the world what we did */ + + AudioUnitEvent theEvent; + + theEvent.mEventType = kAudioUnitEvent_ParameterValueChange; + theEvent.mArgument.mParameter.mAudioUnit = unit->AU(); + theEvent.mArgument.mParameter.mParameterID = d.id; + theEvent.mArgument.mParameter.mScope = d.scope; + theEvent.mArgument.mParameter.mElement = d.element; + + TRACE_API ("notify about parameter change\n"); + AUEventListenerNotify (NULL, NULL, &theEvent); + + Plugin::set_parameter (which, val); } float @@ -1551,11 +1549,10 @@ AUPlugin::parameter_is_output (uint32_t) const return false; } -XMLNode& -AUPlugin::get_state() +void +AUPlugin::add_state (XMLNode* root) { LocaleGuard lg (X_("POSIX")); - XMLNode *root = new XMLNode (state_node_name()); #ifdef AU_STATE_SUPPORT CFDataRef xmlData; @@ -1563,7 +1560,7 @@ AUPlugin::get_state() TRACE_API ("get preset state\n"); if (unit->GetAUPreset (propertyList) != noErr) { - return *root; + return; } // Convert the property list into XML data. @@ -1597,12 +1594,10 @@ AUPlugin::get_state() seen_get_state_message = true; } #endif - - return *root; } int -AUPlugin::set_state(const XMLNode& node, int /* version*/) +AUPlugin::set_state(const XMLNode& node, int version) { #ifdef AU_STATE_SUPPORT int ret = -1; @@ -1650,6 +1645,7 @@ AUPlugin::set_state(const XMLNode& node, int /* version*/) CFRelease (propertyList); } + Plugin::set_state (node, version); return ret; #else if (!seen_set_state_message) { @@ -1657,13 +1653,15 @@ AUPlugin::set_state(const XMLNode& node, int /* version*/) PROGRAM_NAME) << endmsg; } - return 0; + return Plugin::set_state (node, version); #endif } bool -AUPlugin::load_preset (const string& preset_label) +AUPlugin::load_preset (PluginRecord r) { + Plugin::load_preset (r); + #ifdef AU_STATE_SUPPORT bool ret = false; CFPropertyListRef propertyList; @@ -1962,11 +1960,9 @@ AUPlugin::current_preset() const return preset_name; } -vector -AUPlugin::get_presets () +void +AUPlugin::find_presets () { - vector presets; - #ifdef AU_STATE_SUPPORT vector* preset_files; PathScanner scanner; @@ -1976,7 +1972,7 @@ AUPlugin::get_presets () preset_files = scanner (preset_search_path, au_preset_filter, this, true, true, -1, true); if (!preset_files) { - return presets; + return; } for (vector::iterator x = preset_files->begin(); x != preset_files->end(); ++x) { @@ -2006,18 +2002,18 @@ AUPlugin::get_presets () /* now fill the vector with the names we have */ for (UserPresetMap::iterator i = user_preset_map.begin(); i != user_preset_map.end(); ++i) { - presets.push_back (Plugin::PresetRecord (i->second, i->first)); + _presets.insert (i->second, Plugin::PresetRecord (i->second, i->first)); } /* add factory presets */ for (FactoryPresetMap::iterator i = factory_preset_map.begin(); i != factory_preset_map.end(); ++i) { - presets.push_back (Plugin::PresetRecord ("", i->first)); + /* XXX: dubious */ + string const uri = string_compose ("%1", _presets.size ()); + _presets.push_back (uri, Plugin::PresetRecord (uri, i->first)); } #endif - - return presets; } bool diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc index 43fa8e43ee..cab21f46f9 100644 --- a/libs/ardour/ladspa_plugin.cc +++ b/libs/ardour/ladspa_plugin.cc @@ -297,9 +297,8 @@ LadspaPlugin::set_parameter (uint32_t which, float val) { if (which < _descriptor->PortCount) { _shadow_data[which] = (LADSPA_Data) val; -#if 0 - ParameterChanged (Parameter(PluginAutomation, 0, which), val); /* EMIT SIGNAL */ +#if 0 if (which < parameter_count() && controls[which]) { controls[which]->Changed (); } @@ -311,6 +310,8 @@ LadspaPlugin::set_parameter (uint32_t which, float val) "invalid"), name()) << endmsg; } + + Plugin::set_parameter (which, val); } float @@ -341,10 +342,9 @@ LadspaPlugin::nth_parameter (uint32_t n, bool& ok) const return 0; } -XMLNode& -LadspaPlugin::get_state() +void +LadspaPlugin::add_state (XMLNode* root) const { - XMLNode *root = new XMLNode(state_node_name()); XMLNode *child; char buf[16]; LocaleGuard lg (X_("POSIX")); @@ -362,8 +362,6 @@ LadspaPlugin::get_state() root->add_child_nocopy (*child); } } - - return *root; } int @@ -372,7 +370,7 @@ LadspaPlugin::set_state (const XMLNode& node, int version) if (version < 3000) { return set_state_2X (node, version); } - + XMLNodeList nodes; XMLProperty *prop; XMLNodeConstIterator iter; @@ -389,7 +387,7 @@ LadspaPlugin::set_state (const XMLNode& node, int version) nodes = node.children ("Port"); - for(iter = nodes.begin(); iter != nodes.end(); ++iter){ + for (iter = nodes.begin(); iter != nodes.end(); ++iter) { child = *iter; @@ -412,7 +410,7 @@ LadspaPlugin::set_state (const XMLNode& node, int version) latency_compute_run (); - return 0; + return Plugin::set_state (node, version); } int @@ -709,15 +707,14 @@ LadspaPluginInfo::LadspaPluginInfo() } -vector -LadspaPlugin::get_presets () +void +LadspaPlugin::find_presets () { - vector result; uint32_t id; std::string unique (unique_id()); if (!isdigit (unique[0])) { - return result; + return; } id = atol (unique.c_str()); @@ -727,22 +724,19 @@ LadspaPlugin::get_presets () 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); + PresetRecord rec (set_uris->items[i], label); _presets.insert (make_pair (set_uris->items[i], rec)); } } lrdf_free_uris(set_uris); } - - return result; } bool -LadspaPlugin::load_preset (const string& preset_uri) +LadspaPlugin::load_preset (PresetRecord r) { - lrdf_defaults* defs = lrdf_get_setting_values(preset_uri.c_str()); + lrdf_defaults* defs = lrdf_get_setting_values (r.uri.c_str()); if (defs) { for (uint32_t i = 0; i < (uint32_t) defs->count; ++i) { @@ -755,6 +749,7 @@ LadspaPlugin::load_preset (const string& preset_uri) lrdf_free_setting_values(defs); } + Plugin::load_preset (r); return true; } diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index d8daca9f64..dd36d134f5 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -219,7 +219,7 @@ LV2Plugin::default_value (uint32_t port) } const char* -LV2Plugin::port_symbol (uint32_t index) +LV2Plugin::port_symbol (uint32_t index) const { SLV2Port port = slv2_plugin_get_port_by_index(_plugin, index); if (!port) { @@ -236,7 +236,6 @@ LV2Plugin::set_parameter (uint32_t which, float val) { if (which < slv2_plugin_get_num_ports(_plugin)) { _shadow_data[which] = val; - ParameterChanged (which, val); /* EMIT SIGNAL */ #if 0 if (which < parameter_count() && controls[which]) { @@ -249,6 +248,8 @@ LV2Plugin::set_parameter (uint32_t which, float val) "This is a bug in either %2 or the LV2 plugin (%3)"), name(), PROGRAM_NAME, unique_id()) << endmsg; } + + Plugin::set_parameter (which, val); } float @@ -307,10 +308,9 @@ LV2Plugin::lv2_persist_retrieve_callback(void* callback_data, return NULL; } -XMLNode& -LV2Plugin::get_state() +void +LV2Plugin::add_state (XMLNode* root) const { - XMLNode *root = new XMLNode(state_node_name()); XMLNode *child; char buf[16]; LocaleGuard lg (X_("POSIX")); @@ -347,7 +347,7 @@ LV2Plugin::get_state() warning << string_compose( _("Plugin \"%1\% failed to return LV2 persist data"), unique_id()); - return *root; // FIXME: Possibly inconsistent state + return; } LV2PFile file = lv2_pfile_open(state_path.c_str(), true); @@ -356,36 +356,35 @@ LV2Plugin::get_state() root->add_property("state-file", state_filename); } - - return *root; } -vector -LV2Plugin::get_presets() +void +LV2Plugin::find_presets () { - vector result; SLV2Results presets = slv2_plugin_query_sparql(_plugin, "PREFIX lv2p: \n" "PREFIX dc: \n" "SELECT ?p ?name WHERE { <> lv2p:hasPreset ?p . ?p dc:title ?name }\n"); + for (; !slv2_results_finished(presets); slv2_results_next(presets)) { SLV2Value uri = slv2_results_get_binding_value(presets, 0); 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); _presets.insert(std::make_pair(slv2_value_as_string(uri), rec)); } + slv2_results_free(presets); - return result; } bool -LV2Plugin::load_preset(const string& uri) +LV2Plugin::load_preset (PresetRecord r) { + Plugin::load_preset (r); + const string query = string( "PREFIX lv2p: \n" "PREFIX dc: \n" - "SELECT ?sym ?val WHERE { <") + uri + "> lv2:port ?port . " + "SELECT ?sym ?val WHERE { <") + r.uri + "> lv2:port ?port . " " ?port lv2:symbol ?sym ; lv2p:value ?val . }"; SLV2Results values = slv2_plugin_query_sparql(_plugin, query.c_str()); for (; !slv2_results_finished(values); slv2_results_next(values)) { @@ -491,7 +490,7 @@ LV2Plugin::set_state(const XMLNode& node, int version) latency_compute_run (); - return 0; + return Plugin::set_state (node, version); } int diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 1a711b5250..3ba0f8ddec 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -62,13 +62,13 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -PBD::Signal0 Plugin::PresetFileExists; - Plugin::Plugin (AudioEngine& e, Session& s) : _engine (e) , _session (s) , _cycles (0) + , _have_presets (false) , _have_pending_stop_events (false) + , _parameter_changed_since_last_preset (false) { } @@ -79,7 +79,9 @@ Plugin::Plugin (const Plugin& other) , _session (other._session) , _info (other._info) , _cycles (0) + , _have_presets (false) , _have_pending_stop_events (false) + , _parameter_changed_since_last_preset (false) { } @@ -94,10 +96,14 @@ Plugin::remove_preset (string name) { do_remove_preset (name); _presets.erase (preset_by_label (name)->uri); + + _last_preset.uri = ""; + _parameter_changed_since_last_preset = false; PresetRemoved (); /* EMIT SIGNAL */ } -bool +/** @return PresetRecord with empty URI on failure */ +Plugin::PresetRecord Plugin::save_preset (string name) { string const uri = do_save_preset (name); @@ -106,8 +112,8 @@ Plugin::save_preset (string name) _presets.insert (make_pair (uri, PresetRecord (uri, name))); PresetAdded (); /* EMIT SIGNAL */ } - - return !uri.empty (); + + return PresetRecord (uri, name); } PluginPtr @@ -243,3 +249,72 @@ Plugin::realtime_handle_transport_stopped () _tracker.resolve_notes (_pending_stop_events.get_midi (0), 0); _have_pending_stop_events = true; } + +vector +Plugin::get_presets () +{ + if (!_have_presets) { + find_presets (); + _have_presets = true; + } + + vector p; + for (map::const_iterator i = _presets.begin(); i != _presets.end(); ++i) { + p.push_back (i->second); + } + + return p; +} + +/** Set parameters using a preset */ +bool +Plugin::load_preset (PresetRecord r) +{ + _last_preset = r; + _parameter_changed_since_last_preset = false; + + PresetLoaded (); /* EMIT SIGNAL */ + return true; +} + +void +Plugin::set_parameter (uint32_t which, float val) +{ + _parameter_changed_since_last_preset = true; + ParameterChanged (Evoral::Parameter (PluginAutomation, 0, which), val); /* EMIT SIGNAL */ +} + +int +Plugin::set_state (const XMLNode& node, int version) +{ + XMLProperty const * p = node.property (X_("last-preset-uri")); + if (p) { + _last_preset.uri = p->value (); + } + + p = node.property (X_("last-preset-label")); + if (p) { + _last_preset.label = p->value (); + } + + p = node.property (X_("parameter-changed-since-last-preset")); + if (p) { + _parameter_changed_since_last_preset = string_is_affirmative (p->value ()); + } + + return 0; +} + +XMLNode & +Plugin::get_state () +{ + XMLNode* root = new XMLNode (state_node_name ()); + LocaleGuard lg (X_("POSIX")); + + root->add_property (X_("last-preset-uri"), _last_preset.uri); + root->add_property (X_("last-preset-label"), _last_preset.label); + root->add_property (X_("parameter-changed-since-last-preset"), _parameter_changed_since_last_preset ? X_("yes") : X_("no")); + + add_state (root); + return *root; +} diff --git a/libs/ardour/session_vst.cc b/libs/ardour/session_vst.cc index 85b5f13c4c..2aa873c6e6 100644 --- a/libs/ardour/session_vst.cc +++ b/libs/ardour/session_vst.cc @@ -70,8 +70,8 @@ long Session::vst_callback (AEffect* effect, case audioMasterAutomate: SHOW_CALLBACK ("amc: audioMasterAutomate\n"); // index, value, returns 0 - if (effect) { - effect->setParameter (effect, index, opt); + if (plug) { + plug->set_parameter (index, opt); } return 0; diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc index 1f3cc95c27..92aac83beb 100644 --- a/libs/ardour/vst_plugin.cc +++ b/libs/ardour/vst_plugin.cc @@ -125,7 +125,15 @@ void VSTPlugin::set_parameter (uint32_t which, float val) { _plugin->setParameter (_plugin, which, val); - //ParameterChanged (which, val); /* EMIT SIGNAL */ + + if (_fst->want_program == -1 && _fst->want_chunk == 0) { + /* Heinous hack: Plugin::set_parameter below updates the `modified' status of the + current preset, but if _fst->want_program is not -1 then there is a preset + setup pending or in progress, which we don't want any `modified' updates + to happen for. So we only do this if _fst->want_program is -1. + */ + Plugin::set_parameter (which, val); + } } float @@ -147,7 +155,7 @@ VSTPlugin::nth_parameter (uint32_t n, bool& ok) const * @return 0-terminated base64-encoded data; must be passed to g_free () by caller. */ gchar * -VSTPlugin::get_chunk (bool single) +VSTPlugin::get_chunk (bool single) const { guchar* data; int32_t data_size = _plugin->dispatcher (_plugin, 23 /* effGetChunk */, single ? 1 : 0, 0, &data, 0); @@ -173,10 +181,9 @@ VSTPlugin::set_chunk (gchar const * data, bool single) return r; } -XMLNode& -VSTPlugin::get_state() +void +VSTPlugin::add_state (XMLNode* root) const { - XMLNode *root = new XMLNode (state_node_name()); LocaleGuard lg (X_("POSIX")); if (_fst->current_program != -1) { @@ -189,7 +196,7 @@ VSTPlugin::get_state() gchar* data = get_chunk (false); if (data == 0) { - return *root; + return; } /* store information */ @@ -215,12 +222,10 @@ VSTPlugin::get_state() root->add_child_nocopy (*parameters); } - - return *root; } int -VSTPlugin::set_state(const XMLNode& node, int) +VSTPlugin::set_state (const XMLNode& node, int version) { LocaleGuard lg (X_("POSIX")); @@ -275,6 +280,7 @@ VSTPlugin::set_state(const XMLNode& node, int) } + Plugin::set_state (node, version); return ret; } @@ -353,15 +359,54 @@ VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc) } bool -VSTPlugin::load_preset (const string& name) +VSTPlugin::load_preset (PresetRecord r) +{ + bool s; + + if (r.user) { + s = load_user_preset (r); + } else { + s = load_plugin_preset (r); + } + + if (s) { + Plugin::load_preset (r); + } + + return s; +} + +bool +VSTPlugin::load_plugin_preset (PresetRecord r) { + /* This is a plugin-provided preset. + We can't dispatch directly here; too many plugins expects only one GUI thread. + */ + + /* Extract the index of this preset from the URI */ + int id; + int index; + int const p = sscanf (r.uri.c_str(), "VST:%d:%d", &id, &index); + assert (p == 2); + + _fst->want_program = index; + return true; +} + +bool +VSTPlugin::load_user_preset (PresetRecord r) +{ + /* This is a user preset; we load it, and this code also knows about the + non-direct-dispatch thing. + */ + boost::shared_ptr t (presets_tree ()); if (t == 0) { return false; } XMLNode* root = t->root (); - + for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) { XMLProperty* uri = (*i)->property (X_("uri")); @@ -369,11 +414,11 @@ VSTPlugin::load_preset (const string& name) assert (uri); assert (label); - - if (label->value() != name) { + + if (label->value() != r.label) { continue; } - + if (_plugin->flags & 32 /* effFlagsProgramsChunks */) { /* Load a user preset chunk from our XML file and send it via a circuitous route to the plugin */ @@ -395,26 +440,26 @@ VSTPlugin::load_preset (const string& name) } return false; - + } else { for (XMLNodeList::const_iterator j = (*i)->children().begin(); j != (*i)->children().end(); ++j) { if ((*j)->name() == X_("Parameter")) { - - XMLProperty* index = (*j)->property (X_("index")); - XMLProperty* value = (*j)->property (X_("value")); - - assert (index); - assert (value); - - set_parameter (atoi (index->value().c_str()), atof (value->value().c_str ())); + + XMLProperty* index = (*j)->property (X_("index")); + XMLProperty* value = (*j)->property (X_("value")); + + assert (index); + assert (value); + + set_parameter (atoi (index->value().c_str()), atof (value->value().c_str ())); } } - + return true; } } - + return false; } @@ -556,7 +601,6 @@ VSTPlugin::connect_and_run (BufferSet& bufs, } /* we already know it can support processReplacing */ - _plugin->processReplacing (_plugin, ins, outs, nframes); return 0; @@ -670,16 +714,14 @@ VSTPluginInfo::load (Session& session) } } -vector -VSTPlugin::get_presets () +void +VSTPlugin::find_presets () { - vector 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), ""); + PresetRecord r (string_compose (X_("VST:%1:%2"), unique_id (), i), "", false); if (vst_version >= 2) { char buf[256]; @@ -692,7 +734,6 @@ VSTPlugin::get_presets () r.label = string_compose (_("Preset %1"), i); } - p.push_back (r); _presets.insert (make_pair (r.uri, r)); } @@ -710,13 +751,11 @@ VSTPlugin::get_presets () assert (uri); assert (label); - PresetRecord r (uri->value(), label->value()); - p.push_back (r); + PresetRecord r (uri->value(), label->value(), true); _presets.insert (make_pair (r.uri, r)); } } - return p; } /** @return XMLTree with our user presets; could be a new one if no existing