2 Copyright (C) 2006 Paul Davis
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.
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.
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.
20 /* Design notes: The tranzport is a unique device, basically a
21 20 lcd gui with 22 shift keys and 8 blinking lights.
23 As such it has several unique constraints. The device exerts flow control
24 by having a usb write fail. It is pointless to retry madly at that point,
25 the device is busy, and it's not going to become unbusy very quickly.
27 So writes need to be either "mandatory" or "unreliable", and therein
28 lies the rub, as the kernel can also drop writes, and missing an
29 interrupt in userspace is also generally bad.
31 It will be good one day, to break the gui, keyboard, and blinking light
32 components into separate parts, but for now, this remains monolithic.
34 A more complex surface might have hundreds of lights and several displays.
39 #define DEFAULT_USB_TIMEOUT 10
41 #define MAX_TRANZPORT_INFLIGHT 4
42 #define DEBUG_TRANZPORT 0
43 #define HAVE_TRANZPORT_KERNEL_DRIVER 0
49 #define __STDC_FORMAT_MACROS
55 #include <pbd/pthread_utils.h>
57 #include <ardour/route.h>
58 #include <ardour/audio_track.h>
59 #include <ardour/session.h>
60 #include <ardour/tempo.h>
61 #include <ardour/location.h>
62 #include <ardour/dB.h>
64 #include "tranzport_control_protocol.h"
66 using namespace ARDOUR;
73 #include <pbd/abstract_ui.cc>
75 BaseUI::RequestType LEDChange = BaseUI::new_request_type ();
76 BaseUI::RequestType Print = BaseUI::new_request_type ();
77 BaseUI::RequestType SetCurrentTrack = BaseUI::new_request_type ();
79 /* Base Tranzport cmd strings */
81 static const uint8_t cmd_light_on[] = { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
82 static const uint8_t cmd_light_off[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
83 static const uint8_t cmd_write_screen[] = { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
86 gain_to_slider_position (ARDOUR::gain_t g)
89 return pow((6.0*log(g)/log(2.0)+192.0)/198.0, 8.0);
93 static inline ARDOUR::gain_t
94 slider_position_to_gain (double pos)
96 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
97 if (pos == 0.0) return 0;
98 return pow (2.0,(sqrt(sqrt(sqrt(pos)))*198.0-192.0)/6.0);
102 TranzportControlProtocol::TranzportControlProtocol (Session& s)
103 : ControlProtocol (s, X_("Tranzport"))
105 /* tranzport controls one track at a time */
107 set_route_table_size (1);
108 timeout = 6000; // what is this for?
111 _device_status = STATUS_OFFLINE;
113 current_track_id = 0;
114 last_where = max_frames;
115 wheel_mode = WheelTimeline;
116 wheel_shift_mode = WheelShiftGain;
117 wheel_increment = WheelIncrScreen;
118 bling_mode = BlingOff;
119 timerclear (&last_wheel_motion);
121 last_track_gain = FLT_MAX;
122 display_mode = DisplayNormal;
127 print(0,0,"!!Welcome to Ardour!!");
128 print(1,0,"!Peace through Music!");
131 void TranzportControlProtocol::light_validate (LightID light)
133 lights_invalid[light] = 0;
136 void TranzportControlProtocol::light_invalidate (LightID light)
138 lights_invalid[light] = 1;
141 void TranzportControlProtocol::lights_validate ()
143 memset (lights_invalid, 0, sizeof (lights_invalid));
146 void TranzportControlProtocol::lights_invalidate ()
148 memset (lights_invalid, 1, sizeof (lights_invalid));
151 void TranzportControlProtocol::lights_init()
153 for (uint32_t i = 0; i < sizeof(lights_current)/sizeof(lights_current[0]); i++) {
154 lights_invalid[i] = lights_current[i] =
155 lights_pending[i] = lights_flash[i] = false;
162 TranzportControlProtocol::lights_flush ()
164 if ( _device_status == STATUS_OFFLINE) { return (0); }
166 // Figure out iterators one day soon
167 // for (LightID i = i.start(), i = i.end(); i++) {
168 // if (lights_pending[i] != lights_current[i] || lights_invalid[i]) {
169 // if (light_set(i, lights_pending[i])) {
174 if ((lights_pending[LightRecord] != lights_current[LightRecord]) || lights_invalid[LightRecord]) {
175 if (light_set(LightRecord,lights_pending[LightRecord])) {
179 if ((lights_pending[LightTrackrec] != lights_current[LightTrackrec]) || lights_invalid[LightTrackrec]) {
180 if (light_set(LightTrackrec,lights_pending[LightTrackrec])) {
185 if ((lights_pending[LightTrackmute] != lights_current[LightTrackmute]) || lights_invalid[LightTrackmute]) {
186 if (light_set(LightTrackmute,lights_pending[LightTrackmute])) {
191 if ((lights_pending[LightTracksolo] != lights_current[LightTracksolo]) || lights_invalid[LightTracksolo]) {
192 if (light_set(LightTracksolo,lights_pending[LightTracksolo])) {
196 if ((lights_pending[LightAnysolo] != lights_current[LightAnysolo]) || lights_invalid[LightAnysolo]) {
197 if (light_set(LightAnysolo,lights_pending[LightAnysolo])) {
201 if ((lights_pending[LightLoop] != lights_current[LightLoop]) || lights_invalid[LightLoop]) {
202 if (light_set(LightLoop,lights_pending[LightLoop])) {
206 if ((lights_pending[LightPunch] != lights_current[LightPunch]) || lights_invalid[LightPunch]) {
207 if (light_set(LightPunch,lights_pending[LightPunch])) {
215 // Screen specific commands
218 TranzportControlProtocol::screen_clear ()
220 const char *blank = " ";
225 void TranzportControlProtocol::screen_invalidate ()
227 for(int row = 0; row < 2; row++) {
228 for(int col = 0; col < 20; col++) {
229 screen_invalid[row][col] = true;
230 screen_current[row][col] = 0x7f;
231 screen_pending[row][col] = ' ';
232 // screen_flash[row][col] = ' ';
235 // memset (&screen_invalid, 1, sizeof(screen_invalid));
236 // memset (&screen_current, 0x7F, sizeof (screen_current)); // fill cache with a character we otherwise never use
239 void TranzportControlProtocol::screen_validate ()
243 void TranzportControlProtocol::screen_init ()
249 TranzportControlProtocol::screen_flush ()
251 int cell = 0, row, col_base, col, pending = 0;
252 if ( _device_status == STATUS_OFFLINE) { return (-1); }
254 for (row = 0; row < 2 && pending == 0; row++) {
255 for (col_base = 0, col = 0; col < 20 && pending == 0; ) {
256 if ((screen_pending[row][col] != screen_current[row][col])
257 || screen_invalid[row][col]) {
259 /* something in this cell is different, so dump the cell to the device. */
265 cmd[3] = screen_pending[row][col_base];
266 cmd[4] = screen_pending[row][col_base+1];
267 cmd[5] = screen_pending[row][col_base+2];
268 cmd[6] = screen_pending[row][col_base+3];
271 if(write(cmd) != 0) {
272 /* try to update this cell on the next go-round */
273 #if DEBUG_TRANZPORT > 4
274 printf("usb screen update failed for some reason... why? \ncmd and data were %02x %02x %02x %02x %02x %02x %02x %02x\n",
275 cmd[0],cmd[1],cmd[2], cmd[3], cmd[4], cmd[5],cmd[6],cmd[7]);
278 // Shouldn't need to do this
279 // screen_invalid[row][col_base] = screen_invalid[row][col_base+1] =
280 // screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = true;
283 /* successful write: copy to current cached display */
284 screen_invalid[row][col_base] = screen_invalid[row][col_base+1] =
285 screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = false;
286 memcpy (&screen_current[row][col_base], &screen_pending[row][col_base], 4);
289 /* skip the rest of the 4 character cell since we wrote+copied it already */
299 if (col && col % 4 == 0) {
310 // Tranzport specific
312 void TranzportControlProtocol::invalidate()
314 lcd_damage(); lights_invalidate(); screen_invalidate(); // one of these days lcds can be fine but screens not
317 TranzportControlProtocol::~TranzportControlProtocol ()
324 TranzportControlProtocol::set_active (bool yn)
334 if (pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _monitor_work, this) == 0) {
341 cerr << "Begin tranzport shutdown\n";
345 for(int x = 0; x < 10 && flush(); x++) { usleep(1000); }
346 pthread_cancel_one (thread);
347 cerr << "Tranzport Thread dead\n";
350 cerr << "End tranzport shutdown\n";
358 TranzportControlProtocol::show_track_gain ()
360 if (route_table[0]) {
361 gain_t g = route_get_gain (0);
362 if ((g != last_track_gain) || lcd_isdamaged(0,9,8)) {
364 snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
374 TranzportControlProtocol::normal_update ()
376 show_current_track ();
377 show_transport_time ();
383 TranzportControlProtocol::next_display_mode ()
385 switch (display_mode) {
388 enter_big_meter_mode();
391 case DisplayBigMeter:
392 enter_normal_display_mode();
395 case DisplayRecording:
396 enter_normal_display_mode();
399 case DisplayRecordingMeter:
400 enter_big_meter_mode();
405 case DisplayBlingMeter:
406 enter_normal_display_mode();
411 // FIXME, these 3 aren't done yet
414 TranzportControlProtocol::enter_recording_mode ()
416 lcd_damage(); // excessive
419 display_mode = DisplayRecording;
423 TranzportControlProtocol::enter_bling_mode ()
428 display_mode = DisplayBling;
432 TranzportControlProtocol::enter_config_mode ()
437 display_mode = DisplayConfig;
442 TranzportControlProtocol::enter_big_meter_mode ()
448 display_mode = DisplayBigMeter;
452 TranzportControlProtocol::enter_normal_display_mode ()
457 display_mode = DisplayNormal;
465 float def = 0.0f; /* Meter deflection %age */
467 if (db < -70.0f) return 0.0f;
468 if (db > 6.0f) return 1.0f;
471 def = (db + 70.0f) * 0.25f;
472 } else if (db < -50.0f) {
473 def = (db + 60.0f) * 0.5f + 2.5f;
474 } else if (db < -40.0f) {
475 def = (db + 50.0f) * 0.75f + 7.5f;
476 } else if (db < -30.0f) {
477 def = (db + 40.0f) * 1.5f + 15.0f;
478 } else if (db < -20.0f) {
479 def = (db + 30.0f) * 2.0f + 30.0f;
480 } else if (db < 6.0f) {
481 def = (db + 20.0f) * 2.5f + 50.0f;
484 /* 115 is the deflection %age that would be
485 when db=6.0. this is an arbitrary
486 endpoint for our scaling.
493 TranzportControlProtocol::show_meter ()
495 // you only seem to get a route_table[0] on moving forward - bug elsewhere
496 if (route_table[0] == 0) {
497 // Principle of least surprise
498 print (0, 0, "No audio to meter!!!");
499 print (1, 0, "Select another track");
503 float level = route_get_peak_input_power (0, 0);
504 float fraction = log_meter (level);
506 /* Someday add a peak bar*/
508 /* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
509 the screen is 20 chars wide, so we can display 40 different levels. compute the level,
510 then figure out how many "::" to fill. if the answer is odd, make the last one a ":"
513 uint32_t fill = (uint32_t) floor (fraction * 40);
517 if (fill == last_meter_fill) {
522 last_meter_fill = fill;
524 bool add_single_level = (fill % 2 != 0);
527 if (fraction > 0.98) {
528 light_on (LightAnysolo);
531 /* add all full steps */
533 for (i = 0; i < fill; ++i) {
534 buf[i] = 0x07; /* tranzport special code for 4 quadrant LCD block */
537 /* add a possible half-step */
539 if (i < 20 && add_single_level) {
540 buf[i] = 0x03; /* tranzport special code for 2 left quadrant LCD block */
544 /* fill rest with space */
546 for (; i < 20; ++i) {
550 /* print() requires this */
559 TranzportControlProtocol::show_bbt (nframes_t where)
561 if ((where != last_where) || lcd_isdamaged(1,9,8)) {
564 session->tempo_map().bbt_time (where, bbt);
565 sprintf (buf, "%03" PRIu32 "|%02" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
566 last_bars = bbt.bars;
567 last_beats = bbt.beats;
568 last_ticks = bbt.ticks;
571 if(last_ticks < 1960) { print (1, 9, buf); } // save a write so we can do leds
573 // if displaymode is recordmode show beats but not yet
574 lights_pending[LightRecord] = false;
575 lights_pending[LightAnysolo] = false;
577 case 1: if(last_ticks < 500 || last_ticks > 1960) lights_pending[LightRecord] = true; break;
578 default: if(last_ticks < 250) lights_pending[LightAnysolo] = true;
581 // update lights for tempo one day
582 // if (bbt_upper_info_label) {
583 // TempoMap::Metric m (session->tempo_map().metric_at (when));
584 // sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
585 // bbt_lower_info_label->set_text (buf);
586 // sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
587 // bbt_upper_info_label->set_text (buf);
593 TranzportControlProtocol::show_transport_time ()
595 nframes_t where = session->transport_frame();
600 TranzportControlProtocol::show_smpte (nframes_t where)
602 if ((where != last_where) || lcd_isdamaged(1,9,10)) {
607 session->smpte_time (where, smpte);
609 if (smpte.negative) {
610 sprintf (buf, "-%02" PRIu32 ":", smpte.hours);
612 sprintf (buf, " %02" PRIu32 ":", smpte.hours);
616 sprintf (buf, "%02" PRIu32 ":", smpte.minutes);
619 sprintf (buf, "%02" PRIu32 ":", smpte.seconds);
622 sprintf (buf, "%02" PRIu32, smpte.frames);
623 print_noretry (1, 18, buf);
630 TranzportControlProtocol::_monitor_work (void* arg)
632 return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
635 // I note that these usb specific open, close, probe, read routines are basically
636 // pure boilerplate and could easily be abstracted elsewhere
638 #if !HAVE_TRANZPORT_KERNEL_DRIVER
641 TranzportControlProtocol::probe ()
644 struct usb_device *dev;
650 for (bus = usb_busses; bus; bus = bus->next) {
652 for(dev = bus->devices; dev; dev = dev->next) {
653 if (dev->descriptor.idVendor == VENDORID && dev->descriptor.idProduct == PRODUCTID) {
663 TranzportControlProtocol::open ()
666 struct usb_device *dev;
672 for (bus = usb_busses; bus; bus = bus->next) {
674 for(dev = bus->devices; dev; dev = dev->next) {
675 if (dev->descriptor.idVendor != VENDORID)
677 if (dev->descriptor.idProduct != PRODUCTID)
679 return open_core (dev);
683 error << _("Tranzport: no device detected") << endmsg;
688 TranzportControlProtocol::open_core (struct usb_device* dev)
690 if (!(udev = usb_open (dev))) {
691 error << _("Tranzport: cannot open USB transport") << endmsg;
695 if (usb_claim_interface (udev, 0) < 0) {
696 error << _("Tranzport: cannot claim USB interface") << endmsg;
702 if (usb_set_configuration (udev, 1) < 0) {
703 cerr << _("Tranzport: cannot configure USB interface") << endmsg;
710 TranzportControlProtocol::close ()
718 if (usb_release_interface (udev, 0) < 0) {
719 error << _("Tranzport: cannot release interface") << endmsg;
723 if (usb_close (udev)) {
724 error << _("Tranzport: cannot close device") << endmsg;
732 int TranzportControlProtocol::read(uint8_t *buf, uint32_t timeout_override)
735 // Get smarter about handling usb errors soon. Like disconnect
736 // pthread_testcancel();
737 val = usb_interrupt_read (udev, READ_ENDPOINT, (char *) buf, 8, 10);
738 // pthread_testcancel();
744 TranzportControlProtocol::write_noretry (uint8_t* cmd, uint32_t timeout_override)
747 if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
748 val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
752 printf("usb_interrupt_write failed: %d\n", val);
759 printf("usb_interrupt_write failed: %d\n", val);
770 TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
775 if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
777 while((val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout))!=8 && retry++ < MAX_RETRY) {
778 printf("usb_interrupt_write failed, retrying: %d\n", val);
781 if (retry == MAX_RETRY) {
782 printf("Too many retries on a tranzport write, aborting\n");
786 printf("usb_interrupt_write failed: %d\n", val);
790 printf("usb_interrupt_write failed: %d\n", val);
796 return (write_noretry(cmd,timeout_override));
802 #error Kernel API not defined yet for Tranzport
803 // Something like open(/dev/surface/tranzport/event) for reading and raw for writing)
806 // We have a state "Unknown" - STOP USING SPACES FOR IT - switching to arrow character
807 // We have another state - no_retry. Misleading, as we still retry on the next pass
808 // I think it's pointless to keep no_retry and instead we should throttle writes
809 // We have an "displayed" screen
810 // We always draw into the pending screen, which could be any of several screens
811 // We have an active screen
812 // Print arg - we have
814 // so someday I think we need a screen object.
817 screen_flash.clear();
818 screen_flash.print(0,0,"Undone:"); // Someday pull the undo stack from somewhere
819 screen_flash.print(1,0,"Nextup:");
821 if(flash_messages && lcd.getactive() != screen_flash) lcd.setactive(screen_flash,2000);
823 screen::setactive(screen_name,duration); // duration in ms
829 TranzportControlProtocol::flush ()
832 if(!(pending = lights_flush())) {
833 pending = screen_flush();
838 // doing these functions made me realize that screen_invalid should be lcd_isdamaged FIXME soon
840 bool TranzportControlProtocol::lcd_damage()
846 bool TranzportControlProtocol::lcd_damage (int row, int col, int length)
849 int endcol = col+length-1;
850 if((endcol > 19)) { endcol = 19; }
851 if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
852 for(int c = col; c < endcol; c++) {
853 screen_invalid[row][c] = true;
860 // Gotta switch to bitfields, this is collossally dumb
861 // Still working on the layering, arguably screen_invalid should be lcd_invalid
863 bool TranzportControlProtocol::lcd_isdamaged ()
865 for(int r = 0; r < 2; r++) {
866 for(int c = 0; c < 20; c++) {
867 if(screen_invalid[r][c]) {
868 #if DEBUG_TRANZPORT > 5
869 printf("row: %d,col: %d is damaged, should redraw it\n", r,c);
878 bool TranzportControlProtocol::lcd_isdamaged (int row, int col, int length)
881 int endcol = col+length;
882 if((endcol > 19)) { endcol = 19; }
883 if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
884 for(int c = col; c < endcol; c++) {
885 if(screen_invalid[row][c]) {
886 #if DEBUG_TRANZPORT > 5
887 printf("row: %d,col: %d is damaged, should redraw it\n", row,c);
896 // lcd_clear would be a separate function for a smart display
897 // here it does nothing, but for the sake of completeness it should
898 // probably write the lcd, and while I'm on the topic it should probably
899 // take a row, col, length argument....
902 TranzportControlProtocol::lcd_clear ()
907 // These lcd commands are not universally used yet and may drop out of the api
910 TranzportControlProtocol::lcd_flush ()
916 TranzportControlProtocol::lcd_write(uint8_t* cmd, uint32_t timeout_override)
918 return write(cmd,timeout_override);
922 TranzportControlProtocol::lcd_fill (uint8_t fill_char)
927 TranzportControlProtocol::lcd_print (int row, int col, const char* text)
932 void TranzportControlProtocol::lcd_print_noretry (int row, int col, const char* text)
937 // Lights are buffered
940 TranzportControlProtocol::lights_on ()
942 lights_pending[LightRecord] = lights_pending[LightTrackrec] =
943 lights_pending[LightTrackmute] = lights_pending[LightTracksolo] =
944 lights_pending[LightAnysolo] = lights_pending[LightLoop] =
945 lights_pending[LightPunch] = true;
949 TranzportControlProtocol::lights_off ()
951 lights_pending[LightRecord] = lights_pending[LightTrackrec] =
952 lights_pending[LightTrackmute] = lights_pending[LightTracksolo] =
953 lights_pending[LightAnysolo] = lights_pending[LightLoop] =
954 lights_pending[LightPunch] = false;
958 TranzportControlProtocol::light_on (LightID light)
960 lights_pending[light] = true;
965 TranzportControlProtocol::light_off (LightID light)
967 lights_pending[light] = false;
972 TranzportControlProtocol::light_set (LightID light, bool offon)
975 cmd[0] = 0x00; cmd[1] = 0x00; cmd[2] = light; cmd[3] = offon;
976 cmd[4] = 0x00; cmd[5] = 0x00; cmd[6] = 0x00; cmd[7] = 0x00;
978 if (write (cmd) == 0) {
979 lights_current[light] = offon;
980 lights_invalid[light] = false;
987 int TranzportControlProtocol::rtpriority_set(int priority)
989 struct sched_param rtparam;
991 // preallocate and memlock some stack with memlock?
992 char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
993 memset (&rtparam, 0, sizeof (rtparam));
994 rtparam.sched_priority = priority; /* XXX should be relative to audio (JACK) thread */
995 // Note - try SCHED_RR with a low limit
996 // - we don't care if we can't write everything this ms
997 // and it will help if we lose the device
998 if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
999 PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
1005 // Running with realtime privs is bad when you have problems
1007 int TranzportControlProtocol::rtpriority_unset(int priority)
1009 struct sched_param rtparam;
1011 memset (&rtparam, 0, sizeof (rtparam));
1012 rtparam.sched_priority = priority;
1013 if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
1014 PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
1017 PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
1021 // Slowly breaking this into where I can make usb processing it's own thread.
1024 TranzportControlProtocol::monitor_work ()
1027 int val = 0, pending = 0;
1028 bool first_time = true;
1029 uint8_t offline = 0;
1032 PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
1033 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
1034 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
1042 /* bInterval for this beastie is 10ms */
1044 if (_device_status == STATUS_OFFLINE) {
1046 if(offline++ == 1) {
1047 cerr << "Transport has gone offline\n";
1050 offline = 0; // hate writing this
1059 #if DEBUG_TRANZPORT > 2
1060 if(inflight > 1) printf("Inflight: %d\n", inflight);
1064 if (_device_status != STATUS_OFFLINE) {
1071 pending = 3; // Give some time for the device to recover
1073 /* update whatever needs updating */
1076 /* still struggling with a good means of exerting flow control */
1077 // pending = flush();
1083 pending = --inflight; // we just did a whole bunch of writes so wait
1095 int TranzportControlProtocol::lights_show_recording()
1097 // FIXME, flash recording light when recording and transport is moving
1098 return lights_show_normal();
1101 // gotta do bling next!
1103 int TranzportControlProtocol::lights_show_bling()
1105 switch (bling_mode) {
1106 case BlingOff: break;
1107 case BlingKit: break; // rotate rec/mute/solo/any solo back and forth
1108 case BlingRotating: break; // switch between lights
1109 case BlingPairs: break; // Show pairs of lights
1110 case BlingRows: break; // light each row in sequence
1111 case BlingFlashAll: break; // Flash everything randomly
1116 int TranzportControlProtocol::lights_show_normal()
1120 if (route_table[0]) {
1121 boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
1122 lights_pending[LightTrackrec] = at && at->record_enabled();
1123 lights_pending[LightTrackmute] = route_get_muted(0);
1124 lights_pending[LightTracksolo] = route_get_soloed(0);
1126 lights_pending[LightTrackrec] = false;
1127 lights_pending[LightTracksolo] = false;
1128 lights_pending[LightTrackmute] = false;
1131 /* Global settings */
1133 lights_pending[LightLoop] = session->get_play_loop();
1134 lights_pending[LightPunch] = Config->get_punch_in() || Config->get_punch_out();
1135 lights_pending[LightRecord] = session->get_record_enabled();
1136 lights_pending[LightAnysolo] = session->soloing();
1141 int TranzportControlProtocol::lights_show_tempo()
1143 // someday soon fiddle with the lights based on the tempo
1144 return lights_show_normal();
1148 TranzportControlProtocol::update_state ()
1150 /* do the text and light updates */
1152 switch (display_mode) {
1153 case DisplayBigMeter:
1154 lights_show_tempo();
1159 lights_show_normal();
1166 case DisplayRecording:
1167 lights_show_recording();
1171 case DisplayRecordingMeter:
1172 lights_show_recording();
1177 lights_show_bling();
1181 case DisplayBlingMeter:
1182 lights_show_bling();
1190 #define TRANZPORT_BUTTON_HANDLER(callback, button_arg) if (button_changes & button_arg) { \
1191 if (buttonmask & button_arg) { \
1192 callback##_press (buttonmask&ButtonShift); } else { callback##_release (buttonmask&ButtonShift); } }
1195 TranzportControlProtocol::process (uint8_t* buf)
1197 // printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
1199 uint32_t this_button_mask;
1200 uint32_t button_changes;
1202 _device_status = buf[1];
1204 this_button_mask = 0;
1205 this_button_mask |= buf[2] << 24;
1206 this_button_mask |= buf[3] << 16;
1207 this_button_mask |= buf[4] << 8;
1208 this_button_mask |= buf[5];
1209 _datawheel = buf[6];
1211 button_changes = (this_button_mask ^ buttonmask);
1212 buttonmask = this_button_mask;
1218 // SHIFT + STOP + PLAY for bling mode?
1219 // if (button_changes & ButtonPlay & ButtonStop) {
1220 // bling_mode_toggle();
1221 // } or something like that
1223 TRANZPORT_BUTTON_HANDLER(button_event_battery,ButtonBattery);
1224 TRANZPORT_BUTTON_HANDLER(button_event_backlight,ButtonBacklight);
1225 TRANZPORT_BUTTON_HANDLER(button_event_trackleft,ButtonTrackLeft);
1226 TRANZPORT_BUTTON_HANDLER(button_event_trackright,ButtonTrackRight);
1227 TRANZPORT_BUTTON_HANDLER(button_event_trackrec,ButtonTrackRec);
1228 TRANZPORT_BUTTON_HANDLER(button_event_trackmute,ButtonTrackMute);
1229 TRANZPORT_BUTTON_HANDLER(button_event_tracksolo,ButtonTrackSolo);
1230 TRANZPORT_BUTTON_HANDLER(button_event_undo,ButtonUndo);
1231 TRANZPORT_BUTTON_HANDLER(button_event_in,ButtonIn);
1232 TRANZPORT_BUTTON_HANDLER(button_event_out,ButtonOut);
1233 TRANZPORT_BUTTON_HANDLER(button_event_punch,ButtonPunch);
1234 TRANZPORT_BUTTON_HANDLER(button_event_loop,ButtonLoop);
1235 TRANZPORT_BUTTON_HANDLER(button_event_prev,ButtonPrev);
1236 TRANZPORT_BUTTON_HANDLER(button_event_add,ButtonAdd);
1237 TRANZPORT_BUTTON_HANDLER(button_event_next,ButtonNext);
1238 TRANZPORT_BUTTON_HANDLER(button_event_rewind,ButtonRewind);
1239 TRANZPORT_BUTTON_HANDLER(button_event_fastforward,ButtonFastForward);
1240 TRANZPORT_BUTTON_HANDLER(button_event_stop,ButtonStop);
1241 TRANZPORT_BUTTON_HANDLER(button_event_play,ButtonPlay);
1242 TRANZPORT_BUTTON_HANDLER(button_event_record,ButtonRecord);
1247 TranzportControlProtocol::show_current_track ()
1252 if (route_table[0] == 0) {
1253 print (0, 0, "----------");
1254 last_track_gain = FLT_MAX;
1257 v = (char *)route_get_name (0).substr (0, 10).c_str();
1258 if((len = strlen(v)) > 0) {
1259 strncpy(pad,(char *)v,len);
1266 TranzportControlProtocol::button_event_battery_press (bool shifted)
1271 TranzportControlProtocol::button_event_battery_release (bool shifted)
1276 TranzportControlProtocol::button_event_backlight_press (bool shifted)
1279 printf("backlight pressed\n");
1284 TranzportControlProtocol::button_event_backlight_release (bool shifted)
1287 printf("backlight released\n\n");
1292 last_where += 1; /* force time redisplay */
1293 last_track_gain = FLT_MAX;
1294 normal_update(); // redraw_screen();
1299 TranzportControlProtocol::button_event_trackleft_press (bool shifted)
1305 TranzportControlProtocol::button_event_trackleft_release (bool shifted)
1310 TranzportControlProtocol::button_event_trackright_press (bool shifted)
1316 TranzportControlProtocol::button_event_trackright_release (bool shifted)
1321 TranzportControlProtocol::button_event_trackrec_press (bool shifted)
1324 toggle_all_rec_enables ();
1326 route_set_rec_enable (0, !route_get_rec_enable (0));
1331 TranzportControlProtocol::button_event_trackrec_release (bool shifted)
1336 TranzportControlProtocol::button_event_trackmute_press (bool shifted)
1339 // Mute ALL? Something useful when a phone call comes in. Mute master?
1341 route_set_muted (0, !route_get_muted (0));
1346 TranzportControlProtocol::button_event_trackmute_release (bool shifted)
1351 TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
1354 printf("solo pressed\n");
1356 if (display_mode == DisplayBigMeter) {
1357 light_off (LightAnysolo);
1362 session->set_all_solo (!session->soloing());
1364 route_set_soloed (0, !route_get_soloed (0));
1369 TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
1372 printf("solo released\n");
1377 TranzportControlProtocol::button_event_undo_press (bool shifted)
1380 redo (); // someday flash the screen with what was redone
1382 undo (); // someday flash the screen with what was undone
1387 TranzportControlProtocol::button_event_undo_release (bool shifted)
1392 TranzportControlProtocol::button_event_in_press (bool shifted)
1397 ControlProtocol::ZoomIn (); /* EMIT SIGNAL */
1402 TranzportControlProtocol::button_event_in_release (bool shifted)
1407 TranzportControlProtocol::button_event_out_press (bool shifted)
1410 toggle_punch_out ();
1412 ControlProtocol::ZoomOut (); /* EMIT SIGNAL */
1417 TranzportControlProtocol::button_event_out_release (bool shifted)
1422 TranzportControlProtocol::button_event_punch_press (bool shifted)
1427 TranzportControlProtocol::button_event_punch_release (bool shifted)
1432 TranzportControlProtocol::button_event_loop_press (bool shifted)
1435 next_wheel_shift_mode ();
1442 TranzportControlProtocol::button_event_loop_release (bool shifted)
1447 TranzportControlProtocol::button_event_prev_press (bool shifted)
1450 ControlProtocol::ZoomToSession (); /* EMIT SIGNAL */
1457 TranzportControlProtocol::button_event_prev_release (bool shifted)
1462 TranzportControlProtocol::button_event_add_press (bool shifted)
1468 TranzportControlProtocol::button_event_add_release (bool shifted)
1473 TranzportControlProtocol::button_event_next_press (bool shifted)
1483 TranzportControlProtocol::button_event_next_release (bool shifted)
1488 TranzportControlProtocol::button_event_rewind_press (bool shifted)
1498 TranzportControlProtocol::button_event_rewind_release (bool shifted)
1503 TranzportControlProtocol::button_event_fastforward_press (bool shifted)
1513 TranzportControlProtocol::button_event_fastforward_release (bool shifted)
1518 TranzportControlProtocol::button_event_stop_press (bool shifted)
1521 next_display_mode ();
1528 TranzportControlProtocol::button_event_stop_release (bool shifted)
1533 TranzportControlProtocol::button_event_play_press (bool shifted)
1536 set_transport_speed (1.0f);
1543 TranzportControlProtocol::button_event_play_release (bool shifted)
1548 TranzportControlProtocol::button_event_record_press (bool shifted)
1553 rec_enable_toggle ();
1558 TranzportControlProtocol::button_event_record_release (bool shifted)
1562 void button_event_mute (bool pressed, bool shifted)
1564 static int was_pressed = 0;
1569 TranzportControlProtocol::datawheel ()
1571 if ((buttonmask & ButtonTrackRight) || (buttonmask & ButtonTrackLeft)) {
1573 /* track scrolling */
1575 if (_datawheel < WheelDirectionThreshold) {
1581 timerclear (&last_wheel_motion);
1583 } else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
1585 if (_datawheel < WheelDirectionThreshold) {
1591 timerclear (&last_wheel_motion);
1593 } else if (buttonmask & ButtonShift) {
1595 /* parameter control */
1597 if (route_table[0]) {
1598 switch (wheel_shift_mode) {
1599 case WheelShiftGain:
1600 if (_datawheel < WheelDirectionThreshold) {
1607 if (_datawheel < WheelDirectionThreshold) {
1614 case WheelShiftMarker:
1617 case WheelShiftMaster:
1623 timerclear (&last_wheel_motion);
1627 switch (wheel_mode) {
1644 TranzportControlProtocol::scroll ()
1647 if (_datawheel < WheelDirectionThreshold) {
1652 switch(wheel_increment) {
1653 case WheelIncrScreen: ScrollTimeline (0.2*m); break;
1654 default: break; // other modes unimplemented as yet
1659 TranzportControlProtocol::scrub ()
1663 struct timeval delta;
1666 gettimeofday (&now, 0);
1668 if (_datawheel < WheelDirectionThreshold) {
1674 if (dir != last_wheel_dir) {
1675 /* changed direction, start over */
1678 if (timerisset (&last_wheel_motion)) {
1680 timersub (&now, &last_wheel_motion, &delta);
1682 /* 10 clicks per second => speed == 1.0 */
1684 speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
1688 /* start at half-speed and see where we go from there */
1694 last_wheel_motion = now;
1695 last_wheel_dir = dir;
1697 set_transport_speed (speed * dir);
1701 TranzportControlProtocol::config ()
1707 TranzportControlProtocol::shuttle ()
1709 if (_datawheel < WheelDirectionThreshold) {
1710 if (session->transport_speed() < 0) {
1711 session->request_transport_speed (1.0);
1713 session->request_transport_speed (session->transport_speed() + 0.1);
1716 if (session->transport_speed() > 0) {
1717 session->request_transport_speed (-1.0);
1719 session->request_transport_speed (session->transport_speed() - 0.1);
1725 TranzportControlProtocol::step_gain_up ()
1727 if (buttonmask & ButtonStop) {
1728 gain_fraction += 0.001;
1730 gain_fraction += 0.01;
1733 if (gain_fraction > 2.0) {
1734 gain_fraction = 2.0;
1737 route_set_gain (0, slider_position_to_gain (gain_fraction));
1741 TranzportControlProtocol::step_gain_down ()
1743 if (buttonmask & ButtonStop) {
1744 gain_fraction -= 0.001;
1746 gain_fraction -= 0.01;
1749 if (gain_fraction < 0.0) {
1750 gain_fraction = 0.0;
1753 route_set_gain (0, slider_position_to_gain (gain_fraction));
1757 TranzportControlProtocol::step_pan_right ()
1762 TranzportControlProtocol::step_pan_left ()
1767 TranzportControlProtocol::next_wheel_shift_mode ()
1769 switch (wheel_shift_mode) {
1770 case WheelShiftGain:
1771 wheel_shift_mode = WheelShiftPan;
1774 wheel_shift_mode = WheelShiftMaster;
1776 case WheelShiftMaster:
1777 wheel_shift_mode = WheelShiftGain;
1779 case WheelShiftMarker: // Not done yet, disabled
1780 wheel_shift_mode = WheelShiftGain;
1788 TranzportControlProtocol::next_wheel_mode ()
1790 switch (wheel_mode) {
1792 wheel_mode = WheelScrub;
1795 wheel_mode = WheelShuttle;
1798 wheel_mode = WheelTimeline;
1805 TranzportControlProtocol::next_track ()
1807 ControlProtocol::next_track (current_track_id);
1808 gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1812 TranzportControlProtocol::prev_track ()
1814 ControlProtocol::prev_track (current_track_id);
1815 gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1819 TranzportControlProtocol::show_wheel_mode ()
1823 switch (wheel_mode) {
1835 switch (wheel_shift_mode) {
1836 case WheelShiftGain:
1844 case WheelShiftMaster:
1848 case WheelShiftMarker:
1853 print (1, 0, text.c_str());
1856 // Was going to keep state around saying to retry or not
1857 // haven't got to it yet, still not sure it's a good idea
1860 TranzportControlProtocol::print (int row, int col, const char *text) {
1861 print_noretry(row,col,text);
1865 TranzportControlProtocol::print_noretry (int row, int col, const char *text)
1868 uint32_t left = strlen (text);
1872 if (row < 0 || row > 1) {
1876 if (col < 0 || col > 19) {
1882 if (col >= 0 && col < 4) {
1885 } else if (col >= 4 && col < 8) {
1888 } else if (col >= 8 && col < 12) {
1891 } else if (col >= 12 && col < 16) {
1894 } else if (col >= 16 && col < 20) {
1901 int offset = col % 4;
1903 /* copy current cell contents into tmp */
1905 memcpy (tmp, &screen_pending[row][base_col], 4);
1907 /* overwrite with new text */
1909 uint32_t tocopy = min ((4U - offset), left);
1911 memcpy (tmp+offset, text, tocopy);
1913 /* copy it back to pending */
1915 memcpy (&screen_pending[row][base_col], tmp, 4);
1924 TranzportControlProtocol::get_state ()
1926 XMLNode* node = new XMLNode (X_("Protocol"));
1927 node->add_property (X_("name"), _name);
1932 TranzportControlProtocol::set_state (const XMLNode& node)
1938 TranzportControlProtocol::save (char *name)
1940 // Presently unimplemented
1945 TranzportControlProtocol::load (char *name)
1947 // Presently unimplemented