diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 04b9ede947..5cae99e369 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -719,7 +719,7 @@ Editor::Editor (AudioEngine& eng) ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session)); ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false)); ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true)); - + ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll)); constructed = true; instant_save (); } @@ -917,7 +917,6 @@ Editor::reposition_x_origin (jack_nframes_t frame) horizontal_adjustment.set_upper (frame_to_pixel (frame + (current_page_frames()))); } horizontal_adjustment.set_value (frame/frames_per_unit); - XOriginChanged (); /* EMIT_SIGNAL */ } } @@ -950,11 +949,58 @@ Editor::zoom_adjustment_changed () temporal_zoom (fpu); } +void +Editor::control_scroll (float fraction) +{ + ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction)); + + if (!session) { + return; + } + + double step = fraction * current_page_frames(); + jack_nframes_t target; + + if ((fraction < 0.0f) && (session->transport_frame() < (jack_nframes_t) fabs(step))) { + target = 0; + } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) { + target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen + } else { + target = (session->transport_frame() + (fraction * current_page_frames())); + } + + /* move visuals, we'll catch up with it later */ + + playhead_cursor->set_position (target); + + if (target > (current_page_frames() / 2)) { + /* try to center PH in window */ + reposition_x_origin (target - (current_page_frames()/2)); + } else { + reposition_x_origin (0); + } + + /* cancel the existing */ + + control_scroll_connection.disconnect (); + + /* add the next one */ + + control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50); +} + +bool +Editor::deferred_control_scroll (jack_nframes_t target) +{ + session->request_locate (target); + return false; +} + void Editor::canvas_horizontally_scrolled () { leftmost_frame = (jack_nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit); - + update_fixed_rulers (); if (!edit_hscroll_dragging) { @@ -968,7 +1014,7 @@ void Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu) { if (!repos_zoom_queued) { - Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu)); + Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu)); repos_zoom_queued = true; } } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 92b21c0757..1b0a1a4811 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -150,7 +150,6 @@ class Editor : public PublicEditor void connect_to_image_compositor() ; void scroll_timeaxis_to_imageframe_item(const TimeAxisViewItem* item) ; TimeAxisView* get_named_time_axis(const string & name) ; - /* */ void consider_auditioning (ARDOUR::Region&); void hide_a_region (ARDOUR::Region&); @@ -322,7 +321,7 @@ class Editor : public PublicEditor void ensure_float (Gtk::Window&); void show_window (); - + void scroll_tracks_down_line (); void scroll_tracks_up_line (); @@ -715,6 +714,10 @@ class Editor : public PublicEditor Gtk::VBox edit_controls_vbox; Gtk::HBox edit_controls_hbox; + void control_scroll (float); + bool deferred_control_scroll (jack_nframes_t); + sigc::connection control_scroll_connection; + void tie_vertical_scrolling (); void canvas_horizontally_scrolled (); void reposition_and_zoom (jack_nframes_t sample, double fpu); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 03ea5ac456..e5e16381ab 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -60,6 +60,7 @@ #include "sfdb_ui.h" #include "editing.h" #include "gtk-custom-hruler.h" +#include "gui_thread.h" #include "i18n.h" @@ -1021,6 +1022,8 @@ Editor::scroll_tracks_up_line () void Editor::temporal_zoom_step (bool coarser) { + ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser)); + double nfpu; nfpu = frames_per_unit; @@ -1122,6 +1125,8 @@ Editor::temporal_zoom_selection () void Editor::temporal_zoom_session () { + ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session)); + if (session) { temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session"); } diff --git a/libs/ardour/ardour/control_protocol.h b/libs/ardour/ardour/control_protocol.h index 592755b2d7..c2ab8736b7 100644 --- a/libs/ardour/ardour/control_protocol.h +++ b/libs/ardour/ardour/control_protocol.h @@ -46,6 +46,7 @@ class ControlProtocol : public sigc::trackable { static sigc::signal ZoomIn; static sigc::signal ZoomOut; static sigc::signal Enter; + static sigc::signal ScrollTimeline; protected: diff --git a/libs/ardour/control_protocol.cc b/libs/ardour/control_protocol.cc index 18c0b8cab7..d2a84967d2 100644 --- a/libs/ardour/control_protocol.cc +++ b/libs/ardour/control_protocol.cc @@ -38,6 +38,7 @@ sigc::signal ControlProtocol::ZoomToSession; sigc::signal ControlProtocol::ZoomOut; sigc::signal ControlProtocol::ZoomIn; sigc::signal ControlProtocol::Enter; +sigc::signal ControlProtocol::ScrollTimeline; ControlProtocol::ControlProtocol (Session& s, string str) : session (s), diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.cc b/libs/surfaces/tranzport/tranzport_control_protocol.cc index d179f16bf4..eee60c43eb 100644 --- a/libs/surfaces/tranzport/tranzport_control_protocol.cc +++ b/libs/surfaces/tranzport/tranzport_control_protocol.cc @@ -30,7 +30,8 @@ TranzportControlProtocol::TranzportControlProtocol (Session& s) current_route = 0; current_track_id = 0; last_where = max_frames; - wheel_mode = WheelGain; + wheel_mode = WheelTimeline; + wheel_shift_mode = WheelShiftGain; timerclear (&last_wheel_motion); last_wheel_dir = 1; @@ -246,7 +247,11 @@ TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override) { int val; - val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout); + { + LockMonitor lm (write_lock, __LINE__, __FILE__); + val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout); + } + if (val < 0) return val; if (val != 8) @@ -258,8 +263,28 @@ TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override) void TranzportControlProtocol::lcd_clear () { - print (0, 0, " "); - print (1, 0, " "); + /* special case this for speed and atomicity */ + + uint8_t cmd[8]; + + cmd[0] = 0x00; + cmd[1] = 0x01; + cmd[3] = ' '; + cmd[4] = ' '; + cmd[5] = ' '; + cmd[6] = ' '; + cmd[7] = 0x00; + + { + LockMonitor lm (write_lock, __LINE__, __FILE__); + + for (uint8_t i = 0; i < 10; ++i) { + cmd[2] = i; + usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, 500); + } + + memset (current_screen, ' ', sizeof (current_screen)); + } } int @@ -573,7 +598,7 @@ void TranzportControlProtocol::track_gain_changed (void* ignored) { char buf[8]; - snprintf (buf, sizeof (buf), "%.1f", coefficient_to_dB (current_route->gain())); + snprintf (buf, sizeof (buf), "%.1fdB", coefficient_to_dB (current_route->gain())); print (0, 9, buf); } @@ -757,7 +782,7 @@ void TranzportControlProtocol::button_event_loop_press (bool shifted) { if (shifted) { - next_wheel_mode (); + next_wheel_shift_mode (); } } @@ -796,7 +821,11 @@ TranzportControlProtocol::button_event_add_release (bool shifted) void TranzportControlProtocol::button_event_next_press (bool shifted) { - next_marker (); + if (shifted) { + next_wheel_mode (); + } else { + next_marker (); + } } void @@ -913,15 +942,15 @@ TranzportControlProtocol::datawheel () /* parameter control */ if (current_route) { - switch (wheel_mode) { - case WheelGain: + switch (wheel_shift_mode) { + case WheelShiftGain: if (_datawheel < WheelDirectionThreshold) { step_gain_up (); } else { step_gain_down (); } break; - case WheelPan: + case WheelShiftPan: if (_datawheel < WheelDirectionThreshold) { step_pan_right (); } else { @@ -929,7 +958,7 @@ TranzportControlProtocol::datawheel () } break; - case WheelMaster: + case WheelShiftMaster: break; } } @@ -938,43 +967,81 @@ TranzportControlProtocol::datawheel () } else { - float speed; - struct timeval now; - struct timeval delta; - int dir; + switch (wheel_mode) { + case WheelTimeline: + scroll (); + break; + + case WheelScrub: + scrub (); + break; - gettimeofday (&now, 0); - - if (_datawheel < WheelDirectionThreshold) { - dir = 1; - } else { - dir = -1; + case WheelShuttle: + shuttle (); + break; } + } +} - if (dir != last_wheel_dir) { - /* changed direction, start over */ - speed = 1.0f; +void +TranzportControlProtocol::scroll () +{ + if (_datawheel < WheelDirectionThreshold) { + ScrollTimeline (0.2); + } else { + ScrollTimeline (-0.2); + } +} + +void +TranzportControlProtocol::scrub () +{ + float speed; + struct timeval now; + struct timeval delta; + int dir; + + gettimeofday (&now, 0); + + if (_datawheel < WheelDirectionThreshold) { + dir = 1; + } else { + dir = -1; + } + + if (dir != last_wheel_dir) { + /* changed direction, start over */ + speed = 1.0f; + } else { + if (timerisset (&last_wheel_motion)) { + + timersub (&now, &last_wheel_motion, &delta); + + /* 10 clicks per second => speed == 1.0 */ + + speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec); + } else { - if (timerisset (&last_wheel_motion)) { - - timersub (&now, &last_wheel_motion, &delta); - - /* 10 clicks per second => speed == 1.0 */ - - speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec); - - } else { - - /* start at half-speed and see where we go from there */ - - speed = 0.5f; - } + + /* start at half-speed and see where we go from there */ + + speed = 0.5f; } + } + + last_wheel_motion = now; + last_wheel_dir = dir; + + session.request_transport_speed (speed * dir); +} - last_wheel_motion = now; - last_wheel_dir = dir; - - session.request_transport_speed (speed * dir); +void +TranzportControlProtocol::shuttle () +{ + if (_datawheel < WheelDirectionThreshold) { + session.request_transport_speed (session.transport_speed() + 0.1); + } else { + session.request_transport_speed (session.transport_speed() - 0.1); } } @@ -1008,18 +1075,35 @@ TranzportControlProtocol::step_pan_left () { } +void +TranzportControlProtocol::next_wheel_shift_mode () +{ + switch (wheel_shift_mode) { + case WheelShiftGain: + wheel_shift_mode = WheelShiftPan; + break; + case WheelShiftPan: + wheel_shift_mode = WheelShiftMaster; + break; + case WheelShiftMaster: + wheel_shift_mode = WheelShiftGain; + } + + show_wheel_mode (); +} + void TranzportControlProtocol::next_wheel_mode () { switch (wheel_mode) { - case WheelGain: - wheel_mode = WheelPan; + case WheelTimeline: + wheel_mode = WheelScrub; break; - case WheelPan: - wheel_mode = WheelMaster; + case WheelScrub: + wheel_mode = WheelShuttle; break; - case WheelMaster: - wheel_mode = WheelGain; + case WheelShuttle: + wheel_mode = WheelTimeline; } show_wheel_mode (); @@ -1100,19 +1184,35 @@ TranzportControlProtocol::prev_track () void TranzportControlProtocol::show_wheel_mode () { + string text; + switch (wheel_mode) { - case WheelGain: - print (1, 0, _("Wh: gain")); + case WheelTimeline: + text = "Time"; break; - - case WheelPan: - print (1, 0, _("Wh: pan ")); + case WheelScrub: + text = "Scrb"; break; - - case WheelMaster: - print (1, 0, _("Wh: mstr")); + case WheelShuttle: + text = "Shtl"; break; } + + switch (wheel_shift_mode) { + case WheelShiftGain: + text += ":Gain"; + break; + + case WheelShiftPan: + text += ":Pan"; + break; + + case WheelShiftMaster: + text += ":Mstr"; + break; + } + + print (1, 0, text.c_str()); } void diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.h b/libs/surfaces/tranzport/tranzport_control_protocol.h index a655463bc1..c5aa5f90e0 100644 --- a/libs/surfaces/tranzport/tranzport_control_protocol.h +++ b/libs/surfaces/tranzport/tranzport_control_protocol.h @@ -4,7 +4,7 @@ #include #include - +#include #include #include #include @@ -66,12 +66,18 @@ class TranzportControlProtocol : public ControlProtocol { ButtonShift = 0x08000000 }; - enum WheelMode { - WheelGain, - WheelPan, - WheelMaster + enum WheelShiftMode { + WheelShiftGain, + WheelShiftPan, + WheelShiftMaster }; + enum WheelMode { + WheelTimeline, + WheelScrub, + WheelShuttle + }; + pthread_t thread; uint32_t buttonmask; uint32_t timeout; @@ -83,6 +89,7 @@ class TranzportControlProtocol : public ControlProtocol { char current_screen[2][20]; bool lights[7]; WheelMode wheel_mode; + WheelShiftMode wheel_shift_mode; struct timeval last_wheel_motion; int last_wheel_dir; @@ -95,6 +102,8 @@ class TranzportControlProtocol : public ControlProtocol { uint32_t last_frames; jack_nframes_t last_where; + PBD::Lock write_lock; + int open (); int read (uint32_t timeout_override = 0); int write (uint8_t* cmd, uint32_t timeout_override = 0); @@ -121,8 +130,12 @@ class TranzportControlProtocol : public ControlProtocol { void record_status_changed (); void datawheel (); + void scrub (); + void scroll (); + void shuttle (); void next_wheel_mode (); + void next_wheel_shift_mode (); void next_track (); void prev_track ();