diff options
Diffstat (limited to 'libs/ardour/transport_fsm.cc')
-rw-r--r-- | libs/ardour/transport_fsm.cc | 114 |
1 files changed, 107 insertions, 7 deletions
diff --git a/libs/ardour/transport_fsm.cc b/libs/ardour/transport_fsm.cc index f6b17ca071..6b8ee1fd61 100644 --- a/libs/ardour/transport_fsm.cc +++ b/libs/ardour/transport_fsm.cc @@ -55,6 +55,7 @@ TransportFSM::Event::operator delete (void *ptr, size_t /*size*/) TransportFSM::TransportFSM (TransportAPI& tapi) : _last_locate (Locate, 0, MustRoll, false, false, false) /* all but first argument don't matter */ + , last_speed_request (SetSpeed, 0, false, false, false) /* ditto */ , api (&tapi) , processing (0) { @@ -66,6 +67,7 @@ TransportFSM::init () { _motion_state = Stopped; _butler_state = NotWaitingForButler; + _direction_state = Forwards; _last_locate.target = max_samplepos; } @@ -179,7 +181,7 @@ std::string TransportFSM::current_state () const { std::stringstream s; - s << enum_2_string (_motion_state) << '/' << enum_2_string (_butler_state); + s << enum_2_string (_motion_state) << '/' << enum_2_string (_butler_state) << '/' << enum_2_string (_direction_state); return s.str(); } @@ -200,6 +202,20 @@ TransportFSM::process_event (Event& ev, bool already_deferred, bool& deferred) switch (ev.type) { + case SetSpeed: + switch (_motion_state) { + case Stopped: + case Rolling: + set_speed (ev); + break; + default: + if (!already_deferred) { + defer (ev); + deferred = true; + } + } + break; + case StartTransport: switch (_motion_state) { case Stopped: @@ -298,12 +314,33 @@ TransportFSM::process_event (Event& ev, bool already_deferred, bool& deferred) case LocateDone: switch (_motion_state) { case WaitingForLocate: - if (should_not_roll_after_locate()) { - transition (Stopped); - /* already stopped, nothing to do */ - } else { + + if (_reversing) { + + _reversing = false; transition (Rolling); - roll_after_locate (); + + if (most_recently_requested_speed > 0) { + transition (Forwards); + } else { + transition (Forwards); + } + + api->set_transport_speed (last_speed_request.speed, last_speed_request.abort_capture, last_speed_request.clear_state, last_speed_request.as_default); + + if (most_recently_requested_speed != 0.0) { + roll_after_locate (); + } + + } else { + if (should_not_roll_after_locate()) { + transition (Stopped); + /* already stopped, nothing to do */ + } else { + transition (Rolling); + roll_after_locate (); + } + break; } break; default: @@ -375,7 +412,7 @@ TransportFSM::stop_playback (Event const & s) _last_locate.target = max_samplepos; current_roll_after_locate_status = boost::none; - api->stop_transport (s.abort, s.clear_state); + api->stop_transport (s.abort_capture, s.clear_state); } void @@ -536,6 +573,14 @@ TransportFSM::transition (ButlerState bs) } void +TransportFSM::transition (DirectionState ds) +{ + const DirectionState old = _direction_state; + _direction_state = ds; + DEBUG_TRACE (DEBUG::TFSMState, string_compose ("Leave %1, enter %2\n", enum_2_string (old), current_state())); +} + +void TransportFSM::enqueue (Event* ev) { DEBUG_TRACE (DEBUG::TFSMState, string_compose ("queue tfsm event %1\n", enum_2_string (ev->type))); @@ -544,3 +589,58 @@ TransportFSM::enqueue (Event* ev) process_events (); } } + +void +TransportFSM::set_speed (Event const & ev) +{ + if ((rolling() && ev.speed * most_recently_requested_speed < 0.0) || + (stopped() && ev.speed < 0.0) || + (rolling() && most_recently_requested_speed < 0.0 && ev.speed == 0.0)) { + + /* Transport was rolling, and new speed has opposite sign to + * the last requested speed. + * + * OR + * + * Transport was stopped, and new speed is negative. + * + * OR + * + * new speed is zero, last requested speed was negative + * + * SO ... we need to reverse. + * + * The plan: stop normally (with a declick, and schedule a + * locate to our current position, with "force" set to true, + * and roll right after it is complete. + */ + + most_recently_requested_speed = ev.speed; + last_speed_request = ev; + _reversing = true; + + DEBUG_TRACE (DEBUG::TFSMState, string_compose ("reverse, target speed %1 MRRS %2 state %3\n", ev.speed, most_recently_requested_speed, current_state())); + + Event lev (Locate, api->position(), MustRoll, true, false, true); + + transition (DeclickToLocate); + start_declick_for_locate (lev); + + } else { + + most_recently_requested_speed = ev.speed; + api->set_transport_speed (ev.speed, ev.abort_capture, ev.clear_state, ev.as_default); + + } + +} + +bool +TransportFSM::will_roll_fowards () const +{ + if (_reversing) { + return most_recently_requested_speed >= 0; /* note: future speed of zero is equivalent to Forwards */ + } + return (_direction_state == Forwards); +} + |