Made master fader touch and jog go to _master_surface instead of first surface.
[ardour.git] / libs / surfaces / mackie / mackie_control_protocol.cc
index 32be8512476eee7f4436621fd9c524d111837e7c..be1144e6ac57b3d9bb078ca22c44c8ace821769f 100644 (file)
@@ -29,7 +29,6 @@
 #include <float.h>
 #include <sys/time.h>
 #include <errno.h>
-#include <poll.h>
 
 #include <boost/shared_array.hpp>
 
@@ -42,6 +41,7 @@
 #include "pbd/convert.h"
 
 #include "ardour/automation_control.h"
+#include "ardour/async_midi_port.h"
 #include "ardour/dB.h"
 #include "ardour/debug.h"
 #include "ardour/location.h"
 
 using namespace ARDOUR;
 using namespace std;
-using namespace Mackie;
 using namespace PBD;
 using namespace Glib;
+using namespace ArdourSurface;
+using namespace Mackie;
 
 #include "i18n.h"
 
@@ -96,8 +97,6 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
        , AbstractUI<MackieControlUIRequest> ("mackie")
        , _current_initial_bank (0)
        , _timecode_type (ARDOUR::AnyTime::BBT)
-       , _input_bundle (new ARDOUR::Bundle (_("Mackie Control In"), true))
-       , _output_bundle (new ARDOUR::Bundle (_("Mackie Control Out"), false))
        , _gui (0)
        , _zoom_mode (false)
        , _scrub_mode (false)
@@ -109,6 +108,9 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
        , needs_ipmidi_restart (false)
        , _metering_active (true)
        , _initialized (false)
+       , _surfaces_state (0)
+       , _surfaces_version (0)
+       , _session_load (true)
 {
        DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n");
 
@@ -132,7 +134,7 @@ MackieControlProtocol::~MackieControlProtocol()
        DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol tear_down_gui ()\n");
        tear_down_gui ();
 
-       _active = false;
+       delete _surfaces_state;
 
        /* stop event loop */
        DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol BaseUI::quit ()\n");
@@ -270,7 +272,10 @@ MackieControlProtocol::get_sorted_routes()
                if (route_is_locked_to_strip(route)) {
                        continue;
                }
-
+               /* This next section which is not used yet, looks wrong to me
+                       The first four belong here but the bottom five are not a selection
+                       of routes and belong elsewhere as they are v-pot modes.
+               */
                switch (_view_mode) {
                case Mixer:
                        break;
@@ -345,7 +350,9 @@ MackieControlProtocol::switch_banks (uint32_t initial, bool force)
 
        if (_current_initial_bank <= sorted.size()) {
 
-               DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2, available routes %3\n", _current_initial_bank, strip_cnt, sorted.size()));
+               DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2, available routes %3 on %4 surfaces\n", 
+                                                                  _current_initial_bank, strip_cnt, sorted.size(),
+                                                                  surfaces.size()));
 
                // link routes to strips
 
@@ -383,7 +390,7 @@ MackieControlProtocol::set_active (bool yn)
 {
        DEBUG_TRACE (DEBUG::MackieControl, string_compose("MackieControlProtocol::set_active init with yn: '%1'\n", yn));
 
-       if (yn == _active) {
+       if (yn == active()) {
                return 0;
        }
 
@@ -397,7 +404,6 @@ MackieControlProtocol::set_active (bool yn)
                        return -1;
                }
                connect_session_signals ();
-               _active = true;
                update_surfaces ();
                
                /* set up periodic task for metering and automation
@@ -411,10 +417,11 @@ MackieControlProtocol::set_active (bool yn)
 
                BaseUI::quit ();
                close ();
-               _active = false;
 
        }
 
+       ControlProtocol::set_active (yn);
+
        DEBUG_TRACE (DEBUG::MackieControl, string_compose("MackieControlProtocol::set_active done with yn: '%1'\n", yn));
 
        return 0;
@@ -423,7 +430,7 @@ MackieControlProtocol::set_active (bool yn)
 bool
 MackieControlProtocol::periodic ()
 {
-       if (!_active) {
+       if (!active()) {
                return false;
        }
 
@@ -487,8 +494,8 @@ MackieControlProtocol::update_global_button (int id, LedState ls)
        if (!_device_info.has_global_controls()) {
                return;
        }
-
-       boost::shared_ptr<Surface> surface = surfaces.front();
+       // surface needs to be master surface
+       boost::shared_ptr<Surface> surface = _master_surface;
 
        map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (id);
        if (x != surface->controls_by_device_independent_id.end()) {
@@ -507,8 +514,7 @@ MackieControlProtocol::update_global_led (int id, LedState ls)
        if (!_device_info.has_global_controls()) {
                return;
        }
-
-       boost::shared_ptr<Surface> surface = surfaces.front();
+       boost::shared_ptr<Surface> surface = _master_surface;
 
        map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (id);
 
@@ -521,12 +527,24 @@ MackieControlProtocol::update_global_led (int id, LedState ls)
        }
 }
 
+void
+MackieControlProtocol::device_ready ()
+{
+       /* this is not required to be called, but for devices which do
+        * handshaking, it can be called once the device has verified the
+        * connection.
+        */
+        
+       DEBUG_TRACE (DEBUG::MackieControl, string_compose ("device ready init (active=%1)\n", active()));
+       update_surfaces ();
+}
+
 // send messages to surface to set controls to correct values
 void 
 MackieControlProtocol::update_surfaces()
 {
-       DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::update_surfaces() init\n");
-       if (!_active) {
+       DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::update_surfaces() init (active=%1)\n", active()));
+       if (!active()) {
                return;
        }
 
@@ -547,13 +565,13 @@ MackieControlProtocol::initialize()
                        return;
                }
                
-               if (!surfaces.front()->active ()) {
+               if (!_master_surface->active ()) {
                        return;
                }
                
                // sometimes the jog wheel is a pot
                if (_device_info.has_jog_wheel()) {
-                       surfaces.front()->blank_jog_ring ();
+                       _master_surface->blank_jog_ring ();
                }
        }
 
@@ -609,42 +627,51 @@ MackieControlProtocol::set_profile (const string& profile_name)
 }      
 
 int
-MackieControlProtocol::set_device (const string& device_name, bool allow_activation)
+MackieControlProtocol::set_device_info (const string& device_name)
 {
        map<string,DeviceInfo>::iterator d = DeviceInfo::device_info.find (device_name);
 
-       DEBUG_TRACE (DEBUG::MackieControl, string_compose ("new device chosen %1, activation allowed ? %2\n",
-                                                          device_name, allow_activation));
+       DEBUG_TRACE (DEBUG::MackieControl, string_compose ("new device chosen %1\n", device_name));
 
        if (d == DeviceInfo::device_info.end()) {
                return -1;
        }
        
-       if (_active) {
-               clear_ports ();
-               clear_surfaces ();
+       _device_info = d->second;
+
+       return 0;
+}
+
+int
+MackieControlProtocol::set_device (const string& device_name)
+{
+       if (set_device_info (device_name)) {
+               return -1;
        }
 
-       _device_info = d->second;
+       clear_surfaces ();
 
-       if (allow_activation) {
-               set_active (true);
-       } else {
-               if (_active) {
-                       if (create_surfaces ()) {
-                               return -1;
-                       }
-                       switch_banks (0, true);
-               }
+       if (create_surfaces ()) {
+               return -1;
        }
+
+       switch_banks (0, true);
+
        return 0;
 }
 
+gboolean 
+ArdourSurface::ipmidi_input_handler (GIOChannel*, GIOCondition condition, void *data)
+{
+       ArdourSurface::MackieControlProtocol::ipMIDIHandler* ipm = static_cast<ArdourSurface::MackieControlProtocol::ipMIDIHandler*>(data);
+        return ipm->mcp->midi_input_handler (Glib::IOCondition (condition), ipm->port);
+}
+
 int
 MackieControlProtocol::create_surfaces ()
 {
        string device_name;
-       surface_type_t stype = mcu;
+       surface_type_t stype = mcu; // type not yet determined
        char buf[128];
 
        if (_device_info.extenders() == 0) {
@@ -659,18 +686,29 @@ MackieControlProtocol::create_surfaces ()
 
                boost::shared_ptr<Surface> surface;
 
+               if (n == _device_info.master_position()) {
+                       stype = mcu;
+               } else {
+                       stype = ext;
+               }
                try {
                        surface.reset (new Surface (*this, device_name, n, stype));
                } catch (...) {
                        return -1;
                }
 
+               if (n == _device_info.master_position()) {
+                       _master_surface = surface;
+               }
+
+               if (_surfaces_state) {
+                       surface->set_state (*_surfaces_state, _surfaces_version);
+               }
+
                {
                        Glib::Threads::Mutex::Lock lm (surfaces_lock);
                        surfaces.push_back (surface);
                }
-
-               /* next device will be an extender */
                
                if (_device_info.extenders() < 2) {
                        device_name = X_("mackie control #2");
@@ -678,9 +716,12 @@ MackieControlProtocol::create_surfaces ()
                        snprintf (buf, sizeof (buf), X_("mackie control #%d"), n+2);
                        device_name = buf;
                }
-               stype = ext;
 
                if (!_device_info.uses_ipmidi()) {
+
+                       _input_bundle.reset (new ARDOUR::Bundle (_("Mackie Control In"), true));
+                       _output_bundle.reset (new ARDOUR::Bundle (_("Mackie Control Out"), false));
+
                        _input_bundle->add_channel (
                                surface->port().input_port().name(),
                                ARDOUR::DataType::MIDI,
@@ -692,21 +733,53 @@ MackieControlProtocol::create_surfaces ()
                                ARDOUR::DataType::MIDI,
                                session->engine().make_port_name_non_relative (surface->port().output_port().name())
                                );
+
+                       session->BundleAddedOrRemoved ();
+
+               } else {
+                       _input_bundle.reset ((ARDOUR::Bundle*) 0);
+                       _output_bundle.reset ((ARDOUR::Bundle*) 0);
+
+                       session->BundleAddedOrRemoved ();
                }
 
-               int fd;
                MIDI::Port& input_port (surface->port().input_port());
+               AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*> (&input_port);
 
-               if ((fd = input_port.selectable ()) >= 0) {
-                       Glib::RefPtr<IOSource> psrc = IOSource::create (fd, IO_IN|IO_HUP|IO_ERR);
+               if (asp) {
 
-                       psrc->connect (sigc::bind (sigc::mem_fun (this, &MackieControlProtocol::midi_input_handler), &input_port));
-                       psrc->attach (main_loop()->get_context());
-                       
-                       // glibmm hack: for now, store only the GSource*
+                       /* async MIDI port */
+
+                       asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &MackieControlProtocol::midi_input_handler), &input_port));
+                       asp->xthread().attach (main_loop()->get_context());
+
+               } else {
 
-                       port_sources.push_back (psrc->gobj());
-                       g_source_ref (psrc->gobj());
+                       /* ipMIDI port, no IOSource method at this time */
+
+                       int fd;
+
+                       if ((fd = input_port.selectable ()) >= 0) {
+
+                                GIOChannel* ioc = g_io_channel_unix_new (fd);
+                                GSource* gsrc = g_io_create_watch (ioc, GIOCondition (G_IO_IN|G_IO_HUP|G_IO_ERR));
+                                
+                                /* hack up an object so that in the callback from the event loop
+                                   we have both the MackieControlProtocol and the input port.
+                                   
+                                   If we were using C++ for this stuff we wouldn't need this
+                                   but a nasty, not-fixable bug in the binding between C 
+                                   and C++ makes it necessary to avoid C++ for the IO
+                                   callback setup.
+                                */
+
+                                ipMIDIHandler* ipm = new ipMIDIHandler (); /* we will leak this sizeof(pointer)*2 sized object */
+                                ipm->mcp = this;
+                                ipm->port = &input_port;
+
+                                g_source_set_callback (gsrc, (GSourceFunc) ipmidi_input_handler, ipm, NULL);
+                                g_source_attach (gsrc, main_loop()->get_context()->gobj());
+                       }
                }
        }
 
@@ -716,9 +789,6 @@ MackieControlProtocol::create_surfaces ()
 void 
 MackieControlProtocol::close()
 {
-       clear_ports ();
-
-       port_connections.drop_connections ();
        session_connections.drop_connections ();
        route_connections.drop_connections ();
        periodic_connection.disconnect ();
@@ -729,39 +799,47 @@ MackieControlProtocol::close()
 XMLNode& 
 MackieControlProtocol::get_state()
 {
+       XMLNode& node (ControlProtocol::get_state());
+
        DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state init\n");
        char buf[16];
 
-       // add name of protocol
-       XMLNode* node = new XMLNode (X_("Protocol"));
-       node->add_property (X_("name"), ARDOUR::ControlProtocol::_name);
-
        // add current bank
        snprintf (buf, sizeof (buf), "%d", _current_initial_bank);
-       node->add_property (X_("bank"), buf);
+       node.add_property (X_("bank"), buf);
 
        // ipMIDI base port (possibly not used)
        snprintf (buf, sizeof (buf), "%d", _ipmidi_base);
-       node->add_property (X_("ipmidi-base"), buf);
+       node.add_property (X_("ipmidi-base"), buf);
+
+       node.add_property (X_("device-profile"), _device_profile.name());
+       node.add_property (X_("device-name"), _device_info.name());
+
+       XMLNode* snode = new XMLNode (X_("Surfaces"));
+       for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
+               snode->add_child_nocopy ((*s)->get_state());
+       }
 
-       node->add_property (X_("device-profile"), _device_profile.name());
-       node->add_property (X_("device-name"), _device_info.name());
+       node.add_child_nocopy (*snode);
 
        DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state done\n");
 
-       return *node;
+       return node;
 }
 
 int 
-MackieControlProtocol::set_state (const XMLNode & node, int /*version*/)
+MackieControlProtocol::set_state (const XMLNode & node, int version)
 {
-       DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::set_state: active %1\n", _active));
+       DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::set_state: active %1\n", active()));
 
        int retval = 0;
        const XMLProperty* prop;
        uint32_t bank = 0;
-       bool active = _active;
 
+       if (ControlProtocol::set_state (node, version)) {
+               return -1;
+       }
+       
        if ((prop = node.property (X_("ipmidi-base"))) != 0) {
                set_ipmidi_base (atoi (prop->value()));
        }
@@ -771,24 +849,26 @@ MackieControlProtocol::set_state (const XMLNode & node, int /*version*/)
                bank = atoi (prop->value());
        }
        
-       if ((prop = node.property (X_("active"))) != 0) {
-               active = string_is_affirmative (prop->value());
-       }
-
        if ((prop = node.property (X_("device-name"))) != 0) {
-               set_device (prop->value(), false);
+               set_device_info (prop->value());
        }
 
        if ((prop = node.property (X_("device-profile"))) != 0) {
                set_profile (prop->value());
        }
+       
+       XMLNode* snode = node.child (X_("Surfaces"));
+       
+       delete _surfaces_state;
+       _surfaces_state = 0;
 
-       set_active (active);
-
-       if (_active) {
-               switch_banks (bank, true);
+       if (snode) {
+               _surfaces_state = new XMLNode (*snode);
+               _surfaces_version = version;
        }
 
+       switch_banks (bank, true);
+       
        DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::set_state done\n");
 
        return retval;
@@ -850,7 +930,7 @@ MackieControlProtocol::update_timecode_display()
                return;
        }
 
-       boost::shared_ptr<Surface> surface = surfaces.front();
+       boost::shared_ptr<Surface> surface = _master_surface;
 
        if (surface->type() != mcu || !_device_info.has_timecode_display() || !surface->active ()) {
                return;
@@ -886,9 +966,11 @@ MackieControlProtocol::update_timecode_display()
 void MackieControlProtocol::notify_parameter_changed (std::string const & p)
 {
        if (p == "punch-in") {
-               update_global_button (Button::PunchIn, session->config.get_punch_in());
+               // no such button right now
+               // update_global_button (Button::PunchIn, session->config.get_punch_in());
        } else if (p == "punch-out") {
-               update_global_button (Button::PunchOut, session->config.get_punch_out());
+               // no such button right now
+               // update_global_button (Button::PunchOut, session->config.get_punch_out());
        } else if (p == "clicking") {
                // update_global_button (Button::RelayClick, Config->get_clicking());
        } else {
@@ -922,7 +1004,7 @@ MackieControlProtocol::notify_solo_active_changed (bool active)
 
        {
                Glib::Threads::Mutex::Lock lm (surfaces_lock);
-               surface = surfaces.front ();
+               surface = _master_surface;
        }
        
        map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (Led::RudeSolo);
@@ -1000,7 +1082,7 @@ MackieControlProtocol::notify_record_state_changed ()
 
        {
                Glib::Threads::Mutex::Lock lm (surfaces_lock);
-               surface = surfaces.front();
+               surface = _master_surface;
        }
                
        /* rec is a tristate */
@@ -1035,8 +1117,12 @@ list<boost::shared_ptr<ARDOUR::Bundle> >
 MackieControlProtocol::bundles ()
 {
        list<boost::shared_ptr<ARDOUR::Bundle> > b;
-       b.push_back (_input_bundle);
-       b.push_back (_output_bundle);
+
+       if (_input_bundle) {
+               b.push_back (_input_bundle);
+               b.push_back (_output_bundle);
+       }
+
        return b;
 }
 
@@ -1077,8 +1163,8 @@ MackieControlProtocol::build_button_map ()
 
 #define DEFINE_BUTTON_HANDLER(b,p,r) button_map.insert (pair<Button::ID,ButtonHandlers> ((b), ButtonHandlers ((p),(r))));
 
-       DEFINE_BUTTON_HANDLER (Button::IO, &MackieControlProtocol::io_press, &MackieControlProtocol::io_release);
-       DEFINE_BUTTON_HANDLER (Button::Sends, &MackieControlProtocol::sends_press, &MackieControlProtocol::sends_release);
+       DEFINE_BUTTON_HANDLER (Button::Track, &MackieControlProtocol::track_press, &MackieControlProtocol::track_release);
+       DEFINE_BUTTON_HANDLER (Button::Send, &MackieControlProtocol::send_press, &MackieControlProtocol::send_release);
        DEFINE_BUTTON_HANDLER (Button::Pan, &MackieControlProtocol::pan_press, &MackieControlProtocol::pan_release);
        DEFINE_BUTTON_HANDLER (Button::Plugin, &MackieControlProtocol::plugin_press, &MackieControlProtocol::plugin_release);
        DEFINE_BUTTON_HANDLER (Button::Eq, &MackieControlProtocol::eq_press, &MackieControlProtocol::eq_release);
@@ -1088,7 +1174,7 @@ MackieControlProtocol::build_button_map ()
        DEFINE_BUTTON_HANDLER (Button::ChannelLeft, &MackieControlProtocol::channel_left_press, &MackieControlProtocol::channel_left_release);
        DEFINE_BUTTON_HANDLER (Button::ChannelRight, &MackieControlProtocol::channel_right_press, &MackieControlProtocol::channel_right_release);
        DEFINE_BUTTON_HANDLER (Button::Flip, &MackieControlProtocol::flip_press, &MackieControlProtocol::flip_release);
-       DEFINE_BUTTON_HANDLER (Button::Edit, &MackieControlProtocol::edit_press, &MackieControlProtocol::edit_release);
+       DEFINE_BUTTON_HANDLER (Button::View, &MackieControlProtocol::view_press, &MackieControlProtocol::view_release);
        DEFINE_BUTTON_HANDLER (Button::NameValue, &MackieControlProtocol::name_value_press, &MackieControlProtocol::name_value_release);
        DEFINE_BUTTON_HANDLER (Button::TimecodeBeats, &MackieControlProtocol::timecode_beats_press, &MackieControlProtocol::timecode_beats_release);
        DEFINE_BUTTON_HANDLER (Button::F1, &MackieControlProtocol::F1_press, &MackieControlProtocol::F1_release);
@@ -1099,35 +1185,35 @@ MackieControlProtocol::build_button_map ()
        DEFINE_BUTTON_HANDLER (Button::F6, &MackieControlProtocol::F6_press, &MackieControlProtocol::F6_release);
        DEFINE_BUTTON_HANDLER (Button::F7, &MackieControlProtocol::F7_press, &MackieControlProtocol::F7_release);
        DEFINE_BUTTON_HANDLER (Button::F8, &MackieControlProtocol::F8_press, &MackieControlProtocol::F8_release);
-       DEFINE_BUTTON_HANDLER (Button::F9, &MackieControlProtocol::F9_press, &MackieControlProtocol::F9_release);
-       DEFINE_BUTTON_HANDLER (Button::F10, &MackieControlProtocol::F10_press, &MackieControlProtocol::F10_release);
-       DEFINE_BUTTON_HANDLER (Button::F11, &MackieControlProtocol::F11_press, &MackieControlProtocol::F11_release);
-       DEFINE_BUTTON_HANDLER (Button::F12, &MackieControlProtocol::F12_press, &MackieControlProtocol::F12_release);
-       DEFINE_BUTTON_HANDLER (Button::F13, &MackieControlProtocol::F13_press, &MackieControlProtocol::F13_release);
-       DEFINE_BUTTON_HANDLER (Button::F14, &MackieControlProtocol::F14_press, &MackieControlProtocol::F14_release);
-       DEFINE_BUTTON_HANDLER (Button::F15, &MackieControlProtocol::F15_press, &MackieControlProtocol::F15_release);
-       DEFINE_BUTTON_HANDLER (Button::F16, &MackieControlProtocol::F16_press, &MackieControlProtocol::F16_release);
+       DEFINE_BUTTON_HANDLER (Button::MidiTracks, &MackieControlProtocol::miditracks_press, &MackieControlProtocol::miditracks_release);
+       DEFINE_BUTTON_HANDLER (Button::Inputs, &MackieControlProtocol::inputs_press, &MackieControlProtocol::inputs_release);
+       DEFINE_BUTTON_HANDLER (Button::AudioTracks, &MackieControlProtocol::audiotracks_press, &MackieControlProtocol::audiotracks_release);
+       DEFINE_BUTTON_HANDLER (Button::AudioInstruments, &MackieControlProtocol::audioinstruments_press, &MackieControlProtocol::audioinstruments_release);
+       DEFINE_BUTTON_HANDLER (Button::Aux, &MackieControlProtocol::aux_press, &MackieControlProtocol::aux_release);
+       DEFINE_BUTTON_HANDLER (Button::Busses, &MackieControlProtocol::busses_press, &MackieControlProtocol::busses_release);
+       DEFINE_BUTTON_HANDLER (Button::Outputs, &MackieControlProtocol::outputs_press, &MackieControlProtocol::outputs_release);
+       DEFINE_BUTTON_HANDLER (Button::User, &MackieControlProtocol::user_press, &MackieControlProtocol::user_release);
        DEFINE_BUTTON_HANDLER (Button::Shift, &MackieControlProtocol::shift_press, &MackieControlProtocol::shift_release);
        DEFINE_BUTTON_HANDLER (Button::Option, &MackieControlProtocol::option_press, &MackieControlProtocol::option_release);
        DEFINE_BUTTON_HANDLER (Button::Ctrl, &MackieControlProtocol::control_press, &MackieControlProtocol::control_release);
        DEFINE_BUTTON_HANDLER (Button::CmdAlt, &MackieControlProtocol::cmd_alt_press, &MackieControlProtocol::cmd_alt_release);
-       DEFINE_BUTTON_HANDLER (Button::On, &MackieControlProtocol::on_press, &MackieControlProtocol::on_release);
-       DEFINE_BUTTON_HANDLER (Button::RecReady, &MackieControlProtocol::rec_ready_press, &MackieControlProtocol::rec_ready_release);
-       DEFINE_BUTTON_HANDLER (Button::Undo, &MackieControlProtocol::undo_press, &MackieControlProtocol::undo_release);
-       DEFINE_BUTTON_HANDLER (Button::Save, &MackieControlProtocol::save_press, &MackieControlProtocol::save_release);
+       DEFINE_BUTTON_HANDLER (Button::Read, &MackieControlProtocol::read_press, &MackieControlProtocol::read_release);
+       DEFINE_BUTTON_HANDLER (Button::Write, &MackieControlProtocol::write_press, &MackieControlProtocol::write_release);
+       DEFINE_BUTTON_HANDLER (Button::Trim, &MackieControlProtocol::trim_press, &MackieControlProtocol::trim_release);
        DEFINE_BUTTON_HANDLER (Button::Touch, &MackieControlProtocol::touch_press, &MackieControlProtocol::touch_release);
-       DEFINE_BUTTON_HANDLER (Button::Redo, &MackieControlProtocol::redo_press, &MackieControlProtocol::redo_release);
-       DEFINE_BUTTON_HANDLER (Button::Marker, &MackieControlProtocol::marker_press, &MackieControlProtocol::marker_release);
-       DEFINE_BUTTON_HANDLER (Button::Enter, &MackieControlProtocol::enter_press, &MackieControlProtocol::enter_release);
+       DEFINE_BUTTON_HANDLER (Button::Latch, &MackieControlProtocol::latch_press, &MackieControlProtocol::latch_release);
+       DEFINE_BUTTON_HANDLER (Button::Grp, &MackieControlProtocol::grp_press, &MackieControlProtocol::grp_release);
+       DEFINE_BUTTON_HANDLER (Button::Save, &MackieControlProtocol::save_press, &MackieControlProtocol::save_release);
+       DEFINE_BUTTON_HANDLER (Button::Undo, &MackieControlProtocol::undo_press, &MackieControlProtocol::undo_release);
        DEFINE_BUTTON_HANDLER (Button::Cancel, &MackieControlProtocol::cancel_press, &MackieControlProtocol::cancel_release);
-       DEFINE_BUTTON_HANDLER (Button::Mixer, &MackieControlProtocol::mixer_press, &MackieControlProtocol::mixer_release);
-       DEFINE_BUTTON_HANDLER (Button::FrmLeft, &MackieControlProtocol::frm_left_press, &MackieControlProtocol::frm_left_release);
-       DEFINE_BUTTON_HANDLER (Button::FrmRight, &MackieControlProtocol::frm_right_press, &MackieControlProtocol::frm_right_release);
+       DEFINE_BUTTON_HANDLER (Button::Enter, &MackieControlProtocol::enter_press, &MackieControlProtocol::enter_release);
+       DEFINE_BUTTON_HANDLER (Button::Marker, &MackieControlProtocol::marker_press, &MackieControlProtocol::marker_release);
+       DEFINE_BUTTON_HANDLER (Button::Nudge, &MackieControlProtocol::nudge_press, &MackieControlProtocol::nudge_release);
        DEFINE_BUTTON_HANDLER (Button::Loop, &MackieControlProtocol::loop_press, &MackieControlProtocol::loop_release);
-       DEFINE_BUTTON_HANDLER (Button::PunchIn, &MackieControlProtocol::punch_in_press, &MackieControlProtocol::punch_in_release);
-       DEFINE_BUTTON_HANDLER (Button::PunchOut, &MackieControlProtocol::punch_out_press, &MackieControlProtocol::punch_out_release);
-       DEFINE_BUTTON_HANDLER (Button::Home, &MackieControlProtocol::home_press, &MackieControlProtocol::home_release);
-       DEFINE_BUTTON_HANDLER (Button::End, &MackieControlProtocol::end_press, &MackieControlProtocol::end_release);
+       DEFINE_BUTTON_HANDLER (Button::Drop, &MackieControlProtocol::drop_press, &MackieControlProtocol::drop_release);
+       DEFINE_BUTTON_HANDLER (Button::Replace, &MackieControlProtocol::replace_press, &MackieControlProtocol::replace_release);
+       DEFINE_BUTTON_HANDLER (Button::Click, &MackieControlProtocol::click_press, &MackieControlProtocol::click_release);
+       DEFINE_BUTTON_HANDLER (Button::ClearSolo, &MackieControlProtocol::clearsolo_press, &MackieControlProtocol::clearsolo_release);
        DEFINE_BUTTON_HANDLER (Button::Rewind, &MackieControlProtocol::rewind_press, &MackieControlProtocol::rewind_release);
        DEFINE_BUTTON_HANDLER (Button::Ffwd, &MackieControlProtocol::ffwd_press, &MackieControlProtocol::ffwd_release);
        DEFINE_BUTTON_HANDLER (Button::Stop, &MackieControlProtocol::stop_press, &MackieControlProtocol::stop_release);
@@ -1143,29 +1229,6 @@ MackieControlProtocol::build_button_map ()
        DEFINE_BUTTON_HANDLER (Button::UserB, &MackieControlProtocol::user_b_press, &MackieControlProtocol::user_b_release);
        DEFINE_BUTTON_HANDLER (Button::MasterFaderTouch, &MackieControlProtocol::master_fader_touch_press, &MackieControlProtocol::master_fader_touch_release);
 
-       DEFINE_BUTTON_HANDLER (Button::Snapshot, &MackieControlProtocol::snapshot_press, &MackieControlProtocol::snapshot_release);
-       DEFINE_BUTTON_HANDLER (Button::Read, &MackieControlProtocol::read_press, &MackieControlProtocol::read_release);
-       DEFINE_BUTTON_HANDLER (Button::Write, &MackieControlProtocol::write_press, &MackieControlProtocol::write_release);
-       DEFINE_BUTTON_HANDLER (Button::FdrGroup, &MackieControlProtocol::fdrgroup_press, &MackieControlProtocol::fdrgroup_release);
-       DEFINE_BUTTON_HANDLER (Button::ClearSolo, &MackieControlProtocol::clearsolo_press, &MackieControlProtocol::clearsolo_release);
-       DEFINE_BUTTON_HANDLER (Button::Track, &MackieControlProtocol::track_press, &MackieControlProtocol::track_release);
-       DEFINE_BUTTON_HANDLER (Button::Send, &MackieControlProtocol::send_press, &MackieControlProtocol::send_release);
-       DEFINE_BUTTON_HANDLER (Button::MidiTracks, &MackieControlProtocol::miditracks_press, &MackieControlProtocol::miditracks_release);
-       DEFINE_BUTTON_HANDLER (Button::Inputs, &MackieControlProtocol::inputs_press, &MackieControlProtocol::inputs_release);
-       DEFINE_BUTTON_HANDLER (Button::AudioTracks, &MackieControlProtocol::audiotracks_press, &MackieControlProtocol::audiotracks_release);
-       DEFINE_BUTTON_HANDLER (Button::AudioInstruments, &MackieControlProtocol::audioinstruments_press, &MackieControlProtocol::audioinstruments_release);
-       DEFINE_BUTTON_HANDLER (Button::Aux, &MackieControlProtocol::aux_press, &MackieControlProtocol::aux_release);
-       DEFINE_BUTTON_HANDLER (Button::Busses, &MackieControlProtocol::busses_press, &MackieControlProtocol::busses_release);
-       DEFINE_BUTTON_HANDLER (Button::Outputs, &MackieControlProtocol::outputs_press, &MackieControlProtocol::outputs_release);
-       DEFINE_BUTTON_HANDLER (Button::User, &MackieControlProtocol::user_press, &MackieControlProtocol::user_release);
-       DEFINE_BUTTON_HANDLER (Button::Trim, &MackieControlProtocol::trim_press, &MackieControlProtocol::trim_release);
-       DEFINE_BUTTON_HANDLER (Button::Latch, &MackieControlProtocol::latch_press, &MackieControlProtocol::latch_release);
-       DEFINE_BUTTON_HANDLER (Button::Grp, &MackieControlProtocol::grp_press, &MackieControlProtocol::grp_release);
-       DEFINE_BUTTON_HANDLER (Button::Nudge, &MackieControlProtocol::nudge_press, &MackieControlProtocol::nudge_release);
-       DEFINE_BUTTON_HANDLER (Button::Drop, &MackieControlProtocol::drop_press, &MackieControlProtocol::drop_release);
-       DEFINE_BUTTON_HANDLER (Button::Replace, &MackieControlProtocol::replace_press, &MackieControlProtocol::replace_release);
-       DEFINE_BUTTON_HANDLER (Button::Click, &MackieControlProtocol::click_press, &MackieControlProtocol::click_release);
-       DEFINE_BUTTON_HANDLER (Button::View, &MackieControlProtocol::view_press, &MackieControlProtocol::view_release);
 }
 
 void 
@@ -1245,7 +1308,10 @@ MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port)
                */
 
                if (!_device_info.uses_ipmidi()) {
-                       CrossThreadChannel::drain (port->selectable());
+                       AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
+                       if (asp) {
+                               asp->clear ();
+                       }
                }
 
                DEBUG_TRACE (DEBUG::MackieControl, string_compose ("data available on %1\n", port->name()));
@@ -1259,15 +1325,10 @@ MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port)
 void
 MackieControlProtocol::clear_ports ()
 {
-       _input_bundle->remove_channels ();
-       _output_bundle->remove_channels ();
-
-       for (PortSources::iterator i = port_sources.begin(); i != port_sources.end(); ++i) {
-               g_source_destroy (*i);
-               g_source_unref (*i);
+       if (_input_bundle) {
+               _input_bundle->remove_channels ();
+               _output_bundle->remove_channels ();
        }
-
-       port_sources.clear ();
 }
 
 void
@@ -1382,7 +1443,7 @@ MackieControlProtocol::add_down_select_button (int surface, int strip)
 void
 MackieControlProtocol::remove_down_select_button (int surface, int strip)
 {
-       DownButtonList::iterator x = find (_down_select_buttons.begin(), _down_select_buttons.end(), (surface<<8)|(strip&0xf));
+       DownButtonList::iterator x = find (_down_select_buttons.begin(), _down_select_buttons.end(), (uint32_t) (surface<<8)|(strip&0xf));
        DEBUG_TRACE (DEBUG::MackieControl, string_compose ("removing surface %1 strip %2 from down select buttons\n", surface, strip));
        if (x != _down_select_buttons.end()) {
                _down_select_buttons.erase (x);
@@ -1581,7 +1642,7 @@ MackieControlProtocol::set_ipmidi_base (int16_t portnum)
           to restart.
        */
 
-       if (_active && _device_info.uses_ipmidi()) {
+       if (active() && _device_info.uses_ipmidi()) {
                needs_ipmidi_restart = true;
        }
 }
@@ -1589,7 +1650,6 @@ MackieControlProtocol::set_ipmidi_base (int16_t portnum)
 int
 MackieControlProtocol::ipmidi_restart ()
 {
-       clear_ports ();
        clear_surfaces ();
        if (create_surfaces ()) {
                return -1;
@@ -1602,6 +1662,7 @@ MackieControlProtocol::ipmidi_restart ()
 void
 MackieControlProtocol::clear_surfaces ()
 {
+       clear_ports ();
        Glib::Threads::Mutex::Lock lm (surfaces_lock);
        surfaces.clear ();      
 }