summaryrefslogtreecommitdiff
path: root/libs/ardour/transport_fsm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/transport_fsm.cc')
-rw-r--r--libs/ardour/transport_fsm.cc114
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);
+}
+