1 /*
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>
7  *
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.
12  *
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.
17  *
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.
21  */
22 #include <iostream>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include "pbd/error.h"
28 #include "pbd/pthread_utils.h"
29 
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"
36 #include "ardour/transport_master_manager.h"
37 
38 #include "pbd/i18n.h"
39 
40 using namespace std;
41 using namespace ARDOUR;
42 using namespace MIDI;
43 using namespace PBD;
44 using namespace Timecode;
45 
46 /* length (in timecode frames) of the "window" that we consider legal given receipt of
47    a given timecode position. Ardour will try to chase within this window, and will
48    stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
49    in the current direction of motion, so if any timecode arrives that is before the most
50    recently received position (and without the direction of timecode reversing too), we
51    will stop+locate+wait+chase.
52 */
53 const int MTC_TransportMaster::sample_tolerance = 2;
54 
MTC_TransportMaster(std::string const & name)55 MTC_TransportMaster::MTC_TransportMaster (std::string const & name)
56 	: TimecodeTransportMaster (name, MTC)
57 	, can_notify_on_unknown_rate (true)
58 	, mtc_frame (0)
59 	, mtc_frame_dll (0)
60 	, last_inbound_frame (0)
61 	, window_begin (0)
62 	, window_end (0)
63 	, first_mtc_timestamp (0)
64 	, reset_pending (0)
65 	, reset_position (false)
66 	, transport_direction (1)
67 	, busy_guard1 (0)
68 	, busy_guard2 (0)
69 {
70 	init ();
71 }
72 
~MTC_TransportMaster()73 MTC_TransportMaster::~MTC_TransportMaster()
74 {
75 	port_connections.drop_connections();
76 }
77 
78 void
init()79 MTC_TransportMaster::init ()
80 {
81 	reset (true);
82 	resync_latency (false);
83 }
84 
85 void
connection_handler(boost::weak_ptr<ARDOUR::Port> w0,std::string n0,boost::weak_ptr<ARDOUR::Port> w1,std::string n1,bool con)86 MTC_TransportMaster::connection_handler (boost::weak_ptr<ARDOUR::Port> w0, std::string n0, boost::weak_ptr<ARDOUR::Port> w1, std::string n1, bool con)
87 {
88 	TransportMaster::connection_handler(w0, n0, w1, n1, con);
89 
90 	boost::shared_ptr<Port> p = w1.lock ();
91 	if (p == _port) {
92 		resync_latency (false);
93 	}
94 }
95 
96 void
create_port()97 MTC_TransportMaster::create_port ()
98 {
99 	if ((_port = create_midi_port (string_compose ("%1 in", _name))) == 0) {
100 		throw failed_constructor();
101 	}
102 }
103 
104 void
set_session(Session * s)105 MTC_TransportMaster::set_session (Session* s)
106 {
107 	TransportMaster::set_session (s);
108 	TransportMasterViaMIDI::set_session (s);
109 
110 	port_connections.drop_connections();
111 
112 	if (_session) {
113 
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 
118 		parse_timecode_offset ();
119 		reset (true);
120 
121 		parser.mtc_time.connect_same_thread (port_connections,  boost::bind (&MTC_TransportMaster::update_mtc_time, this, _1, _2, _3));
122 		parser.mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_qtr, this, _1, _2, _3));
123 		parser.mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_status, this, _1));
124 	}
125 }
126 
127 void
pre_process(MIDI::pframes_t nframes,samplepos_t now,boost::optional<samplepos_t> session_pos)128 MTC_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
129 {
130 	/* Read and parse incoming MIDI */
131 
132 	maybe_reset ();
133 
134 	if (!_midi_port) {
135 		_current_delta = 0;
136 		DEBUG_TRACE (DEBUG::MTC, "No MTC port registered");
137 		return;
138 	}
139 
140 	_midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
141 
142 	if (session_pos) {
143 		const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
144 		_current_delta = current_pos - *session_pos;
145 	} else {
146 		_current_delta = 0;
147 	}
148 }
149 
150 void
parse_timecode_offset()151 MTC_TransportMaster::parse_timecode_offset() {
152 	Timecode::Time offset_tc;
153 	Timecode::parse_timecode_format (_session->config.get_slave_timecode_offset(), offset_tc);
154 	offset_tc.rate = _session->timecode_frames_per_second();
155 	offset_tc.drop = _session->timecode_drop_frames();
156 	_session->timecode_to_sample(offset_tc, timecode_offset, false, false);
157 	timecode_negative_offset = offset_tc.negative;
158 }
159 
160 void
parameter_changed(std::string const & p)161 MTC_TransportMaster::parameter_changed (std::string const & p)
162 {
163 	if (p == "slave-timecode-offset"
164 			|| p == "timecode-format"
165 			) {
166 		parse_timecode_offset();
167 	}
168 }
169 
170 ARDOUR::samplecnt_t
update_interval() const171 MTC_TransportMaster::update_interval() const
172 {
173 	if (timecode.rate) {
174 		return AudioEngine::instance()->sample_rate() / timecode.rate;
175 	}
176 
177 	return AudioEngine::instance()->sample_rate(); /* useless but what other answer is there? */
178 }
179 
180 ARDOUR::samplecnt_t
resolution() const181 MTC_TransportMaster::resolution () const
182 {
183 	return (samplecnt_t) quarter_frame_duration * 4.0;
184 }
185 
186 ARDOUR::samplecnt_t
seekahead_distance() const187 MTC_TransportMaster::seekahead_distance () const
188 {
189 	return quarter_frame_duration * 8 * transport_direction;
190 }
191 
192 bool
outside_window(samplepos_t pos) const193 MTC_TransportMaster::outside_window (samplepos_t pos) const
194 {
195 	return ((pos < window_begin) || (pos > window_end));
196 }
197 
198 
199 bool
locked() const200 MTC_TransportMaster::locked () const
201 {
202 	DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2\n", parser.mtc_locked(), last_inbound_frame));
203 	return parser.mtc_locked() && last_inbound_frame !=0;
204 }
205 
206 bool
ok() const207 MTC_TransportMaster::ok() const
208 {
209 	return true;
210 }
211 
212 void
queue_reset(bool reset_pos)213 MTC_TransportMaster::queue_reset (bool reset_pos)
214 {
215 	Glib::Threads::Mutex::Lock lm (reset_lock);
216 	reset_pending++;
217 	if (reset_pos) {
218 		reset_position = true;
219 	}
220 }
221 
222 void
maybe_reset()223 MTC_TransportMaster::maybe_reset ()
224 {
225 	Glib::Threads::Mutex::Lock lm (reset_lock);
226 
227 	if (reset_pending) {
228 		reset (reset_position);
229 		reset_pending = 0;
230 		reset_position = false;
231 	}
232 }
233 
234 void
reset(bool with_position)235 MTC_TransportMaster::reset (bool with_position)
236 {
237 	DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_TransportMaster reset %1\n", with_position?"with position":"without position"));
238 
239 	if (with_position) {
240 		current.update (current.position, 0, 0);
241 	} else {
242 		current.reset ();
243 	}
244 	first_mtc_timestamp = 0;
245 	window_begin = 0;
246 	window_end = 0;
247 	transport_direction = 1;
248 	_current_delta = 0;
249 	timecode_format_valid = false;
250 }
251 
252 void
handle_locate(const MIDI::byte * mmc_tc)253 MTC_TransportMaster::handle_locate (const MIDI::byte* mmc_tc)
254 {
255 	MIDI::byte mtc[5];
256 	DEBUG_TRACE (DEBUG::MTC, "MTC_TransportMaster::handle_locate\n");
257 
258 	mtc[4] = last_mtc_fps_byte;
259 	mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
260 	mtc[2] = mmc_tc[1];
261 	mtc[1] = mmc_tc[2];
262 	mtc[0] = mmc_tc[3];
263 
264 	update_mtc_time (mtc, true, 0);
265 }
266 
267 void
init_mtc_dll(samplepos_t tme,double qtr)268 MTC_TransportMaster::init_mtc_dll(samplepos_t tme, double qtr)
269 {
270 	const double omega = 2.0 * M_PI * qtr / 2.0 / double(_session->sample_rate());
271 	b = 1.4142135623730950488 * omega;
272 	c = omega * omega;
273 
274 	e2 = qtr;
275 	t0 = double(tme);
276 	t1 = t0 + e2;
277 	DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
278 }
279 
280 /* called from MIDI parser */
281 void
update_mtc_qtr(Parser & p,int which_qtr,samplepos_t now)282 MTC_TransportMaster::update_mtc_qtr (Parser& p, int which_qtr, samplepos_t now)
283 {
284 	busy_guard1++;
285 	const double qtr_d = quarter_frame_duration;
286 
287 	mtc_frame_dll += qtr_d * (double) transport_direction;
288 	mtc_frame = rint(mtc_frame_dll);
289 
290 	DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
291 
292 	double mtc_speed = 0;
293 	if (first_mtc_timestamp != 0) {
294 		/* update MTC DLL and calculate speed */
295 		const double e = mtc_frame_dll - (double)transport_direction * ((double)now - (double)current.timestamp + t0);
296 		t0 = t1;
297 		t1 += b * e + e2;
298 		e2 += c * e;
299 
300 		mtc_speed = (t1 - t0) / qtr_d;
301 		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));
302 
303 		current.update (mtc_frame, now, mtc_speed);
304 
305 		last_inbound_frame = now;
306 	}
307 
308 	maybe_reset ();
309 
310 	busy_guard2++;
311 }
312 
313 /* called from MIDI parser _after_ update_mtc_qtr()
314  * when a full TC has been received
315  * OR on locate */
316 void
update_mtc_time(const MIDI::byte * msg,bool was_full,samplepos_t now)317 MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samplepos_t now)
318 {
319 	busy_guard1++;
320 
321 	/* "now" can be zero if this is called from a context where we do not have or do not want
322 	   to use a timestamp indicating when this MTC time was received. example: when we received
323 	   a locate command via MMC.
324 	*/
325 	DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
326 	TimecodeFormat tc_format;
327 	bool have_tc = true;
328 
329 	timecode.hours = msg[3];
330 	timecode.minutes = msg[2];
331 	timecode.seconds = msg[1];
332 	timecode.frames = msg[0];
333 
334 	last_mtc_fps_byte = msg[4];
335 
336 	DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
337 
338 	if (now) {
339 		maybe_reset ();
340 	}
341 
342 	switch (msg[4]) {
343 	case MTC_24_FPS:
344 		timecode.rate = 24;
345 		timecode.drop = false;
346 		tc_format = timecode_24;
347 		can_notify_on_unknown_rate = true;
348 		break;
349 	case MTC_25_FPS:
350 		timecode.rate = 25;
351 		timecode.drop = false;
352 		tc_format = timecode_25;
353 		can_notify_on_unknown_rate = true;
354 		break;
355 	case MTC_30_FPS_DROP:
356 		if (fr2997()) {
357 			tc_format = Timecode::timecode_2997000drop;
358 			timecode.rate = (29970.0/1000.0);
359 		} else {
360 			tc_format = timecode_2997drop;
361 			timecode.rate = (30000.0/1001.0);
362 		}
363 		timecode.drop = true;
364 		can_notify_on_unknown_rate = true;
365 		break;
366 	case MTC_30_FPS:
367 		timecode.rate = 30;
368 		timecode.drop = false;
369 		can_notify_on_unknown_rate = true;
370 		tc_format = timecode_30;
371 		break;
372 	default:
373 		/* throttle error messages about unknown MTC rates */
374 		if (can_notify_on_unknown_rate) {
375 			error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
376 						 (int) msg[4])
377 			      << endmsg;
378 			can_notify_on_unknown_rate = false;
379 		}
380 		timecode.rate = _session->timecode_frames_per_second();
381 		timecode.drop = _session->timecode_drop_frames();
382 		have_tc = false;
383 	}
384 
385 	if (have_tc) {
386 		mtc_timecode = tc_format;
387 		timecode_format_valid = true; /* SET FLAG */
388 	}
389 
390 	/* do a careful conversion of the timecode value to a position
391 	   so that we take drop/nondrop and all that nonsense into
392 	   consideration.
393 	*/
394 
395 	quarter_frame_duration = (double(_session->sample_rate()) / (double) timecode.rate / 4.0);
396 
397 	Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
398 		double(_session->sample_rate()),
399 		_session->config.get_subframes_per_frame(),
400 		timecode_negative_offset, timecode_offset
401 		);
402 
403 	DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4)\n", now, timecode, mtc_frame, was_full));
404 
405 	if (was_full || outside_window (mtc_frame)) {
406 		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));
407 		boost::shared_ptr<TransportMaster> c = TransportMasterManager::instance().current();
408 		if (c && c.get() == this && _session->config.get_external_sync()) {
409 			_session->set_requested_return_sample (-1);
410 			_session->request_locate (mtc_frame, MustStop, TRS_MTC);
411 		}
412 		update_mtc_status (MIDI::MTC_Stopped);
413 		reset (false);
414 		reset_window (mtc_frame);
415 	} else {
416 
417 		/* we've had the first set of 8 qtr sample messages, determine position
418 		   and allow continuing qtr sample messages to provide position
419 		   and speed information.
420 		*/
421 
422 		/* We received the last quarter frame 7 quarter frames (1.75 mtc
423 		   samples) after the instance when the contents of the mtc quarter
424 		   samples were decided. Add time to compensate for the elapsed 1.75
425 		   samples.
426 		*/
427 		double qtr = quarter_frame_duration;
428 		long int mtc_off = (long) rint(7.0 * qtr);
429 
430 		DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
431 							 mtc_frame, (4.0*qtr), _session->samples_per_timecode_frame()));
432 
433 		switch (parser.mtc_running()) {
434 		case MTC_Backward:
435 			mtc_frame -= mtc_off;
436 			qtr *= -1.0;
437 			break;
438 		case MTC_Forward:
439 			mtc_frame += mtc_off;
440 			break;
441 		default:
442 			break;
443 		}
444 
445 		DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
446 
447 		if (now) {
448 			if (first_mtc_timestamp == 0 || current.timestamp == 0) {
449 				first_mtc_timestamp = now;
450 				init_mtc_dll(mtc_frame, qtr);
451 				mtc_frame_dll = mtc_frame + midi_port_latency.max;
452 			}
453 			current.update (mtc_frame + midi_port_latency.max, now, current.speed);
454 			reset_window (mtc_frame);
455 		}
456 	}
457 
458 	busy_guard2++;
459 }
460 
461 void
update_mtc_status(MIDI::MTC_Status status)462 MTC_TransportMaster::update_mtc_status (MIDI::MTC_Status status)
463 {
464 	/* XXX !!! thread safety ... called from MIDI I/O context
465 	 * on locate (via ::update_mtc_time())
466 	 */
467 	DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_TransportMaster::update_mtc_status - TID:%1 MTC:%2\n", pthread_name(), mtc_frame));
468 	return; // why was this fn needed anyway ? it just messes up things -> use reset.
469 	busy_guard1++;
470 
471 	switch (status) {
472 	case MTC_Stopped:
473 		current.update (mtc_frame, 0, 0);
474 		break;
475 
476 	case MTC_Forward:
477 		current.update (mtc_frame, 0, 0);
478 		break;
479 
480 	case MTC_Backward:
481 		current.update (mtc_frame, 0, 0);
482 		break;
483 	}
484 	busy_guard2++;
485 }
486 
487 void
reset_window(samplepos_t root)488 MTC_TransportMaster::reset_window (samplepos_t root)
489 {
490 	/* if we're waiting for the master to catch us after seeking ahead, keep the window
491 	   of acceptable MTC samples wide open. otherwise, shrink it down to just 2 video frames
492 	   ahead of the window root (taking direction into account).
493 	*/
494 
495 	samplecnt_t const d = (quarter_frame_duration * 4 * sample_tolerance);
496 
497 	switch (parser.mtc_running()) {
498 	case MTC_Forward:
499 		window_begin = root;
500 		transport_direction = 1;
501 		window_end = root + d;
502 		break;
503 
504 	case MTC_Backward:
505 		transport_direction = -1;
506 		if (root > d) {
507 			window_begin = root - d;
508 			window_end = root;
509 		} else {
510 			window_begin = 0;
511 		}
512 		window_end = root;
513 		break;
514 
515 	default:
516 		/* do nothing */
517 		break;
518 	}
519 
520 	DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
521 }
522 
523 Timecode::TimecodeFormat
apparent_timecode_format() const524 MTC_TransportMaster::apparent_timecode_format () const
525 {
526 	return mtc_timecode;
527 }
528 
529 std::string
position_string() const530 MTC_TransportMaster::position_string() const
531 {
532 	SafeTime last;
533 	current.safe_read (last);
534 	if (last.timestamp == 0 || reset_pending) {
535 		return " --:--:--:--";
536 	}
537 	return Timecode::timecode_format_sampletime(
538 		last.position,
539 		double(_session->sample_rate()),
540 		Timecode::timecode_to_frames_per_second(mtc_timecode),
541 		Timecode::timecode_has_drop_frames(mtc_timecode));
542 }
543 
544 std::string
delta_string() const545 MTC_TransportMaster::delta_string () const
546 {
547 	SafeTime last;
548 	current.safe_read (last);
549 
550 	if (last.timestamp == 0 || reset_pending) {
551 		return X_("\u2012\u2012\u2012\u2012");
552 	} else {
553 		return format_delta_time (_current_delta);
554 	}
555 }
556 
557 void
unregister_port()558 MTC_TransportMaster::unregister_port ()
559 {
560 	_midi_port.reset ();
561 	TransportMaster::unregister_port ();
562 }
563