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/tempo.h"
60 #include "ardour/location.h"
61 #include "ardour/dB.h"
63 #include "tranzport_control_protocol.h"
65 using namespace ARDOUR;
72 #include "pbd/abstract_ui.cc"
74 BaseUI::RequestType LEDChange = BaseUI::new_request_type ();
75 BaseUI::RequestType Print = BaseUI::new_request_type ();
76 BaseUI::RequestType SetCurrentTrack = BaseUI::new_request_type ();
78 /* Base Tranzport cmd strings */
80 static const uint8_t cmd_light_on[] = { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
81 static const uint8_t cmd_light_off[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
82 static const uint8_t cmd_write_screen[] = { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
85 gain_to_slider_position (ARDOUR::gain_t g)
88 return pow((6.0*log(g)/log(2.0)+192.0)/198.0, 8.0);
92 static inline ARDOUR::gain_t
93 slider_position_to_gain (double pos)
95 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
96 if (pos == 0.0) return 0;
97 return pow (2.0,(sqrt(sqrt(sqrt(pos)))*198.0-192.0)/6.0);
101 TranzportControlProtocol::TranzportControlProtocol (Session& s)
102 : ControlProtocol (s, X_("Tranzport"))
104 /* tranzport controls one track at a time */
106 set_route_table_size (1);
107 timeout = 6000; // what is this for?
110 _device_status = STATUS_OFFLINE;
112 current_track_id = 0;
113 last_where = max_frames;
114 wheel_mode = WheelTimeline;
115 wheel_shift_mode = WheelShiftGain;
116 wheel_increment = WheelIncrScreen;
117 bling_mode = BlingOff;
118 timerclear (&last_wheel_motion);
120 last_track_gain = FLT_MAX;
121 display_mode = DisplayNormal;
126 print(0,0,"!!Welcome to Ardour!!");
127 print(1,0,"!Peace through Music!");
130 void TranzportControlProtocol::light_validate (LightID light)
132 lights_invalid[light] = 0;
135 void TranzportControlProtocol::light_invalidate (LightID light)
137 lights_invalid[light] = 1;
140 void TranzportControlProtocol::lights_validate ()
142 memset (lights_invalid, 0, sizeof (lights_invalid));
145 void TranzportControlProtocol::lights_invalidate ()
147 memset (lights_invalid, 1, sizeof (lights_invalid));
150 void TranzportControlProtocol::lights_init()
152 for (uint32_t i = 0; i < sizeof(lights_current)/sizeof(lights_current[0]); i++) {
153 lights_invalid[i] = lights_current[i] =
154 lights_pending[i] = lights_flash[i] = false;
161 TranzportControlProtocol::lights_flush ()
163 if ( _device_status == STATUS_OFFLINE) { return (0); }
165 // Figure out iterators one day soon
166 // for (LightID i = i.start(), i = i.end(); i++) {
167 // if (lights_pending[i] != lights_current[i] || lights_invalid[i]) {
168 // if (light_set(i, lights_pending[i])) {
173 if ((lights_pending[LightRecord] != lights_current[LightRecord]) || lights_invalid[LightRecord]) {
174 if (light_set(LightRecord,lights_pending[LightRecord])) {
178 if ((lights_pending[LightTrackrec] != lights_current[LightTrackrec]) || lights_invalid[LightTrackrec]) {
179 if (light_set(LightTrackrec,lights_pending[LightTrackrec])) {
184 if ((lights_pending[LightTrackmute] != lights_current[LightTrackmute]) || lights_invalid[LightTrackmute]) {
185 if (light_set(LightTrackmute,lights_pending[LightTrackmute])) {
190 if ((lights_pending[LightTracksolo] != lights_current[LightTracksolo]) || lights_invalid[LightTracksolo]) {
191 if (light_set(LightTracksolo,lights_pending[LightTracksolo])) {
195 if ((lights_pending[LightAnysolo] != lights_current[LightAnysolo]) || lights_invalid[LightAnysolo]) {
196 if (light_set(LightAnysolo,lights_pending[LightAnysolo])) {
200 if ((lights_pending[LightLoop] != lights_current[LightLoop]) || lights_invalid[LightLoop]) {
201 if (light_set(LightLoop,lights_pending[LightLoop])) {
205 if ((lights_pending[LightPunch] != lights_current[LightPunch]) || lights_invalid[LightPunch]) {
206 if (light_set(LightPunch,lights_pending[LightPunch])) {
214 // Screen specific commands
217 TranzportControlProtocol::screen_clear ()
219 const char *blank = " ";
224 void TranzportControlProtocol::screen_invalidate ()
226 for(int row = 0; row < 2; row++) {
227 for(int col = 0; col < 20; col++) {
228 screen_invalid[row][col] = true;
229 screen_current[row][col] = 0x7f;
230 screen_pending[row][col] = ' ';
231 // screen_flash[row][col] = ' ';
234 // memset (&screen_invalid, 1, sizeof(screen_invalid));
235 // memset (&screen_current, 0x7F, sizeof (screen_current)); // fill cache with a character we otherwise never use
238 void TranzportControlProtocol::screen_validate ()
242 void TranzportControlProtocol::screen_init ()
248 TranzportControlProtocol::screen_flush ()
250 int cell = 0, row, col_base, col, pending = 0;
251 if ( _device_status == STATUS_OFFLINE) { return (-1); }
253 for (row = 0; row < 2 && pending == 0; row++) {
254 for (col_base = 0, col = 0; col < 20 && pending == 0; ) {
255 if ((screen_pending[row][col] != screen_current[row][col])
256 || screen_invalid[row][col]) {
258 /* something in this cell is different, so dump the cell to the device. */
264 cmd[3] = screen_pending[row][col_base];
265 cmd[4] = screen_pending[row][col_base+1];
266 cmd[5] = screen_pending[row][col_base+2];
267 cmd[6] = screen_pending[row][col_base+3];
270 if(write(cmd) != 0) {
271 /* try to update this cell on the next go-round */
272 #if DEBUG_TRANZPORT > 4
273 printf("usb screen update failed for some reason... why? \ncmd and data were %02x %02x %02x %02x %02x %02x %02x %02x\n",
274 cmd[0],cmd[1],cmd[2], cmd[3], cmd[4], cmd[5],cmd[6],cmd[7]);
277 // Shouldn't need to do this
278 // screen_invalid[row][col_base] = screen_invalid[row][col_base+1] =
279 // screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = true;
282 /* successful write: copy to current cached display */
283 screen_invalid[row][col_base] = screen_invalid[row][col_base+1] =
284 screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = false;
285 memcpy (&screen_current[row][col_base], &screen_pending[row][col_base], 4);
288 /* skip the rest of the 4 character cell since we wrote+copied it already */
298 if (col && col % 4 == 0) {
309 // Tranzport specific
311 void TranzportControlProtocol::invalidate()
313 lcd_damage(); lights_invalidate(); screen_invalidate(); // one of these days lcds can be fine but screens not
316 TranzportControlProtocol::~TranzportControlProtocol ()
323 TranzportControlProtocol::set_active (bool yn)
333 if (pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _monitor_work, this) == 0) {
340 cerr << "Begin tranzport shutdown\n";
344 for(int x = 0; x < 10 && flush(); x++) { usleep(1000); }
345 pthread_cancel_one (thread);
346 cerr << "Tranzport Thread dead\n";
349 cerr << "End tranzport shutdown\n";
357 TranzportControlProtocol::show_track_gain ()
359 if (route_table[0]) {
360 gain_t g = route_get_gain (0);
361 if ((g != last_track_gain) || lcd_isdamaged(0,9,8)) {
363 snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
373 TranzportControlProtocol::normal_update ()
375 show_current_track ();
376 show_transport_time ();
382 TranzportControlProtocol::next_display_mode ()
384 switch (display_mode) {
387 enter_big_meter_mode();
390 case DisplayBigMeter:
391 enter_normal_display_mode();
394 case DisplayRecording:
395 enter_normal_display_mode();
398 case DisplayRecordingMeter:
399 enter_big_meter_mode();
404 case DisplayBlingMeter:
405 enter_normal_display_mode();
410 // FIXME, these 3 aren't done yet
413 TranzportControlProtocol::enter_recording_mode ()
415 lcd_damage(); // excessive
418 display_mode = DisplayRecording;
422 TranzportControlProtocol::enter_bling_mode ()
427 display_mode = DisplayBling;
431 TranzportControlProtocol::enter_config_mode ()
436 display_mode = DisplayConfig;
441 TranzportControlProtocol::enter_big_meter_mode ()
447 display_mode = DisplayBigMeter;
451 TranzportControlProtocol::enter_normal_display_mode ()
456 display_mode = DisplayNormal;
464 float def = 0.0f; /* Meter deflection %age */
466 if (db < -70.0f) return 0.0f;
467 if (db > 6.0f) return 1.0f;
470 def = (db + 70.0f) * 0.25f;
471 } else if (db < -50.0f) {
472 def = (db + 60.0f) * 0.5f + 2.5f;
473 } else if (db < -40.0f) {
474 def = (db + 50.0f) * 0.75f + 7.5f;
475 } else if (db < -30.0f) {
476 def = (db + 40.0f) * 1.5f + 15.0f;
477 } else if (db < -20.0f) {
478 def = (db + 30.0f) * 2.0f + 30.0f;
479 } else if (db < 6.0f) {
480 def = (db + 20.0f) * 2.5f + 50.0f;
483 /* 115 is the deflection %age that would be
484 when db=6.0. this is an arbitrary
485 endpoint for our scaling.
492 TranzportControlProtocol::show_meter ()
494 // you only seem to get a route_table[0] on moving forward - bug elsewhere
495 if (route_table[0] == 0) {
496 // Principle of least surprise
497 print (0, 0, "No audio to meter!!!");
498 print (1, 0, "Select another track");
502 float level = route_get_peak_input_power (0, 0);
503 float fraction = log_meter (level);
505 /* Someday add a peak bar*/
507 /* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
508 the screen is 20 chars wide, so we can display 40 different levels. compute the level,
509 then figure out how many "::" to fill. if the answer is odd, make the last one a ":"
512 uint32_t fill = (uint32_t) floor (fraction * 40);
516 if (fill == last_meter_fill) {
521 last_meter_fill = fill;
523 bool add_single_level = (fill % 2 != 0);
526 if (fraction > 0.98) {
527 light_on (LightAnysolo);
530 /* add all full steps */
532 for (i = 0; i < fill; ++i) {
533 buf[i] = 0x07; /* tranzport special code for 4 quadrant LCD block */
536 /* add a possible half-step */
538 if (i < 20 && add_single_level) {
539 buf[i] = 0x03; /* tranzport special code for 2 left quadrant LCD block */
543 /* fill rest with space */
545 for (; i < 20; ++i) {
549 /* print() requires this */
558 TranzportControlProtocol::show_bbt (nframes_t where)
560 if ((where != last_where) || lcd_isdamaged(1,9,8)) {
563 session->tempo_map().bbt_time (where, bbt);
564 sprintf (buf, "%03" PRIu32 "|%02" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
565 last_bars = bbt.bars;
566 last_beats = bbt.beats;
567 last_ticks = bbt.ticks;
570 if(last_ticks < 1960) { print (1, 9, buf); } // save a write so we can do leds
572 // if displaymode is recordmode show beats but not yet
573 lights_pending[LightRecord] = false;
574 lights_pending[LightAnysolo] = false;
576 case 1: if(last_ticks < 500 || last_ticks > 1960) lights_pending[LightRecord] = true; break;
577 default: if(last_ticks < 250) lights_pending[LightAnysolo] = true;
580 // update lights for tempo one day
581 // if (bbt_upper_info_label) {
582 // TempoMap::Metric m (session->tempo_map().metric_at (when));
583 // sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
584 // bbt_lower_info_label->set_text (buf);
585 // sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
586 // bbt_upper_info_label->set_text (buf);
592 TranzportControlProtocol::show_transport_time ()
594 nframes_t where = session->transport_frame();
599 TranzportControlProtocol::show_smpte (nframes_t where)
601 if ((where != last_where) || lcd_isdamaged(1,9,10)) {
606 session->smpte_time (where, smpte);
608 if (smpte.negative) {
609 sprintf (buf, "-%02" PRIu32 ":", smpte.hours);
611 sprintf (buf, " %02" PRIu32 ":", smpte.hours);
615 sprintf (buf, "%02" PRIu32 ":", smpte.minutes);
618 sprintf (buf, "%02" PRIu32 ":", smpte.seconds);
621 sprintf (buf, "%02" PRIu32, smpte.frames);
622 print_noretry (1, 18, buf);
629 TranzportControlProtocol::_monitor_work (void* arg)
631 return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
634 // I note that these usb specific open, close, probe, read routines are basically
635 // pure boilerplate and could easily be abstracted elsewhere
637 #if !HAVE_TRANZPORT_KERNEL_DRIVER
640 TranzportControlProtocol::probe ()
643 struct usb_device *dev;
649 for (bus = usb_busses; bus; bus = bus->next) {
651 for(dev = bus->devices; dev; dev = dev->next) {
652 if (dev->descriptor.idVendor == VENDORID && dev->descriptor.idProduct == PRODUCTID) {
662 TranzportControlProtocol::open ()
665 struct usb_device *dev;
671 for (bus = usb_busses; bus; bus = bus->next) {
673 for(dev = bus->devices; dev; dev = dev->next) {
674 if (dev->descriptor.idVendor != VENDORID)
676 if (dev->descriptor.idProduct != PRODUCTID)
678 return open_core (dev);
682 error << _("Tranzport: no device detected") << endmsg;
687 TranzportControlProtocol::open_core (struct usb_device* dev)
689 if (!(udev = usb_open (dev))) {
690 error << _("Tranzport: cannot open USB transport") << endmsg;
694 if (usb_claim_interface (udev, 0) < 0) {
695 error << _("Tranzport: cannot claim USB interface") << endmsg;
701 if (usb_set_configuration (udev, 1) < 0) {
702 cerr << _("Tranzport: cannot configure USB interface") << endmsg;
709 TranzportControlProtocol::close ()
717 if (usb_release_interface (udev, 0) < 0) {
718 error << _("Tranzport: cannot release interface") << endmsg;
722 if (usb_close (udev)) {
723 error << _("Tranzport: cannot close device") << endmsg;
731 int TranzportControlProtocol::read(uint8_t *buf, uint32_t timeout_override)
734 // Get smarter about handling usb errors soon. Like disconnect
735 // pthread_testcancel();
736 val = usb_interrupt_read (udev, READ_ENDPOINT, (char *) buf, 8, 10);
737 // pthread_testcancel();
743 TranzportControlProtocol::write_noretry (uint8_t* cmd, uint32_t timeout_override)
746 if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
747 val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
751 printf("usb_interrupt_write failed: %d\n", val);
758 printf("usb_interrupt_write failed: %d\n", val);
769 TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
774 if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
776 while((val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout))!=8 && retry++ < MAX_RETRY) {
777 printf("usb_interrupt_write failed, retrying: %d\n", val);
780 if (retry == MAX_RETRY) {
781 printf("Too many retries on a tranzport write, aborting\n");
785 printf("usb_interrupt_write failed: %d\n", val);
789 printf("usb_interrupt_write failed: %d\n", val);
795 return (write_noretry(cmd,timeout_override));
801 #error Kernel API not defined yet for Tranzport
802 // Something like open(/dev/surface/tranzport/event) for reading and raw for writing)
805 // We have a state "Unknown" - STOP USING SPACES FOR IT - switching to arrow character
806 // We have another state - no_retry. Misleading, as we still retry on the next pass
807 // I think it's pointless to keep no_retry and instead we should throttle writes
808 // We have an "displayed" screen
809 // We always draw into the pending screen, which could be any of several screens
810 // We have an active screen
811 // Print arg - we have
813 // so someday I think we need a screen object.
816 screen_flash.clear();
817 screen_flash.print(0,0,"Undone:"); // Someday pull the undo stack from somewhere
818 screen_flash.print(1,0,"Nextup:");
820 if(flash_messages && lcd.getactive() != screen_flash) lcd.setactive(screen_flash,2000);
822 screen::setactive(screen_name,duration); // duration in ms
828 TranzportControlProtocol::flush ()
831 if(!(pending = lights_flush())) {
832 pending = screen_flush();
837 // doing these functions made me realize that screen_invalid should be lcd_isdamaged FIXME soon
839 bool TranzportControlProtocol::lcd_damage()
845 bool TranzportControlProtocol::lcd_damage (int row, int col, int length)
848 int endcol = col+length-1;
849 if((endcol > 19)) { endcol = 19; }
850 if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
851 for(int c = col; c < endcol; c++) {
852 screen_invalid[row][c] = true;
859 // Gotta switch to bitfields, this is collossally dumb
860 // Still working on the layering, arguably screen_invalid should be lcd_invalid
862 bool TranzportControlProtocol::lcd_isdamaged ()
864 for(int r = 0; r < 2; r++) {
865 for(int c = 0; c < 20; c++) {
866 if(screen_invalid[r][c]) {
867 #if DEBUG_TRANZPORT > 5
868 printf("row: %d,col: %d is damaged, should redraw it\n", r,c);
877 bool TranzportControlProtocol::lcd_isdamaged (int row, int col, int length)
880 int endcol = col+length;
881 if((endcol > 19)) { endcol = 19; }
882 if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
883 for(int c = col; c < endcol; c++) {
884 if(screen_invalid[row][c]) {
885 #if DEBUG_TRANZPORT > 5
886 printf("row: %d,col: %d is damaged, should redraw it\n", row,c);
895 // lcd_clear would be a separate function for a smart display
896 // here it does nothing, but for the sake of completeness it should
897 // probably write the lcd, and while I'm on the topic it should probably
898 // take a row, col, length argument....
901 TranzportControlProtocol::lcd_clear ()
906 // These lcd commands are not universally used yet and may drop out of the api
909 TranzportControlProtocol::lcd_flush ()
915 TranzportControlProtocol::lcd_write(uint8_t* cmd, uint32_t timeout_override)
917 return write(cmd,timeout_override);
921 TranzportControlProtocol::lcd_fill (uint8_t fill_char)
926 TranzportControlProtocol::lcd_print (int row, int col, const char* text)
931 void TranzportControlProtocol::lcd_print_noretry (int row, int col, const char* text)
936 // Lights are buffered
939 TranzportControlProtocol::lights_on ()
941 lights_pending[LightRecord] = lights_pending[LightTrackrec] =
942 lights_pending[LightTrackmute] = lights_pending[LightTracksolo] =
943 lights_pending[LightAnysolo] = lights_pending[LightLoop] =
944 lights_pending[LightPunch] = true;
948 TranzportControlProtocol::lights_off ()
950 lights_pending[LightRecord] = lights_pending[LightTrackrec] =
951 lights_pending[LightTrackmute] = lights_pending[LightTracksolo] =
952 lights_pending[LightAnysolo] = lights_pending[LightLoop] =
953 lights_pending[LightPunch] = false;
957 TranzportControlProtocol::light_on (LightID light)
959 lights_pending[light] = true;
964 TranzportControlProtocol::light_off (LightID light)
966 lights_pending[light] = false;
971 TranzportControlProtocol::light_set (LightID light, bool offon)
974 cmd[0] = 0x00; cmd[1] = 0x00; cmd[2] = light; cmd[3] = offon;
975 cmd[4] = 0x00; cmd[5] = 0x00; cmd[6] = 0x00; cmd[7] = 0x00;
977 if (write (cmd) == 0) {
978 lights_current[light] = offon;
979 lights_invalid[light] = false;
986 int TranzportControlProtocol::rtpriority_set(int priority)
988 struct sched_param rtparam;
990 // preallocate and memlock some stack with memlock?
991 char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
992 memset (&rtparam, 0, sizeof (rtparam));
993 rtparam.sched_priority = priority; /* XXX should be relative to audio (JACK) thread */
994 // Note - try SCHED_RR with a low limit
995 // - we don't care if we can't write everything this ms
996 // and it will help if we lose the device
997 if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
998 PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
1004 // Running with realtime privs is bad when you have problems
1006 int TranzportControlProtocol::rtpriority_unset(int priority)
1008 struct sched_param rtparam;
1010 memset (&rtparam, 0, sizeof (rtparam));
1011 rtparam.sched_priority = priority;
1012 if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
1013 PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
1016 PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
1020 // Slowly breaking this into where I can make usb processing it's own thread.
1023 TranzportControlProtocol::monitor_work ()
1026 int val = 0, pending = 0;
1027 bool first_time = true;
1028 uint8_t offline = 0;
1031 PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("Tranzport"));
1032 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
1033 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
1041 /* bInterval for this beastie is 10ms */
1043 if (_device_status == STATUS_OFFLINE) {
1045 if(offline++ == 1) {
1046 cerr << "Transport has gone offline\n";
1049 offline = 0; // hate writing this
1058 #if DEBUG_TRANZPORT > 2
1059 if(inflight > 1) printf("Inflight: %d\n", inflight);
1063 if (_device_status != STATUS_OFFLINE) {
1070 pending = 3; // Give some time for the device to recover
1072 /* update whatever needs updating */
1075 /* still struggling with a good means of exerting flow control */
1076 // pending = flush();
1082 pending = --inflight; // we just did a whole bunch of writes so wait
1094 int TranzportControlProtocol::lights_show_recording()
1096 // FIXME, flash recording light when recording and transport is moving
1097 return lights_show_normal();
1100 // gotta do bling next!
1102 int TranzportControlProtocol::lights_show_bling()
1104 switch (bling_mode) {
1105 case BlingOff: break;
1106 case BlingKit: break; // rotate rec/mute/solo/any solo back and forth
1107 case BlingRotating: break; // switch between lights
1108 case BlingPairs: break; // Show pairs of lights
1109 case BlingRows: break; // light each row in sequence
1110 case BlingFlashAll: break; // Flash everything randomly
1115 int TranzportControlProtocol::lights_show_normal()
1119 if (route_table[0]) {
1120 boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
1121 lights_pending[LightTrackrec] = at && at->record_enabled();
1122 lights_pending[LightTrackmute] = route_get_muted(0);
1123 lights_pending[LightTracksolo] = route_get_soloed(0);
1125 lights_pending[LightTrackrec] = false;
1126 lights_pending[LightTracksolo] = false;
1127 lights_pending[LightTrackmute] = false;
1130 /* Global settings */
1132 lights_pending[LightLoop] = session->get_play_loop();
1133 lights_pending[LightPunch] = Config->get_punch_in() || Config->get_punch_out();
1134 lights_pending[LightRecord] = session->get_record_enabled();
1135 lights_pending[LightAnysolo] = session->soloing();
1140 int TranzportControlProtocol::lights_show_tempo()
1142 // someday soon fiddle with the lights based on the tempo
1143 return lights_show_normal();
1147 TranzportControlProtocol::update_state ()
1149 /* do the text and light updates */
1151 switch (display_mode) {
1152 case DisplayBigMeter:
1153 lights_show_tempo();
1158 lights_show_normal();
1165 case DisplayRecording:
1166 lights_show_recording();
1170 case DisplayRecordingMeter:
1171 lights_show_recording();
1176 lights_show_bling();
1180 case DisplayBlingMeter:
1181 lights_show_bling();
1189 #define TRANZPORT_BUTTON_HANDLER(callback, button_arg) if (button_changes & button_arg) { \
1190 if (buttonmask & button_arg) { \
1191 callback##_press (buttonmask&ButtonShift); } else { callback##_release (buttonmask&ButtonShift); } }
1194 TranzportControlProtocol::process (uint8_t* buf)
1196 // printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
1198 uint32_t this_button_mask;
1199 uint32_t button_changes;
1201 _device_status = buf[1];
1203 this_button_mask = 0;
1204 this_button_mask |= buf[2] << 24;
1205 this_button_mask |= buf[3] << 16;
1206 this_button_mask |= buf[4] << 8;
1207 this_button_mask |= buf[5];
1208 _datawheel = buf[6];
1210 button_changes = (this_button_mask ^ buttonmask);
1211 buttonmask = this_button_mask;
1217 // SHIFT + STOP + PLAY for bling mode?
1218 // if (button_changes & ButtonPlay & ButtonStop) {
1219 // bling_mode_toggle();
1220 // } or something like that
1222 TRANZPORT_BUTTON_HANDLER(button_event_battery,ButtonBattery);
1223 TRANZPORT_BUTTON_HANDLER(button_event_backlight,ButtonBacklight);
1224 TRANZPORT_BUTTON_HANDLER(button_event_trackleft,ButtonTrackLeft);
1225 TRANZPORT_BUTTON_HANDLER(button_event_trackright,ButtonTrackRight);
1226 TRANZPORT_BUTTON_HANDLER(button_event_trackrec,ButtonTrackRec);
1227 TRANZPORT_BUTTON_HANDLER(button_event_trackmute,ButtonTrackMute);
1228 TRANZPORT_BUTTON_HANDLER(button_event_tracksolo,ButtonTrackSolo);
1229 TRANZPORT_BUTTON_HANDLER(button_event_undo,ButtonUndo);
1230 TRANZPORT_BUTTON_HANDLER(button_event_in,ButtonIn);
1231 TRANZPORT_BUTTON_HANDLER(button_event_out,ButtonOut);
1232 TRANZPORT_BUTTON_HANDLER(button_event_punch,ButtonPunch);
1233 TRANZPORT_BUTTON_HANDLER(button_event_loop,ButtonLoop);
1234 TRANZPORT_BUTTON_HANDLER(button_event_prev,ButtonPrev);
1235 TRANZPORT_BUTTON_HANDLER(button_event_add,ButtonAdd);
1236 TRANZPORT_BUTTON_HANDLER(button_event_next,ButtonNext);
1237 TRANZPORT_BUTTON_HANDLER(button_event_rewind,ButtonRewind);
1238 TRANZPORT_BUTTON_HANDLER(button_event_fastforward,ButtonFastForward);
1239 TRANZPORT_BUTTON_HANDLER(button_event_stop,ButtonStop);
1240 TRANZPORT_BUTTON_HANDLER(button_event_play,ButtonPlay);
1241 TRANZPORT_BUTTON_HANDLER(button_event_record,ButtonRecord);
1246 TranzportControlProtocol::show_current_track ()
1251 if (route_table[0] == 0) {
1252 print (0, 0, "----------");
1253 last_track_gain = FLT_MAX;
1256 v = (char *)route_get_name (0).substr (0, 10).c_str();
1257 if((len = strlen(v)) > 0) {
1258 strncpy(pad,(char *)v,len);
1265 TranzportControlProtocol::button_event_battery_press (bool shifted)
1270 TranzportControlProtocol::button_event_battery_release (bool shifted)
1275 TranzportControlProtocol::button_event_backlight_press (bool shifted)
1278 printf("backlight pressed\n");
1283 TranzportControlProtocol::button_event_backlight_release (bool shifted)
1286 printf("backlight released\n\n");
1291 last_where += 1; /* force time redisplay */
1292 last_track_gain = FLT_MAX;
1293 normal_update(); // redraw_screen();
1298 TranzportControlProtocol::button_event_trackleft_press (bool shifted)
1304 TranzportControlProtocol::button_event_trackleft_release (bool shifted)
1309 TranzportControlProtocol::button_event_trackright_press (bool shifted)
1315 TranzportControlProtocol::button_event_trackright_release (bool shifted)
1320 TranzportControlProtocol::button_event_trackrec_press (bool shifted)
1323 toggle_all_rec_enables ();
1325 route_set_rec_enable (0, !route_get_rec_enable (0));
1330 TranzportControlProtocol::button_event_trackrec_release (bool shifted)
1335 TranzportControlProtocol::button_event_trackmute_press (bool shifted)
1338 // Mute ALL? Something useful when a phone call comes in. Mute master?
1340 route_set_muted (0, !route_get_muted (0));
1345 TranzportControlProtocol::button_event_trackmute_release (bool shifted)
1350 TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
1353 printf("solo pressed\n");
1355 if (display_mode == DisplayBigMeter) {
1356 light_off (LightAnysolo);
1361 session->set_all_solo (!session->soloing());
1363 route_set_soloed (0, !route_get_soloed (0));
1368 TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
1371 printf("solo released\n");
1376 TranzportControlProtocol::button_event_undo_press (bool shifted)
1379 redo (); // someday flash the screen with what was redone
1381 undo (); // someday flash the screen with what was undone
1386 TranzportControlProtocol::button_event_undo_release (bool shifted)
1391 TranzportControlProtocol::button_event_in_press (bool shifted)
1396 ControlProtocol::ZoomIn (); /* EMIT SIGNAL */
1401 TranzportControlProtocol::button_event_in_release (bool shifted)
1406 TranzportControlProtocol::button_event_out_press (bool shifted)
1409 toggle_punch_out ();
1411 ControlProtocol::ZoomOut (); /* EMIT SIGNAL */
1416 TranzportControlProtocol::button_event_out_release (bool shifted)
1421 TranzportControlProtocol::button_event_punch_press (bool shifted)
1426 TranzportControlProtocol::button_event_punch_release (bool shifted)
1431 TranzportControlProtocol::button_event_loop_press (bool shifted)
1434 next_wheel_shift_mode ();
1441 TranzportControlProtocol::button_event_loop_release (bool shifted)
1446 TranzportControlProtocol::button_event_prev_press (bool shifted)
1449 ControlProtocol::ZoomToSession (); /* EMIT SIGNAL */
1456 TranzportControlProtocol::button_event_prev_release (bool shifted)
1461 TranzportControlProtocol::button_event_add_press (bool shifted)
1467 TranzportControlProtocol::button_event_add_release (bool shifted)
1472 TranzportControlProtocol::button_event_next_press (bool shifted)
1482 TranzportControlProtocol::button_event_next_release (bool shifted)
1487 TranzportControlProtocol::button_event_rewind_press (bool shifted)
1497 TranzportControlProtocol::button_event_rewind_release (bool shifted)
1502 TranzportControlProtocol::button_event_fastforward_press (bool shifted)
1512 TranzportControlProtocol::button_event_fastforward_release (bool shifted)
1517 TranzportControlProtocol::button_event_stop_press (bool shifted)
1520 next_display_mode ();
1527 TranzportControlProtocol::button_event_stop_release (bool shifted)
1532 TranzportControlProtocol::button_event_play_press (bool shifted)
1535 set_transport_speed (1.0f);
1542 TranzportControlProtocol::button_event_play_release (bool shifted)
1547 TranzportControlProtocol::button_event_record_press (bool shifted)
1552 rec_enable_toggle ();
1557 TranzportControlProtocol::button_event_record_release (bool shifted)
1561 void button_event_mute (bool pressed, bool shifted)
1563 static int was_pressed = 0;
1568 TranzportControlProtocol::datawheel ()
1570 if ((buttonmask & ButtonTrackRight) || (buttonmask & ButtonTrackLeft)) {
1572 /* track scrolling */
1574 if (_datawheel < WheelDirectionThreshold) {
1580 timerclear (&last_wheel_motion);
1582 } else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
1584 if (_datawheel < WheelDirectionThreshold) {
1590 timerclear (&last_wheel_motion);
1592 } else if (buttonmask & ButtonShift) {
1594 /* parameter control */
1596 if (route_table[0]) {
1597 switch (wheel_shift_mode) {
1598 case WheelShiftGain:
1599 if (_datawheel < WheelDirectionThreshold) {
1606 if (_datawheel < WheelDirectionThreshold) {
1613 case WheelShiftMarker:
1616 case WheelShiftMaster:
1622 timerclear (&last_wheel_motion);
1626 switch (wheel_mode) {
1643 TranzportControlProtocol::scroll ()
1646 if (_datawheel < WheelDirectionThreshold) {
1651 switch(wheel_increment) {
1652 case WheelIncrScreen: ScrollTimeline (0.2*m); break;
1653 default: break; // other modes unimplemented as yet
1658 TranzportControlProtocol::scrub ()
1662 struct timeval delta;
1665 gettimeofday (&now, 0);
1667 if (_datawheel < WheelDirectionThreshold) {
1673 if (dir != last_wheel_dir) {
1674 /* changed direction, start over */
1677 if (timerisset (&last_wheel_motion)) {
1679 timersub (&now, &last_wheel_motion, &delta);
1681 /* 10 clicks per second => speed == 1.0 */
1683 speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
1687 /* start at half-speed and see where we go from there */
1693 last_wheel_motion = now;
1694 last_wheel_dir = dir;
1696 set_transport_speed (speed * dir);
1700 TranzportControlProtocol::config ()
1706 TranzportControlProtocol::shuttle ()
1708 if (_datawheel < WheelDirectionThreshold) {
1709 if (session->transport_speed() < 0) {
1710 session->request_transport_speed (1.0);
1712 session->request_transport_speed (session->transport_speed() + 0.1);
1715 if (session->transport_speed() > 0) {
1716 session->request_transport_speed (-1.0);
1718 session->request_transport_speed (session->transport_speed() - 0.1);
1724 TranzportControlProtocol::step_gain_up ()
1726 if (buttonmask & ButtonStop) {
1727 gain_fraction += 0.001;
1729 gain_fraction += 0.01;
1732 if (gain_fraction > 2.0) {
1733 gain_fraction = 2.0;
1736 route_set_gain (0, slider_position_to_gain (gain_fraction));
1740 TranzportControlProtocol::step_gain_down ()
1742 if (buttonmask & ButtonStop) {
1743 gain_fraction -= 0.001;
1745 gain_fraction -= 0.01;
1748 if (gain_fraction < 0.0) {
1749 gain_fraction = 0.0;
1752 route_set_gain (0, slider_position_to_gain (gain_fraction));
1756 TranzportControlProtocol::step_pan_right ()
1761 TranzportControlProtocol::step_pan_left ()
1766 TranzportControlProtocol::next_wheel_shift_mode ()
1768 switch (wheel_shift_mode) {
1769 case WheelShiftGain:
1770 wheel_shift_mode = WheelShiftPan;
1773 wheel_shift_mode = WheelShiftMaster;
1775 case WheelShiftMaster:
1776 wheel_shift_mode = WheelShiftGain;
1778 case WheelShiftMarker: // Not done yet, disabled
1779 wheel_shift_mode = WheelShiftGain;
1787 TranzportControlProtocol::next_wheel_mode ()
1789 switch (wheel_mode) {
1791 wheel_mode = WheelScrub;
1794 wheel_mode = WheelShuttle;
1797 wheel_mode = WheelTimeline;
1804 TranzportControlProtocol::next_track ()
1806 ControlProtocol::next_track (current_track_id);
1807 gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1811 TranzportControlProtocol::prev_track ()
1813 ControlProtocol::prev_track (current_track_id);
1814 gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1818 TranzportControlProtocol::show_wheel_mode ()
1822 switch (wheel_mode) {
1834 switch (wheel_shift_mode) {
1835 case WheelShiftGain:
1843 case WheelShiftMaster:
1847 case WheelShiftMarker:
1852 print (1, 0, text.c_str());
1855 // Was going to keep state around saying to retry or not
1856 // haven't got to it yet, still not sure it's a good idea
1859 TranzportControlProtocol::print (int row, int col, const char *text) {
1860 print_noretry(row,col,text);
1864 TranzportControlProtocol::print_noretry (int row, int col, const char *text)
1867 uint32_t left = strlen (text);
1871 if (row < 0 || row > 1) {
1875 if (col < 0 || col > 19) {
1881 if (col >= 0 && col < 4) {
1884 } else if (col >= 4 && col < 8) {
1887 } else if (col >= 8 && col < 12) {
1890 } else if (col >= 12 && col < 16) {
1893 } else if (col >= 16 && col < 20) {
1900 int offset = col % 4;
1902 /* copy current cell contents into tmp */
1904 memcpy (tmp, &screen_pending[row][base_col], 4);
1906 /* overwrite with new text */
1908 uint32_t tocopy = min ((4U - offset), left);
1910 memcpy (tmp+offset, text, tocopy);
1912 /* copy it back to pending */
1914 memcpy (&screen_pending[row][base_col], tmp, 4);
1923 TranzportControlProtocol::get_state ()
1925 XMLNode* node = new XMLNode (X_("Protocol"));
1926 node->add_property (X_("name"), _name);
1931 TranzportControlProtocol::set_state (const XMLNode& node)
1937 TranzportControlProtocol::save (char *name)
1939 // Presently unimplemented
1944 TranzportControlProtocol::load (char *name)
1946 // Presently unimplemented