Clean up plugin preset handling a bit.
authorCarl Hetherington <carl@carlh.net>
Sun, 19 Dec 2010 23:11:01 +0000 (23:11 +0000)
committerCarl Hetherington <carl@carlh.net>
Sun, 19 Dec 2010 23:11:01 +0000 (23:11 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@8301 d708f5d6-7413-0410-9779-e7cbd77b26cf

18 files changed:
gtk2_ardour/generic_pluginui.cc
gtk2_ardour/lv2_plugin_ui.cc
gtk2_ardour/lv2_plugin_ui.h
gtk2_ardour/plugin_ui.cc
gtk2_ardour/plugin_ui.h
gtk2_ardour/vst_pluginui.cc
gtk2_ardour/vst_pluginui.h
libs/ardour/ardour/audio_unit.h
libs/ardour/ardour/ladspa_plugin.h
libs/ardour/ardour/lv2_plugin.h
libs/ardour/ardour/plugin.h
libs/ardour/ardour/vst_plugin.h
libs/ardour/audio_unit.cc
libs/ardour/ladspa_plugin.cc
libs/ardour/lv2_plugin.cc
libs/ardour/plugin.cc
libs/ardour/session_vst.cc
libs/ardour/vst_plugin.cc

index f672af112ef5b058aa24b5497dfec15b4a85e5a0..9204912a365b5d03d8d7c678419baf7e2d054ce0 100644 (file)
@@ -92,7 +92,7 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> 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_ptr<Automat
                                //control_ui->combo->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_ptr<Automat
                                //control_ui->combo->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_ptr<Automat
 
                automation_state_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());
                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_ptr<Automat
                output_controls.push_back (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());
 
        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;
index 89d46846ebe32d9da1aef91eba5a0a9398b6cdcf..f8924e5bec048c005863b8ec56722fa1217854ea 100644 (file)
@@ -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 ()
index 817e1e825d1169c8b7a674eb7772c31a5c236270..37234c59eba4259e40e3dbc2cac48778f01fb862 100644 (file)
@@ -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<ARDOUR::LV2Plugin> _lv2;
        std::vector<int> _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
index d18f81b2c43e1b0fc008405e43a0d84b730f94cd..9ad9e38f8ea3a951685650e8bab208fa188f2bbf 100644 (file)
@@ -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<PluginInsert> 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<PluginInsert> 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<Processor> 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<ARDOUR::Plugin::PresetRecord> 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<string> preset_labels;
        vector<ARDOUR::Plugin::PresetRecord> presets = plugin->get_presets();
 
-       no_load_preset = true;
+       ++_no_load_preset;
 
        for (vector<ARDOUR::Plugin::PresetRecord>::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 ();
 }
index 99a4ce36e885fb92ff6f373a8fad416467983e7d..16ecc4bd15fe5123b266db7f0924f201923db8c8 100644 (file)
@@ -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<ARDOUR::PluginInsert>);
@@ -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<ARDOUR::PluginInsert> insert;
        boost::shared_ptr<ARDOUR::Plugin> 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<ARDOUR::Processor> 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<ARDOUR::AutomationControl>);
        std::vector<std::string> 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);
index be8a619e701d617f5f4e6a545e689520fe44868a..b6902445f367d2d2199ac5f20c3e542dd3f3c3e3 100644 (file)
@@ -35,8 +35,6 @@ VSTPluginUI::VSTPluginUI (boost::shared_ptr<PluginInsert> 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<PluginInsert> 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
index 71452617f84747ff50d90fde854906aa65e80fe4..c8666a4da9d892537d9372f087e142e0b7c5def3 100644 (file)
@@ -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 ();
 };
index b00c23b1dc91ae6b82864c8fa6a48a9003520733..abbfdbea3d64ab5c3cb14948cf07f7a484560844 100644 (file)
@@ -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<PresetRecord> 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<CAComponent> comp;
         boost::shared_ptr<CAAudioUnit> 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<std::pair<uint32_t, uint32_t> > parameter_map;
        uint32_t current_maxbuf;
index 7d561dd0a8c37f3c0c65157ee46da0a9f127ea29..457921cf36715baa0e812fc6989fd3cac6fa80d1 100644 (file)
@@ -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<PresetRecord> 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 {
index c2b9ebc7bbe2d320f906fcda57de117402eb66f0..0920a01e6d79464fa39e3583e6d51ce07420891f 100644 (file)
@@ -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<Plugin::PresetRecord> 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;
 };
 
 
index ad002a926ded51efeaca5a181f78ee0dc6f1db92..00ed6bdc94352d9eb7919d10434d4089fe4bc9cd 100644 (file)
@@ -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<PresetRecord> get_presets () = 0;
-       virtual std::string current_preset () const { return std::string(); }
+       std::vector<PresetRecord> 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<void> PresetAdded;
        PBD::Signal0<void> PresetRemoved;
-       
-       /* XXX: no-one listens to this */
-       static PBD::Signal0<bool> PresetFileExists;
 
-       virtual bool has_editor() const = 0;
+       /** Emitted when a preset has been loaded */
+       PBD::Signal0<void> PresetLoaded;
+
+       virtual bool has_editor () const = 0;
 
-       PBD::Signal2<void,uint32_t,float> ParameterChanged;
+       /** Emitted when any parameter changes */
+       PBD::Signal2<void, uint32_t, float> 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<std::string, PresetRecord> _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);
index e9a2c4abdf1a9d7716e1c40421711d78f227a16d..83bf58c4aca65a0e0ca3e2696477f5804c413e5f 100644 (file)
@@ -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<PresetRecord> 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;
index 2e47a0bd48b3bbb732e01783d37123cef0cc7c1c..54342c7f916d83b9d919059cbe7d2c1e7f8698cd 100644 (file)
@@ -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<Plugin::PresetRecord>
-AUPlugin::get_presets ()
+void
+AUPlugin::find_presets ()
 {
-       vector<Plugin::PresetRecord> presets;
-
 #ifdef AU_STATE_SUPPORT
        vector<string*>* 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<string*>::iterator x = preset_files->begin(); x != preset_files->end(); ++x) {
@@ -2006,18 +2002,18 @@ AUPlugin::get_presets ()
         /* now fill the vector<string> 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
index 43fa8e43eea7698cbe0370265788ecb4d4e327d3..cab21f46f94f3cbabbeb7b01b8f7d16f94b8fe17 100644 (file)
@@ -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<Plugin::PresetRecord>
-LadspaPlugin::get_presets ()
+void
+LadspaPlugin::find_presets ()
 {
-       vector<PresetRecord> 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;
 }
 
index d8daca9f648e942147d4fb42fb80ac4ca719580a..dd36d134f510ce45ad5b00169911e162978e792e 100644 (file)
@@ -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<Plugin::PresetRecord>
-LV2Plugin::get_presets()
+void
+LV2Plugin::find_presets ()
 {
-       vector<PresetRecord> result;
        SLV2Results presets = slv2_plugin_query_sparql(_plugin,
                        "PREFIX lv2p: <http://lv2plug.in/ns/dev/presets#>\n"
                        "PREFIX dc:  <http://dublincore.org/documents/dcmi-namespace/>\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: <http://lv2plug.in/ns/dev/presets#>\n"
                        "PREFIX dc:  <http://dublincore.org/documents/dcmi-namespace/>\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
index 1a711b5250eab010a5453795d0bfd832cc8d6fc0..3ba0f8ddeccc785076bcf2bab3d50865efffc866 100644 (file)
@@ -62,13 +62,13 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-PBD::Signal0<bool> 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::PresetRecord>
+Plugin::get_presets ()
+{
+       if (!_have_presets) {
+               find_presets ();
+               _have_presets = true;
+       }
+
+       vector<PresetRecord> p;
+       for (map<string, PresetRecord>::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;
+}
index 85b5f13c4c95c1622dfda130c4bc0b5ac6891b18..2aa873c6e641cd8df324e4f3150d8d8026575649 100644 (file)
@@ -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;
 
index 1f3cc95c27a65e52859a6882f74d43661163c694..92aac83bebaaabd1cb856e604af19f237ee77c4c 100644 (file)
@@ -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<XMLTree> 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<Plugin::PresetRecord>
-VSTPlugin::get_presets ()
+void
+VSTPlugin::find_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), "");
+               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