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.
21 /* Design notes: The tranzport is a unique device, basically a
22 20 lcd gui with 22 shift keys and 8 blinking lights.
24 As such it has several unique constraints. The device exerts flow control
25 by having a usb write fail. It is pointless to retry madly at that point,
26 the device is busy, and it's not going to become unbusy very quickly.
28 So writes need to be either "mandatory" or "unreliable", and therein
29 lies the rub, as the kernel can also drop writes, and missing an
30 interrupt in userspace is also generally bad.
32 It will be good one day, to break the gui, keyboard, and blinking light
33 components into separate parts, but for now, this remains monolithic.
35 A more complex surface might have hundreds of lights and several displays.
40 #define DEFAULT_USB_TIMEOUT 10
42 #define MAX_TRANZPORT_INFLIGHT 4
43 #define DEBUG_TRANZPORT 0
44 #define HAVE_TRANZPORT_KERNEL_DRIVER 0
50 #define __STDC_FORMAT_MACROS
56 #include <pbd/pthread_utils.h>
58 #include <ardour/route.h>
59 #include <ardour/audio_track.h>
60 #include <ardour/session.h>
61 #include <ardour/tempo.h>
62 #include <ardour/location.h>
63 #include <ardour/dB.h>
65 #include "tranzport_control_protocol.h"
67 using namespace ARDOUR;
74 #include <pbd/abstract_ui.cc>
76 BaseUI::RequestType LEDChange = BaseUI::new_request_type ();
77 BaseUI::RequestType Print = BaseUI::new_request_type ();
78 BaseUI::RequestType SetCurrentTrack = BaseUI::new_request_type ();
80 /* Base Tranzport cmd strings */
82 static const uint8_t cmd_light_on[] = { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
83 static const uint8_t cmd_light_off[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
84 static const uint8_t cmd_write_screen[] = { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
87 gain_to_slider_position (ARDOUR::gain_t g)
90 return pow((6.0*log(g)/log(2.0)+192.0)/198.0, 8.0);
94 static inline ARDOUR::gain_t
95 slider_position_to_gain (double pos)
97 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
98 if (pos == 0.0) return 0;
99 return pow (2.0,(sqrt(sqrt(sqrt(pos)))*198.0-192.0)/6.0);
103 TranzportControlProtocol::TranzportControlProtocol (Session& s)
104 : ControlProtocol (s, X_("Tranzport"))
106 /* tranzport controls one track at a time */
108 set_route_table_size (1);
109 timeout = 6000; // what is this for?
112 _device_status = STATUS_OFFLINE;
114 current_track_id = 0;
115 last_where = max_frames;
116 wheel_mode = WheelTimeline;
117 wheel_shift_mode = WheelShiftGain;
118 wheel_increment = WheelIncrScreen;
119 bling_mode = BlingOff;
120 timerclear (&last_wheel_motion);
122 last_track_gain = FLT_MAX;
123 display_mode = DisplayNormal;
128 print(0,0,"!!Welcome to Ardour!!");
129 print(1,0,"!Peace through Music!");
132 void TranzportControlProtocol::light_validate (LightID light)
134 lights_invalid[light] = 0;
137 void TranzportControlProtocol::light_invalidate (LightID light)
139 lights_invalid[light] = 1;
142 void TranzportControlProtocol::lights_validate ()
144 memset (lights_invalid, 0, sizeof (lights_invalid));
147 void TranzportControlProtocol::lights_invalidate ()
149 memset (lights_invalid, 1, sizeof (lights_invalid));
152 void TranzportControlProtocol::lights_init()
154 for (uint32_t i = 0; i < sizeof(lights_current)/sizeof(lights_current[0]); i++) {
155 lights_invalid[i] = lights_current[i] =
156 lights_pending[i] = lights_flash[i] = false;
163 TranzportControlProtocol::lights_flush ()
165 if ( _device_status == STATUS_OFFLINE) { return (0); }
167 // Figure out iterators one day soon
168 // for (LightID i = i.start(), i = i.end(); i++) {
169 // if (lights_pending[i] != lights_current[i] || lights_invalid[i]) {
170 // if (light_set(i, lights_pending[i])) {
175 if ((lights_pending[LightRecord] != lights_current[LightRecord]) || lights_invalid[LightRecord]) {
176 if (light_set(LightRecord,lights_pending[LightRecord])) {
180 if ((lights_pending[LightTrackrec] != lights_current[LightTrackrec]) || lights_invalid[LightTrackrec]) {
181 if (light_set(LightTrackrec,lights_pending[LightTrackrec])) {
186 if ((lights_pending[LightTrackmute] != lights_current[LightTrackmute]) || lights_invalid[LightTrackmute]) {
187 if (light_set(LightTrackmute,lights_pending[LightTrackmute])) {
192 if ((lights_pending[LightTracksolo] != lights_current[LightTracksolo]) || lights_invalid[LightTracksolo]) {
193 if (light_set(LightTracksolo,lights_pending[LightTracksolo])) {
197 if ((lights_pending[LightAnysolo] != lights_current[LightAnysolo]) || lights_invalid[LightAnysolo]) {
198 if (light_set(LightAnysolo,lights_pending[LightAnysolo])) {
202 if ((lights_pending[LightLoop] != lights_current[LightLoop]) || lights_invalid[LightLoop]) {
203 if (light_set(LightLoop,lights_pending[LightLoop])) {
207 if ((lights_pending[LightPunch] != lights_current[LightPunch]) || lights_invalid[LightPunch]) {
208 if (light_set(LightPunch,lights_pending[LightPunch])) {
216 // Screen specific commands
219 TranzportControlProtocol::screen_clear ()
221 const char *blank = " ";
226 void TranzportControlProtocol::screen_invalidate ()
228 for(int row = 0; row < 2; row++) {
229 for(int col = 0; col < 20; col++) {
230 screen_invalid[row][col] = true;
231 screen_current[row][col] = 0x7f;
232 screen_pending[row][col] = ' ';
233 // screen_flash[row][col] = ' ';
236 // memset (&screen_invalid, 1, sizeof(screen_invalid));
237 // memset (&screen_current, 0x7F, sizeof (screen_current)); // fill cache with a character we otherwise never use
240 void TranzportControlProtocol::screen_validate ()
244 void TranzportControlProtocol::screen_init ()
250 TranzportControlProtocol::screen_flush ()
252 int cell = 0, row, col_base, col, pending = 0;
253 if ( _device_status == STATUS_OFFLINE) { return (-1); }
255 for (row = 0; row < 2 && pending == 0; row++) {
256 for (col_base = 0, col = 0; col < 20 && pending == 0; ) {
257 if ((screen_pending[row][col] != screen_current[row][col])
258 || screen_invalid[row][col]) {
260 /* something in this cell is different, so dump the cell to the device. */
266 cmd[3] = screen_pending[row][col_base];
267 cmd[4] = screen_pending[row][col_base+1];
268 cmd[5] = screen_pending[row][col_base+2];
269 cmd[6] = screen_pending[row][col_base+3];
272 if(write(cmd) != 0) {
273 /* try to update this cell on the next go-round */
274 #if DEBUG_TRANZPORT > 4
275 printf("usb screen update failed for some reason... why? \ncmd and data were %02x %02x %02x %02x %02x %02x %02x %02x\n",
276 cmd[0],cmd[1],cmd[2], cmd[3], cmd[4], cmd[5],cmd[6],cmd[7]);
279 // Shouldn't need to do this
280 // screen_invalid[row][col_base] = screen_invalid[row][col_base+1] =
281 // screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = true;
284 /* successful write: copy to current cached display */
285 screen_invalid[row][col_base] = screen_invalid[row][col_base+1] =
286 screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = false;
287 memcpy (&screen_current[row][col_base], &screen_pending[row][col_base], 4);
290 /* skip the rest of the 4 character cell since we wrote+copied it already */
300 if (col && col % 4 == 0) {
311 // Tranzport specific
313 void TranzportControlProtocol::invalidate()
315 lcd_damage(); lights_invalidate(); screen_invalidate(); // one of these days lcds can be fine but screens not
318 TranzportControlProtocol::~TranzportControlProtocol ()
325 TranzportControlProtocol::set_active (bool yn)
335 if (pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _monitor_work, this) == 0) {
342 cerr << "Begin tranzport shutdown\n";
346 for(int x = 0; x < 10 && flush(); x++) { usleep(1000); }
347 pthread_cancel_one (thread);
348 cerr << "Tranzport Thread dead\n";
351 cerr << "End tranzport shutdown\n";
359 TranzportControlProtocol::show_track_gain ()
361 if (route_table[0]) {
362 gain_t g = route_get_gain (0);
363 if ((g != last_track_gain) || lcd_isdamaged(0,9,8)) {
365 snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
375 TranzportControlProtocol::normal_update ()
377 show_current_track ();
378 show_transport_time ();
384 TranzportControlProtocol::next_display_mode ()
386 switch (display_mode) {
389 enter_big_meter_mode();
392 case DisplayBigMeter:
393 enter_normal_display_mode();
396 case DisplayRecording:
397 enter_normal_display_mode();
400 case DisplayRecordingMeter:
401 enter_big_meter_mode();
406 case DisplayBlingMeter:
407 enter_normal_display_mode();
412 // FIXME, these 3 aren't done yet
415 TranzportControlProtocol::enter_recording_mode ()
417 lcd_damage(); // excessive
420 display_mode = DisplayRecording;
424 TranzportControlProtocol::enter_bling_mode ()
429 display_mode = DisplayBling;
433 TranzportControlProtocol::enter_config_mode ()
438 display_mode = DisplayConfig;
443 TranzportControlProtocol::enter_big_meter_mode ()
449 display_mode = DisplayBigMeter;
453 TranzportControlProtocol::enter_normal_display_mode ()
458 display_mode = DisplayNormal;
466 float def = 0.0f; /* Meter deflection %age */
468 if (db < -70.0f) return 0.0f;
469 if (db > 6.0f) return 1.0f;
472 def = (db + 70.0f) * 0.25f;
473 } else if (db < -50.0f) {
474 def = (db + 60.0f) * 0.5f + 2.5f;
475 } else if (db < -40.0f) {
476 def = (db + 50.0f) * 0.75f + 7.5f;
477 } else if (db < -30.0f) {
478 def = (db + 40.0f) * 1.5f + 15.0f;
479 } else if (db < -20.0f) {
480 def = (db + 30.0f) * 2.0f + 30.0f;
481 } else if (db < 6.0f) {
482 def = (db + 20.0f) * 2.5f + 50.0f;
485 /* 115 is the deflection %age that would be
486 when db=6.0. this is an arbitrary
487 endpoint for our scaling.
494 TranzportControlProtocol::show_meter ()
496 // you only seem to get a route_table[0] on moving forward - bug elsewhere
497 if (route_table[0] == 0) {
498 // Principle of least surprise
499 print (0, 0, "No audio to meter!!!");
500 print (1, 0, "Select another track");
504 float level = route_get_peak_input_power (0, 0);
505 float fraction = log_meter (level);
507 /* Someday add a peak bar*/
509 /* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
510 the screen is 20 chars wide, so we can display 40 different levels. compute the level,
511 then figure out how many "::" to fill. if the answer is odd, make the last one a ":"
514 uint32_t fill = (uint32_t) floor (fraction * 40);
518 if (fill == last_meter_fill) {
523 last_meter_fill = fill;
525 bool add_single_level = (fill % 2 != 0);
528 if (fraction > 0.98) {
529 light_on (LightAnysolo);
532 /* add all full steps */
534 for (i = 0; i < fill; ++i) {
535 buf[i] = 0x07; /* tranzport special code for 4 quadrant LCD block */
538 /* add a possible half-step */
540 if (i < 20 && add_single_level) {
541 buf[i] = 0x03; /* tranzport special code for 2 left quadrant LCD block */
545 /* fill rest with space */
547 for (; i < 20; ++i) {
551 /* print() requires this */
560 TranzportControlProtocol::show_bbt (nframes_t where)
562 if ((where != last_where) || lcd_isdamaged(1,9,8)) {
565 session->tempo_map().bbt_time (where, bbt);
566 sprintf (buf, "%03" PRIu32 "|%02" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
567 last_bars = bbt.bars;
568 last_beats = bbt.beats;
569 last_ticks = bbt.ticks;
572 if(last_ticks < 1960) { print (1, 9, buf); } // save a write so we can do leds
574 // if displaymode is recordmode show beats but not yet
575 lights_pending[LightRecord] = false;
576 lights_pending[LightAnysolo] = false;
578 case 1: if(last_ticks < 500 || last_ticks > 1960) lights_pending[LightRecord] = true; break;
579 default: if(last_ticks < 250) lights_pending[LightAnysolo] = true;
582 // update lights for tempo one day
583 // if (bbt_upper_info_label) {
584 // TempoMap::Metric m (session->tempo_map().metric_at (when));
585 // sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
586 // bbt_lower_info_label->set_text (buf);
587 // sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
588 // bbt_upper_info_label->set_text (buf);
594 TranzportControlProtocol::show_transport_time ()
596 nframes_t where = session->transport_frame();
601 TranzportControlProtocol::show_smpte (nframes_t where)
603 if ((where != last_where) || lcd_isdamaged(1,9,10)) {
608 session->smpte_time (where, smpte);
610 if (smpte.negative) {
611 sprintf (buf, "-%02" PRIu32 ":", smpte.hours);
613 sprintf (buf, " %02" PRIu32 ":", smpte.hours);
617 sprintf (buf, "%02" PRIu32 ":", smpte.minutes);
620 sprintf (buf, "%02" PRIu32 ":", smpte.seconds);
623 sprintf (buf, "%02" PRIu32, smpte.frames);
624 print_noretry (1, 18, buf);
631 TranzportControlProtocol::_monitor_work (void* arg)
633 return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
636 // I note that these usb specific open, close, probe, read routines are basically
637 // pure boilerplate and could easily be abstracted elsewhere
639 #if !HAVE_TRANZPORT_KERNEL_DRIVER
642 TranzportControlProtocol::probe ()
645 struct usb_device *dev;
651 for (bus = usb_busses; bus; bus = bus->next) {
653 for(dev = bus->devices; dev; dev = dev->next) {
654 if (dev->descriptor.idVendor == VENDORID && dev->descriptor.idProduct == PRODUCTID) {
664 TranzportControlProtocol::open ()
667 struct usb_device *dev;
673 for (bus = usb_busses; bus; bus = bus->next) {
675 for(dev = bus->devices; dev; dev = dev->next) {
676 if (dev->descriptor.idVendor != VENDORID)
678 if (dev->descriptor.idProduct != PRODUCTID)
680 return open_core (dev);
684 error << _("Tranzport: no device detected") << endmsg;
689 TranzportControlProtocol::open_core (struct usb_device* dev)
691 if (!(udev = usb_open (dev))) {
692 error << _("Tranzport: cannot open USB transport") << endmsg;
696 if (usb_claim_interface (udev, 0) < 0) {
697 error << _("Tranzport: cannot claim USB interface") << endmsg;
703 if (usb_set_configuration (udev, 1) < 0) {
704 cerr << _("Tranzport: cannot configure USB interface") << endmsg;
711 TranzportControlProtocol::close ()
719 if (usb_release_interface (udev, 0) < 0) {
720 error << _("Tranzport: cannot release interface") << endmsg;
724 if (usb_close (udev)) {
725 error << _("Tranzport: cannot close device") << endmsg;
733 int TranzportControlProtocol::read(uint8_t *buf, uint32_t timeout_override)
736 // Get smarter about handling usb errors soon. Like disconnect
737 // pthread_testcancel();
738 val = usb_interrupt_read (udev, READ_ENDPOINT, (char *) buf, 8, 10);
739 // pthread_testcancel();
745 TranzportControlProtocol::write_noretry (uint8_t* cmd, uint32_t timeout_override)
748 if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
749 val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
753 printf("usb_interrupt_write failed: %d\n", val);
760 printf("usb_interrupt_write failed: %d\n", val);
771 TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
776 if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
778 while((val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout))!=8 && retry++ < MAX_RETRY) {
779 printf("usb_interrupt_write failed, retrying: %d\n", val);
782 if (retry == MAX_RETRY) {
783 printf("Too many retries on a tranzport write, aborting\n");
787 printf("usb_interrupt_write failed: %d\n", val);
791 printf("usb_interrupt_write failed: %d\n", val);
797 return (write_noretry(cmd,timeout_override));
803 #error Kernel API not defined yet for Tranzport
804 // Something like open(/dev/surface/tranzport/event) for reading and raw for writing)
807 // We have a state "Unknown" - STOP USING SPACES FOR IT - switching to arrow character
808 // We have another state - no_retry. Misleading, as we still retry on the next pass
809 // I think it's pointless to keep no_retry and instead we should throttle writes
810 // We have an "displayed" screen
811 // We always draw into the pending screen, which could be any of several screens
812 // We have an active screen
813 // Print arg - we have
815 // so someday I think we need a screen object.
818 screen_flash.clear();
819 screen_flash.print(0,0,"Undone:"); // Someday pull the undo stack from somewhere
820 screen_flash.print(1,0,"Nextup:");
822 if(flash_messages && lcd.getactive() != screen_flash) lcd.setactive(screen_flash,2000);
824 screen::setactive(screen_name,duration); // duration in ms
830 TranzportControlProtocol::flush ()
833 if(!(pending = lights_flush())) {
834 pending = screen_flush();
839 // doing these functions made me realize that screen_invalid should be lcd_isdamaged FIXME soon
841 bool TranzportControlProtocol::lcd_damage()
847 bool TranzportControlProtocol::lcd_damage (int row, int col, int length)
850 int endcol = col+length-1;
851 if((endcol > 19)) { endcol = 19; }
852 if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
853 for(int c = col; c < endcol; c++) {
854 screen_invalid[row][c] = true;
861 // Gotta switch to bitfields, this is collossally dumb
862 // Still working on the layering, arguably screen_invalid should be lcd_invalid
864 bool TranzportControlProtocol::lcd_isdamaged ()
866 for(int r = 0; r < 2; r++) {
867 for(int c = 0; c < 20; c++) {
868 if(screen_invalid[r][c]) {
869 #if DEBUG_TRANZPORT > 5
870 printf("row: %d,col: %d is damaged, should redraw it\n", r,c);
879 bool TranzportControlProtocol::lcd_isdamaged (int row, int col, int length)
882 int endcol = col+length;
883 if((endcol > 19)) { endcol = 19; }
884 if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
885 for(int c = col; c < endcol; c++) {
886 if(screen_invalid[row][c]) {
887 #if DEBUG_TRANZPORT > 5
888 printf("row: %d,col: %d is damaged, should redraw it\n", row,c);
897 // lcd_clear would be a separate function for a smart display
898 // here it does nothing, but for the sake of completeness it should
899 // probably write the lcd, and while I'm on the topic it should probably
900 // take a row, col, length argument....
903 TranzportControlProtocol::lcd_clear ()
908 // These lcd commands are not universally used yet and may drop out of the api
911 TranzportControlProtocol::lcd_flush ()
917 TranzportControlProtocol::lcd_write(uint8_t* cmd, uint32_t timeout_override)
919 return write(cmd,timeout_override);
923 TranzportControlProtocol::lcd_fill (uint8_t fill_char)
928 TranzportControlProtocol::lcd_print (int row, int col, const char* text)
933 void TranzportControlProtocol::lcd_print_noretry (int row, int col, const char* text)
938 // Lights are buffered
941 TranzportControlProtocol::lights_on ()
943 lights_pending[LightRecord] = lights_pending[LightTrackrec] =
944 lights_pending[LightTrackmute] = lights_pending[LightTracksolo] =
945 lights_pending[LightAnysolo] = lights_pending[LightLoop] =
946 lights_pending[LightPunch] = true;
950 TranzportControlProtocol::lights_off ()
952 lights_pending[LightRecord] = lights_pending[LightTrackrec] =
953 lights_pending[LightTrackmute] = lights_pending[LightTracksolo] =
954 lights_pending[LightAnysolo] = lights_pending[LightLoop] =
955 lights_pending[LightPunch] = false;
959 TranzportControlProtocol::light_on (LightID light)
961 lights_pending[light] = true;
966 TranzportControlProtocol::light_off (LightID light)
968 lights_pending[light] = false;
973 TranzportControlProtocol::light_set (LightID light, bool offon)
976 cmd[0] = 0x00; cmd[1] = 0x00; cmd[2] = light; cmd[3] = offon;
977 cmd[4] = 0x00; cmd[5] = 0x00; cmd[6] = 0x00; cmd[7] = 0x00;
979 if (write (cmd) == 0) {
980 lights_current[light] = offon;
981 lights_invalid[light] = false;
988 int TranzportControlProtocol::rtpriority_set(int priority)
990 struct sched_param rtparam;
992 // preallocate and memlock some stack with memlock?
993 char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
994 memset (&rtparam, 0, sizeof (rtparam));
995 rtparam.sched_priority = priority; /* XXX should be relative to audio (JACK) thread */
996 // Note - try SCHED_RR with a low limit
997 // - we don't care if we can't write everything this ms
998 // and it will help if we lose the device
999 if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
1000 PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
1006 // Running with realtime privs is bad when you have problems
1008 int TranzportControlProtocol::rtpriority_unset(int priority)
1010 struct sched_param rtparam;
1012 memset (&rtparam, 0, sizeof (rtparam));
1013 rtparam.sched_priority = priority;
1014 if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
1015 PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
1018 PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
1022 // Slowly breaking this into where I can make usb processing it's own thread.
1025 TranzportControlProtocol::monitor_work ()
1028 int val = 0, pending = 0;
1029 bool first_time = true;
1030 uint8_t offline = 0;
1033 PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
1034 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
1035 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
1043 /* bInterval for this beastie is 10ms */
1045 if (_device_status == STATUS_OFFLINE) {
1047 if(offline++ == 1) {
1048 cerr << "Transport has gone offline\n";
1051 offline = 0; // hate writing this
1060 #if DEBUG_TRANZPORT > 2
1061 if(inflight > 1) printf("Inflight: %d\n", inflight);
1065 if (_device_status != STATUS_OFFLINE) {
1072 pending = 3; // Give some time for the device to recover
1074 /* update whatever needs updating */
1077 /* still struggling with a good means of exerting flow control */
1078 // pending = flush();
1084 pending = --inflight; // we just did a whole bunch of writes so wait
1096 int TranzportControlProtocol::lights_show_recording()
1098 // FIXME, flash recording light when recording and transport is moving
1099 return lights_show_normal();
1102 // gotta do bling next!
1104 int TranzportControlProtocol::lights_show_bling()
1106 switch (bling_mode) {
1107 case BlingOff: break;
1108 case BlingKit: break; // rotate rec/mute/solo/any solo back and forth
1109 case BlingRotating: break; // switch between lights
1110 case BlingPairs: break; // Show pairs of lights
1111 case BlingRows: break; // light each row in sequence
1112 case BlingFlashAll: break; // Flash everything randomly
1117 int TranzportControlProtocol::lights_show_normal()
1121 if (route_table[0]) {
1122 boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
1123 lights_pending[LightTrackrec] = at && at->record_enabled();
1124 lights_pending[LightTrackmute] = route_get_muted(0);
1125 lights_pending[LightTracksolo] = route_get_soloed(0);
1127 lights_pending[LightTrackrec] = false;
1128 lights_pending[LightTracksolo] = false;
1129 lights_pending[LightTrackmute] = false;
1132 /* Global settings */
1134 lights_pending[LightLoop] = session->get_play_loop();
1135 lights_pending[LightPunch] = Config->get_punch_in() || Config->get_punch_out();
1136 lights_pending[LightRecord] = session->get_record_enabled();
1137 lights_pending[LightAnysolo] = session->soloing();
1142 int TranzportControlProtocol::lights_show_tempo()
1144 // someday soon fiddle with the lights based on the tempo
1145 return lights_show_normal();
1149 TranzportControlProtocol::update_state ()
1151 /* do the text and light updates */
1153 switch (display_mode) {
1154 case DisplayBigMeter:
1155 lights_show_tempo();
1160 lights_show_normal();
1167 case DisplayRecording:
1168 lights_show_recording();
1172 case DisplayRecordingMeter:
1173 lights_show_recording();
1178 lights_show_bling();
1182 case DisplayBlingMeter:
1183 lights_show_bling();
1191 #define TRANZPORT_BUTTON_HANDLER(callback, button_arg) if (button_changes & button_arg) { \
1192 if (buttonmask & button_arg) { \
1193 callback##_press (buttonmask&ButtonShift); } else { callback##_release (buttonmask&ButtonShift); } }
1196 TranzportControlProtocol::process (uint8_t* buf)
1198 // 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]);
1200 uint32_t this_button_mask;
1201 uint32_t button_changes;
1203 _device_status = buf[1];
1205 this_button_mask = 0;
1206 this_button_mask |= buf[2] << 24;
1207 this_button_mask |= buf[3] << 16;
1208 this_button_mask |= buf[4] << 8;
1209 this_button_mask |= buf[5];
1210 _datawheel = buf[6];
1212 button_changes = (this_button_mask ^ buttonmask);
1213 buttonmask = this_button_mask;
1219 // SHIFT + STOP + PLAY for bling mode?
1220 // if (button_changes & ButtonPlay & ButtonStop) {
1221 // bling_mode_toggle();
1222 // } or something like that
1224 TRANZPORT_BUTTON_HANDLER(button_event_battery,ButtonBattery);
1225 TRANZPORT_BUTTON_HANDLER(button_event_backlight,ButtonBacklight);
1226 TRANZPORT_BUTTON_HANDLER(button_event_trackleft,ButtonTrackLeft);
1227 TRANZPORT_BUTTON_HANDLER(button_event_trackright,ButtonTrackRight);
1228 TRANZPORT_BUTTON_HANDLER(button_event_trackrec,ButtonTrackRec);
1229 TRANZPORT_BUTTON_HANDLER(button_event_trackmute,ButtonTrackMute);
1230 TRANZPORT_BUTTON_HANDLER(button_event_tracksolo,ButtonTrackSolo);
1231 TRANZPORT_BUTTON_HANDLER(button_event_undo,ButtonUndo);
1232 TRANZPORT_BUTTON_HANDLER(button_event_in,ButtonIn);
1233 TRANZPORT_BUTTON_HANDLER(button_event_out,ButtonOut);
1234 TRANZPORT_BUTTON_HANDLER(button_event_punch,ButtonPunch);
1235 TRANZPORT_BUTTON_HANDLER(button_event_loop,ButtonLoop);
1236 TRANZPORT_BUTTON_HANDLER(button_event_prev,ButtonPrev);
1237 TRANZPORT_BUTTON_HANDLER(button_event_add,ButtonAdd);
1238 TRANZPORT_BUTTON_HANDLER(button_event_next,ButtonNext);
1239 TRANZPORT_BUTTON_HANDLER(button_event_rewind,ButtonRewind);
1240 TRANZPORT_BUTTON_HANDLER(button_event_fastforward,ButtonFastForward);
1241 TRANZPORT_BUTTON_HANDLER(button_event_stop,ButtonStop);
1242 TRANZPORT_BUTTON_HANDLER(button_event_play,ButtonPlay);
1243 TRANZPORT_BUTTON_HANDLER(button_event_record,ButtonRecord);
1248 TranzportControlProtocol::show_current_track ()
1253 if (route_table[0] == 0) {
1254 print (0, 0, "----------");
1255 last_track_gain = FLT_MAX;
1258 v = (char *)route_get_name (0).substr (0, 10).c_str();
1259 if((len = strlen(v)) > 0) {
1260 strncpy(pad,(char *)v,len);
1267 TranzportControlProtocol::button_event_battery_press (bool shifted)
1272 TranzportControlProtocol::button_event_battery_release (bool shifted)
1277 TranzportControlProtocol::button_event_backlight_press (bool shifted)
1280 printf("backlight pressed\n");
1285 TranzportControlProtocol::button_event_backlight_release (bool shifted)
1288 printf("backlight released\n\n");
1293 last_where += 1; /* force time redisplay */
1294 last_track_gain = FLT_MAX;
1295 normal_update(); // redraw_screen();
1300 TranzportControlProtocol::button_event_trackleft_press (bool shifted)
1306 TranzportControlProtocol::button_event_trackleft_release (bool shifted)
1311 TranzportControlProtocol::button_event_trackright_press (bool shifted)
1317 TranzportControlProtocol::button_event_trackright_release (bool shifted)
1322 TranzportControlProtocol::button_event_trackrec_press (bool shifted)
1325 toggle_all_rec_enables ();
1327 route_set_rec_enable (0, !route_get_rec_enable (0));
1332 TranzportControlProtocol::button_event_trackrec_release (bool shifted)
1337 TranzportControlProtocol::button_event_trackmute_press (bool shifted)
1340 // Mute ALL? Something useful when a phone call comes in. Mute master?
1342 route_set_muted (0, !route_get_muted (0));
1347 TranzportControlProtocol::button_event_trackmute_release (bool shifted)
1352 TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
1355 printf("solo pressed\n");
1357 if (display_mode == DisplayBigMeter) {
1358 light_off (LightAnysolo);
1363 session->set_all_solo (!session->soloing());
1365 route_set_soloed (0, !route_get_soloed (0));
1370 TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
1373 printf("solo released\n");
1378 TranzportControlProtocol::button_event_undo_press (bool shifted)
1381 redo (); // someday flash the screen with what was redone
1383 undo (); // someday flash the screen with what was undone
1388 TranzportControlProtocol::button_event_undo_release (bool shifted)
1393 TranzportControlProtocol::button_event_in_press (bool shifted)
1398 ControlProtocol::ZoomIn (); /* EMIT SIGNAL */
1403 TranzportControlProtocol::button_event_in_release (bool shifted)
1408 TranzportControlProtocol::button_event_out_press (bool shifted)
1411 toggle_punch_out ();
1413 ControlProtocol::ZoomOut (); /* EMIT SIGNAL */
1418 TranzportControlProtocol::button_event_out_release (bool shifted)
1423 TranzportControlProtocol::button_event_punch_press (bool shifted)
1428 TranzportControlProtocol::button_event_punch_release (bool shifted)
1433 TranzportControlProtocol::button_event_loop_press (bool shifted)
1436 next_wheel_shift_mode ();
1443 TranzportControlProtocol::button_event_loop_release (bool shifted)
1448 TranzportControlProtocol::button_event_prev_press (bool shifted)
1451 ControlProtocol::ZoomToSession (); /* EMIT SIGNAL */
1458 TranzportControlProtocol::button_event_prev_release (bool shifted)
1463 TranzportControlProtocol::button_event_add_press (bool shifted)
1469 TranzportControlProtocol::button_event_add_release (bool shifted)
1474 TranzportControlProtocol::button_event_next_press (bool shifted)
1484 TranzportControlProtocol::button_event_next_release (bool shifted)
1489 TranzportControlProtocol::button_event_rewind_press (bool shifted)
1499 TranzportControlProtocol::button_event_rewind_release (bool shifted)
1504 TranzportControlProtocol::button_event_fastforward_press (bool shifted)
1514 TranzportControlProtocol::button_event_fastforward_release (bool shifted)
1519 TranzportControlProtocol::button_event_stop_press (bool shifted)
1522 next_display_mode ();
1529 TranzportControlProtocol::button_event_stop_release (bool shifted)
1534 TranzportControlProtocol::button_event_play_press (bool shifted)
1537 set_transport_speed (1.0f);
1544 TranzportControlProtocol::button_event_play_release (bool shifted)
1549 TranzportControlProtocol::button_event_record_press (bool shifted)
1554 rec_enable_toggle ();
1559 TranzportControlProtocol::button_event_record_release (bool shifted)
1563 void button_event_mute (bool pressed, bool shifted)
1565 //static int was_pressed = 0;
1570 TranzportControlProtocol::datawheel ()
1572 if ((buttonmask & ButtonTrackRight) || (buttonmask & ButtonTrackLeft)) {
1574 /* track scrolling */
1576 if (_datawheel < WheelDirectionThreshold) {
1582 timerclear (&last_wheel_motion);
1584 } else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
1586 if (_datawheel < WheelDirectionThreshold) {
1592 timerclear (&last_wheel_motion);
1594 } else if (buttonmask & ButtonShift) {
1596 /* parameter control */
1598 if (route_table[0]) {
1599 switch (wheel_shift_mode) {
1600 case WheelShiftGain:
1601 if (_datawheel < WheelDirectionThreshold) {
1608 if (_datawheel < WheelDirectionThreshold) {
1615 case WheelShiftMarker:
1618 case WheelShiftMaster:
1624 timerclear (&last_wheel_motion);
1628 switch (wheel_mode) {
1645 TranzportControlProtocol::scroll ()
1648 if (_datawheel < WheelDirectionThreshold) {
1653 switch(wheel_increment) {
1654 case WheelIncrScreen: ScrollTimeline (0.2*m); break;
1655 default: break; // other modes unimplemented as yet
1660 TranzportControlProtocol::scrub ()
1664 struct timeval delta;
1667 gettimeofday (&now, 0);
1669 if (_datawheel < WheelDirectionThreshold) {
1675 if (dir != last_wheel_dir) {
1676 /* changed direction, start over */
1679 if (timerisset (&last_wheel_motion)) {
1681 timersub (&now, &last_wheel_motion, &delta);
1683 /* 10 clicks per second => speed == 1.0 */
1685 speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
1689 /* start at half-speed and see where we go from there */
1695 last_wheel_motion = now;
1696 last_wheel_dir = dir;
1698 set_transport_speed (speed * dir);
1702 TranzportControlProtocol::config ()
1708 TranzportControlProtocol::shuttle ()
1710 if (_datawheel < WheelDirectionThreshold) {
1711 if (session->transport_speed() < 0) {
1712 session->request_transport_speed (1.0);
1714 session->request_transport_speed (session->transport_speed() + 0.1);
1717 if (session->transport_speed() > 0) {
1718 session->request_transport_speed (-1.0);
1720 session->request_transport_speed (session->transport_speed() - 0.1);
1726 TranzportControlProtocol::step_gain_up ()
1728 if (buttonmask & ButtonStop) {
1729 gain_fraction += 0.001;
1731 gain_fraction += 0.01;
1734 if (gain_fraction > 2.0) {
1735 gain_fraction = 2.0;
1738 route_set_gain (0, slider_position_to_gain (gain_fraction));
1742 TranzportControlProtocol::step_gain_down ()
1744 if (buttonmask & ButtonStop) {
1745 gain_fraction -= 0.001;
1747 gain_fraction -= 0.01;
1750 if (gain_fraction < 0.0) {
1751 gain_fraction = 0.0;
1754 route_set_gain (0, slider_position_to_gain (gain_fraction));
1758 TranzportControlProtocol::step_pan_right ()
1763 TranzportControlProtocol::step_pan_left ()
1768 TranzportControlProtocol::next_wheel_shift_mode ()
1770 switch (wheel_shift_mode) {
1771 case WheelShiftGain:
1772 wheel_shift_mode = WheelShiftPan;
1775 wheel_shift_mode = WheelShiftMaster;
1777 case WheelShiftMaster:
1778 wheel_shift_mode = WheelShiftGain;
1780 case WheelShiftMarker: // Not done yet, disabled
1781 wheel_shift_mode = WheelShiftGain;
1789 TranzportControlProtocol::next_wheel_mode ()
1791 switch (wheel_mode) {
1793 wheel_mode = WheelScrub;
1796 wheel_mode = WheelShuttle;
1799 wheel_mode = WheelTimeline;
1806 TranzportControlProtocol::next_track ()
1808 ControlProtocol::next_track (current_track_id);
1809 gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1813 TranzportControlProtocol::prev_track ()
1815 ControlProtocol::prev_track (current_track_id);
1816 gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
1820 TranzportControlProtocol::show_wheel_mode ()
1824 switch (wheel_mode) {
1836 switch (wheel_shift_mode) {
1837 case WheelShiftGain:
1845 case WheelShiftMaster:
1849 case WheelShiftMarker:
1854 print (1, 0, text.c_str());
1857 // Was going to keep state around saying to retry or not
1858 // haven't got to it yet, still not sure it's a good idea
1861 TranzportControlProtocol::print (int row, int col, const char *text) {
1862 print_noretry(row,col,text);
1866 TranzportControlProtocol::print_noretry (int row, int col, const char *text)
1869 uint32_t left = strlen (text);
1873 if (row < 0 || row > 1) {
1877 if (col < 0 || col > 19) {
1883 if (col >= 0 && col < 4) {
1886 } else if (col >= 4 && col < 8) {
1889 } else if (col >= 8 && col < 12) {
1892 } else if (col >= 12 && col < 16) {
1895 } else if (col >= 16 && col < 20) {
1902 int offset = col % 4;
1904 /* copy current cell contents into tmp */
1906 memcpy (tmp, &screen_pending[row][base_col], 4);
1908 /* overwrite with new text */
1910 uint32_t tocopy = min ((4U - offset), left);
1912 memcpy (tmp+offset, text, tocopy);
1914 /* copy it back to pending */
1916 memcpy (&screen_pending[row][base_col], tmp, 4);
1925 TranzportControlProtocol::get_state ()
1927 XMLNode* node = new XMLNode (X_("Protocol"));
1928 node->add_property (X_("name"), _name);
1933 TranzportControlProtocol::set_state (const XMLNode& node)
1939 TranzportControlProtocol::save (char *name)
1941 // Presently unimplemented
1946 TranzportControlProtocol::load (char *name)
1948 // Presently unimplemented