consolidate all transport masters on a SafeTime object that is a member of the Transp...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 25 Sep 2018 21:46:59 +0000 (17:46 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 27 Sep 2018 15:31:13 +0000 (11:31 -0400)
This seems to have broken some aspects of chasing/locking

libs/ardour/ardour/transport_master.h
libs/ardour/engine_slave.cc
libs/ardour/ltc_slave.cc
libs/ardour/midi_clock_slave.cc
libs/ardour/mtc_slave.cc
libs/ardour/session_transport.cc
libs/ardour/transport_master.cc
libs/ardour/transport_master_manager.cc

index 81d250dda9825690e84be00d397d5ffaa07c456a..f6dae4bff136271b69ee084d1fef75b7535338ab 100644 (file)
@@ -66,6 +66,80 @@ namespace Properties {
        LIBARDOUR_API extern PBD::PropertyDescriptor<ARDOUR::TransportRequestType> allowed_transport_requests;
 };
 
+struct LIBARDOUR_API SafeTime {
+
+       /* This object uses memory fences to provide psuedo-atomic updating of
+        * non-atomic data. If after reading guard1 and guard2 with correct
+        * memory fencing they have the same value, then we know that the other
+        * members are all internally consistent.
+        *
+        * Traditionally, one might do this with a mutex, but this object
+        * provides lock-free write update. The reader might block while
+        * waiting for consistency, but this is extraordinarily unlikely. In
+        * this sense, the design is similar to a spinlock.
+        *
+        * any update starts by incrementing guard1, with a memory fence to
+        * ensure no reordering of this w.r.t later operations.
+        *
+        * then we update the "non-atomic" data members.
+        *
+        * then we update guard2, with another memory fence to prevent
+        * reordering.
+        *
+        * ergo, if guard1 == guard2, the update of the non-atomic members is
+        * complete and the values stored there are consistent.
+        */
+
+       boost::atomic<int> guard1;
+       samplepos_t        position;
+       samplepos_t        timestamp;
+       double             speed;
+       boost::atomic<int> guard2;
+
+       SafeTime() {
+               guard1.store (0);
+               position = 0;
+               timestamp = 0;
+               speed = 0;
+               guard2.store (0);
+       }
+
+       void reset () {
+               guard1.store (0);
+               position = 0;
+               timestamp  = 0;
+               speed = 0;
+               guard2.store (0);
+       }
+
+       void update (samplepos_t p, samplepos_t t, double s) {
+               guard1.fetch_add (1, boost::memory_order_acquire);
+               position = p;
+               timestamp = t;
+               speed = s;
+               guard2.fetch_add (1, boost::memory_order_acquire);
+       }
+
+       void safe_read (SafeTime& dst) const {
+               int tries = 0;
+
+               do {
+                       if (tries == 10) {
+                               std::cerr << X_("SafeTime: atomic read of current time failed, sleeping!") << std::endl;
+                               Glib::usleep (20);
+                               tries = 0;
+                       }
+                       dst.guard1.store (guard1.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
+                       dst.position = position;
+                       dst.timestamp = timestamp;
+                       dst.speed = speed;
+                       dst.guard2.store (guard2.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
+                       tries++;
+
+               } while (dst.guard1.load (boost::memory_order_seq_cst) != dst.guard2.load (boost::memory_order_seq_cst));
+       }
+};
+
 /**
  * @class TransportMaster
  *
@@ -138,7 +212,7 @@ class LIBARDOUR_API TransportMaster : public PBD::Stateful {
         * @param position - The transport position requested
         * @return - The return value is currently ignored (see Session::follow_slave)
         */
-       virtual bool speed_and_position (double& speed, samplepos_t& position, samplepos_t now) = 0;
+       virtual bool speed_and_position (double& speed, samplepos_t& position, samplepos_t & lp, samplepos_t & when, samplepos_t now);
 
        /**
         * reports to ARDOUR whether the TransportMaster is currently synced to its external
@@ -252,6 +326,9 @@ class LIBARDOUR_API TransportMaster : public PBD::Stateful {
 
        TransportRequestType request_mask() const { return _request_mask; }
        void set_request_mask (TransportRequestType);
+
+       void get_current (double&, samplepos_t&, samplepos_t);
+
   protected:
        SyncSource      _type;
        PBD::Property<std::string>   _name;
@@ -264,6 +341,8 @@ class LIBARDOUR_API TransportMaster : public PBD::Stateful {
        PBD::Property<bool> _collect;
        PBD::Property<bool> _connected;
 
+       SafeTime current;
+
        /* DLL - chase incoming data */
 
        int    transport_direction;
@@ -284,57 +363,6 @@ class LIBARDOUR_API TransportMaster : public PBD::Stateful {
        virtual void register_properties ();
 };
 
-struct LIBARDOUR_API SafeTime {
-       boost::atomic<int> guard1;
-       samplepos_t   position;
-       samplepos_t   timestamp;
-       double       speed;
-       boost::atomic<int> guard2;
-
-       SafeTime() {
-               guard1.store (0);
-               position = 0;
-               timestamp = 0;
-               speed = 0;
-               guard2.store (0);
-       }
-
-       SafeTime (SafeTime const & other)
-               : guard1 (other.guard1.load (boost::memory_order_acquire))
-               , position (other.position)
-               , timestamp (other.timestamp)
-               , speed (other.speed)
-               , guard2 (other.guard2.load (boost::memory_order_acquire))
-       {}
-
-       void update (samplepos_t p, samplepos_t t, double s) {
-               guard1.fetch_add (1, boost::memory_order_acquire);
-               position = p;
-               timestamp = t;
-               speed = s;
-               guard2.fetch_add (1, boost::memory_order_acquire);
-       }
-
-       void safe_read (SafeTime& dst) const {
-               int tries = 0;
-
-               do {
-                       if (tries == 10) {
-                               std::cerr << X_("SafeTime: atomic read of current time failed, sleeping!") << std::endl;
-                               Glib::usleep (20);
-                               tries = 0;
-                       }
-                       dst.guard1.store (guard1.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
-                       dst.position = position;
-                       dst.timestamp = timestamp;
-                       dst.speed = speed;
-                       dst.guard2.store (guard2.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
-                       tries++;
-
-               } while (dst.guard1.load (boost::memory_order_seq_cst) != dst.guard2.load (boost::memory_order_seq_cst));
-       }
-};
-
 /** a helper class for any TransportMaster that receives its input via a MIDI
  * port
  */
@@ -377,8 +405,6 @@ class LIBARDOUR_API MTC_TransportMaster : public TimecodeTransportMaster, public
 
        void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
 
-       bool speed_and_position (double&, samplepos_t&, samplepos_t);
-
        bool locked() const;
        bool ok() const;
        void handle_locate (const MIDI::byte*);
@@ -399,7 +425,6 @@ class LIBARDOUR_API MTC_TransportMaster : public TimecodeTransportMaster, public
 
        static const int sample_tolerance;
 
-       SafeTime       current;
        samplepos_t    mtc_frame;               /* current time */
        double         mtc_frame_dll;
        samplepos_t    last_inbound_frame;      /* when we got it; audio clocked */
@@ -430,7 +455,6 @@ class LIBARDOUR_API MTC_TransportMaster : public TimecodeTransportMaster, public
        void update_mtc_qtr (MIDI::Parser&, int, samplepos_t);
        void update_mtc_time (const MIDI::byte *, bool, samplepos_t);
        void update_mtc_status (MIDI::MTC_Status);
-       void read_current (SafeTime *) const;
        void reset_window (samplepos_t);
        bool outside_window (samplepos_t) const;
        void init_mtc_dll(samplepos_t, double);
@@ -446,7 +470,6 @@ public:
        void set_session (Session*);
 
        void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
-       bool speed_and_position (double&, samplepos_t&, samplepos_t);
 
        bool locked() const;
        bool ok() const;
@@ -482,10 +505,7 @@ public:
        LTCFrameExt    prev_sample;
        bool           fps_detected;
 
-       samplecnt_t     monotonic_cnt;
-       samplecnt_t     last_timestamp;
-       samplecnt_t     last_ltc_sample;
-       double          ltc_speed;
+       samplecnt_t    monotonic_cnt;
        int            delayedlocked;
 
        int            ltc_detect_fps_cnt;
@@ -513,7 +533,6 @@ class LIBARDOUR_API MIDIClock_TransportMaster : public TransportMaster, public T
        void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
 
        void rebind (MidiPort&);
-       bool speed_and_position (double&, samplepos_t&, samplepos_t);
 
        bool locked() const;
        bool ok() const;
@@ -558,13 +577,12 @@ class LIBARDOUR_API MIDIClock_TransportMaster : public TransportMaster, public T
        void start (MIDI::Parser& parser, samplepos_t timestamp);
        void contineu (MIDI::Parser& parser, samplepos_t timestamp);
        void stop (MIDI::Parser& parser, samplepos_t timestamp);
-       void position (MIDI::Parser& parser, MIDI::byte* message, size_t size);
+       void position (MIDI::Parser& parser, MIDI::byte* message, size_t size, samplepos_t timestamp);
        // we can't use continue because it is a C++ keyword
        void calculate_one_ppqn_in_samples_at(samplepos_t time);
        samplepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
        void calculate_filter_coefficients (double qpm);
        void update_midi_clock (MIDI::Parser& parser, samplepos_t timestamp);
-       void read_current (SafeTime *) const;
 };
 
 class LIBARDOUR_API Engine_TransportMaster : public TransportMaster
@@ -574,7 +592,7 @@ class LIBARDOUR_API Engine_TransportMaster : public TransportMaster
        ~Engine_TransportMaster  ();
 
        void pre_process (pframes_t nframes, samplepos_t now,  boost::optional<samplepos_t>);
-       bool speed_and_position (double& speed, samplepos_t& pos, samplepos_t);
+       bool speed_and_position (double& speed, samplepos_t& pos, samplepos_t &, samplepos_t &, samplepos_t);
 
        bool starting() const { return _starting; }
        bool locked() const;
index 12b7d313a259031fb201340e956cb5a5640baa5c..a308557bcac2210e0a257b6be861c7e323ac89f7 100644 (file)
@@ -76,7 +76,7 @@ Engine_TransportMaster::pre_process (pframes_t, samplepos_t, boost::optional<sam
 }
 
 bool
-Engine_TransportMaster::speed_and_position (double& sp, samplepos_t& position, samplepos_t /* now */)
+Engine_TransportMaster::speed_and_position (double& sp, samplepos_t& position, samplepos_t& lp, samplepos_t & when, samplepos_t now)
 {
        boost::shared_ptr<AudioBackend> backend = engine.current_backend();
 
@@ -88,6 +88,9 @@ Engine_TransportMaster::speed_and_position (double& sp, samplepos_t& position, s
                return true;
        }
 
+       lp = now;
+       when = now;
+
        _current_delta = 0;
 
        return false;
index 4f47b904bd48f7f71803fa573d3b32eb694c0533..71e560c2f56decbfc91fddae999ecb5a5a40bd68 100644 (file)
@@ -53,8 +53,6 @@ LTC_TransportMaster::LTC_TransportMaster (std::string const & name)
        , samples_per_ltc_frame (0)
        , fps_detected (false)
        , monotonic_cnt (0)
-       , last_timestamp (0)
-       , last_ltc_sample (0)
        , delayedlocked (10)
        , ltc_detect_fps_cnt (0)
        , ltc_detect_fps_max (0)
@@ -185,11 +183,10 @@ LTC_TransportMaster::reset (bool with_ts)
 {
        DEBUG_TRACE (DEBUG::LTC, "LTC reset()\n");
        if (with_ts) {
-               last_timestamp = 0;
+               current.update (current.position, 0, current.speed);
                _current_delta = 0;
        }
        transport_direction = 0;
-       ltc_speed = 0;
        sync_lock_broken = false;
        monotonic_cnt = 0;
 }
@@ -460,53 +457,30 @@ LTC_TransportMaster::process_ltc(samplepos_t const now)
                 */
 
                samplepos_t cur_timestamp = sample.off_end + 1;
+               double ltc_speed = current.speed;
 
-               DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC S: %1 LS: %2  N: %3 L: %4\n", ltc_sample, last_ltc_sample, cur_timestamp, last_timestamp));
+               DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC S: %1 LS: %2  N: %3 L: %4\n", ltc_sample, current.position, cur_timestamp, current.timestamp));
 
-               if (cur_timestamp <= last_timestamp || last_timestamp == 0) {
-                       DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: UNCHANGED: %1\n", ltc_speed));
+               if (cur_timestamp <= current.timestamp || current.timestamp == 0) {
+                       DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: UNCHANGED: %1\n", current.speed));
                } else {
-                       ltc_speed = double (ltc_sample - last_ltc_sample) / double (cur_timestamp - last_timestamp);
-                       DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: %1\n", ltc_speed));
-               }
-
-               if (fabs (ltc_speed) > 10.0) {
-                       ltc_speed = 0;
-               }
-
-               last_timestamp = cur_timestamp;
-               last_ltc_sample = ltc_sample;
-
-       } /* end foreach decoded LTC sample */
-}
+                       ltc_speed = double (ltc_sample - current.position) / double (cur_timestamp - current.timestamp);
 
-bool
-LTC_TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t now)
-{
-       if (!_collect || last_timestamp == 0) {
-               return false;
-       }
-
-       /* XXX these are not atomics and maybe modified in a thread other other than the one
-          that is executing this.
-       */
-
-       speed = ltc_speed;
+                       /* provide a .1% deadzone to lock the speed */
+                       if (fabs (ltc_speed - 1.0) <= 0.001) {
+                               ltc_speed = 1.0;
+                       }
 
-       /* provide a .1% deadzone to lock the speed */
-       if (fabs (speed - 1.0) <= 0.001) {
-               speed = 1.0;
-       }
+                       if (fabs (ltc_speed) > 10.0) {
+                               ltc_speed = 0;
+                       }
 
-       if (speed != 0 && delayedlocked == 0 && fabs(speed) != 1.0) {
-               sync_lock_broken = true;
-               DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed not locked %1 based on %2\n", speed, ltc_speed));
-       }
+                       DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: %1\n", ltc_speed));
+               }
 
-       pos =  last_ltc_sample;
-       pos += (now - last_timestamp) * speed;
+               current.update (ltc_sample, cur_timestamp, ltc_speed);
 
-       return true;
+       } /* end foreach decoded LTC sample */
 }
 
 void
@@ -517,14 +491,14 @@ LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, bo
        monotonic_cnt = now;
 
        DEBUG_TRACE (DEBUG::LTC, string_compose ("pre-process - TID:%1 | latency: %2 | skip %3 | session ? %4| last %5 | dir %6 | sp %7\n",
-                                                pthread_name(), ltc_slave_latency.max, skip, (_session ? 'y' : 'n'), last_timestamp, transport_direction, ltc_speed));
+                                                pthread_name(), ltc_slave_latency.max, skip, (_session ? 'y' : 'n'), current.timestamp, transport_direction, current.speed));
 
-       if (last_timestamp == 0) {
+       if (current.timestamp == 0) {
                if (delayedlocked < 10) {
                        ++delayedlocked;
                }
 
-       } else if (ltc_speed != 0) {
+       } else if (current.speed != 0) {
 
        }
 
@@ -555,11 +529,11 @@ LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, bo
 
        process_ltc (now);
 
-       if (last_timestamp == 0) {
+       if (current.timestamp == 0) {
                DEBUG_TRACE (DEBUG::LTC, "last timestamp == 0\n");
                return;
-       } else if (ltc_speed != 0) {
-               DEBUG_TRACE (DEBUG::LTC, string_compose ("speed non-zero (%1)\n", ltc_speed));
+       } else if (current.speed != 0) {
+               DEBUG_TRACE (DEBUG::LTC, string_compose ("speed non-zero (%1)\n", current.speed));
                if (delayedlocked > 1) {
                        delayedlocked--;
                } else if (_current_delta == 0) {
@@ -567,7 +541,7 @@ LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, bo
                }
        }
 
-       if (abs (now - last_timestamp) > FLYWHEEL_TIMEOUT) {
+       if (abs (now - current.timestamp) > FLYWHEEL_TIMEOUT) {
                DEBUG_TRACE (DEBUG::LTC, "flywheel timeout\n");
                reset();
                /* don't change position from last known */
@@ -575,8 +549,13 @@ LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, bo
                return;
        }
 
+       if (!sync_lock_broken && current.speed != 0 && delayedlocked == 0 && fabs(current.speed) != 1.0) {
+               sync_lock_broken = true;
+               DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed not locked based on %1\n", current.speed));
+       }
+
        if (session_pos) {
-               const samplepos_t current_pos = last_ltc_sample + ((now - last_timestamp) * ltc_speed);
+               const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
                _current_delta = current_pos - *session_pos;
        } else {
                _current_delta = 0;
@@ -606,7 +585,7 @@ LTC_TransportMaster::apparent_timecode_format () const
 std::string
 LTC_TransportMaster::position_string() const
 {
-       if (!_collect || last_timestamp == 0) {
+       if (!_collect || current.timestamp == 0) {
                return " --:--:--:--";
        }
        return Timecode::timecode_format_time(timecode);
@@ -617,9 +596,9 @@ LTC_TransportMaster::delta_string() const
 {
        char delta[80];
 
-       if (!_collect || last_timestamp == 0) {
+       if (!_collect || current.timestamp == 0) {
                snprintf (delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
-       } else if ((monotonic_cnt - last_timestamp) > 2 * samples_per_ltc_frame) {
+       } else if ((monotonic_cnt - current.timestamp) > 2 * samples_per_ltc_frame) {
                snprintf (delta, sizeof(delta), "%s", _("flywheel"));
        } else {
                snprintf (delta, sizeof(delta), "\u0394<span foreground=\"%s\" face=\"monospace\" >%s%s%lld</span>sm",
index 04fa259519835de498bb299fec36698ab47f9460..7fd1c7a58e2f0af47e26db841b454a9839ba3f14 100644 (file)
@@ -49,10 +49,7 @@ using namespace PBD;
 MIDIClock_TransportMaster::MIDIClock_TransportMaster (std::string const & name, int ppqn)
        : TransportMaster (MIDIClock, name)
        , ppqn (ppqn)
-       , last_timestamp (0)
-       , should_be_position (0)
        , midi_clock_count (0)
-       , _speed (0)
        , _running (false)
        , _bpm (0)
 {
@@ -70,7 +67,7 @@ void
 MIDIClock_TransportMaster::init ()
 {
        midi_clock_count = 0;
-       last_timestamp = 0;
+       current.reset ();
 }
 
 void
@@ -88,46 +85,26 @@ MIDIClock_TransportMaster::set_session (Session *session)
                parser.start.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::start, this, _1, _2));
                parser.contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::contineu, this, _1, _2));
                parser.stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::stop, this, _1, _2));
-               parser.position.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::position, this, _1, _2, 3));
+               parser.position.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::position, this, _1, _2, _3, _4));
 
                reset ();
        }
 }
 
-bool
-MIDIClock_TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t now)
-{
-       if (!_running || !_collect) {
-               return false;
-       }
-
-       if (fabs (_speed - 1.0) < 0.001) {
-               speed = 1.0;
-       } else {
-               speed = _speed;
-       }
-
-       pos = should_be_position;
-       pos += (now - last_timestamp) * _speed;
-
-       return true;
-}
-
 void
 MIDIClock_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
 {
        /* Read and parse incoming MIDI */
 
-       DEBUG_TRACE (DEBUG::MidiClock, string_compose ("preprocess with lt = %1 @ %2, running ? %3\n", last_timestamp, now, _running));
+       DEBUG_TRACE (DEBUG::MidiClock, string_compose ("preprocess with lt = %1 @ %2, running ? %3\n", current.timestamp, now, _running));
 
        _midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
 
        /* no clock messages ever, or no clock messages for 1/4 second ? conclude that its stopped */
 
        if (!last_timestamp || (now > last_timestamp && ((now - last_timestamp) > (ENGINE->sample_rate() / 4)))) {
-               _speed = 0.0;
+               current.update (current.position, 0, 0);
                _bpm = 0.0;
-               last_timestamp = 0;
                _running = false;
                _current_delta = 0;
                midi_clock_count = 0;
@@ -137,18 +114,18 @@ MIDIClock_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now
        }
 
        if (!_running && midi_clock_count == 0 && session_pos) {
-               should_be_position = *session_pos;
-               DEBUG_TRACE (DEBUG::MidiClock, string_compose ("set sbp to %1\n", should_be_position));
+               current.update (*session_pos, now, current.speed);
+               DEBUG_TRACE (DEBUG::MidiClock, string_compose ("set sbp to %1\n", current.position));
        }
 
        if (session_pos) {
-               const samplepos_t current_pos = should_be_position + ((now - last_timestamp) * _speed);
+               const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
                _current_delta = current_pos - *session_pos;
        } else {
                _current_delta = 0;
        }
 
-       DEBUG_TRACE (DEBUG::MidiClock, string_compose ("speed_and_position: speed %1 should-be %2 transport %3 \n", _speed, should_be_position, _session->transport_sample()));
+       DEBUG_TRACE (DEBUG::MidiClock, string_compose ("speed_and_position: speed %1 should-be %2 transport %3 \n", current.speed, current.position, _session->transport_sample()));
 }
 
 void
@@ -197,21 +174,21 @@ MIDIClock_TransportMaster::update_midi_clock (Parser& /*parser*/, samplepos_t ti
        samplepos_t elapsed_since_start = timestamp - first_timestamp;
        double e = 0;
 
-       calculate_one_ppqn_in_samples_at (should_be_position);
+       calculate_one_ppqn_in_samples_at (current.position);
 
-       DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock count %1, sbp %2\n", midi_clock_count, should_be_position));
+       DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock count %1, sbp %2\n", midi_clock_count, current.position));
 
        if (midi_clock_count == 0) {
                /* second 0xf8 message after start/reset has arrived */
 
                first_timestamp = timestamp;
-               last_timestamp = timestamp;
+               current.update (0, timestamp, 0);
 
                DEBUG_TRACE (DEBUG::MidiClock, string_compose ("first clock message after start received @ %1\n", timestamp));
 
                midi_clock_count++;
 
-               should_be_position += one_ppqn_in_samples;
+               current.position += one_ppqn_in_samples;
 
        } else if (midi_clock_count == 1) {
 
@@ -233,7 +210,7 @@ MIDIClock_TransportMaster::update_midi_clock (Parser& /*parser*/, samplepos_t ti
                t1 = t0 + e2; /* timestamp we predict for the next 0xf8 clock message */
 
                midi_clock_count++;
-               should_be_position += one_ppqn_in_samples;
+               current.update (one_ppqn_in_samples, timestamp, 0);
 
        } else {
 
@@ -254,7 +231,7 @@ MIDIClock_TransportMaster::update_midi_clock (Parser& /*parser*/, samplepos_t ti
 
                /* _speed is relative to session tempo map */
 
-               _speed = predicted_clock_interval_in_samples / one_ppqn_in_samples;
+               double speed = predicted_clock_interval_in_samples / one_ppqn_in_samples;
 
                /* _bpm (really, _qpm) is absolute */
 
@@ -278,14 +255,14 @@ MIDIClock_TransportMaster::update_midi_clock (Parser& /*parser*/, samplepos_t ti
                }
 
                midi_clock_count++;
-               should_be_position += one_ppqn_in_samples;
+               current.update (current.position + one_ppqn_in_samples, timestamp, speed);
        }
 
        DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock #%1 @ %2 should-be %3 transport %4 error %5 appspeed %6 "
                                                       "read-delta %7 should-be delta %8 t1-t0 %9 t0 %10 t1 %11 framerate %12 engine %13 running %14\n",
                                                       midi_clock_count,                                          // #
                                                       elapsed_since_start,                                       // @
-                                                      should_be_position,                                        // should-be
+                                                      current.position,                                        // should-be
                                                       _session->transport_sample(),                                // transport
                                                       e,                                                     // error
                                                       (t1 - t0) / one_ppqn_in_samples, // appspeed
@@ -311,7 +288,7 @@ MIDIClock_TransportMaster::start (Parser& /*parser*/, samplepos_t timestamp)
        if (!_running) {
                reset();
                _running = true;
-               should_be_position = _session->transport_sample();
+               current.update (_session->transport_sample(), timestamp, 0);
        }
 }
 
@@ -320,9 +297,7 @@ MIDIClock_TransportMaster::reset ()
 {
        DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MidiClock Master reset(): calculated filter for period size %2\n", ENGINE->samples_per_cycle()));
 
-       should_be_position = _session->transport_sample();
-       _speed = 0;
-       last_timestamp = 0;
+       current.update (_session->transport_sample(), 0, 0);
 
        _running = false;
        _current_delta = 0;
@@ -337,7 +312,7 @@ MIDIClock_TransportMaster::contineu (Parser& /*parser*/, samplepos_t /*timestamp
 }
 
 void
-MIDIClock_TransportMaster::stop (Parser& /*parser*/, samplepos_t /*timestamp*/)
+MIDIClock_TransportMaster::stop (Parser& /*parser*/, samplepos_t timestamp)
 {
        DEBUG_TRACE (DEBUG::MidiClock, "MIDIClock_TransportMaster got stop message\n");
 
@@ -356,12 +331,12 @@ MIDIClock_TransportMaster::stop (Parser& /*parser*/, samplepos_t /*timestamp*/)
                //
                // find out the last MIDI beat: go back #midi_clocks mod 6
                // and lets hope the tempo didnt change in those last 6 beats :)
-               should_be_position -= (midi_clock_count % 6) * one_ppqn_in_samples;
+               current.update (current.position - (midi_clock_count % 6) * one_ppqn_in_samples, timestamp, current.speed);
        }
 }
 
 void
-MIDIClock_TransportMaster::position (Parser& /*parser*/, MIDI::byte* message, size_t size)
+MIDIClock_TransportMaster::position (Parser& /*parser*/, MIDI::byte* message, size_t size, samplepos_t timestamp)
 {
        // we are not supposed to get position messages while we are running
        // so lets be robust and ignore those
@@ -379,9 +354,7 @@ MIDIClock_TransportMaster::position (Parser& /*parser*/, MIDI::byte* message, si
 
        DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Song Position: %1 samples: %2\n", position_in_sixteenth_notes, position_in_samples));
 
-       should_be_position = position_in_samples;
-       last_timestamp = 0;
-
+       current.update (position_in_samples, timestamp, current.speed);
 }
 
 bool
index d110c2a32dec94a939dc9779d62ebbd147a920cc..c081de23b5ed07e785a6294d6511167be9edbeb8 100644 (file)
@@ -132,6 +132,8 @@ MTC_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boos
 {
        /* Read and parse incoming MIDI */
 
+       maybe_reset ();
+
        _midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
 
        if (session_pos) {
@@ -222,18 +224,9 @@ MTC_TransportMaster::reset (bool with_position)
        DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_TransportMaster reset %1\n", with_position?"with position":"without position"));
 
        if (with_position) {
-               last_inbound_frame = 0;
-               current.guard1++;
-               current.position = 0;
-               current.timestamp = 0;
-               current.speed = 0;
-               current.guard2++;
+               current.update (0, 0, 0);
        } else {
-               last_inbound_frame = 0;
-               current.guard1++;
-               current.timestamp = 0;
-               current.speed = 0;
-               current.guard2++;
+               current.update (current.position, 0, 0);
        }
        first_mtc_timestamp = 0;
        window_begin = 0;
@@ -294,8 +287,6 @@ MTC_TransportMaster::update_mtc_qtr (Parser& p, int which_qtr, samplepos_t now)
                DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d));
 
                current.update (mtc_frame, now, mtc_speed);
-
-               last_inbound_frame = now;
        }
 
        maybe_reset ();
@@ -481,9 +472,6 @@ MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samp
                }
        }
 
-       if (now) {
-               last_inbound_frame = now;
-       }
        busy_guard2++;
 }
 
@@ -549,62 +537,6 @@ MTC_TransportMaster::reset_window (samplepos_t root)
        DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
 }
 
-/* main entry point from session_process.cc
-xo * in process callback context */
-bool
-MTC_TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t now)
-{
-       SafeTime last;
-
-       if (!_collect) {
-               return false;
-       }
-
-       current.safe_read (last);
-
-       DEBUG_TRACE (DEBUG::MTC, string_compose ("speed&pos: timestamp %1 speed %2 dir %4 now %5 last-in %6\n",
-                                                last.timestamp,
-                                                last.speed,
-                                                transport_direction,
-                                                now,
-                                                last_inbound_frame));
-
-       if (last.timestamp == 0) {
-               return false;
-       }
-
-       if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
-               /* no timecode for two cycles - conclude that it's stopped */
-
-               if (!Config->get_transport_masters_just_roll_when_sync_lost()) {
-                       speed = 0;
-                       pos = last.position;
-                       _current_delta = 0;
-                       queue_reset (false);
-                       DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC not seen for 2 samples - reset pending, pos = %1\n", pos));
-                       return false;
-               }
-       }
-
-
-       DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position mtc-tme: %1 mtc-pos: %2 mtc-spd: %3\n", last.timestamp, last.position, last.speed));
-
-       speed = last.speed;
-
-       /* provide a .1% deadzone to lock the speed */
-       if (fabs (speed - 1.0) <= 0.001) {
-               speed = 1.0;
-       }
-
-       pos =  last.position;
-       pos += (now - last.timestamp) * speed;
-
-       DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 | elapsed: %4\n",
-                                                speed, pos, last.position, (now - last.timestamp)));
-
-       return true;
-}
-
 Timecode::TimecodeFormat
 MTC_TransportMaster::apparent_timecode_format () const
 {
index 95daf7495bfe22332b19f1791938ac7a81616de7..cf10cf11c7d8b4199fd56be3e91d2909335019c3 100644 (file)
@@ -1119,8 +1119,9 @@ Session::start_locate (samplepos_t target_sample, bool with_roll, bool with_flus
 
                double sp;
                samplepos_t pos;
+               samplepos_t ignore1, ignore2;
 
-               transport_master()->speed_and_position (sp, pos, 0);
+               transport_master()->speed_and_position (sp, pos, ignore1, ignore2, 0);
 
                if (target_sample != pos) {
 
index 4dec88272aadb7c9f42422c0e4c1b6b2b3ac1b7d..135e022dbffebaab50c4a19039affe7550fa18de 100644 (file)
@@ -22,6 +22,7 @@
 #include "pbd/debug.h"
 
 #include "ardour/audioengine.h"
+#include "ardour/debug.h"
 #include "ardour/midi_port.h"
 #include "ardour/session.h"
 #include "ardour/transport_master.h"
@@ -84,6 +85,59 @@ TransportMaster::~TransportMaster()
        delete _session;
 }
 
+bool
+TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t& lp, samplepos_t& when, samplepos_t now)
+{
+       if (!_collect) {
+               return false;
+       }
+
+       SafeTime last;
+       current.safe_read (last);
+
+       if (last.timestamp == 0) {
+               return false;
+       }
+
+       if (last.timestamp && now > last.timestamp && now - last.timestamp > labs (seekahead_distance())) {
+               /* no timecode for two cycles - conclude that it's stopped */
+
+               if (!Config->get_transport_masters_just_roll_when_sync_lost()) {
+                       speed = 0;
+                       pos = last.position;
+                       lp = last.position;
+                       when = last.timestamp;
+                       _current_delta = 0;
+                       // queue_reset (false);
+                       DEBUG_TRACE (DEBUG::Slave, string_compose ("%1 not seen for 2 samples - reset pending, pos = %2\n", name(), pos));
+                       return false;
+               }
+       }
+
+       lp = last.position;
+       when = last.timestamp;
+       speed = last.speed;
+       pos   = last.position + (now - last.timestamp) * last.speed;
+
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("%1: speed_and_position tme: %2 pos: %3 spd: %4\n", name(), last.timestamp, last.position, last.speed));
+
+       lp = last.position;
+       when = last.timestamp;
+       speed = last.speed;
+
+       /* provide a .1% deadzone to lock the speed */
+       if (fabs (speed - 1.0) <= 0.001) {
+               speed = 1.0;
+       }
+
+       pos = last.position + (now - last.timestamp) * speed;
+
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("%1 sync spd: %2 pos: %3 | last-pos: %4 | elapsed: %5\n",
+                                                  name(), speed, pos, last.position, (now - last.timestamp)));
+
+       return true;
+}
+
 void
 TransportMaster::register_properties ()
 {
index 80d62b3adcbab5061f65d1dcc50363e9e2b4a575..dee67bc6edb4249f753611b47a2eb7c7c798c5fd 100644 (file)
@@ -175,8 +175,9 @@ TransportMasterManager::pre_process_transport_masters (pframes_t nframes, sample
        }
 
        double engine_speed;
+       samplepos_t ignore1, ignore2;
 
-       if (!_current_master->speed_and_position (_master_speed, _master_position, now)) {
+       if (!_current_master->speed_and_position (_master_speed, _master_position, ignore1, ignore2, now)) {
                return 1.0;
        }