~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to libs/ardour/ardour/slave.h

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "timecode/time.h"
 
32
#include "ltc/ltc.h"
 
33
 
 
34
#include "ardour/types.h"
 
35
#include "midi++/parser.h"
 
36
#include "midi++/types.h"
 
37
 
 
38
 
 
39
/* used for approximate_current_delta(): */
 
40
#define PLUSMINUS(A) ( ((A)<0) ? "-" : (((A)>0) ? "+" : "\u00B1") )
 
41
#define LEADINGZERO(A) ( (A)<10 ? "   " : (A)<100 ? "  " : (A)<1000 ? " " : "" )
 
42
 
 
43
namespace MIDI {
 
44
        class Port;
 
45
}
 
46
 
 
47
namespace ARDOUR {
 
48
 
 
49
class TempoMap;
 
50
class Session;
 
51
 
 
52
/**
 
53
 * @class Slave
 
54
 *
 
55
 * @brief The Slave interface can be used to sync ARDOURs tempo to an external source
 
56
 * like MTC, MIDI Clock, etc.
 
57
 *
 
58
 * The name of the interface may be a bit misleading: A subclass of Slave actually
 
59
 * acts as a time master for ARDOUR, that means ARDOUR will try to follow the
 
60
 * speed and transport position of the implementation of Slave.
 
61
 * Therefore it is rather that class, that makes ARDOUR a slave by connecting it
 
62
 * to its external time master.
 
63
 */
 
64
class Slave {
 
65
  public:
 
66
        Slave() { }
 
67
        virtual ~Slave() {}
 
68
 
 
69
        /**
 
70
         * This is the most important function to implement:
 
71
         * Each process cycle, Session::follow_slave will call this method.
 
72
         *  and after the method call they should
 
73
         *
 
74
         * Session::follow_slave will then try to follow the given
 
75
         * <em>position</em> using a delay locked loop (DLL),
 
76
         * starting with the first given transport speed.
 
77
         * If the values of speed and position contradict each other,
 
78
         * ARDOUR will always follow the position and disregard the speed.
 
79
         * Although, a correct speed is important so that ARDOUR
 
80
         * can sync to the master time source quickly.
 
81
         *
 
82
         * For background information on delay locked loops,
 
83
         * see http://www.kokkinizita.net/papers/usingdll.pdf
 
84
         *
 
85
         * The method has the following precondition:
 
86
         * <ul>
 
87
         *   <li>
 
88
         *       Slave::ok() should return true, otherwise playback will stop
 
89
         *       immediately and the method will not be called
 
90
         *   </li>
 
91
         *   <li>
 
92
         *     when the references speed and position are passed into the Slave
 
93
         *     they are uninitialized
 
94
         *   </li>
 
95
         * </ul>
 
96
         *
 
97
         * After the method call the following postconditions should be met:
 
98
         * <ul>
 
99
         *    <li>
 
100
         *       The first position value on transport start should be 0,
 
101
         *       otherwise ARDOUR will try to locate to the new position
 
102
         *       rather than move to it
 
103
         *    </li>
 
104
         *    <li>
 
105
         *      the references speed and position should be assigned
 
106
         *      to the Slaves current requested transport speed
 
107
         *      and transport position.
 
108
         *    </li>
 
109
         *   <li>
 
110
         *     Slave::resolution() should be greater than the maximum distance of
 
111
         *     ARDOURs transport position to the slaves requested transport position.
 
112
         *   </li>
 
113
         *   <li>Slave::locked() should return true, otherwise Session::no_roll will be called</li>
 
114
         *   <li>Slave::starting() should be false, otherwise the transport will not move until it becomes true</li>     *
 
115
         * </ul>
 
116
         *
 
117
         * @param speed - The transport speed requested
 
118
         * @param position - The transport position requested
 
119
         * @return - The return value is currently ignored (see Session::follow_slave)
 
120
         */
 
121
        virtual bool speed_and_position (double& speed, framepos_t& position) = 0;
 
122
 
 
123
        /**
 
124
         * reports to ARDOUR whether the Slave is currently synced to its external
 
125
         * time source.
 
126
         *
 
127
         * @return - when returning false, the transport will stop rolling
 
128
         */
 
129
        virtual bool locked() const = 0;
 
130
 
 
131
        /**
 
132
         * reports to ARDOUR whether the slave is in a sane state
 
133
         *
 
134
         * @return - when returning false, the transport will be stopped and the slave
 
135
         * disconnected from ARDOUR.
 
136
         */
 
137
        virtual bool ok() const = 0;
 
138
 
 
139
        /**
 
140
         * reports to ARDOUR whether the slave is in the process of starting
 
141
         * to roll
 
142
         *
 
143
         * @return - when returning false, transport will not move until this method returns true
 
144
         */
 
145
        virtual bool starting() const { return false; }
 
146
 
 
147
        /**
 
148
         * @return - the timing resolution of the Slave - If the distance of ARDOURs transport
 
149
         * to the slave becomes greater than the resolution, sound will stop
 
150
         */
 
151
        virtual framecnt_t resolution() const = 0;
 
152
 
 
153
        /**
 
154
         * @return - when returning true, ARDOUR will wait for seekahead_distance() before transport
 
155
         * starts rolling
 
156
         */
 
157
        virtual bool requires_seekahead () const = 0;
 
158
 
 
159
        /**
 
160
         * @return the number of frames that this slave wants to seek ahead. Relevant
 
161
         * only if requires_seekahead() returns true.
 
162
         */
 
163
 
 
164
        virtual framecnt_t seekahead_distance() const { return 0; }
 
165
 
 
166
        /**
 
167
         * @return - when returning true, ARDOUR will use transport speed 1.0 no matter what
 
168
         *           the slave returns
 
169
         */
 
170
        virtual bool is_always_synced() const { return false; }
 
171
 
 
172
        /**
 
173
         * @return - whether ARDOUR should use the slave speed without any adjustments
 
174
         */
 
175
        virtual bool give_slave_full_control_over_transport_speed() const { return false; }
 
176
 
 
177
        /**
 
178
         * @return - current time-delta between engine and sync-source
 
179
         */
 
180
        virtual std::string approximate_current_delta() const { return ""; }
 
181
 
 
182
};
 
183
 
 
184
/// We need this wrapper for testability, it's just too hard to mock up a session class
 
185
class ISlaveSessionProxy {
 
186
  public:
 
187
        virtual ~ISlaveSessionProxy() {}
 
188
        virtual TempoMap&  tempo_map()                 const   { return *((TempoMap *) 0); }
 
189
        virtual framecnt_t frame_rate()                const   { return 0; }
 
190
        virtual framepos_t audible_frame ()            const   { return 0; }
 
191
        virtual framepos_t transport_frame ()          const   { return 0; }
 
192
        virtual pframes_t  frames_since_cycle_start () const   { return 0; }
 
193
        virtual framepos_t frame_time ()               const   { return 0; }
 
194
 
 
195
        virtual void request_locate (framepos_t /*frame*/, bool with_roll = false) {
 
196
                (void) with_roll;
 
197
        }
 
198
        virtual void request_transport_speed (double /*speed*/)                   {}
 
199
};
 
200
 
 
201
 
 
202
/// The Session Proxy for use in real Ardour
 
203
class SlaveSessionProxy : public ISlaveSessionProxy {
 
204
        Session&    session;
 
205
 
 
206
  public:
 
207
        SlaveSessionProxy(Session &s) : session(s) {}
 
208
 
 
209
        TempoMap&  tempo_map()                 const;
 
210
        framecnt_t frame_rate()                const;
 
211
        framepos_t audible_frame ()            const;
 
212
        framepos_t transport_frame ()          const;
 
213
        pframes_t  frames_since_cycle_start () const;
 
214
        framepos_t frame_time ()               const;
 
215
 
 
216
        void request_locate (framepos_t frame, bool with_roll = false);
 
217
        void request_transport_speed (double speed);
 
218
};
 
219
 
 
220
struct SafeTime {
 
221
        volatile int guard1;
 
222
        framepos_t   position;
 
223
        framepos_t   timestamp;
 
224
        double       speed;
 
225
        volatile int guard2;
 
226
 
 
227
        SafeTime() {
 
228
                guard1 = 0;
 
229
                position = 0;
 
230
                timestamp = 0;
 
231
                speed = 0;
 
232
                guard2 = 0;
 
233
        }
 
234
};
 
235
 
 
236
class TimecodeSlave : public Slave {
 
237
  public:
 
238
    TimecodeSlave () {}
 
239
 
 
240
    virtual Timecode::TimecodeFormat apparent_timecode_format() const = 0;
 
241
 
 
242
    /* this is intended to be used by a UI and polled from a timeout. it should
 
243
       return a string describing the current position of the TC source. it
 
244
       should NOT do any computation, but should use a cached value
 
245
       of the TC source position.
 
246
    */
 
247
    virtual std::string approximate_current_position() const = 0;
 
248
 
 
249
    framepos_t        timecode_offset;
 
250
    bool              timecode_negative_offset;
 
251
};
 
252
 
 
253
class MTC_Slave : public TimecodeSlave {
 
254
  public:
 
255
        MTC_Slave (Session&, MIDI::Port&);
 
256
        ~MTC_Slave ();
 
257
 
 
258
        void rebind (MIDI::Port&);
 
259
        bool speed_and_position (double&, framepos_t&);
 
260
 
 
261
        bool locked() const;
 
262
        bool ok() const;
 
263
        void handle_locate (const MIDI::byte*);
 
264
 
 
265
        framecnt_t resolution () const;
 
266
        bool requires_seekahead () const { return false; }
 
267
        framecnt_t seekahead_distance() const;
 
268
        bool give_slave_full_control_over_transport_speed() const;
 
269
 
 
270
        Timecode::TimecodeFormat apparent_timecode_format() const;
 
271
        std::string approximate_current_position() const;
 
272
        std::string approximate_current_delta() const;
 
273
 
 
274
  private:
 
275
        Session&    session;
 
276
        MIDI::Port* port;
 
277
        PBD::ScopedConnectionList port_connections;
 
278
        PBD::ScopedConnection     config_connection;
 
279
        bool        can_notify_on_unknown_rate;
 
280
 
 
281
        static const int frame_tolerance;
 
282
 
 
283
        SafeTime       current;
 
284
        framepos_t     mtc_frame;               /* current time */
 
285
        double         mtc_frame_dll;
 
286
        framepos_t     last_inbound_frame;      /* when we got it; audio clocked */
 
287
        MIDI::byte     last_mtc_fps_byte;
 
288
        framepos_t     window_begin;
 
289
        framepos_t     window_end;
 
290
        framepos_t     first_mtc_timestamp;
 
291
        bool           did_reset_tc_format;
 
292
        Timecode::TimecodeFormat saved_tc_format;
 
293
        Glib::Threads::Mutex    reset_lock;
 
294
        uint32_t       reset_pending;
 
295
        bool           reset_position;
 
296
        int            transport_direction;
 
297
        int            busy_guard1;
 
298
        int            busy_guard2;
 
299
 
 
300
        double         speedup_due_to_tc_mismatch;
 
301
        double         quarter_frame_duration;
 
302
        Timecode::TimecodeFormat mtc_timecode;
 
303
        Timecode::TimecodeFormat a3e_timecode;
 
304
        Timecode::Time timecode;
 
305
        bool           printed_timecode_warning;
 
306
        frameoffset_t  current_delta;
 
307
 
 
308
        /* DLL - chase MTC */
 
309
        double t0; ///< time at the beginning of the MTC quater frame
 
310
        double t1; ///< calculated end of the MTC quater frame
 
311
        double e2; ///< second order loop error
 
312
        double b, c, omega; ///< DLL filter coefficients
 
313
 
 
314
        /* DLL - sync engine */
 
315
        int    engine_dll_initstate;
 
316
        double te0; ///< time at the beginning of the engine process
 
317
        double te1; ///< calculated sync time
 
318
        double ee2; ///< second order loop error
 
319
        double be, ce, oe; ///< DLL filter coefficients
 
320
 
 
321
        void reset (bool with_pos);
 
322
        void queue_reset (bool with_pos);
 
323
        void maybe_reset ();
 
324
 
 
325
        void update_mtc_qtr (MIDI::Parser&, int, framepos_t);
 
326
        void update_mtc_time (const MIDI::byte *, bool, framepos_t);
 
327
        void update_mtc_status (MIDI::MTC_Status);
 
328
        void read_current (SafeTime *) const;
 
329
        void reset_window (framepos_t);
 
330
        bool outside_window (framepos_t) const;
 
331
        void init_mtc_dll(framepos_t, double);
 
332
        void init_engine_dll (framepos_t, framepos_t);
 
333
        void parse_timecode_offset();
 
334
        void parameter_changed(std::string const & p);
 
335
};
 
336
 
 
337
class LTC_Slave : public TimecodeSlave {
 
338
public:
 
339
        LTC_Slave (Session&);
 
340
        ~LTC_Slave ();
 
341
 
 
342
        bool speed_and_position (double&, framepos_t&);
 
343
 
 
344
        bool locked() const;
 
345
        bool ok() const;
 
346
 
 
347
        framecnt_t resolution () const;
 
348
        bool requires_seekahead () const { return false; }
 
349
        framecnt_t seekahead_distance () const { return 0; }
 
350
        bool give_slave_full_control_over_transport_speed() const { return true; }
 
351
 
 
352
        Timecode::TimecodeFormat apparent_timecode_format() const;
 
353
        std::string approximate_current_position() const;
 
354
        std::string approximate_current_delta() const;
 
355
 
 
356
  private:
 
357
        void parse_ltc(const jack_nframes_t, const jack_default_audio_sample_t * const, const framecnt_t);
 
358
        void process_ltc(framepos_t const);
 
359
        void init_engine_dll (framepos_t, int32_t);
 
360
        bool detect_discontinuity(LTCFrameExt *, int, bool);
 
361
        bool detect_ltc_fps(int, bool);
 
362
        bool equal_ltc_frame_time(LTCFrame *a, LTCFrame *b);
 
363
        void reset();
 
364
        void resync_xrun();
 
365
        void resync_latency();
 
366
        void parse_timecode_offset();
 
367
        void parameter_changed(std::string const & p);
 
368
 
 
369
        Session&       session;
 
370
        bool           did_reset_tc_format;
 
371
        Timecode::TimecodeFormat saved_tc_format;
 
372
 
 
373
        LTCDecoder *   decoder;
 
374
        double         frames_per_ltc_frame;
 
375
        Timecode::Time timecode;
 
376
        LTCFrameExt    prev_frame;
 
377
        bool           fps_detected;
 
378
 
 
379
        framecnt_t     monotonic_cnt;
 
380
        framecnt_t     last_timestamp;
 
381
        framecnt_t     last_ltc_frame;
 
382
        double         ltc_speed;
 
383
        frameoffset_t  current_delta;
 
384
        int            delayedlocked;
 
385
 
 
386
        int            ltc_detect_fps_cnt;
 
387
        int            ltc_detect_fps_max;
 
388
        bool           printed_timecode_warning;
 
389
        Timecode::TimecodeFormat ltc_timecode;
 
390
        Timecode::TimecodeFormat a3e_timecode;
 
391
 
 
392
        PBD::ScopedConnectionList port_connections;
 
393
        PBD::ScopedConnection     config_connection;
 
394
        jack_latency_range_t      ltc_slave_latency;
 
395
 
 
396
        /* DLL - chase LTC */
 
397
        int    transport_direction;
 
398
        int    engine_dll_initstate;
 
399
        double t0; ///< time at the beginning of the MTC quater frame
 
400
        double t1; ///< calculated end of the MTC quater frame
 
401
        double e2; ///< second order loop error
 
402
        double b, c; ///< DLL filter coefficients
 
403
};
 
404
 
 
405
class MIDIClock_Slave : public Slave {
 
406
  public:
 
407
        MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24);
 
408
 
 
409
        /// Constructor for unit tests
 
410
        MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24);
 
411
        ~MIDIClock_Slave ();
 
412
 
 
413
        void rebind (MIDI::Port&);
 
414
        bool speed_and_position (double&, framepos_t&);
 
415
 
 
416
        bool locked() const;
 
417
        bool ok() const;
 
418
        bool starting() const;
 
419
 
 
420
        framecnt_t resolution () const;
 
421
        bool requires_seekahead () const { return false; }
 
422
        bool give_slave_full_control_over_transport_speed() const { return true; }
 
423
 
 
424
        void set_bandwidth (double a_bandwith) { bandwidth = a_bandwith; }
 
425
        std::string approximate_current_delta() const;
 
426
 
 
427
  protected:
 
428
        ISlaveSessionProxy* session;
 
429
        MIDI::Port* port;
 
430
        PBD::ScopedConnectionList port_connections;
 
431
 
 
432
        /// pulses per quarter note for one MIDI clock frame (default 24)
 
433
        int         ppqn;
 
434
 
 
435
        /// the duration of one ppqn in frame time
 
436
        double      one_ppqn_in_frames;
 
437
 
 
438
        /// the timestamp of the first MIDI clock message
 
439
        framepos_t  first_timestamp;
 
440
 
 
441
        /// the time stamp and should-be transport position of the last inbound MIDI clock message
 
442
        framepos_t  last_timestamp;
 
443
        double      should_be_position;
 
444
 
 
445
        /// the number of midi clock messages received (zero-based)
 
446
        /// since start
 
447
        long midi_clock_count;
 
448
 
 
449
        //the delay locked loop (DLL), see www.kokkinizita.net/papers/usingdll.pdf
 
450
 
 
451
        /// time at the beginning of the MIDI clock frame
 
452
        double t0;
 
453
 
 
454
        /// calculated end of the MIDI clock frame
 
455
        double t1;
 
456
 
 
457
        /// loop error = real value - expected value
 
458
        double e;
 
459
 
 
460
        /// second order loop error
 
461
        double e2;
 
462
 
 
463
        /// DLL filter bandwidth
 
464
        double bandwidth;
 
465
 
 
466
        /// DLL filter coefficients
 
467
        double b, c, omega;
 
468
 
 
469
        frameoffset_t  current_delta;
 
470
 
 
471
        void reset ();
 
472
        void start (MIDI::Parser& parser, framepos_t timestamp);
 
473
        void contineu (MIDI::Parser& parser, framepos_t timestamp);
 
474
        void stop (MIDI::Parser& parser, framepos_t timestamp);
 
475
        void position (MIDI::Parser& parser, MIDI::byte* message, size_t size);
 
476
        // we can't use continue because it is a C++ keyword
 
477
        void calculate_one_ppqn_in_frames_at(framepos_t time);
 
478
        framepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
 
479
        void calculate_filter_coefficients();
 
480
        void update_midi_clock (MIDI::Parser& parser, framepos_t timestamp);
 
481
        void read_current (SafeTime *) const;
 
482
        bool stop_if_no_more_clock_events(framepos_t& pos, framepos_t now);
 
483
 
 
484
        /// whether transport should be rolling
 
485
        bool _started;
 
486
 
 
487
        /// is true if the MIDI Start message has just been received until
 
488
        /// the first MIDI Clock Event
 
489
        bool _starting;
 
490
};
 
491
 
 
492
class JACK_Slave : public Slave
 
493
{
 
494
  public:
 
495
        JACK_Slave (jack_client_t*);
 
496
        ~JACK_Slave ();
 
497
 
 
498
        bool speed_and_position (double& speed, framepos_t& pos);
 
499
 
 
500
        bool starting() const { return _starting; }
 
501
        bool locked() const;
 
502
        bool ok() const;
 
503
        framecnt_t resolution () const { return 1; }
 
504
        bool requires_seekahead () const { return false; }
 
505
        void reset_client (jack_client_t* jack);
 
506
        bool is_always_synced() const { return true; }
 
507
 
 
508
  private:
 
509
        jack_client_t* jack;
 
510
        double speed;
 
511
        bool _starting;
 
512
};
 
513
 
 
514
} /* namespace */
 
515
 
 
516
#endif /* __ardour_slave_h__ */