From 55b8b44889d1d08fc6b64283670fd0953642ba64 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 23 Mar 2017 19:21:50 +0100 Subject: Improve playhead updates, reduce jitter for follow PH, stationary PH * resolve rounding mistakes * extrapolate and filter position using GUI timing * track engine's position --- gtk2_ardour/editor.cc | 107 +++++++++++++++++++++++++++++++++----------------- gtk2_ardour/editor.h | 4 +- 2 files changed, 74 insertions(+), 37 deletions(-) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 860a401839..22723fa3dc 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -343,7 +343,8 @@ Editor::Editor () , _full_canvas_height (0) , edit_controls_left_menu (0) , edit_controls_right_menu (0) - , last_update_frame (0) + , _last_update_time (0) + , _err_screen_engine (0) , cut_buffer_start (0) , cut_buffer_length (0) , button_bindings (0) @@ -4668,7 +4669,7 @@ Editor::visual_changer (const VisualChange& vc) } if (vc.pending & VisualChange::TimeOrigin) { - set_horizontal_position (vc.time_origin / samples_per_pixel); + set_horizontal_position (sample_to_pixel_unrounded (vc.time_origin)); } if (vc.pending & VisualChange::YOrigin) { @@ -5778,8 +5779,6 @@ Editor::super_rapid_screen_update () /* PLAYHEAD AND VIEWPORT */ - framepos_t const frame = _session->audible_frame(); - /* There are a few reasons why we might not update the playhead / viewport stuff: * * 1. we don't update things when there's a pending locate request, otherwise @@ -5789,46 +5788,82 @@ Editor::super_rapid_screen_update () * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere). * 3. if we're still at the same frame that we were last time, there's nothing to do. */ + if (_pending_locate_request || _session->transport_speed() == 0) { + _last_update_time = 0; + return; + } - if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) { + if (_dragging_playhead) { + _last_update_time = 0; + return; + } - last_update_frame = frame; + framepos_t frame = _session->audible_frame(); + const int64_t now = g_get_monotonic_time (); + double err = 0; - if (!_dragging_playhead) { - playhead_cursor->set_position (frame); - } + if (_last_update_time > 0) { + const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6; + framepos_t guess = playhead_cursor->current_frame () + rint (ds); + err = frame - guess; - if (!_stationary_playhead) { + guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update) + _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2 - if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) { - /* We only do this if we aren't already - handling a visual change (ie if - pending_visual_change.being_handled is - false) so that these requests don't stack - up there are too many of them to handle in - time. - */ - reset_x_origin_to_follow_playhead (); - } +#if 0 // DEBUG + printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n", + frame, guess, ds, + err, _err_screen_engine); +#endif - } else { + frame = guess; + } else { + _err_screen_engine = 0; + } - if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) { - framepos_t const frame = playhead_cursor->current_frame (); - double target = ((double)frame - (double)current_page_samples()/2.0); - if (target <= 0.0) { - target = 0.0; - } - // compare to EditorCursor::set_position() - double const old_pos = sample_to_pixel_unrounded (leftmost_frame); - double const new_pos = sample_to_pixel_unrounded (target); - if (rint (new_pos) != rint (old_pos)) { - reset_x_origin (pixel_to_sample (floor (new_pos))); - } - } + if (err > 8192) { + // in case of x-runs or freewheeling + _last_update_time = 0; + } else { + _last_update_time = now; + } - } + if (playhead_cursor->current_frame () == frame) { + return; + } + + playhead_cursor->set_position (frame); + + if (_session->requested_return_frame() >= 0) { + _last_update_time = 0; + return; + } + + if (!_follow_playhead || pending_visual_change.being_handled) { + /* We only do this if we aren't already + * handling a visual change (ie if + * pending_visual_change.being_handled is + * false) so that these requests don't stack + * up there are too many of them to handle in + * time. + */ + return; + } + if (!_stationary_playhead) { + reset_x_origin_to_follow_playhead (); + } else { + framepos_t const frame = playhead_cursor->current_frame (); + double target = ((double)frame - (double)current_page_samples() / 2.0); + if (target <= 0.0) { + target = 0.0; + } + // compare to EditorCursor::set_position() + double const old_pos = sample_to_pixel_unrounded (leftmost_frame); + double const new_pos = sample_to_pixel_unrounded (target); + if (rint (new_pos) != rint (old_pos)) { + reset_x_origin (pixel_to_sample (new_pos)); + } } } @@ -5850,7 +5885,7 @@ Editor::session_going_away () clicked_routeview = 0; entered_regionview = 0; entered_track = 0; - last_update_frame = 0; + _last_update_time = 0; _drags->abort (); playhead_cursor->hide (); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 917dacb53e..7f6d7ab2af 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1160,11 +1160,13 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD TrackViewList get_tracks_for_range_action () const; sigc::connection super_rapid_screen_update_connection; - framepos_t last_update_frame; void center_screen_internal (framepos_t, float); void super_rapid_screen_update (); + int64_t _last_update_time; + double _err_screen_engine; + void session_going_away (); framepos_t cut_buffer_start; -- cgit v1.2.3