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;
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 ();
64 mtc_timecode = timecode_60; // track changes of MTC timecode
65 a3e_timecode = timecode_60; // track canges of Ardour's timecode
66 printed_timecode_warning = false;
72 MTC_Slave::~MTC_Slave()
74 port_connections.drop_connections();
76 while (busy_guard1 != busy_guard2) {
77 /* make sure MIDI parser is not currently calling any callbacks in here,
78 * else there's a segfault ahead!
80 * XXX this is called from jack rt-context :(
81 * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
86 if (did_reset_tc_format) {
87 session.config.set_timecode_format (saved_tc_format);
92 MTC_Slave::rebind (MIDI::Port& p)
94 port_connections.drop_connections ();
98 port->parser()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
99 port->parser()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
100 port->parser()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
104 MTC_Slave::give_slave_full_control_over_transport_speed() const
106 return true; // DLL align to engine transport
107 // return false; // for Session-level computed varispeed
111 MTC_Slave::resolution () const
113 return (framecnt_t) session.frames_per_timecode_frame();
117 MTC_Slave::seekahead_distance () const
119 return session.frames_per_timecode_frame() * 2 * transport_direction;
123 MTC_Slave::outside_window (framepos_t pos) const
125 return ((pos < window_begin) || (pos > window_end));
130 MTC_Slave::locked () const
132 return port->parser()->mtc_locked();
136 MTC_Slave::ok() const
142 MTC_Slave::queue_reset (bool reset_pos)
144 Glib::Threads::Mutex::Lock lm (reset_lock);
147 reset_position = true;
152 MTC_Slave::maybe_reset ()
154 Glib::Threads::Mutex::Lock lm (reset_lock);
157 reset (reset_position);
159 reset_position = false;
164 MTC_Slave::reset (bool with_position)
166 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_Slave reset %1\n", with_position?"with position":"without position"));
168 last_inbound_frame = 0;
170 current.position = 0;
171 current.timestamp = 0;
175 last_inbound_frame = 0;
177 current.timestamp = 0;
181 first_mtc_timestamp = 0;
184 transport_direction = 1;
188 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
191 DEBUG_TRACE (DEBUG::MTC, "MTC_Slave::handle_locate\n");
193 mtc[4] = last_mtc_fps_byte;
194 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
199 update_mtc_time (mtc, true, 0);
203 MTC_Slave::read_current (SafeTime *st) const
209 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
216 } while (st->guard1 != st->guard2);
220 MTC_Slave::init_mtc_dll(framepos_t mtc_frame, double qtr)
222 omega = 2.0 * M_PI * (session.frames_per_timecode_frame() / 4.0) / double(session.frame_rate());
223 b = 1.4142135623730950488 * omega;
227 t0 = double(mtc_frame);
229 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
233 /* called from MIDI parser */
235 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now)
238 const framepos_t qtr = (session.frames_per_timecode_frame() / 4);
239 const double qtr_d = (session.frames_per_timecode_frame() / 4.0);
241 mtc_frame += qtr * transport_direction;
243 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
245 double mtc_speed = 0;
246 if (first_mtc_timestamp != 0) {
247 /* update MTC DLL and calculate speed */
248 const double e = double(transport_direction) * (double(now) - double(current.timestamp) - qtr_d);
253 mtc_speed = (t1 - t0) / qtr_d;
254 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame DLL t0:%1 t1:%2 err:%3 spd:%4\n", t0, t1, e, mtc_speed));
258 current.position = mtc_frame;
259 current.timestamp = now;
260 current.speed = mtc_speed;
264 last_inbound_frame = now;
269 /* called from MIDI parser _after_ update_mtc_qtr()
270 * when a full TC has been received
273 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
277 /* "now" can be zero if this is called from a context where we do not have or do not want
278 to use a timestamp indicating when this MTC time was received. example: when we received
279 a locate command via MMC.
282 //DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self()));
283 Timecode::Time timecode;
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:
315 timecode.drop = true;
316 tc_format = timecode_30drop;
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 (0 /* TODO preferences */) {
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;
364 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4)\n",
365 now, timecode, mtc_frame, was_full));
367 if (was_full || outside_window (mtc_frame)) {
368 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self()));
369 session.timecode_to_sample (timecode, mtc_frame, true, false); // sets mtc_frame
370 session.request_locate (mtc_frame, false);
371 session.request_transport_speed (0);
372 update_mtc_status (MIDI::MTC_Stopped);
374 reset_window (mtc_frame);
378 /* we've had the first set of 8 qtr frame messages, determine position
379 and allow continuing qtr frame messages to provide position
380 and speed information.
383 /* do a careful conversion of the timecode value to a position
384 so that we take drop/nondrop and all that nonsense into
388 session.timecode_to_sample (timecode, mtc_frame, true, false); // sets mtc_frame
390 /* We received the last quarter frame 7 quarter frames (1.75 mtc
391 frames) after the instance when the contents of the mtc quarter
392 frames were decided. Add time to compensate for the elapsed 1.75
393 frames. Also compensate for audio latency.
396 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame = %1 | %2 FPTC | LAT: %3\n",
397 mtc_frame, session.frames_per_timecode_frame(), session.worst_playback_latency()));
399 long int mtc_off = (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_playback_latency();
400 double qtr = (session.frames_per_timecode_frame() / 4.0);
402 switch (port->parser()->mtc_running()) {
404 mtc_frame -= mtc_off;
408 mtc_frame += mtc_off;
414 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/latency comp) = %1\n", mtc_frame));
417 if (first_mtc_timestamp == 0 || current.timestamp == 0) {
418 first_mtc_timestamp = now;
419 init_mtc_dll(mtc_frame, qtr);
422 current.position = mtc_frame;
423 current.timestamp = now;
425 reset_window (mtc_frame);
430 last_inbound_frame = now;
436 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
438 /* XXX !!! thread safety ... called from MIDI I/O context
439 * on locate (via ::update_mtc_time())
441 DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", ::pthread_self()));
442 return; // why was this fn needed anyway ? it just messes up things -> use reset.
448 current.position = mtc_frame;
449 current.timestamp = 0;
457 current.position = mtc_frame;
458 current.timestamp = 0;
465 current.position = mtc_frame;
466 current.timestamp = 0;
475 MTC_Slave::reset_window (framepos_t root)
477 /* if we're waiting for the master to catch us after seeking ahead, keep the window
478 of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
479 ahead of the window root (taking direction into account).
482 switch (port->parser()->mtc_running()) {
485 transport_direction = 1;
486 if (session.slave_state() == Session::Running) {
487 window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
489 window_end = root + labs(seekahead_distance ());
494 transport_direction = -1;
495 if (session.slave_state() == Session::Running) {
496 framecnt_t const d = session.frames_per_timecode_frame() * frame_tolerance;
498 window_begin = root - d;
504 framecnt_t const d = labs(seekahead_distance ());
506 window_begin = root - d;
519 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
523 MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
525 /* the bandwidth of the DLL is a trade-off,
526 * because the max-speed of the transport in ardour is
527 * limited to +-8.0, a larger bandwidth would cause oscillations
529 * But this is only really a problem if the user performs manual
530 * seeks while transport is running and slaved to MTC.
532 oe = 2.0 * M_PI * double(inc/6.0) / double(session.frame_rate());
533 be = 1.4142135623730950488 * oe;
536 ee2 = double(transport_direction * inc);
539 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
542 /* main entry point from session_process.cc
543 * in jack_process callback context */
545 MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
547 framepos_t now = session.engine().frame_time_at_cycle_start();
548 framepos_t sess_pos = session.transport_frame(); // corresponds to now
553 read_current (&last);
555 /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
556 if (last.timestamp == 0) { engine_dll_initstate = 0; }
557 else if (engine_dll_initstate != transport_direction) {
558 engine_dll_initstate = transport_direction;
559 init_engine_dll(last.position, session.engine().frames_per_cycle());
562 if (last.timestamp == 0) {
564 pos = session.transport_frame() ; // last.position;
565 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos));
569 /* no timecode for two frames - conclude that it's stopped */
570 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
573 session.request_locate (pos, false);
574 session.request_transport_speed (0);
576 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n");
582 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position mtc-tme: %1 mtc-pos: %2\n", last.timestamp, last.position));
583 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position eng-tme: %1 eng-pos: %2\n", now, sess_pos));
585 double speed_flt = last.speed; ///< MTC speed from MTC-quarter-frame DLL
587 /* interpolate position according to speed and time since last quarter-frame*/
588 if (speed_flt == 0.0f) {
593 /* scale elapsed time by the current MTC speed */
594 if (last.timestamp && (now > last.timestamp)) {
595 elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp));
599 if (give_slave_full_control_over_transport_speed()) {
600 /* there is a frame-delta engine vs MTC position
601 * mostly due to quantization and rounding of (speed * nframes)
602 * thus we use an other DLL..
605 /* update engine DLL and calculate speed */
606 const double e = double (last.position + elapsed - sess_pos);
610 speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle());
611 DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4\n", te0, te1, e, speed_flt));
615 pos = last.position + elapsed;
618 /* may happen if the user performs a seek in the timeline while slaved to running MTC
619 * engine-DLL can oscillate back before 0.
620 * also see note in MTC_Slave::init_engine_dll
622 if (pos <0) queue_reset(true);
624 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
625 speed, pos, last.position, elapsed, pos - sess_pos));