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()));
285 TimecodeFormat tc_format;
286 bool reset_tc = true;
288 timecode.hours = msg[3];
289 timecode.minutes = msg[2];
290 timecode.seconds = msg[1];
291 timecode.frames = msg[0];
293 last_mtc_fps_byte = msg[4];
295 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
304 timecode.drop = false;
305 tc_format = timecode_24;
306 can_notify_on_unknown_rate = true;
310 timecode.drop = false;
311 tc_format = timecode_25;
312 can_notify_on_unknown_rate = true;
314 case MTC_30_FPS_DROP:
316 timecode.drop = true;
317 tc_format = timecode_30drop;
318 can_notify_on_unknown_rate = true;
322 timecode.drop = false;
323 can_notify_on_unknown_rate = true;
324 tc_format = timecode_30;
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"),
332 can_notify_on_unknown_rate = false;
334 timecode.rate = session.timecode_frames_per_second();
335 timecode.drop = session.timecode_drop_frames();
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;
347 if (cur_timecode != tc_format) {
348 warning << _("Session and MTC framerate mismatch.") << endmsg;
350 session.config.set_timecode_format (tc_format);
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;
356 if (cur_timecode != tc_format && ! printed_timecode_warning) {
357 warning << _("Session and MTC framerate mismatch.") << endmsg;
358 printed_timecode_warning = true;
361 mtc_timecode = tc_format;
362 a3e_timecode = cur_timecode;
364 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
367 /* do a careful conversion of the timecode value to a position
368 so that we take drop/nondrop and all that nonsense into
372 quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
373 session.timecode_to_sample (timecode, mtc_frame, true, false); // audio-frame according to Ardour's FPS
375 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
376 now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
378 if (was_full || outside_window (mtc_frame)) {
379 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self()));
380 session.request_locate (mtc_frame, false);
381 session.request_transport_speed (0);
382 update_mtc_status (MIDI::MTC_Stopped);
384 reset_window (mtc_frame);
387 /* we've had the first set of 8 qtr frame messages, determine position
388 and allow continuing qtr frame messages to provide position
389 and speed information.
392 /* We received the last quarter frame 7 quarter frames (1.75 mtc
393 frames) after the instance when the contents of the mtc quarter
394 frames were decided. Add time to compensate for the elapsed 1.75
397 double qtr = quarter_frame_duration;
398 long int mtc_off = (long) rint(7.0 * qtr);
400 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
401 mtc_frame, (4.0*qtr), session.frames_per_timecode_frame()));
403 switch (port->parser()->mtc_running()) {
405 mtc_frame -= mtc_off;
409 mtc_frame += mtc_off;
415 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
418 if (first_mtc_timestamp == 0 || current.timestamp == 0) {
419 first_mtc_timestamp = now;
420 init_mtc_dll(mtc_frame, qtr);
423 current.position = mtc_frame;
424 current.timestamp = now;
426 reset_window (mtc_frame);
431 last_inbound_frame = now;
437 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
439 /* XXX !!! thread safety ... called from MIDI I/O context
440 * on locate (via ::update_mtc_time())
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.
449 current.position = mtc_frame;
450 current.timestamp = 0;
458 current.position = mtc_frame;
459 current.timestamp = 0;
466 current.position = mtc_frame;
467 current.timestamp = 0;
476 MTC_Slave::reset_window (framepos_t root)
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).
482 framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance);
484 switch (port->parser()->mtc_running()) {
487 transport_direction = 1;
488 window_end = root + d;
492 transport_direction = -1;
494 window_begin = root - d;
507 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
511 MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
513 /* the bandwidth of the DLL is a trade-off,
514 * because the max-speed of the transport in ardour is
515 * limited to +-8.0, a larger bandwidth would cause oscillations
517 * But this is only really a problem if the user performs manual
518 * seeks while transport is running and slaved to MTC.
520 oe = 2.0 * M_PI * double(inc/6.0) / double(session.frame_rate());
521 be = 1.4142135623730950488 * oe;
524 ee2 = double(transport_direction * inc);
527 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
530 /* main entry point from session_process.cc
531 * in jack_process callback context */
533 MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
535 framepos_t now = session.engine().frame_time_at_cycle_start();
536 framepos_t sess_pos = session.transport_frame(); // corresponds to now
541 read_current (&last);
543 /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
544 if (last.timestamp == 0) { engine_dll_initstate = 0; }
545 else if (engine_dll_initstate != transport_direction) {
546 engine_dll_initstate = transport_direction;
547 init_engine_dll(last.position, session.engine().frames_per_cycle());
550 if (last.timestamp == 0) {
552 pos = session.transport_frame() ; // last.position;
553 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos));
557 /* no timecode for two frames - conclude that it's stopped */
558 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
561 session.request_locate (pos, false);
562 session.request_transport_speed (0);
563 engine_dll_initstate = 0;
565 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n");
571 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position mtc-tme: %1 mtc-pos: %2\n", last.timestamp, last.position));
572 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position eng-tme: %1 eng-pos: %2\n", now, sess_pos));
574 double speed_flt = last.speed; ///< MTC speed from MTC-quarter-frame DLL
576 /* interpolate position according to speed and time since last quarter-frame*/
577 if (speed_flt == 0.0f) {
582 /* scale elapsed time by the current MTC speed */
583 if (last.timestamp && (now > last.timestamp)) {
584 elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp));
588 if (give_slave_full_control_over_transport_speed()) {
589 /* there is a frame-delta engine vs MTC position
590 * mostly due to quantization and rounding of (speed * nframes)
591 * thus we use an other DLL..
594 /* update engine DLL and calculate speed */
595 const double e = double (last.position + elapsed - sess_pos);
599 speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle());
600 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() ));
604 pos = last.position + elapsed;
607 /* may happen if the user performs a seek in the timeline while slaved to running MTC
608 * engine-DLL can oscillate back before 0.
609 * also see note in MTC_Slave::init_engine_dll
611 if (!session.actively_recording()
612 && ( (pos < 0) || (labs(pos - sess_pos) > 4 * resolution()) )
614 engine_dll_initstate = 0;
618 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
619 speed, pos, last.position, elapsed, pos - sess_pos));
624 Timecode::TimecodeFormat
625 MTC_Slave::apparent_timecode_format () const
627 /* XXX to be computed, determined from incoming stream */