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.
22 #include <sys/types.h>
25 #include "pbd/error.h"
26 #include "pbd/pthread_utils.h"
28 #include "ardour/audioengine.h"
29 #include "ardour/debug.h"
30 #include "ardour/midi_buffer.h"
31 #include "ardour/midi_port.h"
32 #include "ardour/session.h"
33 #include "ardour/transport_master.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_TransportMaster::sample_tolerance = 2;
52 MTC_TransportMaster::MTC_TransportMaster (std::string const & name)
53 : TimecodeTransportMaster (name, MTC)
54 , can_notify_on_unknown_rate (true)
57 , last_inbound_frame (0)
60 , first_mtc_timestamp (0)
61 , did_reset_tc_format (false)
63 , reset_position (false)
64 , transport_direction (1)
67 , printed_timecode_warning (false)
69 if ((_port = create_midi_port (string_compose ("%1 in", name))) == 0) {
70 throw failed_constructor();
73 DEBUG_TRACE (DEBUG::Slave, string_compose ("MTC registered %1\n", _port->name()));
78 MTC_TransportMaster::~MTC_TransportMaster()
80 port_connections.drop_connections();
81 config_connection.disconnect();
83 while (busy_guard1 != busy_guard2) {
84 /* make sure MIDI parser is not currently calling any callbacks in here,
85 * else there's a segfault ahead!
87 * XXX this is called from jack rt-context :(
88 * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
93 if (did_reset_tc_format) {
94 _session->config.set_timecode_format (saved_tc_format);
99 MTC_TransportMaster::init ()
105 MTC_TransportMaster::set_session (Session *s)
107 config_connection.disconnect ();
108 port_connections.drop_connections();
114 last_mtc_fps_byte = _session->get_mtc_timecode_bits ();
115 quarter_frame_duration = (double) (_session->samples_per_timecode_frame() / 4.0);
116 mtc_timecode = _session->config.get_timecode_format();
117 a3e_timecode = _session->config.get_timecode_format();
119 parse_timecode_offset ();
122 parser.mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_time, this, _1, _2, _3));
123 parser.mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_qtr, this, _1, _2, _3));
124 parser.mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_status, this, _1));
126 _session->config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_TransportMaster::parameter_changed, this, _1));
131 MTC_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
133 /* Read and parse incoming MIDI */
137 _midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
140 const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
141 _current_delta = current_pos - *session_pos;
148 MTC_TransportMaster::parse_timecode_offset() {
149 Timecode::Time offset_tc;
150 Timecode::parse_timecode_format (_session->config.get_slave_timecode_offset(), offset_tc);
151 offset_tc.rate = _session->timecode_frames_per_second();
152 offset_tc.drop = _session->timecode_drop_frames();
153 _session->timecode_to_sample(offset_tc, timecode_offset, false, false);
154 timecode_negative_offset = offset_tc.negative;
158 MTC_TransportMaster::parameter_changed (std::string const & p)
160 if (p == "slave-timecode-offset"
161 || p == "timecode-format"
163 parse_timecode_offset();
168 MTC_TransportMaster::resolution () const
170 return (samplecnt_t) quarter_frame_duration * 4.0;
174 MTC_TransportMaster::seekahead_distance () const
176 return quarter_frame_duration * 8 * transport_direction;
180 MTC_TransportMaster::outside_window (samplepos_t pos) const
182 return ((pos < window_begin) || (pos > window_end));
187 MTC_TransportMaster::locked () const
189 DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2\n", parser.mtc_locked(), last_inbound_frame));
190 return parser.mtc_locked() && last_inbound_frame !=0;
194 MTC_TransportMaster::ok() const
200 MTC_TransportMaster::queue_reset (bool reset_pos)
202 Glib::Threads::Mutex::Lock lm (reset_lock);
205 reset_position = true;
210 MTC_TransportMaster::maybe_reset ()
212 Glib::Threads::Mutex::Lock lm (reset_lock);
215 reset (reset_position);
217 reset_position = false;
222 MTC_TransportMaster::reset (bool with_position)
224 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_TransportMaster reset %1\n", with_position?"with position":"without position"));
227 current.update (0, 0, 0);
229 current.update (current.position, 0, 0);
231 first_mtc_timestamp = 0;
234 transport_direction = 1;
239 MTC_TransportMaster::handle_locate (const MIDI::byte* mmc_tc)
242 DEBUG_TRACE (DEBUG::MTC, "MTC_TransportMaster::handle_locate\n");
244 mtc[4] = last_mtc_fps_byte;
245 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
250 update_mtc_time (mtc, true, 0);
254 MTC_TransportMaster::init_mtc_dll(samplepos_t tme, double qtr)
256 const double omega = 2.0 * M_PI * qtr / 2.0 / double(_session->sample_rate());
257 b = 1.4142135623730950488 * omega;
263 DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
266 /* called from MIDI parser */
268 MTC_TransportMaster::update_mtc_qtr (Parser& p, int which_qtr, samplepos_t now)
271 const double qtr_d = quarter_frame_duration;
273 mtc_frame_dll += qtr_d * (double) transport_direction;
274 mtc_frame = rint(mtc_frame_dll);
276 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
278 double mtc_speed = 0;
279 if (first_mtc_timestamp != 0) {
280 /* update MTC DLL and calculate speed */
281 const double e = mtc_frame_dll - (double)transport_direction * ((double)now - (double)current.timestamp + t0);
286 mtc_speed = (t1 - t0) / qtr_d;
287 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));
289 current.update (mtc_frame, now, mtc_speed);
297 /* called from MIDI parser _after_ update_mtc_qtr()
298 * when a full TC has been received
301 MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samplepos_t now)
305 /* "now" can be zero if this is called from a context where we do not have or do not want
306 to use a timestamp indicating when this MTC time was received. example: when we received
307 a locate command via MMC.
309 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
310 TimecodeFormat tc_format;
311 bool reset_tc = true;
313 timecode.hours = msg[3];
314 timecode.minutes = msg[2];
315 timecode.seconds = msg[1];
316 timecode.frames = msg[0];
318 last_mtc_fps_byte = msg[4];
320 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
329 timecode.drop = false;
330 tc_format = timecode_24;
331 can_notify_on_unknown_rate = true;
335 timecode.drop = false;
336 tc_format = timecode_25;
337 can_notify_on_unknown_rate = true;
339 case MTC_30_FPS_DROP:
341 tc_format = Timecode::timecode_2997000drop;
342 timecode.rate = (29970.0/1000.0);
344 tc_format = timecode_2997drop;
345 timecode.rate = (30000.0/1001.0);
347 timecode.drop = true;
348 can_notify_on_unknown_rate = true;
352 timecode.drop = false;
353 can_notify_on_unknown_rate = true;
354 tc_format = timecode_30;
357 /* throttle error messages about unknown MTC rates */
358 if (can_notify_on_unknown_rate) {
359 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
362 can_notify_on_unknown_rate = false;
364 timecode.rate = _session->timecode_frames_per_second();
365 timecode.drop = _session->timecode_drop_frames();
370 TimecodeFormat cur_timecode = _session->config.get_timecode_format();
371 if (Config->get_timecode_sync_frame_rate()) {
372 /* enforce time-code */
373 if (!did_reset_tc_format) {
374 saved_tc_format = cur_timecode;
375 did_reset_tc_format = true;
377 if (cur_timecode != tc_format) {
378 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
379 warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
380 Timecode::timecode_format_name(cur_timecode),
381 Timecode::timecode_format_name(tc_format))
385 _session->config.set_timecode_format (tc_format);
387 /* only warn about TC mismatch */
388 if (mtc_timecode != tc_format) printed_timecode_warning = false;
389 if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
391 if (cur_timecode != tc_format && ! printed_timecode_warning) {
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 and MTC framerate mismatch: MTC:%1 %2:%3."),
394 Timecode::timecode_format_name(tc_format),
396 Timecode::timecode_format_name(cur_timecode))
399 printed_timecode_warning = true;
402 mtc_timecode = tc_format;
403 a3e_timecode = cur_timecode;
405 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
408 /* do a careful conversion of the timecode value to a position
409 so that we take drop/nondrop and all that nonsense into
413 quarter_frame_duration = (double(_session->sample_rate()) / (double) timecode.rate / 4.0);
415 Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
416 double(_session->sample_rate()),
417 _session->config.get_subframes_per_frame(),
418 timecode_negative_offset, timecode_offset
421 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
422 now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
424 if (was_full || outside_window (mtc_frame)) {
425 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));
426 _session->set_requested_return_sample (-1);
427 _session->request_transport_speed (0, TRS_MTC);
428 _session->request_locate (mtc_frame, false, TRS_MTC);
429 update_mtc_status (MIDI::MTC_Stopped);
431 reset_window (mtc_frame);
434 /* we've had the first set of 8 qtr sample messages, determine position
435 and allow continuing qtr sample messages to provide position
436 and speed information.
439 /* We received the last quarter frame 7 quarter frames (1.75 mtc
440 samples) after the instance when the contents of the mtc quarter
441 samples were decided. Add time to compensate for the elapsed 1.75
444 double qtr = quarter_frame_duration;
445 long int mtc_off = (long) rint(7.0 * qtr);
447 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
448 mtc_frame, (4.0*qtr), _session->samples_per_timecode_frame()));
450 switch (parser.mtc_running()) {
452 mtc_frame -= mtc_off;
456 mtc_frame += mtc_off;
462 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
465 if (first_mtc_timestamp == 0 || current.timestamp == 0) {
466 first_mtc_timestamp = now;
467 init_mtc_dll(mtc_frame, qtr);
468 mtc_frame_dll = mtc_frame;
470 current.update (mtc_frame, now, current.speed);
471 reset_window (mtc_frame);
479 MTC_TransportMaster::update_mtc_status (MIDI::MTC_Status status)
481 /* XXX !!! thread safety ... called from MIDI I/O context
482 * on locate (via ::update_mtc_time())
484 DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_TransportMaster::update_mtc_status - TID:%1 MTC:%2\n", pthread_name(), mtc_frame));
485 return; // why was this fn needed anyway ? it just messes up things -> use reset.
490 current.update (mtc_frame, 0, 0);
494 current.update (mtc_frame, 0, 0);
498 current.update (mtc_frame, 0, 0);
505 MTC_TransportMaster::reset_window (samplepos_t root)
507 /* if we're waiting for the master to catch us after seeking ahead, keep the window
508 of acceptable MTC samples wide open. otherwise, shrink it down to just 2 video frames
509 ahead of the window root (taking direction into account).
512 samplecnt_t const d = (quarter_frame_duration * 4 * sample_tolerance);
514 switch (parser.mtc_running()) {
517 transport_direction = 1;
518 window_end = root + d;
522 transport_direction = -1;
524 window_begin = root - d;
537 DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
540 Timecode::TimecodeFormat
541 MTC_TransportMaster::apparent_timecode_format () const
547 MTC_TransportMaster::position_string() const
550 current.safe_read (last);
551 if (last.timestamp == 0 || reset_pending) {
552 return " --:--:--:--";
554 return Timecode::timecode_format_sampletime(
556 double(_session->sample_rate()),
557 Timecode::timecode_to_frames_per_second(mtc_timecode),
558 Timecode::timecode_has_drop_frames(mtc_timecode));
562 MTC_TransportMaster::delta_string () const
566 current.safe_read (last);
570 if (last.timestamp == 0 || reset_pending) {
571 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
573 snprintf(delta, sizeof(delta), "\u0394<span foreground=\"green\" face=\"monospace\" >%s%s%" PRIi64 "</span>sm",
574 LEADINGZERO(abs(_current_delta)), PLUSMINUS(-_current_delta), abs(_current_delta));
576 return std::string(delta);