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>
24 #include "pbd/error.h"
25 #include "pbd/enumwriter.h"
26 #include "pbd/failed_constructor.h"
27 #include "pbd/pthread_utils.h"
29 #include "midi++/port.h"
30 #include "ardour/debug.h"
31 #include "ardour/slave.h"
32 #include "ardour/session.h"
33 #include "ardour/audioengine.h"
34 #include "ardour/pi_controller.h"
39 using namespace ARDOUR;
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.
51 const int MTC_Slave::frame_tolerance = 2;
53 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
56 can_notify_on_unknown_rate = true;
57 did_reset_tc_format = false;
61 last_mtc_fps_byte = session.get_mtc_timecode_bits ();
64 speed_accumulator_size = 16;
65 speed_accumulator = new double[speed_accumulator_size];
71 MTC_Slave::~MTC_Slave()
73 if (did_reset_tc_format) {
74 session.config.set_timecode_format (saved_tc_format);
78 delete [] speed_accumulator;
82 MTC_Slave::give_slave_full_control_over_transport_speed() const
84 // return true; // for PiC control */
85 return false; // for Session-level computed varispeed
89 MTC_Slave::rebind (MIDI::Port& p)
91 port_connections.drop_connections ();
95 port->input()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
96 port->input()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
97 port->input()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
101 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
105 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
106 last_inbound_frame = now;
110 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
112 /* "now" can be zero if this is called from a context where we do not have or do not want
113 to use a timestamp indicating when this MTC time was received. example: when we received
114 a locate command via MMC.
121 Timecode::Time timecode;
122 TimecodeFormat tc_format;
123 bool reset_tc = true;
124 nframes64_t window_root = -1;
126 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
128 timecode.hours = msg[3];
129 timecode.minutes = msg[2];
130 timecode.seconds = msg[1];
131 timecode.frames = msg[0];
133 last_mtc_fps_byte = msg[4];
138 timecode.drop = false;
139 tc_format = timecode_24;
140 can_notify_on_unknown_rate = true;
144 timecode.drop = false;
145 tc_format = timecode_25;
146 can_notify_on_unknown_rate = true;
148 case MTC_30_FPS_DROP:
150 timecode.drop = true;
151 tc_format = timecode_30drop;
152 can_notify_on_unknown_rate = true;
156 timecode.drop = false;
157 can_notify_on_unknown_rate = true;
158 tc_format = timecode_30;
161 /* throttle error messages about unknown MTC rates */
162 if (can_notify_on_unknown_rate) {
163 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
166 can_notify_on_unknown_rate = false;
168 timecode.rate = session.timecode_frames_per_second();
169 timecode.drop = session.timecode_drop_frames();
174 if (!did_reset_tc_format) {
175 saved_tc_format = session.config.get_timecode_format();
176 did_reset_tc_format = true;
178 session.config.set_timecode_format (tc_format);
181 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n",
182 now, timecode, mtc_frame, was_full));
184 if (was_full || outside_window (mtc_frame)) {
186 session.timecode_to_sample (timecode, mtc_frame, true, false);
187 session.request_locate (mtc_frame, false);
188 session.request_transport_speed (0);
189 update_mtc_status (MIDI::MTC_Stopped);
190 reset_window (mtc_frame);
195 /* we've had the first set of 8 qtr frame messages, determine position
196 and allow continuing qtr frame messages to provide position
197 and speed information.
200 /* do a careful conversion of the timecode value to a position
201 so that we take drop/nondrop and all that nonsense into
205 session.timecode_to_sample (timecode, mtc_frame, true, false);
207 /* We received the last quarter frame 7 quarter frames (1.75 mtc
208 frames) after the instance when the contents of the mtc quarter
209 frames were decided. Add time to compensate for the elapsed 1.75
210 frames. Also compensate for audio latency.
213 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
218 if (last_mtc_timestamp == 0) {
220 last_mtc_timestamp = now;
221 last_mtc_frame = mtc_frame;
225 if (give_slave_full_control_over_transport_speed()) {
228 * its not the average, but we will assign it to current.speed below
231 static nframes64_t last_seen_timestamp = 0;
232 static nframes64_t last_seen_position = 0;
234 if ((now - last_seen_timestamp) < 300) {
235 mtc_frame = (mtc_frame + last_seen_position)/2;
238 last_seen_timestamp = now;
239 last_seen_position = mtc_frame;
248 nframes64_t time_delta = (now - last_mtc_timestamp);
250 if (time_delta != 0) {
251 double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
253 process_apparent_speed (apparent_speed);
254 DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
256 DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
259 /* every second, recalibrate the starting point for the speed measurement */
260 if (mtc_frame - last_mtc_frame > session.frame_rate()) {
261 last_mtc_timestamp = now;
262 last_mtc_frame = mtc_frame;
268 current.position = mtc_frame;
269 current.timestamp = now;
270 current.speed = average_speed;
272 window_root = mtc_frame;
277 last_inbound_frame = now;
280 if (window_root >= 0) {
281 reset_window (window_root);
286 MTC_Slave::process_apparent_speed (double this_speed)
288 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
290 /* clamp to an expected range */
292 if (this_speed > 4.0 || this_speed < -4.0) {
293 this_speed = average_speed;
296 if (speed_accumulator_cnt >= speed_accumulator_size) {
297 have_first_speed_accumulator = true;
298 speed_accumulator_cnt = 0;
301 speed_accumulator[speed_accumulator_cnt++] = this_speed;
303 if (have_first_speed_accumulator) {
305 for (size_t i = 0; i < speed_accumulator_size; ++i) {
306 average_speed += speed_accumulator[i];
308 average_speed /= speed_accumulator_size;
313 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
317 mtc[4] = last_mtc_fps_byte;
318 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
323 update_mtc_time (mtc, true, 0);
327 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
329 /* XXX !!! thread safety ... called from MIDI I/O context
330 and process() context (via ::speed_and_position())
334 DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
338 current.position = mtc_frame;
339 current.timestamp = 0;
347 current.position = mtc_frame;
348 current.timestamp = 0;
355 current.position = mtc_frame;
356 current.timestamp = 0;
365 MTC_Slave::read_current (SafeTime *st) const
371 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
378 } while (st->guard1 != st->guard2);
382 MTC_Slave::locked () const
384 return port->input()->mtc_locked();
388 MTC_Slave::ok() const
394 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
396 nframes64_t now = session.engine().frame_time();
400 read_current (&last);
402 if (last.timestamp == 0) {
405 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
409 /* no timecode for 1/4 second ? conclude that its stopped */
411 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
414 session.request_locate (pos, false);
415 session.request_transport_speed (0);
417 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
421 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
423 if (give_slave_full_control_over_transport_speed()) {
424 bool in_control = (session.slave_state() == Session::Running);
425 nframes64_t pic_want_locate = 0;
426 //nframes64_t slave_pos = session.audible_frame();
427 nframes64_t slave_pos = session.transport_frame();
428 static double average_speed = 0;
430 average_speed = pic->get_ratio (last.timestamp, last.position, slave_pos, in_control );
431 pic_want_locate = pic->want_locate();
433 if (in_control && pic_want_locate) {
434 last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
435 std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n";
437 last.speed = average_speed;
441 if (last.speed == 0.0f) {
447 /* scale elapsed time by the current MTC speed */
449 if (last.timestamp && (now > last.timestamp)) {
450 elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
451 DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
452 last.timestamp, now, elapsed, last.speed));
454 elapsed = 0; /* XXX is this right? */
458 /* now add the most recent timecode value plus the estimated elapsed interval */
460 pos = last.position + elapsed;
463 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
469 MTC_Slave::resolution() const
471 return (nframes_t) session.frames_per_timecode_frame();
475 MTC_Slave::queue_reset ()
477 Glib::Mutex::Lock lm (reset_lock);
482 MTC_Slave::maybe_reset ()
491 reset_lock.unlock ();
497 port->input()->reset_mtc_state ();
499 last_inbound_frame = 0;
501 current.position = 0;
502 current.timestamp = 0;
509 last_mtc_timestamp = 0;
512 have_first_speed_accumulator = false;
513 speed_accumulator_cnt = 0;
519 MTC_Slave::reset_window (nframes64_t root)
522 /* if we're waiting for the master to catch us after seeking ahead, keep the window
523 of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
524 ahead of the window root (taking direction into account).
527 switch (port->input()->mtc_running()) {
530 if (session.slave_state() == Session::Running) {
531 window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
533 window_end = root + seekahead_distance ();
535 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
539 if (session.slave_state() == Session::Running) {
540 nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
542 window_begin = root - d;
548 nframes_t d = seekahead_distance ();
550 window_begin = root - d;
556 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
566 MTC_Slave::seekahead_distance () const
569 return session.frame_rate();
573 MTC_Slave::outside_window (nframes64_t pos) const
575 return ((pos < window_begin) || (pos > window_end));