2 Copyright (C) 2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #ifndef __ardour_transport_master_h__
21 #define __ardour_transport_master_h__
25 #include <boost/optional.hpp>
26 #include <boost/atomic.hpp>
28 #include <glibmm/threads.h>
29 #include <glibmm/timer.h>
34 #include "pbd/properties.h"
35 #include "pbd/signals.h"
36 #include "pbd/statefuldestructible.h"
38 #include "temporal/time.h"
40 #include "ardour/libardour_visibility.h"
41 #include "ardour/region.h" /* for Properties::locked */
42 #include "ardour/types.h"
44 #include "midi++/parser.h"
45 #include "midi++/types.h"
47 /* used for delta_string(): */
48 #define PLUSMINUS(A) ( ((A)<0) ? "-" : (((A)>0) ? "+" : "\u00B1") )
49 #define LEADINGZERO(A) ( (A)<10 ? " " : (A)<100 ? " " : (A)<1000 ? " " : "" )
61 namespace Properties {
62 LIBARDOUR_API extern PBD::PropertyDescriptor<bool> fr2997;
63 LIBARDOUR_API extern PBD::PropertyDescriptor<bool> collect;
64 LIBARDOUR_API extern PBD::PropertyDescriptor<bool> connected;
65 LIBARDOUR_API extern PBD::PropertyDescriptor<bool> sclock_synced;
66 LIBARDOUR_API extern PBD::PropertyDescriptor<ARDOUR::TransportRequestType> allowed_transport_requests;
69 struct LIBARDOUR_API SafeTime {
71 /* This object uses memory fences to provide psuedo-atomic updating of
72 * non-atomic data. If after reading guard1 and guard2 with correct
73 * memory fencing they have the same value, then we know that the other
74 * members are all internally consistent.
76 * Traditionally, one might do this with a mutex, but this object
77 * provides lock-free write update. The reader might block while
78 * waiting for consistency, but this is extraordinarily unlikely. In
79 * this sense, the design is similar to a spinlock.
81 * any update starts by incrementing guard1, with a memory fence to
82 * ensure no reordering of this w.r.t later operations.
84 * then we update the "non-atomic" data members.
86 * then we update guard2, with another memory fence to prevent
89 * ergo, if guard1 == guard2, the update of the non-atomic members is
90 * complete and the values stored there are consistent.
93 boost::atomic<int> guard1;
95 samplepos_t timestamp;
97 boost::atomic<int> guard2;
115 void update (samplepos_t p, samplepos_t t, double s) {
116 guard1.fetch_add (1, boost::memory_order_acquire);
120 guard2.fetch_add (1, boost::memory_order_acquire);
123 void safe_read (SafeTime& dst) const {
128 std::cerr << X_("SafeTime: atomic read of current time failed, sleeping!") << std::endl;
132 dst.guard1.store (guard1.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
133 dst.position = position;
134 dst.timestamp = timestamp;
136 dst.guard2.store (guard2.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
139 } while (dst.guard1.load (boost::memory_order_seq_cst) != dst.guard2.load (boost::memory_order_seq_cst));
144 * @class TransportMaster
146 * @brief The TransportMaster interface can be used to sync ARDOURs tempo to an external source
147 * like MTC, MIDI Clock, etc. as well as a single internal pseudo master we
148 * call "UI" because it is controlled from any of the user interfaces for
149 * Ardour (GUI, control surfaces, OSC, etc.)
152 class LIBARDOUR_API TransportMaster : public PBD::Stateful {
155 TransportMaster (SyncSource t, std::string const & name);
156 virtual ~TransportMaster();
158 static boost::shared_ptr<TransportMaster> factory (SyncSource, std::string const &, bool removeable);
159 static boost::shared_ptr<TransportMaster> factory (XMLNode const &);
161 virtual void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>) = 0;
164 * This is the most important function to implement:
165 * Each process cycle, Session::follow_slave will call this method.
166 * and after the method call they should
168 * Session::follow_slave will then try to follow the given
169 * <em>position</em> using a delay locked loop (DLL),
170 * starting with the first given transport speed.
171 * If the values of speed and position contradict each other,
172 * ARDOUR will always follow the position and disregard the speed.
173 * Although, a correct speed is important so that ARDOUR
174 * can sync to the master time source quickly.
176 * For background information on delay locked loops,
177 * see http://www.kokkinizita.net/papers/usingdll.pdf
179 * The method has the following precondition:
182 * TransportMaster::ok() should return true, otherwise playback will stop
183 * immediately and the method will not be called
186 * when the references speed and position are passed into the TransportMaster
187 * they are uninitialized
191 * After the method call the following postconditions should be met:
194 * The first position value on transport start should be 0,
195 * otherwise ARDOUR will try to locate to the new position
196 * rather than move to it
199 * the references speed and position should be assigned
200 * to the TransportMasters current requested transport speed
201 * and transport position.
204 * TransportMaster::resolution() should be greater than the maximum distance of
205 * ARDOURs transport position to the slaves requested transport position.
207 * <li>TransportMaster::locked() should return true, otherwise Session::no_roll will be called</li>
208 * <li>TransportMaster::starting() should be false, otherwise the transport will not move until it becomes true</li>
211 * @param speed - The transport speed requested
212 * @param position - The transport position requested
213 * @return - The return value is currently ignored (see Session::follow_slave)
215 virtual bool speed_and_position (double& speed, samplepos_t& position, samplepos_t & lp, samplepos_t & when, samplepos_t now);
217 virtual void reset (bool with_position) = 0;
220 * reports to ARDOUR whether the TransportMaster is currently synced to its external
223 * @return - when returning false, the transport will stop rolling
225 virtual bool locked() const = 0;
228 * reports to ARDOUR whether the slave is in a sane state
230 * @return - when returning false, the transport will be stopped and the slave
231 * disconnected from ARDOUR.
233 virtual bool ok() const = 0;
236 * reports to ARDOUR whether the slave is in the process of starting
239 * @return - when returning false, transport will not move until this method returns true
241 virtual bool starting() const { return false; }
244 * @return - the timing resolution of the TransportMaster - If the distance of ARDOURs transport
245 * to the slave becomes greater than the resolution, sound will stop
247 virtual samplecnt_t resolution() const = 0;
250 * @return - the expected update interval for the data source used by
251 * this transport master. Even if the data is effectively continuous,
252 * this number indicates how long it is between changes to the known
253 * position of the master.
255 virtual samplecnt_t update_interval() const = 0;
258 * @return - when returning true, ARDOUR will wait for seekahead_distance() before transport
261 virtual bool requires_seekahead () const = 0;
264 * @return the number of samples that this slave wants to seek ahead. Relevant
265 * only if requires_seekahead() returns true.
268 virtual samplecnt_t seekahead_distance() const { return 0; }
271 * @return - when returning true, ARDOUR will use transport speed 1.0 no matter what
274 virtual bool sample_clock_synced() const { return _sclock_synced; }
275 virtual void set_sample_clock_synced (bool);
278 * @return - current time-delta between engine and sync-source
280 virtual std::string delta_string() const { return ""; }
282 sampleoffset_t current_delta() const { return _current_delta; }
284 /* this is intended to be used by a UI and polled from a timeout. it should
285 return a string describing the current position of the TC source. it
286 should NOT do any computation, but should use a cached value
287 of the TC source position.
289 virtual std::string position_string() const = 0;
291 virtual bool can_loop() const { return false; }
293 virtual Location* loop_location() const { return 0; }
294 bool has_loop() const { return loop_location() != 0; }
296 SyncSource type() const { return _type; }
297 TransportRequestSource request_type() const {
299 case Engine: /* also JACK */
308 return TRS_MIDIClock;
311 std::string name() const { return _name; }
312 void set_name (std::string const &);
314 int set_state (XMLNode const &, int);
315 XMLNode& get_state();
317 static const std::string state_node_name;
318 static void make_property_quarks ();
320 virtual void set_session (Session*);
322 boost::shared_ptr<Port> port() const { return _port; }
324 bool check_collect();
325 virtual void set_collect (bool);
326 bool collect() const { return _collect; }
328 /* called whenever the manager starts collecting (processing) this
329 transport master. Typically will re-initialize any state used to
330 deal with incoming data.
332 virtual void init() = 0;
334 virtual void check_backend() {}
335 virtual bool allow_request (TransportRequestSource, TransportRequestType) const;
337 TransportRequestType request_mask() const { return _request_mask; }
338 void set_request_mask (TransportRequestType);
340 void get_current (double&, samplepos_t&, samplepos_t);
342 /* this is set at construction, and not changeable later, so it is not
346 bool removeable () const { return _removeable; }
347 void set_removeable (bool yn) { _removeable = yn; }
349 std::string display_name (bool sh/*ort*/ = true) const;
351 virtual void unregister_port ();
355 PBD::Property<std::string> _name;
357 sampleoffset_t _current_delta;
358 bool _pending_collect;
360 PBD::Property<TransportRequestType> _request_mask; /* lists transport requests still accepted when we're in control */
361 PBD::Property<bool> _sclock_synced;
362 PBD::Property<bool> _collect;
363 PBD::Property<bool> _connected;
367 /* DLL - chase incoming data */
369 int transport_direction;
377 boost::shared_ptr<Port> _port;
379 PBD::ScopedConnection port_connection;
380 bool connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn);
382 PBD::ScopedConnection backend_connection;
384 virtual void register_properties ();
387 /** a helper class for any TransportMaster that receives its input via a MIDI
390 class LIBARDOUR_API TransportMasterViaMIDI {
392 boost::shared_ptr<MidiPort> midi_port() const { return _midi_port; }
393 boost::shared_ptr<Port> create_midi_port (std::string const & port_name);
396 TransportMasterViaMIDI () {};
399 boost::shared_ptr<MidiPort> _midi_port;
402 class LIBARDOUR_API TimecodeTransportMaster : public TransportMaster {
404 TimecodeTransportMaster (std::string const & name, SyncSource type);
406 virtual Timecode::TimecodeFormat apparent_timecode_format() const = 0;
407 samplepos_t timecode_offset;
408 bool timecode_negative_offset;
410 bool fr2997() const { return _fr2997; }
411 void set_fr2997 (bool);
414 void register_properties ();
417 PBD::Property<bool> _fr2997;
420 class LIBARDOUR_API MTC_TransportMaster : public TimecodeTransportMaster, public TransportMasterViaMIDI {
422 MTC_TransportMaster (std::string const &);
423 ~MTC_TransportMaster ();
425 void set_session (Session*);
427 void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
429 void unregister_port ();
431 void reset (bool with_pos);
434 void handle_locate (const MIDI::byte*);
436 samplecnt_t update_interval () const;
437 samplecnt_t resolution () const;
438 bool requires_seekahead () const { return false; }
439 samplecnt_t seekahead_distance() const;
442 Timecode::TimecodeFormat apparent_timecode_format() const;
443 std::string position_string() const;
444 std::string delta_string() const;
447 PBD::ScopedConnectionList port_connections;
448 PBD::ScopedConnection config_connection;
449 bool can_notify_on_unknown_rate;
451 static const int sample_tolerance;
453 samplepos_t mtc_frame; /* current time */
454 double mtc_frame_dll;
455 samplepos_t last_inbound_frame; /* when we got it; audio clocked */
456 MIDI::byte last_mtc_fps_byte;
457 samplepos_t window_begin;
458 samplepos_t window_end;
459 samplepos_t first_mtc_timestamp;
460 bool did_reset_tc_format;
461 Timecode::TimecodeFormat saved_tc_format;
462 Glib::Threads::Mutex reset_lock;
463 uint32_t reset_pending;
465 int transport_direction;
469 double speedup_due_to_tc_mismatch;
470 double quarter_frame_duration;
471 Timecode::TimecodeFormat mtc_timecode;
472 Timecode::TimecodeFormat a3e_timecode;
473 Timecode::Time timecode;
474 bool printed_timecode_warning;
476 void queue_reset (bool with_pos);
479 void update_mtc_qtr (MIDI::Parser&, int, samplepos_t);
480 void update_mtc_time (const MIDI::byte *, bool, samplepos_t);
481 void update_mtc_status (MIDI::MTC_Status);
482 void reset_window (samplepos_t);
483 bool outside_window (samplepos_t) const;
484 void init_mtc_dll(samplepos_t, double);
485 void parse_timecode_offset();
486 void parameter_changed(std::string const & p);
489 class LIBARDOUR_API LTC_TransportMaster : public TimecodeTransportMaster {
491 LTC_TransportMaster (std::string const &);
492 ~LTC_TransportMaster ();
494 void set_session (Session*);
496 void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
498 void reset (bool with_pos);
502 samplecnt_t update_interval () const;
503 samplecnt_t resolution () const;
504 bool requires_seekahead () const { return false; }
505 samplecnt_t seekahead_distance () const { return 0; }
508 Timecode::TimecodeFormat apparent_timecode_format() const;
509 std::string position_string() const;
510 std::string delta_string() const;
513 void parse_ltc(const pframes_t, const Sample* const, const samplecnt_t);
514 void process_ltc(samplepos_t const);
515 void init_dll (samplepos_t, int32_t);
516 bool detect_discontinuity(LTCFrameExt *, int, bool);
517 bool detect_ltc_fps(int, bool);
518 bool equal_ltc_sample_time(LTCFrame *a, LTCFrame *b);
520 void resync_latency();
521 void parse_timecode_offset();
522 void parameter_changed(std::string const & p);
524 bool did_reset_tc_format;
525 Timecode::TimecodeFormat saved_tc_format;
527 LTCDecoder * decoder;
528 double samples_per_ltc_frame;
529 Timecode::Time timecode;
530 LTCFrameExt prev_frame;
533 samplecnt_t monotonic_cnt;
534 uint64_t frames_since_reset;
537 int ltc_detect_fps_cnt;
538 int ltc_detect_fps_max;
539 bool printed_timecode_warning;
540 bool sync_lock_broken;
541 Timecode::TimecodeFormat ltc_timecode;
542 Timecode::TimecodeFormat a3e_timecode;
543 double samples_per_timecode_frame;
545 PBD::ScopedConnectionList port_connections;
546 PBD::ScopedConnection config_connection;
547 LatencyRange ltc_slave_latency;
550 class LIBARDOUR_API MIDIClock_TransportMaster : public TransportMaster, public TransportMasterViaMIDI {
552 MIDIClock_TransportMaster (std::string const & name, int ppqn = 24);
554 /// Constructor for unit tests
555 ~MIDIClock_TransportMaster ();
557 void set_session (Session*);
559 void unregister_port ();
561 void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
563 void rebind (MidiPort&);
565 void reset (bool with_pos);
568 bool starting() const;
570 samplecnt_t update_interval () const;
571 samplecnt_t resolution () const;
572 bool requires_seekahead () const { return false; }
575 std::string position_string() const;
576 std::string delta_string() const;
578 float bpm() const { return _bpm; }
581 PBD::ScopedConnectionList port_connections;
583 /// pulses per quarter note for one MIDI clock sample (default 24)
586 /// the duration of one ppqn in sample time
587 double one_ppqn_in_samples;
589 /// the timestamp of the first MIDI clock message
590 samplepos_t first_timestamp;
592 /// the time stamp and should-be transport position of the last inbound MIDI clock message
593 samplepos_t last_timestamp;
594 double should_be_position;
596 /// the number of midi clock messages received (zero-based)
598 long midi_clock_count;
600 /// a DLL to track MIDI clock
606 void start (MIDI::Parser& parser, samplepos_t timestamp);
607 void contineu (MIDI::Parser& parser, samplepos_t timestamp);
608 void stop (MIDI::Parser& parser, samplepos_t timestamp);
609 void position (MIDI::Parser& parser, MIDI::byte* message, size_t size, samplepos_t timestamp);
610 // we can't use continue because it is a C++ keyword
611 void calculate_one_ppqn_in_samples_at(samplepos_t time);
612 samplepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
613 void calculate_filter_coefficients (double qpm);
614 void update_midi_clock (MIDI::Parser& parser, samplepos_t timestamp);
617 class LIBARDOUR_API Engine_TransportMaster : public TransportMaster
620 Engine_TransportMaster (AudioEngine&);
621 ~Engine_TransportMaster ();
623 void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
624 bool speed_and_position (double& speed, samplepos_t& pos, samplepos_t &, samplepos_t &, samplepos_t);
626 bool starting() const { return _starting; }
627 void reset (bool with_position);
630 samplecnt_t update_interval () const;
631 samplecnt_t resolution () const { return 1; }
632 bool requires_seekahead () const { return false; }
633 bool sample_clock_synced() const { return true; }
635 void check_backend();
636 bool allow_request (TransportRequestSource, TransportRequestType) const;
638 std::string position_string() const;
639 std::string delta_string() const;
648 #endif /* __ardour_transport_master_h__ */