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;
189 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
192 DEBUG_TRACE (DEBUG::MTC, "MTC_Slave::handle_locate\n");
194 mtc[4] = last_mtc_fps_byte;
195 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
200 update_mtc_time (mtc, true, 0);
204 MTC_Slave::read_current (SafeTime *st) const
210 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
217 } while (st->guard1 != st->guard2);
221 MTC_Slave::init_mtc_dll(framepos_t tme, double qtr)
223 omega = 2.0 * M_PI * qtr / double(session.frame_rate());
224 b = 1.4142135623730950488 * omega;
230 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
234 /* called from MIDI parser */
236 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now)
239 const double qtr_d = quarter_frame_duration;
240 const framepos_t qtr = rint(qtr_d);
242 mtc_frame += qtr * transport_direction;
244 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
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);
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));
259 current.position = mtc_frame;
260 current.timestamp = now;
261 current.speed = mtc_speed;
265 last_inbound_frame = now;
270 /* called from MIDI parser _after_ update_mtc_qtr()
271 * when a full TC has been received
274 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
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.
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;
287 timecode.hours = msg[3];
288 timecode.minutes = msg[2];
289 timecode.seconds = msg[1];
290 timecode.frames = msg[0];
292 last_mtc_fps_byte = msg[4];
294 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
303 timecode.drop = false;
304 tc_format = timecode_24;
305 can_notify_on_unknown_rate = true;
309 timecode.drop = false;
310 tc_format = timecode_25;
311 can_notify_on_unknown_rate = true;
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;
321 timecode.drop = false;
322 can_notify_on_unknown_rate = true;
323 tc_format = timecode_30;
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"),
331 can_notify_on_unknown_rate = false;
333 timecode.rate = session.timecode_frames_per_second();
334 timecode.drop = session.timecode_drop_frames();
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;
346 if (cur_timecode != tc_format) {
347 warning << _("Session and MTC framerate mismatch.") << endmsg;
349 session.config.set_timecode_format (tc_format);
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;
355 if (cur_timecode != tc_format && ! printed_timecode_warning) {
356 warning << _("Session and MTC framerate mismatch.") << endmsg;
357 printed_timecode_warning = true;
360 mtc_timecode = tc_format;
361 a3e_timecode = cur_timecode;
363 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
366 /* do a careful conversion of the timecode value to a position
367 so that we take drop/nondrop and all that nonsense into
371 quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
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()
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));
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);
388 reset_window (mtc_frame);
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.
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
401 double qtr = quarter_frame_duration;
402 long int mtc_off = (long) rint(7.0 * qtr);
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()));
407 switch (port->parser()->mtc_running()) {
409 mtc_frame -= mtc_off;
413 mtc_frame += mtc_off;
419 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
422 if (first_mtc_timestamp == 0 || current.timestamp == 0) {
423 first_mtc_timestamp = now;
424 init_mtc_dll(mtc_frame, qtr);
427 current.position = mtc_frame;
428 current.timestamp = now;
430 reset_window (mtc_frame);
435 last_inbound_frame = now;
441 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
443 /* XXX !!! thread safety ... called from MIDI I/O context
444 * on locate (via ::update_mtc_time())
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.
453 current.position = mtc_frame;
454 current.timestamp = 0;
462 current.position = mtc_frame;
463 current.timestamp = 0;
470 current.position = mtc_frame;
471 current.timestamp = 0;
480 MTC_Slave::reset_window (framepos_t root)
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).
486 framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance);
488 switch (port->parser()->mtc_running()) {
491 transport_direction = 1;
492 window_end = root + d;
496 transport_direction = -1;
498 window_begin = root - d;
511 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
515 MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
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
521 * But this is only really a problem if the user performs manual
522 * seeks while transport is running and slaved to MTC.
524 oe = 2.0 * M_PI * double(inc/6.0) / double(session.frame_rate());
525 be = 1.4142135623730950488 * oe;
528 ee2 = double(transport_direction * inc);
531 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
534 /* main entry point from session_process.cc
535 * in jack_process callback context */
537 MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
539 framepos_t now = session.engine().frame_time_at_cycle_start();
540 framepos_t sess_pos = session.transport_frame(); // corresponds to now
545 read_current (&last);
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());
554 if (last.timestamp == 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));
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())) {
565 session.request_locate (pos, false);
566 session.request_transport_speed (0);
567 engine_dll_initstate = 0;
569 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n");
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));
578 double speed_flt = last.speed; ///< MTC speed from MTC-quarter-frame DLL
580 /* interpolate position according to speed and time since last quarter-frame*/
581 if (speed_flt == 0.0f) {
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));
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..
598 /* update engine DLL and calculate speed */
599 const double e = double (last.position + elapsed - sess_pos);
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() ));
608 pos = last.position + elapsed;
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
615 if (!session.actively_recording()
616 && ( (pos < 0) || (labs(pos - sess_pos) > 4 * resolution()) )
618 engine_dll_initstate = 0;
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));
628 Timecode::TimecodeFormat
629 MTC_Slave::apparent_timecode_format () const
635 MTC_Slave::approximate_current_position() const
638 if (last.timestamp == 0) {
639 return "--:--:--:--";
641 read_current (&last);
642 return Timecode::timecode_format_sampletime(
644 double(session.frame_rate()),
645 Timecode::timecode_to_frames_per_second(mtc_timecode),
646 Timecode::timecode_has_drop_frames(mtc_timecode));