a) moved metering and meter falloff code into libardour
[ardour.git] / libs / surfaces / tranzport / tranzport_control_protocol.cc
1 #include <iostream>
2 #include <algorithm>
3
4 #include <sys/time.h>
5
6 #include <pbd/pthread_utils.h>
7
8 #include <ardour/route.h>
9 #include <ardour/audio_track.h>
10 #include <ardour/session.h>
11 #include <ardour/location.h>
12 #include <ardour/dB.h>
13
14 #include "tranzport_control_protocol.h"
15
16 using namespace ARDOUR;
17 using namespace std;
18 using namespace sigc;
19
20 #include "i18n.h"
21
22 TranzportControlProtocol::TranzportControlProtocol (Session& s)
23         : ControlProtocol  (s, _("Tranzport"))
24 {
25         timeout = 60000;
26         buttonmask = 0;
27         _datawheel = 0;
28         _device_status = STATUS_OFFLINE;
29         udev = 0;
30         current_route = 0;
31         current_track_id = 0;
32         last_where = max_frames;
33         wheel_mode = WheelTimeline;
34         wheel_shift_mode = WheelShiftGain;
35         timerclear (&last_wheel_motion);
36         last_wheel_dir = 1;
37         display_mode = DisplayNormal;
38         requested_display_mode = display_mode;
39
40         memset (current_screen, 0, sizeof (current_screen));
41
42         for (uint32_t i = 0; i < sizeof(lights)/sizeof(lights[0]); ++i) {
43                 lights[i] = false;
44         }
45
46         session.RecordStateChanged.connect (mem_fun (*this, &TranzportControlProtocol::record_status_changed));
47 }
48
49 TranzportControlProtocol::~TranzportControlProtocol ()
50 {
51         if (udev) {
52                 lcd_clear ();
53                 pthread_cancel_one (thread);
54                 close ();
55         }
56 }
57
58 int
59 TranzportControlProtocol::init ()
60 {
61         if (open ()) {
62                 return -1;
63         }
64
65         lcd_clear ();
66
67         print (0, 0, "Welcome to");
68         print (1, 0, "Ardour");
69
70         show_wheel_mode();
71         next_track ();
72         show_transport_time ();
73
74         /* outbound thread */
75
76         init_thread ();
77
78         /* inbound thread */
79         
80         pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _thread_work, this);
81
82         return 0;
83 }
84
85 bool
86 TranzportControlProtocol::active() const
87 {
88         return true;
89 }
90                 
91 void
92 TranzportControlProtocol::send_route_feedback (list<Route*>& routes)
93 {
94 }
95
96 void
97 TranzportControlProtocol::send_global_feedback ()
98 {
99         if (requested_display_mode != display_mode) {
100                 switch (requested_display_mode) {
101                 case DisplayNormal:
102                         enter_normal_display_mode ();
103                         break;
104                 case DisplayBigMeter:
105                         enter_big_meter_mode ();
106                         break;
107                 }
108         }
109
110         switch (display_mode) {
111         case DisplayBigMeter:
112                 show_meter ();
113                 break;
114
115         case DisplayNormal:
116                 show_transport_time ();
117                 if (session.soloing()) {
118                         light_on (LightAnysolo);
119                 } else {
120                         light_off (LightAnysolo);
121                 }
122                 break;
123         }
124 }
125
126 void
127 TranzportControlProtocol::next_display_mode ()
128 {
129         cerr << "Next display mode\n";
130
131         switch (display_mode) {
132         case DisplayNormal:
133                 requested_display_mode = DisplayBigMeter;
134                 break;
135
136         case DisplayBigMeter:
137                 requested_display_mode = DisplayNormal;
138                 break;
139         }
140 }
141
142 void
143 TranzportControlProtocol::enter_big_meter_mode ()
144 {
145         lcd_clear ();
146         lights_off ();
147         display_mode = DisplayBigMeter;
148 }
149
150 void
151 TranzportControlProtocol::enter_normal_display_mode ()
152 {
153         lcd_clear ();
154         lights_off ();
155         show_current_track ();
156         show_wheel_mode ();
157         show_transport_time ();
158         display_mode = DisplayNormal;
159 }
160
161
162 float
163 log_meter (float db)
164 {
165         float def = 0.0f; /* Meter deflection %age */
166  
167         if (db < -70.0f) {
168                 def = 0.0f;
169         } else if (db < -60.0f) {
170                 def = (db + 70.0f) * 0.25f;
171         } else if (db < -50.0f) {
172                 def = (db + 60.0f) * 0.5f + 2.5f;
173         } else if (db < -40.0f) {
174                 def = (db + 50.0f) * 0.75f + 7.5f;
175         } else if (db < -30.0f) {
176                 def = (db + 40.0f) * 1.5f + 15.0f;
177         } else if (db < -20.0f) {
178                 def = (db + 30.0f) * 2.0f + 30.0f;
179         } else if (db < 6.0f) {
180                 def = (db + 20.0f) * 2.5f + 50.0f;
181         } else {
182                 def = 115.0f;
183         }
184         
185         /* 115 is the deflection %age that would be 
186            when db=6.0. this is an arbitrary
187            endpoint for our scaling.
188         */
189         
190         return def/115.0f;
191 }
192
193 void
194 TranzportControlProtocol::show_meter ()
195 {
196         if (current_route == 0) {
197                 return;
198         }
199
200         float level = current_route->peak_input_power (0);
201         float fraction = log_meter (level);
202         int fill  = (int) floor (fraction * 20);
203         char buf[21];
204         int i;
205
206         for (i = 0; i < fill; ++i) {
207                 buf[i] = 0x70; /* tranzport special code for 4 quadrant LCD block */
208         } 
209         for (; i < 20; ++i) {
210                 buf[i] = ' ';
211         }
212
213         buf[21] = '\0';
214
215         print (0, 0, buf);
216         print (1, 0, buf);
217 }
218
219 void
220 TranzportControlProtocol::show_transport_time ()
221 {
222         jack_nframes_t where = session.transport_frame();
223         
224         if (where != last_where) {
225
226                 char buf[5];
227                 SMPTE_Time smpte;
228
229                 session.smpte_time (where, smpte);
230                 
231                 if (smpte.negative) {
232                         sprintf (buf, "-%02ld:", smpte.hours);
233                 } else {
234                         sprintf (buf, " %02ld:", smpte.hours);
235                 }
236                 print (1, 8, buf);
237
238                 sprintf (buf, "%02ld:", smpte.minutes);
239                 print (1, 12, buf);
240
241                 sprintf (buf, "%02ld:", smpte.seconds);
242                 print (1, 15, buf);
243
244                 sprintf (buf, "%02ld", smpte.frames);
245                 print (1, 18, buf);
246
247                 last_where = where;
248         }
249 }
250
251 void*
252 TranzportControlProtocol::_thread_work (void* arg)
253 {
254         return static_cast<TranzportControlProtocol*>(arg)->thread_work ();
255 }
256
257 void*
258 TranzportControlProtocol::thread_work ()
259 {
260         PBD::ThreadCreated (pthread_self(), X_("tranzport monitor"));
261
262         while (true) {
263                 if (read ()) {
264                         break;
265                 }
266         }
267
268         return 0;
269 }
270
271 int
272 TranzportControlProtocol::open ()
273 {
274         struct usb_bus *bus;
275         struct usb_device *dev;
276
277         usb_init();
278         usb_find_busses();
279         usb_find_devices();
280
281         for (bus = usb_busses; bus; bus = bus->next) {
282
283                 for(dev = bus->devices; dev; dev = dev->next) {
284                         if (dev->descriptor.idVendor != VENDORID)
285                                 continue;
286                         if (dev->descriptor.idProduct != PRODUCTID)
287                                 continue;
288                         return open_core (dev);
289                 }
290         }
291
292         error << _("Tranzport: no device detected") << endmsg;
293         return -1;
294 }
295
296 int
297 TranzportControlProtocol::open_core (struct usb_device* dev)
298 {
299         if (!(udev = usb_open (dev))) {
300                 error << _("Tranzport: cannot open USB transport") << endmsg;
301                 return -1;
302         }
303          
304         if (usb_claim_interface (udev, 0) < 0) {
305                 error << _("Tranzport: cannot claim USB interface") << endmsg;
306                 usb_close (udev);
307                 udev = 0;
308                 return -1;
309         }
310
311         if (usb_set_configuration (udev, 1) < 0) {
312                 error << _("Tranzport: cannot configure USB interface") << endmsg;
313                 usb_close (udev);
314                 udev = 0;
315                 return -1;
316         }
317
318         return 0;
319 }
320
321 int
322 TranzportControlProtocol::close ()
323 {
324         int ret = 0;
325
326         if (udev == 0) {
327                 return 0;
328         }
329
330         if (usb_release_interface (udev, 0) < 0) {
331                 error << _("Tranzport: cannot release interface") << endmsg;
332                 ret = -1;
333         }
334
335         if (usb_close (udev)) {
336                 error << _("Tranzport: cannot close device") << endmsg;
337                 ret = 0;
338         }
339
340         return ret;
341 }
342         
343 int
344 TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
345 {
346         int val;
347
348         {
349                 LockMonitor lm (write_lock, __LINE__, __FILE__);
350                 val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
351         }
352
353         if (val < 0)
354                 return val;
355         if (val != 8)
356                 return -1;
357         return 0;
358
359 }       
360
361 void
362 TranzportControlProtocol::lcd_clear ()
363 {
364         /* special case this for speed and atomicity */
365
366         uint8_t cmd[8];
367         
368         cmd[0] = 0x00;
369         cmd[1] = 0x01;
370         cmd[3] = ' ';
371         cmd[4] = ' ';
372         cmd[5] = ' ';
373         cmd[6] = ' ';
374         cmd[7] = 0x00;
375
376         {
377                 LockMonitor lp (print_lock, __LINE__, __FILE__);
378                 LockMonitor lw (write_lock, __LINE__, __FILE__);
379
380                 for (uint8_t i = 0; i < 10; ++i) {
381                         cmd[2] = i;
382                         usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, 500);
383                 }
384                 
385                 memset (current_screen, ' ', sizeof (current_screen));
386         }
387 }
388
389 void
390 TranzportControlProtocol::lights_off ()
391 {
392         light_off (LightRecord);
393         light_off (LightTrackrec);
394         light_off (LightTrackmute);
395         light_off (LightTracksolo);
396         light_off (LightAnysolo);
397         light_off (LightLoop);
398         light_off (LightPunch);
399 }
400
401 int
402 TranzportControlProtocol::light_on (LightID light)
403 {
404         uint8_t cmd[8];
405
406         if (!lights[light]) {
407
408                 cmd[0] = 0x00;
409                 cmd[1] = 0x00;
410                 cmd[2] = light;
411                 cmd[3] = 0x01;
412                 cmd[4] = 0x00;
413                 cmd[5] = 0x00;
414                 cmd[6] = 0x00;
415                 cmd[7] = 0x00;
416
417                 if (write (cmd, 500) == 0) {
418                         lights[light] = true;
419                         return 0;
420                 } else {
421                         return -1;
422                 }
423
424         } else {
425                 return 0;
426         }
427 }
428
429 int
430 TranzportControlProtocol::light_off (LightID light)
431 {
432         uint8_t cmd[8];
433
434         if (lights[light]) {
435
436                 cmd[0] = 0x00;
437                 cmd[1] = 0x00;
438                 cmd[2] = light;
439                 cmd[3] = 0x00;
440                 cmd[4] = 0x00;
441                 cmd[5] = 0x00;
442                 cmd[6] = 0x00;
443                 cmd[7] = 0x00;
444
445                 if (write (cmd, 500) == 0) {
446                         lights[light] = false;
447                         return 0;
448                 } else {
449                         return -1;
450                 }
451
452         } else {
453                 return 0;
454         }
455 }
456
457 int
458 TranzportControlProtocol::read (uint32_t timeout_override)
459 {
460         uint8_t buf[8];
461         int val;
462
463         memset(buf, 0, 8);
464   again:
465         val = usb_interrupt_read(udev, READ_ENDPOINT, (char*) buf, 8, timeout_override ? timeout_override : timeout);
466         if (val < 0) {
467                 return val;
468         }
469         if (val != 8) {
470                 if (val == 0) {
471                         goto again;
472                 }
473                 return -1;
474         }
475
476         // 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]);
477
478         uint32_t this_button_mask;
479         uint32_t button_changes;
480
481         _device_status = buf[1];
482         this_button_mask = 0;
483         this_button_mask |= buf[2] << 24;
484         this_button_mask |= buf[3] << 16;
485         this_button_mask |= buf[4] << 8;
486         this_button_mask |= buf[5];
487         _datawheel = buf[6];
488
489         button_changes = (this_button_mask ^ buttonmask);
490         buttonmask = this_button_mask;
491
492         if (_datawheel) {
493                 datawheel ();
494         }
495
496         if (button_changes & ButtonBattery) {
497                 if (buttonmask & ButtonBattery) {
498                         button_event_battery_press (buttonmask&ButtonShift);
499                 } else {
500                         button_event_battery_release (buttonmask&ButtonShift);
501                 }
502         }
503         if (button_changes & ButtonBacklight) {
504                 if (buttonmask & ButtonBacklight) {
505                         button_event_backlight_press (buttonmask&ButtonShift);
506                 } else {
507                         button_event_backlight_release (buttonmask&ButtonShift);
508                 }
509         }
510         if (button_changes & ButtonTrackLeft) {
511                 if (buttonmask & ButtonTrackLeft) {
512                         button_event_trackleft_press (buttonmask&ButtonShift);
513                 } else {
514                         button_event_trackleft_release (buttonmask&ButtonShift);
515                 }
516         }
517         if (button_changes & ButtonTrackRight) {
518                 if (buttonmask & ButtonTrackRight) {
519                         button_event_trackright_press (buttonmask&ButtonShift);
520                 } else {
521                         button_event_trackright_release (buttonmask&ButtonShift);
522                 }
523         }
524         if (button_changes & ButtonTrackRec) {
525                 if (buttonmask & ButtonTrackRec) {
526                         button_event_trackrec_press (buttonmask&ButtonShift);
527                 } else {
528                         button_event_trackrec_release (buttonmask&ButtonShift);
529                 }
530         }
531         if (button_changes & ButtonTrackMute) {
532                 if (buttonmask & ButtonTrackMute) {
533                         button_event_trackmute_press (buttonmask&ButtonShift);
534                 } else {
535                         button_event_trackmute_release (buttonmask&ButtonShift);
536                 }
537         }
538         if (button_changes & ButtonTrackSolo) {
539                 if (buttonmask & ButtonTrackSolo) {
540                         button_event_tracksolo_press (buttonmask&ButtonShift);
541                 } else {
542                         button_event_tracksolo_release (buttonmask&ButtonShift);
543                 }
544         }
545         if (button_changes & ButtonUndo) {
546                 if (buttonmask & ButtonUndo) {
547                         button_event_undo_press (buttonmask&ButtonShift);
548                 } else {
549                         button_event_undo_release (buttonmask&ButtonShift);
550                 }
551         }
552         if (button_changes & ButtonIn) {
553                 if (buttonmask & ButtonIn) {
554                         button_event_in_press (buttonmask&ButtonShift);
555                 } else {
556                         button_event_in_release (buttonmask&ButtonShift);
557                 }
558         }
559         if (button_changes & ButtonOut) {
560                 if (buttonmask & ButtonOut) {
561                         button_event_out_press (buttonmask&ButtonShift);
562                 } else {
563                         button_event_out_release (buttonmask&ButtonShift);
564                 }
565         }
566         if (button_changes & ButtonPunch) {
567                 if (buttonmask & ButtonPunch) {
568                         button_event_punch_press (buttonmask&ButtonShift);
569                 } else {
570                         button_event_punch_release (buttonmask&ButtonShift);
571                 }
572         }
573         if (button_changes & ButtonLoop) {
574                 if (buttonmask & ButtonLoop) {
575                         button_event_loop_press (buttonmask&ButtonShift);
576                 } else {
577                         button_event_loop_release (buttonmask&ButtonShift);
578                 }
579         }
580         if (button_changes & ButtonPrev) {
581                 if (buttonmask & ButtonPrev) {
582                         button_event_prev_press (buttonmask&ButtonShift);
583                 } else {
584                         button_event_prev_release (buttonmask&ButtonShift);
585                 }
586         }
587         if (button_changes & ButtonAdd) {
588                 if (buttonmask & ButtonAdd) {
589                         button_event_add_press (buttonmask&ButtonShift);
590                 } else {
591                         button_event_add_release (buttonmask&ButtonShift);
592                 }
593         }
594         if (button_changes & ButtonNext) {
595                 if (buttonmask & ButtonNext) {
596                         button_event_next_press (buttonmask&ButtonShift);
597                 } else {
598                         button_event_next_release (buttonmask&ButtonShift);
599                 }
600         }
601         if (button_changes & ButtonRewind) {
602                 if (buttonmask & ButtonRewind) {
603                         button_event_rewind_press (buttonmask&ButtonShift);
604                 } else {
605                         button_event_rewind_release (buttonmask&ButtonShift);
606                 }
607         }
608         if (button_changes & ButtonFastForward) {
609                 if (buttonmask & ButtonFastForward) {
610                         button_event_fastforward_press (buttonmask&ButtonShift);
611                 } else {
612                         button_event_fastforward_release (buttonmask&ButtonShift);
613                 }
614         }
615         if (button_changes & ButtonStop) {
616                 if (buttonmask & ButtonStop) {
617                         button_event_stop_press (buttonmask&ButtonShift);
618                 } else {
619                         button_event_stop_release (buttonmask&ButtonShift);
620                 }
621         }
622         if (button_changes & ButtonPlay) {
623                 if (buttonmask & ButtonPlay) {
624                         button_event_play_press (buttonmask&ButtonShift);
625                 } else {
626                         button_event_play_release (buttonmask&ButtonShift);
627                 }
628         }
629         if (button_changes & ButtonRecord) {
630                 if (buttonmask & ButtonRecord) {
631                         button_event_record_press (buttonmask&ButtonShift);
632                 } else {
633                         button_event_record_release (buttonmask&ButtonShift);
634                 }
635         }
636                 
637         return 0;
638 }
639
640 void
641 TranzportControlProtocol::show_current_track ()
642 {
643         for (vector<sigc::connection>::iterator i = track_connections.begin(); i != track_connections.end(); ++i) {
644                 (*i).disconnect ();
645         }
646         track_connections.clear ();
647
648         if (current_route == 0) {
649                 print (0, 0, "--------");
650                 return;
651         }
652
653         string name = current_route->name();
654
655         print (0, 0, name.substr (0, 8).c_str());
656
657         track_solo_changed (0);
658         track_mute_changed (0);
659         track_rec_changed (0);
660
661         track_connections.push_back (current_route->solo_changed.connect (mem_fun (*this, &TranzportControlProtocol::track_solo_changed)));
662         track_connections.push_back (current_route->mute_changed.connect (mem_fun (*this, &TranzportControlProtocol::track_mute_changed)));
663         track_connections.push_back (current_route->record_enable_changed.connect (mem_fun (*this, &TranzportControlProtocol::track_rec_changed)));
664         track_connections.push_back (current_route->gain_changed.connect (mem_fun (*this, &TranzportControlProtocol::track_gain_changed)));
665 }
666
667 void
668 TranzportControlProtocol::record_status_changed ()
669 {
670         if (session.get_record_enabled()) {
671                 light_on (LightRecord);
672         } else {
673                 light_off (LightRecord);
674         }
675 }
676
677 void
678 TranzportControlProtocol::track_gain_changed (void* ignored)
679 {
680         char buf[8];
681         snprintf (buf, sizeof (buf), "%.1fdB", coefficient_to_dB (current_route->gain()));
682         print (0, 9, buf);
683 }
684
685 void
686 TranzportControlProtocol::track_solo_changed (void* ignored)
687 {
688         if (current_route->soloed()) {
689                 light_on (LightTracksolo);
690         } else {
691                 light_off (LightTracksolo);
692         }
693 }
694
695 void
696 TranzportControlProtocol::track_mute_changed (void *ignored)
697 {
698         if (current_route->muted()) {
699                 light_on (LightTrackmute);
700         } else {
701                 light_off (LightTrackmute);
702         }
703 }
704
705 void
706 TranzportControlProtocol::track_rec_changed (void *ignored)
707 {
708         if (current_route->record_enabled()) {
709                 light_on (LightTrackrec);
710         } else {
711                 light_off (LightTrackrec);
712         }
713 }
714
715         
716 void
717 TranzportControlProtocol::button_event_battery_press (bool shifted)
718 {
719 }
720
721 void
722 TranzportControlProtocol::button_event_battery_release (bool shifted)
723 {
724 }
725
726 void
727 TranzportControlProtocol::button_event_backlight_press (bool shifted)
728 {
729 }
730
731 void
732 TranzportControlProtocol::button_event_backlight_release (bool shifted)
733 {
734 }
735
736 void
737 TranzportControlProtocol::button_event_trackleft_press (bool shifted)
738 {
739         prev_track ();
740 }
741
742 void
743 TranzportControlProtocol::button_event_trackleft_release (bool shifted)
744 {
745 }
746
747 void
748 TranzportControlProtocol::button_event_trackright_press (bool shifted)
749 {
750         next_track ();
751 }
752
753 void
754 TranzportControlProtocol::button_event_trackright_release (bool shifted)
755 {
756 }
757
758 void
759 TranzportControlProtocol::button_event_trackrec_press (bool shifted)
760 {
761         if (shifted) {
762                 if (session.get_record_enabled()) {
763                         session.record_disenable_all ();
764                 } else {
765                         session.record_enable_all ();
766                 }
767         } else {
768                 if (current_route) {
769                         AudioTrack* at = dynamic_cast<AudioTrack*>(current_route);
770                         at->set_record_enable (!at->record_enabled(), this);
771                 }
772         }
773 }
774
775 void
776 TranzportControlProtocol::button_event_trackrec_release (bool shifted)
777 {
778 }
779
780 void
781 TranzportControlProtocol::button_event_trackmute_press (bool shifted)
782 {
783         if (current_route) {
784                 current_route->set_mute (!current_route->muted(), this);
785         }
786 }
787
788 void
789 TranzportControlProtocol::button_event_trackmute_release (bool shifted)
790 {
791 }
792
793 void
794 TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
795 {
796         if (shifted) {
797                 session.set_all_solo (!session.soloing());
798         } else {
799                 if (current_route) {
800                         current_route->set_solo (!current_route->soloed(), this);
801                 }
802         }
803 }
804
805 void
806 TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
807 {
808 }
809
810 void
811 TranzportControlProtocol::button_event_undo_press (bool shifted)
812 {
813         if (shifted) {
814                 session.redo (1);
815         } else {
816                 session.undo (1);
817         }
818 }
819
820 void
821 TranzportControlProtocol::button_event_undo_release (bool shifted)
822 {
823 }
824
825 void
826 TranzportControlProtocol::button_event_in_press (bool shifted)
827 {
828         if (shifted) {
829                 ControlProtocol::ZoomIn (); /* EMIT SIGNAL */
830         }
831 }
832
833 void
834 TranzportControlProtocol::button_event_in_release (bool shifted)
835 {
836 }
837
838 void
839 TranzportControlProtocol::button_event_out_press (bool shifted)
840 {
841         if (shifted) {
842                 ControlProtocol::ZoomOut (); /* EMIT SIGNAL */
843         }
844 }
845
846 void
847 TranzportControlProtocol::button_event_out_release (bool shifted)
848 {
849 }
850
851 void
852 TranzportControlProtocol::button_event_punch_press (bool shifted)
853 {
854 }
855
856 void
857 TranzportControlProtocol::button_event_punch_release (bool shifted)
858 {
859 }
860
861 void
862 TranzportControlProtocol::button_event_loop_press (bool shifted)
863 {
864         if (shifted) {
865                 next_wheel_shift_mode ();
866         }
867 }
868
869 void
870 TranzportControlProtocol::button_event_loop_release (bool shifted)
871 {
872 }
873
874 void
875 TranzportControlProtocol::button_event_prev_press (bool shifted)
876 {
877         if (shifted) {
878                 ControlProtocol::ZoomToSession (); /* EMIT SIGNAL */
879         } else {
880                 prev_marker ();
881         }
882 }
883
884 void
885 TranzportControlProtocol::button_event_prev_release (bool shifted)
886 {
887 }
888
889 void
890 TranzportControlProtocol::button_event_add_press (bool shifted)
891 {
892         jack_nframes_t when = session.audible_frame();
893         session.locations()->add (new Location (when, when, _("unnamed"), Location::IsMark));
894 }
895
896 void
897 TranzportControlProtocol::button_event_add_release (bool shifted)
898 {
899 }
900
901 void
902 TranzportControlProtocol::button_event_next_press (bool shifted)
903 {
904         if (shifted) {
905                 next_wheel_mode ();
906         } else {
907                 next_marker ();
908         }
909 }
910
911 void
912 TranzportControlProtocol::button_event_next_release (bool shifted)
913 {
914 }
915
916 void
917 TranzportControlProtocol::button_event_rewind_press (bool shifted)
918 {
919         if (shifted) {
920                 session.goto_start ();
921         } else {
922                 session.request_transport_speed (-2.0f);
923         }
924 }
925
926 void
927 TranzportControlProtocol::button_event_rewind_release (bool shifted)
928 {
929 }
930
931 void
932 TranzportControlProtocol::button_event_fastforward_press (bool shifted)
933 {
934         if (shifted) {
935                 session.goto_end();
936         } else {
937                 session.request_transport_speed (2.0f);}
938 }
939
940 void
941 TranzportControlProtocol::button_event_fastforward_release (bool shifted)
942 {
943 }
944
945 void
946 TranzportControlProtocol::button_event_stop_press (bool shifted)
947 {
948         if (shifted) {
949                 next_display_mode ();
950         } else {
951                 session.request_transport_speed (0.0);
952         }
953 }
954
955 void
956 TranzportControlProtocol::button_event_stop_release (bool shifted)
957 {
958 }
959
960 void
961 TranzportControlProtocol::button_event_play_press (bool shifted)
962 {
963         session.request_transport_speed (1.0);
964 }
965
966 void
967 TranzportControlProtocol::button_event_play_release (bool shifted)
968 {
969 }
970
971 void
972 TranzportControlProtocol::button_event_record_press (bool shifted)
973 {
974         if (shifted) {
975                 session.save_state ("");
976         } else {
977                 switch (session.record_status()) {
978                 case Session::Disabled:
979                         if (session.ntracks() == 0) {
980                                 // string txt = _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu.");
981                                 // MessageDialog msg (*editor, txt);
982                                 // msg.run ();
983                                 return;
984                         }
985                         session.maybe_enable_record ();
986                         break;
987                 case Session::Recording:
988                 case Session::Enabled:
989                         session.disable_record (true);
990                 }
991         }
992 }
993
994 void
995 TranzportControlProtocol::button_event_record_release (bool shifted)
996 {
997 }
998
999 void
1000 TranzportControlProtocol::datawheel ()
1001 {
1002         if ((buttonmask & ButtonTrackRight) || (buttonmask & ButtonTrackLeft)) {
1003                 
1004                 /* track scrolling */
1005
1006                 if (_datawheel < WheelDirectionThreshold) {
1007                         next_track ();
1008                 } else {
1009                         prev_track ();
1010                 }
1011
1012                 timerclear (&last_wheel_motion);
1013
1014         } else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
1015                 
1016                 if (_datawheel < WheelDirectionThreshold) {
1017                         next_marker ();
1018                 } else {
1019                         prev_marker ();
1020                 }
1021
1022                 timerclear (&last_wheel_motion);
1023
1024         } else if (buttonmask & ButtonShift) {
1025
1026                 /* parameter control */
1027
1028                 if (current_route) {
1029                         switch (wheel_shift_mode) {
1030                         case WheelShiftGain:
1031                                 if (_datawheel < WheelDirectionThreshold) {
1032                                         step_gain_up ();
1033                                 } else {
1034                                         step_gain_down ();
1035                                 }
1036                                 break;
1037                         case WheelShiftPan:
1038                                 if (_datawheel < WheelDirectionThreshold) {
1039                                         step_pan_right ();
1040                                 } else {
1041                                         step_pan_left ();
1042                                 }
1043                                 break;
1044
1045                         case WheelShiftMaster:
1046                                 break;
1047                         }
1048                 }
1049
1050                 timerclear (&last_wheel_motion);
1051
1052         } else {
1053
1054                 switch (wheel_mode) {
1055                 case WheelTimeline:
1056                         scroll ();
1057                         break;
1058                         
1059                 case WheelScrub:
1060                         scrub ();
1061                         break;
1062
1063                 case WheelShuttle:
1064                         shuttle ();
1065                         break;
1066                 }
1067         }
1068 }
1069
1070 void
1071 TranzportControlProtocol::scroll ()
1072 {
1073         if (_datawheel < WheelDirectionThreshold) {
1074                 ScrollTimeline (0.2);
1075         } else {
1076                 ScrollTimeline (-0.2);
1077         }
1078 }
1079
1080 void
1081 TranzportControlProtocol::scrub ()
1082 {
1083         float speed;
1084         struct timeval now;
1085         struct timeval delta;
1086         int dir;
1087         
1088         gettimeofday (&now, 0);
1089         
1090         if (_datawheel < WheelDirectionThreshold) {
1091                 dir = 1;
1092         } else {
1093                 dir = -1;
1094         }
1095         
1096         if (dir != last_wheel_dir) {
1097                 /* changed direction, start over */
1098                 speed = 1.0f;
1099         } else {
1100                 if (timerisset (&last_wheel_motion)) {
1101                         
1102                         timersub (&now, &last_wheel_motion, &delta);
1103                         
1104                         /* 10 clicks per second => speed == 1.0 */
1105                         
1106                         speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
1107                         
1108                 } else {
1109                         
1110                         /* start at half-speed and see where we go from there */
1111                         
1112                         speed = 0.5f;
1113                 }
1114         }
1115         
1116         last_wheel_motion = now;
1117         last_wheel_dir = dir;
1118         
1119         session.request_transport_speed (speed * dir);
1120 }
1121
1122 void
1123 TranzportControlProtocol::shuttle ()
1124 {
1125         if (_datawheel < WheelDirectionThreshold) {
1126                 if (session.transport_speed() < 0) {
1127                         session.request_transport_speed (1.0);
1128                 } else {
1129                         session.request_transport_speed (session.transport_speed() + 0.1);
1130                 }
1131         } else {
1132                 if (session.transport_speed() > 0) {
1133                         session.request_transport_speed (-1.0);
1134                 } else {
1135                         session.request_transport_speed (session.transport_speed() - 0.1);
1136                 }
1137         }
1138 }
1139
1140 void
1141 TranzportControlProtocol::step_gain_up ()
1142 {
1143         if (buttonmask & ButtonStop) {
1144                 current_route->inc_gain (0.01, this);
1145         } else {
1146                 current_route->inc_gain (0.1, this);
1147         }
1148 }
1149
1150 void
1151 TranzportControlProtocol::step_gain_down ()
1152 {
1153         if (buttonmask & ButtonStop) {
1154                 current_route->inc_gain (-0.01, this);
1155         } else {
1156                 current_route->inc_gain (-0.1, this);
1157         }
1158 }
1159
1160 void
1161 TranzportControlProtocol::step_pan_right ()
1162 {
1163 }
1164
1165 void
1166 TranzportControlProtocol::step_pan_left ()
1167 {
1168 }
1169
1170 void
1171 TranzportControlProtocol::next_wheel_shift_mode ()
1172 {
1173         switch (wheel_shift_mode) {
1174         case WheelShiftGain:
1175                 wheel_shift_mode = WheelShiftPan;
1176                 break;
1177         case WheelShiftPan:
1178                 wheel_shift_mode = WheelShiftMaster;
1179                 break;
1180         case WheelShiftMaster:
1181                 wheel_shift_mode = WheelShiftGain;
1182         }
1183
1184         show_wheel_mode ();
1185 }
1186
1187 void
1188 TranzportControlProtocol::next_wheel_mode ()
1189 {
1190         switch (wheel_mode) {
1191         case WheelTimeline:
1192                 wheel_mode = WheelScrub;
1193                 break;
1194         case WheelScrub:
1195                 wheel_mode = WheelShuttle;
1196                 break;
1197         case WheelShuttle:
1198                 wheel_mode = WheelTimeline;
1199         }
1200
1201         show_wheel_mode ();
1202 }
1203
1204 void
1205 TranzportControlProtocol::next_marker ()
1206 {
1207         Location *location = session.locations()->first_location_after (session.transport_frame());
1208
1209         if (location) {
1210                 session.request_locate (location->start(), session.transport_rolling());
1211         } else {
1212                 session.request_locate (session.current_end_frame());
1213         }
1214 }
1215
1216 void
1217 TranzportControlProtocol::prev_marker ()
1218 {
1219         Location *location = session.locations()->first_location_before (session.transport_frame());
1220         
1221         if (location) {
1222                 session.request_locate (location->start(), session.transport_rolling());
1223         } else {
1224                 session.goto_start ();
1225         }
1226 }
1227
1228 void
1229 TranzportControlProtocol::next_track ()
1230 {
1231         uint32_t limit = session.nroutes();
1232
1233         if (current_track_id == limit) {
1234                 current_track_id = 0;
1235         } else {
1236                 current_track_id++;
1237         }
1238
1239         while (current_track_id < limit) {
1240                 if ((current_route = session.route_by_remote_id (current_track_id)) != 0) {
1241                         break;
1242                 }
1243                 current_track_id++;
1244         }
1245
1246         if (current_track_id == limit) {
1247                 current_track_id = 0;
1248         }
1249
1250         show_current_track ();
1251 }
1252
1253 void
1254 TranzportControlProtocol::prev_track ()
1255 {
1256         if (current_track_id == 0) {
1257                 current_track_id = session.nroutes() - 1;
1258         } else {
1259                 current_track_id--;
1260         }
1261
1262         while (current_track_id >= 0) {
1263                 if ((current_route = session.route_by_remote_id (current_track_id)) != 0) {
1264                         break;
1265                 }
1266                 current_track_id--;
1267         }
1268
1269         if (current_track_id < 0) {
1270                 current_track_id = 0;
1271         }
1272
1273         show_current_track ();
1274 }
1275
1276 void
1277 TranzportControlProtocol::show_wheel_mode ()
1278 {
1279         string text;
1280
1281         switch (wheel_mode) {
1282         case WheelTimeline:
1283                 text = "Time";
1284                 break;
1285         case WheelScrub:
1286                 text = "Scrb";
1287                 break;
1288         case WheelShuttle:
1289                 text = "Shtl";
1290                 break;
1291         }
1292
1293         switch (wheel_shift_mode) {
1294         case WheelShiftGain:
1295                 text += ":Gain";
1296                 break;
1297
1298         case WheelShiftPan:
1299                 text += ":Pan";
1300                 break;
1301
1302         case WheelShiftMaster:
1303                 text += ":Mstr";
1304                 break;
1305         }
1306         
1307         print (1, 0, text.c_str());
1308 }
1309
1310 void
1311 TranzportControlProtocol::print (int row, int col, const char *text)
1312 {
1313         int cell;
1314         uint32_t left = strlen (text);
1315         char tmp[5];
1316         int base_col;
1317         
1318         if (row < 0 || row > 1) {
1319                 return;
1320         }
1321
1322         if (col < 0 || col > 19) {
1323                 return;
1324         }
1325
1326         while (left) {
1327
1328                 if (col >= 0 && col < 4) {
1329                         cell = 0;
1330                         base_col = 0;
1331                 } else if (col >= 4 && col < 8) {
1332                         cell = 1;
1333                         base_col = 4;
1334                 } else if (col >= 8 && col < 12) {
1335                         cell = 2;
1336                         base_col = 8;
1337                 } else if (col >= 12 && col < 16) {
1338                         cell = 3;
1339                         base_col = 12;
1340                 } else if (col >= 16 && col < 20) {
1341                         cell = 4;
1342                         base_col = 16;
1343                 } else {
1344                         return;
1345                 }
1346
1347                 int offset = col % 4;
1348
1349                 {
1350
1351                         LockMonitor lm (print_lock, __LINE__, __FILE__);
1352
1353                         /* copy current cell contents into tmp */
1354                         
1355                         memcpy (tmp, &current_screen[row][base_col], 4);
1356                         
1357                         /* overwrite with new text */
1358                         
1359                         uint32_t tocopy = min ((4U - offset), left);
1360
1361                         memcpy (tmp+offset, text, tocopy);
1362
1363                         uint8_t cmd[8];
1364
1365                         /* compare with current screen */
1366
1367                         if (memcmp (tmp, &current_screen[row][base_col], 4)) {
1368
1369                                 /* different, so update */
1370                                 
1371                                 memcpy (&current_screen[row][base_col], tmp, 4);
1372                                 
1373                                 cmd[0] = 0x00;
1374                                 cmd[1] = 0x01;
1375                                 cmd[2] = cell + (row * 5);
1376                                 cmd[3] = tmp[0];
1377                                 cmd[4] = tmp[1];
1378                                 cmd[5] = tmp[2];
1379                                 cmd[6] = tmp[3];
1380                                 cmd[7] = 0x00;
1381                                 
1382                                 write (cmd, 500);
1383                         }
1384                         
1385                         text += tocopy;
1386                         left -= tocopy;
1387                         col  += tocopy;
1388                 }
1389         }
1390 }       
1391