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;
44 /* length (in timecode frames) of the "window" that we consider legal given receipt of
45 a given timecode position. Ardour will try to chase within this window, and will
46 stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
47 in the current direction of motion, so if any timecode arrives that is before the most
48 recently received position (and without the direction of timecode reversing too), we
49 will stop+locate+wait+chase.
52 const int MTC_Slave::frame_tolerance = 2;
54 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
57 can_notify_on_unknown_rate = true;
58 did_reset_tc_format = false;
60 pic = new PIController (1.0, 8);
62 last_mtc_fps_byte = session.get_mtc_timecode_bits ();
65 speed_accumulator_size = 16;
66 speed_accumulator = new double[speed_accumulator_size];
72 MTC_Slave::~MTC_Slave()
74 if (did_reset_tc_format) {
75 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 for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
97 connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
98 connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
99 connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
103 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
107 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
108 last_inbound_frame = now;
112 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
114 /* "now" can be zero if this is called from a context where we do not have or do not want
115 to use a timestamp indicating when this MTC time was received. example: when we received
116 a locate command via MMC.
123 Timecode::Time timecode;
124 TimecodeFormat tc_format;
125 bool reset_tc = true;
126 nframes64_t window_root = -1;
128 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
130 timecode.hours = msg[3];
131 timecode.minutes = msg[2];
132 timecode.seconds = msg[1];
133 timecode.frames = msg[0];
135 last_mtc_fps_byte = msg[4];
140 timecode.drop = false;
141 tc_format = timecode_24;
142 can_notify_on_unknown_rate = true;
146 timecode.drop = false;
147 tc_format = timecode_25;
148 can_notify_on_unknown_rate = true;
150 case MTC_30_FPS_DROP:
152 timecode.drop = true;
153 tc_format = timecode_30drop;
154 can_notify_on_unknown_rate = true;
158 timecode.drop = false;
159 can_notify_on_unknown_rate = true;
160 tc_format = timecode_30;
163 /* throttle error messages about unknown MTC rates */
164 if (can_notify_on_unknown_rate) {
165 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
168 can_notify_on_unknown_rate = false;
170 timecode.rate = session.timecode_frames_per_second();
171 timecode.drop = session.timecode_drop_frames();
176 if (!did_reset_tc_format) {
177 saved_tc_format = session.config.get_timecode_format();
178 did_reset_tc_format = true;
180 session.config.set_timecode_format (tc_format);
183 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n",
184 now, timecode, mtc_frame, was_full));
186 if (was_full || outside_window (mtc_frame)) {
188 session.timecode_to_sample (timecode, mtc_frame, true, false);
189 session.request_locate (mtc_frame, false);
190 session.request_transport_speed (0);
191 update_mtc_status (MIDI::MTC_Stopped);
192 reset_window (mtc_frame);
197 /* we've had the first set of 8 qtr frame messages, determine position
198 and allow continuing qtr frame messages to provide position
199 and speed information.
202 /* do a careful conversion of the timecode value to a position
203 so that we take drop/nondrop and all that nonsense into
207 session.timecode_to_sample (timecode, mtc_frame, true, false);
209 /* We received the last quarter frame 7 quarter frames (1.75 mtc
210 frames) after the instance when the contents of the mtc quarter
211 frames were decided. Add time to compensate for the elapsed 1.75
212 frames. Also compensate for audio latency.
215 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
220 if (last_mtc_timestamp == 0) {
222 last_mtc_timestamp = now;
223 last_mtc_frame = mtc_frame;
227 if (give_slave_full_control_over_transport_speed()) {
230 * its not the average, but we will assign it to current.speed below
233 average_speed = pic->get_ratio (session.audible_frame() - mtc_frame);
240 nframes64_t time_delta = (now - last_mtc_timestamp);
242 if (time_delta != 0) {
243 double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
245 process_apparent_speed (apparent_speed);
246 DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
248 DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
251 /* every second, recalibrate the starting point for the speed measurement */
252 if (mtc_frame - last_mtc_frame > session.frame_rate()) {
253 last_mtc_timestamp = now;
254 last_mtc_frame = mtc_frame;
260 current.position = mtc_frame;
261 current.timestamp = now;
262 current.speed = average_speed;
264 window_root = mtc_frame;
269 last_inbound_frame = now;
272 if (window_root >= 0) {
273 reset_window (window_root);
278 MTC_Slave::process_apparent_speed (double this_speed)
280 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
282 /* clamp to an expected range */
284 if (this_speed > 4.0 || this_speed < -4.0) {
285 this_speed = average_speed;
288 if (speed_accumulator_cnt >= speed_accumulator_size) {
289 have_first_speed_accumulator = true;
290 speed_accumulator_cnt = 0;
293 speed_accumulator[speed_accumulator_cnt++] = this_speed;
295 if (have_first_speed_accumulator) {
297 for (size_t i = 0; i < speed_accumulator_size; ++i) {
298 average_speed += speed_accumulator[i];
300 average_speed /= speed_accumulator_size;
305 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
309 mtc[4] = last_mtc_fps_byte;
310 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
315 update_mtc_time (mtc, true, 0);
319 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
321 /* XXX !!! thread safety ... called from MIDI I/O context
322 and process() context (via ::speed_and_position())
326 DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
330 current.position = mtc_frame;
331 current.timestamp = 0;
339 current.position = mtc_frame;
340 current.timestamp = 0;
347 current.position = mtc_frame;
348 current.timestamp = 0;
357 MTC_Slave::read_current (SafeTime *st) const
363 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
370 } while (st->guard1 != st->guard2);
374 MTC_Slave::locked () const
376 return port->input()->mtc_locked();
380 MTC_Slave::ok() const
386 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
388 nframes64_t now = session.engine().frame_time();
392 read_current (&last);
394 if (last.timestamp == 0) {
397 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
401 /* no timecode for 1/4 second ? conclude that its stopped */
403 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
406 session.request_locate (pos, false);
407 session.request_transport_speed (0);
409 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
413 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
415 if (last.speed == 0.0f) {
421 /* scale elapsed time by the current MTC speed */
423 if (last.timestamp && (now > last.timestamp)) {
424 elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
425 DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
426 last.timestamp, now, elapsed, last.speed));
428 elapsed = 0; /* XXX is this right? */
432 /* now add the most recent timecode value plus the estimated elapsed interval */
434 pos = elapsed + last.position;
437 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
443 MTC_Slave::resolution() const
445 return (nframes_t) session.frames_per_timecode_frame();
449 MTC_Slave::queue_reset ()
451 Glib::Mutex::Lock lm (reset_lock);
456 MTC_Slave::maybe_reset ()
465 reset_lock.unlock ();
471 port->input()->reset_mtc_state ();
473 last_inbound_frame = 0;
475 current.position = 0;
476 current.timestamp = 0;
483 last_mtc_timestamp = 0;
486 have_first_speed_accumulator = false;
487 speed_accumulator_cnt = 0;
489 pic->out_of_bounds();
493 MTC_Slave::reset_window (nframes64_t root)
496 /* if we're waiting for the master to catch us after seeking ahead, keep the window
497 of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
498 ahead of the window root (taking direction into account).
501 switch (port->input()->mtc_running()) {
504 if (session.slave_state() == Session::Running) {
505 window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
507 window_end = root + seekahead_distance ();
509 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
513 if (session.slave_state() == Session::Running) {
514 nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
516 window_begin = root - d;
522 nframes_t d = seekahead_distance ();
524 window_begin = root - d;
530 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
540 MTC_Slave::seekahead_distance () const
543 return session.frame_rate();
547 MTC_Slave::outside_window (nframes64_t pos) const
549 return ((pos < window_begin) || (pos > window_end));