2 Copyright (C) 2002-4 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <sys/types.h>
25 #include "pbd/error.h"
26 #include "pbd/stacktrace.h"
27 #include "pbd/enumwriter.h"
28 #include "pbd/failed_constructor.h"
29 #include "pbd/pthread_utils.h"
31 #include "midi++/port.h"
32 #include "ardour/debug.h"
33 #include "ardour/slave.h"
34 #include "ardour/session.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/pi_controller.h"
41 using namespace ARDOUR;
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.
53 const int MTC_Slave::frame_tolerance = 2;
55 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
58 can_notify_on_unknown_rate = true;
59 did_reset_tc_format = false;
63 last_mtc_fps_byte = session.get_mtc_timecode_bits ();
66 speed_accumulator_size = 16;
67 speed_accumulator = new double[speed_accumulator_size];
73 MTC_Slave::~MTC_Slave()
75 if (did_reset_tc_format) {
76 session.config.set_timecode_format (saved_tc_format);
80 delete [] speed_accumulator;
84 MTC_Slave::give_slave_full_control_over_transport_speed() const
86 // return true; // for PiC control */
87 return false; // for Session-level computed varispeed
91 MTC_Slave::rebind (MIDI::Port& p)
93 port_connections.drop_connections ();
97 port->input()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
98 port->input()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
99 port->input()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
103 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
105 DEBUG_TRACE (DEBUG::MTC, string_compose ("update MTC qtr does a reset, qtr = %1 now = %2\n", which_qtr, now));
108 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
109 last_inbound_frame = now;
113 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
115 /* "now" can be zero if this is called from a context where we do not have or do not want
116 to use a timestamp indicating when this MTC time was received. example: when we received
117 a locate command via MMC.
121 DEBUG_TRACE (DEBUG::MTC, string_compose ("update MTC time does a reset, was full ? %1 now = %2\n", was_full, now));
125 Timecode::Time timecode;
126 TimecodeFormat tc_format;
127 bool reset_tc = true;
128 nframes64_t window_root = -1;
130 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
132 timecode.hours = msg[3];
133 timecode.minutes = msg[2];
134 timecode.seconds = msg[1];
135 timecode.frames = msg[0];
137 last_mtc_fps_byte = msg[4];
142 timecode.drop = false;
143 tc_format = timecode_24;
144 can_notify_on_unknown_rate = true;
148 timecode.drop = false;
149 tc_format = timecode_25;
150 can_notify_on_unknown_rate = true;
152 case MTC_30_FPS_DROP:
154 timecode.drop = true;
155 tc_format = timecode_30drop;
156 can_notify_on_unknown_rate = true;
160 timecode.drop = false;
161 can_notify_on_unknown_rate = true;
162 tc_format = timecode_30;
165 /* throttle error messages about unknown MTC rates */
166 if (can_notify_on_unknown_rate) {
167 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
170 can_notify_on_unknown_rate = false;
172 timecode.rate = session.timecode_frames_per_second();
173 timecode.drop = session.timecode_drop_frames();
178 if (!did_reset_tc_format) {
179 saved_tc_format = session.config.get_timecode_format();
180 did_reset_tc_format = true;
182 session.config.set_timecode_format (tc_format);
185 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n",
186 now, timecode, mtc_frame, was_full));
188 if (was_full || outside_window (mtc_frame)) {
190 session.timecode_to_sample (timecode, mtc_frame, true, false);
191 session.request_locate (mtc_frame, false);
192 session.request_transport_speed (0);
193 DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC status to stopped, outside MTC window (%1 .. %2 vs. %3)\n",
194 window_begin, window_end, mtc_frame));
195 update_mtc_status (MIDI::MTC_Stopped);
196 DEBUG_TRACE (DEBUG::MTC, string_compose ("outside, so window root reset to %1\n", mtc_frame));
197 reset_window (mtc_frame);
202 /* we've had the first set of 8 qtr frame messages, determine position
203 and allow continuing qtr frame messages to provide position
204 and speed information.
207 /* do a careful conversion of the timecode value to a position
208 so that we take drop/nondrop and all that nonsense into
212 session.timecode_to_sample (timecode, mtc_frame, true, false);
214 /* We received the last quarter frame 7 quarter frames (1.75 mtc
215 frames) after the instance when the contents of the mtc quarter
216 frames were decided. Add time to compensate for the elapsed 1.75
217 frames. Also compensate for audio latency.
220 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
225 if (last_mtc_timestamp == 0) {
227 last_mtc_timestamp = now;
228 last_mtc_frame = mtc_frame;
232 if (give_slave_full_control_over_transport_speed()) {
235 * its not the average, but we will assign it to current.speed below
238 static nframes64_t last_seen_timestamp = 0;
239 static nframes64_t last_seen_position = 0;
241 if ((now - last_seen_timestamp) < 300) {
242 mtc_frame = (mtc_frame + last_seen_position)/2;
245 last_seen_timestamp = now;
246 last_seen_position = mtc_frame;
255 nframes64_t time_delta = (now - last_mtc_timestamp);
257 if (time_delta != 0) {
258 double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
260 process_apparent_speed (apparent_speed);
261 DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
263 DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
266 /* every second, recalibrate the starting point for the speed measurement */
267 if (mtc_frame - last_mtc_frame > session.frame_rate()) {
268 last_mtc_timestamp = now;
269 last_mtc_frame = mtc_frame;
275 current.position = mtc_frame;
276 current.timestamp = now;
277 current.speed = average_speed;
279 window_root = mtc_frame;
284 last_inbound_frame = now;
287 if (window_root >= 0) {
288 DEBUG_TRACE (DEBUG::MTC, string_compose ("window root reset to %1\n", window_root));
289 reset_window (window_root);
294 MTC_Slave::process_apparent_speed (double this_speed)
296 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
298 /* clamp to an expected range */
300 if (this_speed > 4.0 || this_speed < -4.0) {
301 this_speed = average_speed;
304 if (speed_accumulator_cnt >= speed_accumulator_size) {
305 have_first_speed_accumulator = true;
306 speed_accumulator_cnt = 0;
309 speed_accumulator[speed_accumulator_cnt++] = this_speed;
311 if (have_first_speed_accumulator) {
313 for (size_t i = 0; i < speed_accumulator_size; ++i) {
314 average_speed += speed_accumulator[i];
316 average_speed /= speed_accumulator_size;
321 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
325 mtc[4] = last_mtc_fps_byte;
326 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
331 update_mtc_time (mtc, true, 0);
335 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
337 /* XXX !!! thread safety ... called from MIDI I/O context
338 and process() context (via ::speed_and_position())
342 DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
346 current.position = mtc_frame;
347 current.timestamp = 0;
355 current.position = mtc_frame;
356 current.timestamp = 0;
363 current.position = mtc_frame;
364 current.timestamp = 0;
373 MTC_Slave::read_current (SafeTime *st) const
379 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
386 } while (st->guard1 != st->guard2);
390 MTC_Slave::locked () const
392 return port->input()->mtc_locked();
396 MTC_Slave::ok() const
402 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
404 nframes64_t now = session.engine().frame_time();
408 read_current (&last);
410 if (last.timestamp == 0) {
413 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
417 /* no timecode for 1/4 second ? conclude that its stopped */
419 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
422 session.request_locate (pos, false);
423 session.request_transport_speed (0);
425 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
429 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
431 if (give_slave_full_control_over_transport_speed()) {
432 bool in_control = (session.slave_state() == Session::Running);
433 nframes64_t pic_want_locate = 0;
434 //nframes64_t slave_pos = session.audible_frame();
435 nframes64_t slave_pos = session.transport_frame();
436 static double average_speed = 0;
438 average_speed = pic->get_ratio (last.timestamp, last.position, slave_pos, in_control );
439 pic_want_locate = pic->want_locate();
441 if (in_control && pic_want_locate) {
442 last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
443 std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n";
445 last.speed = average_speed;
449 if (last.speed == 0.0f) {
455 /* scale elapsed time by the current MTC speed */
457 if (last.timestamp && (now > last.timestamp)) {
458 elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
459 DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
460 last.timestamp, now, elapsed, last.speed));
462 elapsed = 0; /* XXX is this right? */
466 /* now add the most recent timecode value plus the estimated elapsed interval */
468 pos = last.position + elapsed;
471 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
477 MTC_Slave::resolution() const
479 return (nframes_t) session.frames_per_timecode_frame();
483 MTC_Slave::queue_reset ()
485 DEBUG_TRACE (DEBUG::MTC, "queue reset of MTC slave state\n");
486 PBD::stacktrace (cerr, 35);
487 Glib::Mutex::Lock lm (reset_lock);
492 MTC_Slave::maybe_reset ()
497 DEBUG_TRACE (DEBUG::MTC, "actually reset\n");
502 reset_lock.unlock ();
508 DEBUG_TRACE (DEBUG::MTC, "*****************\n\n\n MTC SLAVE reset ********************\n\n\n");
509 PBD::stacktrace (cerr, 35);
510 port->input()->reset_mtc_state ();
512 last_inbound_frame = 0;
514 current.position = 0;
515 current.timestamp = 0;
522 last_mtc_timestamp = 0;
525 have_first_speed_accumulator = false;
526 speed_accumulator_cnt = 0;
532 MTC_Slave::reset_window (nframes64_t root)
535 /* if we're waiting for the master to catch us after seeking ahead, keep the window
536 of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
537 ahead of the window root (taking direction into account).
540 DEBUG_TRACE (DEBUG::MTC, string_compose ("trying to reset MTC window with state = %1\n", enum_2_string (port->input()->mtc_running())));
542 switch (port->input()->mtc_running()) {
544 DEBUG_TRACE (DEBUG::MTC, "set MTC window while running forward\n");
546 if (session.slave_state() == Session::Running) {
547 window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
549 window_end = root + seekahead_distance ();
554 DEBUG_TRACE (DEBUG::MTC, "set MTC window while running backward\n");
555 if (session.slave_state() == Session::Running) {
556 nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
558 window_begin = root - d;
564 nframes_t d = seekahead_distance ();
566 window_begin = root - d;
575 DEBUG_TRACE (DEBUG::MTC, "not touching MTC window - MTC_Stopped\n");
580 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
584 MTC_Slave::seekahead_distance () const
587 return session.frame_rate();
591 MTC_Slave::outside_window (nframes64_t pos) const
593 return ((pos < window_begin) || (pos > window_end));