more MTC stuff, including toggleable use of torben's PI controller
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 2 Dec 2009 21:26:26 +0000 (21:26 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 2 Dec 2009 21:26:26 +0000 (21:26 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6265 d708f5d6-7413-0410-9779-e7cbd77b26cf

12 files changed:
libs/appleutility/wscript
libs/ardour/ardour/session.h
libs/ardour/ardour/slave.h
libs/ardour/audioengine.cc
libs/ardour/enums.cc
libs/ardour/mtc_slave.cc
libs/ardour/session_midi.cc
libs/ardour/session_process.cc
libs/ardour/session_state.cc
libs/ardour/wscript
libs/midi++2/midi++/parser.h
libs/midi++2/mtc.cc

index 27dc1b9d26925ed644e380dd65dc1c5efd6995a7..87b713a0dc3c78f1021ad071d9522f2221f21454 100644 (file)
@@ -28,7 +28,7 @@ def configure(conf):
        
 def build(bld):
        obj              = bld.new_task_gen('cxx', 'shlib',
-                                                                               uselib = 'COREAUDIO CORESERVICES COREFOUNDATION AUDIOTOOLBOX AUDIOUNITS OSX GTKOSX')
+                                            uselib = 'COREAUDIO CORESERVICES COREFOUNDATION AUDIOTOOLBOX AUDIOUNITS OSX GTKOSX')
        obj.source       = libappleutility_sources
        obj.export_incdirs = ['.']
        obj.includes     = ['.']
@@ -41,4 +41,4 @@ def shutdown():
        autowaf.shutdown()
 
 def i18n(bld):
-       pass
\ No newline at end of file
+       pass
index a3505ec587424341dab1710a5114f2f35c284a7b..4f0acc9381fc232b3d2770204f7705593b53f3f4 100644 (file)
@@ -986,6 +986,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
                PostTransportClearSubstate      = 0x80000
        };
 
+       enum SlaveState {
+               Stopped,
+               Waiting,
+               Running
+       };
+       
+       SlaveState slave_state() const { return _slave_state; }
 
   protected:
        friend class AudioEngine;
@@ -1088,20 +1095,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
        int  average_dir;
        bool have_first_delta_accumulator;
 
-       enum SlaveState {
-               Stopped,
-               Waiting,
-               Running
-       };
-
-       SlaveState slave_state;
+       SlaveState _slave_state;
        nframes_t slave_wait_end;
 
        void reset_slave_state ();
        bool follow_slave (nframes_t);
        void calculate_moving_average_of_slave_delta(int dir, nframes_t this_delta);
-       void track_slave_state(float slave_speed, nframes_t slave_transport_frame,
-                              nframes_t this_delta, bool starting);
+       void track_slave_state(float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta);
        void follow_slave_silently(nframes_t nframes, float slave_speed);
 
         void use_sync_source (SyncSource);
index 16e11097ead472086a00119425dce8220665dc43..dae0d80d109b2bbb5cc9919f8f4bf405ec69d50f 100644 (file)
@@ -29,6 +29,8 @@
 #include "midi++/parser.h"
 #include "midi++/types.h"
 
+class PIController;
+
 namespace MIDI {
        class Port;
 }
@@ -140,11 +142,18 @@ class Slave {
        virtual nframes_t resolution() const = 0;
 
        /**
-        * @return - when returning true, ARDOUR will wait for one second before transport
+        * @return - when returning true, ARDOUR will wait for seekahead_distance() before transport
         * starts rolling
         */
        virtual bool requires_seekahead () const = 0;
 
+       /**
+        * @return the number of frames that this slave wants to seek ahead. Relevant
+        * only if @func requires_seekahead() returns true.
+        */
+
+       virtual nframes64_t seekahead_distance() const { return 0; }
+
        /**
         * @return - when returning true, ARDOUR will use transport speed 1.0 no matter what
         *           the slave returns
@@ -222,35 +231,40 @@ class MTC_Slave : public Slave, public sigc::trackable {
 
        nframes_t resolution() const;
        bool requires_seekahead () const { return true; }
+       nframes64_t seekahead_distance() const;
+       bool give_slave_full_control_over_transport_speed() const;
 
   private:
        Session&    session;
        MIDI::Port* port;
        std::vector<sigc::connection> connections;
        bool        can_notify_on_unknown_rate;
-       
+       PIController* pic;
+
        SafeTime    current;
-       double      instantaneous_speed;
        nframes_t   mtc_frame;               /* current time */
        nframes_t   last_inbound_frame;      /* when we got it; audio clocked */
        MIDI::byte  last_mtc_fps_byte;
-       bool        qtr_frame_messages_valid_for_time;
-
+       nframes64_t window_begin;
+       nframes64_t window_end;
+       nframes64_t    last_mtc_timestamp;
+       nframes64_t    last_mtc_frame;
        bool           did_reset_tc_format;
        TimecodeFormat saved_tc_format;
-
-       static const int32_t accumulator_size = 128;
-       double   accumulator[accumulator_size];
-       int32_t accumulator_index;
-       bool    have_first_accumulated_speed;
+       size_t         speed_accumulator_size;
+       double*        speed_accumulator;
+       size_t         speed_accumulator_cnt;
+       bool           have_first_speed_accumulator;
+       double         average_speed;
 
        void reset ();
        void update_mtc_qtr (MIDI::Parser&, int, nframes_t);
        void update_mtc_time (const MIDI::byte *, bool, nframes_t);
-       void update_mtc_status (MIDI::Parser::MTC_Status);
+       void update_mtc_status (MIDI::MTC_Status);
        void read_current (SafeTime *) const;
-       double compute_apparent_speed (nframes64_t);
-
+       void reset_window (nframes64_t);
+       bool outside_window (nframes64_t) const;
+       void process_apparent_speed (double);
 };
 
 class MIDIClock_Slave : public Slave, public sigc::trackable {
@@ -337,24 +351,6 @@ class MIDIClock_Slave : public Slave, public sigc::trackable {
        bool _starting;
 };
 
-class ADAT_Slave : public Slave
-{
-  public:
-       ADAT_Slave () {}
-       ~ADAT_Slave () {}
-
-       bool speed_and_position (double& speed, nframes64_t& pos) {
-               speed = 0;
-               pos = 0;
-               return false;
-       }
-
-       bool locked() const { return false; }
-       bool ok() const { return false; }
-       nframes_t resolution() const { return 1; }
-       bool requires_seekahead () const { return true; }
-};
-
 class JACK_Slave : public Slave
 {
   public:
index 2e5aea9047282a6e1ba75e46b6b2cfdfff1174d4..2f344eb8ba75b31516a825d89991d8161259e0fb 100644 (file)
@@ -136,9 +136,13 @@ _thread_init_callback (void * /*arg*/)
        */
 
        PBD::notify_gui_about_thread_creation (pthread_self(), X_("Audioengine"), 4096);
-#ifdef WITH_JACK_MIDI
        MIDI::JACK_MidiPort::set_process_thread (pthread_self());
-#endif // WITH_JACK_MIDI
+}
+
+static void
+ardour_jack_error (const char* msg)
+{
+       error << "JACK: " << msg << endmsg;
 }
 
 int
@@ -188,6 +192,8 @@ AudioEngine::start ()
                        jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this);
                }
 
+               jack_set_error_function (ardour_jack_error);
+
                if (jack_activate (_priv_jack) == 0) {
                        _running = true;
                        _has_run = true;
@@ -1121,12 +1127,6 @@ AudioEngine::remove_all_ports ()
        ports.flush ();
 }
 
-static void
-ardour_jack_error (const char* msg)
-{
-       error << "JACK: " << msg << endmsg;
-}
-
 int
 AudioEngine::connect_to_jack (string client_name)
 {
@@ -1148,8 +1148,6 @@ AudioEngine::connect_to_jack (string client_name)
                jack_client_name = jack_get_client_name (_priv_jack);
        }
 
-       jack_set_error_function (ardour_jack_error);
-
        return 0;
 }
 
index 870c60eec72ceb25c2aa4ee265ffcd5fce54b719..4b82950f3e3d404df8e66ae231a0c623524ed305 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include "pbd/enumwriter.h"
+#include "midi++/types.h"
 
 #include "ardour/audiofilesource.h"
 #include "ardour/audioregion.h"
@@ -40,6 +41,7 @@
 using namespace std;
 using namespace PBD;
 using namespace ARDOUR;
+using namespace MIDI;
 
 void
 setup_enum_writer ()
@@ -115,7 +117,9 @@ setup_enum_writer ()
        WaveformShape _WaveformShape;
        QuantizeType _QuantizeType;
        Session::PostTransportWork _Session_PostTransportWork;
-               
+       Session::SlaveState _Session_SlaveState;
+       MTC_Status _MIDI_MTC_Status;
+
 #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)
@@ -305,6 +309,16 @@ setup_enum_writer ()
        REGISTER_CLASS_ENUM (Session::Event, AutoLoop);
        REGISTER (_Session_Event_Type);
 
+       REGISTER_CLASS_ENUM (Session, Stopped);
+       REGISTER_CLASS_ENUM (Session, Waiting);
+       REGISTER_CLASS_ENUM (Session, Running);
+       REGISTER (_Session_SlaveState);
+
+       REGISTER_ENUM (MTC_Stopped);
+       REGISTER_ENUM (MTC_Forward);
+       REGISTER_ENUM (MTC_Backward);
+       REGISTER (_MIDI_MTC_Status);
+
        REGISTER_CLASS_ENUM (Session, PostTransportStop);
        REGISTER_CLASS_ENUM (Session, PostTransportDisableRecord);
        REGISTER_CLASS_ENUM (Session, PostTransportPosition);
index 4ca86236b737c113f8587bdffabfad3f30b61d43..9e566367bcab365e8394b60117e174afc27e6957 100644 (file)
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include "pbd/error.h"
+#include "pbd/enumwriter.h"
 #include "pbd/failed_constructor.h"
 #include "pbd/pthread_utils.h"
 
@@ -30,7 +31,7 @@
 #include "ardour/slave.h"
 #include "ardour/session.h"
 #include "ardour/audioengine.h"
-#include "ardour/cycles.h"
+#include "ardour/pi_controller.h"
 
 #include "i18n.h"
 
@@ -45,8 +46,14 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
 {
        can_notify_on_unknown_rate = true;
        did_reset_tc_format = false;
+
+       pic = new PIController (1.0, 8);
        
        last_mtc_fps_byte = session.get_mtc_timecode_bits ();
+       mtc_frame = 0;
+
+       speed_accumulator_size = 16;
+       speed_accumulator = new double[speed_accumulator_size];
 
        rebind (p);
        reset ();
@@ -57,6 +64,15 @@ MTC_Slave::~MTC_Slave()
        if (did_reset_tc_format) {
                session.config.set_timecode_format (saved_tc_format);
        }
+       delete pic;
+       delete [] speed_accumulator;
+}
+
+bool 
+MTC_Slave::give_slave_full_control_over_transport_speed() const
+{
+       return true; // for PiC control */
+       // return false; // for Session-level computed varispeed
 }
 
 void
@@ -68,6 +84,8 @@ MTC_Slave::rebind (MIDI::Port& p)
 
        port = &p;
 
+       cerr << "Bind to port MTC messages\n";
+
        connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
        connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
        connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
@@ -76,34 +94,8 @@ MTC_Slave::rebind (MIDI::Port& p)
 void
 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
 {
-       DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2, valid-for-time? %3\n", which_qtr, now, qtr_frame_messages_valid_for_time));
-
-       if (qtr_frame_messages_valid_for_time) {
-
-               if (which_qtr != 7) {
-
-                       /* leave position and speed updates for the last
-                          qtr frame message of the 8 to be taken
-                          care of in update_mtc_time(), invoked
-                          by the Parser right after this.
-                       */
-
-                       nframes_t qtr;
-                       
-                       qtr = (long) (session.frames_per_timecode_frame() / 4);
-                       mtc_frame += qtr;
-                       
-                       double speed = compute_apparent_speed (now);
-                       
-                       current.guard1++;
-                       current.position = mtc_frame;
-                       current.timestamp = now;
-                       current.speed = speed;
-                       current.guard2++;
-               }
-
-               last_inbound_frame = now;
-       }
+       DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
+       last_inbound_frame = now;
 }
 
 void
@@ -116,7 +108,8 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
        Timecode::Time timecode;
        TimecodeFormat tc_format;
        bool reset_tc = true;
-       
+       nframes64_t window_root = -1;
+
        DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
        
        timecode.hours = msg[3];
@@ -175,24 +168,28 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
        DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n", 
                                                 now, timecode, mtc_frame, was_full));
 
-       if (was_full) {
+       if (was_full || outside_window (mtc_frame)) {
 
                session.timecode_to_sample (timecode, mtc_frame, true, false);
                session.request_locate (mtc_frame, false);
                session.request_transport_speed (0);
-               update_mtc_status (MIDI::Parser::MTC_Stopped);
-
+               update_mtc_status (MIDI::MTC_Stopped);
+               window_root = mtc_frame;
+               
                reset ();
 
        } else {
-
                        
                /* we've had the first set of 8 qtr frame messages, determine position
-                          and allow continuing qtr frame messages to provide position
-                          and speed information.
+                  and allow continuing qtr frame messages to provide position
+                  and speed information.
                */
                
-               qtr_frame_messages_valid_for_time = true;
+               /* do a careful conversion of the timecode value to a position
+                  so that we take drop/nondrop and all that nonsense into 
+                  consideration.
+               */
+
                session.timecode_to_sample (timecode, mtc_frame, true, false);
                
                /* We received the last quarter frame 7 quarter frames (1.75 mtc
@@ -203,56 +200,84 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
                
                mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
 
+
                if (now) {
-                       double speed = compute_apparent_speed (now);
-                       
+
+                       if (last_mtc_timestamp == 0) {
+
+                               last_mtc_timestamp = now;
+                               last_mtc_frame = mtc_frame;
+
+                       } else {
+
+                               if (give_slave_full_control_over_transport_speed()) {
+                                       /* PIC 
+                                        * 
+                                        * its not the average, but we will assign it to current.speed below
+                                        */
+                                       
+                                       average_speed = pic->get_ratio (session.audible_frame() - mtc_frame);
+                                       
+                               } else {
+
+                                       /* Non-PiC 
+                                        */
+
+                                       nframes64_t time_delta = (now - last_mtc_timestamp);
+                                       
+                                       if (time_delta != 0) {
+                                               double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
+                                               
+                                               process_apparent_speed (apparent_speed);
+                                               DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
+                                       } else {
+                                               DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
+                                       }
+                                       
+                                       /* every second, recalibrate the starting point for the speed measurement */
+                                       if (mtc_frame - last_mtc_frame > session.frame_rate()) {
+                                               last_mtc_timestamp = now;
+                                               last_mtc_frame = mtc_frame;
+                                       }
+                               }
+                       }
+
                        current.guard1++;
                        current.position = mtc_frame;
                        current.timestamp = now;
-                       current.speed = speed;
+                       current.speed = average_speed;
                        current.guard2++;
+                       window_root = mtc_frame;
                }
        }
 
        if (now) {
                last_inbound_frame = now;
        }
+
+       if (window_root >= 0) {
+               reset_window (window_root);
+       }
 }
 
-double
-MTC_Slave::compute_apparent_speed (nframes64_t now)
+void
+MTC_Slave::process_apparent_speed (double this_speed)
 {
-       if (current.timestamp != 0) {
-               
-               double speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp));
-               DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 / %3\n",
-                                                        speed, mtc_frame - current.position, now - current.timestamp));
-               
-               /* crude low pass filter/smoother for speed */
+       DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
 
-               accumulator[accumulator_index++] = speed;
-               
-               if (accumulator_index >= accumulator_size) {
-                       have_first_accumulated_speed = true;
-                       accumulator_index = 0;
-               }
-               
-               if (have_first_accumulated_speed) {
-                       double total = 0;
-                       
-                       for (int32_t i = 0; i < accumulator_size; ++i) {
-                               total += accumulator[i];
-                       }
-                       
-                       speed = total / accumulator_size;
-                       DEBUG_TRACE (DEBUG::MTC, string_compose ("speed smoothed to %1\n", speed));
-               } 
+       if (speed_accumulator_cnt >= speed_accumulator_size) {
+               have_first_speed_accumulator = true;
+               speed_accumulator_cnt = 0;
+       }
 
-               return speed;
-               
-       } else {
-               
-               return 0;
+       speed_accumulator[speed_accumulator_cnt++] = this_speed;
+
+       if (have_first_speed_accumulator) {
+               average_speed = 0.0;
+               for (size_t i = 0; i < speed_accumulator_size; ++i) {
+                       average_speed += speed_accumulator[i];
+               }
+               average_speed /= speed_accumulator_size;
        }
 }
 
@@ -271,16 +296,16 @@ MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
 }
 
 void
-MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
+MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
 {
        /* XXX !!! thread safety ... called from MIDI I/O context
           and process() context (via ::speed_and_position())
        */
 
+
+       DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
        switch (status) {
        case MTC_Stopped:
-               mtc_frame = 0;
-
                current.guard1++;
                current.position = mtc_frame;
                current.timestamp = 0;
@@ -290,27 +315,22 @@ MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
                break;
 
        case MTC_Forward:
-               mtc_frame = 0;
-
                current.guard1++;
                current.position = mtc_frame;
                current.timestamp = 0;
                current.speed = 0;
                current.guard2++;
-
                break;
 
        case MTC_Backward:
-               mtc_frame = 0;
-
                current.guard1++;
                current.position = mtc_frame;
                current.timestamp = 0;
                current.speed = 0;
                current.guard2++;
-
                break;
        }
+       
 }
 
 void
@@ -365,7 +385,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
                pos = last.position;
                session.request_locate (pos, false);
                session.request_transport_speed (0);
-               update_mtc_status (MIDI::Parser::MTC_Stopped);
+               update_mtc_status (MIDI::MTC_Stopped);
                reset();
                DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
                return false;
@@ -384,7 +404,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
                if (last.timestamp && (now > last.timestamp)) {
                        elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
                        DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
-                                                                last.timestamp, now, elapsed, speed));
+                                                                last.timestamp, now, elapsed, last.speed));
                } else {
                        elapsed = 0; /* XXX is this right? */
                }
@@ -422,7 +442,42 @@ MTC_Slave::reset ()
        current.timestamp = 0;
        current.speed = 0;
        current.guard2++;
-       accumulator_index = 0;
-       have_first_accumulated_speed = false;
-       qtr_frame_messages_valid_for_time = false;
+
+       window_begin = 0;
+       window_end = 0;
+       last_mtc_frame = 0;
+       last_mtc_timestamp = 0;
+
+       average_speed = 0;
+       have_first_speed_accumulator = false;
+       speed_accumulator_cnt = 0;
+
+       pic->out_of_bounds();
+}
+
+void
+MTC_Slave::reset_window (nframes64_t root)
+{
+       window_begin = root;
+
+       if (session.slave_state() == Session::Running) {
+               window_end = root + (session.frames_per_timecode_frame() * 2);
+       } else {
+               window_end = root + seekahead_distance ();
+       }
+
+       DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
+}
+
+nframes64_t
+MTC_Slave::seekahead_distance () const
+{
+       /* 1 second */
+       return session.frame_rate();
+}
+
+bool
+MTC_Slave::outside_window (nframes64_t pos) const
+{
+       return ((pos < window_begin) || (pos > window_end));
 }
index d205cc1ca80791c1eafe32a19a126bb8b74b54b9..b05cfc83a2b4327a7382eb868c739ca37a2cc463 100644 (file)
@@ -1261,7 +1261,7 @@ Session::midi_thread_work ()
                        }
 
                        if (pfd[p].revents & POLLIN) {
-                               DEBUG_TRACE (DEBUG::MidiIO, string_compose ("MIDI fd # %1 has data ready\n", p));
+                               DEBUG_TRACE (DEBUG::MidiIO, string_compose ("MIDI fd # %1 has data ready @ %2\n", p, now));
                                fds_ready++;
                                ports[p]->parse (now);
                        }
index e270a7c3ec0e50449e7fc34dfc3720cbe1969db1..4142490af6aa4b0b323ebbc0f9693d754aa0a31f 100644 (file)
@@ -461,7 +461,7 @@ Session::reset_slave_state ()
        average_slave_delta = 1800;
        delta_accumulator_cnt = 0;
        have_first_delta_accumulator = false;
-       slave_state = Stopped;
+       _slave_state = Stopped;
 }
 
 bool
@@ -483,7 +483,6 @@ Session::follow_slave (nframes_t nframes)
        nframes64_t slave_transport_frame;
        nframes_t this_delta;
        int dir;
-       bool starting;
 
        if (!_slave->ok()) {
                stop_transport ();
@@ -493,7 +492,7 @@ Session::follow_slave (nframes_t nframes)
 
        _slave->speed_and_position (slave_speed, slave_transport_frame);
 
-       DEBUG_TRACE (DEBUG::Slave, string_compose ("Slave @ %2 speed %1\n", slave_speed, slave_transport_frame));
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("Slave position %1 speed %2\n", slave_transport_frame, slave_speed));
 
        if (!_slave->locked()) {
                DEBUG_TRACE (DEBUG::Slave, "slave not locked\n");
@@ -508,7 +507,7 @@ Session::follow_slave (nframes_t nframes)
                dir = -1;
        }
 
-       if ((starting = _slave->starting())) {
+       if (_slave->starting()) {
                slave_speed = 0.0f;
        }
 
@@ -524,21 +523,23 @@ Session::follow_slave (nframes_t nframes)
 
        } else {
 
-               /* TC source is able to drift relative to us (slave)
-                  so we need to keep track of the drift and adjust
-                  our speed to remain locked.
+               /* if we are chasing and the average delta between us and the
+                  master gets too big, we want to switch to silent
+                  motion. so keep track of that here.
                */
 
-               calculate_moving_average_of_slave_delta(dir, this_delta);
+               if (_slave_state == Running) {
+                       calculate_moving_average_of_slave_delta(dir, this_delta);
+               }
        }
 
-       track_slave_state (slave_speed, slave_transport_frame, this_delta, starting);
+       track_slave_state (slave_speed, slave_transport_frame, this_delta);
 
-       DEBUG_TRACE (DEBUG::Slave, string_compose ("slave state %1 @ %2 speed %3 cur delta %4 starting %5\n",
-                                                  slave_state, slave_transport_frame, slave_speed, this_delta, starting));
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("slave state %1 @ %2 speed %3 cur delta %4 avg delta %5\n",
+                                                  _slave_state, slave_transport_frame, slave_speed, this_delta, average_slave_delta));
                     
 
-       if (slave_state == Running && !_slave->is_always_synced() && !config.get_timecode_source_is_synced()) {
+       if (_slave_state == Running && !_slave->is_always_synced() && !config.get_timecode_source_is_synced()) {
 
                if (_transport_speed != 0.0f) {
 
@@ -548,7 +549,6 @@ Session::follow_slave (nframes_t nframes)
 
                        float delta;
 
-#ifdef USE_MOVING_AVERAGE_OF_SLAVE
                        if (average_slave_delta == 0) {
                                delta = this_delta;
                                delta *= dir;
@@ -556,52 +556,38 @@ Session::follow_slave (nframes_t nframes)
                                delta = average_slave_delta;
                                delta *= average_dir;
                        }
-#else
-                       delta = this_delta;
-                       delta *= dir;
-#endif
 
 #ifndef NDEBUG
-       if (slave_speed != 0.0) {
-               DEBUG_TRACE (DEBUG::Slave, string_compose ("delta = %1 speed = %2 ts = %3 M@%4 S@%5 avgdelta %6\n",
-                                                          (int) (dir * this_delta),
-                                                          slave_speed,
-                                                          _transport_speed,
-                                                          _transport_frame,
-                                                          slave_transport_frame, 
-                                                          _transport_frame,
-                                                          average_slave_delta));
-       }
+                       if (slave_speed != 0.0) {
+                               DEBUG_TRACE (DEBUG::Slave, string_compose ("delta = %1 speed = %2 ts = %3 M@%4 S@%5 avgdelta %6\n",
+                                                                          (int) (dir * this_delta),
+                                                                          slave_speed,
+                                                                          _transport_speed,
+                                                                          _transport_frame,
+                                                                          slave_transport_frame, 
+                                                                          average_slave_delta));
+                       }
 #endif
-                       if (fabs(delta) > 2048) {
-                               nframes64_t jump_to = slave_transport_frame + lrintf (_current_frame_rate/5.0f);
-                               /* too far off, so locate and keep rolling */
-                               DEBUG_TRACE (DEBUG::Slave, string_compose ("slave delta %1 is too big, locate to %2\n", 
-                                                                          delta, jump_to));
-                               request_locate (jump_to, true);
-                               return false;
+                       
+                       if (_slave->give_slave_full_control_over_transport_speed()) {
+                               set_transport_speed (slave_speed, false, false);
                        } else {
                                float adjusted_speed = slave_speed + (delta /  float(_current_frame_rate));
-                               
-                               if (_slave->give_slave_full_control_over_transport_speed()) {
-                                       request_transport_speed (slave_speed);
-                               } else {
-                                       request_transport_speed (adjusted_speed);
-                                       DEBUG_TRACE (DEBUG::Slave, string_compose ("adjust using %1 towards %2 ratio %3 current %4 slave @ %5\n",
-                                                                                  delta, adjusted_speed, adjusted_speed/slave_speed, _transport_speed,
-                                                                                  slave_speed));
-                               }
+                               request_transport_speed (adjusted_speed);
+                               DEBUG_TRACE (DEBUG::Slave, string_compose ("adjust using %1 towards %2 ratio %3 current %4 slave @ %5\n",
+                                                                          delta, adjusted_speed, adjusted_speed/slave_speed, _transport_speed,
+                                                                          slave_speed));
                        }
                        
-                       if (abs(average_slave_delta) > (long) _slave->resolution()) {
-                               cerr << "average slave delta greater than slave resolution, going to silent motion\n";
+                       if (abs(average_slave_delta) > _slave->resolution()) {
+                               cerr << "average slave delta greater than slave resolution (" << _slave->resolution() << "), going to silent motion\n";
                                goto silent_motion;
                        }
                }
        }
 
 
-       if (!starting && !non_realtime_work_pending()) {
+       if (_slave_state == Running && !non_realtime_work_pending()) {
                /* speed is set, we're locked, and good to go */
                return true;
        }
@@ -645,24 +631,24 @@ Session::calculate_moving_average_of_slave_delta(int dir, nframes_t this_delta)
 }
 
 void
-Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta, bool starting)
+Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta)
 {
        if (slave_speed != 0.0f) {
 
                /* slave is running */
 
-               switch (slave_state) {
+               switch (_slave_state) {
                case Stopped:
                        if (_slave->requires_seekahead()) {
-                               slave_wait_end = slave_transport_frame + _current_frame_rate;
+                               slave_wait_end = slave_transport_frame + _slave->seekahead_distance ();
                                DEBUG_TRACE (DEBUG::Slave, string_compose ("slave stopped, but running, requires seekahead to %1\n", slave_wait_end));
+                               /* we can call locate() here because we are in process context */
                                locate (slave_wait_end, false, false);
-                               slave_state = Waiting;
-                               starting = true;
+                               _slave_state = Waiting;
 
                        } else {
 
-                               slave_state = Running;
+                               _slave_state = Running;
 
                                Location* al = _locations.auto_loop_location();
 
@@ -678,13 +664,24 @@ Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame,
                        break;
 
                case Waiting:
+               default:
+                       break;
+               }
+
+               if (_slave_state == Waiting) {
+
                        DEBUG_TRACE (DEBUG::Slave, string_compose ("slave waiting at %1\n", slave_transport_frame));
 
                        if (slave_transport_frame >= slave_wait_end) {
 
                                DEBUG_TRACE (DEBUG::Slave, string_compose ("slave start at %1 vs %2\n", slave_transport_frame, _transport_frame));
 
-                               slave_state = Running;
+                               _slave_state = Running;
+
+                               /* now perform a "micro-seek" within the disk buffers to realign ourselves
+                                  precisely with the master.
+                               */
+
 
                                bool ok = true;
                                nframes_t frame_delta = slave_transport_frame - _transport_frame;
@@ -713,13 +710,9 @@ Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame,
                                average_slave_delta = 0L;
                                this_delta = 0;
                        }
-                       break;
-
-               default:
-                       break;
                }
 
-               if (slave_state == Running && _transport_speed == 0.0f) {
+               if (_slave_state == Running && _transport_speed == 0.0f) {
                        DEBUG_TRACE (DEBUG::Slave, "slave starts transport\n");
                        start_transport ();
                }
@@ -738,7 +731,7 @@ Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame,
                        force_locate (slave_transport_frame, false);
                }
 
-               slave_state = Stopped;
+               _slave_state = Stopped;
        }
 }
 
index 86a317d1d120227d9cb03d2c18f51081a40e8926..bcc3afbb054f8f66b0d4a28cae82a767bb5d31fe 100644 (file)
@@ -263,7 +263,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        average_slave_delta = 1800; // !!! why 1800 ????
        have_first_delta_accumulator = false;
        delta_accumulator_cnt = 0;
-       slave_state = Stopped;
+       _slave_state = Stopped;
 
        _engine.GraphReordered.connect (mem_fun (*this, &Session::graph_reordered));
 
index 48cd6ccb6f83384a2ebc81eb1f5c16e314de10c5..bf850ebeab7b65cee1efa7020403c65e8259bb43 100644 (file)
@@ -132,6 +132,7 @@ libardour_sources = [
        'onset_detector.cc',
        'panner.cc',
        'pcm_utils.cc',
+       'pi_controller.cc',
        'playlist.cc',
        'playlist_factory.cc',
        'plugin.cc',
index b8364cc02525b850c9972f7325960300a902f5dc..365f2fb46a37652436f44534a5d9d33b729c4463 100644 (file)
@@ -116,12 +116,6 @@ class Parser : public sigc::trackable {
 
        /* MTC */
 
-       enum MTC_Status {
-               MTC_Stopped = 0,
-               MTC_Forward,
-               MTC_Backward
-       };
-
        MTC_FPS mtc_fps() const { return _mtc_fps; }
        MTC_Status  mtc_running() const { return _mtc_running; }
        const byte *mtc_current() const { return _mtc_time; }
index 74b528e5e34f3ab40e5dcbe9e29376f52e450a3b..a49f469d2bd90ee7e8dc0fd806a31c002c3f6dfd 100644 (file)
@@ -226,7 +226,7 @@ Parser::process_mtc_quarter_frame (byte *msg)
        /* time code is looking good */
 
 #ifdef DEBUG_MTC
-       cerr << "for quarter frame " << which_quarter_frame << " byte = " << hex << (int) msg[1] << dec << endl;
+       // cerr << "for quarter frame " << which_quarter_frame << " byte = " << hex << (int) msg[1] << dec << endl;
 #endif
 
        switch (which_quarter_frame) {
@@ -276,6 +276,10 @@ Parser::process_mtc_quarter_frame (byte *msg)
 
        } 
        
+#ifdef DEBUG_MTC
+       cerr << "Emit MTC Qtr\n";
+#endif
+
        mtc_qtr (*this, which_quarter_frame, _timestamp); /* EMIT_SIGNAL */
 
        // mtc (*this, &msg[1], msglen - 1);