ardour
mtc_slave.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-4 Paul Davis
3  Overhaul 2012 Robin Gareus <robin@gareus.org>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 #include <iostream>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 
25 #include "pbd/error.h"
26 #include "pbd/pthread_utils.h"
27 
28 #include "ardour/audioengine.h"
29 #include "ardour/debug.h"
30 #include "ardour/midi_buffer.h"
31 #include "ardour/midi_port.h"
32 #include "ardour/session.h"
33 #include "ardour/slave.h"
34 
35 #include <glibmm/timer.h>
36 
37 #include "i18n.h"
38 
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace MIDI;
42 using namespace PBD;
43 using namespace Timecode;
44 
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.
51 */
52 const int MTC_Slave::frame_tolerance = 2;
53 
54 MTC_Slave::MTC_Slave (Session& s, MidiPort& p)
55  : session (s)
56  , port (&p)
57 {
59  did_reset_tc_format = false;
60  reset_pending = 0;
61  reset_position = false;
62  mtc_frame = 0;
63  mtc_frame_dll = 0;
66 
69 
70  mtc_timecode = session.config.get_timecode_format();
71  a3e_timecode = session.config.get_timecode_format();
73 
74  session.config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_Slave::parameter_changed, this, _1));
76  reset (true);
77 
78  port->self_parser().mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
79  port->self_parser().mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
80  port->self_parser().mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
81 }
82 
84 {
87 
88  while (busy_guard1 != busy_guard2) {
89  /* make sure MIDI parser is not currently calling any callbacks in here,
90  * else there's a segfault ahead!
91  *
92  * XXX this is called from jack rt-context :(
93  * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
94  */
95  sched_yield();
96  }
97 
98  if (did_reset_tc_format) {
99  session.config.set_timecode_format (saved_tc_format);
100  }
101 }
102 
103 void
105 {
107 
108  port = &p;
109 
110 }
111 
112 void
114  Timecode::Time offset_tc;
115  Timecode::parse_timecode_format(session.config.get_slave_timecode_offset(), offset_tc);
116  offset_tc.rate = session.timecode_frames_per_second();
117  offset_tc.drop = session.timecode_drop_frames();
118  session.timecode_to_sample(offset_tc, timecode_offset, false, false);
119  timecode_negative_offset = offset_tc.negative;
120 }
121 
122 void
123 MTC_Slave::parameter_changed (std::string const & p)
124 {
125  if (p == "slave-timecode-offset"
126  || p == "timecode-format"
127  ) {
129  }
130 }
131 
132 bool
134 {
135  return true; // DLL align to engine transport
136  // return false; // for Session-level computed varispeed
137 }
138 
141 {
142  return (framecnt_t) quarter_frame_duration * 4.0;
143 }
144 
147 {
149 }
150 
151 bool
153 {
154  return ((pos < window_begin) || (pos > window_end));
155 }
156 
157 
158 bool
160 {
161  DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2 initstate %3\n", port->self_parser().mtc_locked(), last_inbound_frame, engine_dll_initstate));
162  return port->self_parser().mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0;
163 }
164 
165 bool
167 {
168  return true;
169 }
170 
171 void
172 MTC_Slave::queue_reset (bool reset_pos)
173 {
175  reset_pending++;
176  if (reset_pos) {
177  reset_position = true;
178  }
179 }
180 
181 void
183 {
185 
186  if (reset_pending) {
188  reset_pending = 0;
189  reset_position = false;
190  }
191 }
192 
193 void
194 MTC_Slave::reset (bool with_position)
195 {
196  DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_Slave reset %1\n", with_position?"with position":"without position"));
197  if (with_position) {
198  last_inbound_frame = 0;
199  current.guard1++;
200  current.position = 0;
201  current.timestamp = 0;
202  current.speed = 0;
203  current.guard2++;
204  } else {
205  last_inbound_frame = 0;
206  current.guard1++;
207  current.timestamp = 0;
208  current.speed = 0;
209  current.guard2++;
210  }
212  window_begin = 0;
213  window_end = 0;
215  current_delta = 0;
216 }
217 
218 void
219 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
220 {
221  MIDI::byte mtc[5];
222  DEBUG_TRACE (DEBUG::MTC, "MTC_Slave::handle_locate\n");
223 
224  mtc[4] = last_mtc_fps_byte;
225  mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
226  mtc[2] = mmc_tc[1];
227  mtc[1] = mmc_tc[2];
228  mtc[0] = mmc_tc[3];
229 
230  update_mtc_time (mtc, true, 0);
231 }
232 
233 void
235 {
236  int tries = 0;
237 
238  do {
239  if (tries == 10) {
240  error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
241  Glib::usleep (20);
242  tries = 0;
243  }
244  *st = current;
245  tries++;
246 
247  } while (st->guard1 != st->guard2);
248 }
249 
250 void
252 {
253  omega = 2.0 * M_PI * qtr / 2.0 / double(session.frame_rate());
254  b = 1.4142135623730950488 * omega;
255  c = omega * omega;
256 
257  e2 = qtr;
258  t0 = double(tme);
259  t1 = t0 + e2;
260  DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
261 }
262 
263 /* called from MIDI parser */
264 void
265 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now)
266 {
267  busy_guard1++;
268  const double qtr_d = quarter_frame_duration;
269 
270  mtc_frame_dll += qtr_d * (double) transport_direction;
271  mtc_frame = rint(mtc_frame_dll);
272 
273  DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
274 
275  double mtc_speed = 0;
276  if (first_mtc_timestamp != 0) {
277  /* update MTC DLL and calculate speed */
278  const double e = mtc_frame_dll - (double)transport_direction * ((double)now - (double)current.timestamp + t0);
279  t0 = t1;
280  t1 += b * e + e2;
281  e2 += c * e;
282 
283  mtc_speed = (t1 - t0) / qtr_d;
284  DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d));
285 
286  current.guard1++;
288  current.timestamp = now;
289  current.speed = mtc_speed;
290  current.guard2++;
291 
292  last_inbound_frame = now;
293  }
294 
295  maybe_reset ();
296 
297  busy_guard2++;
298 }
299 
300 /* called from MIDI parser _after_ update_mtc_qtr()
301  * when a full TC has been received
302  * OR on locate */
303 void
304 MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now)
305 {
306  busy_guard1++;
307 
308  /* "now" can be zero if this is called from a context where we do not have or do not want
309  to use a timestamp indicating when this MTC time was received. example: when we received
310  a locate command via MMC.
311  */
312  DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
313  TimecodeFormat tc_format;
314  bool reset_tc = true;
315 
316  timecode.hours = msg[3];
317  timecode.minutes = msg[2];
318  timecode.seconds = msg[1];
319  timecode.frames = msg[0];
320 
321  last_mtc_fps_byte = msg[4];
322 
323  DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
324 
325  if (now) {
326  maybe_reset ();
327  }
328 
329  switch (msg[4]) {
330  case MTC_24_FPS:
331  timecode.rate = 24;
332  timecode.drop = false;
333  tc_format = timecode_24;
335  break;
336  case MTC_25_FPS:
337  timecode.rate = 25;
338  timecode.drop = false;
339  tc_format = timecode_25;
341  break;
342  case MTC_30_FPS_DROP:
343  if (Config->get_timecode_source_2997()) {
344  tc_format = Timecode::timecode_2997000drop;
345  timecode.rate = (29970.0/1000.0);
346  } else {
347  tc_format = timecode_2997drop;
348  timecode.rate = (30000.0/1001.0);
349  }
350  timecode.drop = true;
352  break;
353  case MTC_30_FPS:
354  timecode.rate = 30;
355  timecode.drop = false;
357  tc_format = timecode_30;
358  break;
359  default:
360  /* throttle error messages about unknown MTC rates */
362  error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
363  (int) msg[4])
364  << endmsg;
366  }
369  reset_tc = false;
370  }
371 
372  if (reset_tc) {
373  TimecodeFormat cur_timecode = session.config.get_timecode_format();
374  if (Config->get_timecode_sync_frame_rate()) {
375  /* enforce time-code */
376  if (!did_reset_tc_format) {
377  saved_tc_format = cur_timecode;
378  did_reset_tc_format = true;
379  }
380  if (cur_timecode != tc_format) {
381  if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
382  warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
383  Timecode::timecode_format_name(cur_timecode),
384  Timecode::timecode_format_name(tc_format))
385  << endmsg;
386  }
387  }
388  session.config.set_timecode_format (tc_format);
389  } else {
390  /* only warn about TC mismatch */
391  if (mtc_timecode != tc_format) printed_timecode_warning = false;
392  if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
393 
394  if (cur_timecode != tc_format && ! printed_timecode_warning) {
395  if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
396  warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 %2:%3."),
397  Timecode::timecode_format_name(tc_format),
398  PROGRAM_NAME,
399  Timecode::timecode_format_name(cur_timecode))
400  << endmsg;
401  }
403  }
404  }
405  mtc_timecode = tc_format;
406  a3e_timecode = cur_timecode;
407 
408  speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
409  }
410 
411  /* do a careful conversion of the timecode value to a position
412  so that we take drop/nondrop and all that nonsense into
413  consideration.
414  */
415 
416  quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
417 
418  Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
419  double(session.frame_rate()),
420  session.config.get_subframes_per_frame(),
422  );
423 
424  DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
425  now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
426 
427  if (was_full || outside_window (mtc_frame)) {
428  DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC %1 or outside window %2\n", was_full, outside_window (mtc_frame)));
431  update_mtc_status (MIDI::MTC_Stopped);
432  reset (false);
434  } else {
435 
436  /* we've had the first set of 8 qtr frame messages, determine position
437  and allow continuing qtr frame messages to provide position
438  and speed information.
439  */
440 
441  /* We received the last quarter frame 7 quarter frames (1.75 mtc
442  frames) after the instance when the contents of the mtc quarter
443  frames were decided. Add time to compensate for the elapsed 1.75
444  frames.
445  */
446  double qtr = quarter_frame_duration;
447  long int mtc_off = (long) rint(7.0 * qtr);
448 
449  DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
451 
452  switch (port->self_parser().mtc_running()) {
453  case MTC_Backward:
454  mtc_frame -= mtc_off;
455  qtr *= -1.0;
456  break;
457  case MTC_Forward:
458  mtc_frame += mtc_off;
459  break;
460  default:
461  break;
462  }
463 
464  DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
465 
466  if (now) {
467  if (first_mtc_timestamp == 0 || current.timestamp == 0) {
468  first_mtc_timestamp = now;
469  init_mtc_dll(mtc_frame, qtr);
471  }
472  current.guard1++;
474  current.timestamp = now;
475  current.guard2++;
477  }
478  }
479 
480  if (now) {
481  last_inbound_frame = now;
482  }
483  busy_guard2++;
484 }
485 
486 void
487 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
488 {
489  /* XXX !!! thread safety ... called from MIDI I/O context
490  * on locate (via ::update_mtc_time())
491  */
492  DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", pthread_name()));
493  return; // why was this fn needed anyway ? it just messes up things -> use reset.
494  busy_guard1++;
495 
496  switch (status) {
497  case MTC_Stopped:
498  current.guard1++;
500  current.timestamp = 0;
501  current.speed = 0;
502  current.guard2++;
503 
504  break;
505 
506  case MTC_Forward:
507  current.guard1++;
509  current.timestamp = 0;
510  current.speed = 0;
511  current.guard2++;
512  break;
513 
514  case MTC_Backward:
515  current.guard1++;
517  current.timestamp = 0;
518  current.speed = 0;
519  current.guard2++;
520  break;
521  }
522  busy_guard2++;
523 }
524 
525 void
527 {
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).
531  */
532 
534 
535  switch (port->self_parser().mtc_running()) {
536  case MTC_Forward:
537  window_begin = root;
539  window_end = root + d;
540  break;
541 
542  case MTC_Backward:
543  transport_direction = -1;
544  if (root > d) {
545  window_begin = root - d;
546  window_end = root;
547  } else {
548  window_begin = 0;
549  }
550  window_end = root;
551  break;
552 
553  default:
554  /* do nothing */
555  break;
556  }
557 
558  DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
559 }
560 
561 void
563 {
564  /* the bandwidth of the DLL is a trade-off,
565  * because the max-speed of the transport in ardour is
566  * limited to +-8.0, a larger bandwidth would cause oscillations
567  *
568  * But this is only really a problem if the user performs manual
569  * seeks while transport is running and slaved to MTC.
570  */
571  oe = 2.0 * M_PI * double(inc) / 2.0 / double(session.frame_rate());
572  be = 1.4142135623730950488 * oe;
573  ce = oe * oe;
574 
575  ee2 = double(transport_direction * inc);
576  te0 = double(pos);
577  te1 = te0 + ee2;
578  DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", te0, te1, ee2));
579 }
580 
581 /* main entry point from session_process.cc
582 xo * in process callback context */
583 bool
585 {
587  framepos_t sess_pos = session.transport_frame(); // corresponds to now
588  //sess_pos -= session.engine().frames_since_cycle_start();
589 
590  SafeTime last;
591  frameoffset_t elapsed;
592  bool engine_dll_reinitialized = false;
593 
594  read_current (&last);
595 
596  DEBUG_TRACE (DEBUG::MTC, string_compose ("speed&pos: timestamp %1 speed %2 initstate %3 dir %4 tpos %5 now %6 last-in %7\n",
597  last.timestamp,
598  last.speed,
601  sess_pos,
602  now,
604 
605  /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */
606  if (last.timestamp == 0) {
608  } else if (engine_dll_initstate != transport_direction && last.speed != 0) {
611  engine_dll_reinitialized = true;
612  }
613 
614  if (last.timestamp == 0) {
615  speed = 0;
616  pos = session.transport_frame() ; // last.position;
617  DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos));
618  return true;
619  }
620 
621  /* no timecode for two frames - conclude that it's stopped */
623  speed = 0;
624  pos = last.position;
625  session.request_locate (pos, false);
628  queue_reset (false);
629  DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n");
630  return false;
631  }
632 
633 
634  DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position mtc-tme: %1 mtc-pos: %2 mtc-spd: %3\n", last.timestamp, last.position, last.speed));
635  DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position eng-tme: %1 eng-pos: %2\n", now, sess_pos));
636 
637  double speed_flt = last.speed;
638 
639  /* interpolate position according to speed and time since last quarter-frame*/
640  if (speed_flt == 0.0f) {
641  elapsed = 0;
642  } else {
643  /* scale elapsed time by the current MTC speed */
644  elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp));
645  if (give_slave_full_control_over_transport_speed() && !engine_dll_reinitialized) {
646  /* there is an engine vs MTC position frame-delta.
647  * This mostly due to quantization and rounding of (speed * nframes)
648  * but can also due to the session-process not calling
649  * speed_and_position() every cycle under some circumstances.
650  * Thus we use an other DLL to align the engine and the MTC
651  */
652 
653  /* update engine DLL and calculate speed */
654  const double e = double (last.position + elapsed - sess_pos);
655  te0 = te1;
656  te1 += be * e + ee2;
657  ee2 += ce * e;
658  speed_flt = (te1 - te0) / double(session.engine().samples_per_cycle());
659  DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().samples_per_cycle() ));
660  }
661  }
662 
663  pos = last.position + elapsed;
664  speed = speed_flt;
665 
666  /* may happen if the user performs a seek in the timeline while slaved to running MTC
667  * engine-DLL can oscillate back before 0.
668  * also see note in MTC_Slave::init_engine_dll
669  */
671  && speed != 0
672  && ((pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()))) {
674  queue_reset (false);
675  }
676 
677  /* provide a .1% deadzone to lock the speed */
678  if (fabs (speed - 1.0) <= 0.001)
679  speed = 1.0;
680 
681  DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
682  speed, pos, last.position, elapsed, pos - sess_pos));
683 
684  current_delta = (pos - sess_pos);
685 
686  return true;
687 }
688 
689 Timecode::TimecodeFormat
691 {
692  return mtc_timecode;
693 }
694 
695 std::string
697 {
698  SafeTime last;
699  read_current (&last);
700  if (last.timestamp == 0 || reset_pending) {
701  return " --:--:--:--";
702  }
703  return Timecode::timecode_format_sampletime(
704  last.position,
705  double(session.frame_rate()),
706  Timecode::timecode_to_frames_per_second(mtc_timecode),
707  Timecode::timecode_has_drop_frames(mtc_timecode));
708 }
709 
710 std::string
712 {
713  char delta[80];
714  SafeTime last;
715  read_current (&last);
716  if (last.timestamp == 0 || reset_pending) {
717  snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
718  } else {
719  snprintf(delta, sizeof(delta), "\u0394<span foreground=\"green\" face=\"monospace\" >%s%s%" PRIi64 "</span>sm",
721  }
722  return std::string(delta);
723 }
void parameter_changed(std::string const &p)
Definition: mtc_slave.cc:123
bool timecode_negative_offset
Definition: slave.h:252
double timecode_frames_per_second() const
Definition: session_time.cc:55
void read_current(SafeTime *) const
Definition: mtc_slave.cc:234
LIBPBD_API const char * pthread_name()
double te1
calculated sync time
Definition: slave.h:319
framepos_t mtc_frame
Definition: slave.h:286
#define LEADINGZERO(A)
Definition: slave.h:41
bool actively_recording() const
Definition: session.h:280
pframes_t samples_per_cycle() const
Definition: audioengine.cc:983
framepos_t position
Definition: slave.h:224
double omega
DLL filter coefficients.
Definition: slave.h:314
framepos_t last_inbound_frame
Definition: slave.h:288
MIDI::Parser & self_parser()
Definition: midi_port.h:61
Glib::Threads::Mutex reset_lock
Definition: slave.h:295
Session & session
Definition: slave.h:277
Timecode::TimecodeFormat a3e_timecode
Definition: slave.h:305
tuple f
Definition: signals.py:35
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
double te0
time at the beginning of the engine process
Definition: slave.h:318
framepos_t first_mtc_timestamp
Definition: slave.h:292
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
SessionConfiguration config
Definition: session.h:866
double t0
time at the beginning of the MTC quater frame
Definition: slave.h:311
void request_locate(framepos_t frame, bool with_roll=false)
framecnt_t frame_rate() const
Definition: session.h:365
uint32_t reset_pending
Definition: slave.h:296
int transport_direction
Definition: slave.h:298
bool speed_and_position(double &, framepos_t &)
Definition: mtc_slave.cc:584
void update_mtc_status(MIDI::MTC_Status)
Definition: mtc_slave.cc:487
void parse_timecode_offset()
Definition: mtc_slave.cc:113
framepos_t timecode_offset
Definition: slave.h:251
double frames_per_timecode_frame() const
Definition: session.h:370
PBD::ScopedConnectionList port_connections
Definition: slave.h:279
#define _(Text)
Definition: i18n.h:11
bool can_notify_on_unknown_rate
Definition: slave.h:281
bool timecode_drop_frames() const
Definition: session_time.cc:61
int64_t framecnt_t
Definition: types.h:76
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
bool outside_window(framepos_t) const
Definition: mtc_slave.cc:152
bool did_reset_tc_format
Definition: slave.h:293
#define PLUSMINUS(A)
Definition: slave.h:40
double speed
Definition: slave.h:226
void update_mtc_time(const MIDI::byte *, bool, framepos_t)
Definition: mtc_slave.cc:304
PBD::ScopedConnection config_connection
Definition: slave.h:280
framepos_t transport_frame() const
Definition: session.h:551
Definition: amp.h:29
void request_transport_speed(double speed, bool as_default=false)
void reset(bool with_pos)
Definition: mtc_slave.cc:194
bool locked() const
Definition: mtc_slave.cc:159
SafeTime current
Definition: slave.h:285
framepos_t timestamp
Definition: slave.h:225
framepos_t sample_time_at_cycle_start()
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
int64_t framepos_t
Definition: types.h:66
framepos_t window_end
Definition: slave.h:291
Timecode::TimecodeFormat saved_tc_format
Definition: slave.h:294
std::string approximate_current_delta() const
Definition: mtc_slave.cc:711
int64_t frameoffset_t
Definition: types.h:71
double speedup_due_to_tc_mismatch
Definition: slave.h:302
PBD::Signal1< void, std::string > ParameterChanged
Definition: configuration.h:44
static const int frame_tolerance
Definition: slave.h:283
MIDI::byte get_mtc_timecode_bits() const
Definition: session.h:373
std::string approximate_current_position() const
Definition: mtc_slave.cc:696
bool give_slave_full_control_over_transport_speed() const
Definition: mtc_slave.cc:133
bool reset_position
Definition: slave.h:297
double quarter_frame_duration
Definition: slave.h:303
void timecode_to_sample(Timecode::Time &timecode, framepos_t &sample, bool use_offset, bool use_subframes) const
Definition: debug.h:30
frameoffset_t current_delta
Definition: slave.h:308
bool ok() const
Definition: mtc_slave.cc:166
LIBARDOUR_API uint64_t MTC
Definition: debug.cc:39
Timecode::TimecodeFormat apparent_timecode_format() const
Definition: mtc_slave.cc:690
MIDI::byte last_mtc_fps_byte
Definition: slave.h:289
void init_mtc_dll(framepos_t, double)
Definition: mtc_slave.cc:251
double t1
calculated end of the MTC quater frame
Definition: slave.h:312
double ee2
second order loop error
Definition: slave.h:320
void init_engine_dll(framepos_t, framepos_t)
Definition: mtc_slave.cc:562
int engine_dll_initstate
Definition: slave.h:317
volatile int guard1
Definition: slave.h:223
bool printed_timecode_warning
Definition: slave.h:307
double mtc_frame_dll
Definition: slave.h:287
void update_mtc_qtr(MIDI::Parser &, int, framepos_t)
Definition: mtc_slave.cc:265
void queue_reset(bool with_pos)
Definition: mtc_slave.cc:172
void rebind(MidiPort &)
Definition: mtc_slave.cc:104
void reset_window(framepos_t)
Definition: mtc_slave.cc:526
Timecode::TimecodeFormat mtc_timecode
Definition: slave.h:304
void handle_locate(const MIDI::byte *)
Definition: mtc_slave.cc:219
double oe
DLL filter coefficients.
Definition: slave.h:321
framecnt_t resolution() const
Definition: mtc_slave.cc:140
framecnt_t seekahead_distance() const
Definition: mtc_slave.cc:146
AudioEngine & engine()
Definition: session.h:546
Definition: ardour.h:41
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
Timecode::Time timecode
Definition: slave.h:306
double e2
second order loop error
Definition: slave.h:313
framepos_t window_begin
Definition: slave.h:290
volatile int guard2
Definition: slave.h:227
MidiPort * port
Definition: slave.h:278