make generic MIDI control track remote control ID changes; fixup messes in the editor...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 30 Dec 2009 12:41:10 +0000 (12:41 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 30 Dec 2009 12:41:10 +0000 (12:41 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6413 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/editor_routes.cc
gtk2_ardour/mixer_ui.cc
libs/ardour/ardour/route.h
libs/ardour/route.cc
libs/ardour/session.cc
libs/surfaces/generic_midi/generic_midi_control_protocol.cc
libs/surfaces/generic_midi/midicontrollable.cc
libs/surfaces/generic_midi/midicontrollable.h

index 2ee8927fd2bbcd24a7b3868a61ebce3103a6e179..1a55d9157396730f30278d75a88f5804e2455214 100644 (file)
@@ -892,8 +892,6 @@ EditorRoutes::move_selected_tracks (bool up)
        }
 
        _model->reorder (neworder);
-
-       _session->sync_order_keys (N_ ("editor"));
 }
 
 void
index b750f8a470ed4e7cc0e6e5813b112e7cd243b092..87c48a4348673c0c20f73ae7da5d056a516ea1c5 100644 (file)
@@ -689,7 +689,9 @@ void
 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
 {
        strip_redisplay_does_not_sync_order_keys = true;
-       _session->set_remote_control_ids();
+       if (!strip_redisplay_does_not_reset_order_keys) {
+               _session->set_remote_control_ids();
+       }
        redisplay_track_list ();
        strip_redisplay_does_not_sync_order_keys = false;
 }
@@ -699,7 +701,6 @@ Mixer_UI::track_list_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::
 {
        // never reset order keys because of a property change
        strip_redisplay_does_not_reset_order_keys = true;
-       _session->set_remote_control_ids();
        redisplay_track_list ();
        strip_redisplay_does_not_reset_order_keys = false;
 }
@@ -709,7 +710,6 @@ Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
 {
        /* this could require an order sync */
        if (_session && !_session->deletion_in_progress()) {
-               _session->set_remote_control_ids();
                redisplay_track_list ();
        }
 }
index 9630975d1ffc9c71d0efd4ac3b599bb725089c96..bb02396773e116c493170ce98ccb4cea895183b0 100644 (file)
@@ -306,8 +306,15 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
 
        void set_remote_control_id (uint32_t id);
        uint32_t remote_control_id () const;
+
+       /* for things concerned about *this* route's RID */
+
        PBD::Signal0<void> RemoteControlIDChanged;
 
+       /* for things concerned about any route's RID changes */
+
+       static PBD::Signal0<void> RemoteControlIDChange;
+
        void sync_order_keys (std::string const &);
        static PBD::Signal1<void,std::string const &> SyncOrderKeys;
 
index 09e38eaa862c491479f279694749c8526b5b6236..9c08080d2d92de9f5dd3cbac004a0896814e86fb 100644 (file)
@@ -25,6 +25,7 @@
 #include "pbd/xml++.h"
 #include "pbd/enumwriter.h"
 #include "pbd/memento_command.h"
+#include "pbd/stacktrace.h"
 
 #include "evoral/Curve.hpp"
 
@@ -64,6 +65,7 @@ using namespace PBD;
 
 uint32_t Route::order_key_cnt = 0;
 PBD::Signal1<void,string const&> Route::SyncOrderKeys;
+PBD::Signal0<void> Route::RemoteControlIDChange;
 
 Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        : SessionObject (sess, name)
@@ -177,6 +179,7 @@ Route::set_remote_control_id (uint32_t id)
        if (id != _remote_control_id) {
                _remote_control_id = id;
                RemoteControlIDChanged ();
+               RemoteControlIDChange ();
        }
 }
 
index 19aca23c346f8a0300c282de1e2f76e5cb9e58a8..1f61322b4b64e8c6e1492076f42d2d37081eca1b 100644 (file)
@@ -2170,6 +2170,7 @@ Session::add_routes (RouteList& new_routes, bool save)
        }
 
        RouteAdded (new_routes); /* EMIT SIGNAL */
+       Route::RemoteControlIDChange (); /* EMIT SIGNAL */
 }
 
 void
@@ -4183,6 +4184,7 @@ Session::sync_order_keys (std::string const & base)
        }
 
        Route::SyncOrderKeys (base); // EMIT SIGNAL
+       Route::RemoteControlIDChange (); // EMIT SIGNAL
 }
 
 
index e7fa9018c9b510fe0c760a2f3f4502fb11581685..6a29c2768468d3169e3a9857fb9d3be4e4872572 100644 (file)
@@ -82,6 +82,7 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
        Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
 
        Session::SendFeedback.connect (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
+       Route::RemoteControlIDChange.connect (*this, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
 
        reload_maps ();
 }
@@ -407,7 +408,7 @@ GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos,
                
                // Create a MIDIControllable
                MIDIControllable* mc = new MIDIControllable (*_port, *control);
-               
+
                // Remove any old binding for this midi channel/type/value pair
                // Note:  can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
                for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
@@ -426,7 +427,6 @@ GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos,
                // Update the MIDI Controllable based on the the pos param
                // Here is where a table lookup for user mappings could go; for now we'll just wing it...
                mc->bind_midi(channel, MIDI::controller, value);
-               mc->set_learned (true);
 
                controllables.push_back (mc);
        }
@@ -518,6 +518,7 @@ GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
                                
                                if (c) {
                                        MIDIControllable* mc = new MIDIControllable (*_port, *c);
+
                                        if (mc->set_state (**niter, version) == 0) {
                                                controllables.push_back (mc);
                                        }
@@ -623,8 +624,6 @@ GenericMidiControlProtocol::load_bindings (const string& xmlpath)
 
                        } else if (child->property ("function")) {
 
-                               cerr << "try to create a function from " << child->property ("function")->value() << endl;
-
                                /* function */
                                MIDIFunction* mf;
 
@@ -686,7 +685,13 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node)
        prop = node.property (X_("uri"));
        uri = prop->value();
 
-       MIDIControllable* mc = new MIDIControllable (*_port, uri, false);
+       MIDIControllable* mc = new MIDIControllable (*_port, false);
+
+       if (mc->init (uri)) {
+               delete mc;
+               return 0;
+       }
+
        mc->bind_midi (channel, ev, detail);
 
        cerr << "New MC with URI " << uri << " on channel " << (int) channel << " detail = " << (int) detail << endl;
@@ -703,55 +708,11 @@ GenericMidiControlProtocol::reset_controllables ()
                MIDIControllable* existingBinding = (*iter);
 
                if (!existingBinding->learned()) {
-                       cerr << "Look for " << existingBinding->current_uri() << endl;
-
-                       /* parse URI to get remote control ID and "what" is to be controlled */
-
-                       std::string uri = existingBinding->current_uri();
-                       string::size_type last_slash;
-                       string useful_part;
-                       
-                       if ((last_slash = uri.find_last_of ('/')) == string::npos) {
-                               existingBinding->set_controllable (0);
-                               continue;
+                       uint32_t rid = existingBinding->rid();
+                       if (existingBinding->bank_relative()) {
+                               rid += _current_bank * _bank_size;
                        }
-                       
-                       useful_part = uri.substr (last_slash+1);
-                       
-                       char ridstr[64];
-                       char what[64];
-                       
-                       if (sscanf (useful_part.c_str(), "rid=%63[^?]?%63s", ridstr, what) != 2) {
-                               existingBinding->set_controllable (0);
-                               continue;
-                       }
-                       
-                       /* now parse RID string and determine if its a bank-driven ID */
-                       
-                       uint32_t rid;
-
-                       if (strncmp (ridstr, "B-", 2) == 0) {
-
-                               if (sscanf (&ridstr[2], "%" PRIu32, &rid) != 1) {
-                                       existingBinding->set_controllable (0);
-                                       continue;
-                               }
-                               
-                               rid += _bank_size * _current_bank;
-
-                       } else {
-                               if (sscanf (&ridstr[2], "%" PRIu32, &rid) != 1) {
-                                       existingBinding->set_controllable (0);
-                                       continue;
-                               }
-                       }
-
-                       /* go get it (allowed to fail) */
-
-                       cerr << "Look for controllable via " << rid << " and " << what << endl;
-
-                       boost::shared_ptr<Controllable> c = session->controllable_by_rid_and_name (rid, what);
-                       cerr << "\tgot " << c << endl;
+                       boost::shared_ptr<Controllable> c = session->controllable_by_rid_and_name (rid, existingBinding->what().c_str());
                        existingBinding->set_controllable (c.get());
                }
        }
index 6b0a08b62057e7bb432e8f3a23a8b1813e2c9480..0cebabd80bce1b858250f3a801579c0d956072dd 100644 (file)
@@ -17,6 +17,9 @@
 
 */
 
+#define __STDC_FORMAT_MACROS 1
+#include <stdint.h>
+
 #include <cstdio> /* for sprintf, sigh */
 #include <climits>
 
@@ -35,16 +38,32 @@ using namespace MIDI;
 using namespace PBD;
 using namespace ARDOUR;
 
-MIDIControllable::MIDIControllable (Port& p, const string& c, bool is_bistate)
-       : controllable (0), _current_uri (c), _port (p), bistate (is_bistate)
+MIDIControllable::MIDIControllable (Port& p, bool is_bistate)
+       : controllable (0)
+       , _port (p)
+       , bistate (is_bistate)
 {
-       init ();
+       _learned = false; /* from URI */
+       setting = false;
+       last_value = 0; // got a better idea ?
+       control_type = none;
+       _control_description = "MIDI Control: none";
+       control_additional = (byte) -1;
+       feedback = true; // for now
 }
 
 MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool is_bistate)
-       : controllable (&c), _current_uri (c.uri()), _port (p), bistate (is_bistate)
+       : controllable (&c)
+       , _port (p)
+       , bistate (is_bistate)
 {
-       init ();
+       _learned = true; /* from controllable */
+       setting = false;
+       last_value = 0; // got a better idea ?
+       control_type = none;
+       _control_description = "MIDI Control: none";
+       control_additional = (byte) -1;
+       feedback = true; // for now
 }
 
 MIDIControllable::~MIDIControllable ()
@@ -52,20 +71,52 @@ MIDIControllable::~MIDIControllable ()
        drop_external_control ();
 }
 
-void
-MIDIControllable::init ()
+int
+MIDIControllable::init (const std::string& s)
 {
-       _learned = false;
-       setting = false;
-       last_value = 0; // got a better idea ?
-       control_type = none;
-       _control_description = "MIDI Control: none";
-       control_additional = (byte) -1;
-       feedback = true; // for now
+       _current_uri = s;
 
-       /* use channel 0 ("1") as the initial channel */
+       if (!_current_uri.empty()) {
 
-       midi_rebind (0);
+               /* parse URI to get remote control ID and "what" is to be controlled */
+               
+               string::size_type last_slash;
+               string useful_part;
+               
+               if ((last_slash = _current_uri.find_last_of ('/')) == string::npos) {
+                       return -1;
+               }
+               
+               useful_part = _current_uri.substr (last_slash+1);
+               
+               char ridstr[64];
+               char what[64];
+               
+               if (sscanf (useful_part.c_str(), "rid=%63[^?]?%63s", ridstr, what) != 2) {
+                       return -1;
+               }
+               
+               _what = what;
+
+               /* now parse RID string and determine if its a bank-driven ID */
+               
+               if (strncmp (ridstr, "B-", 2) == 0) {
+                       
+                       if (sscanf (&ridstr[2], "%" PRIu32, &_rid) != 1) {
+                               return -1;
+                       }
+                       
+                       _bank_relative = true;
+
+               } else {
+                       if (sscanf (&ridstr[2], "%" PRIu32, &_rid) != 1) {
+                               return -1;
+                       }
+                       _bank_relative = false;
+               }
+       }
+
+       return 0;
 }
 
 void
@@ -83,10 +134,7 @@ MIDIControllable::midi_forget ()
 void
 MIDIControllable::drop_external_control ()
 {
-       midi_sense_connection[0].disconnect ();
-       midi_sense_connection[1].disconnect ();
-       midi_learn_connection.disconnect ();
-
+       midi_forget ();
        control_type = none;
        control_additional = (byte) -1;
 }
index cd42afde56b6da62d8f086472c2e55de367faf03..b5aa115feee4e0b9e85561950d93cc93211fb7ac 100644 (file)
@@ -42,13 +42,16 @@ class MIDIControllable : public PBD::Stateful
 {
   public:
        MIDIControllable (MIDI::Port&, PBD::Controllable&, bool bistate = false);
-       MIDIControllable (MIDI::Port&, const std::string& uri, bool bistate = false);
+       MIDIControllable (MIDI::Port&, bool bistate = false);
        virtual ~MIDIControllable ();
 
+       int init (const std::string&);
+
        void rediscover_controllable ();
+       bool bank_relative() const { return _bank_relative; }
+       uint32_t rid() const { return _rid; }
+       std::string what() const { return _what; }
 
-       bool ok() const { return !_current_uri.empty(); }
-       
        void send_feedback ();
        MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, bool force = false);
        
@@ -64,7 +67,6 @@ class MIDIControllable : public PBD::Stateful
        float control_to_midi(float val);
        float midi_to_control(float val);
 
-       void set_learned (bool yn) { _learned = yn; }
        bool learned() const { return _learned; }
 
        MIDI::Port& get_port() const { return _port; }
@@ -98,8 +100,9 @@ class MIDIControllable : public PBD::Stateful
        MIDI::channel_t  control_channel;
        std::string     _control_description;
        bool             feedback;
-
-       void init ();
+       uint32_t        _rid;
+       std::string     _what;
+       bool            _bank_relative;
        
        void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t);
        void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on);