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