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