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