Amend 883ee9c2, setup required invisible processor
[ardour.git] / libs / ardour / session_process.cc
index bece787fd71b531bb4eb314fb615fb10959ddb0e..319634499b274f631b71b4777d47261bf6839afb 100644 (file)
@@ -22,6 +22,9 @@
 #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"
 
@@ -53,6 +56,90 @@ using namespace ARDOUR;
 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.
  */
@@ -66,7 +153,6 @@ Session::process (pframes_t nframes)
 
        if (processing_blocked()) {
                _silent = true;
-               cerr << "%%%%%%%%%%%%%% session process blocked\n";
                return;
        }
 
@@ -448,6 +534,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));
 
        end_sample = _transport_sample + samples_moved;
 
@@ -497,11 +584,13 @@ Session::process_with_events (pframes_t nframes)
 
                        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));
                        }
 
@@ -522,8 +611,12 @@ Session::process_with_events (pframes_t nframes)
 
                                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);
@@ -601,7 +694,8 @@ Session::process_without_events (pframes_t nframes)
                no_roll (nframes);
                return;
        } else {
-               samples_moved = (samplecnt_t) nframes;
+               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()) {
@@ -632,8 +726,12 @@ Session::process_without_events (pframes_t nframes)
 
        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);
@@ -730,6 +828,7 @@ Session::maybe_sync_start (pframes_t & nframes)
                _silent = true;
 
                if (Config->get_locate_while_waiting_for_sync()) {
+                       DEBUG_TRACE (DEBUG::Transport, "micro-locate while waiting for sync\n");
                        if (micro_locate (nframes)) {
                                /* XXX ERROR !!! XXX */
                        }
@@ -861,7 +960,6 @@ Session::process_event (SessionEvent* ev)
                break;
 
        case SessionEvent::SetTransportMaster:
-               cerr << "Process TMM current request\n";
                TransportMasterManager::instance().set_current (ev->transport_master);
                break;
 
@@ -1077,16 +1175,19 @@ Session::follow_transport_master (pframes_t nframes)
 
        slave_speed = tmm.get_current_speed_in_process_context();
        slave_transport_sample = tmm.get_current_position_in_process_context ();
+
+       track_transport_master (slave_speed, slave_transport_sample);
+
+       /* transport sample may have been moved during ::track_transport_master() */
+
        delta = _transport_sample - slave_transport_sample;
 
        DEBUG_TRACE (DEBUG::Slave, string_compose ("session at %1, master at %2, delta: %3 res: %4\n", _transport_sample, slave_transport_sample, delta, tmm.current()->resolution()));
 
-       track_transport_master (slave_speed, slave_transport_sample);
-
        if (transport_master_tracking_state == Running) {
 
                if (!actively_recording() && abs (delta) > tmm.current()->resolution()) {
-                       DEBUG_TRACE (DEBUG::Slave, string_compose ("average slave delta %1 greater than slave resolution %2\n", delta, tmm.current()->resolution()));
+                       DEBUG_TRACE (DEBUG::Slave, string_compose ("current slave delta %1 greater than slave resolution %2\n", delta, tmm.current()->resolution()));
                        if (micro_locate (-delta) != 0) {
                                DEBUG_TRACE (DEBUG::Slave, "micro-locate didn't work, set no disk output true\n");
 
@@ -1125,28 +1226,13 @@ Session::track_transport_master (float slave_speed, samplepos_t slave_transport_
 
                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:
@@ -1155,7 +1241,7 @@ Session::track_transport_master (float slave_speed, samplepos_t slave_transport_
 
                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) {