remove Id: lines from many/all headers and some more source files
[ardour.git] / libs / surfaces / frontier / tranzport / tranzport_control_protocol.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
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
20 /* Design notes: The tranzport is a unique device, basically a 
21    20 lcd gui with 22 shift keys and 8 blinking lights. 
22
23    As such it has several unique constraints. The device exerts flow control
24    by having a usb write fail. It is pointless to retry madly at that point,
25    the device is busy, and it's not going to become unbusy very quickly. 
26
27    So writes need to be either "mandatory" or "unreliable", and therein 
28    lies the rub, as the kernel can also drop writes, and missing an
29    interrupt in userspace is also generally bad.
30
31    It will be good one day, to break the gui, keyboard, and blinking light
32    components into separate parts, but for now, this remains monolithic.
33
34    A more complex surface might have hundreds of lights and several displays.
35
36    mike.taht@gmail.com
37  */
38
39 #define DEFAULT_USB_TIMEOUT 10
40 #define MAX_RETRY 1
41 #define MAX_TRANZPORT_INFLIGHT 4
42 #define DEBUG_TRANZPORT 0
43 #define HAVE_TRANZPORT_KERNEL_DRIVER 0
44
45 #include <iostream>
46 #include <algorithm>
47 #include <cmath>
48
49 #define __STDC_FORMAT_MACROS
50 #include <inttypes.h>
51 #include <float.h>
52 #include <sys/time.h>
53 #include <errno.h>
54
55 #include <pbd/pthread_utils.h>
56
57 #include <ardour/route.h>
58 #include <ardour/audio_track.h>
59 #include <ardour/session.h>
60 #include <ardour/tempo.h>
61 #include <ardour/location.h>
62 #include <ardour/dB.h>
63
64 #include "tranzport_control_protocol.h"
65
66 using namespace ARDOUR;
67 using namespace std;
68 using namespace sigc;
69 using namespace PBD;
70
71 #include "i18n.h"
72
73 #include <pbd/abstract_ui.cc>
74
75 BaseUI::RequestType LEDChange = BaseUI::new_request_type ();
76 BaseUI::RequestType Print = BaseUI::new_request_type ();
77 BaseUI::RequestType SetCurrentTrack = BaseUI::new_request_type ();
78
79 /* Base Tranzport cmd strings */
80
81 static const uint8_t cmd_light_on[] =  { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
82 static const uint8_t cmd_light_off[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
83 static const uint8_t cmd_write_screen[] =  { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
84
85 static inline double 
86 gain_to_slider_position (ARDOUR::gain_t g)
87 {
88         if (g == 0) return 0;
89         return pow((6.0*log(g)/log(2.0)+192.0)/198.0, 8.0);
90
91 }
92
93 static inline ARDOUR::gain_t 
94 slider_position_to_gain (double pos)
95 {
96         /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
97         if (pos == 0.0) return 0;
98         return pow (2.0,(sqrt(sqrt(sqrt(pos)))*198.0-192.0)/6.0);
99 }
100
101
102 TranzportControlProtocol::TranzportControlProtocol (Session& s)
103         : ControlProtocol  (s, X_("Tranzport"))
104 {
105         /* tranzport controls one track at a time */
106
107         set_route_table_size (1);
108         timeout = 6000; // what is this for?
109         buttonmask = 0;
110         _datawheel = 0;
111         _device_status = STATUS_OFFLINE;
112         udev = 0;
113         current_track_id = 0;
114         last_where = max_frames;
115         wheel_mode = WheelTimeline;
116         wheel_shift_mode = WheelShiftGain;
117         wheel_increment = WheelIncrScreen;
118         bling_mode = BlingOff;
119         timerclear (&last_wheel_motion);
120         last_wheel_dir = 1;
121         last_track_gain = FLT_MAX;
122         display_mode = DisplayNormal;
123         gain_fraction = 0.0;
124         invalidate();
125         screen_init();
126         lights_init();
127         print(0,0,"!!Welcome to Ardour!!");
128         print(1,0,"!Peace through Music!");
129 }
130
131 void TranzportControlProtocol::light_validate (LightID light) 
132 {
133         lights_invalid[light] = 0;
134 }
135
136 void TranzportControlProtocol::light_invalidate (LightID light) 
137 {
138         lights_invalid[light] = 1;
139 }
140
141 void TranzportControlProtocol::lights_validate () 
142 {
143         memset (lights_invalid, 0, sizeof (lights_invalid)); 
144 }
145
146 void TranzportControlProtocol::lights_invalidate () 
147 {
148         memset (lights_invalid, 1, sizeof (lights_invalid)); 
149 }
150
151 void TranzportControlProtocol::lights_init()
152 {
153         for (uint32_t i = 0; i < sizeof(lights_current)/sizeof(lights_current[0]); i++) {
154                 lights_invalid[i] = lights_current[i] = 
155                         lights_pending[i] = lights_flash[i] = false;
156         }
157 }
158
159
160
161 int
162 TranzportControlProtocol::lights_flush ()
163 {
164         if ( _device_status == STATUS_OFFLINE) { return (0); }
165
166         //  Figure out iterators one day soon
167         //  for (LightID i = i.start(), i = i.end(); i++) {
168         //  if (lights_pending[i] != lights_current[i] || lights_invalid[i]) {
169         //    if (light_set(i, lights_pending[i])) { 
170         //       return i-1;
171         //    } 
172         //  }
173         //}
174         if ((lights_pending[LightRecord] != lights_current[LightRecord]) || lights_invalid[LightRecord]) {
175                 if (light_set(LightRecord,lights_pending[LightRecord])) {
176                         return 1;
177                 }
178         }
179         if ((lights_pending[LightTrackrec] != lights_current[LightTrackrec]) || lights_invalid[LightTrackrec]) {
180                 if (light_set(LightTrackrec,lights_pending[LightTrackrec])) {
181                         return 1;
182                 }
183         }
184
185         if ((lights_pending[LightTrackmute] != lights_current[LightTrackmute]) || lights_invalid[LightTrackmute]) {
186                 if (light_set(LightTrackmute,lights_pending[LightTrackmute])) {
187                         return 1;
188                 }
189         }
190
191         if ((lights_pending[LightTracksolo] != lights_current[LightTracksolo]) || lights_invalid[LightTracksolo]) {
192                 if (light_set(LightTracksolo,lights_pending[LightTracksolo])) {
193                         return 1;
194                 }
195         }
196         if ((lights_pending[LightAnysolo] != lights_current[LightAnysolo]) || lights_invalid[LightAnysolo]) {
197                 if (light_set(LightAnysolo,lights_pending[LightAnysolo])) {
198                         return 1;
199                 }
200         }
201         if ((lights_pending[LightLoop] != lights_current[LightLoop]) || lights_invalid[LightLoop]) {
202                 if (light_set(LightLoop,lights_pending[LightLoop])) {
203                         return 1;
204                 }
205         }
206         if ((lights_pending[LightPunch] != lights_current[LightPunch]) || lights_invalid[LightPunch]) {
207                 if (light_set(LightPunch,lights_pending[LightPunch])) {
208                         return 1;
209                 }
210         }
211
212         return 0;
213 }
214
215 // Screen specific commands
216
217 void
218 TranzportControlProtocol::screen_clear ()
219 {
220         const char *blank = "                    ";
221         print(0,0,blank); 
222         print(1,0,blank);
223 }
224
225 void TranzportControlProtocol::screen_invalidate ()
226 {
227         for(int row = 0; row < 2; row++) {
228                 for(int col = 0; col < 20; col++) {
229                         screen_invalid[row][col] = true;
230                         screen_current[row][col] = 0x7f;
231                         screen_pending[row][col] = ' ';
232                         // screen_flash[row][col] = ' ';
233                 }
234         }
235         // memset (&screen_invalid, 1, sizeof(screen_invalid));
236         // memset (&screen_current, 0x7F, sizeof (screen_current)); // fill cache with a character we otherwise never use
237 }
238
239 void TranzportControlProtocol::screen_validate ()
240 {
241 }
242
243 void TranzportControlProtocol::screen_init ()
244 {
245         screen_invalidate();
246 }
247
248 int
249 TranzportControlProtocol::screen_flush ()
250 {
251         int cell = 0, row, col_base, col, pending = 0;
252         if ( _device_status == STATUS_OFFLINE) { return (-1); }
253
254         for (row = 0; row < 2 && pending == 0; row++) {
255                 for (col_base = 0, col = 0; col < 20 && pending == 0; ) {
256                         if ((screen_pending[row][col] != screen_current[row][col]) 
257                                         || screen_invalid[row][col]) {
258
259                                 /* something in this cell is different, so dump the cell to the device. */
260
261                                 uint8_t cmd[8]; 
262                                 cmd[0] = 0x00; 
263                                 cmd[1] = 0x01; 
264                                 cmd[2] = cell; 
265                                 cmd[3] = screen_pending[row][col_base]; 
266                                 cmd[4] = screen_pending[row][col_base+1];
267                                 cmd[5] = screen_pending[row][col_base+2]; 
268                                 cmd[6] = screen_pending[row][col_base+3];
269                                 cmd[7] = 0x00;
270
271                                 if(write(cmd) != 0) {
272                                         /* try to update this cell on the next go-round */
273 #if DEBUG_TRANZPORT > 4
274                                         printf("usb screen update failed for some reason... why? \ncmd and data were %02x %02x %02x %02x %02x %02x %02x %02x\n", 
275                                                         cmd[0],cmd[1],cmd[2], cmd[3], cmd[4], cmd[5],cmd[6],cmd[7]); 
276 #endif
277                                         pending += 1;   
278                                         // Shouldn't need to do this
279                                         // screen_invalid[row][col_base] = screen_invalid[row][col_base+1] = 
280                                         // screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = true;
281
282                                 } else {
283                                         /* successful write: copy to current cached display */
284                                         screen_invalid[row][col_base] = screen_invalid[row][col_base+1] = 
285                                                 screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = false;
286                                         memcpy (&screen_current[row][col_base], &screen_pending[row][col_base], 4);
287                                 }
288
289                                 /* skip the rest of the 4 character cell since we wrote+copied it already */
290
291                                 col_base += 4;
292                                 col = col_base;
293                                 cell++;
294
295                         } else {
296
297                                 col++;
298
299                                 if (col && col % 4 == 0) {
300                                         cell++;
301                                         col_base += 4;
302                                 }
303                         }
304                 }
305         }
306         return pending;
307 }
308
309
310 //  Tranzport specific
311
312 void TranzportControlProtocol::invalidate() 
313 {
314         lcd_damage(); lights_invalidate(); screen_invalidate(); // one of these days lcds can be fine but screens not
315 }
316
317 TranzportControlProtocol::~TranzportControlProtocol ()
318 {
319         set_active (false);
320 }
321
322
323 int
324 TranzportControlProtocol::set_active (bool yn)
325 {
326         if (yn != _active) {
327
328                 if (yn) {
329
330                         if (open ()) {
331                                 return -1;
332                         }
333
334                         if (pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _monitor_work, this) == 0) {
335                                 _active = true;
336                         } else {
337                                 return -1;
338                         }
339
340                 } else {
341                         cerr << "Begin tranzport shutdown\n";
342                         screen_clear ();
343                         lcd_damage();
344                         lights_off ();
345                         for(int x = 0; x < 10 && flush(); x++) { usleep(1000); }
346                         pthread_cancel_one (thread);
347                         cerr << "Tranzport Thread dead\n";
348                         close ();
349                         _active = false;
350                         cerr << "End tranzport shutdown\n";
351                 } 
352         }
353
354         return 0;
355 }
356
357 void
358 TranzportControlProtocol::show_track_gain ()
359 {
360         if (route_table[0]) {
361                 gain_t g = route_get_gain (0);
362                 if ((g != last_track_gain) || lcd_isdamaged(0,9,8)) {
363                         char buf[16]; 
364                         snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
365                         print (0, 9, buf); 
366                         last_track_gain = g;
367                 }
368         } else {
369                 print (0, 9, "        "); 
370         }
371 }
372
373 void
374 TranzportControlProtocol::normal_update ()
375 {
376         show_current_track ();
377         show_transport_time ();
378         show_track_gain ();
379         show_wheel_mode ();
380 }
381
382 void
383 TranzportControlProtocol::next_display_mode ()
384 {
385         switch (display_mode) {
386
387                 case DisplayNormal:
388                         enter_big_meter_mode();
389                         break;
390
391                 case DisplayBigMeter:
392                         enter_normal_display_mode();
393                         break;
394
395                 case DisplayRecording:
396                         enter_normal_display_mode();
397                         break;
398
399                 case DisplayRecordingMeter:
400                         enter_big_meter_mode();
401                         break;
402
403                 case DisplayConfig: 
404                 case DisplayBling:
405                 case DisplayBlingMeter:
406                         enter_normal_display_mode();
407                         break;
408         }
409 }
410
411 // FIXME, these 3 aren't done yet
412
413 void
414 TranzportControlProtocol::enter_recording_mode ()
415 {
416         lcd_damage(); // excessive
417         screen_clear ();
418         lights_off ();
419         display_mode = DisplayRecording;
420 }
421
422 void
423 TranzportControlProtocol::enter_bling_mode ()
424 {
425         lcd_damage();
426         screen_clear ();
427         lights_off ();
428         display_mode = DisplayBling;
429 }
430
431 void
432 TranzportControlProtocol::enter_config_mode ()
433 {
434         lcd_damage();
435         screen_clear ();
436         lights_off ();
437         display_mode = DisplayConfig;
438 }
439
440
441 void
442 TranzportControlProtocol::enter_big_meter_mode ()
443 {
444         screen_clear ();
445         lcd_damage();
446         lights_off ();
447         last_meter_fill = 0;
448         display_mode = DisplayBigMeter;
449 }
450
451 void
452 TranzportControlProtocol::enter_normal_display_mode ()
453 {
454         screen_clear ();
455         lcd_damage();
456         lights_off ();
457         display_mode = DisplayNormal;
458         //  normal_update();
459 }
460
461
462 float
463 log_meter (float db)
464 {
465         float def = 0.0f; /* Meter deflection %age */
466
467         if (db < -70.0f) return 0.0f;
468         if (db > 6.0f) return 1.0f;
469
470         if (db < -60.0f) {
471                 def = (db + 70.0f) * 0.25f;
472         } else if (db < -50.0f) {
473                 def = (db + 60.0f) * 0.5f + 2.5f;
474         } else if (db < -40.0f) {
475                 def = (db + 50.0f) * 0.75f + 7.5f;
476         } else if (db < -30.0f) {
477                 def = (db + 40.0f) * 1.5f + 15.0f;
478         } else if (db < -20.0f) {
479                 def = (db + 30.0f) * 2.0f + 30.0f;
480         } else if (db < 6.0f) {
481                 def = (db + 20.0f) * 2.5f + 50.0f;
482         }
483
484         /* 115 is the deflection %age that would be 
485            when db=6.0. this is an arbitrary
486            endpoint for our scaling.
487            */
488
489         return def/115.0f;
490 }
491
492 void
493 TranzportControlProtocol::show_meter ()
494 {
495         // you only seem to get a route_table[0] on moving forward - bug elsewhere
496         if (route_table[0] == 0) {
497                 // Principle of least surprise
498                 print (0, 0, "No audio to meter!!!");
499                 print (1, 0, "Select another track"); 
500                 return;
501         }
502
503         float level = route_get_peak_input_power (0, 0);
504         float fraction = log_meter (level);
505
506         /* Someday add a peak bar*/
507
508         /* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
509            the screen is 20 chars wide, so we can display 40 different levels. compute the level,
510            then figure out how many "::" to fill. if the answer is odd, make the last one a ":"
511            */
512
513         uint32_t fill  = (uint32_t) floor (fraction * 40);
514         char buf[21];
515         uint32_t i;
516
517         if (fill == last_meter_fill) {
518                 /* nothing to do */
519                 return;
520         }
521
522         last_meter_fill = fill;
523
524         bool add_single_level = (fill % 2 != 0);
525         fill /= 2;
526
527         if (fraction > 0.98) {
528                 light_on (LightAnysolo);
529         }
530
531         /* add all full steps */
532
533         for (i = 0; i < fill; ++i) {
534                 buf[i] = 0x07; /* tranzport special code for 4 quadrant LCD block */
535         } 
536
537         /* add a possible half-step */
538
539         if (i < 20 && add_single_level) {
540                 buf[i] = 0x03; /* tranzport special code for 2 left quadrant LCD block */
541                 ++i;
542         }
543
544         /* fill rest with space */
545
546         for (; i < 20; ++i) {
547                 buf[i] = ' ';
548         }
549
550         /* print() requires this */
551
552         buf[21] = '\0';
553
554         print (0, 0, buf);
555         print (1, 0, buf);
556 }
557
558 void
559 TranzportControlProtocol::show_bbt (nframes_t where)
560
561         if ((where != last_where) || lcd_isdamaged(1,9,8)) {
562                 char buf[16];
563                 BBT_Time bbt;
564                 session->tempo_map().bbt_time (where, bbt);
565                 sprintf (buf, "%03" PRIu32 "|%02" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
566                 last_bars = bbt.bars;
567                 last_beats = bbt.beats;
568                 last_ticks = bbt.ticks;
569                 last_where = where;
570
571                 if(last_ticks < 1960) { print (1, 9, buf); } // save a write so we can do leds
572
573                 // if displaymode is recordmode show beats but not yet
574                 lights_pending[LightRecord] = false;
575                 lights_pending[LightAnysolo] = false;
576                 switch(last_beats) {
577                         case 1: if(last_ticks < 500 || last_ticks > 1960) lights_pending[LightRecord] = true; break;
578                         default: if(last_ticks < 250) lights_pending[LightAnysolo] = true;
579                 }
580
581                 // update lights for tempo one day
582                 //        if (bbt_upper_info_label) {
583                 //     TempoMap::Metric m (session->tempo_map().metric_at (when));
584                 //     sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
585                 //      bbt_lower_info_label->set_text (buf);
586                 //      sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
587                 //      bbt_upper_info_label->set_text (buf);
588         }
589         }
590
591
592 void
593 TranzportControlProtocol::show_transport_time ()
594 {
595         nframes_t where = session->transport_frame();
596         show_bbt(where);
597 }       
598
599 void
600 TranzportControlProtocol::show_smpte (nframes_t where)
601 {
602         if ((where != last_where) || lcd_isdamaged(1,9,10)) {
603
604                 char buf[5];
605                 SMPTE::Time smpte;
606
607                 session->smpte_time (where, smpte);
608
609                 if (smpte.negative) {
610                         sprintf (buf, "-%02" PRIu32 ":", smpte.hours);
611                 } else {
612                         sprintf (buf, " %02" PRIu32 ":", smpte.hours);
613                 }
614                 print (1, 8, buf);
615
616                 sprintf (buf, "%02" PRIu32 ":", smpte.minutes);
617                 print (1, 12, buf);
618
619                 sprintf (buf, "%02" PRIu32 ":", smpte.seconds);
620                 print (1, 15, buf);
621
622                 sprintf (buf, "%02" PRIu32, smpte.frames);
623                 print_noretry (1, 18, buf); 
624
625                 last_where = where;
626         }
627 }
628
629 void*
630 TranzportControlProtocol::_monitor_work (void* arg)
631 {
632         return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
633 }
634
635 // I note that these usb specific open, close, probe, read routines are basically 
636 // pure boilerplate and could easily be abstracted elsewhere
637
638 #if !HAVE_TRANZPORT_KERNEL_DRIVER
639
640 bool
641 TranzportControlProtocol::probe ()
642 {
643         struct usb_bus *bus;
644         struct usb_device *dev;
645
646         usb_init();
647         usb_find_busses();
648         usb_find_devices();
649
650         for (bus = usb_busses; bus; bus = bus->next) {
651
652                 for(dev = bus->devices; dev; dev = dev->next) {
653                         if (dev->descriptor.idVendor == VENDORID && dev->descriptor.idProduct == PRODUCTID) {
654                                 return true; 
655                         }
656                 }
657         }
658
659         return false;
660 }
661
662 int
663 TranzportControlProtocol::open ()
664 {
665         struct usb_bus *bus;
666         struct usb_device *dev;
667
668         usb_init();
669         usb_find_busses();
670         usb_find_devices();
671
672         for (bus = usb_busses; bus; bus = bus->next) {
673
674                 for(dev = bus->devices; dev; dev = dev->next) {
675                         if (dev->descriptor.idVendor != VENDORID)
676                                 continue;
677                         if (dev->descriptor.idProduct != PRODUCTID)
678                                 continue;
679                         return open_core (dev);
680                 }
681         }
682
683         error << _("Tranzport: no device detected") << endmsg;
684         return -1;
685 }
686
687 int
688 TranzportControlProtocol::open_core (struct usb_device* dev)
689 {
690         if (!(udev = usb_open (dev))) {
691                 error << _("Tranzport: cannot open USB transport") << endmsg;
692                 return -1;
693         }
694          
695         if (usb_claim_interface (udev, 0) < 0) {
696                 error << _("Tranzport: cannot claim USB interface") << endmsg;
697                 usb_close (udev);
698                 udev = 0;
699                 return -1;
700         }
701
702         if (usb_set_configuration (udev, 1) < 0) {
703                 cerr << _("Tranzport: cannot configure USB interface") << endmsg;
704         }
705
706         return 0;
707 }
708
709 int
710 TranzportControlProtocol::close ()
711 {
712         int ret = 0;
713
714         if (udev == 0) {
715                 return 0;
716         }
717
718         if (usb_release_interface (udev, 0) < 0) {
719                 error << _("Tranzport: cannot release interface") << endmsg;
720                 ret = -1;
721         }
722
723         if (usb_close (udev)) {
724                 error << _("Tranzport: cannot close device") << endmsg;
725                 udev = 0;
726                 ret = 0;
727         }
728
729         return ret;
730 }
731
732 int TranzportControlProtocol::read(uint8_t *buf, uint32_t timeout_override) 
733 {
734         int val;
735         // Get smarter about handling usb errors soon. Like disconnect
736         //  pthread_testcancel();
737         val = usb_interrupt_read (udev, READ_ENDPOINT, (char *) buf, 8, 10);
738         //  pthread_testcancel();
739         return val;
740
741
742         
743 int
744 TranzportControlProtocol::write_noretry (uint8_t* cmd, uint32_t timeout_override)
745 {
746         int val;
747         if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
748         val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
749
750         if (val < 0) {
751 #if DEBUG_TRANZPORT
752                 printf("usb_interrupt_write failed: %d\n", val);
753 #endif
754                 return val;
755                 }
756
757         if (val != 8) {
758 #if DEBUG_TRANZPORT
759                 printf("usb_interrupt_write failed: %d\n", val);
760 #endif
761                 return -1;
762                 }
763         ++inflight;
764
765         return 0;
766
767 }       
768
769 int
770 TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
771 {
772 #if MAX_RETRY > 1
773         int val;
774         int retry = 0;
775         if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
776         
777         while((val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout))!=8 && retry++ < MAX_RETRY) {
778                 printf("usb_interrupt_write failed, retrying: %d\n", val);
779         }
780
781         if (retry == MAX_RETRY) {
782                 printf("Too many retries on a tranzport write, aborting\n");
783                 }
784
785         if (val < 0) {
786                 printf("usb_interrupt_write failed: %d\n", val);
787                 return val;
788                 }
789         if (val != 8) {
790                 printf("usb_interrupt_write failed: %d\n", val);
791                 return -1;
792                 }
793         ++inflight;
794         return 0;
795 #else
796         return (write_noretry(cmd,timeout_override));
797 #endif
798
799 }       
800
801 #else
802 #error Kernel API not defined yet for Tranzport
803 // Something like open(/dev/surface/tranzport/event) for reading and raw for writing)
804 #endif
805
806 // We have a state "Unknown" - STOP USING SPACES FOR IT - switching to arrow character
807 // We have another state - no_retry. Misleading, as we still retry on the next pass
808 // I think it's pointless to keep no_retry and instead we should throttle writes 
809 // We have an "displayed" screen
810 // We always draw into the pending screen, which could be any of several screens
811 // We have an active screen
812 // Print arg - we have 
813 // setactive
814 // so someday I think we need a screen object.
815
816 /*
817 screen_flash.clear();
818 screen_flash.print(0,0,"Undone:"); // Someday pull the undo stack from somewhere
819 screen_flash.print(1,0,"Nextup:"); 
820
821 if(flash_messages && lcd.getactive() != screen_flash) lcd.setactive(screen_flash,2000);
822
823 screen::setactive(screen_name,duration); // duration in ms
824 screen::getactive();
825 */
826
827
828 int
829 TranzportControlProtocol::flush ()
830 {
831         int pending = 0;
832         if(!(pending = lights_flush())) {
833                 pending = screen_flush(); 
834         } 
835         return pending;
836 }
837
838 // doing these functions made me realize that screen_invalid should be lcd_isdamaged FIXME soon
839
840 bool TranzportControlProtocol::lcd_damage() 
841 {
842         screen_invalidate();
843         return true;
844 }
845
846 bool TranzportControlProtocol::lcd_damage (int row, int col, int length)
847 {
848         bool result = false;
849         int endcol = col+length-1;
850         if((endcol > 19)) { endcol = 19; } 
851         if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
852                 for(int c = col; c < endcol; c++) {
853                         screen_invalid[row][c] = true;
854                 }
855                 result = true;
856         }
857         return result;
858 }
859
860 // Gotta switch to bitfields, this is collossally dumb
861 // Still working on the layering, arguably screen_invalid should be lcd_invalid
862
863 bool TranzportControlProtocol::lcd_isdamaged () 
864 {
865         for(int r = 0; r < 2; r++) {
866                 for(int c = 0; c < 20; c++) {
867                         if(screen_invalid[r][c]) {
868 #if DEBUG_TRANZPORT > 5 
869                                 printf("row: %d,col: %d is damaged, should redraw it\n", r,c);
870 #endif
871                                 return true;
872                         }
873                 }
874         }
875         return false;
876 }
877
878 bool TranzportControlProtocol::lcd_isdamaged (int row, int col, int length)
879 {
880         bool result = 0;
881         int endcol = col+length;
882         if((endcol > 19)) { endcol = 19; } 
883         if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
884                 for(int c = col; c < endcol; c++) {
885                         if(screen_invalid[row][c]) {
886 #if DEBUG_TRANZPORT > 5 
887                                 printf("row: %d,col: %d is damaged, should redraw it\n", row,c);
888 #endif
889                                 return true;
890                         }
891                 }
892         }
893         return result;
894 }
895
896 // lcd_clear would be a separate function for a smart display
897 // here it does nothing, but for the sake of completeness it should
898 // probably write the lcd, and while I'm on the topic it should probably
899 // take a row, col, length argument....
900
901 void
902 TranzportControlProtocol::lcd_clear ()
903 {
904
905 }
906
907 // These lcd commands are not universally used yet and may drop out of the api
908
909 int
910 TranzportControlProtocol::lcd_flush ()
911 {
912         return 0; 
913 }
914
915 int 
916 TranzportControlProtocol::lcd_write(uint8_t* cmd, uint32_t timeout_override)
917 {
918         return write(cmd,timeout_override);
919 }
920
921 void 
922 TranzportControlProtocol::lcd_fill (uint8_t fill_char) 
923 {
924 }
925
926 void 
927 TranzportControlProtocol::lcd_print (int row, int col, const char* text) 
928 {
929         print(row,col,text);
930 }
931
932 void TranzportControlProtocol::lcd_print_noretry (int row, int col, const char* text)
933 {
934         print(row,col,text);
935 }
936
937 // Lights are buffered
938
939 void
940 TranzportControlProtocol::lights_on ()
941 {
942         lights_pending[LightRecord] = lights_pending[LightTrackrec] = 
943                 lights_pending[LightTrackmute] =  lights_pending[LightTracksolo] = 
944                 lights_pending[LightAnysolo] =   lights_pending[LightLoop] = 
945                 lights_pending[LightPunch] = true;
946 }
947
948 void
949 TranzportControlProtocol::lights_off ()
950 {
951         lights_pending[LightRecord] = lights_pending[LightTrackrec] = 
952                 lights_pending[LightTrackmute] =  lights_pending[LightTracksolo] = 
953                 lights_pending[LightAnysolo] =   lights_pending[LightLoop] = 
954                 lights_pending[LightPunch] = false;
955 }
956
957 int
958 TranzportControlProtocol::light_on (LightID light)
959 {
960         lights_pending[light] = true;
961         return 0;
962 }
963
964 int
965 TranzportControlProtocol::light_off (LightID light)
966 {
967         lights_pending[light] = false;
968         return 0;
969 }
970
971 int
972 TranzportControlProtocol::light_set (LightID light, bool offon)
973 {
974         uint8_t cmd[8];
975         cmd[0] = 0x00;  cmd[1] = 0x00;  cmd[2] = light;  cmd[3] = offon;
976         cmd[4] = 0x00;  cmd[5] = 0x00;  cmd[6] = 0x00;  cmd[7] = 0x00;
977
978         if (write (cmd) == 0) {
979                 lights_current[light] = offon;
980                 lights_invalid[light] = false;
981                 return 0;
982         } else {
983                 return -1;
984         }
985 }
986
987 int TranzportControlProtocol::rtpriority_set(int priority) 
988 {
989         struct sched_param rtparam;
990         int err;
991         // preallocate and memlock some stack with memlock?
992         char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
993         memset (&rtparam, 0, sizeof (rtparam));
994         rtparam.sched_priority = priority; /* XXX should be relative to audio (JACK) thread */
995         // Note - try SCHED_RR with a low limit 
996         // - we don't care if we can't write everything this ms
997         // and it will help if we lose the device
998         if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
999                 PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
1000                 return 1;
1001         } 
1002         return 0;
1003 }
1004
1005 // Running with realtime privs is bad when you have problems
1006
1007 int TranzportControlProtocol::rtpriority_unset(int priority) 
1008 {
1009         struct sched_param rtparam;
1010         int err;
1011         memset (&rtparam, 0, sizeof (rtparam));
1012         rtparam.sched_priority = priority;      
1013         if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
1014                 PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
1015                 return 1;
1016         } 
1017         PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
1018         return 0;
1019 }
1020
1021 // Slowly breaking this into where I can make usb processing it's own thread.
1022
1023 void*
1024 TranzportControlProtocol::monitor_work ()
1025 {
1026         uint8_t buf[8];
1027         int val = 0, pending = 0;
1028         bool first_time = true;
1029         uint8_t offline = 0;
1030
1031
1032         PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
1033         pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
1034         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
1035         next_track ();
1036         rtpriority_set();
1037         inflight=0;
1038         flush();
1039
1040         while (true) {
1041
1042                 /* bInterval for this beastie is 10ms */
1043
1044                 if (_device_status == STATUS_OFFLINE) {
1045                         first_time = true;
1046                         if(offline++ == 1) { 
1047                                 cerr << "Transport has gone offline\n";
1048                         }
1049                 } else { 
1050                         offline = 0; // hate writing this
1051                 }
1052
1053                 val = read(buf);
1054
1055                 if (val == 8) {
1056                         process (buf);
1057                 }
1058
1059 #if DEBUG_TRANZPORT > 2
1060                 if(inflight > 1) printf("Inflight: %d\n", inflight);
1061 #endif
1062
1063
1064                 if (_device_status != STATUS_OFFLINE) {
1065                         if (first_time) {
1066                                 invalidate();
1067                                 lcd_clear ();
1068                                 lights_off ();
1069                                 first_time = false;
1070                                 offline = 0;
1071                                 pending = 3; // Give some time for the device to recover
1072                         }
1073                         /* update whatever needs updating */
1074                         update_state ();
1075
1076                         /* still struggling with a good means of exerting flow control */
1077                         // pending = flush();
1078
1079                         if(pending == 0) {
1080                                 pending = flush(); 
1081                         } else {
1082                                 if(inflight > 0) {
1083                                         pending = --inflight; // we just did a whole bunch of writes so wait
1084                                 } else {
1085                                         pending = 0;
1086                                 }
1087                         }
1088                         // pending = 0;
1089                 } 
1090         }
1091
1092         return (void*) 0;
1093 }
1094
1095 int TranzportControlProtocol::lights_show_recording() 
1096 {
1097         //   FIXME, flash recording light when recording and transport is moving
1098         return     lights_show_normal();
1099 }
1100
1101 // gotta do bling next!
1102
1103 int TranzportControlProtocol::lights_show_bling() 
1104 {
1105         switch (bling_mode) {
1106                 case BlingOff: break;
1107                 case BlingKit: break; // rotate rec/mute/solo/any solo back and forth
1108                 case BlingRotating: break; // switch between lights
1109                 case BlingPairs: break; // Show pairs of lights
1110                 case BlingRows: break; // light each row in sequence
1111                 case BlingFlashAll: break; // Flash everything randomly
1112         }
1113         return 0;
1114 }
1115
1116 int TranzportControlProtocol::lights_show_normal() 
1117 {
1118         /* Track only */
1119
1120         if (route_table[0]) {
1121                 boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
1122                 lights_pending[LightTrackrec]  = at && at->record_enabled();
1123                 lights_pending[LightTrackmute] = route_get_muted(0); 
1124                 lights_pending[LightTracksolo] = route_get_soloed(0);
1125         } else {
1126                 lights_pending[LightTrackrec]  = false;
1127                 lights_pending[LightTracksolo] = false;
1128                 lights_pending[LightTrackmute] = false;
1129         }
1130
1131         /* Global settings */
1132
1133         lights_pending[LightLoop]        = session->get_play_loop(); 
1134         lights_pending[LightPunch]       = Config->get_punch_in() || Config->get_punch_out();
1135         lights_pending[LightRecord]      = session->get_record_enabled();
1136         lights_pending[LightAnysolo]     = session->soloing();
1137
1138         return 0;
1139 }
1140
1141 int TranzportControlProtocol::lights_show_tempo() 
1142 {
1143         // someday soon fiddle with the lights based on the tempo 
1144         return     lights_show_normal();
1145 }
1146
1147 int
1148 TranzportControlProtocol::update_state ()
1149 {
1150         /* do the text and light updates */
1151
1152         switch (display_mode) {
1153                 case DisplayBigMeter:
1154                         lights_show_tempo();
1155                         show_meter ();
1156                         break;
1157
1158                 case DisplayNormal:
1159                         lights_show_normal();
1160                         normal_update ();
1161                         break;
1162
1163                 case DisplayConfig:
1164                         break;
1165
1166                 case DisplayRecording:
1167                         lights_show_recording();
1168                         normal_update(); 
1169                         break;
1170
1171                 case DisplayRecordingMeter:
1172                         lights_show_recording();
1173                         show_meter(); 
1174                         break;
1175
1176                 case DisplayBling:
1177                         lights_show_bling();
1178                         normal_update();
1179                         break;
1180
1181                 case DisplayBlingMeter:
1182                         lights_show_bling();
1183                         show_meter();
1184                         break;
1185         }
1186         return 0;
1187
1188 }
1189
1190 #define TRANZPORT_BUTTON_HANDLER(callback, button_arg) if (button_changes & button_arg) { \
1191     if (buttonmask & button_arg) { \
1192       callback##_press (buttonmask&ButtonShift); } else { callback##_release (buttonmask&ButtonShift); } }
1193
1194 int
1195 TranzportControlProtocol::process (uint8_t* buf)
1196 {
1197         // printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
1198
1199         uint32_t this_button_mask;
1200         uint32_t button_changes;
1201
1202         _device_status = buf[1];
1203
1204         this_button_mask = 0;
1205         this_button_mask |= buf[2] << 24;
1206         this_button_mask |= buf[3] << 16;
1207         this_button_mask |= buf[4] << 8;
1208         this_button_mask |= buf[5];
1209         _datawheel = buf[6];
1210
1211         button_changes = (this_button_mask ^ buttonmask);
1212         buttonmask = this_button_mask;
1213
1214         if (_datawheel) {
1215                 datawheel ();
1216         }
1217
1218         // SHIFT + STOP + PLAY for bling mode?
1219         // if (button_changes & ButtonPlay & ButtonStop) {
1220         // bling_mode_toggle();  
1221         // } or something like that
1222
1223         TRANZPORT_BUTTON_HANDLER(button_event_battery,ButtonBattery);
1224         TRANZPORT_BUTTON_HANDLER(button_event_backlight,ButtonBacklight);
1225         TRANZPORT_BUTTON_HANDLER(button_event_trackleft,ButtonTrackLeft);
1226         TRANZPORT_BUTTON_HANDLER(button_event_trackright,ButtonTrackRight);
1227         TRANZPORT_BUTTON_HANDLER(button_event_trackrec,ButtonTrackRec);
1228         TRANZPORT_BUTTON_HANDLER(button_event_trackmute,ButtonTrackMute);
1229         TRANZPORT_BUTTON_HANDLER(button_event_tracksolo,ButtonTrackSolo);
1230         TRANZPORT_BUTTON_HANDLER(button_event_undo,ButtonUndo);
1231         TRANZPORT_BUTTON_HANDLER(button_event_in,ButtonIn);
1232         TRANZPORT_BUTTON_HANDLER(button_event_out,ButtonOut);
1233         TRANZPORT_BUTTON_HANDLER(button_event_punch,ButtonPunch);
1234         TRANZPORT_BUTTON_HANDLER(button_event_loop,ButtonLoop);
1235         TRANZPORT_BUTTON_HANDLER(button_event_prev,ButtonPrev);
1236         TRANZPORT_BUTTON_HANDLER(button_event_add,ButtonAdd);
1237         TRANZPORT_BUTTON_HANDLER(button_event_next,ButtonNext);
1238         TRANZPORT_BUTTON_HANDLER(button_event_rewind,ButtonRewind);
1239         TRANZPORT_BUTTON_HANDLER(button_event_fastforward,ButtonFastForward);
1240         TRANZPORT_BUTTON_HANDLER(button_event_stop,ButtonStop);
1241         TRANZPORT_BUTTON_HANDLER(button_event_play,ButtonPlay);
1242         TRANZPORT_BUTTON_HANDLER(button_event_record,ButtonRecord);
1243         return 0;
1244 }
1245
1246 void
1247 TranzportControlProtocol::show_current_track ()
1248 {
1249         char pad[11];
1250         char *v;
1251         int len;
1252         if (route_table[0] == 0) {
1253                 print (0, 0, "----------");
1254                 last_track_gain = FLT_MAX;
1255         } else {
1256                 strcpy(pad,"          ");
1257                 v =  (char *)route_get_name (0).substr (0, 10).c_str();
1258                 if((len = strlen(v)) > 0) {
1259                         strncpy(pad,(char *)v,len);
1260                 }
1261                 print (0, 0, pad);
1262         }
1263 }
1264
1265 void
1266 TranzportControlProtocol::button_event_battery_press (bool shifted)
1267 {
1268 }
1269
1270 void
1271 TranzportControlProtocol::button_event_battery_release (bool shifted)
1272 {
1273 }
1274
1275 void
1276 TranzportControlProtocol::button_event_backlight_press (bool shifted)
1277 {
1278 #if DEBUG_TRANZPORT
1279         printf("backlight pressed\n");
1280 #endif
1281 }
1282
1283 void
1284 TranzportControlProtocol::button_event_backlight_release (bool shifted)
1285 {
1286 #if DEBUG_TRANZPORT
1287         printf("backlight released\n\n");
1288 #endif
1289         if (shifted) {
1290                 lcd_damage();
1291                 lcd_clear();
1292                 last_where += 1; /* force time redisplay */
1293                 last_track_gain = FLT_MAX;
1294                 normal_update(); //  redraw_screen();  
1295         }
1296 }
1297
1298 void
1299 TranzportControlProtocol::button_event_trackleft_press (bool shifted)
1300 {
1301         prev_track ();
1302 }
1303
1304 void
1305 TranzportControlProtocol::button_event_trackleft_release (bool shifted)
1306 {
1307 }
1308
1309 void
1310 TranzportControlProtocol::button_event_trackright_press (bool shifted)
1311 {
1312         next_track ();
1313 }
1314
1315 void
1316 TranzportControlProtocol::button_event_trackright_release (bool shifted)
1317 {
1318 }
1319
1320 void
1321 TranzportControlProtocol::button_event_trackrec_press (bool shifted)
1322 {
1323         if (shifted) {
1324                 toggle_all_rec_enables ();
1325         } else {
1326                 route_set_rec_enable (0, !route_get_rec_enable (0));
1327         }
1328 }
1329
1330 void
1331 TranzportControlProtocol::button_event_trackrec_release (bool shifted)
1332 {
1333 }
1334
1335 void
1336 TranzportControlProtocol::button_event_trackmute_press (bool shifted)
1337 {
1338         if (shifted) {
1339           // Mute ALL? Something useful when a phone call comes in. Mute master?
1340         } else {
1341           route_set_muted (0, !route_get_muted (0));
1342         }
1343 }
1344
1345 void
1346 TranzportControlProtocol::button_event_trackmute_release (bool shifted)
1347 {
1348 }
1349
1350 void
1351 TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
1352 {
1353 #if DEBUG_TRANZPORT
1354         printf("solo pressed\n");
1355 #endif
1356         if (display_mode == DisplayBigMeter) {
1357                 light_off (LightAnysolo);
1358                 return;
1359         }
1360
1361         if (shifted) {
1362                 session->set_all_solo (!session->soloing());
1363         } else {
1364                 route_set_soloed (0, !route_get_soloed (0));
1365         }
1366 }
1367
1368 void
1369 TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
1370 {
1371 #if DEBUG_TRANZPORT
1372         printf("solo released\n");
1373 #endif
1374 }
1375
1376 void
1377 TranzportControlProtocol::button_event_undo_press (bool shifted)
1378 {
1379         if (shifted) {
1380                 redo (); // someday flash the screen with what was redone
1381         } else {
1382                 undo (); // someday flash the screen with what was undone
1383         }
1384 }
1385
1386 void
1387 TranzportControlProtocol::button_event_undo_release (bool shifted)
1388 {
1389 }
1390
1391 void
1392 TranzportControlProtocol::button_event_in_press (bool shifted)
1393 {
1394         if (shifted) {
1395                 toggle_punch_in ();
1396         } else {
1397                 ControlProtocol::ZoomIn (); /* EMIT SIGNAL */
1398         }
1399 }
1400
1401 void
1402 TranzportControlProtocol::button_event_in_release (bool shifted)
1403 {
1404 }
1405
1406 void
1407 TranzportControlProtocol::button_event_out_press (bool shifted)
1408 {
1409         if (shifted) {
1410                 toggle_punch_out ();
1411         } else {
1412                 ControlProtocol::ZoomOut (); /* EMIT SIGNAL */
1413         }
1414 }
1415
1416 void
1417 TranzportControlProtocol::button_event_out_release (bool shifted)
1418 {
1419 }
1420
1421 void
1422 TranzportControlProtocol::button_event_punch_press (bool shifted)
1423 {
1424 }
1425
1426 void
1427 TranzportControlProtocol::button_event_punch_release (bool shifted)
1428 {
1429 }
1430
1431 void
1432 TranzportControlProtocol::button_event_loop_press (bool shifted)
1433 {
1434         if (shifted) {
1435                 next_wheel_shift_mode ();
1436         } else {
1437                 loop_toggle ();
1438         }
1439 }
1440
1441 void
1442 TranzportControlProtocol::button_event_loop_release (bool shifted)
1443 {
1444 }
1445
1446 void
1447 TranzportControlProtocol::button_event_prev_press (bool shifted)
1448 {
1449         if (shifted) {
1450                 ControlProtocol::ZoomToSession (); /* EMIT SIGNAL */
1451         } else {
1452                 prev_marker ();
1453         }
1454 }
1455
1456 void
1457 TranzportControlProtocol::button_event_prev_release (bool shifted)
1458 {
1459 }
1460
1461 void
1462 TranzportControlProtocol::button_event_add_press (bool shifted)
1463 {
1464         add_marker ();
1465 }
1466
1467 void
1468 TranzportControlProtocol::button_event_add_release (bool shifted)
1469 {
1470 }
1471
1472 void
1473 TranzportControlProtocol::button_event_next_press (bool shifted)
1474 {
1475         if (shifted) {
1476                 next_wheel_mode ();
1477         } else {
1478                 next_marker ();
1479         }
1480 }
1481
1482 void
1483 TranzportControlProtocol::button_event_next_release (bool shifted)
1484 {
1485 }
1486
1487 void
1488 TranzportControlProtocol::button_event_rewind_press (bool shifted)
1489 {
1490         if (shifted) {
1491                 goto_start ();
1492         } else {
1493                 rewind ();
1494         }
1495 }
1496
1497 void
1498 TranzportControlProtocol::button_event_rewind_release (bool shifted)
1499 {
1500 }
1501
1502 void
1503 TranzportControlProtocol::button_event_fastforward_press (bool shifted)
1504 {
1505         if (shifted) {
1506                 goto_end ();
1507         } else {
1508                 ffwd ();
1509         }
1510 }
1511
1512 void
1513 TranzportControlProtocol::button_event_fastforward_release (bool shifted)
1514 {
1515 }
1516
1517 void
1518 TranzportControlProtocol::button_event_stop_press (bool shifted)
1519 {
1520         if (shifted) {
1521                 next_display_mode ();
1522         } else {
1523                 transport_stop ();
1524         }
1525 }
1526
1527 void
1528 TranzportControlProtocol::button_event_stop_release (bool shifted)
1529 {
1530 }
1531
1532 void
1533 TranzportControlProtocol::button_event_play_press (bool shifted)
1534 {
1535         if (shifted) {
1536           set_transport_speed (1.0f);
1537         } else {
1538           transport_play ();
1539         }
1540 }
1541
1542 void
1543 TranzportControlProtocol::button_event_play_release (bool shifted)
1544 {
1545 }
1546
1547 void
1548 TranzportControlProtocol::button_event_record_press (bool shifted)
1549 {
1550         if (shifted) {
1551                 save_state ();
1552         } else {
1553                 rec_enable_toggle ();
1554         }
1555 }
1556
1557 void
1558 TranzportControlProtocol::button_event_record_release (bool shifted)
1559 {
1560 }
1561
1562 void button_event_mute (bool pressed, bool shifted)
1563 {
1564         static int was_pressed = 0;
1565         //  if(pressed) { }
1566 }
1567
1568 void
1569 TranzportControlProtocol::datawheel ()
1570 {
1571         if ((buttonmask & ButtonTrackRight) || (buttonmask & ButtonTrackLeft)) {
1572
1573                 /* track scrolling */
1574
1575                 if (_datawheel < WheelDirectionThreshold) {
1576                         next_track ();
1577                 } else {
1578                         prev_track ();
1579                 }
1580
1581                 timerclear (&last_wheel_motion);
1582
1583         } else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
1584
1585                 if (_datawheel < WheelDirectionThreshold) {
1586                         next_marker ();
1587                 } else {
1588                         prev_marker ();
1589                 }
1590
1591                 timerclear (&last_wheel_motion);
1592
1593         } else if (buttonmask & ButtonShift) {
1594
1595                 /* parameter control */
1596
1597                 if (route_table[0]) {
1598                         switch (wheel_shift_mode) {
1599                                 case WheelShiftGain:
1600                                         if (_datawheel < WheelDirectionThreshold) {
1601                                                 step_gain_up ();
1602                                         } else {
1603                                                 step_gain_down ();
1604                                         }
1605                                         break;
1606                                 case WheelShiftPan:
1607                                         if (_datawheel < WheelDirectionThreshold) {
1608                                                 step_pan_right ();
1609                                         } else {
1610                                                 step_pan_left ();
1611                                         }
1612                                         break;
1613
1614                                 case WheelShiftMarker:
1615                                         break;
1616
1617                                 case WheelShiftMaster:
1618                                         break;
1619
1620                         }
1621                 }
1622
1623                 timerclear (&last_wheel_motion);
1624
1625         } else {
1626
1627                 switch (wheel_mode) {
1628                         case WheelTimeline:
1629                                 scroll ();
1630                                 break;
1631
1632                         case WheelScrub:
1633                                 scrub ();
1634                                 break;
1635
1636                         case WheelShuttle:
1637                                 shuttle ();
1638                                 break;
1639                 }
1640         }
1641 }
1642
1643 void
1644 TranzportControlProtocol::scroll ()
1645 {
1646         float m = 1.0;
1647         if (_datawheel < WheelDirectionThreshold) {
1648                 m = 1.0;
1649         } else {
1650                 m = -1.0;
1651         }
1652         switch(wheel_increment) {
1653                 case WheelIncrScreen: ScrollTimeline (0.2*m); break;
1654                 default: break; // other modes unimplemented as yet
1655         }
1656 }
1657
1658 void
1659 TranzportControlProtocol::scrub ()
1660 {
1661         float speed;
1662         struct timeval now;
1663         struct timeval delta;
1664         int dir;
1665
1666         gettimeofday (&now, 0);
1667
1668         if (_datawheel < WheelDirectionThreshold) {
1669                 dir = 1;
1670         } else {
1671                 dir = -1;
1672         }
1673
1674         if (dir != last_wheel_dir) {
1675                 /* changed direction, start over */
1676                 speed = 0.1f;
1677         } else {
1678                 if (timerisset (&last_wheel_motion)) {
1679
1680                         timersub (&now, &last_wheel_motion, &delta);
1681
1682                         /* 10 clicks per second => speed == 1.0 */
1683
1684                         speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
1685
1686                 } else {
1687
1688                         /* start at half-speed and see where we go from there */
1689
1690                         speed = 0.5f;
1691                 }
1692         }
1693
1694         last_wheel_motion = now;
1695         last_wheel_dir = dir;
1696
1697         set_transport_speed (speed * dir);
1698 }
1699
1700 void
1701 TranzportControlProtocol::config ()
1702 {
1703   // FIXME
1704 }
1705
1706 void
1707 TranzportControlProtocol::shuttle ()
1708 {
1709         if (_datawheel < WheelDirectionThreshold) {
1710                 if (session->transport_speed() < 0) {
1711                         session->request_transport_speed (1.0);
1712                 } else {
1713                         session->request_transport_speed (session->transport_speed() + 0.1);
1714                 }
1715         } else {
1716                 if (session->transport_speed() > 0) {
1717                         session->request_transport_speed (-1.0);
1718                 } else {
1719                         session->request_transport_speed (session->transport_speed() - 0.1);
1720                 }
1721         }
1722 }
1723
1724 void
1725 TranzportControlProtocol::step_gain_up ()
1726 {
1727         if (buttonmask & ButtonStop) {
1728                 gain_fraction += 0.001;
1729         } else {
1730                 gain_fraction += 0.01;
1731         }
1732
1733         if (gain_fraction > 2.0) {
1734                 gain_fraction = 2.0;
1735         }
1736         
1737         route_set_gain (0, slider_position_to_gain (gain_fraction));
1738 }
1739
1740 void
1741 TranzportControlProtocol::step_gain_down ()
1742 {
1743         if (buttonmask & ButtonStop) {
1744                 gain_fraction -= 0.001;
1745         } else {
1746                 gain_fraction -= 0.01;
1747         }
1748
1749         if (gain_fraction < 0.0) {
1750                 gain_fraction = 0.0;
1751         }
1752         
1753         route_set_gain (0, slider_position_to_gain (gain_fraction));
1754 }
1755
1756 void
1757 TranzportControlProtocol::step_pan_right ()
1758 {
1759 }
1760
1761 void
1762 TranzportControlProtocol::step_pan_left ()
1763 {
1764 }
1765
1766 void
1767 TranzportControlProtocol::next_wheel_shift_mode ()
1768 {
1769         switch (wheel_shift_mode) {
1770         case WheelShiftGain:
1771                 wheel_shift_mode = WheelShiftPan;
1772                 break;
1773         case WheelShiftPan:
1774                 wheel_shift_mode = WheelShiftMaster;
1775                 break;
1776         case WheelShiftMaster:
1777                 wheel_shift_mode = WheelShiftGain;
1778                 break;
1779         case WheelShiftMarker: // Not done yet, disabled
1780                 wheel_shift_mode = WheelShiftGain;
1781                 break;
1782         }
1783
1784         show_wheel_mode ();
1785 }
1786
1787 void
1788 TranzportControlProtocol::next_wheel_mode ()
1789 {
1790         switch (wheel_mode) {
1791         case WheelTimeline:
1792                 wheel_mode = WheelScrub;
1793                 break;
1794         case WheelScrub:
1795                 wheel_mode = WheelShuttle;
1796                 break;
1797         case WheelShuttle:
1798                 wheel_mode = WheelTimeline;
1799         }
1800
1801         show_wheel_mode ();
1802 }
1803
1804 void
1805 TranzportControlProtocol::next_track ()
1806 {
1807         ControlProtocol::next_track (current_track_id);
1808         gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1809 }
1810
1811 void
1812 TranzportControlProtocol::prev_track ()
1813 {
1814         ControlProtocol::prev_track (current_track_id);
1815         gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1816 }
1817
1818 void
1819 TranzportControlProtocol::show_wheel_mode ()
1820 {
1821         string text;
1822
1823         switch (wheel_mode) {
1824                 case WheelTimeline:
1825                         text = "Time";
1826                         break;
1827                 case WheelScrub:
1828                         text = "Scrb";
1829                         break;
1830                 case WheelShuttle:
1831                         text = "Shtl";
1832                         break;
1833         }
1834
1835         switch (wheel_shift_mode) {
1836                 case WheelShiftGain:
1837                         text += ":Gain";
1838                         break;
1839
1840                 case WheelShiftPan:
1841                         text += ":Pan ";
1842                         break;
1843
1844                 case WheelShiftMaster:
1845                         text += ":Mstr";
1846                         break;
1847
1848                 case WheelShiftMarker:
1849                         text += ":Mrkr";
1850                         break;
1851         }
1852
1853         print (1, 0, text.c_str());
1854 }
1855
1856 // Was going to keep state around saying to retry or not
1857 // haven't got to it yet, still not sure it's a good idea
1858
1859 void
1860 TranzportControlProtocol::print (int row, int col, const char *text) {
1861         print_noretry(row,col,text);
1862 }
1863
1864 void
1865 TranzportControlProtocol::print_noretry (int row, int col, const char *text)
1866 {
1867         int cell;
1868         uint32_t left = strlen (text);
1869         char tmp[5];
1870         int base_col;
1871         
1872         if (row < 0 || row > 1) {
1873                 return;
1874         }
1875
1876         if (col < 0 || col > 19) {
1877                 return;
1878         }
1879
1880         while (left) {
1881
1882                 if (col >= 0 && col < 4) {
1883                         cell = 0;
1884                         base_col = 0;
1885                 } else if (col >= 4 && col < 8) {
1886                         cell = 1;
1887                         base_col = 4;
1888                 } else if (col >= 8 && col < 12) {
1889                         cell = 2;
1890                         base_col = 8;
1891                 } else if (col >= 12 && col < 16) {
1892                         cell = 3;
1893                         base_col = 12;
1894                 } else if (col >= 16 && col < 20) {
1895                         cell = 4;
1896                         base_col = 16;
1897                 } else {
1898                         return;
1899                 }
1900
1901                 int offset = col % 4;
1902
1903                 /* copy current cell contents into tmp */
1904                 
1905                 memcpy (tmp, &screen_pending[row][base_col], 4);
1906                 
1907                 /* overwrite with new text */
1908                 
1909                 uint32_t tocopy = min ((4U - offset), left);
1910                 
1911                 memcpy (tmp+offset, text, tocopy);
1912                 
1913                 /* copy it back to pending */
1914                 
1915                 memcpy (&screen_pending[row][base_col], tmp, 4);
1916                 
1917                 text += tocopy;
1918                 left -= tocopy;
1919                 col  += tocopy;
1920         }
1921 }       
1922
1923 XMLNode&
1924 TranzportControlProtocol::get_state () 
1925 {
1926         XMLNode* node = new XMLNode (X_("Protocol"));
1927         node->add_property (X_("name"), _name);
1928         return *node;
1929 }
1930
1931 int
1932 TranzportControlProtocol::set_state (const XMLNode& node)
1933 {
1934         return 0;
1935 }
1936
1937 int
1938 TranzportControlProtocol::save (char *name) 
1939 {
1940         // Presently unimplemented
1941         return 0;
1942 }
1943
1944 int
1945 TranzportControlProtocol::load (char *name) 
1946 {
1947         // Presently unimplemented
1948         return 0;
1949 }