#include <algorithm>
#include <unistd.h>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
#include "pbd/error.h"
#include "pbd/enumwriter.h"
using namespace PBD;
using namespace std;
+/* state machine */
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace TransportState
+{
+ /* events */
+ struct play {};
+ struct stop {};
+
+ /* front-end: define the FSM structure */
+ struct TransportFSM : public msm::front::state_machine_def<TransportFSM>
+ {
+
+ /* FSM states */
+ struct Stopped : public msm::front::state<>
+ {
+ template <class Event,class FSM> void
+ on_entry (Event const&, FSM&)
+ {
+ std::cout << "entering: Stopped" << std::endl;
+ }
+ template <class Event,class FSM> void
+ on_exit (Event const&, FSM&)
+ {
+ std::cout << "leaving: Stopped" << std::endl;
+ }
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM> void
+ on_entry (Event const&, FSM&)
+ {
+ std::cout << "entering: Playing" << std::endl;
+ }
+
+ template <class Event,class FSM> void
+ on_exit (Event const&, FSM&)
+ {
+ std::cout << "leaving: Playing" << std::endl;
+ }
+ };
+
+ /* the initial state */
+ typedef Stopped initial_state;
+
+ /* transition actions */
+ void start_playback (play const&)
+ {
+ std::cout << "player::start_playback\n";
+ }
+
+ void stop_playback (stop const&)
+ {
+ std::cout << "player::stop_playback\n";
+ }
+
+ typedef TransportFSM _t; // makes transition table cleaner
+
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &_t::start_playback >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &_t::stop_playback >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ };
+
+ typedef msm::back::state_machine<TransportFSM> transport_fsm;
+
+ void test()
+ {
+ transport_fsm t;
+ t.start ();
+ t.process_event (play());
+ t.process_event (stop());
+ t.stop();
+ }
+
+};
+
/** Called by the audio engine when there is work to be done with JACK.
* @param nframes Number of samples to process.
*/
if (processing_blocked()) {
_silent = true;
- cerr << "%%%%%%%%%%%%%% session process blocked\n";
return;
}
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));
end_sample = _transport_sample + samples_moved;
this_nframes = nframes; /* real (jack) time relative */
samples_moved = (samplecnt_t) floor (_transport_speed * nframes); /* transport relative */
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("sub-loop plan to move transport by %1 (%2 @ %3)\n", samples_moved, nframes, _transport_speed));
/* running an event, position transport precisely to its time */
if (this_event && this_event->action_sample <= end_sample && this_event->action_sample >= _transport_sample) {
/* this isn't quite right for reverse play */
samples_moved = (samplecnt_t) (this_event->action_sample - _transport_sample);
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("sub-loop2 plan to move transport by %1 (%2 @ %3)\n", samples_moved, nframes, _transport_speed));
this_nframes = abs (floor(samples_moved / _transport_speed));
}
if (samples_moved < 0) {
decrement_transport_position (-samples_moved);
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("DEcrement transport by %1 to %2\n", samples_moved, _transport_sample));
} else if (samples_moved) {
increment_transport_position (samples_moved);
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("INcrement transport by %1 to %2\n", samples_moved, _transport_sample));
+ } else {
+ DEBUG_TRACE (DEBUG::Transport, "no transport motion\n");
}
maybe_stop (stop_limit);
return;
} else {
samples_moved = (samplecnt_t) nframes * _transport_speed;
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("no-events, plan to move transport by %1 (%2 @ %3)\n", samples_moved, nframes, _transport_speed));
}
if (!_exporting && !timecode_transmission_suspended()) {
if (samples_moved < 0) {
decrement_transport_position (-samples_moved);
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("DEcrement transport by %1 to %2\n", samples_moved, _transport_sample));
} else if (samples_moved) {
increment_transport_position (samples_moved);
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("INcrement transport by %1 to %2\n", samples_moved, _transport_sample));
+ } else {
+ DEBUG_TRACE (DEBUG::Transport, "no transport motion\n");
}
maybe_stop (stop_limit);
break;
case SessionEvent::SetTransportMaster:
- cerr << "Process TMM current request\n";
TransportMasterManager::instance().set_current (ev->transport_master);
break;
switch (transport_master_tracking_state) {
case Stopped:
- if (master->requires_seekahead()) {
- master_wait_end = slave_transport_sample + master->seekahead_distance ();
- DEBUG_TRACE (DEBUG::Slave, string_compose ("slave stopped, but running, requires seekahead to %1\n", master_wait_end));
- /* we can call locate() here because we are in process context */
- if (micro_locate (master_wait_end - _transport_sample) != 0) {
- locate (master_wait_end, false, false);
- }
- transport_master_tracking_state = Waiting;
-
- } else {
-
- DEBUG_TRACE (DEBUG::Slave, string_compose ("slave stopped -> running at %1\n", slave_transport_sample));
-
- if (slave_transport_sample != _transport_sample) {
- DEBUG_TRACE (DEBUG::Slave, string_compose ("require locate to run. eng: %1 -> sl: %2\n", _transport_sample, slave_transport_sample));
- if (micro_locate (slave_transport_sample - _transport_sample) != 0) {
- locate (slave_transport_sample, false, false);
- }
- }
- transport_master_tracking_state = Running;
+ master_wait_end = slave_transport_sample + worst_latency_preroll() + master->seekahead_distance ();
+ DEBUG_TRACE (DEBUG::Slave, string_compose ("slave stopped, but running, requires seekahead to %1, now WAITING\n", master_wait_end));
+ /* we can call locate() here because we are in process context */
+ if (micro_locate (master_wait_end - _transport_sample) != 0) {
+ locate (master_wait_end, false, false);
}
- break;
+ transport_master_tracking_state = Waiting;
case Waiting:
default:
if (transport_master_tracking_state == Waiting) {
- DEBUG_TRACE (DEBUG::Slave, string_compose ("slave waiting at %1\n", slave_transport_sample));
+ DEBUG_TRACE (DEBUG::Slave, string_compose ("master currently at %1, waiting to pass %2\n", slave_transport_sample, master_wait_end));
if (slave_transport_sample >= master_wait_end) {