rename Timecode::BBT_Time::ticks_per_beat to Timecode::BBT_Time::ticks_per_bar_divisi...
[ardour.git] / libs / surfaces / mackie / mackie_control_protocol.cc
1 /*
2         Copyright (C) 2006,2007 John Anderson
3
4         This program is free software; you can redistribute it and/or modify
5         it under the terms of the GNU General Public License as published by
6         the Free Software Foundation; either version 2 of the License, or
7         (at your option) any later version.
8
9         This program is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12         GNU General Public License for more details.
13
14         You should have received a copy of the GNU General Public License
15         along with this program; if not, write to the Free Software
16         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <fcntl.h>
20 #include <iostream>
21 #include <algorithm>
22 #include <cmath>
23 #include <sstream>
24 #include <vector>
25 #include <iomanip>
26
27 #include <inttypes.h>
28 #include <float.h>
29 #include <sys/time.h>
30 #include <errno.h>
31 #include <poll.h>
32
33 #include <boost/shared_array.hpp>
34
35 #include "midi++/types.h"
36 #include "midi++/port.h"
37 #include "midi++/manager.h"
38 #include "pbd/pthread_utils.h"
39 #include "pbd/error.h"
40 #include "pbd/memento_command.h"
41 #include "pbd/convert.h"
42
43 #include "ardour/dB.h"
44 #include "ardour/debug.h"
45 #include "ardour/location.h"
46 #include "ardour/midi_ui.h"
47 #include "ardour/panner.h"
48 #include "ardour/panner_shell.h"
49 #include "ardour/route.h"
50 #include "ardour/session.h"
51 #include "ardour/tempo.h"
52 #include "ardour/types.h"
53 #include "ardour/audioengine.h"
54
55 #include "mackie_control_protocol.h"
56
57 #include "midi_byte_array.h"
58 #include "mackie_control_exception.h"
59 #include "route_signal.h"
60 #include "mackie_midi_builder.h"
61 #include "surface_port.h"
62 #include "surface.h"
63 #include "bcf_surface.h"
64 #include "mackie_surface.h"
65
66 using namespace ARDOUR;
67 using namespace std;
68 using namespace Mackie;
69 using namespace PBD;
70
71 #include "i18n.h"
72
73 #include "pbd/abstract_ui.cc" // instantiate template
74
75 MackieMidiBuilder builder;
76
77 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
78 #define ui_bind(f, ...) boost::protect (boost::bind (f, __VA_ARGS__))
79
80 extern PBD::EventLoop::InvalidationRecord* __invalidator (sigc::trackable& trackable, const char*, int);
81 #define invalidator(x) __invalidator ((x), __FILE__, __LINE__)
82
83 MackieControlProtocol::MackieControlProtocol (Session& session)
84         : ControlProtocol (session, X_("Mackie"), MidiControlUI::instance())
85         , AbstractUI<MackieControlUIRequest> ("mackie")
86         , _current_initial_bank (0)
87         , _surface (0)
88         , _jog_wheel (*this)
89         , _timecode_type (ARDOUR::AnyTime::BBT)
90         , _input_bundle (new ARDOUR::Bundle (_("Mackie Control In"), true))
91         , _output_bundle (new ARDOUR::Bundle (_("Mackie Control Out"), false))
92         , _gui (0)
93 {
94         DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n");
95
96         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
97                 audio_engine_connections, invalidator (*this), ui_bind (&MackieControlProtocol::port_connected_or_disconnected, this, _2, _4, _5),
98                 midi_ui_context ()
99                 );
100 }
101
102 MackieControlProtocol::~MackieControlProtocol()
103 {
104         DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol\n");
105
106         try {
107                 close();
108         }
109         catch (exception & e) {
110                 cout << "~MackieControlProtocol caught " << e.what() << endl;
111         }
112         catch (...) {
113                 cout << "~MackieControlProtocol caught unknown" << endl;
114         }
115
116         DEBUG_TRACE (DEBUG::MackieControl, "finished ~MackieControlProtocol::MackieControlProtocol\n");
117 }
118
119 Mackie::Surface& 
120 MackieControlProtocol::surface()
121 {
122         if (_surface == 0) {
123                 throw MackieControlException ("_surface is 0 in MackieControlProtocol::surface");
124         }
125         return *_surface;
126 }
127
128 const Mackie::SurfacePort& 
129 MackieControlProtocol::mcu_port() const
130 {
131         if (_ports.size() < 1) {
132                 return _dummy_port;
133         } else {
134                 return dynamic_cast<const MackiePort &> (*_ports[0]);
135         }
136 }
137
138 Mackie::SurfacePort& 
139 MackieControlProtocol::mcu_port()
140 {
141         if (_ports.size() < 1) {
142                 return _dummy_port;
143         } else {
144                 return dynamic_cast<MackiePort &> (*_ports[0]);
145         }
146 }
147
148 // go to the previous track.
149 // Assume that get_sorted_routes().size() > route_table.size()
150 void 
151 MackieControlProtocol::prev_track()
152 {
153         if (_current_initial_bank >= 1) {
154                 session->set_dirty();
155                 switch_banks (_current_initial_bank - 1);
156         }
157 }
158
159 // go to the next track.
160 // Assume that get_sorted_routes().size() > route_table.size()
161 void 
162 MackieControlProtocol::next_track()
163 {
164         Sorted sorted = get_sorted_routes();
165         if (_current_initial_bank + route_table.size() < sorted.size()) {
166                 session->set_dirty();
167                 switch_banks (_current_initial_bank + 1);
168         }
169 }
170
171 void 
172 MackieControlProtocol::clear_route_signals()
173 {
174         for (RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it) {
175                 delete *it;
176         }
177         route_signals.clear();
178 }
179
180 // return the port for a given id - 0 based
181 // throws an exception if no port found
182 MackiePort& 
183 MackieControlProtocol::port_for_id (uint32_t index)
184 {
185         uint32_t current_max = 0;
186         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
187                 current_max += (*it)->strips();
188                 if (index < current_max) return **it;
189         }
190
191         // oops - no matching port
192         ostringstream os;
193         os << "No port for index " << index;
194         throw MackieControlException (os.str());
195 }
196
197 // predicate for sort call in get_sorted_routes
198 struct RouteByRemoteId
199 {
200         bool operator () (const boost::shared_ptr<Route> & a, const boost::shared_ptr<Route> & b) const
201         {
202                 return a->remote_control_id() < b->remote_control_id();
203         }
204
205         bool operator () (const Route & a, const Route & b) const
206         {
207                 return a.remote_control_id() < b.remote_control_id();
208         }
209
210         bool operator () (const Route * a, const Route * b) const
211         {
212                 return a->remote_control_id() < b->remote_control_id();
213         }
214 };
215
216 MackieControlProtocol::Sorted 
217 MackieControlProtocol::get_sorted_routes()
218 {
219         Sorted sorted;
220
221         // fetch all routes
222         boost::shared_ptr<RouteList> routes = session->get_routes();
223         set<uint32_t> remote_ids;
224
225         // routes with remote_id 0 should never be added
226         // TODO verify this with ardour devs
227         // remote_ids.insert (0);
228
229         // sort in remote_id order, and exclude master, control and hidden routes
230         // and any routes that are already set.
231         for (RouteList::iterator it = routes->begin(); it != routes->end(); ++it) {
232                 Route & route = **it;
233                 if (
234                         route.active()
235                         && !route.is_master()
236                         && !route.is_hidden()
237                         && !route.is_monitor()
238                         && remote_ids.find (route.remote_control_id()) == remote_ids.end()
239                         ) {
240                         sorted.push_back (*it);
241                         remote_ids.insert (route.remote_control_id());
242                 }
243         }
244         sort (sorted.begin(), sorted.end(), RouteByRemoteId());
245         return sorted;
246 }
247
248 void 
249 MackieControlProtocol::refresh_current_bank()
250 {
251         switch_banks (_current_initial_bank);
252 }
253
254 void 
255 MackieControlProtocol::switch_banks (int initial)
256 {
257         // DON'T prevent bank switch if initial == _current_initial_bank
258         // because then this method can't be used as a refresh
259
260         // sanity checking
261         Sorted sorted = get_sorted_routes();
262         int delta = sorted.size() - route_table.size();
263         if (initial < 0 || (delta > 0 && initial > delta)) {
264                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("not switching to %1\n", initial));
265                 return;
266         }
267         _current_initial_bank = initial;
268
269         // first clear the signals from old routes
270         // taken care of by the RouteSignal destructors
271         clear_route_signals();
272
273         // now set the signals for new routes
274         if (_current_initial_bank <= sorted.size()) {
275                 // fetch the bank start and end to switch to
276                 uint32_t end_pos = min (route_table.size(), sorted.size());
277                 Sorted::iterator it = sorted.begin() + _current_initial_bank;
278                 Sorted::iterator end = sorted.begin() + _current_initial_bank + end_pos;
279
280                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2\n", _current_initial_bank, end_pos));
281
282                 // clear out routes from our table in case any have been deleted
283                 for (vector<boost::shared_ptr<Route> >::iterator i = route_table.begin(); i != route_table.end(); ++i) {
284                         i->reset ();
285                 }
286
287                 // link routes to strips
288                 uint32_t i = 0;
289                 for (; it != end && it != sorted.end(); ++it, ++i) {
290                         boost::shared_ptr<Route> route = *it;
291
292                         assert (surface().strips[i]);
293                         Strip & strip = *surface().strips[i];
294
295                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("remote id %1 connecting %2 to %3 with port %4\n", 
296                                                                            route->remote_control_id(), route->name(), strip.name(), port_for_id(i)));
297                         route_table[i] = route;
298                         RouteSignal * rs = new RouteSignal (route, *this, strip, port_for_id(i));
299                         route_signals.push_back (rs);
300                         // update strip from route
301                         rs->notify_all();
302                 }
303
304                 // create dead strips if there aren't enough routes to
305                 // fill a bank
306                 for (; i < route_table.size(); ++i) {
307                         Strip & strip = *surface().strips[i];
308                         // send zero for this strip
309                         MackiePort & port = port_for_id(i);
310                         port.write (builder.zero_strip (port, strip));
311                 }
312         }
313
314         // display the current start bank.
315         surface().display_bank_start (mcu_port(), builder, _current_initial_bank);
316 }
317
318 void 
319 MackieControlProtocol::zero_all()
320 {
321         // TODO turn off Timecode displays
322
323         // zero all strips
324         for (Surface::Strips::iterator it = surface().strips.begin(); it != surface().strips.end(); ++it) {
325                 MackiePort & port = port_for_id ((*it)->index());
326                 port.write (builder.zero_strip (port, **it));
327         }
328
329         // and the master strip
330         mcu_port().write (builder.zero_strip (dynamic_cast<MackiePort&> (mcu_port()), master_strip()));
331
332         // turn off global buttons and leds
333         // global buttons are only ever on mcu_port, so we don't have
334         // to figure out which port.
335         for (Surface::Controls::iterator it = surface().controls.begin(); it != surface().controls.end(); ++it) {
336                 Control & control = **it;
337                 if (!control.group().is_strip() && control.accepts_feedback()) {
338                         mcu_port().write (builder.zero_control (control));
339                 }
340         }
341
342         // any hardware-specific stuff
343         surface().zero_all (mcu_port(), builder);
344 }
345
346 int 
347 MackieControlProtocol::set_active (bool yn)
348 {
349         if (yn == _active) {
350                 return 0;
351         }
352         
353         try
354         {
355                 // the reason for the locking and unlocking is that
356                 // glibmm can't do a condition wait on a RecMutex
357                 if (yn) {
358                         // TODO what happens if this fails half way?
359                         
360                         // create MackiePorts
361                         {
362                                 Glib::Mutex::Lock lock (update_mutex);
363                                 create_ports();
364                         }
365                         
366                         // now initialise MackiePorts - ie exchange sysex messages
367                         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
368                                 (*it)->open();
369                         }
370                         
371                         // wait until all ports are active
372                         // TODO a more sophisticated approach would
373                         // allow things to start up with only an MCU, even if
374                         // extenders were specified but not responding.
375                         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
376                                 (*it)->wait_for_init();
377                         }
378                         
379                         // create surface object. This depends on the ports being
380                         // correctly initialised
381                         initialize_surface();
382                         connect_session_signals();
383                         
384                         // yeehah!
385                         _active = true;
386                         
387                         // send current control positions to surface
388                         // must come after _active = true otherwise it won't run
389                         update_surface();
390                 } else {
391                         close();
392                         _active = false;
393                 }
394         }
395         
396         catch (exception & e) {
397                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("set_active to false because exception caught: %1\n", e.what()));
398                 _active = false;
399                 throw;
400         }
401
402         return 0;
403 }
404
405 bool 
406 MackieControlProtocol::handle_strip_button (SurfacePort & port, Control & control, ButtonState bs, boost::shared_ptr<Route> route)
407 {
408         bool state = false;
409
410         if (bs == press) {
411                 if (control.name() == "recenable") {
412                         state = !route->record_enabled();
413                         route->set_record_enabled (state, this);
414                 } else if (control.name() == "mute") {
415                         state = !route->muted();
416                         route->set_mute (state, this);
417                 } else if (control.name() == "solo") {
418                         state = !route->soloed();
419                         route->set_solo (state, this);
420                 } else if (control.name() == "select") {
421                         // TODO make the track selected. Whatever that means.
422                         //state = default_button_press (dynamic_cast<Button&> (control));
423                 } else if (control.name() == "vselect") {
424                         // TODO could be used to select different things to apply the pot to?
425                         //state = default_button_press (dynamic_cast<Button&> (control));
426                 }
427         }
428
429         if (control.name() == "fader_touch") {
430                 state = bs == press;
431                 control.strip().gain().set_in_use (state);
432
433                 if (ARDOUR::Config->get_mackie_emulation() == "bcf" && state) {
434                         /* BCF faders don't support touch, so add a timeout to reset
435                            their `in_use' state.
436                         */
437                         port.add_in_use_timeout (control.strip().gain(), &control.strip().fader_touch());
438                 }
439         }
440
441         return state;
442 }
443
444 void 
445 MackieControlProtocol::update_led (Mackie::Button & button, Mackie::LedState ls)
446 {
447         if (ls != none) {
448                 SurfacePort * port = 0;
449                 if (button.group().is_strip()) {
450                         if (button.group().is_master()) {
451                                 port = &mcu_port();
452                         } else {
453                                 port = &port_for_id (dynamic_cast<const Strip&> (button.group()).index());
454                         }
455                 } else {
456                         port = &mcu_port();
457                 }
458                 port->write (builder.build_led (button, ls));
459         }
460 }
461
462 void 
463 MackieControlProtocol::update_timecode_beats_led()
464 {
465         switch (_timecode_type) {
466                 case ARDOUR::AnyTime::BBT:
467                         update_global_led ("beats", on);
468                         update_global_led ("timecode", off);
469                         break;
470                 case ARDOUR::AnyTime::Timecode:
471                         update_global_led ("timecode", on);
472                         update_global_led ("beats", off);
473                         break;
474                 default:
475                         ostringstream os;
476                         os << "Unknown Anytime::Type " << _timecode_type;
477                         throw runtime_error (os.str());
478         }
479 }
480
481 void 
482 MackieControlProtocol::update_global_button (const string & name, LedState ls)
483 {
484         if (surface().controls_by_name.find (name) != surface().controls_by_name.end()) {
485                 Button * button = dynamic_cast<Button*> (surface().controls_by_name[name]);
486                 mcu_port().write (builder.build_led (button->led(), ls));
487         } else {
488                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Button %1 not found\n", name));
489         }
490 }
491
492 void 
493 MackieControlProtocol::update_global_led (const string & name, LedState ls)
494 {
495         if (surface().controls_by_name.find (name) != surface().controls_by_name.end()) {
496                 Led * led = dynamic_cast<Led*> (surface().controls_by_name[name]);
497                 mcu_port().write (builder.build_led (*led, ls));
498         } else {
499                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Led %1 not found\n", name));
500         }
501 }
502
503 // send messages to surface to set controls to correct values
504 void 
505 MackieControlProtocol::update_surface()
506 {
507         if (!_active) {
508                 return;
509         }
510
511         // do the initial bank switch to connect signals
512         // _current_initial_bank is initialised by set_state
513         switch_banks (_current_initial_bank);
514         
515         /* Create a RouteSignal for the master route, if we don't already have one */
516         if (!master_route_signal) {
517                 boost::shared_ptr<Route> mr = master_route ();
518                 if (mr) {
519                         master_route_signal = boost::shared_ptr<RouteSignal> (new RouteSignal (mr, *this, master_strip(), mcu_port()));
520                         // update strip from route
521                         master_route_signal->notify_all();
522                 }
523         }
524         
525         // sometimes the jog wheel is a pot
526         surface().blank_jog_ring (mcu_port(), builder);
527         
528         // update global buttons and displays
529         notify_record_state_changed();
530         notify_transport_state_changed();
531         update_timecode_beats_led();
532 }
533
534 void 
535 MackieControlProtocol::connect_session_signals()
536 {
537         // receive routes added
538         session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_route_added, this, _1), midi_ui_context());
539         // receive record state toggled
540         session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_record_state_changed, this), midi_ui_context());
541         // receive transport state changed
542         session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_transport_state_changed, this), midi_ui_context());
543         // receive punch-in and punch-out
544         Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
545         session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
546         // receive rude solo changed
547         session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_solo_active_changed, this, _1), midi_ui_context());
548
549         // make sure remote id changed signals reach here
550         // see also notify_route_added
551         Sorted sorted = get_sorted_routes();
552
553         for (Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it) {
554                 (*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind(&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
555         }
556 }
557
558 void 
559 MackieControlProtocol::add_port (MIDI::Port & midi_input_port, MIDI::Port & midi_output_port, int number)
560 {
561         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add port %1 %2\n", midi_input_port.name(), midi_output_port.name()));
562
563         MackiePort * sport = new MackiePort (*this, midi_input_port, midi_output_port, number);
564         _ports.push_back (sport);
565         
566         sport->init_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_init, this, sport));
567         sport->active_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_active, this, sport));
568         sport->inactive_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_inactive, this, sport));
569
570         _input_bundle->add_channel (
571                 midi_input_port.name(),
572                 ARDOUR::DataType::MIDI,
573                 session->engine().make_port_name_non_relative (midi_input_port.name())
574                 );
575         
576         _output_bundle->add_channel (
577                 midi_output_port.name(),
578                 ARDOUR::DataType::MIDI,
579                 session->engine().make_port_name_non_relative (midi_output_port.name())
580                 );
581 }
582
583 void 
584 MackieControlProtocol::create_ports()
585 {
586         MIDI::Manager * mm = MIDI::Manager::instance();
587         MIDI::Port * midi_input_port = mm->add_port (
588                 new MIDI::Port (string_compose (_("%1 in"), default_port_name), MIDI::Port::IsInput, session->engine().jack())
589                 );
590         MIDI::Port * midi_output_port = mm->add_port (
591                 new MIDI::Port (string_compose (_("%1 out"), default_port_name), MIDI::Port::IsOutput, session->engine().jack())
592                 );
593
594         /* Create main port */
595
596         if (!midi_input_port->ok() || !midi_output_port->ok()) {
597                 ostringstream os;
598                 os << _("Mackie control MIDI ports could not be created; Mackie control disabled");
599                 error << os.str() << endmsg;
600                 throw MackieControlException (os.str());
601         }
602
603         add_port (*midi_input_port, *midi_output_port, 0);
604
605         /* Create extender ports */
606
607         for (uint32_t index = 1; index <= Config->get_mackie_extenders(); ++index) {
608                 MIDI::Port * midi_input_port = mm->add_port (
609                         new MIDI::Port (string_compose (_("mcu_xt_%1 in"), index), MIDI::Port::IsInput, session->engine().jack())
610                         );
611                 MIDI::Port * midi_output_port = mm->add_port (
612                         new MIDI::Port (string_compose (_("mcu_xt_%1 out"), index), MIDI::Port::IsOutput, session->engine().jack())
613                         );
614                 if (midi_input_port->ok() && midi_output_port->ok()) {
615                         add_port (*midi_input_port, *midi_output_port, index);
616                 }
617         }
618 }
619
620 boost::shared_ptr<Route> 
621 MackieControlProtocol::master_route()
622 {
623         return session->master_out ();
624 }
625
626 Strip& 
627 MackieControlProtocol::master_strip()
628 {
629         return dynamic_cast<Strip&> (*surface().groups["master"]);
630 }
631
632 void 
633 MackieControlProtocol::initialize_surface()
634 {
635         // set up the route table
636         int strips = 0;
637         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
638                 strips += (*it)->strips();
639         }
640
641         set_route_table_size (strips);
642
643         // TODO same as code in mackie_port.cc
644         string emulation = ARDOUR::Config->get_mackie_emulation();
645         if (emulation == "bcf") {
646                 _surface = new BcfSurface (strips);
647         } else if (emulation == "mcu") {
648                 _surface = new MackieSurface (strips);
649         } else {
650                 ostringstream os;
651                 os << "no Surface class found for emulation: " << emulation;
652                 throw MackieControlException (os.str());
653         }
654
655         _surface->init();
656
657         // Connect events. Must be after route table otherwise there will be trouble
658
659         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
660                 (*it)->control_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_control_event, this, _1, _2, _3));
661         }
662 }
663
664 void 
665 MackieControlProtocol::close()
666 {
667
668         // must be before other shutdown otherwise polling loop
669         // calls methods on objects that are deleted
670
671         port_connections.drop_connections ();
672         session_connections.drop_connections ();
673         route_connections.drop_connections ();
674
675         if (_surface != 0) {
676                 // These will fail if the port has gone away.
677                 // So catch the exception and do the rest of the
678                 // close afterwards
679                 // because the bcf doesn't respond to the next 3 sysex messages
680                 try {
681                         zero_all();
682                 }
683
684                 catch (exception & e) {
685                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::close caught exception: %1\n", e.what()));
686                 }
687
688                 for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
689                         try {
690                                 MackiePort & port = **it;
691                                 // faders to minimum
692                                 port.write_sysex (0x61);
693                                 // All LEDs off
694                                 port.write_sysex (0x62);
695                                 // Reset (reboot into offline mode)
696                                 port.write_sysex (0x63);
697                         }
698                         catch (exception & e) {
699                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::close caught exception: %1\n", e.what()));
700                         }
701                 }
702
703                 // disconnect routes from strips
704                 clear_route_signals();
705                 delete _surface;
706                 _surface = 0;
707         }
708
709         // shut down MackiePorts
710         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
711                 delete *it;
712         }
713
714         _ports.clear();
715 }
716
717 XMLNode& 
718 MackieControlProtocol::get_state()
719 {
720         DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state\n");
721
722         // add name of protocol
723         XMLNode* node = new XMLNode (X_("Protocol"));
724         node->add_property (X_("name"), ARDOUR::ControlProtocol::_name);
725
726         // add current bank
727         ostringstream os;
728         os << _current_initial_bank;
729         node->add_property (X_("bank"), os.str());
730
731         return *node;
732 }
733
734 int 
735 MackieControlProtocol::set_state (const XMLNode & node, int /*version*/)
736 {
737         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::set_state: active %1\n", _active));
738
739         int retval = 0;
740
741         // fetch current bank
742
743         if (node.property (X_("bank")) != 0) {
744                 string bank = node.property (X_("bank"))->value();
745                 try {
746                         set_active (true);
747                         uint32_t new_bank = atoi (bank.c_str());
748                         if (_current_initial_bank != new_bank) {
749                                 switch_banks (new_bank);
750                         }
751                 }
752                 catch (exception & e) {
753                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("exception in MackieControlProtocol::set_state: %1\n", e.what()));
754                         return -1;
755                 }
756         }
757
758         return retval;
759 }
760
761 void 
762 MackieControlProtocol::handle_control_event (SurfacePort & port, Control & control, const ControlState & state)
763 {
764         // find the route for the control, if there is one
765         boost::shared_ptr<Route> route;
766         if (control.group().is_strip()) {
767                 if (control.group().is_master()) {
768                         route = master_route();
769                 } else {
770                         uint32_t index = control.ordinal() - 1 + (port.number() * port.strips());
771                         if (index < route_table.size())
772                                 route = route_table[index];
773                         else
774                                 cerr << "Warning: index is " << index << " which is not in the route table, size: " << route_table.size() << endl;
775                 }
776         }
777
778         // This handles control element events from the surface
779         // the state of the controls on the surface is usually updated
780         // from UI events.
781         switch (control.type()) {
782                 case Control::type_fader:
783                         // find the route in the route table for the id
784                         // if the route isn't available, skip it
785                         // at which point the fader should just reset itself
786                         if (route != 0)
787                         {
788                                 route->gain_control()->set_value (slider_position_to_gain (state.pos));
789
790                                 if (ARDOUR::Config->get_mackie_emulation() == "bcf") {
791                                         /* reset the timeout while we're still moving the fader */
792                                         port.add_in_use_timeout (control, control.in_use_touch_control);
793                                 }
794
795                                 // must echo bytes back to slider now, because
796                                 // the notifier only works if the fader is not being
797                                 // touched. Which it is if we're getting input.
798                                 port.write (builder.build_fader ((Fader&)control, state.pos));
799                         }
800                         break;
801
802                 case Control::type_button:
803                         if (control.group().is_strip()) {
804                                 // strips
805                                 if (route != 0) {
806                                         handle_strip_button (port, control, state.button_state, route);
807                                 } else {
808                                         // no route so always switch the light off
809                                         // because no signals will be emitted by a non-route
810                                         port.write (builder.build_led (control.led(), off));
811                                 }
812                         } else if (control.group().is_master()) {
813                                 // master fader touch
814                                 if (route != 0) {
815                                         handle_strip_button (port, control, state.button_state, route);
816                                 }
817                         } else {
818                                 // handle all non-strip buttons
819                                 surface().handle_button (*this, state.button_state, dynamic_cast<Button&> (control));
820                         }
821                         break;
822
823                 // pot (jog wheel, external control)
824                 case Control::type_pot:
825                         if (control.group().is_strip()) {
826                                 if (route) {
827                                         boost::shared_ptr<Panner> panner = route->panner_shell()->panner();
828                                         // pan for mono input routes, or stereo linked panners
829                                         if (panner) {
830                                                 double p = panner->position ();
831                                                 
832                                                 // calculate new value, and adjust
833                                                 p += state.delta * state.sign;
834                                                 p = min (1.0, p);
835                                                 p = max (0.0, p);
836                                                 panner->set_position (p);
837                                         }
838                                 } else {
839                                         // it's a pot for an umnapped route, so turn all the lights off
840                                         port.write (builder.build_led_ring (dynamic_cast<Pot &> (control), off));
841                                 }
842                         }
843                         else
844                         {
845                                 if (control.is_jog()) {
846                                         _jog_wheel.jog_event (port, control, state);
847                                 } else {
848                                         cout << "external controller" << state.ticks * state.sign << endl;
849                                 }
850                         }
851                         break;
852
853                 default:
854                         cout << "Control::type not handled: " << control.type() << endl;
855         }
856 }
857
858 /////////////////////////////////////////////////
859 // handlers for Route signals
860 // TODO should these be part of RouteSignal?
861 // They started off as signal/slot handlers for signals
862 // from Route, but they're also used in polling for automation
863 /////////////////////////////////////////////////
864
865 void 
866 MackieControlProtocol::notify_solo_changed (RouteSignal * route_signal)
867 {
868         try {
869                 Button & button = route_signal->strip().solo();
870                 route_signal->port().write (builder.build_led (button, route_signal->route()->soloed()));
871         }
872         catch (exception & e) {
873                 cout << e.what() << endl;
874         }
875 }
876
877 void 
878 MackieControlProtocol::notify_mute_changed (RouteSignal * route_signal)
879 {
880         try {
881                 Button & button = route_signal->strip().mute();
882                 route_signal->port().write (builder.build_led (button, route_signal->route()->muted()));
883         }
884         catch (exception & e) {
885                 cout << e.what() << endl;
886         }
887 }
888
889 void 
890 MackieControlProtocol::notify_record_enable_changed (RouteSignal * route_signal)
891 {
892         try {
893                 Button & button = route_signal->strip().recenable();
894                 route_signal->port().write (builder.build_led (button, route_signal->route()->record_enabled()));
895         }
896         catch (exception & e) {
897                 cout << e.what() << endl;
898         }
899 }
900
901 void MackieControlProtocol::notify_active_changed (RouteSignal *)
902 {
903         try {
904                 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::notify_active_changed\n");
905                 refresh_current_bank();
906         }
907         catch (exception & e) {
908                 cout << e.what() << endl;
909         }
910 }
911
912 void 
913 MackieControlProtocol::notify_gain_changed (RouteSignal * route_signal, bool force_update)
914 {
915         try {
916                 Fader & fader = route_signal->strip().gain();
917                 if (!fader.in_use()) {
918                         float gain_value = gain_to_slider_position (route_signal->route()->gain_control()->get_value());
919                         // check that something has actually changed
920                         if (force_update || gain_value != route_signal->last_gain_written()) {
921                                 route_signal->port().write (builder.build_fader (fader, gain_value));
922                                 route_signal->last_gain_written (gain_value);
923                         }
924                 }
925         }
926         catch (exception & e) {
927                 cout << e.what() << endl;
928         }
929 }
930
931 void 
932 MackieControlProtocol::notify_property_changed (const PropertyChange& what_changed, RouteSignal * route_signal)
933 {
934         if (!what_changed.contains (Properties::name)) {
935                 return;
936         }
937
938         try {
939                 Strip & strip = route_signal->strip();
940                 
941                 /* XXX: not sure about this check to only display stuff for strips of index < 8 */
942                 if (!strip.is_master() && strip.index() < 8) {
943                         string line1;
944                         string fullname = route_signal->route()->name();
945
946                         if (fullname.length() <= 6) {
947                                 line1 = fullname;
948                         } else {
949                                 line1 = PBD::short_version (fullname, 6);
950                         }
951
952                         SurfacePort & port = route_signal->port();
953                         port.write (builder.strip_display (port, strip, 0, line1));
954                         port.write (builder.strip_display_blank (port, strip, 1));
955                 }
956         }
957         catch (exception & e) {
958                 cout << e.what() << endl;
959         }
960 }
961
962 void 
963 MackieControlProtocol::notify_panner_changed (RouteSignal * route_signal, bool force_update)
964 {
965         try {
966                 Pot & pot = route_signal->strip().vpot();
967                 boost::shared_ptr<Panner> panner = route_signal->route()->panner();
968                 if (panner) {
969                         double pos = panner->position ();
970
971                         // cache the MidiByteArray here, because the mackie led control is much lower
972                         // resolution than the panner control. So we save lots of byte
973                         // sends in spite of more work on the comparison
974                         MidiByteArray bytes = builder.build_led_ring (pot, ControlState (on, pos), MackieMidiBuilder::midi_pot_mode_dot);
975                         // check that something has actually changed
976                         if (force_update || bytes != route_signal->last_pan_written())
977                         {
978                                 route_signal->port().write (bytes);
979                                 route_signal->last_pan_written (bytes);
980                         }
981                 } else {
982                         route_signal->port().write (builder.zero_control (pot));
983                 }
984         }
985         catch (exception & e) {
986                 cout << e.what() << endl;
987         }
988 }
989
990 // TODO handle plugin automation polling
991 void 
992 MackieControlProtocol::update_automation (RouteSignal & rs)
993 {
994         ARDOUR::AutoState gain_state = rs.route()->gain_control()->automation_state();
995
996         if (gain_state == Touch || gain_state == Play) {
997                 notify_gain_changed (&rs, false);
998         }
999
1000         if (rs.route()->panner()) {
1001                 ARDOUR::AutoState panner_state = rs.route()->panner()->automation_state();
1002                 if (panner_state == Touch || panner_state == Play) {
1003                         notify_panner_changed (&rs, false);
1004                 }
1005         }
1006 }
1007
1008 string 
1009 MackieControlProtocol::format_bbt_timecode (framepos_t now_frame)
1010 {
1011         Timecode::BBT_Time bbt_time;
1012         session->bbt_time (now_frame, bbt_time);
1013
1014         // According to the Logic docs
1015         // digits: 888/88/88/888
1016         // BBT mode: Bars/Beats/Subdivisions/Ticks
1017         ostringstream os;
1018         os << setw(3) << setfill('0') << bbt_time.bars;
1019         os << setw(2) << setfill('0') << bbt_time.beats;
1020
1021         // figure out subdivisions per beat
1022         const Meter & meter = session->tempo_map().meter_at (now_frame);
1023         int subdiv = 2;
1024         if (meter.note_divisor() == 8 && (meter.divisions_per_bar() == 12.0 || meter.divisions_per_bar() == 9.0 || meter.divisions_per_bar() == 6.0)) {
1025                 subdiv = 3;
1026         }
1027
1028         uint32_t subdivisions = bbt_time.ticks / uint32_t (Timecode::BBT_Time::ticks_per_bar_division / subdiv);
1029         uint32_t ticks = bbt_time.ticks % uint32_t (Timecode::BBT_Time::ticks_per_bar_division / subdiv);
1030
1031         os << setw(2) << setfill('0') << subdivisions + 1;
1032         os << setw(3) << setfill('0') << ticks;
1033
1034         return os.str();
1035 }
1036
1037 string 
1038 MackieControlProtocol::format_timecode_timecode (framepos_t now_frame)
1039 {
1040         Timecode::Time timecode;
1041         session->timecode_time (now_frame, timecode);
1042
1043         // According to the Logic docs
1044         // digits: 888/88/88/888
1045         // Timecode mode: Hours/Minutes/Seconds/Frames
1046         ostringstream os;
1047         os << setw(3) << setfill('0') << timecode.hours;
1048         os << setw(2) << setfill('0') << timecode.minutes;
1049         os << setw(2) << setfill('0') << timecode.seconds;
1050         os << setw(3) << setfill('0') << timecode.frames;
1051
1052         return os.str();
1053 }
1054
1055 void 
1056 MackieControlProtocol::update_timecode_display()
1057 {
1058         if (surface().has_timecode_display()) {
1059                 // do assignment here so current_frame is fixed
1060                 framepos_t current_frame = session->transport_frame();
1061                 string timecode;
1062
1063                 switch (_timecode_type) {
1064                         case ARDOUR::AnyTime::BBT:
1065                                 timecode = format_bbt_timecode (current_frame);
1066                                 break;
1067                         case ARDOUR::AnyTime::Timecode:
1068                                 timecode = format_timecode_timecode (current_frame);
1069                                 break;
1070                         default:
1071                                 ostringstream os;
1072                                 os << "Unknown timecode: " << _timecode_type;
1073                                 throw runtime_error (os.str());
1074                 }
1075
1076                 // only write the timecode string to the MCU if it's changed
1077                 // since last time. This is to reduce midi bandwidth used.
1078                 if (timecode != _timecode_last) {
1079                         surface().display_timecode (mcu_port(), builder, timecode, _timecode_last);
1080                         _timecode_last = timecode;
1081                 }
1082         }
1083 }
1084
1085 void 
1086 MackieControlProtocol::poll_session_data()
1087 {
1088         // XXX need to attach this to a timer in the MIDI UI event loop (20msec)
1089
1090         if (_active) {
1091                 // do all currently mapped routes
1092                 for (RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it) {
1093                         update_automation (**it);
1094                 }
1095
1096                 // and the master strip
1097                 if (master_route_signal != 0) {
1098                         update_automation (*master_route_signal);
1099                 }
1100
1101                 update_timecode_display();
1102         }
1103 }
1104
1105 /////////////////////////////////////
1106 // Transport Buttons
1107 /////////////////////////////////////
1108
1109 LedState 
1110 MackieControlProtocol::frm_left_press (Button &)
1111 {
1112         // can use first_mark_before/after as well
1113         unsigned long elapsed = _frm_left_last.restart();
1114
1115         Location * loc = session->locations()->first_location_before (
1116                 session->transport_frame()
1117         );
1118
1119         // allow a quick double to go past a previous mark
1120         if (session->transport_rolling() && elapsed < 500 && loc != 0) {
1121                 Location * loc_two_back = session->locations()->first_location_before (loc->start());
1122                 if (loc_two_back != 0)
1123                 {
1124                         loc = loc_two_back;
1125                 }
1126         }
1127
1128         // move to the location, if it's valid
1129         if (loc != 0) {
1130                 session->request_locate (loc->start(), session->transport_rolling());
1131         }
1132
1133         return on;
1134 }
1135
1136 LedState 
1137 MackieControlProtocol::frm_left_release (Button &)
1138 {
1139         return off;
1140 }
1141
1142 LedState 
1143 MackieControlProtocol::frm_right_press (Button &)
1144 {
1145         // can use first_mark_before/after as well
1146         Location * loc = session->locations()->first_location_after (session->transport_frame());
1147         
1148         if (loc != 0) {
1149                 session->request_locate (loc->start(), session->transport_rolling());
1150         }
1151                 
1152         return on;
1153 }
1154
1155 LedState 
1156 MackieControlProtocol::frm_right_release (Button &)
1157 {
1158         return off;
1159 }
1160
1161 LedState 
1162 MackieControlProtocol::stop_press (Button &)
1163 {
1164         session->request_stop();
1165         return on;
1166 }
1167
1168 LedState 
1169 MackieControlProtocol::stop_release (Button &)
1170 {
1171         return session->transport_stopped();
1172 }
1173
1174 LedState 
1175 MackieControlProtocol::play_press (Button &)
1176 {
1177         session->request_transport_speed (1.0);
1178         return on;
1179 }
1180
1181 LedState 
1182 MackieControlProtocol::play_release (Button &)
1183 {
1184         return session->transport_rolling();
1185 }
1186
1187 LedState 
1188 MackieControlProtocol::record_press (Button &)
1189 {
1190         if (session->get_record_enabled()) {
1191                 session->disable_record (false);
1192         } else {
1193                 session->maybe_enable_record();
1194         }
1195         return on;
1196 }
1197
1198 LedState 
1199 MackieControlProtocol::record_release (Button &)
1200 {
1201         if (session->get_record_enabled()) {
1202                 if (session->transport_rolling()) {
1203                         return on;
1204                 } else {
1205                         return flashing;
1206                 }
1207         } else {
1208                 return off;
1209         }
1210 }
1211
1212 LedState 
1213 MackieControlProtocol::rewind_press (Button &)
1214 {
1215         _jog_wheel.push (JogWheel::speed);
1216         _jog_wheel.transport_direction (-1);
1217         session->request_transport_speed (-_jog_wheel.transport_speed());
1218         return on;
1219 }
1220
1221 LedState 
1222 MackieControlProtocol::rewind_release (Button &)
1223 {
1224         _jog_wheel.pop();
1225         _jog_wheel.transport_direction (0);
1226         if (_transport_previously_rolling) {
1227                 session->request_transport_speed (1.0);
1228         } else {
1229                 session->request_stop();
1230         }
1231         return off;
1232 }
1233
1234 LedState 
1235 MackieControlProtocol::ffwd_press (Button &)
1236 {
1237         _jog_wheel.push (JogWheel::speed);
1238         _jog_wheel.transport_direction (1);
1239         session->request_transport_speed (_jog_wheel.transport_speed());
1240         return on;
1241 }
1242
1243 LedState 
1244 MackieControlProtocol::ffwd_release (Button &)
1245 {
1246         _jog_wheel.pop();
1247         _jog_wheel.transport_direction (0);
1248         if (_transport_previously_rolling) {
1249                 session->request_transport_speed (1.0);
1250         } else {
1251                 session->request_stop();
1252         }
1253         return off;
1254 }
1255
1256 LedState 
1257 MackieControlProtocol::loop_press (Button &)
1258 {
1259         session->request_play_loop (!session->get_play_loop());
1260         return on;
1261 }
1262
1263 LedState 
1264 MackieControlProtocol::loop_release (Button &)
1265 {
1266         return session->get_play_loop();
1267 }
1268
1269 LedState 
1270 MackieControlProtocol::punch_in_press (Button &)
1271 {
1272         bool const state = !session->config.get_punch_in();
1273         session->config.set_punch_in (state);
1274         return state;
1275 }
1276
1277 LedState 
1278 MackieControlProtocol::punch_in_release (Button &)
1279 {
1280         return session->config.get_punch_in();
1281 }
1282
1283 LedState 
1284 MackieControlProtocol::punch_out_press (Button &)
1285 {
1286         bool const state = !session->config.get_punch_out();
1287         session->config.set_punch_out (state);
1288         return state;
1289 }
1290
1291 LedState 
1292 MackieControlProtocol::punch_out_release (Button &)
1293 {
1294         return session->config.get_punch_out();
1295 }
1296
1297 LedState 
1298 MackieControlProtocol::home_press (Button &)
1299 {
1300         session->goto_start();
1301         return on;
1302 }
1303
1304 LedState 
1305 MackieControlProtocol::home_release (Button &)
1306 {
1307         return off;
1308 }
1309
1310 LedState 
1311 MackieControlProtocol::end_press (Button &)
1312 {
1313         session->goto_end();
1314         return on;
1315 }
1316
1317 LedState 
1318 MackieControlProtocol::end_release (Button &)
1319 {
1320         return off;
1321 }
1322
1323 LedState 
1324 MackieControlProtocol::clicking_press (Button &)
1325 {
1326         bool state = !Config->get_clicking();
1327         Config->set_clicking (state);
1328         return state;
1329 }
1330
1331 LedState 
1332 MackieControlProtocol::clicking_release (Button &)
1333 {
1334         return Config->get_clicking();
1335 }
1336
1337 LedState MackieControlProtocol::global_solo_press (Button &)
1338 {
1339         bool state = !session->soloing();
1340         session->set_solo (session->get_routes(), state);
1341         return state;
1342 }
1343
1344 LedState MackieControlProtocol::global_solo_release (Button &)
1345 {
1346         return session->soloing();
1347 }
1348
1349 ///////////////////////////////////////////
1350 // Session signals
1351 ///////////////////////////////////////////
1352
1353 void MackieControlProtocol::notify_parameter_changed (std::string const & p)
1354 {
1355         if (p == "punch-in") {
1356                 update_global_button ("punch_in", session->config.get_punch_in());
1357         } else if (p == "punch-out") {
1358                 update_global_button ("punch_out", session->config.get_punch_out());
1359         } else if (p == "clicking") {
1360                 update_global_button ("clicking", Config->get_clicking());
1361         } else {
1362                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("parameter changed: %1\n", p));
1363         }
1364 }
1365
1366 // RouteList is the set of routes that have just been added
1367 void 
1368 MackieControlProtocol::notify_route_added (ARDOUR::RouteList & rl)
1369 {
1370         // currently assigned banks are less than the full set of
1371         // strips, so activate the new strip now.
1372         if (route_signals.size() < route_table.size()) {
1373                 refresh_current_bank();
1374         }
1375         // otherwise route added, but current bank needs no updating
1376
1377         // make sure remote id changes in the new route are handled
1378         typedef ARDOUR::RouteList ARS;
1379
1380         for (ARS::iterator it = rl.begin(); it != rl.end(); ++it) {
1381                 (*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
1382         }
1383 }
1384
1385 void 
1386 MackieControlProtocol::notify_solo_active_changed (bool active)
1387 {
1388         Button * rude_solo = reinterpret_cast<Button*> (surface().controls_by_name["solo"]);
1389         mcu_port().write (builder.build_led (*rude_solo, active ? flashing : off));
1390 }
1391
1392 void 
1393 MackieControlProtocol::notify_remote_id_changed()
1394 {
1395         Sorted sorted = get_sorted_routes();
1396
1397         // if a remote id has been moved off the end, we need to shift
1398         // the current bank backwards.
1399         if (sorted.size() - _current_initial_bank < route_signals.size()) {
1400                 // but don't shift backwards past the zeroth channel
1401                 switch_banks (max((Sorted::size_type) 0, sorted.size() - route_signals.size()));
1402         } else {
1403                 // Otherwise just refresh the current bank
1404                 refresh_current_bank();
1405         }
1406 }
1407
1408 ///////////////////////////////////////////
1409 // Transport signals
1410 ///////////////////////////////////////////
1411
1412 void 
1413 MackieControlProtocol::notify_record_state_changed()
1414 {
1415         // switch rec button on / off / flashing
1416         Button * rec = reinterpret_cast<Button*> (surface().controls_by_name["record"]);
1417         mcu_port().write (builder.build_led (*rec, record_release (*rec)));
1418 }
1419
1420 void 
1421 MackieControlProtocol::notify_transport_state_changed()
1422 {
1423         // switch various play and stop buttons on / off
1424         update_global_button ("play", session->transport_rolling());
1425         update_global_button ("stop", !session->transport_rolling());
1426         update_global_button ("loop", session->get_play_loop());
1427
1428         _transport_previously_rolling = session->transport_rolling();
1429
1430         // rec is special because it's tristate
1431         Button * rec = reinterpret_cast<Button*> (surface().controls_by_name["record"]);
1432         mcu_port().write (builder.build_led (*rec, record_release (*rec)));
1433 }
1434
1435 /////////////////////////////////////
1436 // Bank Switching
1437 /////////////////////////////////////
1438 LedState 
1439 MackieControlProtocol::left_press (Button &)
1440 {
1441         Sorted sorted = get_sorted_routes();
1442         if (sorted.size() > route_table.size()) {
1443                 int new_initial = _current_initial_bank - route_table.size();
1444                 if (new_initial < 0) {
1445                         new_initial = 0;
1446                 }
1447                 
1448                 if (new_initial != int (_current_initial_bank)) {
1449                         session->set_dirty();
1450                         switch_banks (new_initial);
1451                 }
1452
1453                 return on;
1454         } else {
1455                 return flashing;
1456         }
1457 }
1458
1459 LedState 
1460 MackieControlProtocol::left_release (Button &)
1461 {
1462         return off;
1463 }
1464
1465 LedState 
1466 MackieControlProtocol::right_press (Button &)
1467 {
1468         Sorted sorted = get_sorted_routes();
1469         if (sorted.size() > route_table.size()) {
1470                 uint32_t delta = sorted.size() - (route_table.size() + _current_initial_bank);
1471
1472                 if (delta > route_table.size()) {
1473                         delta = route_table.size();
1474                 }
1475                 
1476                 if (delta > 0) {
1477                         session->set_dirty();
1478                         switch_banks (_current_initial_bank + delta);
1479                 }
1480
1481                 return on;
1482         } else {
1483                 return flashing;
1484         }
1485 }
1486
1487 LedState 
1488 MackieControlProtocol::right_release (Button &)
1489 {
1490         return off;
1491 }
1492
1493 LedState 
1494 MackieControlProtocol::channel_left_press (Button &)
1495 {
1496         Sorted sorted = get_sorted_routes();
1497         if (sorted.size() > route_table.size()) {
1498                 prev_track();
1499                 return on;
1500         } else {
1501                 return flashing;
1502         }
1503 }
1504
1505 LedState 
1506 MackieControlProtocol::channel_left_release (Button &)
1507 {
1508         return off;
1509 }
1510
1511 LedState 
1512 MackieControlProtocol::channel_right_press (Button &)
1513 {
1514         Sorted sorted = get_sorted_routes();
1515         if (sorted.size() > route_table.size()) {
1516                 next_track();
1517                 return on;
1518         } else {
1519                 return flashing;
1520         }
1521 }
1522
1523 LedState 
1524 MackieControlProtocol::channel_right_release (Button &)
1525 {
1526         return off;
1527 }
1528
1529 /////////////////////////////////////
1530 // Functions
1531 /////////////////////////////////////
1532 LedState 
1533 MackieControlProtocol::marker_press (Button &)
1534 {
1535         // cut'n'paste from LocationUI::add_new_location()
1536         string markername;
1537         framepos_t where = session->audible_frame();
1538         session->locations()->next_available_name(markername,"mcu");
1539         Location *location = new Location (*session, where, where, markername, Location::IsMark);
1540         session->begin_reversible_command (_("add marker"));
1541         XMLNode &before = session->locations()->get_state();
1542         session->locations()->add (location, true);
1543         XMLNode &after = session->locations()->get_state();
1544         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
1545         session->commit_reversible_command ();
1546         return on;
1547 }
1548
1549 LedState 
1550 MackieControlProtocol::marker_release (Button &)
1551 {
1552         return off;
1553 }
1554
1555 void 
1556 jog_wheel_state_display (JogWheel::State state, SurfacePort & port)
1557 {
1558         switch (state) {
1559                 case JogWheel::zoom:
1560                         port.write (builder.two_char_display ("Zm"));
1561                         break;
1562                 case JogWheel::scroll:
1563                         port.write (builder.two_char_display ("Sc"));
1564                         break;
1565                 case JogWheel::scrub:
1566                         port.write (builder.two_char_display ("Sb"));
1567                         break;
1568                 case JogWheel::shuttle:
1569                         port.write (builder.two_char_display ("Sh"));
1570                         break;
1571                 case JogWheel::speed:
1572                         port.write (builder.two_char_display ("Sp"));
1573                         break;
1574                 case JogWheel::select:
1575                         port.write (builder.two_char_display ("Se"));
1576                         break;
1577         }
1578 }
1579
1580 Mackie::LedState 
1581 MackieControlProtocol::zoom_press (Mackie::Button &)
1582 {
1583         _jog_wheel.zoom_state_toggle();
1584         update_global_button ("scrub", _jog_wheel.jog_wheel_state() == JogWheel::scrub);
1585         jog_wheel_state_display (_jog_wheel.jog_wheel_state(), mcu_port());
1586         return _jog_wheel.jog_wheel_state() == JogWheel::zoom;
1587 }
1588
1589 Mackie::LedState 
1590 MackieControlProtocol::zoom_release (Mackie::Button &)
1591 {
1592         return _jog_wheel.jog_wheel_state() == JogWheel::zoom;
1593 }
1594
1595 Mackie::LedState 
1596 MackieControlProtocol::scrub_press (Mackie::Button &)
1597 {
1598         _jog_wheel.scrub_state_cycle();
1599         update_global_button ("zoom", _jog_wheel.jog_wheel_state() == JogWheel::zoom);
1600         jog_wheel_state_display (_jog_wheel.jog_wheel_state(), mcu_port());
1601         return (
1602                 _jog_wheel.jog_wheel_state() == JogWheel::scrub
1603                 ||
1604                 _jog_wheel.jog_wheel_state() == JogWheel::shuttle
1605                 );
1606 }
1607
1608 Mackie::LedState 
1609 MackieControlProtocol::scrub_release (Mackie::Button &)
1610 {
1611         return (
1612                 _jog_wheel.jog_wheel_state() == JogWheel::scrub
1613                 ||
1614                 _jog_wheel.jog_wheel_state() == JogWheel::shuttle
1615                 );
1616 }
1617
1618 LedState 
1619 MackieControlProtocol::drop_press (Button &)
1620 {
1621         session->remove_last_capture();
1622         return on;
1623 }
1624
1625 LedState 
1626 MackieControlProtocol::drop_release (Button &)
1627 {
1628         return off;
1629 }
1630
1631 LedState 
1632 MackieControlProtocol::save_press (Button &)
1633 {
1634         session->save_state ("");
1635         return on;
1636 }
1637
1638 LedState 
1639 MackieControlProtocol::save_release (Button &)
1640 {
1641         return off;
1642 }
1643
1644 LedState 
1645 MackieControlProtocol::timecode_beats_press (Button &)
1646 {
1647         switch (_timecode_type) {
1648         case ARDOUR::AnyTime::BBT:
1649                 _timecode_type = ARDOUR::AnyTime::Timecode;
1650                 break;
1651         case ARDOUR::AnyTime::Timecode:
1652                 _timecode_type = ARDOUR::AnyTime::BBT;
1653                 break;
1654         default:
1655                 ostringstream os;
1656                 os << "Unknown Anytime::Type " << _timecode_type;
1657                 throw runtime_error (os.str());
1658         }
1659         update_timecode_beats_led();
1660         return on;
1661 }
1662
1663 LedState 
1664 MackieControlProtocol::timecode_beats_release (Button &)
1665 {
1666         return off;
1667 }
1668
1669 list<boost::shared_ptr<ARDOUR::Bundle> >
1670 MackieControlProtocol::bundles ()
1671 {
1672         list<boost::shared_ptr<ARDOUR::Bundle> > b;
1673         b.push_back (_input_bundle);
1674         b.push_back (_output_bundle);
1675         return b;
1676 }
1677
1678 void
1679 MackieControlProtocol::port_connected_or_disconnected (string a, string b, bool connected)
1680 {
1681         /* If something is connected to one of our output ports, send MIDI to update the surface
1682            to whatever state it should have.
1683         */
1684
1685         if (!connected) {
1686                 return;
1687         }
1688
1689         MackiePorts::const_iterator i = _ports.begin();
1690         while (i != _ports.end()) {
1691
1692                 string const n = AudioEngine::instance()->make_port_name_non_relative ((*i)->output_port().name ());
1693
1694                 if (a == n || b == n) {
1695                         break;
1696                 }
1697
1698                 ++i;
1699         }
1700
1701         if (i != _ports.end ()) {
1702                 update_surface ();
1703         }
1704 }
1705
1706 void
1707 MackieControlProtocol::do_request (MackieControlUIRequest* req)
1708 {
1709         if (req->type == CallSlot) {
1710
1711                 call_slot (MISSING_INVALIDATOR, req->the_slot);
1712
1713         } else if (req->type == Quit) {
1714
1715                 stop ();
1716         }
1717 }
1718
1719 int
1720 MackieControlProtocol::stop ()
1721 {
1722         BaseUI::quit ();
1723
1724         return 0;
1725 }