MTC slave: 2997fudge option
[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 = session.config.get_timecode_format();
66         a3e_timecode = session.config.get_timecode_format();
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() && last_inbound_frame !=0 && engine_dll_initstate !=0;
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         current_delta = 0;
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 / 2.0 / 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 = mtc_frame - (double(transport_direction) * (double(now) - double(current.timestamp) + t0));
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                 current.guard1++;
259                 current.position = mtc_frame;
260                 current.timestamp = now;
261                 current.speed = mtc_speed;
262                 current.guard2++;
263
264                 last_inbound_frame = now;
265         }
266
267         maybe_reset ();
268
269         busy_guard2++;
270 }
271
272 /* called from MIDI parser _after_ update_mtc_qtr()
273  * when a full TC has been received
274  * OR on locate */
275 void
276 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
277 {
278         busy_guard1++;
279
280         /* "now" can be zero if this is called from a context where we do not have or do not want
281            to use a timestamp indicating when this MTC time was received. example: when we received
282            a locate command via MMC.
283         */
284
285         //DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self()));
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                 if (Config->get_timecode_source_2997()) {
317                         tc_format = Timecode::timecode_2997000drop;
318                         timecode.rate = (29970.0/1000.0);
319                 } else {
320                         tc_format = timecode_2997drop;
321                         timecode.rate = (30000.0/1001.0);
322                 }
323                 timecode.drop = true;
324                 can_notify_on_unknown_rate = true;
325                 break;
326         case MTC_30_FPS:
327                 timecode.rate = 30;
328                 timecode.drop = false;
329                 can_notify_on_unknown_rate = true;
330                 tc_format = timecode_30;
331                 break;
332         default:
333                 /* throttle error messages about unknown MTC rates */
334                 if (can_notify_on_unknown_rate) {
335                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
336                                                  (int) msg[4])
337                               << endmsg;
338                         can_notify_on_unknown_rate = false;
339                 }
340                 timecode.rate = session.timecode_frames_per_second();
341                 timecode.drop = session.timecode_drop_frames();
342                 reset_tc = false;
343         }
344
345         if (reset_tc) {
346                 TimecodeFormat cur_timecode = session.config.get_timecode_format();
347                 if (Config->get_timecode_sync_frame_rate()) {
348                         /* enforce time-code */
349                         if (!did_reset_tc_format) {
350                                 saved_tc_format = cur_timecode;
351                                 did_reset_tc_format = true;
352                         }
353                         if (cur_timecode != tc_format) {
354                                 warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
355                                                 Timecode::timecode_format_name(cur_timecode),
356                                                 Timecode::timecode_format_name(tc_format))
357                                         << endmsg;
358                         }
359                         session.config.set_timecode_format (tc_format);
360                 } else {
361                         /* only warn about TC mismatch */
362                         if (mtc_timecode != tc_format) printed_timecode_warning = false;
363                         if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
364
365                         if (cur_timecode != tc_format && ! printed_timecode_warning) {
366                                 warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 Ardour:%2."),
367                                                 Timecode::timecode_format_name(tc_format),
368                                                 Timecode::timecode_format_name(cur_timecode))
369                                         << endmsg;
370                                 printed_timecode_warning = true;
371                         }
372                 }
373                 mtc_timecode = tc_format;
374                 a3e_timecode = cur_timecode;
375
376                 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
377         }
378
379         /* do a careful conversion of the timecode value to a position
380            so that we take drop/nondrop and all that nonsense into
381            consideration.
382         */
383
384         quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
385
386         Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
387                 double(session.frame_rate()),
388                 session.config.get_subframes_per_frame(),
389                 session.config.get_timecode_offset_negative(), session.config.get_timecode_offset()
390                 );
391
392         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
393                                                  now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
394
395         if (was_full || outside_window (mtc_frame)) {
396                 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self()));
397                 session.request_locate (mtc_frame, false);
398                 session.request_transport_speed (0);
399                 update_mtc_status (MIDI::MTC_Stopped);
400                 reset (false);
401                 reset_window (mtc_frame);
402         } else {
403
404                 /* we've had the first set of 8 qtr frame messages, determine position
405                    and allow continuing qtr frame messages to provide position
406                    and speed information.
407                 */
408
409                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
410                    frames) after the instance when the contents of the mtc quarter
411                    frames were decided. Add time to compensate for the elapsed 1.75
412                    frames.
413                 */
414                 double qtr = quarter_frame_duration;
415                 long int mtc_off = (long) rint(7.0 * qtr);
416
417                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
418                                                          mtc_frame, (4.0*qtr), session.frames_per_timecode_frame()));
419
420                 switch (port->parser()->mtc_running()) {
421                 case MTC_Backward:
422                         mtc_frame -= mtc_off;
423                         qtr *= -1.0;
424                         break;
425                 case MTC_Forward:
426                         mtc_frame += mtc_off;
427                         break;
428                 default:
429                         break;
430                 }
431
432                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
433
434                 if (now) {
435                         if (first_mtc_timestamp == 0 || current.timestamp == 0) {
436                                 first_mtc_timestamp = now;
437                                 init_mtc_dll(mtc_frame, qtr);
438                         }
439                         current.guard1++;
440                         current.position = mtc_frame;
441                         current.timestamp = now;
442                         current.guard2++;
443                         reset_window (mtc_frame);
444                 }
445         }
446
447         if (now) {
448                 last_inbound_frame = now;
449         }
450         busy_guard2++;
451 }
452
453 void
454 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
455 {
456         /* XXX !!! thread safety ... called from MIDI I/O context
457          * on locate (via ::update_mtc_time())
458          */
459         DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", ::pthread_self()));
460         return; // why was this fn needed anyway ? it just messes up things -> use reset.
461         busy_guard1++;
462
463         switch (status) {
464         case MTC_Stopped:
465                 current.guard1++;
466                 current.position = mtc_frame;
467                 current.timestamp = 0;
468                 current.speed = 0;
469                 current.guard2++;
470
471                 break;
472
473         case MTC_Forward:
474                 current.guard1++;
475                 current.position = mtc_frame;
476                 current.timestamp = 0;
477                 current.speed = 0;
478                 current.guard2++;
479                 break;
480
481         case MTC_Backward:
482                 current.guard1++;
483                 current.position = mtc_frame;
484                 current.timestamp = 0;
485                 current.speed = 0;
486                 current.guard2++;
487                 break;
488         }
489         busy_guard2++;
490 }
491
492 void
493 MTC_Slave::reset_window (framepos_t root)
494 {
495         /* if we're waiting for the master to catch us after seeking ahead, keep the window
496            of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
497            ahead of the window root (taking direction into account).
498         */
499         framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance);
500
501         switch (port->parser()->mtc_running()) {
502         case MTC_Forward:
503                 window_begin = root;
504                 transport_direction = 1;
505                 window_end = root + d;
506                 break;
507
508         case MTC_Backward:
509                 transport_direction = -1;
510                 if (root > d) {
511                         window_begin = root - d;
512                         window_end = root;
513                 } else {
514                         window_begin = 0;
515                 }
516                 window_end = root;
517                 break;
518
519         default:
520                 /* do nothing */
521                 break;
522         }
523
524         DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
525 }
526
527 void
528 MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
529 {
530         /* the bandwidth of the DLL is a trade-off,
531          * because the max-speed of the transport in ardour is
532          * limited to +-8.0, a larger bandwidth would cause oscillations
533          *
534          * But this is only really a problem if the user performs manual
535          * seeks while transport is running and slaved to MTC.
536          */
537         oe = 2.0 * M_PI * double(inc) / 2.0 / double(session.frame_rate());
538         be = 1.4142135623730950488 * oe;
539         ce = oe * oe;
540
541         ee2 = double(transport_direction * inc);
542         te0 = double(pos);
543         te1 = te0 + ee2;
544         DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
545 }
546
547 /* main entry point from session_process.cc
548  * in jack_process callback context */
549 bool
550 MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
551 {
552         framepos_t now = session.engine().frame_time_at_cycle_start();
553         framepos_t sess_pos = session.transport_frame(); // corresponds to now
554         //sess_pos -= session.engine().frames_since_cycle_start();
555
556         SafeTime last;
557         frameoffset_t elapsed;
558         bool engine_dll_reinitialized = false;
559
560         read_current (&last);
561
562         /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
563         if (last.timestamp == 0) { engine_dll_initstate = 0; }
564         else if (engine_dll_initstate != transport_direction && last.speed != 0) {
565                 engine_dll_initstate = transport_direction;
566                 init_engine_dll(last.position, session.engine().frames_per_cycle());
567                 engine_dll_reinitialized = true;
568         }
569
570         if (last.timestamp == 0) {
571                 speed = 0;
572                 pos = session.transport_frame() ; // last.position;
573                 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos));
574                 return true;
575         }
576
577         /* no timecode for two frames - conclude that it's stopped */
578         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
579                 speed = 0;
580                 pos = last.position;
581                 session.request_locate (pos, false);
582                 session.request_transport_speed (0);
583                 engine_dll_initstate = 0;
584                 queue_reset (false);
585                 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n");
586                 return false;
587         }
588
589
590         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position mtc-tme: %1 mtc-pos: %2 mtc-spd: %3\n", last.timestamp, last.position, last.speed));
591         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position eng-tme: %1 eng-pos: %2\n", now, sess_pos));
592
593         double speed_flt = last.speed; ///< MTC speed from MTC-quarter-frame DLL
594
595         /* interpolate position according to speed and time since last quarter-frame*/
596         if (speed_flt == 0.0f) {
597                 elapsed = 0;
598         }
599         else
600         {
601                 /* scale elapsed time by the current MTC speed */
602                 elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp));
603                 if (give_slave_full_control_over_transport_speed() && !engine_dll_reinitialized) {
604                         /* there is an engine vs MTC position frame-delta.
605                          * This mostly due to quantization and rounding of (speed * nframes)
606                          * but can also due to the session-process not calling
607                          * speed_and_position() every cycle under some circumstances.
608                          * Thus we use an other DLL to align the engine and the MTC
609                          */
610
611                         /* update engine DLL and calculate speed */
612                         const double e = double (last.position + elapsed - sess_pos);
613                         te0 = te1;
614                         te1 += be * e + ee2;
615                         ee2 += ce * e;
616                         speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle());
617                         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() ));
618                 }
619         }
620
621         pos = last.position + elapsed;
622         speed = speed_flt;
623
624         /* may happen if the user performs a seek in the timeline while slaved to running MTC
625          * engine-DLL can oscillate back before 0.
626          * also see note in MTC_Slave::init_engine_dll
627          */
628         if (!session.actively_recording()
629             && speed != 0
630                         && ( (pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()) )
631             ) {
632                 engine_dll_initstate = 0;
633                 queue_reset (false);
634         }
635
636         /* provide a .1% deadzone to lock the speed */
637         if (fabs(speed - 1.0) <= 0.001)
638                 speed = 1.0;
639
640         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
641                                                  speed, pos, last.position, elapsed,  pos - sess_pos));
642
643         current_delta = (pos - sess_pos);
644
645         return true;
646 }
647
648 Timecode::TimecodeFormat
649 MTC_Slave::apparent_timecode_format () const
650 {
651         return mtc_timecode;
652 }
653
654 std::string
655 MTC_Slave::approximate_current_position() const
656 {
657         SafeTime last;
658         read_current (&last);
659         if (last.timestamp == 0 || reset_pending) {
660                 return " --:--:--:--";
661         }
662         return Timecode::timecode_format_sampletime(
663                 last.position,
664                 double(session.frame_rate()),
665                 Timecode::timecode_to_frames_per_second(mtc_timecode),
666                 Timecode::timecode_has_drop_frames(mtc_timecode));
667 }
668
669 std::string
670 MTC_Slave::approximate_current_delta() const
671 {
672         char delta[24];
673         SafeTime last;
674         read_current (&last);
675         if (last.timestamp == 0 || reset_pending) {
676                 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
677         } else {
678                 // TODO if current_delta > 1 frame -> display timecode.
679                 snprintf(delta, sizeof(delta), "%s%4" PRIi64 " sm",
680                                 PLUSMINUS(-current_delta), abs(current_delta));
681         }
682         return std::string(delta);
683 }