/* libltc - en+decode linear timecode Copyright (C) 2006-2015 Robin Gareus This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include #include #include "ltc/ltc.h" #include "ltc/decoder.h" #include "ltc/encoder.h" /* -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * Decoder */ LTCDecoder* ltc_decoder_create(int apv, int queue_len) { LTCDecoder* d = (LTCDecoder*) calloc(1, sizeof(LTCDecoder)); if (!d) return NULL; d->queue_len = queue_len; d->queue = (LTCFrameExt*) calloc(d->queue_len, sizeof(LTCFrameExt)); if (!d->queue) { free(d); return NULL; } d->biphase_state = 1; d->snd_to_biphase_period = apv / 80; d->snd_to_biphase_lmt = (d->snd_to_biphase_period * 3) / 4; d->snd_to_biphase_min = SAMPLE_CENTER; d->snd_to_biphase_max = SAMPLE_CENTER; d->frame_start_prev = -1; d->biphase_tic = 0; return d; } int ltc_decoder_free(LTCDecoder *d) { if (!d) return 1; if (d->queue) free(d->queue); free(d); return 0; } void ltc_decoder_write(LTCDecoder *d, ltcsnd_sample_t *buf, size_t size, ltc_off_t posinfo) { decode_ltc(d, buf, size, posinfo); } #define LTC_CONVERSION_BUF_SIZE 1024 #define LTCWRITE_TEMPLATE(FN, FORMAT, CONV) \ void ltc_decoder_write_ ## FN (LTCDecoder *d, FORMAT *buf, size_t size, ltc_off_t posinfo) { \ ltcsnd_sample_t tmp[LTC_CONVERSION_BUF_SIZE]; \ size_t copyStart = 0; \ while (copyStart < size) { \ int i; \ int c = size - copyStart; \ c = (c > LTC_CONVERSION_BUF_SIZE) ? LTC_CONVERSION_BUF_SIZE : c; \ for (i=0; i < c; i++) { \ tmp[i] = CONV; \ } \ decode_ltc(d, tmp, c, posinfo + (ltc_off_t)copyStart); \ copyStart += c; \ } \ } LTCWRITE_TEMPLATE(float, float, 128 + (buf[copyStart+i] * 127.0)) /* this relies on the compiler to use an arithemtic right-shift for signed values */ LTCWRITE_TEMPLATE(s16, short, 128 + (buf[copyStart+i] >> 8)) /* this relies on the compiler to use a logical right-shift for unsigned values */ LTCWRITE_TEMPLATE(u16, unsigned short, (buf[copyStart+i] >> 8)) #undef LTC_CONVERSION_BUF_SIZE int ltc_decoder_read(LTCDecoder* d, LTCFrameExt* frame) { if (!frame) return -1; if (d->queue_read_off != d->queue_write_off) { memcpy(frame, &d->queue[d->queue_read_off], sizeof(LTCFrameExt)); d->queue_read_off++; if (d->queue_read_off == d->queue_len) d->queue_read_off = 0; return 1; } return 0; } void ltc_decoder_queue_flush(LTCDecoder* d) { while (d->queue_read_off != d->queue_write_off) { d->queue_read_off++; if (d->queue_read_off == d->queue_len) d->queue_read_off = 0; } } int ltc_decoder_queue_length(LTCDecoder* d) { return (d->queue_write_off - d->queue_read_off + d->queue_len) % d->queue_len; } /* -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * Encoder */ LTCEncoder* ltc_encoder_create(double sample_rate, double fps, enum LTC_TV_STANDARD standard, int flags) { if (sample_rate < 1) return NULL; LTCEncoder* e = (LTCEncoder*) calloc(1, sizeof(LTCEncoder)); if (!e) return NULL; /*-3.0 dBFS default */ e->enc_lo = 38; e->enc_hi = 218; e->bufsize = 1 + ceil(sample_rate / fps); e->buf = (ltcsnd_sample_t*) calloc(e->bufsize, sizeof(ltcsnd_sample_t)); if (!e->buf) { free(e); return NULL; } ltc_frame_reset(&e->f); ltc_encoder_reinit(e, sample_rate, fps, standard, flags); return e; } void ltc_encoder_free(LTCEncoder *e) { if (!e) return; if (e->buf) free(e->buf); free(e); } int ltc_encoder_reinit(LTCEncoder *e, double sample_rate, double fps, enum LTC_TV_STANDARD standard, int flags) { if (sample_rate < 1) return -1; size_t bufsize = 1 + ceil(sample_rate / fps); if (bufsize > e->bufsize) { return -1; } e->state = 0; e->offset = 0; e->sample_rate = sample_rate; ltc_encoder_set_filter(e, 40.0); e->fps = fps; e->flags = flags; e->standard = standard; e->samples_per_clock = sample_rate / (fps * 80.0); e->samples_per_clock_2 = e->samples_per_clock / 2.0; e->sample_remainder = 0.5; if (flags & LTC_BGF_DONT_TOUCH) { e->f.col_frame = 0; if (flags<C_TC_CLOCK) { e->f.binary_group_flag_bit1 = 1; } else { e->f.binary_group_flag_bit1 = 0; } switch (standard) { case LTC_TV_625_50: /* 25 fps mode */ e->f.biphase_mark_phase_correction = 0; // BGF0 e->f.binary_group_flag_bit0 = (flags<C_USE_DATE)?1:0; // BGF2 break; default: e->f.binary_group_flag_bit0 = 0; e->f.binary_group_flag_bit2 = (flags<C_USE_DATE)?1:0; break; } } if ((flags<C_NO_PARITY) == 0) { ltc_frame_set_parity(&e->f, standard); } if ((int)rint(fps * 100.0) == 2997) e->f.dfbit = 1; else e->f.dfbit = 0; return 0; } void ltc_encoder_reset(LTCEncoder *e) { e->state = 0; e->sample_remainder = 0.5; e->offset = 0; } int ltc_encoder_set_volume(LTCEncoder *e, double dBFS) { if (dBFS > 0) return -1; double pp = rint(127.0 * pow(10, dBFS/20.0)); if (pp < 1 || pp > 127) return -1; ltcsnd_sample_t diff = ((ltcsnd_sample_t) pp)&0x7f; e->enc_lo = SAMPLE_CENTER - diff; e->enc_hi = SAMPLE_CENTER + diff; return 0; } void ltc_encoder_set_filter(LTCEncoder *e, double rise_time) { /* low-pass-filter * LTC signal should have a rise time of 40 us +/- 10 us. * * rise-time means from <10% to >90% of the signal. * in each call to addvalues() we start at 50% (SAMPLE_CENTER), so * here we need half-of it. */ if (rise_time <= 0) e->filter_const = 0; else e->filter_const = 1.0 - exp( -1.0 / (e->sample_rate * rise_time / 2000000.0 / exp(1.0)) ); } int ltc_encoder_set_bufsize(LTCEncoder *e, double sample_rate, double fps) { free (e->buf); e->offset = 0; e->bufsize = 1 + ceil(sample_rate / fps); e->buf = (ltcsnd_sample_t*) calloc(e->bufsize, sizeof(ltcsnd_sample_t)); if (!e->buf) { return -1; } return 0; } int ltc_encoder_encode_byte(LTCEncoder *e, int byte, double speed) { return encode_byte(e, byte, speed); } void ltc_encoder_encode_frame(LTCEncoder *e) { int byte; for (byte = 0 ; byte < 10 ; byte++) { encode_byte(e, byte, 1.0); } } void ltc_encoder_get_timecode(LTCEncoder *e, SMPTETimecode *t) { ltc_frame_to_time(t, &e->f, e->flags); } void ltc_encoder_set_timecode(LTCEncoder *e, SMPTETimecode *t) { ltc_time_to_frame(&e->f, t, e->standard, e->flags); } void ltc_encoder_get_frame(LTCEncoder *e, LTCFrame *f) { memcpy(f, &e->f, sizeof(LTCFrame)); } void ltc_encoder_set_frame(LTCEncoder *e, LTCFrame *f) { memcpy(&e->f, f, sizeof(LTCFrame)); } int ltc_encoder_inc_timecode(LTCEncoder *e) { return ltc_frame_increment (&e->f, rint(e->fps), e->standard, e->flags); } int ltc_encoder_dec_timecode(LTCEncoder *e) { return ltc_frame_decrement (&e->f, rint(e->fps), e->standard, e->flags); } size_t ltc_encoder_get_buffersize(LTCEncoder *e) { return(e->bufsize); } void ltc_encoder_buffer_flush(LTCEncoder *e) { e->offset = 0; } ltcsnd_sample_t *ltc_encoder_get_bufptr(LTCEncoder *e, int *size, int flush) { if (size) *size = e->offset; if (flush) e->offset = 0; return e->buf; } int ltc_encoder_get_buffer(LTCEncoder *e, ltcsnd_sample_t *buf) { const int len = e->offset; memcpy(buf, e->buf, len * sizeof(ltcsnd_sample_t) ); e->offset = 0; return(len); } void ltc_frame_set_parity(LTCFrame *frame, enum LTC_TV_STANDARD standard) { int i; unsigned char p = 0; if (standard != LTC_TV_625_50) { /* 30fps, 24fps */ frame->biphase_mark_phase_correction = 0; } else { /* 25fps */ frame->binary_group_flag_bit2 = 0; } for (i=0; i < LTC_FRAME_BIT_COUNT / 8; ++i){ p = p ^ (((unsigned char*)frame)[i]); } #define PRY(BIT) ((p>>BIT)&1) if (standard != LTC_TV_625_50) { /* 30fps, 24fps */ frame->biphase_mark_phase_correction = PRY(0)^PRY(1)^PRY(2)^PRY(3)^PRY(4)^PRY(5)^PRY(6)^PRY(7); } else { /* 25fps */ frame->binary_group_flag_bit2 = PRY(0)^PRY(1)^PRY(2)^PRY(3)^PRY(4)^PRY(5)^PRY(6)^PRY(7); } } ltc_off_t ltc_frame_alignment(double samples_per_frame, enum LTC_TV_STANDARD standard) { switch (standard) { case LTC_TV_525_60: return rint(samples_per_frame * 4.0 / 525.0); case LTC_TV_625_50: return rint(samples_per_frame * 1.0 / 625.0); default: return 0; } }