2 * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
3 * Copyright (C) 2008-2019 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2009-2010 Carl Hetherington <carl@carlh.net>
5 * Copyright (C) 2012-2017 Robin Gareus <robin@gareus.org>
6 * Copyright (C) 2013-2018 John Emmas <john@creativepost.co.uk>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <sys/types.h>
27 #include "pbd/error.h"
28 #include "pbd/pthread_utils.h"
30 #include "ardour/audioengine.h"
31 #include "ardour/debug.h"
32 #include "ardour/midi_buffer.h"
33 #include "ardour/midi_port.h"
34 #include "ardour/session.h"
35 #include "ardour/transport_master.h"
40 using namespace ARDOUR;
43 using namespace Timecode;
45 /* length (in timecode frames) of the "window" that we consider legal given receipt of
46 a given timecode position. Ardour will try to chase within this window, and will
47 stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
48 in the current direction of motion, so if any timecode arrives that is before the most
49 recently received position (and without the direction of timecode reversing too), we
50 will stop+locate+wait+chase.
52 const int MTC_TransportMaster::sample_tolerance = 2;
54 MTC_TransportMaster::MTC_TransportMaster (std::string const & name)
55 : TimecodeTransportMaster (name, MTC)
56 , can_notify_on_unknown_rate (true)
59 , last_inbound_frame (0)
62 , first_mtc_timestamp (0)
63 , did_reset_tc_format (false)
65 , reset_position (false)
66 , transport_direction (1)
69 , printed_timecode_warning (false)
71 if ((_port = create_midi_port (string_compose ("%1 in", name))) == 0) {
72 throw failed_constructor();
75 DEBUG_TRACE (DEBUG::Slave, string_compose ("MTC registered %1\n", _port->name()));
80 MTC_TransportMaster::~MTC_TransportMaster()
82 port_connections.drop_connections();
83 config_connection.disconnect();
85 while (busy_guard1 != busy_guard2) {
86 /* make sure MIDI parser is not currently calling any callbacks in here,
87 * else there's a segfault ahead!
89 * XXX this is called from jack rt-context :(
90 * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
95 if (did_reset_tc_format) {
96 _session->config.set_timecode_format (saved_tc_format);
101 MTC_TransportMaster::init ()
107 MTC_TransportMaster::set_session (Session *s)
109 config_connection.disconnect ();
110 port_connections.drop_connections();
116 last_mtc_fps_byte = _session->get_mtc_timecode_bits ();
117 quarter_frame_duration = (double) (_session->samples_per_timecode_frame() / 4.0);
118 mtc_timecode = _session->config.get_timecode_format();
119 a3e_timecode = _session->config.get_timecode_format();
121 parse_timecode_offset ();
124 parser.mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_time, this, _1, _2, _3));
125 parser.mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_qtr, this, _1, _2, _3));
126 parser.mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_status, this, _1));
128 _session->config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_TransportMaster::parameter_changed, this, _1));
133 MTC_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
135 /* Read and parse incoming MIDI */
139 _midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
142 const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
143 _current_delta = current_pos - *session_pos;
150 MTC_TransportMaster::parse_timecode_offset() {
151 Timecode::Time offset_tc;
152 Timecode::parse_timecode_format (_session->config.get_slave_timecode_offset(), offset_tc);
153 offset_tc.rate = _session->timecode_frames_per_second();
154 offset_tc.drop = _session->timecode_drop_frames();
155 _session->timecode_to_sample(offset_tc, timecode_offset, false, false);
156 timecode_negative_offset = offset_tc.negative;
160 MTC_TransportMaster::parameter_changed (std::string const & p)
162 if (p == "slave-timecode-offset"
163 || p == "timecode-format"
165 parse_timecode_offset();
170 MTC_TransportMaster::update_interval() const
173 return AudioEngine::instance()->sample_rate() / timecode.rate;
176 return AudioEngine::instance()->sample_rate(); /* useless but what other answer is there? */
180 MTC_TransportMaster::resolution () const
182 return (samplecnt_t) quarter_frame_duration * 4.0;
186 MTC_TransportMaster::seekahead_distance () const
188 return quarter_frame_duration * 8 * transport_direction;
192 MTC_TransportMaster::outside_window (samplepos_t pos) const
194 return ((pos < window_begin) || (pos > window_end));
199 MTC_TransportMaster::locked () const
201 DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2\n", parser.mtc_locked(), last_inbound_frame));
202 return parser.mtc_locked() && last_inbound_frame !=0;
206 MTC_TransportMaster::ok() const
212 MTC_TransportMaster::queue_reset (bool reset_pos)
214 Glib::Threads::Mutex::Lock lm (reset_lock);
217 reset_position = true;
222 MTC_TransportMaster::maybe_reset ()
224 Glib::Threads::Mutex::Lock lm (reset_lock);
227 reset (reset_position);
229 reset_position = false;
234 MTC_TransportMaster::reset (bool with_position)
236 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_TransportMaster reset %1\n", with_position?"with position":"without position"));
239 current.update (current.position, 0, 0);
243 first_mtc_timestamp = 0;
246 transport_direction = 1;
251 MTC_TransportMaster::handle_locate (const MIDI::byte* mmc_tc)
254 DEBUG_TRACE (DEBUG::MTC, "MTC_TransportMaster::handle_locate\n");
256 mtc[4] = last_mtc_fps_byte;
257 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
262 update_mtc_time (mtc, true, 0);
266 MTC_TransportMaster::init_mtc_dll(samplepos_t tme, double qtr)
268 const double omega = 2.0 * M_PI * qtr / 2.0 / double(_session->sample_rate());
269 b = 1.4142135623730950488 * omega;
275 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
278 /* called from MIDI parser */
280 MTC_TransportMaster::update_mtc_qtr (Parser& p, int which_qtr, samplepos_t now)
283 const double qtr_d = quarter_frame_duration;
285 mtc_frame_dll += qtr_d * (double) transport_direction;
286 mtc_frame = rint(mtc_frame_dll);
288 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
290 double mtc_speed = 0;
291 if (first_mtc_timestamp != 0) {
292 /* update MTC DLL and calculate speed */
293 const double e = mtc_frame_dll - (double)transport_direction * ((double)now - (double)current.timestamp + t0);
298 mtc_speed = (t1 - t0) / qtr_d;
299 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d));
301 current.update (mtc_frame, now, mtc_speed);
303 last_inbound_frame = now;
311 /* called from MIDI parser _after_ update_mtc_qtr()
312 * when a full TC has been received
315 MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samplepos_t now)
319 /* "now" can be zero if this is called from a context where we do not have or do not want
320 to use a timestamp indicating when this MTC time was received. example: when we received
321 a locate command via MMC.
323 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
324 TimecodeFormat tc_format;
325 bool reset_tc = true;
327 timecode.hours = msg[3];
328 timecode.minutes = msg[2];
329 timecode.seconds = msg[1];
330 timecode.frames = msg[0];
332 last_mtc_fps_byte = msg[4];
334 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
343 timecode.drop = false;
344 tc_format = timecode_24;
345 can_notify_on_unknown_rate = true;
349 timecode.drop = false;
350 tc_format = timecode_25;
351 can_notify_on_unknown_rate = true;
353 case MTC_30_FPS_DROP:
355 tc_format = Timecode::timecode_2997000drop;
356 timecode.rate = (29970.0/1000.0);
358 tc_format = timecode_2997drop;
359 timecode.rate = (30000.0/1001.0);
361 timecode.drop = true;
362 can_notify_on_unknown_rate = true;
366 timecode.drop = false;
367 can_notify_on_unknown_rate = true;
368 tc_format = timecode_30;
371 /* throttle error messages about unknown MTC rates */
372 if (can_notify_on_unknown_rate) {
373 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
376 can_notify_on_unknown_rate = false;
378 timecode.rate = _session->timecode_frames_per_second();
379 timecode.drop = _session->timecode_drop_frames();
384 TimecodeFormat cur_timecode = _session->config.get_timecode_format();
385 if (Config->get_timecode_sync_frame_rate()) {
386 /* enforce time-code */
387 if (!did_reset_tc_format) {
388 saved_tc_format = cur_timecode;
389 did_reset_tc_format = true;
391 if (cur_timecode != tc_format) {
392 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
393 warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
394 Timecode::timecode_format_name(cur_timecode),
395 Timecode::timecode_format_name(tc_format))
399 _session->config.set_timecode_format (tc_format);
401 /* only warn about TC mismatch */
402 if (mtc_timecode != tc_format) printed_timecode_warning = false;
403 if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
405 if (cur_timecode != tc_format && ! printed_timecode_warning) {
406 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
407 warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 %2:%3."),
408 Timecode::timecode_format_name(tc_format),
410 Timecode::timecode_format_name(cur_timecode))
413 printed_timecode_warning = true;
416 mtc_timecode = tc_format;
417 a3e_timecode = cur_timecode;
419 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
422 /* do a careful conversion of the timecode value to a position
423 so that we take drop/nondrop and all that nonsense into
427 quarter_frame_duration = (double(_session->sample_rate()) / (double) timecode.rate / 4.0);
429 Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
430 double(_session->sample_rate()),
431 _session->config.get_subframes_per_frame(),
432 timecode_negative_offset, timecode_offset
435 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
436 now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
438 if (was_full || outside_window (mtc_frame)) {
439 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC %1 or outside window %2 MTC %3\n", was_full, outside_window (mtc_frame), mtc_frame));
440 _session->set_requested_return_sample (-1);
441 _session->request_transport_speed (0, TRS_MTC);
442 _session->request_locate (mtc_frame, false, TRS_MTC);
443 update_mtc_status (MIDI::MTC_Stopped);
445 reset_window (mtc_frame);
448 /* we've had the first set of 8 qtr sample messages, determine position
449 and allow continuing qtr sample messages to provide position
450 and speed information.
453 /* We received the last quarter frame 7 quarter frames (1.75 mtc
454 samples) after the instance when the contents of the mtc quarter
455 samples were decided. Add time to compensate for the elapsed 1.75
458 double qtr = quarter_frame_duration;
459 long int mtc_off = (long) rint(7.0 * qtr);
461 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
462 mtc_frame, (4.0*qtr), _session->samples_per_timecode_frame()));
464 switch (parser.mtc_running()) {
466 mtc_frame -= mtc_off;
470 mtc_frame += mtc_off;
476 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
479 if (first_mtc_timestamp == 0 || current.timestamp == 0) {
480 first_mtc_timestamp = now;
481 init_mtc_dll(mtc_frame, qtr);
482 mtc_frame_dll = mtc_frame;
484 current.update (mtc_frame, now, current.speed);
485 reset_window (mtc_frame);
493 MTC_TransportMaster::update_mtc_status (MIDI::MTC_Status status)
495 /* XXX !!! thread safety ... called from MIDI I/O context
496 * on locate (via ::update_mtc_time())
498 DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_TransportMaster::update_mtc_status - TID:%1 MTC:%2\n", pthread_name(), mtc_frame));
499 return; // why was this fn needed anyway ? it just messes up things -> use reset.
504 current.update (mtc_frame, 0, 0);
508 current.update (mtc_frame, 0, 0);
512 current.update (mtc_frame, 0, 0);
519 MTC_TransportMaster::reset_window (samplepos_t root)
521 /* if we're waiting for the master to catch us after seeking ahead, keep the window
522 of acceptable MTC samples wide open. otherwise, shrink it down to just 2 video frames
523 ahead of the window root (taking direction into account).
526 samplecnt_t const d = (quarter_frame_duration * 4 * sample_tolerance);
528 switch (parser.mtc_running()) {
531 transport_direction = 1;
532 window_end = root + d;
536 transport_direction = -1;
538 window_begin = root - d;
551 DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
554 Timecode::TimecodeFormat
555 MTC_TransportMaster::apparent_timecode_format () const
561 MTC_TransportMaster::position_string() const
564 current.safe_read (last);
565 if (last.timestamp == 0 || reset_pending) {
566 return " --:--:--:--";
568 return Timecode::timecode_format_sampletime(
570 double(_session->sample_rate()),
571 Timecode::timecode_to_frames_per_second(mtc_timecode),
572 Timecode::timecode_has_drop_frames(mtc_timecode));
576 MTC_TransportMaster::delta_string () const
580 current.safe_read (last);
584 if (last.timestamp == 0 || reset_pending) {
585 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
587 snprintf(delta, sizeof(delta), "\u0394<span foreground=\"green\" face=\"monospace\" >%s%s%" PRIi64 "</span>sm",
588 LEADINGZERO(abs(_current_delta)), PLUSMINUS(-_current_delta), abs(_current_delta));
590 return std::string(delta);
594 MTC_TransportMaster::unregister_port ()
597 TransportMaster::unregister_port ();