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.
118 DEBUG_TRACE (DEBUG::MTC, string_compose ("update MTC time does a reset, was full ? %1 now = %2\n", was_full, now));
122 Timecode::Time timecode;
123 TimecodeFormat tc_format;
124 bool reset_tc = true;
125 nframes64_t window_root = -1;
127 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
129 timecode.hours = msg[3];
130 timecode.minutes = msg[2];
131 timecode.seconds = msg[1];
132 timecode.frames = msg[0];
134 last_mtc_fps_byte = msg[4];
139 timecode.drop = false;
140 tc_format = timecode_24;
141 can_notify_on_unknown_rate = true;
145 timecode.drop = false;
146 tc_format = timecode_25;
147 can_notify_on_unknown_rate = true;
149 case MTC_30_FPS_DROP:
151 timecode.drop = true;
152 tc_format = timecode_30drop;
153 can_notify_on_unknown_rate = true;
157 timecode.drop = false;
158 can_notify_on_unknown_rate = true;
159 tc_format = timecode_30;
162 /* throttle error messages about unknown MTC rates */
163 if (can_notify_on_unknown_rate) {
164 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
167 can_notify_on_unknown_rate = false;
169 timecode.rate = session.timecode_frames_per_second();
170 timecode.drop = session.timecode_drop_frames();
175 if (!did_reset_tc_format) {
176 saved_tc_format = session.config.get_timecode_format();
177 did_reset_tc_format = true;
179 session.config.set_timecode_format (tc_format);
182 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n",
183 now, timecode, mtc_frame, was_full));
185 if (was_full || outside_window (mtc_frame)) {
187 session.timecode_to_sample (timecode, mtc_frame, true, false);
188 session.request_locate (mtc_frame, false);
189 session.request_transport_speed (0);
190 DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC status to stopped, outside MTC window (%1 .. %2 vs. %3)\n",
191 window_begin, window_end, mtc_frame));
192 update_mtc_status (MIDI::MTC_Stopped);
193 DEBUG_TRACE (DEBUG::MTC, string_compose ("outside, so window root reset to %1\n", mtc_frame));
194 reset_window (mtc_frame);
199 /* we've had the first set of 8 qtr frame messages, determine position
200 and allow continuing qtr frame messages to provide position
201 and speed information.
204 /* do a careful conversion of the timecode value to a position
205 so that we take drop/nondrop and all that nonsense into
209 session.timecode_to_sample (timecode, mtc_frame, true, false);
211 /* We received the last quarter frame 7 quarter frames (1.75 mtc
212 frames) after the instance when the contents of the mtc quarter
213 frames were decided. Add time to compensate for the elapsed 1.75
214 frames. Also compensate for audio latency.
217 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
222 if (last_mtc_timestamp == 0) {
224 last_mtc_timestamp = now;
225 last_mtc_frame = mtc_frame;
229 if (give_slave_full_control_over_transport_speed()) {
232 * its not the average, but we will assign it to current.speed below
235 static nframes64_t last_seen_timestamp = 0;
236 static nframes64_t last_seen_position = 0;
238 if ((now - last_seen_timestamp) < 300) {
239 mtc_frame = (mtc_frame + last_seen_position)/2;
242 last_seen_timestamp = now;
243 last_seen_position = mtc_frame;
252 nframes64_t time_delta = (now - last_mtc_timestamp);
254 if (time_delta != 0) {
255 double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
257 process_apparent_speed (apparent_speed);
258 DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
260 DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
263 /* every second, recalibrate the starting point for the speed measurement */
264 if (mtc_frame - last_mtc_frame > session.frame_rate()) {
265 last_mtc_timestamp = now;
266 last_mtc_frame = mtc_frame;
272 current.position = mtc_frame;
273 current.timestamp = now;
274 current.speed = average_speed;
276 window_root = mtc_frame;
281 last_inbound_frame = now;
284 if (window_root >= 0) {
285 DEBUG_TRACE (DEBUG::MTC, string_compose ("window root reset to %1\n", window_root));
286 reset_window (window_root);
291 MTC_Slave::process_apparent_speed (double this_speed)
293 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
295 /* clamp to an expected range */
297 if (this_speed > 4.0 || this_speed < -4.0) {
298 this_speed = average_speed;
301 if (speed_accumulator_cnt >= speed_accumulator_size) {
302 have_first_speed_accumulator = true;
303 speed_accumulator_cnt = 0;
306 speed_accumulator[speed_accumulator_cnt++] = this_speed;
308 if (have_first_speed_accumulator) {
310 for (size_t i = 0; i < speed_accumulator_size; ++i) {
311 average_speed += speed_accumulator[i];
313 average_speed /= speed_accumulator_size;
318 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
322 mtc[4] = last_mtc_fps_byte;
323 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
328 update_mtc_time (mtc, true, 0);
332 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
334 /* XXX !!! thread safety ... called from MIDI I/O context
335 and process() context (via ::speed_and_position())
339 DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
343 current.position = mtc_frame;
344 current.timestamp = 0;
352 current.position = mtc_frame;
353 current.timestamp = 0;
360 current.position = mtc_frame;
361 current.timestamp = 0;
370 MTC_Slave::read_current (SafeTime *st) const
376 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
383 } while (st->guard1 != st->guard2);
387 MTC_Slave::locked () const
389 return port->input()->mtc_locked();
393 MTC_Slave::ok() const
399 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
401 nframes64_t now = session.engine().frame_time();
405 read_current (&last);
407 if (last.timestamp == 0) {
410 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
414 /* no timecode for 1/4 second ? conclude that its stopped */
416 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
419 session.request_locate (pos, false);
420 session.request_transport_speed (0);
422 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
426 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
428 if (give_slave_full_control_over_transport_speed()) {
429 bool in_control = (session.slave_state() == Session::Running);
430 nframes64_t pic_want_locate = 0;
431 //nframes64_t slave_pos = session.audible_frame();
432 nframes64_t slave_pos = session.transport_frame();
433 static double average_speed = 0;
435 average_speed = pic->get_ratio (last.timestamp, last.position, slave_pos, in_control );
436 pic_want_locate = pic->want_locate();
438 if (in_control && pic_want_locate) {
439 last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
440 std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n";
442 last.speed = average_speed;
446 if (last.speed == 0.0f) {
452 /* scale elapsed time by the current MTC speed */
454 if (last.timestamp && (now > last.timestamp)) {
455 elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
456 DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
457 last.timestamp, now, elapsed, last.speed));
459 elapsed = 0; /* XXX is this right? */
463 /* now add the most recent timecode value plus the estimated elapsed interval */
465 pos = last.position + elapsed;
468 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
474 MTC_Slave::resolution() const
476 return (nframes_t) session.frames_per_timecode_frame();
480 MTC_Slave::queue_reset ()
482 Glib::Mutex::Lock lm (reset_lock);
487 MTC_Slave::maybe_reset ()
492 DEBUG_TRACE (DEBUG::MTC, "actually reset\n");
497 reset_lock.unlock ();
503 port->input()->reset_mtc_state ();
505 last_inbound_frame = 0;
507 current.position = 0;
508 current.timestamp = 0;
515 last_mtc_timestamp = 0;
518 have_first_speed_accumulator = false;
519 speed_accumulator_cnt = 0;
525 MTC_Slave::reset_window (nframes64_t root)
528 /* if we're waiting for the master to catch us after seeking ahead, keep the window
529 of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
530 ahead of the window root (taking direction into account).
533 DEBUG_TRACE (DEBUG::MTC, string_compose ("trying to reset MTC window with state = %1\n", enum_2_string (port->input()->mtc_running())));
535 switch (port->input()->mtc_running()) {
538 if (session.slave_state() == Session::Running) {
539 window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
541 window_end = root + seekahead_distance ();
543 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
547 if (session.slave_state() == Session::Running) {
548 nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
550 window_begin = root - d;
556 nframes_t d = seekahead_distance ();
558 window_begin = root - d;
564 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
574 MTC_Slave::seekahead_distance () const
577 return session.frame_rate();
581 MTC_Slave::outside_window (nframes64_t pos) const
583 return ((pos < window_begin) || (pos > window_end));