dedd3332a85d815ec773c999a7f835758b6712fb
[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::drop_press (Button &)
1725 {
1726         session->remove_last_capture();
1727         return on;
1728 }
1729
1730 LedState 
1731 MackieControlProtocol::drop_release (Button &)
1732 {
1733         return off;
1734 }
1735
1736 LedState 
1737 MackieControlProtocol::save_press (Button &)
1738 {
1739         session->save_state ("");
1740         return on;
1741 }
1742
1743 LedState 
1744 MackieControlProtocol::save_release (Button &)
1745 {
1746         return off;
1747 }
1748
1749 LedState 
1750 MackieControlProtocol::timecode_beats_press (Button &)
1751 {
1752         switch (_timecode_type) {
1753         case ARDOUR::AnyTime::BBT:
1754                 _timecode_type = ARDOUR::AnyTime::Timecode;
1755                 break;
1756         case ARDOUR::AnyTime::Timecode:
1757                 _timecode_type = ARDOUR::AnyTime::BBT;
1758                 break;
1759         default:
1760                 ostringstream os;
1761                 os << "Unknown Anytime::Type " << _timecode_type;
1762                 throw runtime_error (os.str());
1763         }
1764         update_timecode_beats_led();
1765         return on;
1766 }
1767
1768 LedState 
1769 MackieControlProtocol::timecode_beats_release (Button &)
1770 {
1771         return off;
1772 }
1773
1774 list<boost::shared_ptr<ARDOUR::Bundle> >
1775 MackieControlProtocol::bundles ()
1776 {
1777         list<boost::shared_ptr<ARDOUR::Bundle> > b;
1778         b.push_back (_input_bundle);
1779         b.push_back (_output_bundle);
1780         return b;
1781 }
1782
1783 void
1784 MackieControlProtocol::port_connected_or_disconnected (string a, string b, bool connected)
1785 {
1786         /* If something is connected to one of our output ports, send MIDI to update the surface
1787            to whatever state it should have.
1788         */
1789
1790         if (!connected) {
1791                 return;
1792         }
1793
1794         MackiePorts::const_iterator i = _ports.begin();
1795         while (i != _ports.end()) {
1796
1797                 string const n = AudioEngine::instance()->make_port_name_non_relative ((*i)->output_port().name ());
1798
1799                 if (a == n || b == n) {
1800                         break;
1801                 }
1802
1803                 ++i;
1804         }
1805
1806         if (i != _ports.end ()) {
1807                 update_surface ();
1808         }
1809 }
1810
1811 void
1812 MackieControlProtocol::do_request (MackieControlUIRequest* req)
1813 {
1814         if (req->type == CallSlot) {
1815
1816                 call_slot (MISSING_INVALIDATOR, req->the_slot);
1817
1818         } else if (req->type == Quit) {
1819
1820                 stop ();
1821         }
1822 }
1823
1824 int
1825 MackieControlProtocol::stop ()
1826 {
1827         BaseUI::quit ();
1828
1829         return 0;
1830 }
1831
1832 /** Add a timeout so that a control's in_use flag will be reset some time in the future.
1833  *  @param in_use_control the control whose in_use flag to reset.
1834  *  @param touch_control a touch control to emit an event for, or 0.
1835  */
1836 void
1837 MackieControlProtocol::add_in_use_timeout (SurfacePort& port, Control& in_use_control, Control* touch_control)
1838 {
1839         Glib::RefPtr<Glib::TimeoutSource> timeout (Glib::TimeoutSource::create (250)); // milliseconds
1840
1841         in_use_control.in_use_connection.disconnect ();
1842         in_use_control.in_use_connection = timeout->connect (
1843                 sigc::bind (sigc::mem_fun (*this, &MackieControlProtocol::control_in_use_timeout), &port, &in_use_control, touch_control));
1844         in_use_control.in_use_touch_control = touch_control;
1845
1846         timeout->attach (main_loop()->get_context());
1847
1848         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("timeout queued for port %1, control %2 touch control %3\n",
1849                                                            &port, &in_use_control, touch_control));}
1850
1851 /** Handle timeouts to reset in_use for controls that can't
1852  *  do this by themselves (e.g. pots, and faders without touch support).
1853  *  @param in_use_control the control whose in_use flag to reset.
1854  *  @param touch_control a touch control to emit an event for, or 0.
1855  */
1856 bool
1857 MackieControlProtocol::control_in_use_timeout (SurfacePort* port, Control* in_use_control, Control* touch_control)
1858 {
1859         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("timeout elapsed for port %1, control %2 touch control %3\n",
1860                                                            port, in_use_control, touch_control));
1861
1862         in_use_control->set_in_use (false);
1863
1864         if (touch_control) {
1865                 // empty control_state
1866                 ControlState control_state;
1867                 handle_control_event (*port, *touch_control, control_state);
1868         }
1869         
1870         // only call this method once from the timer
1871         return false;
1872 }
1873
1874 void 
1875 MackieControlProtocol::update_led (Button& button, Mackie::LedState ls)
1876 {
1877         if (ls != none) {
1878                 SurfacePort * port = 0;
1879
1880                 if (button.group().is_strip()) {
1881                         if (button.group().is_master()) {
1882                                 port = &mcu_port();
1883                         } else {
1884                                 port = &port_for_id (dynamic_cast<const Strip&> (button.group()).index());
1885                         }
1886                 } else {
1887                         port = &mcu_port();
1888                 }
1889                 port->write (builder.build_led (button, ls));
1890         }
1891 }
1892
1893 void 
1894 MackieControlProtocol::handle_button_event (Button& button, ButtonState bs)
1895 {
1896         if  (bs != press && bs != release) {
1897                 update_led (button, none);
1898                 return;
1899         }
1900         
1901         LedState ls;
1902
1903         DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Handling %1 for button %2\n", (bs == press ? "press" : "release"), button.raw_id()));
1904
1905         switch  (button.raw_id()) {
1906         case 0x28: // io
1907                 switch  (bs) {
1908                 case press: ls = io_press (button); break;
1909                 case release: ls = io_release (button); break;
1910                 case neither: break;
1911                 }
1912                 break;
1913                 
1914         case 0x29: // sends
1915                 switch  (bs) {
1916                 case press: ls = sends_press (button); break;
1917                 case release: ls = sends_release (button); break;
1918                 case neither: break;
1919                 }
1920                 break;
1921                 
1922         case 0x2a: // pan
1923                 switch  (bs) {
1924                 case press: ls = pan_press (button); break;
1925                 case release: ls = pan_release (button); break;
1926                 case neither: break;
1927                 }
1928                 break;
1929                 
1930         case 0x2b: // plugin
1931                 switch  (bs) {
1932                 case press: ls = plugin_press (button); break;
1933                 case release: ls = plugin_release (button); break;
1934                 case neither: break;
1935                 }
1936                 break;
1937                 
1938         case 0x2c: // eq
1939                 switch  (bs) {
1940                 case press: ls = eq_press (button); break;
1941                 case release: ls = eq_release (button); break;
1942                 case neither: break;
1943                 }
1944                 break;
1945                 
1946         case 0x2d: // dyn
1947                 switch  (bs) {
1948                 case press: ls = dyn_press (button); break;
1949                 case release: ls = dyn_release (button); break;
1950                 case neither: break;
1951                 }
1952                 break;
1953                 
1954         case 0x2e: // left
1955                 switch  (bs) {
1956                 case press: ls = left_press (button); break;
1957                 case release: ls = left_release (button); break;
1958                 case neither: break;
1959                 }
1960                 break;
1961                 
1962         case 0x2f: // right
1963                 switch  (bs) {
1964                 case press: ls = right_press (button); break;
1965                 case release: ls = right_release (button); break;
1966                 case neither: break;
1967                 }
1968                 break;
1969                 
1970         case 0x30: // channel_left
1971                 switch  (bs) {
1972                 case press: ls = channel_left_press (button); break;
1973                 case release: ls = channel_left_release (button); break;
1974                 case neither: break;
1975                 }
1976                 break;
1977                 
1978         case 0x31: // channel_right
1979                 switch  (bs) {
1980                 case press: ls = channel_right_press (button); break;
1981                 case release: ls = channel_right_release (button); break;
1982                 case neither: break;
1983                 }
1984                 break;
1985                 
1986         case 0x32: // flip
1987                 switch  (bs) {
1988                 case press: ls = flip_press (button); break;
1989                 case release: ls = flip_release (button); break;
1990                 case neither: break;
1991                 }
1992                 break;
1993
1994         case 0x33: // edit
1995                 switch  (bs) {
1996                 case press: ls = edit_press (button); break;
1997                 case release: ls = edit_release (button); break;
1998                 case neither: break;
1999                 }
2000                 break;
2001
2002         case 0x34: // name_value
2003                 switch  (bs) {
2004                 case press: ls = name_value_press (button); break;
2005                 case release: ls = name_value_release (button); break;
2006                 case neither: break;
2007                 }
2008                 break;
2009
2010         case 0x35: // timecode_beats
2011                 switch  (bs) {
2012                 case press: ls = timecode_beats_press (button); break;
2013                 case release: ls = timecode_beats_release (button); break;
2014                 case neither: break;
2015                 }
2016                 break;
2017
2018         case 0x36: // F1
2019                 switch  (bs) {
2020                 case press: ls = F1_press (button); break;
2021                 case release: ls = F1_release (button); break;
2022                 case neither: break;
2023                 }
2024                 break;
2025
2026         case 0x37: // F2
2027                 switch  (bs) {
2028                 case press: ls = F2_press (button); break;
2029                 case release: ls = F2_release (button); break;
2030                 case neither: break;
2031                 }
2032                 break;
2033
2034         case 0x38: // F3
2035                 switch  (bs) {
2036                 case press: ls = F3_press (button); break;
2037                 case release: ls = F3_release (button); break;
2038                 case neither: break;
2039                 }
2040                 break;
2041
2042         case 0x39: // F4
2043                 switch  (bs) {
2044                 case press: ls = F4_press (button); break;
2045                 case release: ls = F4_release (button); break;
2046                 case neither: break;
2047                 }
2048                 break;
2049
2050         case 0x3a: // F5
2051                 switch  (bs) {
2052                 case press: ls = F5_press (button); break;
2053                 case release: ls = F5_release (button); break;
2054                 case neither: break;
2055                 }
2056                 break;
2057
2058         case 0x3b: // F6
2059                 switch  (bs) {
2060                 case press: ls = F6_press (button); break;
2061                 case release: ls = F6_release (button); break;
2062                 case neither: break;
2063                 }
2064                 break;
2065
2066         case 0x3c: // F7
2067                 switch  (bs) {
2068                 case press: ls = F7_press (button); break;
2069                 case release: ls = F7_release (button); break;
2070                 case neither: break;
2071                 }
2072                 break;
2073
2074         case 0x3d: // F8
2075                 switch  (bs) {
2076                 case press: ls = F8_press (button); break;
2077                 case release: ls = F8_release (button); break;
2078                 case neither: break;
2079                 }
2080                 break;
2081
2082         case 0x3e: // F9
2083                 switch  (bs) {
2084                 case press: ls = F9_press (button); break;
2085                 case release: ls = F9_release (button); break;
2086                 case neither: break;
2087                 }
2088                 break;
2089
2090         case 0x3f: // F10
2091                 switch  (bs) {
2092                 case press: ls = F10_press (button); break;
2093                 case release: ls = F10_release (button); break;
2094                 case neither: break;
2095                 }
2096                 break;
2097
2098         case 0x40: // F11
2099                 switch  (bs) {
2100                 case press: ls = F11_press (button); break;
2101                 case release: ls = F11_release (button); break;
2102                 case neither: break;
2103                 }
2104                 break;
2105
2106         case 0x41: // F12
2107                 switch  (bs) {
2108                 case press: ls = F12_press (button); break;
2109                 case release: ls = F12_release (button); break;
2110                 case neither: break;
2111                 }
2112                 break;
2113
2114         case 0x42: // F13
2115                 switch  (bs) {
2116                 case press: ls = F13_press (button); break;
2117                 case release: ls = F13_release (button); break;
2118                 case neither: break;
2119                 }
2120                 break;
2121
2122         case 0x43: // F14
2123                 switch  (bs) {
2124                 case press: ls = F14_press (button); break;
2125                 case release: ls = F14_release (button); break;
2126                 case neither: break;
2127                 }
2128                 break;
2129
2130         case 0x44: // F15
2131                 switch  (bs) {
2132                 case press: ls = F15_press (button); break;
2133                 case release: ls = F15_release (button); break;
2134                 case neither: break;
2135                 }
2136                 break;
2137
2138         case 0x45: // F16
2139                 switch  (bs) {
2140                 case press: ls = F16_press (button); break;
2141                 case release: ls = F16_release (button); break;
2142                 case neither: break;
2143                 }
2144                 break;
2145
2146         case 0x46: // shift
2147                 switch  (bs) {
2148                 case press: ls = shift_press (button); break;
2149                 case release: ls = shift_release (button); break;
2150                 case neither: break;
2151                 }
2152                 break;
2153
2154         case 0x47: // option
2155                 switch  (bs) {
2156                 case press: ls = option_press (button); break;
2157                 case release: ls = option_release (button); break;
2158                 case neither: break;
2159                 }
2160                 break;
2161
2162         case 0x48: // control
2163                 switch  (bs) {
2164                 case press: ls = control_press (button); break;
2165                 case release: ls = control_release (button); break;
2166                 case neither: break;
2167                 }
2168                 break;
2169
2170         case 0x49: // cmd_alt
2171                 switch  (bs) {
2172                 case press: ls = cmd_alt_press (button); break;
2173                 case release: ls = cmd_alt_release (button); break;
2174                 case neither: break;
2175                 }
2176                 break;
2177
2178         case 0x4a: // on
2179                 switch  (bs) {
2180                 case press: ls = on_press (button); break;
2181                 case release: ls = on_release (button); break;
2182                 case neither: break;
2183                 }
2184                 break;
2185
2186         case 0x4b: // rec_ready
2187                 switch  (bs) {
2188                 case press: ls = rec_ready_press (button); break;
2189                 case release: ls = rec_ready_release (button); break;
2190                 case neither: break;
2191                 }
2192                 break;
2193
2194         case 0x4c: // undo
2195                 switch  (bs) {
2196                 case press: ls = undo_press (button); break;
2197                 case release: ls = undo_release (button); break;
2198                 case neither: break;
2199                 }
2200                 break;
2201
2202         case 0x4d: // snapshot
2203                 switch  (bs) {
2204                 case press: ls = snapshot_press (button); break;
2205                 case release: ls = snapshot_release (button); break;
2206                 case neither: break;
2207                 }
2208                 break;
2209
2210         case 0x4e: // touch
2211                 switch  (bs) {
2212                 case press: ls = touch_press (button); break;
2213                 case release: ls = touch_release (button); break;
2214                 case neither: break;
2215                 }
2216                 break;
2217
2218         case 0x4f: // redo
2219                 switch  (bs) {
2220                 case press: ls = redo_press (button); break;
2221                 case release: ls = redo_release (button); break;
2222                 case neither: break;
2223                 }
2224                 break;
2225
2226         case 0x50: // marker
2227                 switch  (bs) {
2228                 case press: ls = marker_press (button); break;
2229                 case release: ls = marker_release (button); break;
2230                 case neither: break;
2231                 }
2232                 break;
2233
2234         case 0x51: // enter
2235                 switch  (bs) {
2236                 case press: ls = enter_press (button); break;
2237                 case release: ls = enter_release (button); break;
2238                 case neither: break;
2239                 }
2240                 break;
2241
2242         case 0x52: // cancel
2243                 switch  (bs) {
2244                 case press: ls = cancel_press (button); break;
2245                 case release: ls = cancel_release (button); break;
2246                 case neither: break;
2247                 }
2248                 break;
2249
2250         case 0x53: // mixer
2251                 switch  (bs) {
2252                 case press: ls = mixer_press (button); break;
2253                 case release: ls = mixer_release (button); break;
2254                 case neither: break;
2255                 }
2256                 break;
2257
2258         case 0x54: // frm_left
2259                 switch  (bs) {
2260                 case press: ls = frm_left_press (button); break;
2261                 case release: ls = frm_left_release (button); break;
2262                 case neither: break;
2263                 }
2264                 break;
2265
2266         case 0x55: // frm_right
2267                 switch  (bs) {
2268                 case press: ls = frm_right_press (button); break;
2269                 case release: ls = frm_right_release (button); break;
2270                 case neither: break;
2271                 }
2272                 break;
2273
2274         case 0x56: // loop
2275                 switch  (bs) {
2276                 case press: ls = loop_press (button); break;
2277                 case release: ls = loop_release (button); break;
2278                 case neither: break;
2279                 }
2280                 break;
2281
2282         case 0x57: // punch_in
2283                 switch  (bs) {
2284                 case press: ls = punch_in_press (button); break;
2285                 case release: ls = punch_in_release (button); break;
2286                 case neither: break;
2287                 }
2288                 break;
2289
2290         case 0x58: // punch_out
2291                 switch  (bs) {
2292                 case press: ls = punch_out_press (button); break;
2293                 case release: ls = punch_out_release (button); break;
2294                 case neither: break;
2295                 }
2296                 break;
2297
2298         case 0x59: // home
2299                 switch  (bs) {
2300                 case press: ls = home_press (button); break;
2301                 case release: ls = home_release (button); break;
2302                 case neither: break;
2303                 }
2304                 break;
2305
2306         case 0x5a: // end
2307                 switch  (bs) {
2308                 case press: ls = end_press (button); break;
2309                 case release: ls = end_release (button); break;
2310                 case neither: break;
2311                 }
2312                 break;
2313
2314         case 0x5b: // rewind
2315                 switch  (bs) {
2316                 case press: ls = rewind_press (button); break;
2317                 case release: ls = rewind_release (button); break;
2318                 case neither: break;
2319                 }
2320                 break;
2321
2322         case 0x5c: // ffwd
2323                 switch  (bs) {
2324                 case press: ls = ffwd_press (button); break;
2325                 case release: ls = ffwd_release (button); break;
2326                 case neither: break;
2327                 }
2328                 break;
2329
2330         case 0x5d: // stop
2331                 switch  (bs) {
2332                 case press: ls = stop_press (button); break;
2333                 case release: ls = stop_release (button); break;
2334                 case neither: break;
2335                 }
2336                 break;
2337
2338         case 0x5e: // play
2339                 switch  (bs) {
2340                 case press: ls = play_press (button); break;
2341                 case release: ls = play_release (button); break;
2342                 case neither: break;
2343                 }
2344                 break;
2345
2346         case 0x5f: // record
2347                 switch  (bs) {
2348                 case press: ls = record_press (button); break;
2349                 case release: ls = record_release (button); break;
2350                 case neither: break;
2351                 }
2352                 break;
2353
2354         case 0x60: // cursor_up
2355                 switch  (bs) {
2356                 case press: ls = cursor_up_press (button); break;
2357                 case release: ls = cursor_up_release (button); break;
2358                 case neither: break;
2359                 }
2360                 break;
2361
2362         case 0x61: // cursor_down
2363                 switch  (bs) {
2364                 case press: ls = cursor_down_press (button); break;
2365                 case release: ls = cursor_down_release (button); break;
2366                 case neither: break;
2367                 }
2368                 break;
2369
2370         case 0x62: // cursor_left
2371                 switch  (bs) {
2372                 case press: ls = cursor_left_press (button); break;
2373                 case release: ls = cursor_left_release (button); break;
2374                 case neither: break;
2375                 }
2376                 break;
2377
2378         case 0x63: // cursor_right
2379                 switch  (bs) {
2380                 case press: ls = cursor_right_press (button); break;
2381                 case release: ls = cursor_right_release (button); break;
2382                 case neither: break;
2383                 }
2384                 break;
2385
2386         case 0x64: // zoom
2387                 switch  (bs) {
2388                 case press: ls = zoom_press (button); break;
2389                 case release: ls = zoom_release (button); break;
2390                 case neither: break;
2391                 }
2392                 break;
2393
2394         case 0x65: // scrub
2395                 switch  (bs) {
2396                 case press: ls = scrub_press (button); break;
2397                 case release: ls = scrub_release (button); break;
2398                 case neither: break;
2399                 }
2400                 break;
2401
2402         case 0x66: // user_a
2403                 switch  (bs) {
2404                 case press: ls = user_a_press (button); break;
2405                 case release: ls = user_a_release (button); break;
2406                 case neither: break;
2407                 }
2408                 break;
2409
2410         case 0x67: // user_b
2411                 switch  (bs) {
2412                 case press: ls = user_b_press (button); break;
2413                 case release: ls = user_b_release (button); break;
2414                 case neither: break;
2415                 }
2416                 break;
2417
2418         }
2419
2420         update_led (button, ls);
2421 }