X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fardour%2Fslave.h;h=74cf4371b0e801e592512514a22aacfad0e44d76;hb=ba0458cf1f6c69366e89631d8fff916ad183d768;hp=16e11097ead472086a00119425dce8220665dc43;hpb=9e9cb3bf31a8cbf00ecf43ea0c3acd8b8bb86760;p=ardour.git diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index 16e11097ea..74cf4371b0 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -22,13 +22,19 @@ #include +#include +#include + #include -#include +#include "pbd/signals.h" + #include "ardour/types.h" #include "midi++/parser.h" #include "midi++/types.h" +class PIChaser; + namespace MIDI { class Port; } @@ -61,7 +67,7 @@ class Slave { * and after the method call they should * * Session::follow_slave will then try to follow the given - * position using a delay locked loop (DLL), + * position using a delay locked loop (DLL), * starting with the first given transport speed. * If the values of speed and position contradict each other, * ARDOUR will always follow the position and disregard the speed. @@ -107,7 +113,7 @@ class Slave { * @param position - The transport position requested * @return - The return value is currently ignored (see Session::follow_slave) */ - virtual bool speed_and_position (double& speed, nframes64_t& position) = 0; + virtual bool speed_and_position (double& speed, framepos_t& position) = 0; /** * reports to ARDOUR whether the Slave is currently synced to its external @@ -140,11 +146,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 requires_seekahead() returns true. + */ + + virtual framepos_t seekahead_distance() const { return 0; } + /** * @return - when returning true, ARDOUR will use transport speed 1.0 no matter what * the slave returns @@ -160,14 +173,15 @@ class Slave { /// We need this wrapper for testability, it's just too hard to mock up a session class class ISlaveSessionProxy { public: + virtual ~ISlaveSessionProxy() {} virtual TempoMap& tempo_map() const { return *((TempoMap *) 0); } virtual nframes_t frame_rate() const { return 0; } - virtual nframes64_t audible_frame () const { return 0; } - virtual nframes64_t transport_frame () const { return 0; } + virtual framepos_t audible_frame () const { return 0; } + virtual framepos_t transport_frame () const { return 0; } virtual nframes_t frames_since_cycle_start () const { return 0; } - virtual nframes64_t frame_time () const { return 0; } + virtual framepos_t frame_time () const { return 0; } - virtual void request_locate (nframes64_t /*frame*/, bool with_roll = false) { + virtual void request_locate (framepos_t /*frame*/, bool with_roll = false) { (void) with_roll; } virtual void request_transport_speed (double /*speed*/) {} @@ -183,19 +197,19 @@ class SlaveSessionProxy : public ISlaveSessionProxy { TempoMap& tempo_map() const; nframes_t frame_rate() const; - nframes64_t audible_frame () const; - nframes64_t transport_frame () const; + framepos_t audible_frame () const; + framepos_t transport_frame () const; nframes_t frames_since_cycle_start () const; - nframes64_t frame_time () const; + framepos_t frame_time () const; - void request_locate (nframes64_t frame, bool with_roll = false); + void request_locate (framepos_t frame, bool with_roll = false); void request_transport_speed (double speed); }; struct SafeTime { volatile int guard1; - nframes64_t position; - nframes64_t timestamp; + framepos_t position; + framepos_t timestamp; double speed; volatile int guard2; @@ -208,13 +222,13 @@ struct SafeTime { } }; -class MTC_Slave : public Slave, public sigc::trackable { +class MTC_Slave : public Slave { public: MTC_Slave (Session&, MIDI::Port&); ~MTC_Slave (); void rebind (MIDI::Port&); - bool speed_and_position (double&, nframes64_t&); + bool speed_and_position (double&, framepos_t&); bool locked() const; bool ok() const; @@ -222,47 +236,60 @@ class MTC_Slave : public Slave, public sigc::trackable { nframes_t resolution() const; bool requires_seekahead () const { return true; } + framepos_t seekahead_distance() const; + bool give_slave_full_control_over_transport_speed() const; private: Session& session; MIDI::Port* port; - std::vector connections; + PBD::ScopedConnectionList port_connections; bool can_notify_on_unknown_rate; - - 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; - + 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 (); - static const int32_t accumulator_size = 128; - double accumulator[accumulator_size]; - int32_t accumulator_index; - bool have_first_accumulated_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 (framepos_t); + bool outside_window (framepos_t) const; + void process_apparent_speed (double); }; -class MIDIClock_Slave : public Slave, public sigc::trackable { +class MIDIClock_Slave : public Slave { public: MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24); /// Constructor for unit tests - MIDIClock_Slave (ISlaveSessionProxy* session_proxy, int ppqn = 24); + MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24); ~MIDIClock_Slave (); void rebind (MIDI::Port&); - bool speed_and_position (double&, nframes64_t&); + bool speed_and_position (double&, framepos_t&); bool locked() const; bool ok() const; @@ -274,10 +301,10 @@ class MIDIClock_Slave : public Slave, public sigc::trackable { void set_bandwidth (double a_bandwith) { bandwidth = a_bandwith; } - private: + protected: ISlaveSessionProxy* session; MIDI::Port* port; - std::vector connections; + PBD::ScopedConnectionList port_connections; /// pulses per quarter note for one MIDI clock frame (default 24) int ppqn; @@ -317,17 +344,17 @@ class MIDIClock_Slave : public Slave, public sigc::trackable { double b, c, omega; void reset (); - void start (MIDI::Parser& parser, nframes64_t timestamp); - void contineu (MIDI::Parser& parser, nframes64_t timestamp); - void stop (MIDI::Parser& parser, nframes64_t timestamp); + void start (MIDI::Parser& parser, framepos_t timestamp); + void contineu (MIDI::Parser& parser, framepos_t timestamp); + void stop (MIDI::Parser& parser, framepos_t timestamp); void position (MIDI::Parser& parser, MIDI::byte* message, size_t size); // we can't use continue because it is a C++ keyword - void calculate_one_ppqn_in_frames_at(nframes64_t time); - nframes64_t calculate_song_position(uint16_t song_position_in_sixteenth_notes); + void calculate_one_ppqn_in_frames_at(framepos_t time); + framepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes); void calculate_filter_coefficients(); - void update_midi_clock (MIDI::Parser& parser, nframes64_t timestamp); + void update_midi_clock (MIDI::Parser& parser, framepos_t timestamp); void read_current (SafeTime *) const; - bool stop_if_no_more_clock_events(nframes64_t& pos, nframes64_t now); + bool stop_if_no_more_clock_events(framepos_t& pos, framepos_t now); /// whether transport should be rolling bool _started; @@ -337,31 +364,13 @@ 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: JACK_Slave (jack_client_t*); ~JACK_Slave (); - bool speed_and_position (double& speed, nframes64_t& pos); + bool speed_and_position (double& speed, framepos_t& pos); bool starting() const { return _starting; } bool locked() const;