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 = session.config.get_timecode_format();
66 a3e_timecode = session.config.get_timecode_format();
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() && last_inbound_frame !=0 && engine_dll_initstate !=0;
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 / 2.0 / 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 = mtc_frame - (double(transport_direction) * (double(now) - double(current.timestamp) + t0));
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));
259 current.position = mtc_frame;
260 current.timestamp = now;
261 current.speed = mtc_speed;
264 last_inbound_frame = now;
272 /* called from MIDI parser _after_ update_mtc_qtr()
273 * when a full TC has been received
276 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now)
280 /* "now" can be zero if this is called from a context where we do not have or do not want
281 to use a timestamp indicating when this MTC time was received. example: when we received
282 a locate command via MMC.
285 //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:
316 if (Config->get_timecode_source_2997()) {
317 tc_format = Timecode::timecode_2997000drop;
318 timecode.rate = (29970.0/1000.0);
320 tc_format = timecode_2997drop;
321 timecode.rate = (30000.0/1001.0);
323 timecode.drop = true;
324 can_notify_on_unknown_rate = true;
328 timecode.drop = false;
329 can_notify_on_unknown_rate = true;
330 tc_format = timecode_30;
333 /* throttle error messages about unknown MTC rates */
334 if (can_notify_on_unknown_rate) {
335 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
338 can_notify_on_unknown_rate = false;
340 timecode.rate = session.timecode_frames_per_second();
341 timecode.drop = session.timecode_drop_frames();
346 TimecodeFormat cur_timecode = session.config.get_timecode_format();
347 if (Config->get_timecode_sync_frame_rate()) {
348 /* enforce time-code */
349 if (!did_reset_tc_format) {
350 saved_tc_format = cur_timecode;
351 did_reset_tc_format = true;
353 if (cur_timecode != tc_format) {
354 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
355 warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
356 Timecode::timecode_format_name(cur_timecode),
357 Timecode::timecode_format_name(tc_format))
361 session.config.set_timecode_format (tc_format);
363 /* only warn about TC mismatch */
364 if (mtc_timecode != tc_format) printed_timecode_warning = false;
365 if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
367 if (cur_timecode != tc_format && ! printed_timecode_warning) {
368 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
369 warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 Ardour:%2."),
370 Timecode::timecode_format_name(tc_format),
371 Timecode::timecode_format_name(cur_timecode))
374 printed_timecode_warning = true;
377 mtc_timecode = tc_format;
378 a3e_timecode = cur_timecode;
380 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
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 quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
390 Timecode::timecode_to_sample (timecode, mtc_frame, false, false,
391 double(session.frame_rate()),
392 session.config.get_subframes_per_frame(),
393 session.config.get_timecode_offset_negative(), session.config.get_timecode_offset()
396 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
397 now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
399 if (was_full || outside_window (mtc_frame)) {
400 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self()));
401 session.request_locate (mtc_frame, false);
402 session.request_transport_speed (0);
403 update_mtc_status (MIDI::MTC_Stopped);
405 reset_window (mtc_frame);
408 /* we've had the first set of 8 qtr frame messages, determine position
409 and allow continuing qtr frame messages to provide position
410 and speed information.
413 /* We received the last quarter frame 7 quarter frames (1.75 mtc
414 frames) after the instance when the contents of the mtc quarter
415 frames were decided. Add time to compensate for the elapsed 1.75
418 double qtr = quarter_frame_duration;
419 long int mtc_off = (long) rint(7.0 * qtr);
421 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
422 mtc_frame, (4.0*qtr), session.frames_per_timecode_frame()));
424 switch (port->parser()->mtc_running()) {
426 mtc_frame -= mtc_off;
430 mtc_frame += mtc_off;
436 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
439 if (first_mtc_timestamp == 0 || current.timestamp == 0) {
440 first_mtc_timestamp = now;
441 init_mtc_dll(mtc_frame, qtr);
444 current.position = mtc_frame;
445 current.timestamp = now;
447 reset_window (mtc_frame);
452 last_inbound_frame = now;
458 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
460 /* XXX !!! thread safety ... called from MIDI I/O context
461 * on locate (via ::update_mtc_time())
463 DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", ::pthread_self()));
464 return; // why was this fn needed anyway ? it just messes up things -> use reset.
470 current.position = mtc_frame;
471 current.timestamp = 0;
479 current.position = mtc_frame;
480 current.timestamp = 0;
487 current.position = mtc_frame;
488 current.timestamp = 0;
497 MTC_Slave::reset_window (framepos_t root)
499 /* if we're waiting for the master to catch us after seeking ahead, keep the window
500 of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
501 ahead of the window root (taking direction into account).
503 framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance);
505 switch (port->parser()->mtc_running()) {
508 transport_direction = 1;
509 window_end = root + d;
513 transport_direction = -1;
515 window_begin = root - d;
528 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
532 MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
534 /* the bandwidth of the DLL is a trade-off,
535 * because the max-speed of the transport in ardour is
536 * limited to +-8.0, a larger bandwidth would cause oscillations
538 * But this is only really a problem if the user performs manual
539 * seeks while transport is running and slaved to MTC.
541 oe = 2.0 * M_PI * double(inc) / 2.0 / double(session.frame_rate());
542 be = 1.4142135623730950488 * oe;
545 ee2 = double(transport_direction * inc);
548 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
551 /* main entry point from session_process.cc
552 * in jack_process callback context */
554 MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
556 framepos_t now = session.engine().frame_time_at_cycle_start();
557 framepos_t sess_pos = session.transport_frame(); // corresponds to now
558 //sess_pos -= session.engine().frames_since_cycle_start();
561 frameoffset_t elapsed;
562 bool engine_dll_reinitialized = false;
564 read_current (&last);
566 /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
567 if (last.timestamp == 0) { engine_dll_initstate = 0; }
568 else if (engine_dll_initstate != transport_direction && last.speed != 0) {
569 engine_dll_initstate = transport_direction;
570 init_engine_dll(last.position, session.engine().frames_per_cycle());
571 engine_dll_reinitialized = true;
574 if (last.timestamp == 0) {
576 pos = session.transport_frame() ; // last.position;
577 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos));
581 /* no timecode for two frames - conclude that it's stopped */
582 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
585 session.request_locate (pos, false);
586 session.request_transport_speed (0);
587 engine_dll_initstate = 0;
589 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n");
594 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position mtc-tme: %1 mtc-pos: %2 mtc-spd: %3\n", last.timestamp, last.position, last.speed));
595 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position eng-tme: %1 eng-pos: %2\n", now, sess_pos));
597 double speed_flt = last.speed; ///< MTC speed from MTC-quarter-frame DLL
599 /* interpolate position according to speed and time since last quarter-frame*/
600 if (speed_flt == 0.0f) {
605 /* scale elapsed time by the current MTC speed */
606 elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp));
607 if (give_slave_full_control_over_transport_speed() && !engine_dll_reinitialized) {
608 /* there is an engine vs MTC position frame-delta.
609 * This mostly due to quantization and rounding of (speed * nframes)
610 * but can also due to the session-process not calling
611 * speed_and_position() every cycle under some circumstances.
612 * Thus we use an other DLL to align the engine and the MTC
615 /* update engine DLL and calculate speed */
616 const double e = double (last.position + elapsed - sess_pos);
620 speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle());
621 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() ));
625 pos = last.position + elapsed;
628 /* may happen if the user performs a seek in the timeline while slaved to running MTC
629 * engine-DLL can oscillate back before 0.
630 * also see note in MTC_Slave::init_engine_dll
632 if (!session.actively_recording()
634 && ( (pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()) )
636 engine_dll_initstate = 0;
640 /* provide a .1% deadzone to lock the speed */
641 if (fabs(speed - 1.0) <= 0.001)
644 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
645 speed, pos, last.position, elapsed, pos - sess_pos));
647 current_delta = (pos - sess_pos);
652 Timecode::TimecodeFormat
653 MTC_Slave::apparent_timecode_format () const
659 MTC_Slave::approximate_current_position() const
662 read_current (&last);
663 if (last.timestamp == 0 || reset_pending) {
664 return " \u2012\u2012:\u2012\u2012:\u2012\u2012:\u2012\u2012";
666 return Timecode::timecode_format_sampletime(
668 double(session.frame_rate()),
669 Timecode::timecode_to_frames_per_second(mtc_timecode),
670 Timecode::timecode_has_drop_frames(mtc_timecode));
674 MTC_Slave::approximate_current_delta() const
678 read_current (&last);
679 if (last.timestamp == 0 || reset_pending) {
680 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
682 // TODO if current_delta > 1 frame -> display timecode.
683 snprintf(delta, sizeof(delta), "\u0394 %s%4" PRIi64 " sm",
684 PLUSMINUS(-current_delta), abs(current_delta));
686 return std::string(delta);