modification to make generic MIDI actually work again
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 10 Jul 2006 20:01:47 +0000 (20:01 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 10 Jul 2006 20:01:47 +0000 (20:01 +0000)
git-svn-id: svn://localhost/ardour2/trunk@673 d708f5d6-7413-0410-9779-e7cbd77b26cf

14 files changed:
libs/ardour/ardour/control_protocol_manager.h
libs/ardour/control_protocol_manager.cc
libs/gtkmm2ext/binding_proxy.cc
libs/gtkmm2ext/gtkmm2ext/binding_proxy.h
libs/gtkmm2ext/popup.cc
libs/pbd/pbd/controllable.h
libs/surfaces/control_protocol/control_protocol/control_protocol.h
libs/surfaces/generic_midi/generic_midi_control_protocol.cc
libs/surfaces/generic_midi/generic_midi_control_protocol.h
libs/surfaces/generic_midi/interface.cc
libs/surfaces/generic_midi/midicontrollable.cc
libs/surfaces/generic_midi/midicontrollable.h
libs/surfaces/tranzport/tranzport_control_protocol.cc
libs/surfaces/tranzport/tranzport_control_protocol.h

index 9202696dff44ee7f3b1db443ca0119dbc37dc6b1..8eda7a4555b83a648faa3b1aa3f68f3f40dada50 100644 (file)
@@ -23,6 +23,7 @@ struct ControlProtocolInfo {
     std::string path;
     bool requested;
     bool mandatory;
+    XMLNode* state;
 };
 
  class ControlProtocolManager : public sigc::trackable, public Stateful
index c2fb18895322398a462e6e874dc812c46a1602cc..0370886a35b338d14bed27ae7e2c3def0d18a902 100644 (file)
@@ -49,6 +49,10 @@ ControlProtocolManager::set_session (Session& s)
                if ((*i)->requested || (*i)->mandatory) {
                        instantiate (**i);
                        (*i)->requested = false;
+
+                       if ((*i)->state) {
+                               (*i)->protocol->set_state (*(*i)->state);
+                       }
                }
        }
 }
@@ -181,6 +185,7 @@ ControlProtocolManager::control_protocol_discover (string path)
                        cpi->protocol = 0;
                        cpi->requested = false;
                        cpi->mandatory = descriptor->mandatory;
+                       cpi->state = 0;
                        
                        control_protocol_info.push_back (cpi);
                        
index a29cb41632f20bf2148cb0b999dcf44376c99b67..3a2f5bbbc837e423e78379a2ae05e25792a77947 100644 (file)
@@ -62,7 +62,8 @@ BindingProxy::button_press_handler (GdkEventButton *ev)
                if (Controllable::StartLearning (&controllable)) {
                        string prompt = _("operate controller now");
                        prompter.set_text (prompt);
-                       prompter.show_all ();
+                       prompter.touch (); // shows popup
+                       learning_connection = controllable.LearningFinished.connect (mem_fun (*this, &BindingProxy::learning_finished));
                }
                return true;
        }
@@ -70,9 +71,18 @@ BindingProxy::button_press_handler (GdkEventButton *ev)
        return false;
 }
 
+void
+BindingProxy::learning_finished ()
+{
+       learning_connection.disconnect ();
+       prompter.touch (); // hides popup
+}
+
+
 bool
 BindingProxy::prompter_hiding (GdkEventAny *ev)
 {
+       learning_connection.disconnect ();
        Controllable::StopLearning (&controllable);
        return false;
 }
index 365668f72c5d0985df2c01035f30e9d4546f5bf4..a26c8ace2a6417e0abf5554a7dde67a2b221a161 100644 (file)
@@ -46,7 +46,8 @@ class BindingProxy : public sigc::trackable
        PBD::Controllable& controllable;
        guint bind_button;
        guint bind_statemask;
-
+       sigc::connection learning_connection;
+       void learning_finished ();
        bool prompter_hiding (GdkEventAny *);
 };
 
index 0a48ebfc594ce551cb85e1b84b3ed6aeb05549ba..a8ffc4af669526baaca8ec481899d5dc36e6a842 100644 (file)
@@ -73,11 +73,12 @@ PopUp::remove ()
 {
        hide ();
 
+       if (popdown_time != 0 && timeout != -1) {
+               gtk_timeout_remove (timeout);
+       }
+
        if (delete_on_hide) {
                std::cerr << "deleting prompter\n";
-               if (popdown_time != 0 && timeout != -1) {
-                       gtk_timeout_remove (timeout);
-               }
                gtk_idle_add (idle_delete, this);
        }
 }
@@ -125,11 +126,12 @@ PopUp::on_delete_event (GdkEventAny* ev)
 {
        hide();
 
+       if (popdown_time != 0 && timeout != -1) {
+               gtk_timeout_remove (timeout);
+       }       
+
        if (delete_on_hide) {
                std::cerr << "deleting prompter\n" << endl;
-               if (popdown_time != 0 && timeout != -1) {
-                       gtk_timeout_remove (timeout);
-               }
                gtk_idle_add (idle_delete, this);
        }
 
index 4948e4e4a04d5150e9fb99041d921e1a763aafc5..c46e477b6ecd1fda518a3a879b59c5684fcc3c56 100644 (file)
@@ -21,6 +21,8 @@ class Controllable : public virtual sigc::trackable, public Stateful {
 
        virtual bool can_send_feedback() const { return true; }
 
+       sigc::signal<void> LearningFinished;
+
        static sigc::signal<void,Controllable*> Created;
        static sigc::signal<void,Controllable*> GoingAway;
 
index 69135f2b4b010c3f1a60603582cebed802632494..2bd23f5b48ae730c03eef81f587799cfa917de7f 100644 (file)
@@ -26,7 +26,7 @@
 #include <vector>
 #include <list>
 #include <sigc++/sigc++.h>
-
+#include <pbd/stateful.h>
 #include <control_protocol/basic_ui.h>
 
 namespace ARDOUR {
@@ -34,7 +34,7 @@ namespace ARDOUR {
 class Route;
 class Session;
 
-class ControlProtocol : public sigc::trackable, public BasicUI {
+class ControlProtocol : public sigc::trackable, public Stateful, public BasicUI {
   public:
        ControlProtocol (Session&, std::string name);
        virtual ~ControlProtocol();
index dec891703e5e6940379b19517f858e35bebb76af..d905c0bc41bcf1299007f3dedc57973811cd2a01 100644 (file)
@@ -20,6 +20,9 @@
 
 #include <algorithm>
 
+#include <pbd/error.h>
+#include <pbd/failed_constructor.h>
+
 #include <midi++/port.h>
 #include <midi++/manager.h>
 #include <midi++/port_request.h>
@@ -39,9 +42,17 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
        : ControlProtocol  (s, _("GenericMIDI"))
 {
        MIDI::Manager* mm = MIDI::Manager::instance();
-       MIDI::PortRequest pr ("ardour:MIDI control", "ardour:MIDI control", "duplex", "alsa/seq");
+
+       /* XXX it might be nice to run "control" through i18n, but thats a bit tricky because
+          the name is defined in ardour.rc which is likely not internationalized.
+       */
        
-       _port = mm->add_port (pr);
+       _port = mm->port (X_("control"));
+
+       if (_port == 0) {
+               error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg;
+               throw failed_constructor();
+       }
 
        _feedback_interval = 10000; // microseconds
        last_feedback_time = 0;
@@ -112,11 +123,13 @@ GenericMidiControlProtocol::start_learning (Controllable* c)
 
        MIDIControllable* mc = new MIDIControllable (*_port, *c);
        
-
        {
                Glib::Mutex::Lock lm (pending_lock);
-               pending_controllables.push_back (mc);
-               mc->learning_stopped.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
+               std::pair<MIDIControllables::iterator,bool> result;
+               result = pending_controllables.insert (mc);
+               if (result.second) {
+                       c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
+               }
        }
 
        mc->learn_about_external_control ();
@@ -135,7 +148,7 @@ GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
                pending_controllables.erase (i);
        }
 
-       controllables.push_back (mc);
+       controllables.insert (mc);
 }
 
 void
@@ -156,3 +169,65 @@ GenericMidiControlProtocol::stop_learning (Controllable* c)
                }
        }
 }
+
+XMLNode&
+GenericMidiControlProtocol::get_state () 
+{
+       XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
+       XMLNode* children = new XMLNode (X_("controls"));
+
+       node->add_child_nocopy (*children);
+
+       Glib::Mutex::Lock lm2 (controllables_lock);
+       for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
+               children->add_child_nocopy ((*i)->get_state());
+       }
+
+       return *node;
+}
+
+int
+GenericMidiControlProtocol::set_state (const XMLNode& node)
+{
+       XMLNodeList nlist;
+       XMLNodeConstIterator niter;
+       Controllable* c;
+
+       {
+               Glib::Mutex::Lock lm (pending_lock);
+               pending_controllables.clear ();
+       }
+
+       Glib::Mutex::Lock lm2 (controllables_lock);
+
+       controllables.clear ();
+
+       nlist = node.children();
+
+       if (nlist.empty()) {
+               return 0;
+       }
+
+       nlist = nlist.front()->children ();
+
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+               XMLProperty* prop;
+
+               if ((prop = (*niter)->property ("id")) != 0) {
+
+                       ID id = prop->value ();
+
+                       c = session->controllable_by_id (id);
+
+                       if (c) {
+                               MIDIControllable* mc = new MIDIControllable (*_port, *c);
+                               if (mc->set_state (**niter) == 0) {
+                                       controllables.insert (mc);
+                               }
+                       }
+               }
+       }
+       
+       return 0;
+}
index f86f5f64347d8bab56b22dadf63f4775da71d183..5f5a470b13c2c8b04c341a295067ffc54fb03675 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef ardour_generic_midi_control_protocol_h
 #define ardour_generic_midi_control_protocol_h
 
-#include <vector>
+#include <set>
 #include <glibmm/thread.h>
 #include <ardour/types.h>
 
@@ -32,6 +32,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
        MIDI::Port* port () const { return _port; }
        void set_feedback_interval (ARDOUR::microseconds_t);
 
+       XMLNode& get_state ();
+       int set_state (const XMLNode&);
+
   private:
        MIDI::Port* _port;
        ARDOUR::microseconds_t _feedback_interval;
@@ -40,7 +43,7 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
        void _send_feedback ();
        void  send_feedback ();
 
-       typedef std::vector<MIDIControllable*> MIDIControllables;
+       typedef std::set<MIDIControllable*> MIDIControllables;
        MIDIControllables controllables;
        MIDIControllables pending_controllables;
        Glib::Mutex controllables_lock;
index c6c59c658992ec49e5f793074ed968ba184dddb6..230be694f23a66185c6ffdbaee6ce2c2cdf5c170 100644 (file)
@@ -1,3 +1,5 @@
+#include <pbd/failed_constructor.h>
+
 #include <control_protocol/control_protocol.h>
 #include "generic_midi_control_protocol.h"
 
@@ -6,7 +8,13 @@ using namespace ARDOUR;
 ControlProtocol*
 new_generic_midi_protocol (ControlProtocolDescriptor* descriptor, Session* s)
 {
-       GenericMidiControlProtocol* gmcp =  new GenericMidiControlProtocol (*s);
+       GenericMidiControlProtocol* gmcp;
+               
+       try {
+               gmcp =  new GenericMidiControlProtocol (*s);
+       } catch (failed_constructor& err) {
+               return 0;
+       }
        
        if (gmcp->set_active (true)) {
                delete gmcp;
index f4b7ef665b46e97b9cbec6faae1f65d712b651c2..d6135fd2a86f426b6685a0cac8393297cc129177 100644 (file)
@@ -90,7 +90,6 @@ MIDIControllable::learn_about_external_control ()
 {
        drop_external_control ();
        midi_learn_connection = _port.input()->any.connect (mem_fun (*this, &MIDIControllable::midi_receiver));
-       learning_started ();
 }
 
 void
@@ -199,7 +198,7 @@ MIDIControllable::midi_receiver (Parser &p, byte *msg, size_t len)
 
        bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]);
 
-       learning_stopped ();
+       controllable.LearningFinished ();
 }
 
 void
index 7dd0be1d870513aced021c25877ff8556fba497c..ab15f9f4ab3fd6425001e7e582dbffbef043c97c 100644 (file)
@@ -53,9 +53,6 @@ class MIDIControllable : public Stateful
        void stop_learning ();
        void drop_external_control ();
 
-       sigc::signal<void> learning_started;
-       sigc::signal<void> learning_stopped;
-
        bool get_midi_feedback () { return feedback; }
        void set_midi_feedback (bool val) { feedback = val; }
 
index 09ab88e4ed481a9d16eca4a13be2cb1dd89d1904..1fe9b7231a8c49cb391d914597b58e45cd094f0a 100644 (file)
@@ -1574,3 +1574,15 @@ TranzportControlProtocol::print (int row, int col, const char *text)
        }
 }      
 
+XMLNode&
+TranzportControlProtocol::get_state () 
+{
+       XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
+       return *node;
+}
+
+int
+TranzportControlProtocol::set_state (const XMLNode& node)
+{
+       return 0;
+}
index 546cc2f2af3189ff5bbc85b59ee9a94fc79bc201..e6e1a83e46720607bd509eb9e50203cb23182811 100644 (file)
@@ -23,6 +23,9 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
 
        static bool probe ();
 
+       XMLNode& get_state ();
+       int set_state (const XMLNode&);
+
   private:
        static const int VENDORID = 0x165b;
        static const int PRODUCTID = 0x8101;