fixes for destructive track offsets of various kinds; move from jack_nframes_t -...
[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 #include <iostream>
22 #include <algorithm>
23 #include <cmath>
24
25 #define __STDC_FORMAT_MACROS
26 #include <inttypes.h>
27 #include <float.h>
28 #include <sys/time.h>
29 #include <errno.h>
30
31 #include <pbd/pthread_utils.h>
32
33 #include <ardour/route.h>
34 #include <ardour/audio_track.h>
35 #include <ardour/session.h>
36 #include <ardour/location.h>
37 #include <ardour/dB.h>
38
39 #include "tranzport_control_protocol.h"
40
41 using namespace ARDOUR;
42 using namespace std;
43 using namespace sigc;
44 using namespace PBD;
45
46 #include "i18n.h"
47
48 #include <pbd/abstract_ui.cc>
49
50 BaseUI::RequestType LEDChange = BaseUI::new_request_type ();
51 BaseUI::RequestType Print = BaseUI::new_request_type ();
52 BaseUI::RequestType SetCurrentTrack = BaseUI::new_request_type ();
53
54 static inline double 
55 gain_to_slider_position (ARDOUR::gain_t g)
56 {
57         if (g == 0) return 0;
58         return pow((6.0*log(g)/log(2.0)+192.0)/198.0, 8.0);
59
60 }
61
62 static inline ARDOUR::gain_t 
63 slider_position_to_gain (double pos)
64 {
65         /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
66         if (pos == 0.0) return 0;
67         return pow (2.0,(sqrt(sqrt(sqrt(pos)))*198.0-192.0)/6.0);
68 }
69
70
71 TranzportControlProtocol::TranzportControlProtocol (Session& s)
72         : ControlProtocol  (s, X_("Tranzport"))
73 {
74         /* tranzport controls one track at a time */
75
76         set_route_table_size (1);
77         
78         timeout = 60000;
79         buttonmask = 0;
80         _datawheel = 0;
81         _device_status = STATUS_OFFLINE;
82         udev = 0;
83         current_track_id = 0;
84         last_where = max_frames;
85         wheel_mode = WheelTimeline;
86         wheel_shift_mode = WheelShiftGain;
87         timerclear (&last_wheel_motion);
88         last_wheel_dir = 1;
89         last_track_gain = FLT_MAX;
90         display_mode = DisplayNormal;
91         gain_fraction = 0.0;
92
93         memset (current_screen, 0, sizeof (current_screen));
94         memset (pending_screen, 0, sizeof (pending_screen));
95
96         for (uint32_t i = 0; i < sizeof(lights)/sizeof(lights[0]); ++i) {
97                 lights[i] = false;
98         }
99
100         for (uint32_t i = 0; i < sizeof(pending_lights)/sizeof(pending_lights[0]); ++i) {
101                 pending_lights[i] = false;
102         }
103 }
104
105 TranzportControlProtocol::~TranzportControlProtocol ()
106 {
107         set_active (false);
108 }
109
110 bool
111 TranzportControlProtocol::probe ()
112 {
113         struct usb_bus *bus;
114         struct usb_device *dev;
115
116         usb_init();
117         usb_find_busses();
118         usb_find_devices();
119
120         for (bus = usb_busses; bus; bus = bus->next) {
121
122                 for(dev = bus->devices; dev; dev = dev->next) {
123                         if (dev->descriptor.idVendor == VENDORID && dev->descriptor.idProduct == PRODUCTID) {
124                                 return true; 
125                         }
126                 }
127         }
128
129         return false;
130 }
131
132 int
133 TranzportControlProtocol::set_active (bool yn)
134 {
135         if (yn != _active) {
136
137                 if (yn) {
138
139                         if (open ()) {
140                                 return -1;
141                         }
142                         
143                         if (pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _monitor_work, this) == 0) {
144                                 _active = true;
145                         } else {
146                                 return -1;
147                         }
148
149                 } else {
150                         cerr << "Begin tranzport shutdown\n";
151                         pthread_cancel_one (thread);
152                         cerr << "Thread dead\n";
153                         // lcd_clear ();
154                         // lights_off ();
155                         // cerr << "dev reset\n";
156                         close ();
157                         _active = false;
158                         cerr << "End tranzport shutdown\n";
159                 } 
160         }
161
162         return 0;
163 }
164
165 void
166 TranzportControlProtocol::show_track_gain ()
167 {
168         if (route_table[0]) {
169                 gain_t g = route_get_gain (0);
170                 if (g != last_track_gain) {
171                         char buf[16];
172                         snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
173                         print (0, 9, buf); 
174                         last_track_gain = g;
175                 }
176         } else {
177                 print (0, 9, "        "); 
178         }
179 }
180
181 void
182 TranzportControlProtocol::normal_update ()
183 {
184         show_current_track ();
185         show_transport_time ();
186         show_track_gain ();
187         show_wheel_mode ();
188 }
189
190 void
191 TranzportControlProtocol::next_display_mode ()
192 {
193         switch (display_mode) {
194         case DisplayNormal:
195                 display_mode = DisplayBigMeter;
196                 break;
197
198         case DisplayBigMeter:
199                 display_mode = DisplayNormal;
200                 break;
201         }
202 }
203
204 void
205 TranzportControlProtocol::enter_big_meter_mode ()
206 {
207         lcd_clear ();
208         lights_off ();
209         last_meter_fill = 0;
210         display_mode = DisplayBigMeter;
211 }
212
213 void
214 TranzportControlProtocol::enter_normal_display_mode ()
215 {
216         last_where += 1; /* force time redisplay */
217         last_track_gain = FLT_MAX; /* force gain redisplay */
218
219         lcd_clear ();
220         lights_off ();
221         show_current_track ();
222         show_wheel_mode ();
223         show_wheel_mode ();
224         show_transport_time ();
225         display_mode = DisplayNormal;
226 }
227
228
229 float
230 log_meter (float db)
231 {
232         float def = 0.0f; /* Meter deflection %age */
233  
234         if (db < -70.0f) {
235                 def = 0.0f;
236         } else if (db < -60.0f) {
237                 def = (db + 70.0f) * 0.25f;
238         } else if (db < -50.0f) {
239                 def = (db + 60.0f) * 0.5f + 2.5f;
240         } else if (db < -40.0f) {
241                 def = (db + 50.0f) * 0.75f + 7.5f;
242         } else if (db < -30.0f) {
243                 def = (db + 40.0f) * 1.5f + 15.0f;
244         } else if (db < -20.0f) {
245                 def = (db + 30.0f) * 2.0f + 30.0f;
246         } else if (db < 6.0f) {
247                 def = (db + 20.0f) * 2.5f + 50.0f;
248         } else {
249                 def = 115.0f;
250         }
251         
252         /* 115 is the deflection %age that would be 
253            when db=6.0. this is an arbitrary
254            endpoint for our scaling.
255         */
256         
257         return def/115.0f;
258 }
259
260 void
261 TranzportControlProtocol::show_meter ()
262 {
263         if (route_table[0] == 0) {
264                 return;
265         }
266
267         float level = route_get_peak_input_power (0, 0);
268         float fraction = log_meter (level);
269
270         /* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
271            the screen is 20 chars wide, so we can display 40 different levels. compute the level,
272            then figure out how many "::" to fill. if the answer is odd, make the last one a ":"
273         */
274
275         uint32_t fill  = (uint32_t) floor (fraction * 40);
276         char buf[21];
277         uint32_t i;
278
279         if (fill == last_meter_fill) {
280                 /* nothing to do */
281                 return;
282         }
283
284         last_meter_fill = fill;
285
286         bool add_single_level = (fill % 2 != 0);
287         fill /= 2;
288         
289         if (fraction > 0.98) {
290                 light_on (LightAnysolo);
291         }
292
293         /* add all full steps */
294
295         for (i = 0; i < fill; ++i) {
296                 buf[i] = 0x07; /* tranzport special code for 4 quadrant LCD block */
297         } 
298
299         /* add a possible half-step */
300
301         if (i < 20 && add_single_level) {
302                 buf[i] = 0x03; /* tranzport special code for 2 left quadrant LCD block */
303                 ++i;
304         }
305
306         /* fill rest with space */
307
308         for (; i < 20; ++i) {
309                 buf[i] = ' ';
310         }
311
312         /* print() requires this */
313         
314         buf[21] = '\0';
315
316         print (0, 0, buf);
317         print (1, 0, buf);
318 }
319
320 void
321 TranzportControlProtocol::show_transport_time ()
322 {
323         nframes_t where = session->transport_frame();
324         
325         if (where != last_where) {
326
327                 char buf[5];
328                 SMPTE::Time smpte;
329
330                 session->smpte_time (where, smpte);
331                 
332                 if (smpte.negative) {
333                         sprintf (buf, "-%02" PRIu32 ":", smpte.hours);
334                 } else {
335                         sprintf (buf, " %02" PRIu32 ":", smpte.hours);
336                 }
337                 print (1, 8, buf);
338
339                 sprintf (buf, "%02" PRIu32 ":", smpte.minutes);
340                 print (1, 12, buf);
341
342                 sprintf (buf, "%02" PRIu32 ":", smpte.seconds);
343                 print (1, 15, buf);
344
345                 sprintf (buf, "%02" PRIu32, smpte.frames);
346                 print (1, 18, buf);
347
348                 last_where = where;
349         }
350 }
351
352 void*
353 TranzportControlProtocol::_monitor_work (void* arg)
354 {
355         return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
356 }
357
358 int
359 TranzportControlProtocol::open ()
360 {
361         struct usb_bus *bus;
362         struct usb_device *dev;
363
364         usb_init();
365         usb_find_busses();
366         usb_find_devices();
367
368         for (bus = usb_busses; bus; bus = bus->next) {
369
370                 for(dev = bus->devices; dev; dev = dev->next) {
371                         if (dev->descriptor.idVendor != VENDORID)
372                                 continue;
373                         if (dev->descriptor.idProduct != PRODUCTID)
374                                 continue;
375                         return open_core (dev);
376                 }
377         }
378
379         error << _("Tranzport: no device detected") << endmsg;
380         return -1;
381 }
382
383 int
384 TranzportControlProtocol::open_core (struct usb_device* dev)
385 {
386         if (!(udev = usb_open (dev))) {
387                 error << _("Tranzport: cannot open USB transport") << endmsg;
388                 return -1;
389         }
390          
391         if (usb_claim_interface (udev, 0) < 0) {
392                 error << _("Tranzport: cannot claim USB interface") << endmsg;
393                 usb_close (udev);
394                 udev = 0;
395                 return -1;
396         }
397
398         if (usb_set_configuration (udev, 1) < 0) {
399                 cerr << _("Tranzport: cannot configure USB interface") << endmsg;
400         }
401
402         return 0;
403 }
404
405 int
406 TranzportControlProtocol::close ()
407 {
408         int ret = 0;
409
410         if (udev == 0) {
411                 return 0;
412         }
413
414         if (usb_release_interface (udev, 0) < 0) {
415                 error << _("Tranzport: cannot release interface") << endmsg;
416                 ret = -1;
417         }
418
419         if (usb_close (udev)) {
420                 error << _("Tranzport: cannot close device") << endmsg;
421                 udev = 0;
422                 ret = 0;
423         }
424
425         return ret;
426 }
427         
428 int
429 TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
430 {
431         int val;
432
433         val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
434
435         if (val < 0)
436                 return val;
437         if (val != 8)
438                 return -1;
439         return 0;
440
441 }       
442
443 void
444 TranzportControlProtocol::lcd_clear ()
445 {
446         /* special case this for speed and atomicity */
447
448         uint8_t cmd[8];
449         
450         cmd[0] = 0x00;
451         cmd[1] = 0x01;
452         cmd[3] = ' ';
453         cmd[4] = ' ';
454         cmd[5] = ' ';
455         cmd[6] = ' ';
456         cmd[7] = 0x00;
457
458         for (uint8_t i = 0; i < 10; ++i) {
459                 cmd[2] = i;
460                 usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, 1000);
461         }
462         
463         memset (current_screen, ' ', sizeof (current_screen));
464         memset (pending_screen, ' ', sizeof (pending_screen));
465 }
466
467 void
468 TranzportControlProtocol::lights_off ()
469 {
470         uint8_t cmd[8];
471
472         cmd[0] = 0x00;
473         cmd[1] = 0x00;
474         cmd[3] = 0x00;
475         cmd[4] = 0x00;
476         cmd[5] = 0x00;
477         cmd[6] = 0x00;
478         cmd[7] = 0x00;
479
480         cmd[2] = LightRecord;
481         if (write (cmd, 1000) == 0) {
482                 lights[LightRecord] = false;
483         }
484         cmd[2] = LightTrackrec;
485         if (write (cmd, 1000) == 0) {
486                 lights[LightTrackrec] = false;
487         }
488         cmd[2] = LightTrackmute;
489         if (write (cmd, 1000) == 0) {
490                 lights[LightTrackmute] = false;
491         }
492         cmd[2] = LightTracksolo;
493         if (write (cmd, 1000) == 0) {
494                 lights[LightTracksolo] = false;
495         }
496         cmd[2] = LightAnysolo;
497         if (write (cmd, 1000) == 0) {
498                 lights[LightAnysolo] = false;
499         }
500         cmd[2] = LightLoop;
501         if (write (cmd, 1000) == 0) {
502                 lights[LightLoop] = false;
503         }
504         cmd[2] = LightPunch;
505         if (write (cmd, 1000) == 0) {
506                 lights[LightPunch] = false;
507         }
508 }
509
510 int
511 TranzportControlProtocol::light_on (LightID light)
512 {
513         uint8_t cmd[8];
514
515         if (!lights[light]) {
516
517                 cmd[0] = 0x00;
518                 cmd[1] = 0x00;
519                 cmd[2] = light;
520                 cmd[3] = 0x01;
521                 cmd[4] = 0x00;
522                 cmd[5] = 0x00;
523                 cmd[6] = 0x00;
524                 cmd[7] = 0x00;
525
526                 if (write (cmd, 1000) == 0) {
527                         lights[light] = true;
528                         return 0;
529                 } else {
530                         return -1;
531                 }
532
533         } else {
534                 return 0;
535         }
536 }
537
538 int
539 TranzportControlProtocol::light_off (LightID light)
540 {
541         uint8_t cmd[8];
542
543         if (lights[light]) {
544
545                 cmd[0] = 0x00;
546                 cmd[1] = 0x00;
547                 cmd[2] = light;
548                 cmd[3] = 0x00;
549                 cmd[4] = 0x00;
550                 cmd[5] = 0x00;
551                 cmd[6] = 0x00;
552                 cmd[7] = 0x00;
553
554                 if (write (cmd, 1000) == 0) {
555                         lights[light] = false;
556                         return 0;
557                 } else {
558                         return -1;
559                 }
560
561         } else {
562                 return 0;
563         }
564 }
565
566 void*
567 TranzportControlProtocol::monitor_work ()
568 {
569         struct sched_param rtparam;
570         int err;
571         uint8_t buf[8];
572         int val;
573         bool first_time = true;
574
575         PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
576
577         memset (&rtparam, 0, sizeof (rtparam));
578         rtparam.sched_priority = 3; /* XXX should be relative to audio (JACK) thread */
579         
580         if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
581                 // do we care? not particularly.
582                 PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
583         } 
584
585         pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
586         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
587
588         next_track ();
589
590         while (true) {
591
592                 /* bInterval for this beastie is 10ms */
593
594                 /* anything to read ? */
595
596                 if (_device_status == STATUS_OFFLINE) {
597                         light_off (LightRecord);
598                         first_time = true;
599                 }
600
601                 pthread_testcancel();
602                 val = usb_interrupt_read (udev, READ_ENDPOINT, (char*) buf, 8, 10);
603                 pthread_testcancel();
604
605                 if (val == 8) {
606                         process (buf);
607                 }
608
609                 if (_device_status != STATUS_OFFLINE) {
610                         if (first_time) {
611                                 lcd_clear ();
612                                 lights_off ();
613                                 first_time = false;
614                         }
615                         /* update whatever needs updating */
616                         update_state ();
617                 }
618         }
619
620         return (void*) 0;
621 }
622
623 int
624 TranzportControlProtocol::update_state ()
625 {
626         int row;
627         int col_base;
628         int col;
629         int cell;
630
631         /* do the text updates */
632
633         switch (display_mode) {
634         case DisplayBigMeter:
635                 show_meter ();
636                 break;
637
638         case DisplayNormal:
639                 normal_update ();
640                 break;
641         }
642
643         /* next: flush LCD */
644
645         cell = 0;
646         
647         for (row = 0; row < 2; ++row) {
648
649                 for (col_base = 0, col = 0; col < 20; ) {
650                         
651                         if (pending_screen[row][col] != current_screen[row][col]) {
652
653                                 /* something in this cell is different, so dump the cell
654                                    to the device.
655                                 */
656
657                                 uint8_t cmd[8];
658                                 
659                                 cmd[0] = 0x00;
660                                 cmd[1] = 0x01;
661                                 cmd[2] = cell;
662                                 cmd[3] = pending_screen[row][col_base];
663                                 cmd[4] = pending_screen[row][col_base+1];
664                                 cmd[5] = pending_screen[row][col_base+2];
665                                 cmd[6] = pending_screen[row][col_base+3];
666                                 cmd[7] = 0x00;
667
668                                 if (usb_interrupt_write (udev, WRITE_ENDPOINT, (char *) cmd, 8, 1000) == 8) {
669                                         /* successful write: copy to current */
670                                         memcpy (&current_screen[row][col_base], &pending_screen[row][col_base], 4);
671                                 }
672
673                                 /* skip the rest of the 4 character cell since we wrote+copied it already */
674                                 
675                                 col_base += 4;
676                                 col = col_base;
677                                 cell++;
678
679                         } else {
680
681                                 col++;
682                                 
683                                 if (col && col % 4 == 0) {
684                                         cell++;
685                                         col_base += 4;
686                                 }
687                         }
688                 }
689         }
690
691         /* now update LED's */
692
693         /* per track */
694
695         if (route_table[0]) {
696                 boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
697                 if (at && at->record_enabled()) {
698                         pending_lights[LightTrackrec] = true;
699                 } else {
700                         pending_lights[LightTrackrec] = false;
701                 }
702                 if (route_get_muted (0)) {
703                         pending_lights[LightTrackmute] = true;
704                 } else {
705                         pending_lights[LightTrackmute] = false;
706                 }
707                 if (route_get_soloed (0)) {
708                         pending_lights[LightTracksolo] = true;
709                 } else {
710                         pending_lights[LightTracksolo] = false;
711                 }
712
713         } else {
714                 pending_lights[LightTrackrec] = false;
715                 pending_lights[LightTracksolo] = false;
716                 pending_lights[LightTrackmute] = false;
717         }
718
719         /* global */
720
721         if (Config->get_auto_loop()) {
722                 pending_lights[LightLoop] = true;
723         } else {
724                 pending_lights[LightLoop] = false;
725         }
726
727         if (Config->get_punch_in() || Config->get_punch_out()) {
728                 pending_lights[LightPunch] = true;
729         } else {
730                 pending_lights[LightPunch] = false;
731         }
732
733         if (session->get_record_enabled()) {
734                 pending_lights[LightRecord] = true;
735         } else {
736                 pending_lights[LightRecord] = false;
737         }
738
739         if (session->soloing ()) {
740                 pending_lights[LightAnysolo] = true;
741         } else {
742                 pending_lights[LightAnysolo] = false;
743         }
744
745         /* flush changed light change */
746
747         if (pending_lights[LightRecord] != lights[LightRecord]) {
748                 if (pending_lights[LightRecord]) {
749                         light_on (LightRecord);
750                 } else {
751                         light_off (LightRecord);
752                 }
753         }
754
755         if (pending_lights[LightTracksolo] != lights[LightTracksolo]) {
756                 if (pending_lights[LightTracksolo]) {
757                         light_on (LightTracksolo);
758                 } else {
759                         light_off (LightTracksolo);
760                 }
761         }
762
763         if (pending_lights[LightTrackmute] != lights[LightTrackmute]) {
764                 if (pending_lights[LightTrackmute]) {
765                         light_on (LightTrackmute);
766                 } else {
767                         light_off (LightTrackmute);
768                 }
769         }
770
771         if (pending_lights[LightTracksolo] != lights[LightTracksolo]) {
772                 if (pending_lights[LightTracksolo]) {
773                         light_on (LightTracksolo);
774                 } else {
775                         light_off (LightTracksolo);
776                 }
777         }
778
779         if (pending_lights[LightAnysolo] != lights[LightAnysolo]) {
780                 if (pending_lights[LightAnysolo]) {
781                         light_on (LightAnysolo);
782                 } else {
783                         light_off (LightAnysolo);
784                 }
785         }
786
787         if (pending_lights[LightLoop] != lights[LightLoop]) {
788                 if (pending_lights[LightLoop]) {
789                         light_on (LightLoop);
790                 } else {
791                         light_off (LightLoop);
792                 }
793         }
794
795         if (pending_lights[LightPunch] != lights[LightPunch]) {
796                 if (pending_lights[LightPunch]) {
797                         light_on (LightPunch);
798                 } else {
799                         light_off (LightPunch);
800                 }
801         }
802
803         return 0;
804 }
805
806 int
807 TranzportControlProtocol::process (uint8_t* buf)
808 {
809         // 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]);
810
811         uint32_t this_button_mask;
812         uint32_t button_changes;
813
814         _device_status = buf[1];
815         this_button_mask = 0;
816         this_button_mask |= buf[2] << 24;
817         this_button_mask |= buf[3] << 16;
818         this_button_mask |= buf[4] << 8;
819         this_button_mask |= buf[5];
820         _datawheel = buf[6];
821
822         button_changes = (this_button_mask ^ buttonmask);
823         buttonmask = this_button_mask;
824
825         if (_datawheel) {
826                 datawheel ();
827         }
828
829         if (button_changes & ButtonBattery) {
830                 if (buttonmask & ButtonBattery) {
831                         button_event_battery_press (buttonmask&ButtonShift);
832                 } else {
833                         button_event_battery_release (buttonmask&ButtonShift);
834                 }
835         }
836         if (button_changes & ButtonBacklight) {
837                 if (buttonmask & ButtonBacklight) {
838                         button_event_backlight_press (buttonmask&ButtonShift);
839                 } else {
840                         button_event_backlight_release (buttonmask&ButtonShift);
841                 }
842         }
843         if (button_changes & ButtonTrackLeft) {
844                 if (buttonmask & ButtonTrackLeft) {
845                         button_event_trackleft_press (buttonmask&ButtonShift);
846                 } else {
847                         button_event_trackleft_release (buttonmask&ButtonShift);
848                 }
849         }
850         if (button_changes & ButtonTrackRight) {
851                 if (buttonmask & ButtonTrackRight) {
852                         button_event_trackright_press (buttonmask&ButtonShift);
853                 } else {
854                         button_event_trackright_release (buttonmask&ButtonShift);
855                 }
856         }
857         if (button_changes & ButtonTrackRec) {
858                 if (buttonmask & ButtonTrackRec) {
859                         button_event_trackrec_press (buttonmask&ButtonShift);
860                 } else {
861                         button_event_trackrec_release (buttonmask&ButtonShift);
862                 }
863         }
864         if (button_changes & ButtonTrackMute) {
865                 if (buttonmask & ButtonTrackMute) {
866                         button_event_trackmute_press (buttonmask&ButtonShift);
867                 } else {
868                         button_event_trackmute_release (buttonmask&ButtonShift);
869                 }
870         }
871         if (button_changes & ButtonTrackSolo) {
872                 if (buttonmask & ButtonTrackSolo) {
873                         button_event_tracksolo_press (buttonmask&ButtonShift);
874                 } else {
875                         button_event_tracksolo_release (buttonmask&ButtonShift);
876                 }
877         }
878         if (button_changes & ButtonUndo) {
879                 if (buttonmask & ButtonUndo) {
880                         button_event_undo_press (buttonmask&ButtonShift);
881                 } else {
882                         button_event_undo_release (buttonmask&ButtonShift);
883                 }
884         }
885         if (button_changes & ButtonIn) {
886                 if (buttonmask & ButtonIn) {
887                         button_event_in_press (buttonmask&ButtonShift);
888                 } else {
889                         button_event_in_release (buttonmask&ButtonShift);
890                 }
891         }
892         if (button_changes & ButtonOut) {
893                 if (buttonmask & ButtonOut) {
894                         button_event_out_press (buttonmask&ButtonShift);
895                 } else {
896                         button_event_out_release (buttonmask&ButtonShift);
897                 }
898         }
899         if (button_changes & ButtonPunch) {
900                 if (buttonmask & ButtonPunch) {
901                         button_event_punch_press (buttonmask&ButtonShift);
902                 } else {
903                         button_event_punch_release (buttonmask&ButtonShift);
904                 }
905         }
906         if (button_changes & ButtonLoop) {
907                 if (buttonmask & ButtonLoop) {
908                         button_event_loop_press (buttonmask&ButtonShift);
909                 } else {
910                         button_event_loop_release (buttonmask&ButtonShift);
911                 }
912         }
913         if (button_changes & ButtonPrev) {
914                 if (buttonmask & ButtonPrev) {
915                         button_event_prev_press (buttonmask&ButtonShift);
916                 } else {
917                         button_event_prev_release (buttonmask&ButtonShift);
918                 }
919         }
920         if (button_changes & ButtonAdd) {
921                 if (buttonmask & ButtonAdd) {
922                         button_event_add_press (buttonmask&ButtonShift);
923                 } else {
924                         button_event_add_release (buttonmask&ButtonShift);
925                 }
926         }
927         if (button_changes & ButtonNext) {
928                 if (buttonmask & ButtonNext) {
929                         button_event_next_press (buttonmask&ButtonShift);
930                 } else {
931                         button_event_next_release (buttonmask&ButtonShift);
932                 }
933         }
934         if (button_changes & ButtonRewind) {
935                 if (buttonmask & ButtonRewind) {
936                         button_event_rewind_press (buttonmask&ButtonShift);
937                 } else {
938                         button_event_rewind_release (buttonmask&ButtonShift);
939                 }
940         }
941         if (button_changes & ButtonFastForward) {
942                 if (buttonmask & ButtonFastForward) {
943                         button_event_fastforward_press (buttonmask&ButtonShift);
944                 } else {
945                         button_event_fastforward_release (buttonmask&ButtonShift);
946                 }
947         }
948         if (button_changes & ButtonStop) {
949                 if (buttonmask & ButtonStop) {
950                         button_event_stop_press (buttonmask&ButtonShift);
951                 } else {
952                         button_event_stop_release (buttonmask&ButtonShift);
953                 }
954         }
955         if (button_changes & ButtonPlay) {
956                 if (buttonmask & ButtonPlay) {
957                         button_event_play_press (buttonmask&ButtonShift);
958                 } else {
959                         button_event_play_release (buttonmask&ButtonShift);
960                 }
961         }
962         if (button_changes & ButtonRecord) {
963                 if (buttonmask & ButtonRecord) {
964                         button_event_record_press (buttonmask&ButtonShift);
965                 } else {
966                         button_event_record_release (buttonmask&ButtonShift);
967                 }
968         }
969                 
970         return 0;
971 }
972
973 void
974 TranzportControlProtocol::show_current_track ()
975 {
976         if (route_table[0] == 0) {
977                 print (0, 0, "--------");
978         } else {
979                 print (0, 0, route_get_name (0).substr (0, 8).c_str());
980         }
981 }
982
983 void
984 TranzportControlProtocol::button_event_battery_press (bool shifted)
985 {
986 }
987
988 void
989 TranzportControlProtocol::button_event_battery_release (bool shifted)
990 {
991 }
992
993 void
994 TranzportControlProtocol::button_event_backlight_press (bool shifted)
995 {
996 }
997
998 void
999 TranzportControlProtocol::button_event_backlight_release (bool shifted)
1000 {
1001 }
1002
1003 void
1004 TranzportControlProtocol::button_event_trackleft_press (bool shifted)
1005 {
1006         prev_track ();
1007 }
1008
1009 void
1010 TranzportControlProtocol::button_event_trackleft_release (bool shifted)
1011 {
1012 }
1013
1014 void
1015 TranzportControlProtocol::button_event_trackright_press (bool shifted)
1016 {
1017         next_track ();
1018 }
1019
1020 void
1021 TranzportControlProtocol::button_event_trackright_release (bool shifted)
1022 {
1023 }
1024
1025 void
1026 TranzportControlProtocol::button_event_trackrec_press (bool shifted)
1027 {
1028         if (shifted) {
1029                 toggle_all_rec_enables ();
1030         } else {
1031                 route_set_rec_enable (0, !route_get_rec_enable (0));
1032         }
1033 }
1034
1035 void
1036 TranzportControlProtocol::button_event_trackrec_release (bool shifted)
1037 {
1038 }
1039
1040 void
1041 TranzportControlProtocol::button_event_trackmute_press (bool shifted)
1042 {
1043         route_set_muted (0, !route_get_muted (0));
1044 }
1045
1046 void
1047 TranzportControlProtocol::button_event_trackmute_release (bool shifted)
1048 {
1049 }
1050
1051 void
1052 TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
1053 {
1054         if (display_mode == DisplayBigMeter) {
1055                 light_off (LightAnysolo);
1056                 return;
1057         }
1058
1059         if (shifted) {
1060                 session->set_all_solo (!session->soloing());
1061         } else {
1062                 route_set_soloed (0, !route_get_soloed (0));
1063         }
1064 }
1065
1066 void
1067 TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
1068 {
1069 }
1070
1071 void
1072 TranzportControlProtocol::button_event_undo_press (bool shifted)
1073 {
1074         if (shifted) {
1075                 redo ();
1076         } else {
1077                 undo ();
1078         }
1079 }
1080
1081 void
1082 TranzportControlProtocol::button_event_undo_release (bool shifted)
1083 {
1084 }
1085
1086 void
1087 TranzportControlProtocol::button_event_in_press (bool shifted)
1088 {
1089         if (shifted) {
1090                 toggle_punch_in ();
1091         } else {
1092                 ControlProtocol::ZoomIn (); /* EMIT SIGNAL */
1093         }
1094 }
1095
1096 void
1097 TranzportControlProtocol::button_event_in_release (bool shifted)
1098 {
1099 }
1100
1101 void
1102 TranzportControlProtocol::button_event_out_press (bool shifted)
1103 {
1104         if (shifted) {
1105                 toggle_punch_out ();
1106         } else {
1107                 ControlProtocol::ZoomOut (); /* EMIT SIGNAL */
1108         }
1109 }
1110
1111 void
1112 TranzportControlProtocol::button_event_out_release (bool shifted)
1113 {
1114 }
1115
1116 void
1117 TranzportControlProtocol::button_event_punch_press (bool shifted)
1118 {
1119 }
1120
1121 void
1122 TranzportControlProtocol::button_event_punch_release (bool shifted)
1123 {
1124 }
1125
1126 void
1127 TranzportControlProtocol::button_event_loop_press (bool shifted)
1128 {
1129         if (shifted) {
1130                 next_wheel_shift_mode ();
1131         } else {
1132                 loop_toggle ();
1133         }
1134 }
1135
1136 void
1137 TranzportControlProtocol::button_event_loop_release (bool shifted)
1138 {
1139 }
1140
1141 void
1142 TranzportControlProtocol::button_event_prev_press (bool shifted)
1143 {
1144         if (shifted) {
1145                 ControlProtocol::ZoomToSession (); /* EMIT SIGNAL */
1146         } else {
1147                 prev_marker ();
1148         }
1149 }
1150
1151 void
1152 TranzportControlProtocol::button_event_prev_release (bool shifted)
1153 {
1154 }
1155
1156 void
1157 TranzportControlProtocol::button_event_add_press (bool shifted)
1158 {
1159         add_marker ();
1160 }
1161
1162 void
1163 TranzportControlProtocol::button_event_add_release (bool shifted)
1164 {
1165 }
1166
1167 void
1168 TranzportControlProtocol::button_event_next_press (bool shifted)
1169 {
1170         if (shifted) {
1171                 next_wheel_mode ();
1172         } else {
1173                 next_marker ();
1174         }
1175 }
1176
1177 void
1178 TranzportControlProtocol::button_event_next_release (bool shifted)
1179 {
1180 }
1181
1182 void
1183 TranzportControlProtocol::button_event_rewind_press (bool shifted)
1184 {
1185         if (shifted) {
1186                 goto_start ();
1187         } else {
1188                 rewind ();
1189         }
1190 }
1191
1192 void
1193 TranzportControlProtocol::button_event_rewind_release (bool shifted)
1194 {
1195 }
1196
1197 void
1198 TranzportControlProtocol::button_event_fastforward_press (bool shifted)
1199 {
1200         if (shifted) {
1201                 goto_end ();
1202         } else {
1203                 ffwd ();
1204         }
1205 }
1206
1207 void
1208 TranzportControlProtocol::button_event_fastforward_release (bool shifted)
1209 {
1210 }
1211
1212 void
1213 TranzportControlProtocol::button_event_stop_press (bool shifted)
1214 {
1215         if (shifted) {
1216                 next_display_mode ();
1217         } else {
1218                 transport_stop ();
1219         }
1220 }
1221
1222 void
1223 TranzportControlProtocol::button_event_stop_release (bool shifted)
1224 {
1225 }
1226
1227 void
1228 TranzportControlProtocol::button_event_play_press (bool shifted)
1229 {
1230         transport_play ();
1231 }
1232
1233 void
1234 TranzportControlProtocol::button_event_play_release (bool shifted)
1235 {
1236 }
1237
1238 void
1239 TranzportControlProtocol::button_event_record_press (bool shifted)
1240 {
1241         if (shifted) {
1242                 save_state ();
1243         } else {
1244                 rec_enable_toggle ();
1245         }
1246 }
1247
1248 void
1249 TranzportControlProtocol::button_event_record_release (bool shifted)
1250 {
1251 }
1252
1253 void
1254 TranzportControlProtocol::datawheel ()
1255 {
1256         if ((buttonmask & ButtonTrackRight) || (buttonmask & ButtonTrackLeft)) {
1257                 
1258                 /* track scrolling */
1259
1260                 if (_datawheel < WheelDirectionThreshold) {
1261                         next_track ();
1262                 } else {
1263                         prev_track ();
1264                 }
1265
1266                 timerclear (&last_wheel_motion);
1267
1268         } else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
1269                 
1270                 if (_datawheel < WheelDirectionThreshold) {
1271                         next_marker ();
1272                 } else {
1273                         prev_marker ();
1274                 }
1275
1276                 timerclear (&last_wheel_motion);
1277
1278         } else if (buttonmask & ButtonShift) {
1279
1280                 /* parameter control */
1281
1282                 if (route_table[0]) {
1283                         switch (wheel_shift_mode) {
1284                         case WheelShiftGain:
1285                                 if (_datawheel < WheelDirectionThreshold) {
1286                                         step_gain_up ();
1287                                 } else {
1288                                         step_gain_down ();
1289                                 }
1290                                 break;
1291                         case WheelShiftPan:
1292                                 if (_datawheel < WheelDirectionThreshold) {
1293                                         step_pan_right ();
1294                                 } else {
1295                                         step_pan_left ();
1296                                 }
1297                                 break;
1298
1299                         case WheelShiftMaster:
1300                                 break;
1301                         }
1302                 }
1303
1304                 timerclear (&last_wheel_motion);
1305
1306         } else {
1307
1308                 switch (wheel_mode) {
1309                 case WheelTimeline:
1310                         scroll ();
1311                         break;
1312                         
1313                 case WheelScrub:
1314                         scrub ();
1315                         break;
1316
1317                 case WheelShuttle:
1318                         shuttle ();
1319                         break;
1320                 }
1321         }
1322 }
1323
1324 void
1325 TranzportControlProtocol::scroll ()
1326 {
1327         if (_datawheel < WheelDirectionThreshold) {
1328                 ScrollTimeline (0.2);
1329         } else {
1330                 ScrollTimeline (-0.2);
1331         }
1332 }
1333
1334 void
1335 TranzportControlProtocol::scrub ()
1336 {
1337         float speed;
1338         struct timeval now;
1339         struct timeval delta;
1340         int dir;
1341         
1342         gettimeofday (&now, 0);
1343         
1344         if (_datawheel < WheelDirectionThreshold) {
1345                 dir = 1;
1346         } else {
1347                 dir = -1;
1348         }
1349         
1350         if (dir != last_wheel_dir) {
1351                 /* changed direction, start over */
1352                 speed = 0.1f;
1353         } else {
1354                 if (timerisset (&last_wheel_motion)) {
1355                         
1356                         timersub (&now, &last_wheel_motion, &delta);
1357                         
1358                         /* 10 clicks per second => speed == 1.0 */
1359                         
1360                         speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
1361                         
1362                 } else {
1363                         
1364                         /* start at half-speed and see where we go from there */
1365                         
1366                         speed = 0.5f;
1367                 }
1368         }
1369         
1370         last_wheel_motion = now;
1371         last_wheel_dir = dir;
1372         
1373         set_transport_speed (speed * dir);
1374 }
1375
1376 void
1377 TranzportControlProtocol::shuttle ()
1378 {
1379         if (_datawheel < WheelDirectionThreshold) {
1380                 if (session->transport_speed() < 0) {
1381                         session->request_transport_speed (1.0);
1382                 } else {
1383                         session->request_transport_speed (session->transport_speed() + 0.1);
1384                 }
1385         } else {
1386                 if (session->transport_speed() > 0) {
1387                         session->request_transport_speed (-1.0);
1388                 } else {
1389                         session->request_transport_speed (session->transport_speed() - 0.1);
1390                 }
1391         }
1392 }
1393
1394 void
1395 TranzportControlProtocol::step_gain_up ()
1396 {
1397         if (buttonmask & ButtonStop) {
1398                 gain_fraction += 0.001;
1399         } else {
1400                 gain_fraction += 0.01;
1401         }
1402
1403         if (gain_fraction > 2.0) {
1404                 gain_fraction = 2.0;
1405         }
1406         
1407         route_set_gain (0, slider_position_to_gain (gain_fraction));
1408 }
1409
1410 void
1411 TranzportControlProtocol::step_gain_down ()
1412 {
1413         if (buttonmask & ButtonStop) {
1414                 gain_fraction -= 0.001;
1415         } else {
1416                 gain_fraction -= 0.01;
1417         }
1418
1419         if (gain_fraction < 0.0) {
1420                 gain_fraction = 0.0;
1421         }
1422         
1423         route_set_gain (0, slider_position_to_gain (gain_fraction));
1424 }
1425
1426 void
1427 TranzportControlProtocol::step_pan_right ()
1428 {
1429 }
1430
1431 void
1432 TranzportControlProtocol::step_pan_left ()
1433 {
1434 }
1435
1436 void
1437 TranzportControlProtocol::next_wheel_shift_mode ()
1438 {
1439         switch (wheel_shift_mode) {
1440         case WheelShiftGain:
1441                 wheel_shift_mode = WheelShiftPan;
1442                 break;
1443         case WheelShiftPan:
1444                 wheel_shift_mode = WheelShiftMaster;
1445                 break;
1446         case WheelShiftMaster:
1447                 wheel_shift_mode = WheelShiftGain;
1448         }
1449
1450         show_wheel_mode ();
1451 }
1452
1453 void
1454 TranzportControlProtocol::next_wheel_mode ()
1455 {
1456         switch (wheel_mode) {
1457         case WheelTimeline:
1458                 wheel_mode = WheelScrub;
1459                 break;
1460         case WheelScrub:
1461                 wheel_mode = WheelShuttle;
1462                 break;
1463         case WheelShuttle:
1464                 wheel_mode = WheelTimeline;
1465         }
1466
1467         show_wheel_mode ();
1468 }
1469
1470 void
1471 TranzportControlProtocol::next_track ()
1472 {
1473         ControlProtocol::next_track (current_track_id);
1474         gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1475 }
1476
1477 void
1478 TranzportControlProtocol::prev_track ()
1479 {
1480         ControlProtocol::prev_track (current_track_id);
1481         gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1482 }
1483
1484 void
1485 TranzportControlProtocol::show_wheel_mode ()
1486 {
1487         string text;
1488
1489         switch (wheel_mode) {
1490         case WheelTimeline:
1491                 text = "Time";
1492                 break;
1493         case WheelScrub:
1494                 text = "Scrb";
1495                 break;
1496         case WheelShuttle:
1497                 text = "Shtl";
1498                 break;
1499         }
1500
1501         switch (wheel_shift_mode) {
1502         case WheelShiftGain:
1503                 text += ":Gain";
1504                 break;
1505
1506         case WheelShiftPan:
1507                 text += ":Pan";
1508                 break;
1509
1510         case WheelShiftMaster:
1511                 text += ":Mstr";
1512                 break;
1513         }
1514         
1515         print (1, 0, text.c_str());
1516 }
1517
1518 void
1519 TranzportControlProtocol::print (int row, int col, const char *text)
1520 {
1521         int cell;
1522         uint32_t left = strlen (text);
1523         char tmp[5];
1524         int base_col;
1525         
1526         if (row < 0 || row > 1) {
1527                 return;
1528         }
1529
1530         if (col < 0 || col > 19) {
1531                 return;
1532         }
1533
1534         while (left) {
1535
1536                 if (col >= 0 && col < 4) {
1537                         cell = 0;
1538                         base_col = 0;
1539                 } else if (col >= 4 && col < 8) {
1540                         cell = 1;
1541                         base_col = 4;
1542                 } else if (col >= 8 && col < 12) {
1543                         cell = 2;
1544                         base_col = 8;
1545                 } else if (col >= 12 && col < 16) {
1546                         cell = 3;
1547                         base_col = 12;
1548                 } else if (col >= 16 && col < 20) {
1549                         cell = 4;
1550                         base_col = 16;
1551                 } else {
1552                         return;
1553                 }
1554
1555                 int offset = col % 4;
1556
1557                 /* copy current cell contents into tmp */
1558                 
1559                 memcpy (tmp, &pending_screen[row][base_col], 4);
1560                 
1561                 /* overwrite with new text */
1562                 
1563                 uint32_t tocopy = min ((4U - offset), left);
1564                 
1565                 memcpy (tmp+offset, text, tocopy);
1566                 
1567                 /* copy it back to pending */
1568                 
1569                 memcpy (&pending_screen[row][base_col], tmp, 4);
1570                 
1571                 text += tocopy;
1572                 left -= tocopy;
1573                 col  += tocopy;
1574         }
1575 }       
1576
1577 XMLNode&
1578 TranzportControlProtocol::get_state () 
1579 {
1580         XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
1581         return *node;
1582 }
1583
1584 int
1585 TranzportControlProtocol::set_state (const XMLNode& node)
1586 {
1587         return 0;
1588 }