ardour
ltc_slave.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 Paul Davis
3  Witten by 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/debug.h"
29 #include "ardour/slave.h"
30 #include "ardour/session.h"
31 #include "ardour/audioengine.h"
32 #include "ardour/audio_port.h"
33 
34 #include "i18n.h"
35 
36 using namespace std;
37 using namespace ARDOUR;
38 using namespace MIDI;
39 using namespace PBD;
40 using namespace Timecode;
41 
42 #define FLYWHEEL_TIMEOUT ( 1 * session.frame_rate() )
43 
44 LTC_Slave::LTC_Slave (Session& s)
45  : session (s)
46 {
50 
51  did_reset_tc_format = false;
52  delayedlocked = 10;
53  monotonic_cnt = 0;
54  fps_detected=false;
55  sync_lock_broken = false;
56 
57  ltc_timecode = session.config.get_timecode_format();
58  a3e_timecode = session.config.get_timecode_format();
61  memset(&prev_frame, 0, sizeof(LTCFrameExt));
62 
63  decoder = ltc_decoder_create((int) frames_per_ltc_frame, 128 /*queue size*/);
64 
65  session.config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&LTC_Slave::parameter_changed, this, _1));
67  reset();
69  session.Xrun.connect_same_thread (port_connections, boost::bind (&LTC_Slave::resync_xrun, this));
70  session.engine().GraphReordered.connect_same_thread (port_connections, boost::bind (&LTC_Slave::resync_latency, this));
71 }
72 
74 {
77 
78  if (did_reset_tc_format) {
79  session.config.set_timecode_format (saved_tc_format);
80  }
81 
82  ltc_decoder_free(decoder);
83 }
84 
85 void
87  Timecode::Time offset_tc;
88  Timecode::parse_timecode_format(session.config.get_slave_timecode_offset(), offset_tc);
89  offset_tc.rate = session.timecode_frames_per_second();
90  offset_tc.drop = session.timecode_drop_frames();
91  session.timecode_to_sample(offset_tc, timecode_offset, false, false);
92  timecode_negative_offset = offset_tc.negative;
93 }
94 
95 void
96 LTC_Slave::parameter_changed (std::string const & p)
97 {
98  if (p == "slave-timecode-offset"
99  || p == "timecode-format"
100  ) {
102  }
103 }
104 
107 {
108  return (framecnt_t) (session.frame_rate() / 1000);
109 }
110 
111 bool
113 {
114  return (delayedlocked < 5);
115 }
116 
117 bool
119 {
120  return true;
121 }
122 
123 void
125 {
126  DEBUG_TRACE (DEBUG::LTC, "LTC resync_xrun()\n");
128  sync_lock_broken = false;
129 }
130 
131 void
133 {
134  DEBUG_TRACE (DEBUG::LTC, "LTC resync_latency()\n");
136  sync_lock_broken = false;
137 
138  if (!session.deletion_in_progress() && session.ltc_output_io()) { /* check if Port exits */
141  }
142 }
143 
144 void
146 {
147  DEBUG_TRACE (DEBUG::LTC, "LTC reset()\n");
148  last_timestamp = 0;
149  current_delta = 0;
151  ltc_speed = 0;
153  sync_lock_broken = false;
154 }
155 
156 void
157 LTC_Slave::parse_ltc(const ARDOUR::pframes_t nframes, const Sample* const in, const ARDOUR::framecnt_t posinfo)
158 {
159  pframes_t i;
160  unsigned char sound[8192];
161  if (nframes > 8192) {
162  /* TODO warn once or wrap, loop conversion below
163  * does jack/A3 support > 8192 spp anyway?
164  */
165  return;
166  }
167 
168  for (i = 0; i < nframes; i++) {
169  const int snd=(int)rint((127.0*in[i])+128.0);
170  sound[i] = (unsigned char) (snd&0xff);
171  }
172  ltc_decoder_write(decoder, sound, nframes, posinfo);
173  return;
174 }
175 
176 bool
177 LTC_Slave::equal_ltc_frame_time(LTCFrame *a, LTCFrame *b) {
178  if ( a->frame_units != b->frame_units
179  || a->frame_tens != b->frame_tens
180  || a->dfbit != b->dfbit
181  || a->secs_units != b->secs_units
182  || a->secs_tens != b->secs_tens
183  || a->mins_units != b->mins_units
184  || a->mins_tens != b->mins_tens
185  || a->hours_units != b->hours_units
186  || a->hours_tens != b->hours_tens
187  ) {
188  return false;
189  }
190  return true;
191 }
192 
193 bool
194 LTC_Slave::detect_discontinuity(LTCFrameExt *frame, int fps, bool fuzzy) {
195  bool discontinuity_detected = false;
196 
197  if (fuzzy && (
198  ( frame->reverse && prev_frame.ltc.frame_units == 0)
199  ||(!frame->reverse && frame->ltc.frame_units == 0)
200  )) {
201  memcpy(&prev_frame, frame, sizeof(LTCFrameExt));
202  return false;
203  }
204 
205  if (frame->reverse) {
206  ltc_frame_decrement(&prev_frame.ltc, fps, LTC_TV_525_60, 0);
207  } else {
208  ltc_frame_increment(&prev_frame.ltc, fps, LTC_TV_525_60, 0);
209  }
210  if (!equal_ltc_frame_time(&prev_frame.ltc, &frame->ltc)) {
211  discontinuity_detected = true;
212  }
213 
214  memcpy(&prev_frame, frame, sizeof(LTCFrameExt));
215  return discontinuity_detected;
216 }
217 
218 bool
219 LTC_Slave::detect_ltc_fps(int frameno, bool df)
220 {
221  bool fps_changed = false;
222  double detected_fps = 0;
223  if (frameno > ltc_detect_fps_max)
224  {
225  ltc_detect_fps_max = frameno;
226  }
228 
229  if (ltc_detect_fps_cnt > 40) {
231  detected_fps = ltc_detect_fps_max + 1;
232  if (df) {
233  /* LTC df -> indicates fractional framerate */
234  if (Config->get_timecode_source_2997()) {
235  detected_fps = detected_fps * 999.0 / 1000.0;
236  } else {
237  detected_fps = detected_fps * 1000.0 / 1001.0;
238  }
239  }
240 
241  if (timecode.rate != detected_fps || timecode.drop != df) {
242  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC detected FPS: %1%2\n", detected_fps, df?"df":"ndf"));
243  } else {
244  detected_fps = 0; /* no cange */
245  }
246  }
248  }
249 
250  /* when changed */
251  if (detected_fps != 0 && (detected_fps != timecode.rate || df != timecode.drop)) {
252  timecode.rate = detected_fps;
253  timecode.drop = df;
254  frames_per_ltc_frame = double(session.frame_rate()) / timecode.rate;
255  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC reset to FPS: %1%2 ; audio-frames per LTC: %3\n",
256  detected_fps, df?"df":"ndf", frames_per_ltc_frame));
257  fps_changed=true;
258  }
259 
260  /* poll and check session TC */
261  TimecodeFormat tc_format = apparent_timecode_format();
262  TimecodeFormat cur_timecode = session.config.get_timecode_format();
263 
264  if (Config->get_timecode_sync_frame_rate()) {
265  /* enforce time-code */
266  if (!did_reset_tc_format) {
267  saved_tc_format = cur_timecode;
268  did_reset_tc_format = true;
269  }
270  if (cur_timecode != tc_format) {
271  if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
272  warning << string_compose(_("Session framerate adjusted from %1 to LTC's %2."),
273  Timecode::timecode_format_name(cur_timecode),
274  Timecode::timecode_format_name(tc_format))
275  << endmsg;
276  }
277  session.config.set_timecode_format (tc_format);
278  }
279  } else {
280  /* only warn about TC mismatch */
281  if (ltc_timecode != tc_format) printed_timecode_warning = false;
282  if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
283 
284  if (cur_timecode != tc_format && ! printed_timecode_warning) {
285  if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
286  warning << string_compose(_("Session and LTC framerate mismatch: LTC:%1 Session:%2."),
287  Timecode::timecode_format_name(tc_format),
288  Timecode::timecode_format_name(cur_timecode))
289  << endmsg;
290  }
292  }
293  }
294  ltc_timecode = tc_format;
295  a3e_timecode = cur_timecode;
296 
297  return fps_changed;
298 }
299 
300 void
302 {
303  LTCFrameExt frame;
304  enum LTC_TV_STANDARD tv_standard = LTC_TV_625_50;
305  while (ltc_decoder_read(decoder, &frame)) {
306  SMPTETimecode stime;
307 
308  ltc_frame_to_time(&stime, &frame.ltc, 0);
309  timecode.negative = false;
310  timecode.subframes = 0;
311 
312  /* set timecode.rate and timecode.drop: */
313  bool ltc_is_static = equal_ltc_frame_time(&prev_frame.ltc, &frame.ltc);
314 
315  if (detect_discontinuity(&frame, ceil(timecode.rate), !fps_detected)) {
317  fps_detected=false;
318  }
319 
320  if (!ltc_is_static && detect_ltc_fps(stime.frame, (frame.ltc.dfbit)? true : false)) {
321  reset();
322  fps_detected=true;
323  }
324 
325 #if 0 // Devel/Debug
326  fprintf(stdout, "LTC %02d:%02d:%02d%c%02d | %8lld %8lld%s\n",
327  stime.hours,
328  stime.mins,
329  stime.secs,
330  (frame.ltc.dfbit) ? '.' : ':',
331  stime.frame,
332  frame.off_start,
333  frame.off_end,
334  frame.reverse ? " R" : " "
335  );
336 #endif
337 
338  /* when a full LTC frame is decoded, the timecode the LTC frame
339  * is referring has just passed.
340  * So we send the _next_ timecode which
341  * is expected to start at the end of the current frame
342  */
343  int fps_i = ceil(timecode.rate);
344 
345  switch(fps_i) {
346  case 30:
347  if (timecode.drop) {
348  tv_standard = LTC_TV_525_60;
349  } else {
350  tv_standard = LTC_TV_1125_60;
351  }
352  break;
353  case 25:
354  tv_standard = LTC_TV_625_50;
355  break;
356  default:
357  tv_standard = LTC_TV_FILM_24; /* == LTC_TV_1125_60 == no offset, 24,30fps BGF */
358  break;
359  }
360 
361  if (!frame.reverse) {
362  ltc_frame_increment(&frame.ltc, fps_i, tv_standard, 0);
363  ltc_frame_to_time(&stime, &frame.ltc, 0);
365  frame.off_start -= ltc_frame_alignment(session.frames_per_timecode_frame(), tv_standard);
366  frame.off_end -= ltc_frame_alignment(session.frames_per_timecode_frame(), tv_standard);
367  } else {
368  ltc_frame_decrement(&frame.ltc, fps_i, tv_standard, 0);
369  int off = frame.off_end - frame.off_start;
370  frame.off_start += off - ltc_frame_alignment(session.frames_per_timecode_frame(), tv_standard);
371  frame.off_end += off - ltc_frame_alignment(session.frames_per_timecode_frame(), tv_standard);
372  transport_direction = -1;
373  }
374 
375  timecode.hours = stime.hours;
376  timecode.minutes = stime.mins;
377  timecode.seconds = stime.secs;
378  timecode.frames = stime.frame;
379 
380  /* map LTC timecode to session TC setting */
381  framepos_t ltc_frame;
382  Timecode::timecode_to_sample (timecode, ltc_frame, true, false,
383  double(session.frame_rate()),
384  session.config.get_subframes_per_frame(),
386  );
387 
389 
390  framepos_t cur_timestamp = frame.off_end + 1;
391  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC F: %1 LF: %2 N: %3 L: %4\n", ltc_frame, last_ltc_frame, cur_timestamp, last_timestamp));
392  if (frame.off_end + 1 <= last_timestamp || last_timestamp == 0) {
393  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: UNCHANGED: %1\n", ltc_speed));
394  } else {
395  ltc_speed = double(ltc_frame - last_ltc_frame) / double(cur_timestamp - last_timestamp);
396  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: %1\n", ltc_speed));
397  }
398 
399  if (fabs(ltc_speed) > 10.0) {
400  ltc_speed = 0;
401  }
402 
403  last_timestamp = frame.off_end + 1;
404  last_ltc_frame = ltc_frame;
405  } /* end foreach decoded LTC frame */
406 }
407 
408 void
410 {
411  double omega = 2.0 * M_PI * double(inc) / double(session.frame_rate());
412  b = 1.4142135623730950488 * omega;
413  c = omega * omega;
414 
415  e2 = double(ltc_speed * inc);
416  t0 = double(pos);
417  t1 = t0 + e2;
418  DEBUG_TRACE (DEBUG::LTC, string_compose ("[re-]init Engine DLL %1 %2 %3\n", t0, t1, e2));
419 }
420 
421 /* main entry point from session_process.cc
422  * called from process callback context
423  * so it is OK to use get_buffer()
424  */
425 bool
427 {
428  bool engine_init_called = false;
430  framepos_t sess_pos = session.transport_frame(); // corresponds to now
432 
433  Sample* in;
434 
436 
437  in = (Sample*) AudioEngine::instance()->port_engine().get_buffer (ltcport->port_handle(), nframes);
438 
439  frameoffset_t skip = now - (monotonic_cnt + nframes);
440  monotonic_cnt = now;
441  DEBUG_TRACE (DEBUG::LTC, string_compose ("speed_and_position - TID:%1 | latency: %2 | skip %3\n", pthread_name(), ltc_slave_latency.max, skip));
442 
443  if (last_timestamp == 0) {
445  if (delayedlocked < 10) ++delayedlocked;
446  }
447  else if (engine_dll_initstate != transport_direction && ltc_speed != 0) {
449  init_engine_dll(last_ltc_frame + rint(ltc_speed * double(2 * nframes + now - last_timestamp)),
451  engine_init_called = true;
452  }
453 
454  if (in) {
455  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC Process eng-tme: %1 eng-pos: %2\n", now, sess_pos));
456  /* when the jack-graph changes and if ardour performs
457  * locates, the audioengine is stopped (skipping frames) while
458  * jack [time] moves along.
459  */
460  if (skip > 0) {
461  DEBUG_TRACE (DEBUG::LTC, string_compose("engine skipped %1 frames. Feeding silence to LTC parser.\n", skip));
462  if (skip >= 8192) skip = 8192;
463  unsigned char sound[8192];
464  memset(sound, 0, sizeof(char) * skip);
465  ltc_decoder_write(decoder, sound, nframes, now);
466  } else if (skip != 0) {
467  /* this should never happen. it may if monotonic_cnt, now overflow on 64bit */
468  DEBUG_TRACE (DEBUG::LTC, string_compose("engine skipped %1 frames\n", skip));
469  reset();
470  }
471 
472  parse_ltc(nframes, in, now);
473  process_ltc(now);
474  }
475 
476  if (last_timestamp == 0) {
477  DEBUG_TRACE (DEBUG::LTC, "last timestamp == 0\n");
478  speed = 0;
479  pos = session.transport_frame();
480  return true;
481  } else if (ltc_speed != 0) {
482  if (delayedlocked > 1) delayedlocked--;
483  else if (current_delta == 0) delayedlocked = 0;
484  }
485 
486  if (abs(now - last_timestamp) > FLYWHEEL_TIMEOUT) {
487  DEBUG_TRACE (DEBUG::LTC, "flywheel timeout\n");
488  reset();
489  speed = 0;
490  pos = session.transport_frame();
491  return true;
492  }
493 
494  /* it take 2 cycles from naught to rolling.
495  * during these to initial cycles the speed == 0
496  *
497  * the first cycle:
498  * DEBUG::Slave: slave stopped, move to NNN
499  * DEBUG::Transport: Request forced locate to NNN
500  * DEBUG::Slave: slave state 0 @ NNN speed 0 cur delta VERY-LARGE-DELTA avg delta 1800
501  * DEBUG::Slave: silent motion
502  * DEBUG::Transport: realtime stop @ NNN
503  * DEBUG::Transport: Butler transport work, todo = PostTransportStop,PostTransportLocate,PostTransportClearSubstate
504  *
505  * [engine skips frames to locate, jack time keeps rolling on]
506  *
507  * the second cycle:
508  *
509  * DEBUG::LTC: [re-]init Engine DLL
510  * DEBUG::Slave: slave stopped, move to NNN+
511  * ...
512  *
513  * we need to seek two cycles ahead: 2 * nframes
514  */
515  if (engine_dll_initstate == 0) {
516  DEBUG_TRACE (DEBUG::LTC, "engine DLL not initialized. ltc_speed\n");
517  speed = 0;
518  pos = last_ltc_frame + rint(ltc_speed * double(2 * nframes + now - last_timestamp));
519  return true;
520  }
521 
522  /* interpolate position according to speed and time since last LTC-frame*/
523  double speed_flt = ltc_speed;
524  double elapsed = (now - last_timestamp) * speed_flt;
525 
526  if (!engine_init_called) {
527  const double e = elapsed + double (last_ltc_frame - sess_pos);
528  t0 = t1;
529  t1 += b * e + e2;
530  e2 += c * e;
531  speed_flt = (t1 - t0) / double(session.engine().samples_per_cycle());
532  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, speed_flt, e2 - session.engine().samples_per_cycle() ));
533  } else {
534  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC adjusting elapsed (no DLL) from %1 by %2\n", elapsed, (2 * nframes * ltc_speed)));
535  speed_flt = 0;
536  elapsed += 2.0 * nframes * ltc_speed; /* see note above */
537  }
538 
539  pos = last_ltc_frame + rint(elapsed);
540  speed = speed_flt;
541  current_delta = (pos - sess_pos);
542 
543  if (((pos < 0) || (labs(current_delta) > 2 * session.frame_rate()))) {
544  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC large drift: %1\n", current_delta));
545  reset();
546  speed = 0;
547  pos = session.transport_frame();
548  return true;
549  }
550 
551  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n",
552  speed, pos, last_ltc_frame, elapsed, current_delta));
553 
554  /* provide a .1% deadzone to lock the speed */
555  if (fabs(speed - 1.0) <= 0.001) {
556  speed = 1.0;
557  }
558 
559  if (speed != 0 && delayedlocked == 0 && fabsf(speed) != 1.0) {
560  sync_lock_broken = true;
561  DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed not locked %1 %2\n", speed, ltc_speed));
562  }
563 
564  return true;
565 }
566 
567 Timecode::TimecodeFormat
569 {
570  if (timecode.rate == 24 && !timecode.drop)
571  return timecode_24;
572  else if (timecode.rate == 25 && !timecode.drop)
573  return timecode_25;
574  else if (rint(timecode.rate * 100) == 2997 && !timecode.drop)
575  return (Config->get_timecode_source_2997() ? timecode_2997000 : timecode_2997);
576  else if (rint(timecode.rate * 100) == 2997 && timecode.drop)
577  return (Config->get_timecode_source_2997() ? timecode_2997000drop : timecode_2997drop);
578  else if (timecode.rate == 30 && timecode.drop)
579  return timecode_2997drop; // timecode_30drop; // LTC counting to 30 frames w/DF *means* 29.97 df
580  else if (timecode.rate == 30 && !timecode.drop)
581  return timecode_30;
582 
583  /* XXX - unknown timecode format */
584  return session.config.get_timecode_format();
585 }
586 
587 std::string
589 {
590  if (last_timestamp == 0) {
591  return " --:--:--:--";
592  }
593  return Timecode::timecode_format_time(timecode);
594 }
595 
596 std::string
598 {
599  char delta[80];
600  if (last_timestamp == 0 || engine_dll_initstate == 0) {
601  snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
602  } else if ((monotonic_cnt - last_timestamp) > 2 * frames_per_ltc_frame) {
603  snprintf(delta, sizeof(delta), "%s", _("flywheel"));
604  } else {
605  snprintf(delta, sizeof(delta), "\u0394<span foreground=\"%s\" face=\"monospace\" >%s%s%lld</span>sm",
606  sync_lock_broken ? "red" : "green",
608  }
609  return std::string(delta);
610 }
double t1
calculated end of the MTC quater frame
Definition: slave.h:403
bool timecode_negative_offset
Definition: slave.h:252
double timecode_frames_per_second() const
Definition: session_time.cc:55
LIBPBD_API const char * pthread_name()
void process_ltc(framepos_t const)
Definition: ltc_slave.cc:301
framecnt_t last_ltc_frame
Definition: slave.h:383
bool equal_ltc_frame_time(LTCFrame *a, LTCFrame *b)
Definition: ltc_slave.cc:177
bool printed_timecode_warning
Definition: slave.h:390
#define LEADINGZERO(A)
Definition: slave.h:41
LTCFrameExt prev_frame
Definition: slave.h:378
bool locked() const
Definition: ltc_slave.cc:112
framecnt_t worst_playback_latency() const
Definition: session.h:397
double ltc_speed
Definition: slave.h:384
pframes_t samples_per_cycle() const
Definition: audioengine.cc:983
int engine_dll_initstate
Definition: slave.h:401
std::string approximate_current_delta() const
Definition: ltc_slave.cc:597
frameoffset_t current_delta
Definition: slave.h:385
PBD::ScopedConnection config_connection
Definition: slave.h:396
void get_connected_latency_range(LatencyRange &range, bool playback) const
Definition: port.cc:375
uint32_t pframes_t
Definition: types.h:61
Definition: Beats.hpp:239
LIBPBD_API Transmitter warning
Session & session
Definition: slave.h:371
virtual void * get_buffer(PortHandle, pframes_t)=0
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
SessionConfiguration config
Definition: session.h:866
PortEngine::PortHandle port_handle()
Definition: port.h:101
static AudioEngine * instance()
Definition: audioengine.h:196
framecnt_t frame_rate() const
Definition: session.h:365
#define FLYWHEEL_TIMEOUT
Definition: ltc_slave.cc:42
PortEngine & port_engine()
PBD::Signal0< void > GraphReordered
Definition: port_manager.h:126
framecnt_t monotonic_cnt
Definition: slave.h:381
framepos_t timecode_offset
Definition: slave.h:251
double frames_per_timecode_frame() const
Definition: session.h:370
#define _(Text)
Definition: i18n.h:11
int transport_direction
Definition: slave.h:400
std::string approximate_current_position() const
Definition: ltc_slave.cc:588
bool timecode_drop_frames() const
Definition: session_time.cc:61
bool detect_ltc_fps(int, bool)
Definition: ltc_slave.cc:219
int64_t framecnt_t
Definition: types.h:76
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
double c
DLL filter coefficients.
Definition: slave.h:405
float Sample
Definition: types.h:54
LatencyRange ltc_slave_latency
Definition: slave.h:397
void parse_ltc(const pframes_t, const Sample *const, const framecnt_t)
Definition: ltc_slave.cc:157
boost::shared_ptr< IO > ltc_output_io()
Definition: session.h:961
PBD::Signal1< void, framepos_t > Xrun
Definition: session.h:311
#define PLUSMINUS(A)
Definition: slave.h:40
double t0
time at the beginning of the MTC quater frame
Definition: slave.h:402
framecnt_t resolution() const
Definition: ltc_slave.cc:106
LTCDecoder * decoder
Definition: slave.h:375
void resync_latency()
Definition: ltc_slave.cc:132
framepos_t transport_frame() const
Definition: session.h:551
Definition: amp.h:29
double e2
second order loop error
Definition: slave.h:404
bool deletion_in_progress() const
Definition: session.h:179
bool sync_lock_broken
Definition: slave.h:391
void init_engine_dll(framepos_t, int32_t)
Definition: ltc_slave.cc:409
framepos_t sample_time_at_cycle_start()
framecnt_t last_timestamp
Definition: slave.h:382
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
int64_t framepos_t
Definition: types.h:66
int delayedlocked
Definition: slave.h:386
int64_t frameoffset_t
Definition: types.h:71
void parse_timecode_offset()
Definition: ltc_slave.cc:86
PBD::Signal1< void, std::string > ParameterChanged
Definition: configuration.h:44
Timecode::TimecodeFormat a3e_timecode
Definition: slave.h:393
int ltc_detect_fps_cnt
Definition: slave.h:388
bool speed_and_position(double &, framepos_t &)
Definition: ltc_slave.cc:426
Timecode::Time timecode
Definition: slave.h:377
Timecode::TimecodeFormat apparent_timecode_format() const
Definition: ltc_slave.cc:568
Timecode::TimecodeFormat ltc_timecode
Definition: slave.h:392
bool did_reset_tc_format
Definition: slave.h:372
int ltc_detect_fps_max
Definition: slave.h:389
void timecode_to_sample(Timecode::Time &timecode, framepos_t &sample, bool use_offset, bool use_subframes) const
void parameter_changed(std::string const &p)
Definition: ltc_slave.cc:96
Definition: debug.h:30
bool fps_detected
Definition: slave.h:379
PBD::ScopedConnectionList port_connections
Definition: slave.h:395
bool detect_discontinuity(LTCFrameExt *, int, bool)
Definition: ltc_slave.cc:194
uint32_t max
Definition: types.h:623
double frames_per_ltc_frame
Definition: slave.h:376
LIBARDOUR_API uint64_t LTC
Definition: debug.cc:40
Timecode::TimecodeFormat saved_tc_format
Definition: slave.h:373
bool ok() const
Definition: ltc_slave.cc:118
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
boost::shared_ptr< Port > ltc_input_port() const
Definition: session.cc:5538