move TimecodeFormat to libtimecode
[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 #include "ardour/pi_controller.h"
34
35 #include "i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace MIDI;
40 using namespace PBD;
41 using namespace Timecode;
42
43 /* length (in timecode frames) of the "window" that we consider legal given receipt of
44    a given timecode position. Ardour will try to chase within this window, and will
45    stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
46    in the current direction of motion, so if any timecode arrives that is before the most
47    recently received position (and without the direction of timecode reversing too), we
48    will stop+locate+wait+chase.
49 */
50 const int MTC_Slave::frame_tolerance = 2;
51
52 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
53         : session (s)
54 {
55         can_notify_on_unknown_rate = true;
56         did_reset_tc_format = false;
57         reset_pending = 0;
58         reset_position = false;
59         mtc_frame = 0;
60         engine_dll_initstate = 0;
61         busy_guard1 = busy_guard2 = 0;
62
63         last_mtc_fps_byte = session.get_mtc_timecode_bits ();
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) session.frames_per_timecode_frame();
115 }
116
117 ARDOUR::framecnt_t
118 MTC_Slave::seekahead_distance () const
119 {
120         return session.frames_per_timecode_frame() * 2 * 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 mtc_frame, double qtr)
222 {
223         omega = 2.0 * M_PI * (session.frames_per_timecode_frame() / 4.0) / double(session.frame_rate());
224         b = 1.4142135623730950488 * omega;
225         c = omega * omega;
226
227         e2 = qtr;
228         t0 = double(mtc_frame);
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 framepos_t qtr = (session.frames_per_timecode_frame() / 4);
240         const double qtr_d = (session.frames_per_timecode_frame() / 4.0);
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\n", t0, t1, e, mtc_speed));
256         }
257
258         current.guard1++;
259         current.position = mtc_frame;
260         current.timestamp = now;
261         current.speed = mtc_speed;
262         current.guard2++;
263
264         maybe_reset ();
265         last_inbound_frame = now;
266
267         busy_guard2++;
268 }
269
270 /* called from MIDI parser _after_ update_mtc_qtr()
271  * when a full TC has been received
272  * OR on locate */
273 void
274 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
275 {
276         busy_guard1++;
277
278         /* "now" can be zero if this is called from a context where we do not have or do not want
279            to use a timestamp indicating when this MTC time was received. example: when we received
280            a locate command via MMC.
281         */
282
283         //DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self()));
284         Time timecode;
285         TimecodeFormat tc_format;
286         bool reset_tc = true;
287
288         timecode.hours = msg[3];
289         timecode.minutes = msg[2];
290         timecode.seconds = msg[1];
291         timecode.frames = msg[0];
292
293         last_mtc_fps_byte = msg[4];
294
295         DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
296
297         if (now) {
298                 maybe_reset ();
299         }
300
301         switch (msg[4]) {
302         case MTC_24_FPS:
303                 timecode.rate = 24;
304                 timecode.drop = false;
305                 tc_format = timecode_24;
306                 can_notify_on_unknown_rate = true;
307                 break;
308         case MTC_25_FPS:
309                 timecode.rate = 25;
310                 timecode.drop = false;
311                 tc_format = timecode_25;
312                 can_notify_on_unknown_rate = true;
313                 break;
314         case MTC_30_FPS_DROP:
315                 timecode.rate = 30;
316                 timecode.drop = true;
317                 tc_format = timecode_30drop;
318                 can_notify_on_unknown_rate = true;
319                 break;
320         case MTC_30_FPS:
321                 timecode.rate = 30;
322                 timecode.drop = false;
323                 can_notify_on_unknown_rate = true;
324                 tc_format = timecode_30;
325                 break;
326         default:
327                 /* throttle error messages about unknown MTC rates */
328                 if (can_notify_on_unknown_rate) {
329                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
330                                                  (int) msg[4])
331                               << endmsg;
332                         can_notify_on_unknown_rate = false;
333                 }
334                 timecode.rate = session.timecode_frames_per_second();
335                 timecode.drop = session.timecode_drop_frames();
336                 reset_tc = false;
337         }
338
339         if (reset_tc) {
340                 TimecodeFormat cur_timecode = session.config.get_timecode_format();
341                 if (Config->get_timecode_sync_frame_rate()) {
342                         /* enforce time-code */
343                         if (!did_reset_tc_format) {
344                                 saved_tc_format = cur_timecode;
345                                 did_reset_tc_format = true;
346                         }
347                         if (cur_timecode != tc_format) {
348                                 warning << _("Session and MTC framerate mismatch.") << endmsg;
349                         }
350                         session.config.set_timecode_format (tc_format);
351                 } else {
352                         /* only warn about TC mismatch */
353                         if (mtc_timecode != tc_format) printed_timecode_warning = false;
354                         if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
355
356                         if (cur_timecode != tc_format && ! printed_timecode_warning) {
357                                 warning << _("Session and MTC framerate mismatch.") << endmsg;
358                                 printed_timecode_warning = true;
359                         }
360                 }
361                 mtc_timecode = tc_format;
362                 a3e_timecode = cur_timecode;
363         }
364
365         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4)\n",
366                                                  now, timecode, mtc_frame, was_full));
367
368         if (was_full || outside_window (mtc_frame)) {
369                 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self()));
370                 session.timecode_to_sample (timecode, mtc_frame, true, false); // sets mtc_frame
371                 session.request_locate (mtc_frame, false);
372                 session.request_transport_speed (0);
373                 update_mtc_status (MIDI::MTC_Stopped);
374                 reset (false);
375                 reset_window (mtc_frame);
376
377         } else {
378
379                 /* we've had the first set of 8 qtr frame messages, determine position
380                    and allow continuing qtr frame messages to provide position
381                    and speed information.
382                 */
383
384                 /* do a careful conversion of the timecode value to a position
385                    so that we take drop/nondrop and all that nonsense into
386                    consideration.
387                 */
388
389                 session.timecode_to_sample (timecode, mtc_frame, true, false); // sets mtc_frame
390
391                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
392                    frames) after the instance when the contents of the mtc quarter
393                    frames were decided. Add time to compensate for the elapsed 1.75
394                    frames. Also compensate for audio latency.
395                 */
396
397                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame = %1 | %2 FPTC | LAT: %3\n",
398                                                          mtc_frame, session.frames_per_timecode_frame(), session.worst_playback_latency()));
399
400                 long int mtc_off = (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_playback_latency();
401                 double qtr = (session.frames_per_timecode_frame() / 4.0);
402
403                 switch (port->parser()->mtc_running()) {
404                 case MTC_Backward:
405                         mtc_frame -= mtc_off;
406                         qtr *= -1.0;
407                         break;
408                 case MTC_Forward:
409                         mtc_frame += mtc_off;
410                         break;
411                 default:
412                         break;
413                 }
414
415                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/latency comp) = %1\n", mtc_frame));
416
417                 if (now) {
418                         if (first_mtc_timestamp == 0 || current.timestamp == 0) {
419                                 first_mtc_timestamp = now;
420                                 init_mtc_dll(mtc_frame, qtr);
421                         }
422                         current.guard1++;
423                         current.position = mtc_frame;
424                         current.timestamp = now;
425                         current.guard2++;
426                         reset_window (mtc_frame);
427                 }
428         }
429
430         if (now) {
431                 last_inbound_frame = now;
432         }
433         busy_guard2++;
434 }
435
436 void
437 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
438 {
439         /* XXX !!! thread safety ... called from MIDI I/O context
440          * on locate (via ::update_mtc_time())
441          */
442         DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", ::pthread_self()));
443         return; // why was this fn needed anyway ? it just messes up things -> use reset.
444         busy_guard1++;
445
446         switch (status) {
447         case MTC_Stopped:
448                 current.guard1++;
449                 current.position = mtc_frame;
450                 current.timestamp = 0;
451                 current.speed = 0;
452                 current.guard2++;
453
454                 break;
455
456         case MTC_Forward:
457                 current.guard1++;
458                 current.position = mtc_frame;
459                 current.timestamp = 0;
460                 current.speed = 0;
461                 current.guard2++;
462                 break;
463
464         case MTC_Backward:
465                 current.guard1++;
466                 current.position = mtc_frame;
467                 current.timestamp = 0;
468                 current.speed = 0;
469                 current.guard2++;
470                 break;
471         }
472         busy_guard2++;
473 }
474
475 void
476 MTC_Slave::reset_window (framepos_t root)
477 {
478         /* if we're waiting for the master to catch us after seeking ahead, keep the window
479            of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
480            ahead of the window root (taking direction into account).
481         */
482
483         switch (port->parser()->mtc_running()) {
484         case MTC_Forward:
485                 window_begin = root;
486                 transport_direction = 1;
487                 if (session.slave_state() == Session::Running) {
488                         window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
489                 } else {
490                         window_end = root + labs(seekahead_distance ());
491                 }
492                 break;
493
494         case MTC_Backward:
495                 transport_direction = -1;
496                 if (session.slave_state() == Session::Running) {
497                         framecnt_t const d = session.frames_per_timecode_frame() * frame_tolerance;
498                         if (root > d) {
499                                 window_begin = root - d;
500                                 window_end = root;
501                         } else {
502                                 window_begin = 0;
503                         }
504                 } else {
505                         framecnt_t const d = labs(seekahead_distance ());
506                         if (root > d) {
507                                 window_begin = root - d;
508                         } else {
509                                 window_begin = 0;
510                         }
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
551         SafeTime last;
552         framecnt_t elapsed;
553
554         read_current (&last);
555
556         /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
557         if (last.timestamp == 0) { engine_dll_initstate = 0; }
558         else if (engine_dll_initstate != transport_direction) { 
559                 engine_dll_initstate = transport_direction;
560                 init_engine_dll(last.position, session.engine().frames_per_cycle());
561         }
562
563         if (last.timestamp == 0) {
564                 speed = 0;
565                 pos = session.transport_frame() ; // last.position;
566                 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos));
567                 return true;
568         }
569
570         /* no timecode for two frames - conclude that it's stopped */
571         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
572                 speed = 0;
573                 pos = last.position;
574                 session.request_locate (pos, false);
575                 session.request_transport_speed (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\n", te0, te1, e, speed_flt));
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 (pos <0) queue_reset(true);
624
625         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
626                                                  speed, pos, last.position, elapsed,  pos - sess_pos));
627
628         return true;
629 }