change transport API, session API, transportFSM API to move reverse management and motion state (partially) into TFSM
This commit is contained in:
parent
efd6a856f8
commit
4b10beec08
|
@ -771,7 +771,8 @@ public:
|
|||
bool transport_stopped() const;
|
||||
bool transport_stopped_or_stopping() const;
|
||||
bool transport_rolling() const;
|
||||
|
||||
bool transport_will_roll_forwards() const;
|
||||
|
||||
bool silent () { return _silent; }
|
||||
|
||||
TempoMap& tempo_map() { return *_tempo_map; }
|
||||
|
@ -1254,6 +1255,8 @@ protected:
|
|||
void schedule_butler_for_transport_work ();
|
||||
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 abort, bool clear_state, bool as_default);
|
||||
|
||||
private:
|
||||
int create (const std::string& mix_template, BusProfile const *);
|
||||
|
@ -1692,7 +1695,6 @@ private:
|
|||
int micro_locate (samplecnt_t distance);
|
||||
|
||||
void force_locate (samplepos_t sample, LocateTransportDisposition);
|
||||
void set_transport_speed (double speed, bool abort = false, bool clear_state = false, bool as_default = false);
|
||||
void realtime_stop (bool abort, bool clear_state);
|
||||
void realtime_locate (bool);
|
||||
void non_realtime_start_scrub ();
|
||||
|
|
|
@ -41,6 +41,8 @@ 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 abort_capture, bool clear_state, bool as_default) = 0;
|
||||
virtual samplepos_t position() const = 0;
|
||||
};
|
||||
|
||||
} /* end namespace ARDOUR */
|
||||
|
|
|
@ -39,13 +39,14 @@ struct TransportFSM
|
|||
StartTransport,
|
||||
StopTransport,
|
||||
Locate,
|
||||
LocateDone
|
||||
LocateDone,
|
||||
SetSpeed,
|
||||
};
|
||||
|
||||
struct Event : public boost::intrusive::list_base_hook<> {
|
||||
EventType type;
|
||||
/* for stop */
|
||||
bool abort;
|
||||
/* for stop and speed */
|
||||
bool abort_capture;
|
||||
bool clear_state;
|
||||
/* for locate */
|
||||
LocateTransportDisposition ltd;
|
||||
|
@ -53,10 +54,13 @@ struct TransportFSM
|
|||
samplepos_t target;
|
||||
bool for_loop_end;
|
||||
bool force;
|
||||
/* for SetSpeed */
|
||||
double speed;
|
||||
bool as_default;
|
||||
|
||||
Event (EventType t)
|
||||
: type (t)
|
||||
, abort (false)
|
||||
, abort_capture (false)
|
||||
, clear_state (false)
|
||||
, ltd (MustStop)
|
||||
, with_flush (false)
|
||||
|
@ -69,7 +73,7 @@ struct TransportFSM
|
|||
}
|
||||
Event (EventType t, bool ab, bool cl)
|
||||
: type (t)
|
||||
, abort (ab)
|
||||
, abort_capture (ab)
|
||||
, clear_state (cl)
|
||||
, ltd (MustStop)
|
||||
, with_flush (false)
|
||||
|
@ -81,7 +85,7 @@ struct TransportFSM
|
|||
}
|
||||
Event (EventType t, samplepos_t pos, LocateTransportDisposition l, bool fl, bool lp, bool f4c)
|
||||
: type (t)
|
||||
, abort (false)
|
||||
, abort_capture (false)
|
||||
, clear_state (false)
|
||||
, ltd (l)
|
||||
, with_flush (fl)
|
||||
|
@ -91,6 +95,15 @@ struct TransportFSM
|
|||
{
|
||||
assert (t == Locate);
|
||||
}
|
||||
Event (EventType t, double sp, bool ab, bool cs, bool ad)
|
||||
: type (t)
|
||||
, abort_capture (ab)
|
||||
, clear_state (cs)
|
||||
, speed (sp)
|
||||
, as_default (ad)
|
||||
{
|
||||
assert (t == SetSpeed);
|
||||
}
|
||||
|
||||
void* operator new (size_t);
|
||||
void operator delete (void *ptr, size_t /*size*/);
|
||||
|
@ -128,11 +141,18 @@ struct TransportFSM
|
|||
WaitingForButler
|
||||
};
|
||||
|
||||
enum DirectionState {
|
||||
Forwards,
|
||||
Backwards,
|
||||
Reversing,
|
||||
};
|
||||
|
||||
std::string current_state () const;
|
||||
|
||||
private:
|
||||
MotionState _motion_state;
|
||||
ButlerState _butler_state;
|
||||
DirectionState _direction_state;
|
||||
|
||||
void init();
|
||||
|
||||
|
@ -147,6 +167,7 @@ struct TransportFSM
|
|||
void start_locate_while_stopped (Event const &) const;
|
||||
void interrupt_locate (Event const &) const;
|
||||
void start_declick_for_locate (Event const &);
|
||||
void set_speed (Event const &);
|
||||
|
||||
/* guards */
|
||||
|
||||
|
@ -161,18 +182,23 @@ struct TransportFSM
|
|||
bool waiting_for_butler() const { return _butler_state == WaitingForButler; }
|
||||
bool declick_in_progress() const { return _motion_state == DeclickToLocate || _motion_state == DeclickToStop; }
|
||||
bool declicking_for_locate() const { return _motion_state == DeclickToLocate; }
|
||||
bool forwards() const { return _direction_state == Forwards; }
|
||||
bool backwards() const { return _direction_state == Backwards; }
|
||||
bool will_roll_fowards() const;
|
||||
|
||||
void enqueue (Event* ev);
|
||||
|
||||
private:
|
||||
|
||||
void transition (MotionState ms);
|
||||
void transition (ButlerState bs);
|
||||
void transition (MotionState);
|
||||
void transition (ButlerState);
|
||||
void transition (DirectionState);
|
||||
|
||||
void process_events ();
|
||||
bool process_event (Event&, bool was_deferred, bool& deferred);
|
||||
|
||||
Event _last_locate;
|
||||
Event last_speed_request;
|
||||
|
||||
TransportAPI* api;
|
||||
typedef boost::intrusive::list<Event> EventList;
|
||||
|
@ -180,6 +206,8 @@ struct TransportFSM
|
|||
EventList deferred_events;
|
||||
int processing;
|
||||
mutable boost::optional<bool> current_roll_after_locate_status;
|
||||
double most_recently_requested_speed;
|
||||
bool _reversing;
|
||||
|
||||
void defer (Event& ev);
|
||||
void bad_transition (Event const &);
|
||||
|
|
|
@ -155,10 +155,11 @@ setup_enum_writer ()
|
|||
TransportFSM::EventType _TransportFSM_EventType;
|
||||
TransportFSM::MotionState _TransportFSM_MotionState;
|
||||
TransportFSM::ButlerState _TransportFSM_ButlerState;
|
||||
TransportFSM::DirectionState _TransportFSM_DirectionState;
|
||||
LoopFadeChoice _LoopFadeChooice;
|
||||
TransportState _TransportState;
|
||||
LocateTransportDisposition _LocateTransportDisposition;
|
||||
|
||||
|
||||
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||
#define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e)
|
||||
|
@ -809,6 +810,7 @@ setup_enum_writer ()
|
|||
REGISTER_CLASS_ENUM (TransportFSM, StopTransport);
|
||||
REGISTER_CLASS_ENUM (TransportFSM, Locate);
|
||||
REGISTER_CLASS_ENUM (TransportFSM, LocateDone);
|
||||
REGISTER_CLASS_ENUM (TransportFSM, SetSpeed);
|
||||
REGISTER (_TransportFSM_EventType);
|
||||
|
||||
REGISTER_CLASS_ENUM (TransportFSM, Stopped);
|
||||
|
@ -818,11 +820,15 @@ setup_enum_writer ()
|
|||
REGISTER_CLASS_ENUM (TransportFSM, WaitingForLocate);
|
||||
REGISTER (_TransportFSM_MotionState);
|
||||
|
||||
|
||||
REGISTER_CLASS_ENUM (TransportFSM, NotWaitingForButler);
|
||||
REGISTER_CLASS_ENUM (TransportFSM, WaitingForButler);
|
||||
REGISTER (_TransportFSM_ButlerState);
|
||||
|
||||
REGISTER_CLASS_ENUM (TransportFSM, Forwards);
|
||||
REGISTER_CLASS_ENUM (TransportFSM, Backwards);
|
||||
REGISTER_CLASS_ENUM (TransportFSM, Reversing);
|
||||
REGISTER (_TransportFSM_DirectionState);
|
||||
|
||||
REGISTER_ENUM (NoLoopFade);
|
||||
REGISTER_ENUM (EndLoopFade);
|
||||
REGISTER_ENUM (BothLoopFade);
|
||||
|
|
|
@ -191,7 +191,6 @@ Session::Session (AudioEngine &eng,
|
|||
, _engine_speed (1.0)
|
||||
, _transport_speed (0)
|
||||
, _default_transport_speed (1.0)
|
||||
, _last_transport_speed (0)
|
||||
, _signalled_varispeed (0)
|
||||
, _target_transport_speed (0.0)
|
||||
, auto_play_legal (false)
|
||||
|
|
|
@ -253,7 +253,7 @@ Session::process_export_fw (pframes_t nframes)
|
|||
return;
|
||||
}
|
||||
|
||||
set_transport_speed (1.0, false);
|
||||
set_transport_speed (1.0, false, false, false);
|
||||
butler_transport_work ();
|
||||
g_atomic_int_set (&_butler->should_do_transport_work, 0);
|
||||
butler_completed_transport_work ();
|
||||
|
|
|
@ -61,6 +61,7 @@ using namespace std;
|
|||
|
||||
#define TFSM_EVENT(evtype) { _transport_fsm->enqueue (new TransportFSM::Event (evtype)); }
|
||||
#define TFSM_STOP(abort,clear) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::StopTransport,abort,clear)); }
|
||||
#define TFSM_SPEED(speed,abort,clear_state,as_default) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::SetSpeed,speed,abort,clear_state,as_default)); }
|
||||
#define TFSM_LOCATE(target,ltd,flush,loop,force) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::Locate,target,ltd,flush,loop,force)); }
|
||||
|
||||
|
||||
|
@ -480,7 +481,7 @@ Session::process_with_events (pframes_t nframes)
|
|||
assert (_transport_speed == 0 || _transport_speed == 1.0 || _transport_speed == -1.0);
|
||||
|
||||
samples_moved = (samplecnt_t) nframes * _transport_speed;
|
||||
// DEBUG_TRACE (DEBUG::Transport, string_compose ("plan to move transport by %1 (%2 @ %3)\n", samples_moved, nframes, _transport_speed));
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("plan to move transport by %1 (%2 @ %3)\n", samples_moved, nframes, _transport_speed));
|
||||
|
||||
end_sample = _transport_sample + samples_moved;
|
||||
|
||||
|
@ -641,10 +642,12 @@ Session::process_without_events (pframes_t nframes)
|
|||
assert (_transport_speed == 0 || _transport_speed == 1.0 || _transport_speed == -1.0);
|
||||
|
||||
if (_transport_speed == 0) {
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("transport not moving @ %1\n", _transport_sample));
|
||||
no_roll (nframes);
|
||||
return;
|
||||
} else {
|
||||
samples_moved = (samplecnt_t) nframes * _transport_speed;
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("plan to move transport by %1 (%2 @ %3)\n", samples_moved, nframes, _transport_speed));
|
||||
}
|
||||
|
||||
if (!_exporting && !timecode_transmission_suspended()) {
|
||||
|
@ -894,8 +897,8 @@ Session::process_event (SessionEvent* ev)
|
|||
break;
|
||||
|
||||
|
||||
case SessionEvent::SetTransportSpeed:
|
||||
set_transport_speed (ev->speed, ev->yes_or_no, ev->second_yes_or_no, ev->third_yes_or_no);
|
||||
case SessionEvent::SetTransportSpeed:
|
||||
TFSM_SPEED (ev->speed, ev->yes_or_no, ev->second_yes_or_no, ev->third_yes_or_no);
|
||||
break;
|
||||
|
||||
case SessionEvent::SetTransportMaster:
|
||||
|
|
|
@ -99,10 +99,9 @@ Session::realtime_stop (bool abort, bool clear_state)
|
|||
DEBUG_TRACE (DEBUG::Transport, string_compose ("realtime stop @ %1 speed = %2\n", _transport_sample, _transport_speed));
|
||||
PostTransportWork todo = PostTransportWork (0);
|
||||
|
||||
if (_last_transport_speed < 0.0f) {
|
||||
todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
|
||||
if (_transport_speed < 0.0f) {
|
||||
todo = (PostTransportWork (todo | PostTransportStop));
|
||||
_default_transport_speed = 1.0;
|
||||
DiskReader::inc_no_disk_output (); // for the buffer reversal
|
||||
} else {
|
||||
todo = PostTransportWork (todo | PostTransportStop);
|
||||
}
|
||||
|
@ -195,7 +194,7 @@ Session::locate (samplepos_t target_sample, bool with_roll, bool with_flush, boo
|
|||
*/
|
||||
|
||||
if (with_roll) {
|
||||
set_transport_speed (1.0, 0, false);
|
||||
set_transport_speed (1.0, false, false, false);
|
||||
}
|
||||
loop_changing = false;
|
||||
TFSM_EVENT (TransportFSM::LocateDone);
|
||||
|
@ -383,11 +382,17 @@ void
|
|||
Session::set_transport_speed (double speed, bool abort, bool clear_state, bool as_default)
|
||||
{
|
||||
ENSURE_PROCESS_THREAD;
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n",
|
||||
speed, abort, clear_state, _transport_speed, _transport_sample, as_default));
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1 from %4 (es = %7), abort = %2 clear_state = %3, as_default %6\n",
|
||||
speed, abort, clear_state, _transport_speed, _transport_sample, as_default, _engine_speed));
|
||||
|
||||
if ((_engine_speed != 1) && (_engine_speed == fabs (speed)) && (speed * _transport_speed) >= 0) {
|
||||
/* engine speed is not changing and no direction change, do nothing */
|
||||
DEBUG_TRACE (DEBUG::Transport, "no reason to change speed, do nothing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
|
||||
and user needs. We really need CD-style "skip" playback for ffwd and rewind.
|
||||
and user needs. XXX We really need CD-style "skip" playback for ffwd and rewind.
|
||||
*/
|
||||
|
||||
if (speed > 0) {
|
||||
|
@ -397,6 +402,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a
|
|||
}
|
||||
|
||||
double new_engine_speed = 1.0;
|
||||
|
||||
if (speed != 0) {
|
||||
new_engine_speed = fabs (speed);
|
||||
if (speed < 0) speed = -1;
|
||||
|
@ -510,26 +516,12 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a
|
|||
before the last stop, then we have to do extra work.
|
||||
*/
|
||||
|
||||
PostTransportWork todo = PostTransportWork (0);
|
||||
|
||||
if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0 && speed < 0.0)) {
|
||||
todo = PostTransportWork (todo | PostTransportReverse);
|
||||
DiskReader::inc_no_disk_output (); // for the buffer reversal
|
||||
_last_roll_or_reversal_location = _transport_sample;
|
||||
}
|
||||
|
||||
_last_transport_speed = _transport_speed;
|
||||
_transport_speed = speed;
|
||||
|
||||
if (as_default) {
|
||||
_default_transport_speed = speed;
|
||||
}
|
||||
|
||||
if (todo) {
|
||||
add_post_transport_work (todo);
|
||||
TFSM_EVENT (TransportFSM::ButlerRequired);
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
|
||||
|
||||
/* throttle signal emissions.
|
||||
|
@ -537,7 +529,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a
|
|||
* usually changes every cycle (tiny amounts due to DLL).
|
||||
* Emitting a signal every cycle is overkill and unwarranted.
|
||||
*
|
||||
* Using _last_transport_speed is not acceptable,
|
||||
* Using _transport_speed is not acceptable,
|
||||
* since it allows for large changes over a long period
|
||||
* of time. Hence we introduce a dedicated variable to keep track
|
||||
*
|
||||
|
@ -713,7 +705,7 @@ Session::butler_completed_transport_work ()
|
|||
|
||||
bool start_after_butler_done_msg = false;
|
||||
|
||||
if ((ptw & (PostTransportReverse|PostTransportRoll))) {
|
||||
if (ptw & PostTransportRoll) {
|
||||
start_after_butler_done_msg = true;
|
||||
}
|
||||
|
||||
|
@ -1188,29 +1180,6 @@ Session::butler_transport_work ()
|
|||
}
|
||||
}
|
||||
|
||||
if (ptw & PostTransportReverse) {
|
||||
|
||||
clear_clicks();
|
||||
|
||||
/* don't seek if locate will take care of that in non_realtime_stop() */
|
||||
|
||||
if (!(ptw & PostTransportLocate)) {
|
||||
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||
(*i)->non_realtime_locate (_transport_sample);
|
||||
|
||||
if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
|
||||
/* new request, stop seeking, and start again */
|
||||
g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
VCAList v = _vca_manager->vcas ();
|
||||
for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||
(*i)->non_realtime_locate (_transport_sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ptw & PostTransportLocate) {
|
||||
DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
|
||||
non_realtime_locate ();
|
||||
|
@ -2043,3 +2012,9 @@ Session::declick_in_progress () const
|
|||
{
|
||||
return _transport_fsm->declick_in_progress();
|
||||
}
|
||||
|
||||
bool
|
||||
Session::transport_will_roll_forwards () const
|
||||
{
|
||||
return _transport_fsm->will_roll_fowards ();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -535,6 +572,14 @@ TransportFSM::transition (ButlerState bs)
|
|||
DEBUG_TRACE (DEBUG::TFSMState, string_compose ("Leave %1, enter %2\n", enum_2_string (old), current_state()));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user