MTC-slave: print error if framerate mismatch
[ardour.git] / libs / ardour / ardour / slave.h
1 /*
2     Copyright (C) 2002 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #ifndef __ardour_slave_h__
21 #define __ardour_slave_h__
22
23 #include <vector>
24
25 #include <glibmm/threads.h>
26
27 #include <jack/jack.h>
28
29 #include "pbd/signals.h"
30
31 #include "ardour/types.h"
32 #include "midi++/parser.h"
33 #include "midi++/types.h"
34
35 namespace MIDI {
36         class Port;
37 }
38
39 namespace ARDOUR {
40
41 class TempoMap;
42 class Session;
43
44 /**
45  * @class Slave
46  *
47  * @brief The Slave interface can be used to sync ARDOURs tempo to an external source
48  * like MTC, MIDI Clock, etc.
49  *
50  * The name of the interface may be a bit misleading: A subclass of Slave actually
51  * acts as a time master for ARDOUR, that means ARDOUR will try to follow the
52  * speed and transport position of the implementation of Slave.
53  * Therefore it is rather that class, that makes ARDOUR a slave by connecting it
54  * to its external time master.
55  */
56 class Slave {
57   public:
58         Slave() { }
59         virtual ~Slave() {}
60
61         /**
62          * This is the most important function to implement:
63          * Each process cycle, Session::follow_slave will call this method.
64          *  and after the method call they should
65          *
66          * Session::follow_slave will then try to follow the given
67          * <em>position</em> using a delay locked loop (DLL),
68          * starting with the first given transport speed.
69          * If the values of speed and position contradict each other,
70          * ARDOUR will always follow the position and disregard the speed.
71          * Although, a correct speed is important so that ARDOUR
72          * can sync to the master time source quickly.
73          *
74          * For background information on delay locked loops,
75          * see http://www.kokkinizita.net/papers/usingdll.pdf
76          *
77          * The method has the following precondition:
78          * <ul>
79          *   <li>
80          *       Slave::ok() should return true, otherwise playback will stop
81          *       immediately and the method will not be called
82          *   </li>
83          *   <li>
84          *     when the references speed and position are passed into the Slave
85          *     they are uninitialized
86          *   </li>
87          * </ul>
88          *
89          * After the method call the following postconditions should be met:
90          * <ul>
91          *    <li>
92          *       The first position value on transport start should be 0,
93          *       otherwise ARDOUR will try to locate to the new position
94          *       rather than move to it
95          *    </li>
96          *    <li>
97          *      the references speed and position should be assigned
98          *      to the Slaves current requested transport speed
99          *      and transport position.
100          *    </li>
101          *   <li>
102          *     Slave::resolution() should be greater than the maximum distance of
103          *     ARDOURs transport position to the slaves requested transport position.
104          *   </li>
105          *   <li>Slave::locked() should return true, otherwise Session::no_roll will be called</li>
106          *   <li>Slave::starting() should be false, otherwise the transport will not move until it becomes true</li>     *
107          * </ul>
108          *
109          * @param speed - The transport speed requested
110          * @param position - The transport position requested
111          * @return - The return value is currently ignored (see Session::follow_slave)
112          */
113         virtual bool speed_and_position (double& speed, framepos_t& position) = 0;
114
115         /**
116          * reports to ARDOUR whether the Slave is currently synced to its external
117          * time source.
118          *
119          * @return - when returning false, the transport will stop rolling
120          */
121         virtual bool locked() const = 0;
122
123         /**
124          * reports to ARDOUR whether the slave is in a sane state
125          *
126          * @return - when returning false, the transport will be stopped and the slave
127          * disconnected from ARDOUR.
128          */
129         virtual bool ok() const = 0;
130
131         /**
132          * reports to ARDOUR whether the slave is in the process of starting
133          * to roll
134          *
135          * @return - when returning false, transport will not move until this method returns true
136          */
137         virtual bool starting() const { return false; }
138
139         /**
140          * @return - the timing resolution of the Slave - If the distance of ARDOURs transport
141          * to the slave becomes greater than the resolution, sound will stop
142          */
143         virtual framecnt_t resolution() const = 0;
144
145         /**
146          * @return - when returning true, ARDOUR will wait for seekahead_distance() before transport
147          * starts rolling
148          */
149         virtual bool requires_seekahead () const = 0;
150
151         /**
152          * @return the number of frames that this slave wants to seek ahead. Relevant
153          * only if requires_seekahead() returns true.
154          */
155
156         virtual framecnt_t seekahead_distance() const { return 0; }
157
158         /**
159          * @return - when returning true, ARDOUR will use transport speed 1.0 no matter what
160          *           the slave returns
161          */
162         virtual bool is_always_synced() const { return false; }
163
164         /**
165          * @return - whether ARDOUR should use the slave speed without any adjustments
166          */
167         virtual bool give_slave_full_control_over_transport_speed() const { return false; }
168 };
169
170 /// We need this wrapper for testability, it's just too hard to mock up a session class
171 class ISlaveSessionProxy {
172   public:
173         virtual ~ISlaveSessionProxy() {}
174         virtual TempoMap&  tempo_map()                 const   { return *((TempoMap *) 0); }
175         virtual framecnt_t frame_rate()                const   { return 0; }
176         virtual framepos_t audible_frame ()            const   { return 0; }
177         virtual framepos_t transport_frame ()          const   { return 0; }
178         virtual pframes_t  frames_since_cycle_start () const   { return 0; }
179         virtual framepos_t frame_time ()               const   { return 0; }
180
181         virtual void request_locate (framepos_t /*frame*/, bool with_roll = false) {
182                 (void) with_roll;
183         }
184         virtual void request_transport_speed (double /*speed*/)                   {}
185 };
186
187
188 /// The Session Proxy for use in real Ardour
189 class SlaveSessionProxy : public ISlaveSessionProxy {
190         Session&    session;
191
192   public:
193         SlaveSessionProxy(Session &s) : session(s) {}
194
195         TempoMap&  tempo_map()                 const;
196         framecnt_t frame_rate()                const;
197         framepos_t audible_frame ()            const;
198         framepos_t transport_frame ()          const;
199         pframes_t  frames_since_cycle_start () const;
200         framepos_t frame_time ()               const;
201
202         void request_locate (framepos_t frame, bool with_roll = false);
203         void request_transport_speed (double speed);
204 };
205
206 struct SafeTime {
207         volatile int guard1;
208         framepos_t   position;
209         framepos_t   timestamp;
210         double       speed;
211         volatile int guard2;
212
213         SafeTime() {
214                 guard1 = 0;
215                 position = 0;
216                 timestamp = 0;
217                 speed = 0;
218                 guard2 = 0;
219         }
220 };
221
222 class MTC_Slave : public Slave {
223   public:
224         MTC_Slave (Session&, MIDI::Port&);
225         ~MTC_Slave ();
226
227         void rebind (MIDI::Port&);
228         bool speed_and_position (double&, framepos_t&);
229
230         bool locked() const;
231         bool ok() const;
232         void handle_locate (const MIDI::byte*);
233
234         framecnt_t resolution () const;
235         bool requires_seekahead () const { return true; }
236         framecnt_t seekahead_distance() const;
237         bool give_slave_full_control_over_transport_speed() const;
238
239   private:
240         Session&    session;
241         MIDI::Port* port;
242         PBD::ScopedConnectionList port_connections;
243         bool        can_notify_on_unknown_rate;
244
245         static const int frame_tolerance;
246
247         SafeTime       current;
248         framepos_t     mtc_frame;               /* current time */
249         framepos_t     last_inbound_frame;      /* when we got it; audio clocked */
250         MIDI::byte     last_mtc_fps_byte;
251         framepos_t     window_begin;
252         framepos_t     window_end;
253         framepos_t     first_mtc_timestamp;
254         bool           did_reset_tc_format;
255         TimecodeFormat saved_tc_format;
256         Glib::Threads::Mutex    reset_lock;
257         uint32_t       reset_pending;
258         bool           reset_position;
259         int            transport_direction;
260         int            busy_guard1;
261         int            busy_guard2;
262
263         TimecodeFormat mtc_timecode;
264         TimecodeFormat a3e_timecode;
265         bool           printed_timecode_warning;
266
267         /* DLL - chase MTC */
268         double t0; ///< time at the beginning of the MTC quater frame
269         double t1; ///< calculated end of the MTC quater frame
270         double e2; ///< second order loop error
271         double b, c, omega; ///< DLL filter coefficients
272
273         /* DLL - sync engine */
274         int    engine_dll_initstate;
275         double te0; ///< time at the beginning of the engine process
276         double te1; ///< calculated sync time
277         double ee2; ///< second order loop error
278         double be, ce, oe; ///< DLL filter coefficients
279
280         void reset (bool with_pos);
281         void queue_reset (bool with_pos);
282         void maybe_reset ();
283
284         void update_mtc_qtr (MIDI::Parser&, int, framepos_t);
285         void update_mtc_time (const MIDI::byte *, bool, framepos_t);
286         void update_mtc_status (MIDI::MTC_Status);
287         void read_current (SafeTime *) const;
288         void reset_window (framepos_t);
289         bool outside_window (framepos_t) const;
290         void init_mtc_dll(framepos_t, double);
291         void init_engine_dll (framepos_t, framepos_t);
292 };
293
294 class MIDIClock_Slave : public Slave {
295   public:
296         MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24);
297
298         /// Constructor for unit tests
299         MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24);
300         ~MIDIClock_Slave ();
301
302         void rebind (MIDI::Port&);
303         bool speed_and_position (double&, framepos_t&);
304
305         bool locked() const;
306         bool ok() const;
307         bool starting() const;
308
309         framecnt_t resolution () const;
310         bool requires_seekahead () const { return false; }
311         bool give_slave_full_control_over_transport_speed() const { return true; }
312
313         void set_bandwidth (double a_bandwith) { bandwidth = a_bandwith; }
314
315   protected:
316         ISlaveSessionProxy* session;
317         MIDI::Port* port;
318         PBD::ScopedConnectionList port_connections;
319
320         /// pulses per quarter note for one MIDI clock frame (default 24)
321         int         ppqn;
322
323         /// the duration of one ppqn in frame time
324         double      one_ppqn_in_frames;
325
326         /// the timestamp of the first MIDI clock message
327         framepos_t  first_timestamp;
328
329         /// the time stamp and should-be transport position of the last inbound MIDI clock message
330         framepos_t  last_timestamp;
331         double      should_be_position;
332
333         /// the number of midi clock messages received (zero-based)
334         /// since start
335         long midi_clock_count;
336
337         //the delay locked loop (DLL), see www.kokkinizita.net/papers/usingdll.pdf
338
339         /// time at the beginning of the MIDI clock frame
340         double t0;
341
342         /// calculated end of the MIDI clock frame
343         double t1;
344
345         /// loop error = real value - expected value
346         double e;
347
348         /// second order loop error
349         double e2;
350
351         /// DLL filter bandwidth
352         double bandwidth;
353
354         /// DLL filter coefficients
355         double b, c, omega;
356
357         void reset ();
358         void start (MIDI::Parser& parser, framepos_t timestamp);
359         void contineu (MIDI::Parser& parser, framepos_t timestamp);
360         void stop (MIDI::Parser& parser, framepos_t timestamp);
361         void position (MIDI::Parser& parser, MIDI::byte* message, size_t size);
362         // we can't use continue because it is a C++ keyword
363         void calculate_one_ppqn_in_frames_at(framepos_t time);
364         framepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
365         void calculate_filter_coefficients();
366         void update_midi_clock (MIDI::Parser& parser, framepos_t timestamp);
367         void read_current (SafeTime *) const;
368         bool stop_if_no_more_clock_events(framepos_t& pos, framepos_t now);
369
370         /// whether transport should be rolling
371         bool _started;
372
373         /// is true if the MIDI Start message has just been received until
374         /// the first MIDI Clock Event
375         bool _starting;
376 };
377
378 class JACK_Slave : public Slave
379 {
380   public:
381         JACK_Slave (jack_client_t*);
382         ~JACK_Slave ();
383
384         bool speed_and_position (double& speed, framepos_t& pos);
385
386         bool starting() const { return _starting; }
387         bool locked() const;
388         bool ok() const;
389         framecnt_t resolution () const { return 1; }
390         bool requires_seekahead () const { return false; }
391         void reset_client (jack_client_t* jack);
392         bool is_always_synced() const { return true; }
393
394   private:
395         jack_client_t* jack;
396         double speed;
397         bool _starting;
398 };
399
400 } /* namespace */
401
402 #endif /* __ardour_slave_h__ */