second (and hopefully) final part of changes to respond to header format changes...
[ArdourMidi.git] / libs / ardour / mtc_slave.cc
bloba67bb7481d122dab27e391ed405897ab127ab57b
1 /*
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.
19 #include <iostream>
20 #include <errno.h>
21 #include <poll.h>
22 #include <sys/types.h>
23 #include <unistd.h>
25 #include "pbd/error.h"
26 #include "pbd/enumwriter.h"
27 #include "pbd/failed_constructor.h"
28 #include "pbd/pthread_utils.h"
30 #include "midi++/port.h"
31 #include "ardour/debug.h"
32 #include "ardour/slave.h"
33 #include "ardour/session.h"
34 #include "ardour/audioengine.h"
35 #include "ardour/pi_controller.h"
37 #include "i18n.h"
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace MIDI;
42 using namespace PBD;
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)
55 : session (s)
57 can_notify_on_unknown_rate = true;
58 did_reset_tc_format = false;
59 reset_pending = 0;
60 reset_position = false;
62 pic = new PIChaser();
64 last_mtc_fps_byte = session.get_mtc_timecode_bits ();
65 mtc_frame = 0;
67 speed_accumulator_size = 16;
68 speed_accumulator = new double[speed_accumulator_size];
70 rebind (p);
71 reset (true);
74 MTC_Slave::~MTC_Slave()
76 if (did_reset_tc_format) {
77 session.config.set_timecode_format (saved_tc_format);
80 delete pic;
81 delete [] speed_accumulator;
84 bool
85 MTC_Slave::give_slave_full_control_over_transport_speed() const
87 return true; // for PiC control */
88 // return false; // for Session-level computed varispeed
91 void
92 MTC_Slave::rebind (MIDI::Port& p)
94 port_connections.drop_connections ();
96 port = &p;
98 port->parser()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
99 port->parser()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
100 port->parser()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
103 void
104 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
106 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
107 maybe_reset ();
108 last_inbound_frame = now;
111 void
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.
119 if (now) {
120 maybe_reset ();
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];
137 switch (msg[4]) {
138 case MTC_24_FPS:
139 timecode.rate = 24;
140 timecode.drop = false;
141 tc_format = timecode_24;
142 can_notify_on_unknown_rate = true;
143 break;
144 case MTC_25_FPS:
145 timecode.rate = 25;
146 timecode.drop = false;
147 tc_format = timecode_25;
148 can_notify_on_unknown_rate = true;
149 break;
150 case MTC_30_FPS_DROP:
151 timecode.rate = 30;
152 timecode.drop = true;
153 tc_format = timecode_30drop;
154 can_notify_on_unknown_rate = true;
155 break;
156 case MTC_30_FPS:
157 timecode.rate = 30;
158 timecode.drop = false;
159 can_notify_on_unknown_rate = true;
160 tc_format = timecode_30;
161 break;
162 default:
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"),
166 (int) msg[4])
167 << endmsg;
168 can_notify_on_unknown_rate = false;
170 timecode.rate = session.timecode_frames_per_second();
171 timecode.drop = session.timecode_drop_frames();
172 reset_tc = false;
175 if (reset_tc) {
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 (false);
193 reset_window (mtc_frame);
195 } else {
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
204 consideration.
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();
218 if (now) {
220 if (last_mtc_timestamp == 0) {
222 last_mtc_timestamp = now;
223 last_mtc_frame = mtc_frame;
225 } else {
227 if (give_slave_full_control_over_transport_speed()) {
228 /* PIC
230 * its not the average, but we will assign it to current.speed below
233 static nframes64_t last_seen_timestamp = 0;
234 static nframes64_t last_seen_position = 0;
236 if ((now - last_seen_timestamp) < 300) {
237 mtc_frame = (mtc_frame + last_seen_position)/2;
240 last_seen_timestamp = now;
241 last_seen_position = mtc_frame;
245 } else {
247 /* Non-PiC
250 nframes64_t time_delta = (now - last_mtc_timestamp);
252 if (time_delta != 0) {
253 double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
255 process_apparent_speed (apparent_speed);
256 DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
257 } else {
258 DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
261 /* every second, recalibrate the starting point for the speed measurement */
262 if (mtc_frame - last_mtc_frame > session.frame_rate()) {
263 last_mtc_timestamp = now;
264 last_mtc_frame = mtc_frame;
269 current.guard1++;
270 current.position = mtc_frame;
271 current.timestamp = now;
272 current.speed = average_speed;
273 current.guard2++;
274 window_root = mtc_frame;
278 if (now) {
279 last_inbound_frame = now;
282 if (window_root >= 0) {
283 reset_window (window_root);
287 void
288 MTC_Slave::process_apparent_speed (double this_speed)
290 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
292 /* clamp to an expected range */
294 if (this_speed > 4.0 || this_speed < -4.0) {
295 this_speed = average_speed;
298 if (speed_accumulator_cnt >= speed_accumulator_size) {
299 have_first_speed_accumulator = true;
300 speed_accumulator_cnt = 0;
303 speed_accumulator[speed_accumulator_cnt++] = this_speed;
305 if (have_first_speed_accumulator) {
306 average_speed = 0.0;
307 for (size_t i = 0; i < speed_accumulator_size; ++i) {
308 average_speed += speed_accumulator[i];
310 average_speed /= speed_accumulator_size;
314 void
315 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
317 MIDI::byte mtc[5];
319 mtc[4] = last_mtc_fps_byte;
320 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
321 mtc[2] = mmc_tc[1];
322 mtc[1] = mmc_tc[2];
323 mtc[0] = mmc_tc[3];
325 update_mtc_time (mtc, true, 0);
328 void
329 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
331 /* XXX !!! thread safety ... called from MIDI I/O context
332 and process() context (via ::speed_and_position())
335 switch (status) {
336 case MTC_Stopped:
337 current.guard1++;
338 current.position = mtc_frame;
339 current.timestamp = 0;
340 current.speed = 0;
341 current.guard2++;
343 break;
345 case MTC_Forward:
346 current.guard1++;
347 current.position = mtc_frame;
348 current.timestamp = 0;
349 current.speed = 0;
350 current.guard2++;
351 break;
353 case MTC_Backward:
354 current.guard1++;
355 current.position = mtc_frame;
356 current.timestamp = 0;
357 current.speed = 0;
358 current.guard2++;
359 break;
364 void
365 MTC_Slave::read_current (SafeTime *st) const
367 int tries = 0;
369 do {
370 if (tries == 10) {
371 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
372 usleep (20);
373 tries = 0;
375 *st = current;
376 tries++;
378 } while (st->guard1 != st->guard2);
381 bool
382 MTC_Slave::locked () const
384 return port->parser()->mtc_locked();
387 bool
388 MTC_Slave::ok() const
390 return true;
393 bool
394 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
396 nframes64_t now = session.engine().frame_time();
397 SafeTime last;
398 nframes_t elapsed;
399 bool in_control = false;
401 read_current (&last);
403 if (last.timestamp == 0) {
404 speed = 0;
405 pos = last.position;
406 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
407 return true;
410 /* no timecode for 1/4 second ? conclude that its stopped */
412 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
413 speed = 0;
414 pos = last.position;
415 session.request_locate (pos, false);
416 session.request_transport_speed (0);
417 queue_reset (false);
418 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
419 return false;
422 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
424 if (give_slave_full_control_over_transport_speed()) {
425 in_control = (session.slave_state() == Session::Running);
426 nframes64_t pic_want_locate = 0;
427 //nframes64_t slave_pos = session.audible_frame();
428 nframes64_t slave_pos = session.transport_frame();
429 static double average_speed = 0;
431 nframes64_t ref_now = session.engine().frame_time_at_cycle_start();
432 average_speed = pic->get_ratio (last.timestamp, last.position, ref_now, slave_pos, in_control, session.engine().frames_per_cycle());
434 pic_want_locate = pic->want_locate();
436 if (in_control && pic_want_locate) {
437 last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
438 std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n";
439 } else {
440 last.speed = average_speed;
444 if (last.speed == 0.0f) {
446 elapsed = 0;
448 } else {
450 /* scale elapsed time by the current MTC speed */
452 if (last.timestamp && (now > last.timestamp)) {
453 elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
454 DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
455 last.timestamp, now, elapsed, last.speed));
456 } else {
457 elapsed = 0; /* XXX is this right? */
461 /* now add the most recent timecode value plus the estimated elapsed interval */
463 if (in_control) {
464 pos = session.transport_frame();
465 } else {
466 pos = last.position + elapsed;
469 speed = last.speed;
471 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
474 DEBUG_TRACE (DEBUG::MTC, string_compose ("last = %1 elapsed = %2 pos = %3 speed = %4\n", last.position, elapsed, pos, speed));
476 return true;
479 ARDOUR::nframes_t
480 MTC_Slave::resolution() const
482 return (nframes_t) session.frames_per_timecode_frame();
485 void
486 MTC_Slave::queue_reset (bool reset_pos)
488 Glib::Mutex::Lock lm (reset_lock);
489 reset_pending++;
490 if (reset_pos) {
491 reset_position = true;
495 void
496 MTC_Slave::maybe_reset ()
498 Glib::Mutex::Lock lm (reset_lock);
500 if (reset_pending) {
501 reset (reset_position);
502 reset_pending = 0;
503 reset_position = false;
507 void
508 MTC_Slave::reset (bool with_position)
510 if (with_position) {
511 last_inbound_frame = 0;
512 current.guard1++;
513 current.position = 0;
514 current.timestamp = 0;
515 current.speed = 0;
516 current.guard2++;
517 } else {
518 last_inbound_frame = 0;
519 current.guard1++;
520 current.timestamp = 0;
521 current.speed = 0;
522 current.guard2++;
525 window_begin = 0;
526 window_end = 0;
527 last_mtc_frame = 0;
528 last_mtc_timestamp = 0;
530 average_speed = 0;
531 have_first_speed_accumulator = false;
532 speed_accumulator_cnt = 0;
534 pic->reset();
537 void
538 MTC_Slave::reset_window (nframes64_t root)
541 /* if we're waiting for the master to catch us after seeking ahead, keep the window
542 of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
543 ahead of the window root (taking direction into account).
546 switch (port->parser()->mtc_running()) {
547 case MTC_Forward:
548 window_begin = root;
549 if (session.slave_state() == Session::Running) {
550 window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
551 } else {
552 window_end = root + seekahead_distance ();
554 break;
556 case MTC_Backward:
557 if (session.slave_state() == Session::Running) {
558 nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
559 if (root > d) {
560 window_begin = root - d;
561 window_end = root;
562 } else {
563 window_begin = 0;
565 } else {
566 nframes_t d = seekahead_distance ();
567 if (root > d) {
568 window_begin = root - d;
569 } else {
570 window_begin = 0;
573 window_end = root;
574 break;
576 default:
577 /* do nothing */
578 break;
581 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
584 nframes64_t
585 MTC_Slave::seekahead_distance () const
587 /* 1 second */
588 return session.frame_rate();
591 bool
592 MTC_Slave::outside_window (nframes64_t pos) const
594 return ((pos < window_begin) || (pos > window_end));