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"
33 #include "ardour/pi_controller.h"
38 using namespace ARDOUR;
41 using namespace Timecode;
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.
50 const int MTC_Slave::frame_tolerance = 2;
52 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
55 can_notify_on_unknown_rate = true;
56 did_reset_tc_format = false;
58 reset_position = false;
60 engine_dll_initstate = 0;
61 busy_guard1 = busy_guard2 = 0;
63 last_mtc_fps_byte = session.get_mtc_timecode_bits ();
64 quarter_frame_duration = (double(session.frames_per_timecode_frame()) / 4.0);
66 mtc_timecode = timecode_60; // track changes of MTC timecode
67 a3e_timecode = timecode_60; // track canges of Ardour's timecode
68 printed_timecode_warning = false;
74 MTC_Slave::~MTC_Slave()
76 port_connections.drop_connections();
78 while (busy_guard1 != busy_guard2) {
79 /* make sure MIDI parser is not currently calling any callbacks in here,
80 * else there's a segfault ahead!
82 * XXX this is called from jack rt-context :(
83 * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
88 if (did_reset_tc_format) {
89 session.config.set_timecode_format (saved_tc_format);
94 MTC_Slave::rebind (MIDI::Port& p)
96 port_connections.drop_connections ();
100 port->parser()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
101 port->parser()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
102 port->parser()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
106 MTC_Slave::give_slave_full_control_over_transport_speed() const
108 return true; // DLL align to engine transport
109 // return false; // for Session-level computed varispeed
113 MTC_Slave::resolution () const
115 return (framecnt_t) quarter_frame_duration * 4.0;
119 MTC_Slave::seekahead_distance () const
121 return quarter_frame_duration * 8 * transport_direction;
125 MTC_Slave::outside_window (framepos_t pos) const
127 return ((pos < window_begin) || (pos > window_end));
132 MTC_Slave::locked () const
134 return port->parser()->mtc_locked();
138 MTC_Slave::ok() const
144 MTC_Slave::queue_reset (bool reset_pos)
146 Glib::Threads::Mutex::Lock lm (reset_lock);
149 reset_position = true;
154 MTC_Slave::maybe_reset ()
156 Glib::Threads::Mutex::Lock lm (reset_lock);
159 reset (reset_position);
161 reset_position = false;
166 MTC_Slave::reset (bool with_position)
168 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_Slave reset %1\n", with_position?"with position":"without position"));
170 last_inbound_frame = 0;
172 current.position = 0;
173 current.timestamp = 0;
177 last_inbound_frame = 0;
179 current.timestamp = 0;
183 first_mtc_timestamp = 0;
186 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));
247 double mtc_speed = 0;
248 if (first_mtc_timestamp != 0) {
249 /* update MTC DLL and calculate speed */
250 const double e = double(transport_direction) * (double(now) - double(current.timestamp) - qtr_d);
255 mtc_speed = (t1 - t0) / qtr_d;
256 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));
260 current.position = mtc_frame;
261 current.timestamp = now;
262 current.speed = mtc_speed;
266 last_inbound_frame = now;
271 /* called from MIDI parser _after_ update_mtc_qtr()
272 * when a full TC has been received
275 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
279 /* "now" can be zero if this is called from a context where we do not have or do not want
280 to use a timestamp indicating when this MTC time was received. example: when we received
281 a locate command via MMC.
284 //DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self()));
286 TimecodeFormat tc_format;
287 bool reset_tc = true;
289 timecode.hours = msg[3];
290 timecode.minutes = msg[2];
291 timecode.seconds = msg[1];
292 timecode.frames = msg[0];
294 last_mtc_fps_byte = msg[4];
296 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
305 timecode.drop = false;
306 tc_format = timecode_24;
307 can_notify_on_unknown_rate = true;
311 timecode.drop = false;
312 tc_format = timecode_25;
313 can_notify_on_unknown_rate = true;
315 case MTC_30_FPS_DROP:
317 timecode.drop = true;
318 tc_format = timecode_30drop;
319 can_notify_on_unknown_rate = true;
323 timecode.drop = false;
324 can_notify_on_unknown_rate = true;
325 tc_format = timecode_30;
328 /* throttle error messages about unknown MTC rates */
329 if (can_notify_on_unknown_rate) {
330 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
333 can_notify_on_unknown_rate = false;
335 timecode.rate = session.timecode_frames_per_second();
336 timecode.drop = session.timecode_drop_frames();
341 TimecodeFormat cur_timecode = session.config.get_timecode_format();
342 if (Config->get_timecode_sync_frame_rate()) {
343 /* enforce time-code */
344 if (!did_reset_tc_format) {
345 saved_tc_format = cur_timecode;
346 did_reset_tc_format = true;
348 if (cur_timecode != tc_format) {
349 warning << _("Session and MTC framerate mismatch.") << endmsg;
351 session.config.set_timecode_format (tc_format);
353 /* only warn about TC mismatch */
354 if (mtc_timecode != tc_format) printed_timecode_warning = false;
355 if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
357 if (cur_timecode != tc_format && ! printed_timecode_warning) {
358 warning << _("Session and MTC framerate mismatch.") << endmsg;
359 printed_timecode_warning = true;
362 mtc_timecode = tc_format;
363 a3e_timecode = cur_timecode;
365 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
368 /* do a careful conversion of the timecode value to a position
369 so that we take drop/nondrop and all that nonsense into
373 quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
374 session.timecode_to_sample (timecode, mtc_frame, true, false); // audio-frame according to Ardour's FPS
376 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
377 now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
379 if (was_full || outside_window (mtc_frame)) {
380 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self()));
381 session.request_locate (mtc_frame, false);
382 session.request_transport_speed (0);
383 update_mtc_status (MIDI::MTC_Stopped);
385 reset_window (mtc_frame);
388 /* we've had the first set of 8 qtr frame messages, determine position
389 and allow continuing qtr frame messages to provide position
390 and speed information.
393 /* We received the last quarter frame 7 quarter frames (1.75 mtc
394 frames) after the instance when the contents of the mtc quarter
395 frames were decided. Add time to compensate for the elapsed 1.75
398 double qtr = quarter_frame_duration;
399 long int mtc_off = (long) rint(7.0 * qtr);
401 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
402 mtc_frame, (4.0*qtr), session.frames_per_timecode_frame()));
404 switch (port->parser()->mtc_running()) {
406 mtc_frame -= mtc_off;
410 mtc_frame += mtc_off;
416 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
419 if (first_mtc_timestamp == 0 || current.timestamp == 0) {
420 first_mtc_timestamp = now;
421 init_mtc_dll(mtc_frame, qtr);
424 current.position = mtc_frame;
425 current.timestamp = now;
427 reset_window (mtc_frame);
432 last_inbound_frame = now;
438 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
440 /* XXX !!! thread safety ... called from MIDI I/O context
441 * on locate (via ::update_mtc_time())
443 DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", ::pthread_self()));
444 return; // why was this fn needed anyway ? it just messes up things -> use reset.
450 current.position = mtc_frame;
451 current.timestamp = 0;
459 current.position = mtc_frame;
460 current.timestamp = 0;
467 current.position = mtc_frame;
468 current.timestamp = 0;
477 MTC_Slave::reset_window (framepos_t root)
479 /* if we're waiting for the master to catch us after seeking ahead, keep the window
480 of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
481 ahead of the window root (taking direction into account).
483 framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance);
485 switch (port->parser()->mtc_running()) {
488 transport_direction = 1;
489 window_end = root + d;
493 transport_direction = -1;
495 window_begin = root - d;
508 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
512 MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
514 /* the bandwidth of the DLL is a trade-off,
515 * because the max-speed of the transport in ardour is
516 * limited to +-8.0, a larger bandwidth would cause oscillations
518 * But this is only really a problem if the user performs manual
519 * seeks while transport is running and slaved to MTC.
521 oe = 2.0 * M_PI * double(inc/6.0) / double(session.frame_rate());
522 be = 1.4142135623730950488 * oe;
525 ee2 = double(transport_direction * inc);
528 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
531 /* main entry point from session_process.cc
532 * in jack_process callback context */
534 MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
536 framepos_t now = session.engine().frame_time_at_cycle_start();
537 framepos_t sess_pos = session.transport_frame(); // corresponds to now
542 read_current (&last);
544 /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
545 if (last.timestamp == 0) { engine_dll_initstate = 0; }
546 else if (engine_dll_initstate != transport_direction) {
547 engine_dll_initstate = transport_direction;
548 init_engine_dll(last.position, session.engine().frames_per_cycle());
551 if (last.timestamp == 0) {
553 pos = session.transport_frame() ; // last.position;
554 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos));
558 /* no timecode for two frames - conclude that it's stopped */
559 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
562 session.request_locate (pos, false);
563 session.request_transport_speed (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 (pos <0) queue_reset(true);
613 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
614 speed, pos, last.position, elapsed, pos - sess_pos));
619 Timecode::TimecodeFormat
620 MTC_Slave::apparent_timecode_format () const
622 /* XXX to be computed, determined from incoming stream */