basics for a TimecodeSlave parent class for MTC and LTC
[ardour.git] / libs / ardour / mtc_slave.cc
1 /*
2     Copyright (C) 2002-4 Paul Davis
3     Overhaul 2012 Robin Gareus <robin@gareus.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20 #include <iostream>
21 #include <errno.h>
22 #include <poll.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include "pbd/error.h"
27
28 #include "midi++/port.h"
29 #include "ardour/debug.h"
30 #include "ardour/slave.h"
31 #include "ardour/session.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/pi_controller.h"
34
35 #include "i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace MIDI;
40 using namespace PBD;
41 using namespace Timecode;
42
43 /* length (in timecode frames) of the "window" that we consider legal given receipt of
44    a given timecode position. Ardour will try to chase within this window, and will
45    stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
46    in the current direction of motion, so if any timecode arrives that is before the most
47    recently received position (and without the direction of timecode reversing too), we
48    will stop+locate+wait+chase.
49 */
50 const int MTC_Slave::frame_tolerance = 2;
51
52 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
53         : session (s)
54 {
55         can_notify_on_unknown_rate = true;
56         did_reset_tc_format = false;
57         reset_pending = 0;
58         reset_position = false;
59         mtc_frame = 0;
60         engine_dll_initstate = 0;
61         busy_guard1 = busy_guard2 = 0;
62
63         last_mtc_fps_byte = session.get_mtc_timecode_bits ();
64         quarter_frame_duration = (double(session.frames_per_timecode_frame()) / 4.0);
65
66         mtc_timecode = timecode_60; // track changes of MTC timecode
67         a3e_timecode = timecode_60; // track canges of Ardour's timecode
68         printed_timecode_warning = false;
69
70         reset (true);
71         rebind (p);
72 }
73
74 MTC_Slave::~MTC_Slave()
75 {
76         port_connections.drop_connections();
77
78         while (busy_guard1 != busy_guard2) {
79                 /* make sure MIDI parser is not currently calling any callbacks in here,
80                  * else there's a segfault ahead!
81                  *
82                  * XXX this is called from jack rt-context :(
83                  * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
84                  */
85                 sched_yield();
86         }
87
88         if (did_reset_tc_format) {
89                 session.config.set_timecode_format (saved_tc_format);
90         }
91 }
92
93 void
94 MTC_Slave::rebind (MIDI::Port& p)
95 {
96         port_connections.drop_connections ();
97
98         port = &p;
99
100         port->parser()->mtc_time.connect_same_thread (port_connections,  boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
101         port->parser()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
102         port->parser()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
103 }
104
105 bool
106 MTC_Slave::give_slave_full_control_over_transport_speed() const
107 {
108         return true; // DLL align to engine transport
109         // return false; // for Session-level computed varispeed
110 }
111
112 ARDOUR::framecnt_t
113 MTC_Slave::resolution () const
114 {
115         return (framecnt_t) quarter_frame_duration * 4.0;
116 }
117
118 ARDOUR::framecnt_t
119 MTC_Slave::seekahead_distance () const
120 {
121         return quarter_frame_duration * 8 * transport_direction;
122 }
123
124 bool
125 MTC_Slave::outside_window (framepos_t pos) const
126 {
127         return ((pos < window_begin) || (pos > window_end));
128 }
129
130
131 bool
132 MTC_Slave::locked () const
133 {
134         return port->parser()->mtc_locked();
135 }
136
137 bool
138 MTC_Slave::ok() const
139 {
140         return true;
141 }
142
143 void
144 MTC_Slave::queue_reset (bool reset_pos)
145 {
146         Glib::Threads::Mutex::Lock lm (reset_lock);
147         reset_pending++;
148         if (reset_pos) {
149                 reset_position = true;
150         }
151 }
152
153 void
154 MTC_Slave::maybe_reset ()
155 {
156         Glib::Threads::Mutex::Lock lm (reset_lock);
157
158         if (reset_pending) {
159                 reset (reset_position);
160                 reset_pending = 0;
161                 reset_position = false;
162         }
163 }
164
165 void
166 MTC_Slave::reset (bool with_position)
167 {
168         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_Slave reset %1\n", with_position?"with position":"without position"));
169         if (with_position) {
170                 last_inbound_frame = 0;
171                 current.guard1++;
172                 current.position = 0;
173                 current.timestamp = 0;
174                 current.speed = 0;
175                 current.guard2++;
176         } else {
177                 last_inbound_frame = 0;
178                 current.guard1++;
179                 current.timestamp = 0;
180                 current.speed = 0;
181                 current.guard2++;
182         }
183         first_mtc_timestamp = 0;
184         window_begin = 0;
185         window_end = 0;
186         transport_direction = 1;
187 }
188
189 void
190 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
191 {
192         MIDI::byte mtc[5];
193         DEBUG_TRACE (DEBUG::MTC, "MTC_Slave::handle_locate\n");
194
195         mtc[4] = last_mtc_fps_byte;
196         mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
197         mtc[2] = mmc_tc[1];
198         mtc[1] = mmc_tc[2];
199         mtc[0] = mmc_tc[3];
200
201         update_mtc_time (mtc, true, 0);
202 }
203
204 void
205 MTC_Slave::read_current (SafeTime *st) const
206 {
207         int tries = 0;
208
209         do {
210                 if (tries == 10) {
211                         error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
212                         usleep (20);
213                         tries = 0;
214                 }
215                 *st = current;
216                 tries++;
217
218         } while (st->guard1 != st->guard2);
219 }
220
221 void
222 MTC_Slave::init_mtc_dll(framepos_t tme, double qtr)
223 {
224         omega = 2.0 * M_PI * qtr / double(session.frame_rate());
225         b = 1.4142135623730950488 * omega;
226         c = omega * omega;
227
228         e2 = qtr;
229         t0 = double(tme);
230         t1 = t0 + e2;
231         DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
232 }
233
234
235 /* called from MIDI parser */
236 void
237 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now)
238 {
239         busy_guard1++;
240         const double qtr_d = quarter_frame_duration;
241         const framepos_t qtr = rint(qtr_d);
242
243         mtc_frame += qtr * transport_direction;
244
245         DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
246
247         double mtc_speed = 0;
248         if (first_mtc_timestamp != 0) {
249                 /* update MTC DLL and calculate speed */
250                 const double e = double(transport_direction) * (double(now) - double(current.timestamp) - qtr_d);
251                 t0 = t1;
252                 t1 += b * e + e2;
253                 e2 += c * e;
254
255                 mtc_speed = (t1 - t0) / qtr_d;
256                 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d));
257         }
258
259         current.guard1++;
260         current.position = mtc_frame;
261         current.timestamp = now;
262         current.speed = mtc_speed;
263         current.guard2++;
264
265         maybe_reset ();
266         last_inbound_frame = now;
267
268         busy_guard2++;
269 }
270
271 /* called from MIDI parser _after_ update_mtc_qtr()
272  * when a full TC has been received
273  * OR on locate */
274 void
275 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
276 {
277         busy_guard1++;
278
279         /* "now" can be zero if this is called from a context where we do not have or do not want
280            to use a timestamp indicating when this MTC time was received. example: when we received
281            a locate command via MMC.
282         */
283
284         //DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self()));
285         Time timecode;
286         TimecodeFormat tc_format;
287         bool reset_tc = true;
288
289         timecode.hours = msg[3];
290         timecode.minutes = msg[2];
291         timecode.seconds = msg[1];
292         timecode.frames = msg[0];
293
294         last_mtc_fps_byte = msg[4];
295
296         DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
297
298         if (now) {
299                 maybe_reset ();
300         }
301
302         switch (msg[4]) {
303         case MTC_24_FPS:
304                 timecode.rate = 24;
305                 timecode.drop = false;
306                 tc_format = timecode_24;
307                 can_notify_on_unknown_rate = true;
308                 break;
309         case MTC_25_FPS:
310                 timecode.rate = 25;
311                 timecode.drop = false;
312                 tc_format = timecode_25;
313                 can_notify_on_unknown_rate = true;
314                 break;
315         case MTC_30_FPS_DROP:
316                 timecode.rate = 30;
317                 timecode.drop = true;
318                 tc_format = timecode_30drop;
319                 can_notify_on_unknown_rate = true;
320                 break;
321         case MTC_30_FPS:
322                 timecode.rate = 30;
323                 timecode.drop = false;
324                 can_notify_on_unknown_rate = true;
325                 tc_format = timecode_30;
326                 break;
327         default:
328                 /* throttle error messages about unknown MTC rates */
329                 if (can_notify_on_unknown_rate) {
330                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
331                                                  (int) msg[4])
332                               << endmsg;
333                         can_notify_on_unknown_rate = false;
334                 }
335                 timecode.rate = session.timecode_frames_per_second();
336                 timecode.drop = session.timecode_drop_frames();
337                 reset_tc = false;
338         }
339
340         if (reset_tc) {
341                 TimecodeFormat cur_timecode = session.config.get_timecode_format();
342                 if (Config->get_timecode_sync_frame_rate()) {
343                         /* enforce time-code */
344                         if (!did_reset_tc_format) {
345                                 saved_tc_format = cur_timecode;
346                                 did_reset_tc_format = true;
347                         }
348                         if (cur_timecode != tc_format) {
349                                 warning << _("Session and MTC framerate mismatch.") << endmsg;
350                         }
351                         session.config.set_timecode_format (tc_format);
352                 } else {
353                         /* only warn about TC mismatch */
354                         if (mtc_timecode != tc_format) printed_timecode_warning = false;
355                         if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
356
357                         if (cur_timecode != tc_format && ! printed_timecode_warning) {
358                                 warning << _("Session and MTC framerate mismatch.") << endmsg;
359                                 printed_timecode_warning = true;
360                         }
361                 }
362                 mtc_timecode = tc_format;
363                 a3e_timecode = cur_timecode;
364
365                 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
366         }
367
368         /* do a careful conversion of the timecode value to a position
369            so that we take drop/nondrop and all that nonsense into
370            consideration.
371         */
372
373         quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
374         session.timecode_to_sample (timecode, mtc_frame, true, false); // audio-frame according to Ardour's FPS
375
376         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
377                                                  now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
378
379         if (was_full || outside_window (mtc_frame)) {
380                 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self()));
381                 session.request_locate (mtc_frame, false);
382                 session.request_transport_speed (0);
383                 update_mtc_status (MIDI::MTC_Stopped);
384                 reset (false);
385                 reset_window (mtc_frame);
386         } else {
387
388                 /* we've had the first set of 8 qtr frame messages, determine position
389                    and allow continuing qtr frame messages to provide position
390                    and speed information.
391                 */
392
393                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
394                    frames) after the instance when the contents of the mtc quarter
395                    frames were decided. Add time to compensate for the elapsed 1.75
396                    frames.
397                 */
398                 double qtr = quarter_frame_duration;
399                 long int mtc_off = (long) rint(7.0 * qtr);
400
401                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
402                                                          mtc_frame, (4.0*qtr), session.frames_per_timecode_frame()));
403
404                 switch (port->parser()->mtc_running()) {
405                 case MTC_Backward:
406                         mtc_frame -= mtc_off;
407                         qtr *= -1.0;
408                         break;
409                 case MTC_Forward:
410                         mtc_frame += mtc_off;
411                         break;
412                 default:
413                         break;
414                 }
415
416                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
417
418                 if (now) {
419                         if (first_mtc_timestamp == 0 || current.timestamp == 0) {
420                                 first_mtc_timestamp = now;
421                                 init_mtc_dll(mtc_frame, qtr);
422                         }
423                         current.guard1++;
424                         current.position = mtc_frame;
425                         current.timestamp = now;
426                         current.guard2++;
427                         reset_window (mtc_frame);
428                 }
429         }
430
431         if (now) {
432                 last_inbound_frame = now;
433         }
434         busy_guard2++;
435 }
436
437 void
438 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
439 {
440         /* XXX !!! thread safety ... called from MIDI I/O context
441          * on locate (via ::update_mtc_time())
442          */
443         DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", ::pthread_self()));
444         return; // why was this fn needed anyway ? it just messes up things -> use reset.
445         busy_guard1++;
446
447         switch (status) {
448         case MTC_Stopped:
449                 current.guard1++;
450                 current.position = mtc_frame;
451                 current.timestamp = 0;
452                 current.speed = 0;
453                 current.guard2++;
454
455                 break;
456
457         case MTC_Forward:
458                 current.guard1++;
459                 current.position = mtc_frame;
460                 current.timestamp = 0;
461                 current.speed = 0;
462                 current.guard2++;
463                 break;
464
465         case MTC_Backward:
466                 current.guard1++;
467                 current.position = mtc_frame;
468                 current.timestamp = 0;
469                 current.speed = 0;
470                 current.guard2++;
471                 break;
472         }
473         busy_guard2++;
474 }
475
476 void
477 MTC_Slave::reset_window (framepos_t root)
478 {
479         /* if we're waiting for the master to catch us after seeking ahead, keep the window
480            of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
481            ahead of the window root (taking direction into account).
482         */
483         framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance);
484
485         switch (port->parser()->mtc_running()) {
486         case MTC_Forward:
487                 window_begin = root;
488                 transport_direction = 1;
489                 window_end = root + d;
490                 break;
491
492         case MTC_Backward:
493                 transport_direction = -1;
494                 if (root > d) {
495                         window_begin = root - d;
496                         window_end = root;
497                 } else {
498                         window_begin = 0;
499                 }
500                 window_end = root;
501                 break;
502
503         default:
504                 /* do nothing */
505                 break;
506         }
507
508         DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
509 }
510
511 void
512 MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
513 {
514         /* the bandwidth of the DLL is a trade-off,
515          * because the max-speed of the transport in ardour is
516          * limited to +-8.0, a larger bandwidth would cause oscillations
517          *
518          * But this is only really a problem if the user performs manual
519          * seeks while transport is running and slaved to MTC.
520          */
521         oe = 2.0 * M_PI * double(inc/6.0) / double(session.frame_rate());
522         be = 1.4142135623730950488 * oe;
523         ce = oe * oe;
524
525         ee2 = double(transport_direction * inc);
526         te0 = double(pos);
527         te1 = te0 + ee2;
528         DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
529 }
530
531 /* main entry point from session_process.cc
532  * in jack_process callback context */
533 bool
534 MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
535 {
536         framepos_t now = session.engine().frame_time_at_cycle_start();
537         framepos_t sess_pos = session.transport_frame(); // corresponds to now
538
539         SafeTime last;
540         framecnt_t elapsed;
541
542         read_current (&last);
543
544         /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
545         if (last.timestamp == 0) { engine_dll_initstate = 0; }
546         else if (engine_dll_initstate != transport_direction) { 
547                 engine_dll_initstate = transport_direction;
548                 init_engine_dll(last.position, session.engine().frames_per_cycle());
549         }
550
551         if (last.timestamp == 0) {
552                 speed = 0;
553                 pos = session.transport_frame() ; // last.position;
554                 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos));
555                 return true;
556         }
557
558         /* no timecode for two frames - conclude that it's stopped */
559         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
560                 speed = 0;
561                 pos = last.position;
562                 session.request_locate (pos, false);
563                 session.request_transport_speed (0);
564                 queue_reset (false);
565                 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n");
566                 return false;
567         }
568
569
570
571         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position mtc-tme: %1 mtc-pos: %2\n", last.timestamp, last.position));
572         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position eng-tme: %1 eng-pos: %2\n", now, sess_pos));
573
574         double speed_flt = last.speed; ///< MTC speed from MTC-quarter-frame DLL
575
576         /* interpolate position according to speed and time since last quarter-frame*/
577         if (speed_flt == 0.0f) {
578                 elapsed = 0;
579         }
580         else
581         {
582                 /* scale elapsed time by the current MTC speed */
583                 if (last.timestamp && (now > last.timestamp)) {
584                         elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp));
585                 } else {
586                         elapsed = 0;
587                 }
588                 if (give_slave_full_control_over_transport_speed()) {
589                         /* there is a frame-delta engine vs MTC position
590                          * mostly due to quantization and rounding of (speed * nframes)
591                          * thus we use an other DLL..
592                          */
593
594                         /* update engine DLL and calculate speed */
595                         const double e = double (last.position + elapsed - sess_pos);
596                         te0 = te1;
597                         te1 += be * e + ee2;
598                         ee2 += ce * e;
599                         speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle());
600                         DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().frames_per_cycle() ));
601                 }
602         }
603
604         pos = last.position + elapsed;
605         speed = speed_flt;
606
607         /* may happen if the user performs a seek in the timeline while slaved to running MTC
608          * engine-DLL can oscillate back before 0.
609          * also see note in MTC_Slave::init_engine_dll
610          */
611         if (pos <0) queue_reset(true);
612
613         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
614                                                  speed, pos, last.position, elapsed,  pos - sess_pos));
615
616         return true;
617 }
618
619 Timecode::TimecodeFormat
620 MTC_Slave::apparent_timecode_format () const
621 {
622         /* XXX to be computed, determined from incoming stream */
623         return timecode_30;
624 }