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