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