2 Copyright (C) 2002-4 Paul Davis
3 Overhaul 2012 Robin Gareus <robin@gareus.org>
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.
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.
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.
23 #include <sys/types.h>
26 #include "pbd/error.h"
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"
37 using namespace ARDOUR;
40 using namespace Timecode;
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.
49 const int MTC_Slave::frame_tolerance = 2;
51 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
54 can_notify_on_unknown_rate = true;
55 did_reset_tc_format = false;
57 reset_position = false;
59 engine_dll_initstate = 0;
60 busy_guard1 = busy_guard2 = 0;
62 last_mtc_fps_byte = session.get_mtc_timecode_bits ();
63 quarter_frame_duration = (double(session.frames_per_timecode_frame()) / 4.0);
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;
73 MTC_Slave::~MTC_Slave()
75 port_connections.drop_connections();
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!
81 * XXX this is called from jack rt-context :(
82 * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
87 if (did_reset_tc_format) {
88 session.config.set_timecode_format (saved_tc_format);
93 MTC_Slave::rebind (MIDI::Port& p)
95 port_connections.drop_connections ();
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));
105 MTC_Slave::give_slave_full_control_over_transport_speed() const
107 return true; // DLL align to engine transport
108 // return false; // for Session-level computed varispeed
112 MTC_Slave::resolution () const
114 return (framecnt_t) quarter_frame_duration * 4.0;
118 MTC_Slave::seekahead_distance () const
120 return quarter_frame_duration * 8 * transport_direction;
124 MTC_Slave::outside_window (framepos_t pos) const
126 return ((pos < window_begin) || (pos > window_end));
131 MTC_Slave::locked () const
133 return port->parser()->mtc_locked();
137 MTC_Slave::ok() const
143 MTC_Slave::queue_reset (bool reset_pos)
145 Glib::Threads::Mutex::Lock lm (reset_lock);
148 reset_position = true;
153 MTC_Slave::maybe_reset ()
155 Glib::Threads::Mutex::Lock lm (reset_lock);
158 reset (reset_position);
160 reset_position = false;
165 MTC_Slave::reset (bool with_position)
167 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_Slave reset %1\n", with_position?"with position":"without position"));
169 last_inbound_frame = 0;
171 current.position = 0;
172 current.timestamp = 0;
176 last_inbound_frame = 0;
178 current.timestamp = 0;
182 first_mtc_timestamp = 0;
185 transport_direction = 1;
190 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
193 DEBUG_TRACE (DEBUG::MTC, "MTC_Slave::handle_locate\n");
195 mtc[4] = last_mtc_fps_byte;
196 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
201 update_mtc_time (mtc, true, 0);
205 MTC_Slave::read_current (SafeTime *st) const
211 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
218 } while (st->guard1 != st->guard2);
222 MTC_Slave::init_mtc_dll(framepos_t tme, double qtr)
224 omega = 2.0 * M_PI * qtr / double(session.frame_rate());
225 b = 1.4142135623730950488 * omega;
231 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
235 /* called from MIDI parser */
237 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now)
240 const double qtr_d = quarter_frame_duration;
241 const framepos_t qtr = rint(qtr_d);
243 mtc_frame += qtr * transport_direction;
245 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
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);
256 mtc_speed = (t1 - t0) / qtr_d;
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));
262 current.position = mtc_frame;
263 current.timestamp = ts;
264 current.speed = mtc_speed;
268 last_inbound_frame = now;
273 /* called from MIDI parser _after_ update_mtc_qtr()
274 * when a full TC has been received
277 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
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.
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;
290 timecode.hours = msg[3];
291 timecode.minutes = msg[2];
292 timecode.seconds = msg[1];
293 timecode.frames = msg[0];
295 last_mtc_fps_byte = msg[4];
297 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
306 timecode.drop = false;
307 tc_format = timecode_24;
308 can_notify_on_unknown_rate = true;
312 timecode.drop = false;
313 tc_format = timecode_25;
314 can_notify_on_unknown_rate = true;
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;
324 timecode.drop = false;
325 can_notify_on_unknown_rate = true;
326 tc_format = timecode_30;
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"),
334 can_notify_on_unknown_rate = false;
336 timecode.rate = session.timecode_frames_per_second();
337 timecode.drop = session.timecode_drop_frames();
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;
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))
355 session.config.set_timecode_format (tc_format);
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;
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))
366 printed_timecode_warning = true;
369 mtc_timecode = tc_format;
370 a3e_timecode = cur_timecode;
372 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
375 /* do a careful conversion of the timecode value to a position
376 so that we take drop/nondrop and all that nonsense into
380 quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
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()
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));
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);
397 reset_window (mtc_frame);
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.
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
410 double qtr = quarter_frame_duration;
411 long int mtc_off = (long) rint(7.0 * qtr);
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()));
416 switch (port->parser()->mtc_running()) {
418 mtc_frame -= mtc_off;
422 mtc_frame += mtc_off;
428 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
431 if (first_mtc_timestamp == 0 || current.timestamp == 0) {
432 first_mtc_timestamp = now;
433 init_mtc_dll(mtc_frame, qtr);
436 current.position = mtc_frame;
437 current.timestamp = now;
439 reset_window (mtc_frame);
444 last_inbound_frame = now;
450 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
452 /* XXX !!! thread safety ... called from MIDI I/O context
453 * on locate (via ::update_mtc_time())
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.
462 current.position = mtc_frame;
463 current.timestamp = 0;
471 current.position = mtc_frame;
472 current.timestamp = 0;
479 current.position = mtc_frame;
480 current.timestamp = 0;
489 MTC_Slave::reset_window (framepos_t root)
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).
495 framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance);
497 switch (port->parser()->mtc_running()) {
500 transport_direction = 1;
501 window_end = root + d;
505 transport_direction = -1;
507 window_begin = root - d;
520 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
524 MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
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
530 * But this is only really a problem if the user performs manual
531 * seeks while transport is running and slaved to MTC.
533 oe = 2.0 * M_PI * double(inc/6.0) / double(session.frame_rate());
534 be = 1.4142135623730950488 * oe;
537 ee2 = double(transport_direction * inc);
540 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
543 /* main entry point from session_process.cc
544 * in jack_process callback context */
546 MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
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();
555 read_current (&last);
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());
564 if (last.timestamp == 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));
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())) {
575 session.request_locate (pos, false);
576 session.request_transport_speed (0);
577 engine_dll_initstate = 0;
579 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n");
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));
588 double speed_flt = last.speed; ///< MTC speed from MTC-quarter-frame DLL
590 /* interpolate position according to speed and time since last quarter-frame*/
591 if (speed_flt == 0.0f) {
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));
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..
608 /* update engine DLL and calculate speed */
609 const double e = double (last.position + elapsed - sess_pos);
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() ));
618 pos = last.position + elapsed;
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
625 if (!session.actively_recording()
627 && ( (pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()) )
629 engine_dll_initstate = 0;
634 /* provide a 1% deadzone to lock the speed */
635 if (fabs(speed - 1.0) <= 0.01)
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));
642 current_delta = (pos - sess_pos);
647 Timecode::TimecodeFormat
648 MTC_Slave::apparent_timecode_format () const
654 MTC_Slave::approximate_current_position() const
657 read_current (&last);
658 if (last.timestamp == 0 || reset_pending) {
659 return " --:--:--:--";
661 return Timecode::timecode_format_sampletime(
663 double(session.frame_rate()),
664 Timecode::timecode_to_frames_per_second(mtc_timecode),
665 Timecode::timecode_has_drop_frames(mtc_timecode));
669 MTC_Slave::approximate_current_delta() const
673 read_current (&last);
674 if (last.timestamp == 0 || reset_pending) {
675 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
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));
681 return std::string(delta);