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