MCP: register thread with GUI and create session event pool
[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/meter.h"
48 #include "ardour/panner.h"
49 #include "ardour/panner_shell.h"
50 #include "ardour/route.h"
51 #include "ardour/session.h"
52 #include "ardour/tempo.h"
53 #include "ardour/types.h"
54 #include "ardour/audioengine.h"
55
56 #include "mackie_control_protocol.h"
57
58 #include "midi_byte_array.h"
59 #include "mackie_control_exception.h"
60 #include "route_signal.h"
61 #include "mackie_midi_builder.h"
62 #include "surface_port.h"
63 #include "surface.h"
64 #include "bcf_surface.h"
65 #include "mackie_surface.h"
66
67 #include "strip.h"
68 #include "control_group.h"
69 #include "meter.h"
70 #include "button.h"
71 #include "fader.h"
72 #include "pot.h"
73
74 using namespace ARDOUR;
75 using namespace std;
76 using namespace Mackie;
77 using namespace PBD;
78
79 #include "i18n.h"
80
81 #include "pbd/abstract_ui.cc" // instantiate template
82
83 #define NUCLEUS_DEBUG 1
84
85 MackieMidiBuilder builder;
86
87 #define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
88 #define ui_bind(f, ...) boost::protect (boost::bind (f, __VA_ARGS__))
89
90 extern PBD::EventLoop::InvalidationRecord* __invalidator (sigc::trackable& trackable, const char*, int);
91 #define invalidator(x) __invalidator ((x), __FILE__, __LINE__)
92
93 MackieControlProtocol::MackieControlProtocol (Session& session)
94         : ControlProtocol (session, X_("Mackie"), MidiControlUI::instance())
95         , AbstractUI<MackieControlUIRequest> ("mackie")
96         , _current_initial_bank (0)
97         , _surface (0)
98         , _jog_wheel (*this)
99         , _timecode_type (ARDOUR::AnyTime::BBT)
100         , _input_bundle (new ARDOUR::Bundle (_("Mackie Control In"), true))
101         , _output_bundle (new ARDOUR::Bundle (_("Mackie Control Out"), false))
102         , _gui (0)
103         , _zoom_mode (false)
104         , _current_selected_track (-1)
105 {
106         DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n");
107
108         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
109                 audio_engine_connections, invalidator (*this), ui_bind (&MackieControlProtocol::port_connected_or_disconnected, this, _2, _4, _5),
110                 midi_ui_context ()
111                 );
112 }
113
114 MackieControlProtocol::~MackieControlProtocol()
115 {
116         DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol\n");
117
118         _active = false;
119
120         try {
121                 close();
122         }
123         catch (exception & e) {
124                 cout << "~MackieControlProtocol caught " << e.what() << endl;
125         }
126         catch (...) {
127                 cout << "~MackieControlProtocol caught unknown" << endl;
128         }
129
130         DEBUG_TRACE (DEBUG::MackieControl, "finished ~MackieControlProtocol::MackieControlProtocol\n");
131 }
132
133 void
134 MackieControlProtocol::thread_init ()
135 {
136         PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self(), X_("MackieControl"), 2048);
137         ARDOUR::SessionEvent::create_per_thread_pool (X_("MackieControl"), 128);
138 }
139
140 Mackie::Surface& 
141 MackieControlProtocol::surface()
142 {
143         if (_surface == 0) {
144                 throw MackieControlException ("_surface is 0 in MackieControlProtocol::surface");
145         }
146         return *_surface;
147 }
148
149 const Mackie::SurfacePort& 
150 MackieControlProtocol::mcu_port() const
151 {
152         if (_ports.size() < 1) {
153                 return _dummy_port;
154         } else {
155                 return dynamic_cast<const MackiePort &> (*_ports[0]);
156         }
157 }
158
159 Mackie::SurfacePort& 
160 MackieControlProtocol::mcu_port()
161 {
162         if (_ports.size() < 1) {
163                 return _dummy_port;
164         } else {
165                 return dynamic_cast<MackiePort &> (*_ports[0]);
166         }
167 }
168
169 // go to the previous track.
170 // Assume that get_sorted_routes().size() > route_table.size()
171 void 
172 MackieControlProtocol::prev_track()
173 {
174         if (_current_initial_bank >= 1) {
175                 session->set_dirty();
176                 switch_banks (_current_initial_bank - 1);
177         }
178 }
179
180 // go to the next track.
181 // Assume that get_sorted_routes().size() > route_table.size()
182 void 
183 MackieControlProtocol::next_track()
184 {
185         Sorted sorted = get_sorted_routes();
186         if (_current_initial_bank + route_table.size() < sorted.size()) {
187                 session->set_dirty();
188                 switch_banks (_current_initial_bank + 1);
189         }
190 }
191
192 void 
193 MackieControlProtocol::clear_route_signals()
194 {
195         Glib::Mutex::Lock lm (route_signals_lock);
196
197         for (RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it) {
198                 delete *it;
199         }
200
201         route_signals.clear();
202 }
203
204 // return the port for a given id - 0 based
205 // throws an exception if no port found
206 MackiePort& 
207 MackieControlProtocol::port_for_id (uint32_t index)
208 {
209         uint32_t current_max = 0;
210
211         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
212                 current_max += (*it)->strips();
213                 if (index < current_max) { 
214                         return **it;
215                 }
216         }
217
218         // oops - no matching port
219         ostringstream os;
220         os << "No port for index " << index;
221         cerr << "No port for index " << index << endl;
222         throw MackieControlException (os.str());
223 }
224
225 // predicate for sort call in get_sorted_routes
226 struct RouteByRemoteId
227 {
228         bool operator () (const boost::shared_ptr<Route> & a, const boost::shared_ptr<Route> & b) const
229         {
230                 return a->remote_control_id() < b->remote_control_id();
231         }
232
233         bool operator () (const Route & a, const Route & b) const
234         {
235                 return a.remote_control_id() < b.remote_control_id();
236         }
237
238         bool operator () (const Route * a, const Route * b) const
239         {
240                 return a->remote_control_id() < b->remote_control_id();
241         }
242 };
243
244 MackieControlProtocol::Sorted 
245 MackieControlProtocol::get_sorted_routes()
246 {
247         Sorted sorted;
248
249         // fetch all routes
250         boost::shared_ptr<RouteList> routes = session->get_routes();
251         set<uint32_t> remote_ids;
252
253         // routes with remote_id 0 should never be added
254         // TODO verify this with ardour devs
255         // remote_ids.insert (0);
256
257         // sort in remote_id order, and exclude master, control and hidden routes
258         // and any routes that are already set.
259         for (RouteList::iterator it = routes->begin(); it != routes->end(); ++it) {
260                 Route & route = **it;
261                 if (
262                         route.active()
263                         && !route.is_master()
264                         && !route.is_hidden()
265                         && !route.is_monitor()
266                         && remote_ids.find (route.remote_control_id()) == remote_ids.end()
267                         ) {
268                         sorted.push_back (*it);
269                         remote_ids.insert (route.remote_control_id());
270                 }
271         }
272         sort (sorted.begin(), sorted.end(), RouteByRemoteId());
273         return sorted;
274 }
275
276 void 
277 MackieControlProtocol::refresh_current_bank()
278 {
279         switch_banks (_current_initial_bank);
280 }
281
282 void 
283 MackieControlProtocol::switch_banks (int initial)
284 {
285         // DON'T prevent bank switch if initial == _current_initial_bank
286         // because then this method can't be used as a refresh
287
288         Sorted sorted = get_sorted_routes();
289         int delta = sorted.size() - route_table.size();
290
291         if (initial < 0 || (delta > 0 && initial > delta)) {
292                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("not switching to %1\n", initial));
293                 return;
294         }
295
296         _current_initial_bank = initial;
297         _current_selected_track = -1;
298
299         clear_route_signals();
300
301         // now set the signals for new routes
302         if (_current_initial_bank <= sorted.size()) {
303
304                 uint32_t end_pos = min (route_table.size(), sorted.size());
305                 uint32_t i = 0;
306                 Sorted::iterator it = sorted.begin() + _current_initial_bank;
307                 Sorted::iterator end = sorted.begin() + _current_initial_bank + end_pos;
308
309                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2\n", _current_initial_bank, end_pos));
310
311                 route_table.clear ();
312                 set_route_table_size (surface().strips.size());
313
314                 // link routes to strips
315
316                 Glib::Mutex::Lock lm (route_signals_lock);
317
318                 for (; it != end && it != sorted.end(); ++it, ++i) {
319                         boost::shared_ptr<Route> route = *it;
320
321                         assert (surface().strips[i]);
322                         Strip & strip = *surface().strips[i];
323
324                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("remote id %1 connecting %2 to %3 with port %4\n", 
325                                                                            route->remote_control_id(), route->name(), strip.name(), port_for_id(i)));
326                         set_route_table (i, route);
327                         RouteSignal * rs = new RouteSignal (route, *this, strip, port_for_id(i));
328                         route_signals.push_back (rs);
329                         rs->notify_all ();
330                 }
331
332                 // create dead strips if there aren't enough routes to
333                 // fill a bank
334                 for (; i < route_table.size(); ++i) {
335                         Strip & strip = *surface().strips[i];
336                         // send zero for this strip
337                         MackiePort & port = port_for_id(i);
338                         port.write (builder.zero_strip (port, strip));
339                 }
340         }
341
342         // display the current start bank.
343         surface().display_bank_start (mcu_port(), builder, _current_initial_bank);
344 }
345
346 void 
347 MackieControlProtocol::zero_all()
348 {
349         // TODO turn off Timecode displays
350
351         // zero all strips
352         for (Surface::Strips::iterator it = surface().strips.begin(); it != surface().strips.end(); ++it) {
353                 MackiePort & port = port_for_id ((*it)->index());
354                 port.write (builder.zero_strip (port, **it));
355         }
356
357         // and the master strip
358         mcu_port().write (builder.zero_strip (dynamic_cast<MackiePort&> (mcu_port()), master_strip()));
359
360         // turn off global buttons and leds
361         // global buttons are only ever on mcu_port, so we don't have
362         // to figure out which port.
363         for (Surface::Controls::iterator it = surface().controls.begin(); it != surface().controls.end(); ++it) {
364                 Control & control = **it;
365                 if (!control.group().is_strip() && control.accepts_feedback()) {
366                         mcu_port().write (builder.zero_control (control));
367                 }
368         }
369
370         // any hardware-specific stuff
371         surface().zero_all (mcu_port(), builder);
372 }
373
374 int 
375 MackieControlProtocol::set_active (bool yn)
376 {
377         if (yn == _active) {
378                 return 0;
379         }
380
381         try
382         {
383                 // the reason for the locking and unlocking is that
384                 // glibmm can't do a condition wait on a RecMutex
385                 if (yn) {
386                         // TODO what happens if this fails half way?
387
388                         // start an event loop
389
390                         BaseUI::run ();
391                         
392                         // create MackiePorts
393                         {
394                                 Glib::Mutex::Lock lock (update_mutex);
395                                 create_ports();
396                         }
397                         
398                         // now initialise MackiePorts - ie exchange sysex messages
399                         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
400                                 (*it)->open();
401                         }
402                         
403                         // wait until all ports are active
404                         // TODO a more sophisticated approach would
405                         // allow things to start up with only an MCU, even if
406                         // extenders were specified but not responding.
407                         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
408                                 (*it)->wait_for_init();
409                         }
410                         
411                         // create surface object. This depends on the ports being
412                         // correctly initialised
413                         initialize_surface();
414                         connect_session_signals();
415                         
416                         // yeehah!
417                         _active = true;
418                         
419                         // send current control positions to surface
420                         // must come after _active = true otherwise it won't run
421                         update_surface();
422
423                         Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (100); // milliseconds
424
425                         periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::periodic));
426
427                         periodic_timeout->attach (main_loop()->get_context());
428
429                 } else {
430                         BaseUI::quit ();
431                         close();
432                         _active = false;
433                 }
434         }
435         
436         catch (exception & e) {
437                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("set_active to false because exception caught: %1\n", e.what()));
438                 _active = false;
439                 throw;
440         }
441
442         return 0;
443 }
444
445 bool
446 MackieControlProtocol::periodic ()
447 {
448         if (!_active) {
449                 return false;
450         }
451
452         {
453                 Glib::Mutex::Lock lm (route_signals_lock);
454                 for (RouteSignals::iterator rs = route_signals.begin(); rs != route_signals.end(); ++rs) {
455                         update_automation (**rs);
456                         float dB = const_cast<PeakMeter&> ((*rs)->route()->peak_meter()).peak_power (0);
457                         (*rs)->port().write ((*rs)->strip().meter().update_message (dB));
458                 }
459
460                 // and the master strip
461                 if (master_route_signal != 0) {
462                         update_automation (*master_route_signal);
463                 }
464         }
465
466         update_timecode_display();
467
468         return true;
469 }
470
471 bool 
472 MackieControlProtocol::handle_strip_button (SurfacePort & port, Control & control, ButtonState bs, boost::shared_ptr<Route> route)
473 {
474         bool state = false;
475
476         if (bs == press) {
477                 if (control.name() == "recenable") {
478                         state = !route->record_enabled();
479                         route->set_record_enabled (state, this);
480                 } else if (control.name() == "mute") {
481                         state = !route->muted();
482                         route->set_mute (state, this);
483                 } else if (control.name() == "solo") {
484                         state = !route->soloed();
485                         route->set_solo (state, this);
486                 } else if (control.name() == "select") {
487                         Strip* strip = const_cast<Strip*>(dynamic_cast<const Strip*>(&control.group()));
488                         if (strip) {
489                                 if (strip->index() < route_table.size()) {
490                                         boost::shared_ptr<Route> r = route_table[strip->index()];
491                                         if (r->remote_control_id() == _current_selected_track) {
492                                                 UnselectTrack (); /* EMIT SIGNAL */
493                                                 _current_selected_track = -1;
494                                         } else {
495                                                 SelectByRID (r->remote_control_id()); /* EMIT SIGNAL */
496                                                 _current_selected_track = r->remote_control_id();;
497                                         }
498                                 } 
499                         }
500                 } else if (control.name() == "vselect") {
501                         // TODO could be used to select different things to apply the pot to?
502                         //state = default_button_press (dynamic_cast<Button&> (control));
503                 }
504         }
505
506         if (control.name() == "fader_touch") {
507                 state = bs == press;
508                 Strip* strip = const_cast<Strip*>(dynamic_cast<const Strip*>(&control.group()));
509                 
510                 if (strip) {
511                         strip->gain().set_in_use (state);
512
513                         if (ARDOUR::Config->get_mackie_emulation() == "bcf" && state) {
514                                 /* BCF faders don't support touch, so add a timeout to reset
515                                    their `in_use' state.
516                                 */
517                                 add_in_use_timeout (port, strip->gain(), &strip->fader_touch());
518                         }
519                 }
520         }
521
522         return state;
523 }
524
525 void 
526 MackieControlProtocol::update_timecode_beats_led()
527 {
528         switch (_timecode_type) {
529                 case ARDOUR::AnyTime::BBT:
530                         update_global_led ("beats", on);
531                         update_global_led ("timecode", off);
532                         break;
533                 case ARDOUR::AnyTime::Timecode:
534                         update_global_led ("timecode", on);
535                         update_global_led ("beats", off);
536                         break;
537                 default:
538                         ostringstream os;
539                         os << "Unknown Anytime::Type " << _timecode_type;
540                         throw runtime_error (os.str());
541         }
542 }
543
544 void 
545 MackieControlProtocol::update_global_button (const string & name, LedState ls)
546 {
547         if (surface().controls_by_name.find (name) != surface().controls_by_name.end()) {
548                 Button * button = dynamic_cast<Button*> (surface().controls_by_name[name]);
549                 mcu_port().write (builder.build_led (button->led(), ls));
550         } else {
551                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Button %1 not found\n", name));
552         }
553 }
554
555 void 
556 MackieControlProtocol::update_global_led (const string & name, LedState ls)
557 {
558         if (surface().controls_by_name.find (name) != surface().controls_by_name.end()) {
559                 Led * led = dynamic_cast<Led*> (surface().controls_by_name[name]);
560                 mcu_port().write (builder.build_led (*led, ls));
561         } else {
562                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Led %1 not found\n", name));
563         }
564 }
565
566 // send messages to surface to set controls to correct values
567 void 
568 MackieControlProtocol::update_surface()
569 {
570         if (!_active) {
571                 return;
572         }
573
574         // do the initial bank switch to connect signals
575         // _current_initial_bank is initialised by set_state
576         switch_banks (_current_initial_bank);
577         
578         /* Create a RouteSignal for the master route, if we don't already have one */
579         if (!master_route_signal) {
580                 boost::shared_ptr<Route> mr = master_route ();
581                 if (mr) {
582                         master_route_signal = boost::shared_ptr<RouteSignal> (new RouteSignal (mr, *this, master_strip(), mcu_port()));
583                         // update strip from route
584                         master_route_signal->notify_all();
585                 }
586         }
587         
588         // sometimes the jog wheel is a pot
589         surface().blank_jog_ring (mcu_port(), builder);
590         
591         // update global buttons and displays
592         notify_record_state_changed();
593         notify_transport_state_changed();
594         update_timecode_beats_led();
595 }
596
597 void 
598 MackieControlProtocol::connect_session_signals()
599 {
600         // receive routes added
601         session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_route_added, this, _1), midi_ui_context());
602         // receive record state toggled
603         session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_record_state_changed, this), midi_ui_context());
604         // receive transport state changed
605         session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_transport_state_changed, this), midi_ui_context());
606         // receive punch-in and punch-out
607         Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
608         session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
609         // receive rude solo changed
610         session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_solo_active_changed, this, _1), midi_ui_context());
611
612         // make sure remote id changed signals reach here
613         // see also notify_route_added
614         Sorted sorted = get_sorted_routes();
615
616         for (Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it) {
617                 (*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind(&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
618         }
619 }
620
621 void 
622 MackieControlProtocol::add_port (MIDI::Port & midi_input_port, MIDI::Port & midi_output_port, int number, MackiePort::port_type_t port_type)
623 {
624         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add port %1 %2\n", midi_input_port.name(), midi_output_port.name()));
625
626         MackiePort * sport = new MackiePort (*this, midi_input_port, midi_output_port, number, port_type);
627         _ports.push_back (sport);
628         
629         sport->init_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_init, this, sport));
630         sport->active_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_active, this, sport));
631         sport->inactive_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_inactive, this, sport));
632
633         _input_bundle->add_channel (
634                 midi_input_port.name(),
635                 ARDOUR::DataType::MIDI,
636                 session->engine().make_port_name_non_relative (midi_input_port.name())
637                 );
638         
639         _output_bundle->add_channel (
640                 midi_output_port.name(),
641                 ARDOUR::DataType::MIDI,
642                 session->engine().make_port_name_non_relative (midi_output_port.name())
643                 );
644 }
645
646 void 
647 MackieControlProtocol::create_ports()
648 {
649         MIDI::Manager * mm = MIDI::Manager::instance();
650         MIDI::Port * midi_input_port = mm->add_port (
651                 new MIDI::Port (string_compose (_("%1 in"), default_port_name), MIDI::Port::IsInput, session->engine().jack())
652                 );
653         MIDI::Port * midi_output_port = mm->add_port (
654                 new MIDI::Port (string_compose (_("%1 out"), default_port_name), MIDI::Port::IsOutput, session->engine().jack())
655                 );
656
657         /* Create main port */
658
659         if (!midi_input_port->ok() || !midi_output_port->ok()) {
660                 ostringstream os;
661                 os << _("Mackie control MIDI ports could not be created; Mackie control disabled");
662                 error << os.str() << endmsg;
663                 throw MackieControlException (os.str());
664         }
665
666         add_port (*midi_input_port, *midi_output_port, 0, MackiePort::mcu);
667
668         /* Create extender ports */
669
670         for (uint32_t index = 1; index <= Config->get_mackie_extenders(); ++index) {
671                 MIDI::Port * midi_input_port = mm->add_port (
672                         new MIDI::Port (string_compose (_("mcu_xt_%1 in"), index), MIDI::Port::IsInput, session->engine().jack())
673                         );
674                 MIDI::Port * midi_output_port = mm->add_port (
675                         new MIDI::Port (string_compose (_("mcu_xt_%1 out"), index), MIDI::Port::IsOutput, session->engine().jack())
676                         );
677                 if (midi_input_port->ok() && midi_output_port->ok()) {
678                         add_port (*midi_input_port, *midi_output_port, index, MackiePort::ext);
679                 }
680         }
681 }
682
683 boost::shared_ptr<Route> 
684 MackieControlProtocol::master_route()
685 {
686         return session->master_out ();
687 }
688
689 Strip& 
690 MackieControlProtocol::master_strip()
691 {
692         return dynamic_cast<Strip&> (*surface().groups["master"]);
693 }
694
695 void 
696 MackieControlProtocol::initialize_surface()
697 {
698         // set up the route table
699         int strips = 0;
700         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
701                 strips += (*it)->strips();
702         }
703
704         set_route_table_size (strips);
705
706         // TODO same as code in mackie_port.cc
707         string emulation = ARDOUR::Config->get_mackie_emulation();
708         if (emulation == "bcf") {
709                 _surface = new BcfSurface (strips);
710         } else if (emulation == "mcu") {
711                 _surface = new MackieSurface (strips);
712         } else {
713                 ostringstream os;
714                 os << "no Surface class found for emulation: " << emulation;
715                 throw MackieControlException (os.str());
716         }
717
718         _surface->init();
719 }
720
721 void 
722 MackieControlProtocol::close()
723 {
724
725         // must be before other shutdown otherwise polling loop
726         // calls methods on objects that are deleted
727
728         port_connections.drop_connections ();
729         session_connections.drop_connections ();
730         route_connections.drop_connections ();
731         periodic_connection.disconnect ();
732
733         if (_surface != 0) {
734                 // These will fail if the port has gone away.
735                 // So catch the exception and do the rest of the
736                 // close afterwards
737                 // because the bcf doesn't respond to the next 3 sysex messages
738                 try {
739                         zero_all();
740                 }
741
742                 catch (exception & e) {
743                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::close caught exception: %1\n", e.what()));
744                 }
745
746                 for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
747                         try {
748                                 MackiePort & port = **it;
749                                 // faders to minimum
750                                 port.write_sysex (0x61);
751                                 // All LEDs off
752                                 port.write_sysex (0x62);
753                                 // Reset (reboot into offline mode)
754                                 port.write_sysex (0x63);
755                         }
756                         catch (exception & e) {
757                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::close caught exception: %1\n", e.what()));
758                         }
759                 }
760
761                 // disconnect routes from strips
762                 clear_route_signals();
763                 delete _surface;
764                 _surface = 0;
765         }
766
767         // shut down MackiePorts
768         for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) {
769                 delete *it;
770         }
771
772         _ports.clear();
773 }
774
775 XMLNode& 
776 MackieControlProtocol::get_state()
777 {
778         DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state\n");
779
780         // add name of protocol
781         XMLNode* node = new XMLNode (X_("Protocol"));
782         node->add_property (X_("name"), ARDOUR::ControlProtocol::_name);
783
784         // add current bank
785         ostringstream os;
786         os << _current_initial_bank;
787         node->add_property (X_("bank"), os.str());
788
789         return *node;
790 }
791
792 int 
793 MackieControlProtocol::set_state (const XMLNode & node, int /*version*/)
794 {
795         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::set_state: active %1\n", _active));
796
797         int retval = 0;
798
799         // fetch current bank
800
801         if (node.property (X_("bank")) != 0) {
802                 string bank = node.property (X_("bank"))->value();
803                 try {
804                         set_active (true);
805                         uint32_t new_bank = atoi (bank.c_str());
806                         if (_current_initial_bank != new_bank) {
807                                 switch_banks (new_bank);
808                         }
809                 }
810                 catch (exception & e) {
811                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("exception in MackieControlProtocol::set_state: %1\n", e.what()));
812                         return -1;
813                 }
814         }
815
816         return retval;
817 }
818
819 void 
820 MackieControlProtocol::handle_control_event (SurfacePort & port, Control & control, const ControlState & state)
821 {
822         // find the route for the control, if there is one
823         boost::shared_ptr<Route> route;
824
825         if (control.group().is_strip()) {
826                 if (control.group().is_master()) {
827                         DEBUG_TRACE (DEBUG::MackieControl, "master strip control event\n");
828                         route = master_route();
829                 } else {
830                         uint32_t index = control.ordinal() - 1 + (port.number() * port.strips());
831                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip control event, index = %1, rt size = %2\n",
832                                                                            index, route_table.size()));
833                         if (index < route_table.size()) {
834                                 route = route_table[index];
835                                 if (route) {
836                                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("modifying %1\n", route->name()));
837                                 } else {
838                                         DEBUG_TRACE (DEBUG::MackieControl, "no route found!\n");
839                                 }
840                         } else {
841                                 cerr << "Warning: index is " << index << " which is not in the route table, size: " << route_table.size() << endl;
842                                 DEBUG_TRACE (DEBUG::MackieControl, "illegal route index found!\n");
843                         }
844                 }
845         }
846
847         // This handles control element events from the surface
848         // the state of the controls on the surface is usually updated
849         // from UI events.
850         switch (control.type()) {
851                 case Control::type_fader:
852                         // find the route in the route table for the id
853                         // if the route isn't available, skip it
854                         // at which point the fader should just reset itself
855                         if (route != 0)
856                         {
857                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", state.pos));
858
859                                 route->gain_control()->set_value (slider_position_to_gain (state.pos));
860
861                                 if (ARDOUR::Config->get_mackie_emulation() == "bcf") {
862                                         /* reset the timeout while we're still moving the fader */
863                                         add_in_use_timeout (port, control, control.in_use_touch_control);
864                                 }
865
866                                 // must echo bytes back to slider now, because
867                                 // the notifier only works if the fader is not being
868                                 // touched. Which it is if we're getting input.
869                                 port.write (builder.build_fader ((Fader&)control, state.pos));
870                         }
871                         break;
872
873                 case Control::type_button:
874                         if (control.group().is_strip()) {
875                                 // strips
876                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip button %1\n", control.id()));
877                                 if (route != 0) {
878                                         handle_strip_button (port, control, state.button_state, route);
879                                 } else {
880                                         // no route so always switch the light off
881                                         // because no signals will be emitted by a non-route
882                                         port.write (builder.build_led (control.led(), off));
883                                 }
884                         } else if (control.group().is_master()) {
885                                 // master fader touch
886                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("master strip button %1\n", control.id()));
887                                 if (route != 0) {
888                                         handle_strip_button (port, control, state.button_state, route);
889                                 }
890                         } else {
891                                 // handle all non-strip buttons
892                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("global button %1\n", control.id()));
893                                 handle_button_event (dynamic_cast<Button&>(control), state.button_state);
894
895                         }
896                         break;
897
898                 // pot (jog wheel, external control)
899                 case Control::type_pot:
900                         if (control.group().is_strip()) {
901                                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip pot %1\n", control.id()));
902                                 if (route) {
903                                         boost::shared_ptr<Panner> panner = route->panner_shell()->panner();
904                                         // pan for mono input routes, or stereo linked panners
905                                         if (panner) {
906                                                 double p = panner->position ();
907                                                 
908                                                 // calculate new value, and adjust
909                                                 p += state.delta * state.sign;
910                                                 p = min (1.0, p);
911                                                 p = max (0.0, p);
912                                                 panner->set_position (p);
913                                         }
914                                 } else {
915                                         // it's a pot for an umnapped route, so turn all the lights off
916                                         port.write (builder.build_led_ring (dynamic_cast<Pot &> (control), off));
917                                 }
918                         } else {
919                                 if (control.is_jog()) {
920                                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Jog wheel moved %1\n", state.ticks));
921                                         _jog_wheel.jog_event (port, control, state);
922                                 } else {
923                                         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("External controller moved %1\n", state.ticks));
924                                         cout << "external controller" << state.ticks * state.sign << endl;
925                                 }
926                         }
927                         break;
928
929                 default:
930                         cout << "Control::type not handled: " << control.type() << endl;
931         }
932 }
933
934 /////////////////////////////////////////////////
935 // handlers for Route signals
936 // TODO should these be part of RouteSignal?
937 // They started off as signal/slot handlers for signals
938 // from Route, but they're also used in polling for automation
939 /////////////////////////////////////////////////
940
941 void 
942 MackieControlProtocol::notify_solo_changed (RouteSignal * route_signal)
943 {
944         try {
945                 Button & button = route_signal->strip().solo();
946                 route_signal->port().write (builder.build_led (button, route_signal->route()->soloed()));
947         }
948         catch (exception & e) {
949                 cout << e.what() << endl;
950         }
951 }
952
953 void 
954 MackieControlProtocol::notify_mute_changed (RouteSignal * route_signal)
955 {
956         try {
957                 Button & button = route_signal->strip().mute();
958                 route_signal->port().write (builder.build_led (button, route_signal->route()->muted()));
959         }
960         catch (exception & e) {
961                 cout << e.what() << endl;
962         }
963 }
964
965 void 
966 MackieControlProtocol::notify_record_enable_changed (RouteSignal * route_signal)
967 {
968         try {
969                 Button & button = route_signal->strip().recenable();
970                 route_signal->port().write (builder.build_led (button, route_signal->route()->record_enabled()));
971         }
972         catch (exception & e) {
973                 cout << e.what() << endl;
974         }
975 }
976
977 void MackieControlProtocol::notify_active_changed (RouteSignal *)
978 {
979         try {
980                 DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::notify_active_changed\n");
981                 refresh_current_bank();
982         }
983         catch (exception & e) {
984                 cout << e.what() << endl;
985         }
986 }
987
988 void 
989 MackieControlProtocol::notify_gain_changed (RouteSignal * route_signal, bool force_update)
990 {
991         try {
992                 Fader & fader = route_signal->strip().gain();
993                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("route %1 gain change, update fader %2 on port %3\n", 
994                                                                    route_signal->route()->name(), 
995                                                                    fader.raw_id(),
996                                                                    route_signal->port().output_port().name()));
997                 if (!fader.in_use()) {
998                         float gain_value = gain_to_slider_position (route_signal->route()->gain_control()->get_value());
999                         // check that something has actually changed
1000                         if (force_update || gain_value != route_signal->last_gain_written()) {
1001                                 route_signal->port().write (builder.build_fader (fader, gain_value));
1002                                 route_signal->last_gain_written (gain_value);
1003                         }
1004                 }
1005         }
1006         catch (exception & e) {
1007                 cout << e.what() << endl;
1008         }
1009 }
1010
1011 void 
1012 MackieControlProtocol::notify_property_changed (const PropertyChange& what_changed, RouteSignal * route_signal)
1013 {
1014         if (!what_changed.contains (Properties::name)) {
1015                 return;
1016         }
1017
1018         try {
1019                 Strip & strip = route_signal->strip();
1020                 
1021                 if (!strip.is_master()) {
1022                         string line1;
1023                         string fullname = route_signal->route()->name();
1024
1025                         if (fullname.length() <= 6) {
1026                                 line1 = fullname;
1027                         } else {
1028                                 line1 = PBD::short_version (fullname, 6);
1029                         }
1030
1031 #ifdef NUCLEUS_DEBUG
1032                         cerr << "show strip name from " << fullname << " as " << line1 << endl;
1033 #endif
1034
1035                         SurfacePort & port = route_signal->port();
1036                         port.write (builder.strip_display (port, strip, 0, line1));
1037                         port.write (builder.strip_display_blank (port, strip, 1));
1038                 }
1039         }
1040         catch (exception & e) {
1041                 cout << e.what() << endl;
1042         }
1043 }
1044
1045 void 
1046 MackieControlProtocol::notify_panner_changed (RouteSignal * route_signal, bool force_update)
1047 {
1048         try {
1049                 Pot & pot = route_signal->strip().vpot();
1050                 boost::shared_ptr<Panner> panner = route_signal->route()->panner();
1051                 if (panner) {
1052                         double pos = panner->position ();
1053
1054                         // cache the MidiByteArray here, because the mackie led control is much lower
1055                         // resolution than the panner control. So we save lots of byte
1056                         // sends in spite of more work on the comparison
1057                         MidiByteArray bytes = builder.build_led_ring (pot, ControlState (on, pos), MackieMidiBuilder::midi_pot_mode_dot);
1058                         // check that something has actually changed
1059                         if (force_update || bytes != route_signal->last_pan_written())
1060                         {
1061                                 route_signal->port().write (bytes);
1062                                 route_signal->last_pan_written (bytes);
1063                         }
1064                 } else {
1065                         route_signal->port().write (builder.zero_control (pot));
1066                 }
1067         }
1068         catch (exception & e) {
1069                 cout << e.what() << endl;
1070         }
1071 }
1072
1073 // TODO handle plugin automation polling
1074 void 
1075 MackieControlProtocol::update_automation (RouteSignal & rs)
1076 {
1077         ARDOUR::AutoState gain_state = rs.route()->gain_control()->automation_state();
1078
1079         if (gain_state == Touch || gain_state == Play) {
1080                 notify_gain_changed (&rs, false);
1081         }
1082
1083         if (rs.route()->panner()) {
1084                 ARDOUR::AutoState panner_state = rs.route()->panner()->automation_state();
1085                 if (panner_state == Touch || panner_state == Play) {
1086                         notify_panner_changed (&rs, false);
1087                 }
1088         }
1089 }
1090
1091 string 
1092 MackieControlProtocol::format_bbt_timecode (framepos_t now_frame)
1093 {
1094         Timecode::BBT_Time bbt_time;
1095         session->bbt_time (now_frame, bbt_time);
1096
1097         // According to the Logic docs
1098         // digits: 888/88/88/888
1099         // BBT mode: Bars/Beats/Subdivisions/Ticks
1100         ostringstream os;
1101         os << setw(3) << setfill('0') << bbt_time.bars;
1102         os << setw(2) << setfill('0') << bbt_time.beats;
1103
1104         // figure out subdivisions per beat
1105         const ARDOUR::Meter & meter = session->tempo_map().meter_at (now_frame);
1106         int subdiv = 2;
1107         if (meter.note_divisor() == 8 && (meter.divisions_per_bar() == 12.0 || meter.divisions_per_bar() == 9.0 || meter.divisions_per_bar() == 6.0)) {
1108                 subdiv = 3;
1109         }
1110
1111         uint32_t subdivisions = bbt_time.ticks / uint32_t (Timecode::BBT_Time::ticks_per_beat / subdiv);
1112         uint32_t ticks = bbt_time.ticks % uint32_t (Timecode::BBT_Time::ticks_per_beat / subdiv);
1113
1114         os << setw(2) << setfill('0') << subdivisions + 1;
1115         os << setw(3) << setfill('0') << ticks;
1116
1117         return os.str();
1118 }
1119
1120 string 
1121 MackieControlProtocol::format_timecode_timecode (framepos_t now_frame)
1122 {
1123         Timecode::Time timecode;
1124         session->timecode_time (now_frame, timecode);
1125
1126         // According to the Logic docs
1127         // digits: 888/88/88/888
1128         // Timecode mode: Hours/Minutes/Seconds/Frames
1129         ostringstream os;
1130         os << setw(3) << setfill('0') << timecode.hours;
1131         os << setw(2) << setfill('0') << timecode.minutes;
1132         os << setw(2) << setfill('0') << timecode.seconds;
1133         os << setw(3) << setfill('0') << timecode.frames;
1134
1135         return os.str();
1136 }
1137
1138 void 
1139 MackieControlProtocol::update_timecode_display()
1140 {
1141         if (surface().has_timecode_display()) {
1142                 // do assignment here so current_frame is fixed
1143                 framepos_t current_frame = session->transport_frame();
1144                 string timecode;
1145
1146                 switch (_timecode_type) {
1147                         case ARDOUR::AnyTime::BBT:
1148                                 timecode = format_bbt_timecode (current_frame);
1149                                 break;
1150                         case ARDOUR::AnyTime::Timecode:
1151                                 timecode = format_timecode_timecode (current_frame);
1152                                 break;
1153                         default:
1154                                 ostringstream os;
1155                                 os << "Unknown timecode: " << _timecode_type;
1156                                 throw runtime_error (os.str());
1157                 }
1158
1159                 // only write the timecode string to the MCU if it's changed
1160                 // since last time. This is to reduce midi bandwidth used.
1161                 if (timecode != _timecode_last) {
1162                         surface().display_timecode (mcu_port(), builder, timecode, _timecode_last);
1163                         _timecode_last = timecode;
1164                 }
1165         }
1166 }
1167
1168 /////////////////////////////////////
1169 // Transport Buttons
1170 /////////////////////////////////////
1171
1172 LedState 
1173 MackieControlProtocol::frm_left_press (Button &)
1174 {
1175         // can use first_mark_before/after as well
1176         unsigned long elapsed = _frm_left_last.restart();
1177
1178         Location * loc = session->locations()->first_location_before (
1179                 session->transport_frame()
1180         );
1181
1182         // allow a quick double to go past a previous mark
1183         if (session->transport_rolling() && elapsed < 500 && loc != 0) {
1184                 Location * loc_two_back = session->locations()->first_location_before (loc->start());
1185                 if (loc_two_back != 0)
1186                 {
1187                         loc = loc_two_back;
1188                 }
1189         }
1190
1191         // move to the location, if it's valid
1192         if (loc != 0) {
1193                 session->request_locate (loc->start(), session->transport_rolling());
1194         }
1195
1196         return on;
1197 }
1198
1199 LedState 
1200 MackieControlProtocol::frm_left_release (Button &)
1201 {
1202         return off;
1203 }
1204
1205 LedState 
1206 MackieControlProtocol::frm_right_press (Button &)
1207 {
1208         // can use first_mark_before/after as well
1209         Location * loc = session->locations()->first_location_after (session->transport_frame());
1210         
1211         if (loc != 0) {
1212                 session->request_locate (loc->start(), session->transport_rolling());
1213         }
1214                 
1215         return on;
1216 }
1217
1218 LedState 
1219 MackieControlProtocol::frm_right_release (Button &)
1220 {
1221         return off;
1222 }
1223
1224 LedState 
1225 MackieControlProtocol::stop_press (Button &)
1226 {
1227         session->request_stop();
1228         return on;
1229 }
1230
1231 LedState 
1232 MackieControlProtocol::stop_release (Button &)
1233 {
1234         return session->transport_stopped();
1235 }
1236
1237 LedState 
1238 MackieControlProtocol::play_press (Button &)
1239 {
1240         session->request_transport_speed (1.0);
1241         return on;
1242 }
1243
1244 LedState 
1245 MackieControlProtocol::play_release (Button &)
1246 {
1247         return session->transport_rolling();
1248 }
1249
1250 LedState 
1251 MackieControlProtocol::record_press (Button &)
1252 {
1253         if (session->get_record_enabled()) {
1254                 session->disable_record (false);
1255         } else {
1256                 session->maybe_enable_record();
1257         }
1258         return on;
1259 }
1260
1261 LedState 
1262 MackieControlProtocol::record_release (Button &)
1263 {
1264         if (session->get_record_enabled()) {
1265                 if (session->transport_rolling()) {
1266                         return on;
1267                 } else {
1268                         return flashing;
1269                 }
1270         } else {
1271                 return off;
1272         }
1273 }
1274
1275 LedState 
1276 MackieControlProtocol::rewind_press (Button &)
1277 {
1278         _jog_wheel.push (JogWheel::speed);
1279         _jog_wheel.transport_direction (-1);
1280         session->request_transport_speed (-_jog_wheel.transport_speed());
1281         return on;
1282 }
1283
1284 LedState 
1285 MackieControlProtocol::rewind_release (Button &)
1286 {
1287         _jog_wheel.pop();
1288         _jog_wheel.transport_direction (0);
1289         if (_transport_previously_rolling) {
1290                 session->request_transport_speed (1.0);
1291         } else {
1292                 session->request_stop();
1293         }
1294         return off;
1295 }
1296
1297 LedState 
1298 MackieControlProtocol::ffwd_press (Button &)
1299 {
1300         _jog_wheel.push (JogWheel::speed);
1301         _jog_wheel.transport_direction (1);
1302         session->request_transport_speed (_jog_wheel.transport_speed());
1303         return on;
1304 }
1305
1306 LedState 
1307 MackieControlProtocol::ffwd_release (Button &)
1308 {
1309         _jog_wheel.pop();
1310         _jog_wheel.transport_direction (0);
1311         if (_transport_previously_rolling) {
1312                 session->request_transport_speed (1.0);
1313         } else {
1314                 session->request_stop();
1315         }
1316         return off;
1317 }
1318
1319 LedState 
1320 MackieControlProtocol::loop_press (Button &)
1321 {
1322         session->request_play_loop (!session->get_play_loop());
1323         return on;
1324 }
1325
1326 LedState 
1327 MackieControlProtocol::loop_release (Button &)
1328 {
1329         return session->get_play_loop();
1330 }
1331
1332 LedState 
1333 MackieControlProtocol::punch_in_press (Button &)
1334 {
1335         bool const state = !session->config.get_punch_in();
1336         session->config.set_punch_in (state);
1337         return state;
1338 }
1339
1340 LedState 
1341 MackieControlProtocol::punch_in_release (Button &)
1342 {
1343         return session->config.get_punch_in();
1344 }
1345
1346 LedState 
1347 MackieControlProtocol::punch_out_press (Button &)
1348 {
1349         bool const state = !session->config.get_punch_out();
1350         session->config.set_punch_out (state);
1351         return state;
1352 }
1353
1354 LedState 
1355 MackieControlProtocol::punch_out_release (Button &)
1356 {
1357         return session->config.get_punch_out();
1358 }
1359
1360 LedState 
1361 MackieControlProtocol::home_press (Button &)
1362 {
1363         session->goto_start();
1364         return on;
1365 }
1366
1367 LedState 
1368 MackieControlProtocol::home_release (Button &)
1369 {
1370         return off;
1371 }
1372
1373 LedState 
1374 MackieControlProtocol::end_press (Button &)
1375 {
1376         session->goto_end();
1377         return on;
1378 }
1379
1380 LedState 
1381 MackieControlProtocol::end_release (Button &)
1382 {
1383         return off;
1384 }
1385
1386 LedState 
1387 MackieControlProtocol::clicking_press (Button &)
1388 {
1389         bool state = !Config->get_clicking();
1390         Config->set_clicking (state);
1391         return state;
1392 }
1393
1394 LedState 
1395 MackieControlProtocol::clicking_release (Button &)
1396 {
1397         return Config->get_clicking();
1398 }
1399
1400 LedState MackieControlProtocol::global_solo_press (Button &)
1401 {
1402         bool state = !session->soloing();
1403         session->set_solo (session->get_routes(), state);
1404         return state;
1405 }
1406
1407 LedState MackieControlProtocol::global_solo_release (Button &)
1408 {
1409         return session->soloing();
1410 }
1411
1412 ///////////////////////////////////////////
1413 // Session signals
1414 ///////////////////////////////////////////
1415
1416 void MackieControlProtocol::notify_parameter_changed (std::string const & p)
1417 {
1418         if (p == "punch-in") {
1419                 update_global_button ("punch_in", session->config.get_punch_in());
1420         } else if (p == "punch-out") {
1421                 update_global_button ("punch_out", session->config.get_punch_out());
1422         } else if (p == "clicking") {
1423                 update_global_button ("clicking", Config->get_clicking());
1424         } else {
1425                 DEBUG_TRACE (DEBUG::MackieControl, string_compose ("parameter changed: %1\n", p));
1426         }
1427 }
1428
1429 // RouteList is the set of routes that have just been added
1430 void 
1431 MackieControlProtocol::notify_route_added (ARDOUR::RouteList & rl)
1432 {
1433         // currently assigned banks are less than the full set of
1434         // strips, so activate the new strip now.
1435
1436         {
1437                 Glib::Mutex::Lock lm (route_signals_lock);
1438                 if (route_signals.size() < route_table.size()) {
1439                         refresh_current_bank();
1440                 }
1441         }
1442
1443         // otherwise route added, but current bank needs no updating
1444
1445         // make sure remote id changes in the new route are handled
1446         typedef ARDOUR::RouteList ARS;
1447
1448         for (ARS::iterator it = rl.begin(); it != rl.end(); ++it) {
1449                 (*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
1450         }
1451 }
1452
1453 void 
1454 MackieControlProtocol::notify_solo_active_changed (bool active)
1455 {
1456         Button * rude_solo = reinterpret_cast<Button*> (surface().controls_by_name["solo"]);
1457         mcu_port().write (builder.build_led (*rude_solo, active ? flashing : off));
1458 }
1459
1460 void 
1461 MackieControlProtocol::notify_remote_id_changed()
1462 {
1463         Sorted sorted = get_sorted_routes();
1464
1465         // if a remote id has been moved off the end, we need to shift
1466         // the current bank backwards.
1467
1468         uint32_t sz;
1469
1470         {
1471                 Glib::Mutex::Lock lm (route_signals_lock);
1472                 sz = route_signals.size();
1473         }
1474
1475         if (sorted.size() - _current_initial_bank < sz) {
1476                 // but don't shift backwards past the zeroth channel
1477                 switch_banks (max((Sorted::size_type) 0, sorted.size() - sz));
1478         } else {
1479                 // Otherwise just refresh the current bank
1480                 refresh_current_bank();
1481         }
1482 }
1483
1484 ///////////////////////////////////////////
1485 // Transport signals
1486 ///////////////////////////////////////////
1487
1488 void 
1489 MackieControlProtocol::notify_record_state_changed()
1490 {
1491         // switch rec button on / off / flashing
1492         Button * rec = reinterpret_cast<Button*> (surface().controls_by_name["record"]);
1493         mcu_port().write (builder.build_led (*rec, record_release (*rec)));
1494 }
1495
1496 void 
1497 MackieControlProtocol::notify_transport_state_changed()
1498 {
1499         // switch various play and stop buttons on / off
1500         update_global_button ("play", session->transport_rolling());
1501         update_global_button ("stop", !session->transport_rolling());
1502         update_global_button ("loop", session->get_play_loop());
1503
1504         _transport_previously_rolling = session->transport_rolling();
1505
1506         // rec is special because it's tristate
1507         Button * rec = reinterpret_cast<Button*> (surface().controls_by_name["record"]);
1508         mcu_port().write (builder.build_led (*rec, record_release (*rec)));
1509 }
1510
1511 LedState 
1512 MackieControlProtocol::left_press (Button &)
1513 {
1514         Sorted sorted = get_sorted_routes();
1515         if (sorted.size() > route_table.size()) {
1516                 int new_initial = _current_initial_bank - route_table.size();
1517                 if (new_initial < 0) {
1518                         new_initial = 0;
1519                 }
1520                 
1521                 if (new_initial != int (_current_initial_bank)) {
1522                         session->set_dirty();
1523                         switch_banks (new_initial);
1524                 }
1525
1526                 return on;
1527         } else {
1528                 return flashing;
1529         }
1530 }
1531
1532 LedState 
1533 MackieControlProtocol::left_release (Button &)
1534 {
1535         return off;
1536 }
1537
1538 LedState 
1539 MackieControlProtocol::right_press (Button &)
1540 {
1541         return off;
1542 }
1543
1544 LedState 
1545 MackieControlProtocol::right_release (Button &)
1546 {
1547         if (_zoom_mode) {
1548
1549         }
1550
1551         return off;
1552 }
1553
1554 LedState
1555 MackieControlProtocol::cursor_left_press (Button& )
1556 {
1557         if (_zoom_mode) {
1558
1559                 if (false) { // button_down (BUTTON_OPTION)) {
1560                         /* reset selected tracks to default vertical zoom */
1561                 } else {
1562                         ZoomOut (); /* EMIT SIGNAL */
1563                 }
1564         }
1565
1566         return off;
1567 }
1568
1569 LedState
1570 MackieControlProtocol::cursor_left_release (Button&)
1571 {
1572         return off;
1573 }
1574
1575 LedState
1576 MackieControlProtocol::cursor_right_press (Button& )
1577 {
1578         if (_zoom_mode) {
1579
1580                 if (false) { // button_down (BUTTON_OPTION)) {
1581                         /* reset selected tracks to default vertical zoom */
1582                 } else {
1583                         ZoomIn (); /* EMIT SIGNAL */
1584                 }
1585         }
1586
1587         return off;
1588 }
1589
1590 LedState
1591 MackieControlProtocol::cursor_right_release (Button&)
1592 {
1593         return off;
1594 }
1595
1596 LedState
1597 MackieControlProtocol::cursor_up_press (Button&)
1598 {
1599         return off;
1600 }
1601
1602 LedState
1603 MackieControlProtocol::cursor_up_release (Button&)
1604 {
1605         return off;
1606 }
1607
1608 LedState
1609 MackieControlProtocol::cursor_down_press (Button&)
1610 {
1611         return off;
1612 }
1613
1614 LedState
1615 MackieControlProtocol::cursor_down_release (Button&)
1616 {
1617         return off;
1618 }
1619
1620 LedState 
1621 MackieControlProtocol::channel_left_press (Button &)
1622 {
1623         Sorted sorted = get_sorted_routes();
1624         if (sorted.size() > route_table.size()) {
1625                 prev_track();
1626                 return on;
1627         } else {
1628                 return flashing;
1629         }
1630 }
1631
1632 LedState 
1633 MackieControlProtocol::channel_left_release (Button &)
1634 {
1635         return off;
1636 }
1637
1638 LedState 
1639 MackieControlProtocol::channel_right_press (Button &)
1640 {
1641         Sorted sorted = get_sorted_routes();
1642         if (sorted.size() > route_table.size()) {
1643                 next_track();
1644                 return on;
1645         } else {
1646                 return flashing;
1647         }
1648 }
1649
1650 LedState 
1651 MackieControlProtocol::channel_right_release (Button &)
1652 {
1653         return off;
1654 }
1655
1656 /////////////////////////////////////
1657 // Functions
1658 /////////////////////////////////////
1659 LedState 
1660 MackieControlProtocol::marker_press (Button &)
1661 {
1662         // cut'n'paste from LocationUI::add_new_location()
1663         string markername;
1664         framepos_t where = session->audible_frame();
1665         session->locations()->next_available_name(markername,"mcu");
1666         Location *location = new Location (*session, where, where, markername, Location::IsMark);
1667         session->begin_reversible_command (_("add marker"));
1668         XMLNode &before = session->locations()->get_state();
1669         session->locations()->add (location, true);
1670         XMLNode &after = session->locations()->get_state();
1671         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
1672         session->commit_reversible_command ();
1673         return on;
1674 }
1675
1676 LedState 
1677 MackieControlProtocol::marker_release (Button &)
1678 {
1679         return off;
1680 }
1681
1682 void 
1683 jog_wheel_state_display (JogWheel::State state, SurfacePort & port)
1684 {
1685         switch (state) {
1686                 case JogWheel::zoom:
1687                         port.write (builder.two_char_display ("Zm"));
1688                         break;
1689                 case JogWheel::scroll:
1690                         port.write (builder.two_char_display ("Sc"));
1691                         break;
1692                 case JogWheel::scrub:
1693                         port.write (builder.two_char_display ("Sb"));
1694                         break;
1695                 case JogWheel::shuttle:
1696                         port.write (builder.two_char_display ("Sh"));
1697                         break;
1698                 case JogWheel::speed:
1699                         port.write (builder.two_char_display ("Sp"));
1700                         break;
1701                 case JogWheel::select:
1702                         port.write (builder.two_char_display ("Se"));
1703                         break;
1704         }
1705 }
1706
1707 Mackie::LedState 
1708 MackieControlProtocol::zoom_press (Mackie::Button &)
1709 {
1710         _zoom_mode = !_zoom_mode;
1711         return (_zoom_mode ? on : off);
1712         
1713 }
1714
1715 Mackie::LedState 
1716 MackieControlProtocol::zoom_release (Mackie::Button &)
1717 {
1718         return off;
1719 }
1720
1721 Mackie::LedState 
1722 MackieControlProtocol::scrub_press (Mackie::Button &)
1723 {
1724         _jog_wheel.scrub_state_cycle();
1725         update_global_button ("zoom", _jog_wheel.jog_wheel_state() == JogWheel::zoom);
1726         jog_wheel_state_display (_jog_wheel.jog_wheel_state(), mcu_port());
1727         return (
1728                 _jog_wheel.jog_wheel_state() == JogWheel::scrub
1729                 ||
1730                 _jog_wheel.jog_wheel_state() == JogWheel::shuttle
1731                 );
1732 }
1733
1734 Mackie::LedState 
1735 MackieControlProtocol::scrub_release (Mackie::Button &)
1736 {
1737         return (
1738                 _jog_wheel.jog_wheel_state() == JogWheel::scrub
1739                 ||
1740                 _jog_wheel.jog_wheel_state() == JogWheel::shuttle
1741                 );
1742 }
1743
1744 LedState
1745 MackieControlProtocol::undo_press (Button&)
1746 {
1747         Undo(); /* EMIT SIGNAL */
1748         return off;
1749 }
1750
1751 LedState
1752 MackieControlProtocol::undo_release (Button&)
1753 {
1754         return off;
1755 }
1756
1757 LedState
1758 MackieControlProtocol::redo_press (Button&)
1759 {
1760         Redo(); /* EMIT SIGNAL */
1761         return off;
1762 }
1763
1764 LedState
1765 MackieControlProtocol::redo_release (Button&)
1766 {
1767         return off;
1768 }
1769
1770 LedState 
1771 MackieControlProtocol::drop_press (Button &)
1772 {
1773         session->remove_last_capture();
1774         return on;
1775 }
1776
1777 LedState 
1778 MackieControlProtocol::drop_release (Button &)
1779 {
1780         return off;
1781 }
1782
1783 LedState 
1784 MackieControlProtocol::save_press (Button &)
1785 {
1786         session->save_state ("");
1787         return on;
1788 }
1789
1790 LedState 
1791 MackieControlProtocol::save_release (Button &)
1792 {
1793         return off;
1794 }
1795
1796 LedState 
1797 MackieControlProtocol::timecode_beats_press (Button &)
1798 {
1799         switch (_timecode_type) {
1800         case ARDOUR::AnyTime::BBT:
1801                 _timecode_type = ARDOUR::AnyTime::Timecode;
1802                 break;
1803         case ARDOUR::AnyTime::Timecode:
1804                 _timecode_type = ARDOUR::AnyTime::BBT;
1805                 break;
1806         default:
1807                 ostringstream os;
1808                 os << "Unknown Anytime::Type " << _timecode_type;
1809                 throw runtime_error (os.str());
1810         }
1811         update_timecode_beats_led();
1812         return on;
1813 }
1814
1815 LedState 
1816 MackieControlProtocol::timecode_beats_release (Button &)
1817 {
1818         return off;
1819 }
1820
1821 list<boost::shared_ptr<ARDOUR::Bundle> >
1822 MackieControlProtocol::bundles ()
1823 {
1824         list<boost::shared_ptr<ARDOUR::Bundle> > b;
1825         b.push_back (_input_bundle);
1826         b.push_back (_output_bundle);
1827         return b;
1828 }
1829
1830 void
1831 MackieControlProtocol::port_connected_or_disconnected (string a, string b, bool connected)
1832 {
1833         /* If something is connected to one of our output ports, send MIDI to update the surface
1834            to whatever state it should have.
1835         */
1836
1837         if (!connected) {
1838                 return;
1839         }
1840
1841         MackiePorts::const_iterator i = _ports.begin();
1842         while (i != _ports.end()) {
1843
1844                 string const n = AudioEngine::instance()->make_port_name_non_relative ((*i)->output_port().name ());
1845
1846                 if (a == n || b == n) {
1847                         break;
1848                 }
1849
1850                 ++i;
1851         }
1852
1853         if (i != _ports.end ()) {
1854                 update_surface ();
1855         }
1856 }
1857
1858 void
1859 MackieControlProtocol::do_request (MackieControlUIRequest* req)
1860 {
1861         if (req->type == CallSlot) {
1862
1863                 call_slot (MISSING_INVALIDATOR, req->the_slot);
1864
1865         } else if (req->type == Quit) {
1866
1867                 stop ();
1868         }
1869 }
1870
1871 int
1872 MackieControlProtocol::stop ()
1873 {
1874         BaseUI::quit ();
1875
1876         return 0;
1877 }
1878
1879 /** Add a timeout so that a control's in_use flag will be reset some time in the future.
1880  *  @param in_use_control the control whose in_use flag to reset.
1881  *  @param touch_control a touch control to emit an event for, or 0.
1882  */
1883 void
1884 MackieControlProtocol::add_in_use_timeout (SurfacePort& port, Control& in_use_control, Control* touch_control)
1885 {
1886         Glib::RefPtr<Glib::TimeoutSource> timeout (Glib::TimeoutSource::create (250)); // milliseconds
1887
1888         in_use_control.in_use_connection.disconnect ();
1889         in_use_control.in_use_connection = timeout->connect (
1890                 sigc::bind (sigc::mem_fun (*this, &MackieControlProtocol::control_in_use_timeout), &port, &in_use_control, touch_control));
1891         in_use_control.in_use_touch_control = touch_control;
1892
1893         timeout->attach (main_loop()->get_context());
1894
1895         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("timeout queued for port %1, control %2 touch control %3\n",
1896                                                            &port, &in_use_control, touch_control));}
1897
1898 /** Handle timeouts to reset in_use for controls that can't
1899  *  do this by themselves (e.g. pots, and faders without touch support).
1900  *  @param in_use_control the control whose in_use flag to reset.
1901  *  @param touch_control a touch control to emit an event for, or 0.
1902  */
1903 bool
1904 MackieControlProtocol::control_in_use_timeout (SurfacePort* port, Control* in_use_control, Control* touch_control)
1905 {
1906         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("timeout elapsed for port %1, control %2 touch control %3\n",
1907                                                            port, in_use_control, touch_control));
1908
1909         in_use_control->set_in_use (false);
1910
1911         if (touch_control) {
1912                 // empty control_state
1913                 ControlState control_state;
1914                 handle_control_event (*port, *touch_control, control_state);
1915         }
1916         
1917         // only call this method once from the timer
1918         return false;
1919 }
1920
1921 void 
1922 MackieControlProtocol::update_led (Button& button, Mackie::LedState ls)
1923 {
1924         if (ls != none) {
1925                 SurfacePort * port = 0;
1926
1927                 if (button.group().is_strip()) {
1928                         if (button.group().is_master()) {
1929                                 port = &mcu_port();
1930                         } else {
1931                                 port = &port_for_id (dynamic_cast<const Strip&> (button.group()).index());
1932                         }
1933                 } else {
1934                         port = &mcu_port();
1935                 }
1936                 port->write (builder.build_led (button, ls));
1937         }
1938 }
1939
1940 void 
1941 MackieControlProtocol::handle_button_event (Button& button, ButtonState bs)
1942 {
1943         if  (bs != press && bs != release) {
1944                 update_led (button, none);
1945                 return;
1946         }
1947         
1948         LedState ls;
1949
1950         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Handling %1 for button %2\n", (bs == press ? "press" : "release"), button.raw_id()));
1951
1952         switch  (button.raw_id()) {
1953         case 0x28: // io
1954                 switch  (bs) {
1955                 case press: ls = io_press (button); break;
1956                 case release: ls = io_release (button); break;
1957                 case neither: break;
1958                 }
1959                 break;
1960                 
1961         case 0x29: // sends
1962                 switch  (bs) {
1963                 case press: ls = sends_press (button); break;
1964                 case release: ls = sends_release (button); break;
1965                 case neither: break;
1966                 }
1967                 break;
1968                 
1969         case 0x2a: // pan
1970                 switch  (bs) {
1971                 case press: ls = pan_press (button); break;
1972                 case release: ls = pan_release (button); break;
1973                 case neither: break;
1974                 }
1975                 break;
1976                 
1977         case 0x2b: // plugin
1978                 switch  (bs) {
1979                 case press: ls = plugin_press (button); break;
1980                 case release: ls = plugin_release (button); break;
1981                 case neither: break;
1982                 }
1983                 break;
1984                 
1985         case 0x2c: // eq
1986                 switch  (bs) {
1987                 case press: ls = eq_press (button); break;
1988                 case release: ls = eq_release (button); break;
1989                 case neither: break;
1990                 }
1991                 break;
1992                 
1993         case 0x2d: // dyn
1994                 switch  (bs) {
1995                 case press: ls = dyn_press (button); break;
1996                 case release: ls = dyn_release (button); break;
1997                 case neither: break;
1998                 }
1999                 break;
2000                 
2001         case 0x2e: // left
2002                 switch  (bs) {
2003                 case press: ls = left_press (button); break;
2004                 case release: ls = left_release (button); break;
2005                 case neither: break;
2006                 }
2007                 break;
2008                 
2009         case 0x2f: // right
2010                 switch  (bs) {
2011                 case press: ls = right_press (button); break;
2012                 case release: ls = right_release (button); break;
2013                 case neither: break;
2014                 }
2015                 break;
2016                 
2017         case 0x30: // channel_left
2018                 switch  (bs) {
2019                 case press: ls = channel_left_press (button); break;
2020                 case release: ls = channel_left_release (button); break;
2021                 case neither: break;
2022                 }
2023                 break;
2024                 
2025         case 0x31: // channel_right
2026                 switch  (bs) {
2027                 case press: ls = channel_right_press (button); break;
2028                 case release: ls = channel_right_release (button); break;
2029                 case neither: break;
2030                 }
2031                 break;
2032                 
2033         case 0x32: // flip
2034                 switch  (bs) {
2035                 case press: ls = flip_press (button); break;
2036                 case release: ls = flip_release (button); break;
2037                 case neither: break;
2038                 }
2039                 break;
2040
2041         case 0x33: // edit
2042                 switch  (bs) {
2043                 case press: ls = edit_press (button); break;
2044                 case release: ls = edit_release (button); break;
2045                 case neither: break;
2046                 }
2047                 break;
2048
2049         case 0x34: // name_value
2050                 switch  (bs) {
2051                 case press: ls = name_value_press (button); break;
2052                 case release: ls = name_value_release (button); break;
2053                 case neither: break;
2054                 }
2055                 break;
2056
2057         case 0x35: // timecode_beats
2058                 switch  (bs) {
2059                 case press: ls = timecode_beats_press (button); break;
2060                 case release: ls = timecode_beats_release (button); break;
2061                 case neither: break;
2062                 }
2063                 break;
2064
2065         case 0x36: // F1
2066                 switch  (bs) {
2067                 case press: ls = F1_press (button); break;
2068                 case release: ls = F1_release (button); break;
2069                 case neither: break;
2070                 }
2071                 break;
2072
2073         case 0x37: // F2
2074                 switch  (bs) {
2075                 case press: ls = F2_press (button); break;
2076                 case release: ls = F2_release (button); break;
2077                 case neither: break;
2078                 }
2079                 break;
2080
2081         case 0x38: // F3
2082                 switch  (bs) {
2083                 case press: ls = F3_press (button); break;
2084                 case release: ls = F3_release (button); break;
2085                 case neither: break;
2086                 }
2087                 break;
2088
2089         case 0x39: // F4
2090                 switch  (bs) {
2091                 case press: ls = F4_press (button); break;
2092                 case release: ls = F4_release (button); break;
2093                 case neither: break;
2094                 }
2095                 break;
2096
2097         case 0x3a: // F5
2098                 switch  (bs) {
2099                 case press: ls = F5_press (button); break;
2100                 case release: ls = F5_release (button); break;
2101                 case neither: break;
2102                 }
2103                 break;
2104
2105         case 0x3b: // F6
2106                 switch  (bs) {
2107                 case press: ls = F6_press (button); break;
2108                 case release: ls = F6_release (button); break;
2109                 case neither: break;
2110                 }
2111                 break;
2112
2113         case 0x3c: // F7
2114                 switch  (bs) {
2115                 case press: ls = F7_press (button); break;
2116                 case release: ls = F7_release (button); break;
2117                 case neither: break;
2118                 }
2119                 break;
2120
2121         case 0x3d: // F8
2122                 switch  (bs) {
2123                 case press: ls = F8_press (button); break;
2124                 case release: ls = F8_release (button); break;
2125                 case neither: break;
2126                 }
2127                 break;
2128
2129         case 0x3e: // F9
2130                 switch  (bs) {
2131                 case press: ls = F9_press (button); break;
2132                 case release: ls = F9_release (button); break;
2133                 case neither: break;
2134                 }
2135                 break;
2136
2137         case 0x3f: // F10
2138                 switch  (bs) {
2139                 case press: ls = F10_press (button); break;
2140                 case release: ls = F10_release (button); break;
2141                 case neither: break;
2142                 }
2143                 break;
2144
2145         case 0x40: // F11
2146                 switch  (bs) {
2147                 case press: ls = F11_press (button); break;
2148                 case release: ls = F11_release (button); break;
2149                 case neither: break;
2150                 }
2151                 break;
2152
2153         case 0x41: // F12
2154                 switch  (bs) {
2155                 case press: ls = F12_press (button); break;
2156                 case release: ls = F12_release (button); break;
2157                 case neither: break;
2158                 }
2159                 break;
2160
2161         case 0x42: // F13
2162                 switch  (bs) {
2163                 case press: ls = F13_press (button); break;
2164                 case release: ls = F13_release (button); break;
2165                 case neither: break;
2166                 }
2167                 break;
2168
2169         case 0x43: // F14
2170                 switch  (bs) {
2171                 case press: ls = F14_press (button); break;
2172                 case release: ls = F14_release (button); break;
2173                 case neither: break;
2174                 }
2175                 break;
2176
2177         case 0x44: // F15
2178                 switch  (bs) {
2179                 case press: ls = F15_press (button); break;
2180                 case release: ls = F15_release (button); break;
2181                 case neither: break;
2182                 }
2183                 break;
2184
2185         case 0x45: // F16
2186                 switch  (bs) {
2187                 case press: ls = F16_press (button); break;
2188                 case release: ls = F16_release (button); break;
2189                 case neither: break;
2190                 }
2191                 break;
2192
2193         case 0x46: // shift
2194                 switch  (bs) {
2195                 case press: ls = shift_press (button); break;
2196                 case release: ls = shift_release (button); break;
2197                 case neither: break;
2198                 }
2199                 break;
2200
2201         case 0x47: // option
2202                 switch  (bs) {
2203                 case press: ls = option_press (button); break;
2204                 case release: ls = option_release (button); break;
2205                 case neither: break;
2206                 }
2207                 break;
2208
2209         case 0x48: // control
2210                 switch  (bs) {
2211                 case press: ls = control_press (button); break;
2212                 case release: ls = control_release (button); break;
2213                 case neither: break;
2214                 }
2215                 break;
2216
2217         case 0x49: // cmd_alt
2218                 switch  (bs) {
2219                 case press: ls = cmd_alt_press (button); break;
2220                 case release: ls = cmd_alt_release (button); break;
2221                 case neither: break;
2222                 }
2223                 break;
2224
2225         case 0x4a: // on
2226                 switch  (bs) {
2227                 case press: ls = on_press (button); break;
2228                 case release: ls = on_release (button); break;
2229                 case neither: break;
2230                 }
2231                 break;
2232
2233         case 0x4b: // rec_ready
2234                 switch  (bs) {
2235                 case press: ls = rec_ready_press (button); break;
2236                 case release: ls = rec_ready_release (button); break;
2237                 case neither: break;
2238                 }
2239                 break;
2240
2241         case 0x4c: // undo
2242                 switch  (bs) {
2243                 case press: ls = undo_press (button); break;
2244                 case release: ls = undo_release (button); break;
2245                 case neither: break;
2246                 }
2247                 break;
2248
2249         case 0x4d: // snapshot
2250                 switch  (bs) {
2251                 case press: ls = snapshot_press (button); break;
2252                 case release: ls = snapshot_release (button); break;
2253                 case neither: break;
2254                 }
2255                 break;
2256
2257         case 0x4e: // touch
2258                 switch  (bs) {
2259                 case press: ls = touch_press (button); break;
2260                 case release: ls = touch_release (button); break;
2261                 case neither: break;
2262                 }
2263                 break;
2264
2265         case 0x4f: // redo
2266                 switch  (bs) {
2267                 case press: ls = redo_press (button); break;
2268                 case release: ls = redo_release (button); break;
2269                 case neither: break;
2270                 }
2271                 break;
2272
2273         case 0x50: // marker
2274                 switch  (bs) {
2275                 case press: ls = marker_press (button); break;
2276                 case release: ls = marker_release (button); break;
2277                 case neither: break;
2278                 }
2279                 break;
2280
2281         case 0x51: // enter
2282                 switch  (bs) {
2283                 case press: ls = enter_press (button); break;
2284                 case release: ls = enter_release (button); break;
2285                 case neither: break;
2286                 }
2287                 break;
2288
2289         case 0x52: // cancel
2290                 switch  (bs) {
2291                 case press: ls = cancel_press (button); break;
2292                 case release: ls = cancel_release (button); break;
2293                 case neither: break;
2294                 }
2295                 break;
2296
2297         case 0x53: // mixer
2298                 switch  (bs) {
2299                 case press: ls = mixer_press (button); break;
2300                 case release: ls = mixer_release (button); break;
2301                 case neither: break;
2302                 }
2303                 break;
2304
2305         case 0x54: // frm_left
2306                 switch  (bs) {
2307                 case press: ls = frm_left_press (button); break;
2308                 case release: ls = frm_left_release (button); break;
2309                 case neither: break;
2310                 }
2311                 break;
2312
2313         case 0x55: // frm_right
2314                 switch  (bs) {
2315                 case press: ls = frm_right_press (button); break;
2316                 case release: ls = frm_right_release (button); break;
2317                 case neither: break;
2318                 }
2319                 break;
2320
2321         case 0x56: // loop
2322                 switch  (bs) {
2323                 case press: ls = loop_press (button); break;
2324                 case release: ls = loop_release (button); break;
2325                 case neither: break;
2326                 }
2327                 break;
2328
2329         case 0x57: // punch_in
2330                 switch  (bs) {
2331                 case press: ls = punch_in_press (button); break;
2332                 case release: ls = punch_in_release (button); break;
2333                 case neither: break;
2334                 }
2335                 break;
2336
2337         case 0x58: // punch_out
2338                 switch  (bs) {
2339                 case press: ls = punch_out_press (button); break;
2340                 case release: ls = punch_out_release (button); break;
2341                 case neither: break;
2342                 }
2343                 break;
2344
2345         case 0x59: // home
2346                 switch  (bs) {
2347                 case press: ls = home_press (button); break;
2348                 case release: ls = home_release (button); break;
2349                 case neither: break;
2350                 }
2351                 break;
2352
2353         case 0x5a: // end
2354                 switch  (bs) {
2355                 case press: ls = end_press (button); break;
2356                 case release: ls = end_release (button); break;
2357                 case neither: break;
2358                 }
2359                 break;
2360
2361         case 0x5b: // rewind
2362                 switch  (bs) {
2363                 case press: ls = rewind_press (button); break;
2364                 case release: ls = rewind_release (button); break;
2365                 case neither: break;
2366                 }
2367                 break;
2368
2369         case 0x5c: // ffwd
2370                 switch  (bs) {
2371                 case press: ls = ffwd_press (button); break;
2372                 case release: ls = ffwd_release (button); break;
2373                 case neither: break;
2374                 }
2375                 break;
2376
2377         case 0x5d: // stop
2378                 switch  (bs) {
2379                 case press: ls = stop_press (button); break;
2380                 case release: ls = stop_release (button); break;
2381                 case neither: break;
2382                 }
2383                 break;
2384
2385         case 0x5e: // play
2386                 switch  (bs) {
2387                 case press: ls = play_press (button); break;
2388                 case release: ls = play_release (button); break;
2389                 case neither: break;
2390                 }
2391                 break;
2392
2393         case 0x5f: // record
2394                 switch  (bs) {
2395                 case press: ls = record_press (button); break;
2396                 case release: ls = record_release (button); break;
2397                 case neither: break;
2398                 }
2399                 break;
2400
2401         case 0x60: // cursor_up
2402                 switch  (bs) {
2403                 case press: ls = cursor_up_press (button); break;
2404                 case release: ls = cursor_up_release (button); break;
2405                 case neither: break;
2406                 }
2407                 break;
2408
2409         case 0x61: // cursor_down
2410                 switch  (bs) {
2411                 case press: ls = cursor_down_press (button); break;
2412                 case release: ls = cursor_down_release (button); break;
2413                 case neither: break;
2414                 }
2415                 break;
2416
2417         case 0x62: // cursor_left
2418                 switch  (bs) {
2419                 case press: ls = cursor_left_press (button); break;
2420                 case release: ls = cursor_left_release (button); break;
2421                 case neither: break;
2422                 }
2423                 break;
2424
2425         case 0x63: // cursor_right
2426                 switch  (bs) {
2427                 case press: ls = cursor_right_press (button); break;
2428                 case release: ls = cursor_right_release (button); break;
2429                 case neither: break;
2430                 }
2431                 break;
2432
2433         case 0x64: // zoom
2434                 switch  (bs) {
2435                 case press: ls = zoom_press (button); break;
2436                 case release: ls = zoom_release (button); break;
2437                 case neither: break;
2438                 }
2439                 break;
2440
2441         case 0x65: // scrub
2442                 switch  (bs) {
2443                 case press: ls = scrub_press (button); break;
2444                 case release: ls = scrub_release (button); break;
2445                 case neither: break;
2446                 }
2447                 break;
2448
2449         case 0x66: // user_a
2450                 switch  (bs) {
2451                 case press: ls = user_a_press (button); break;
2452                 case release: ls = user_a_release (button); break;
2453                 case neither: break;
2454                 }
2455                 break;
2456
2457         case 0x67: // user_b
2458                 switch  (bs) {
2459                 case press: ls = user_b_press (button); break;
2460                 case release: ls = user_b_release (button); break;
2461                 case neither: break;
2462                 }
2463                 break;
2464
2465         }
2466
2467         update_led (button, ls);
2468 }