diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 2d0b9728f4..b53470da6b 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1345,7 +1345,7 @@ protected: bool should_roll_after_locate () const; double speed() const { return _transport_speed; } samplepos_t position() const { return _transport_sample; } - void set_transport_speed (double speed, bool as_default); + void set_transport_speed (double speed, bool as_default, bool at_next_start); bool need_declick_before_locate () const; private: diff --git a/libs/ardour/ardour/transport_api.h b/libs/ardour/ardour/transport_api.h index 3d78b30e52..6fac31ac53 100644 --- a/libs/ardour/ardour/transport_api.h +++ b/libs/ardour/ardour/transport_api.h @@ -41,7 +41,7 @@ class LIBARDOUR_API TransportAPI virtual void schedule_butler_for_transport_work () = 0; virtual bool should_roll_after_locate () const = 0; virtual double speed() const = 0; - virtual void set_transport_speed (double speed, bool as_default) = 0; + virtual void set_transport_speed (double speed, bool as_default, bool at_next_start) = 0; virtual samplepos_t position() const = 0; virtual bool need_declick_before_locate () const = 0; }; diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 32cf5a942d..a9cf463db4 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -370,7 +370,7 @@ Session::post_locate () * @param speed New speed */ void -Session::set_transport_speed (double speed, bool as_default) +Session::set_transport_speed (double speed, bool as_default, bool at_next_start) { ENSURE_PROCESS_THREAD; DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %1 Set transport speed to %2 from %3 (es = %4) (def %5), as_default %6\n", _transport_sample, speed, _transport_speed, _engine_speed, _default_transport_speed, as_default)); diff --git a/libs/ardour/transport_fsm.cc b/libs/ardour/transport_fsm.cc index e807035c7e..9486452624 100644 --- a/libs/ardour/transport_fsm.cc +++ b/libs/ardour/transport_fsm.cc @@ -638,36 +638,57 @@ TransportFSM::enqueue (Event* ev) void TransportFSM::set_speed (Event const & ev) { - bool initial_reverse = false; - assert (ev.speed != 0.0); - DEBUG_TRACE (DEBUG::TFSMState, string_compose ("%1, target speed %2 MRRS %3 state %4\n", (ev.speed == 0.0 ? "stopping" : "continue"), ev.speed, most_recently_requested_speed, current_state())); - api->set_transport_speed (ev.speed, ev.as_default); + bool initial_reverse = false; + bool must_reverse = false; - const double mrrs = most_recently_requested_speed; + DEBUG_TRACE (DEBUG::TFSMState, string_compose ("::set_speed(): target speed %1 MRRS %2 state %3\n", ev.speed, most_recently_requested_speed, current_state())); - /* corner case: first call to ::set_speed() has a negative - * speed - */ + /* This "must_roll" value is a bit complicated to explain. If we were moving at anything other than normal speed+direction, + and then stop, and reset-default-speed-on-stop is enabled, Session::stop_transport() will queue a SetSpeed + request to restore the default speed to 1.0. However, because of the stop in progress, the SetSpeed event + will be deferred during the stop. Eventually, we will handle it, and call this method. If we need to reverse + direction, the locate will end up using compute_should_roll(), with rolling state already set to DeclickToLocate. + + If we pass in RollIfAppropriate as the after-locate roll disposition, the logic there will conclude that we should roll. + This logic is correct in cases where we do a normal locate, but not for a locate-for-reverse when stopping. + + So, instead of using RollIfAppropriate, determine here is our after-locate state should be rolling or stopped, and pass + MustRoll or MustStop to the locate request. This will get compute_should_roll() to do the right thing, and once the locate + is complete, we will be in the correct state. + */ + + + const bool must_roll = rolling(); if (most_recently_requested_speed == std::numeric_limits::max()) { /* have never rolled yet */ initial_reverse = true; } + if (ev.speed * most_recently_requested_speed < 0.0 || initial_reverse) { + must_reverse = true; + } + + api->set_transport_speed (ev.speed, ev.as_default, !rolling() || must_reverse); + + /* corner case: first call to ::set_speed() has a negative + * speed + */ + most_recently_requested_speed = ev.speed; - if (ev.speed * mrrs < 0.0 || initial_reverse) { + if (must_reverse) { /* direction change */ - DEBUG_TRACE (DEBUG::TFSMState, string_compose ("switch-directions, target speed %1 MRRS %2 state %3 IR %4\n", ev.speed, mrrs, current_state(), initial_reverse)); + DEBUG_TRACE (DEBUG::TFSMState, string_compose ("switch-directions, target speed %1 state %2 IR %3\n", ev.speed, current_state(), initial_reverse)); last_speed_request = ev; transition (Reversing); - Event lev (Locate, api->position(), RollIfAppropriate, false, false, true); + Event lev (Locate, api->position(), must_roll ? MustRoll : MustStop, false, false, true); transition (DeclickToLocate); start_declick_for_locate (lev);