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