//#define LTC_GEN_FRAMEDBUG
//#define LTC_GEN_TXDBUG
+#ifndef MAX
+#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
+#endif
+#ifndef MIN
+#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
+#endif
+
+/* LTC signal should have a rise time of 25 us +/- 5 us.
+ * yet with most sound-cards a square-wave of 1-2 sample
+ * introduces rather some ringing and small oscillations.
+ * so we low-pass filter the signal a bit, depending
+ * on the sample-rate.
+ *
+ * TODO: this should become an adaptive value, when
+ * the playback speed is increases so that 1 bit < 3-4
+ * audio samples, we should fall back to 25 us.
+ */
+#define LTC_RISE_TIME MIN (100, MAX(25, (2000000 / engine().frame_rate())))
+
void
Session::ltc_tx_initialize()
{
0);
ltc_encoder_set_bufsize(ltc_encoder, nominal_frame_rate(), 23.0);
+ ltc_encoder_set_filter(ltc_encoder, LTC_RISE_TIME);
/* buffersize for 1 LTC frame: (1 + sample-rate / fps) bytes
* usually returned by ltc_encoder_get_buffersize(encoder)
/* range from libltc (38..218) || - 128.0 -> (-90..90) */
const float ltcvol = Config->get_ltc_output_volume()/(90.0); // pow(10, db/20.0)/(90.0);
-#if 1
- /* TODO read layency only on demand -> ::ltc_tx_reset()
- * this is already prepared.
- *
- * ..but first fix jack2 issue with re-computing latency
- * in the correct order. Until then, querying it in the
- * process-callback is the only way to get the current value
- *
- * update: fix for this issue is known -- common/JackEngine.cpp
- * but not yet applied to jack2 git.
- */
- ltcport->get_connected_latency_range(ltc_out_latency, true);
-#endif
DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX %1 to %2 / %3 | lat: %4\n", start_frame, end_frame, nframes, ltc_out_latency.max));
/* all systems go. Now here's the plan:
ltc_tx_cleanup();
return;
}
+ if (nominal_frame_rate() <= 48000) {
+ ltc_encoder_set_filter(ltc_encoder, LTC_RISE_TIME);
+ }
ltc_enc_tcformat = cur_timecode;
ltc_tx_reset();
}
#define SIGNUM(a) ( (a) < 0 ? -1 : 1)
bool speed_changed = false;
- /* use port latency compensation */
-#if 1
- /* The generated timecode is offset by the port-latency,
+ /* port latency compensation:
+ * The _generated timecode_ is offset by the port-latency,
* therefore the offset depends on the direction of transport.
*/
- framepos_t cycle_start_frame = (current_speed < 0) ? (start_frame + ltc_out_latency.max) : (start_frame - ltc_out_latency.max);
-#else
- /* This comes in handy when testing sync - record output on an A3 track
- * see also http://tracker.ardour.org/view.php?id=5073
- */
- framepos_t cycle_start_frame = start_frame;
-#endif
+ framepos_t cycle_start_frame = (current_speed < 0) ? (start_frame - ltc_out_latency.max) : (start_frame + ltc_out_latency.max);
/* cycle-start may become negative due to latency compensation */
if (cycle_start_frame < 0) { cycle_start_frame = 0; }
DEBUG_TRACE (DEBUG::LTC, string_compose("LTC TX5 restart @ %1 + %2 - %3 | byte %4\n",
ltc_enc_pos, ltc_enc_cnt, cyc_off, ltc_enc_byte));
}
+#if 1 /* experimental sample bit alignment */
+ else if (ltc_speed != 0 && (fptcf / ltc_speed / 80) > 3 ) {
+ /* We may get away without a DLL if speed-changes are uniform enough and
+ * no oscillation takes place, the linear approx here should reduce the
+ * jitter sufficiently when generating LTC from another LTC source or
+ * JACK-transport or ardour internal clock.
+ *
+ * Note that the granularity of the LTC encoder speed is 1 byte =
+ * (frames-per-timecode-frame / 10) audio-samples.
+ *
+ * Thus, tiny speed changes won't have any effect and larger ones
+ * may lead to oscillations.
+ * To be better than that, resampling (or a rewrite of the encoder) is
+ * required.
+ */
+ ltc_speed -= ((ltc_enc_pos + ltc_enc_cnt - poff) - cycle_start_frame) / engine().frame_rate();
+ }
+#endif
// (6) encode and output
ltc_enc_byte = (ltc_enc_byte + 1)%10;
if (ltc_enc_byte == 0 && ltc_speed != 0) {
ltc_encoder_inc_timecode(ltc_encoder);
+#if 0 /* force fixed parity -- scope debug */
+ LTCFrame f;
+ ltc_encoder_get_frame(ltc_encoder, &f);
+ f.biphase_mark_phase_correction=0;
+ ltc_encoder_set_frame(ltc_encoder, &f);
+#endif
ltc_tx_recalculate_position();
ltc_enc_cnt = 0;
} else if (ltc_enc_byte == 0) {