MTC: map between timecodes
[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         Timecode::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         double         speedup_due_to_tc_mismatch;
264         double         quarter_frame_duration;
265         Timecode::TimecodeFormat mtc_timecode;
266         Timecode::TimecodeFormat a3e_timecode;
267         bool           printed_timecode_warning;
268
269         /* DLL - chase MTC */
270         double t0; ///< time at the beginning of the MTC quater frame
271         double t1; ///< calculated end of the MTC quater frame
272         double e2; ///< second order loop error
273         double b, c, omega; ///< DLL filter coefficients
274
275         /* DLL - sync engine */
276         int    engine_dll_initstate;
277         double te0; ///< time at the beginning of the engine process
278         double te1; ///< calculated sync time
279         double ee2; ///< second order loop error
280         double be, ce, oe; ///< DLL filter coefficients
281
282         void reset (bool with_pos);
283         void queue_reset (bool with_pos);
284         void maybe_reset ();
285
286         void update_mtc_qtr (MIDI::Parser&, int, framepos_t);
287         void update_mtc_time (const MIDI::byte *, bool, framepos_t);
288         void update_mtc_status (MIDI::MTC_Status);
289         void read_current (SafeTime *) const;
290         void reset_window (framepos_t);
291         bool outside_window (framepos_t) const;
292         void init_mtc_dll(framepos_t, double);
293         void init_engine_dll (framepos_t, framepos_t);
294 };
295
296 class MIDIClock_Slave : public Slave {
297   public:
298         MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24);
299
300         /// Constructor for unit tests
301         MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24);
302         ~MIDIClock_Slave ();
303
304         void rebind (MIDI::Port&);
305         bool speed_and_position (double&, framepos_t&);
306
307         bool locked() const;
308         bool ok() const;
309         bool starting() const;
310
311         framecnt_t resolution () const;
312         bool requires_seekahead () const { return false; }
313         bool give_slave_full_control_over_transport_speed() const { return true; }
314
315         void set_bandwidth (double a_bandwith) { bandwidth = a_bandwith; }
316
317   protected:
318         ISlaveSessionProxy* session;
319         MIDI::Port* port;
320         PBD::ScopedConnectionList port_connections;
321
322         /// pulses per quarter note for one MIDI clock frame (default 24)
323         int         ppqn;
324
325         /// the duration of one ppqn in frame time
326         double      one_ppqn_in_frames;
327
328         /// the timestamp of the first MIDI clock message
329         framepos_t  first_timestamp;
330
331         /// the time stamp and should-be transport position of the last inbound MIDI clock message
332         framepos_t  last_timestamp;
333         double      should_be_position;
334
335         /// the number of midi clock messages received (zero-based)
336         /// since start
337         long midi_clock_count;
338
339         //the delay locked loop (DLL), see www.kokkinizita.net/papers/usingdll.pdf
340
341         /// time at the beginning of the MIDI clock frame
342         double t0;
343
344         /// calculated end of the MIDI clock frame
345         double t1;
346
347         /// loop error = real value - expected value
348         double e;
349
350         /// second order loop error
351         double e2;
352
353         /// DLL filter bandwidth
354         double bandwidth;
355
356         /// DLL filter coefficients
357         double b, c, omega;
358
359         void reset ();
360         void start (MIDI::Parser& parser, framepos_t timestamp);
361         void contineu (MIDI::Parser& parser, framepos_t timestamp);
362         void stop (MIDI::Parser& parser, framepos_t timestamp);
363         void position (MIDI::Parser& parser, MIDI::byte* message, size_t size);
364         // we can't use continue because it is a C++ keyword
365         void calculate_one_ppqn_in_frames_at(framepos_t time);
366         framepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
367         void calculate_filter_coefficients();
368         void update_midi_clock (MIDI::Parser& parser, framepos_t timestamp);
369         void read_current (SafeTime *) const;
370         bool stop_if_no_more_clock_events(framepos_t& pos, framepos_t now);
371
372         /// whether transport should be rolling
373         bool _started;
374
375         /// is true if the MIDI Start message has just been received until
376         /// the first MIDI Clock Event
377         bool _starting;
378 };
379
380 class JACK_Slave : public Slave
381 {
382   public:
383         JACK_Slave (jack_client_t*);
384         ~JACK_Slave ();
385
386         bool speed_and_position (double& speed, framepos_t& pos);
387
388         bool starting() const { return _starting; }
389         bool locked() const;
390         bool ok() const;
391         framecnt_t resolution () const { return 1; }
392         bool requires_seekahead () const { return false; }
393         void reset_client (jack_client_t* jack);
394         bool is_always_synced() const { return true; }
395
396   private:
397         jack_client_t* jack;
398         double speed;
399         bool _starting;
400 };
401
402 } /* namespace */
403
404 #endif /* __ardour_slave_h__ */