Clean up generic and LV2 plugin GUI to deal with ParameterChanged(Externally) alteration
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 20 Oct 2015 14:12:51 +0000 (10:12 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 20 Oct 2015 14:23:49 +0000 (10:23 -0400)
gtk2_ardour/lv2_plugin_ui.cc
gtk2_ardour/lv2_plugin_ui.h
gtk2_ardour/plugin_ui.cc
gtk2_ardour/plugin_ui.h

index 141f437f4cdadbc21c7d8fcc4fc2ab179e9ed454..e2c446ef20555de5b9ee6d1a46e40e67a55f85ad 100644 (file)
@@ -20,7 +20,9 @@
 #include "ardour/lv2_plugin.h"
 #include "ardour/session.h"
 #include "pbd/error.h"
+#include "pbd/stacktrace.h"
 
+#include "gui_thread.h"
 #include "lv2_plugin_ui.h"
 #include "timers.h"
 
@@ -53,6 +55,9 @@ LV2PluginUI::write_from_ui(void*       controller,
                }
 
                boost::shared_ptr<AutomationControl> ac = me->_controllables[port_index];
+               /* Cache our local copy of the last value received from the GUI */
+               me->_values[port_index] = *(const float*) buffer;
+               /* Now update the control itself */
                if (ac) {
                        ac->set_value(*(const float*)buffer);
                }
@@ -120,26 +125,18 @@ LV2PluginUI::on_external_ui_closed(void* controller)
 }
 
 void
-LV2PluginUI::parameter_changed(uint32_t port_index, float val)
+LV2PluginUI::control_changed (uint32_t port_index)
 {
-       PlugUIBase::parameter_changed(port_index, val);
-
-       if (val != _values[port_index]) {
-               parameter_update(port_index, val);
+       /* Must run in GUI thread because we modify _updates with no lock */
+       if (_lv2->get_parameter (port_index) != _values[port_index]) {
+               /* current plugin parameter does not match last value received
+                  from GUI, so queue an update to push it to the GUI during
+                  our regular timeout.
+               */
+               _updates.insert (port_index);
        }
 }
 
-void
-LV2PluginUI::parameter_update(uint32_t port_index, float val)
-{
-       if (!_inst) {
-               return;
-       }
-
-       suil_instance_port_event((SuilInstance*)_inst, port_index, 4, 0, &val);
-       _values[port_index] = val;
-}
-
 bool
 LV2PluginUI::start_updating(GdkEventAny*)
 {
@@ -183,13 +180,14 @@ LV2PluginUI::output_update()
                }
        }
 
-       /* FIXME only works with control output ports (which is all we support now anyway) */
-       uint32_t nports = _output_ports.size();
-       for (uint32_t i = 0; i < nports; ++i) {
-               uint32_t index = _output_ports[i];
-               parameter_changed(index, _lv2->get_parameter(index));
+       if (_inst) {
+               for (Updates::iterator i = _updates.begin(); i != _updates.end(); ++i) {
+                       float val = _lv2->get_parameter (*i);
+                       /* push current value to the GUI */
+                       suil_instance_port_event ((SuilInstance*)_inst, (*i), 4, 0, &val);
+               }
+               _updates.clear ();
        }
-
 }
 
 LV2PluginUI::LV2PluginUI(boost::shared_ptr<PluginInsert> pi,
@@ -358,12 +356,14 @@ LV2PluginUI::lv2ui_instantiate(const std::string& title)
                bool     ok;
                uint32_t port = _lv2->nth_parameter(i, ok);
                if (ok) {
-                       _values[port]        = _lv2->get_parameter(port);
                        _controllables[port] = boost::dynamic_pointer_cast<ARDOUR::AutomationControl> (
                                insert->control(Evoral::Parameter(PluginAutomation, 0, port)));
 
-                       if (_lv2->parameter_is_control(port) && _lv2->parameter_is_input(port)) {
-                               parameter_update(port, _values[port]);
+                       /* FIXME only works with control output ports (which is all we support now anyway) */
+                       if (_controllables[port] && _lv2->parameter_is_control(port) && _lv2->parameter_is_input(port)) {
+                               _controllables[port]->Changed.connect (control_connections, invalidator (*this), boost::bind (&LV2PluginUI::control_changed, this, port), gui_context());
+                               /* queue for first update ("push") to GUI */
+                               _updates.insert (port);
                        }
                }
        }
@@ -401,9 +401,7 @@ LV2PluginUI::lv2ui_free()
 
 LV2PluginUI::~LV2PluginUI ()
 {
-       if (_values) {
-               delete[] _values;
-       }
+       delete [] _values;
 
        _message_update_connection.disconnect();
        _screen_update_connection.disconnect();
index 6a8acf9cf53e0454e38a3c08d1127ac201da43db..25ab4b9e30f3771f9c8f49b047bad686435586bb 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <list>
 #include <map>
+#include <set>
 #include <vector>
 
 #include <gtkmm/widget.h>
@@ -64,7 +65,7 @@ class LV2PluginUI : public PlugUIBase, public Gtk::VBox
 
   private:
 
-       void parameter_changed (uint32_t, float);
+       void control_changed (uint32_t);
 
        typedef boost::shared_ptr<ARDOUR::AutomationControl> ControllableRef;
 
@@ -85,6 +86,8 @@ class LV2PluginUI : public PlugUIBase, public Gtk::VBox
        LV2_Feature                          _parent_feature;
        Gtk::Window*                         _win_ptr;
        void*                                _inst;
+       typedef std::set<uint32_t> Updates;
+       Updates                              _updates;
 
        static void on_external_ui_closed(void* controller);
 
index 37c01462b28348e631edeca709bb8394cbe82744..19dbee422fb8a08e074f0aa08d5a669ff2ac7954 100644 (file)
@@ -484,7 +484,7 @@ PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi)
        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 ());
+       plugin->PresetDirty.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset_modified, this), gui_context ());
 
        insert->AutomationStateChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::automation_state_changed, this), gui_context());
 
@@ -813,12 +813,6 @@ PlugUIBase::update_preset_modified ()
        }
 }
 
-void
-PlugUIBase::parameter_changed (uint32_t, float)
-{
-       update_preset_modified ();
-}
-
 void
 PlugUIBase::preset_added_or_removed ()
 {
index 41f4ef39f1d01bbf1721e8b7a5423e4ca3f8f8dd..d2e5e21cca15f918d86fd0337ffbc7b9fc292f7d 100644 (file)
@@ -170,7 +170,6 @@ class PlugUIBase : public virtual sigc::trackable, public PBD::ScopedConnectionL
        void processor_active_changed (boost::weak_ptr<ARDOUR::Processor> p);
        void plugin_going_away ();
        void automation_state_changed ();
-       virtual void parameter_changed (uint32_t, float);
        void preset_added_or_removed ();
        void update_preset_modified ();