+ PIChaser* pic;
+
+ static const int frame_tolerance;
+
+ SafeTime current;
+ framepos_t mtc_frame; /* current time */
+ framepos_t last_inbound_frame; /* when we got it; audio clocked */
+ MIDI::byte last_mtc_fps_byte;
+ framepos_t window_begin;
+ framepos_t window_end;
+ framepos_t last_mtc_timestamp;
+ framepos_t last_mtc_frame;
+ bool did_reset_tc_format;
+ TimecodeFormat saved_tc_format;
+ size_t speed_accumulator_size;
+ double* speed_accumulator;
+ size_t speed_accumulator_cnt;
+ bool have_first_speed_accumulator;
+ double average_speed;
+ Glib::Mutex reset_lock;
+ uint32_t reset_pending;
+ bool reset_position;
+
+ void reset (bool with_pos);
+ void queue_reset (bool with_pos);
+ void maybe_reset ();
+
+ void update_mtc_qtr (MIDI::Parser&, int, framepos_t);
+ void update_mtc_time (const MIDI::byte *, bool, framepos_t);
+ void update_mtc_status (MIDI::MTC_Status);
+ void read_current (SafeTime *) const;
+ void reset_window (framepos_t);
+ bool outside_window (framepos_t) const;
+ void process_apparent_speed (double);
+};
+
+class MIDIClock_Slave : public Slave {
+ public:
+ MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24);
+
+ /// Constructor for unit tests
+ MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24);
+ ~MIDIClock_Slave ();
+
+ void rebind (MIDI::Port&);
+ bool speed_and_position (double&, framepos_t&);
+
+ bool locked() const;
+ bool ok() const;
+ bool starting() const;
+
+ framecnt_t resolution () const;
+ bool requires_seekahead () const { return false; }
+ bool give_slave_full_control_over_transport_speed() const { return true; }
+
+ void set_bandwidth (double a_bandwith) { bandwidth = a_bandwith; }
+
+ protected:
+ ISlaveSessionProxy* session;
+ MIDI::Port* port;
+ PBD::ScopedConnectionList port_connections;
+
+ /// pulses per quarter note for one MIDI clock frame (default 24)
+ int ppqn;
+
+ /// the duration of one ppqn in frame time
+ double one_ppqn_in_frames;
+
+ /// the timestamp of the first MIDI clock message
+ framepos_t first_timestamp;