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