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