Please consider a donation to the Higher Intellect project. See https://preterhuman.net/donate.php or the Donate to Higher Intellect page for more info. |
Ltc.c
Jump to navigation
Jump to search
/* * ltc.c - example of using dmLTC * * compile with -ldmedia and -laudio * * parses and prints out LTC codewords from audio input. * * works with sampling rates 22k and above, may work less than * that too. */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdarg.h> #include <string.h> #include <sys/fcntl.h> #include <unistd.h> #include <sys/uio.h> #include <dmedia/audio.h> #include <dmedia/dmedia.h> #include <sys/dmcommon.h> #include <dmedia/dm_params.h> #include <dmedia/dm_timecode.h> #include <dmedia/dm_audio.h> #include <dmedia/dm_ltc.h> /* Utility Routines ---------------------------------------------------- */ void error_exit(char *format, ...) { va_list ap; va_start(ap, format); vfprintf( stdout, format, ap ); va_end(ap); fprintf( stdout, "\n" ); exit(2); } void error(char *format, ...) { va_list ap; va_start(ap, format); vfprintf( stdout, format, ap ); va_end(ap); fprintf( stdout, "\n" ); } void print_tc_type_name(int tc_type) { switch (tc_type & DM_TC_FORMAT_MASK) { case DM_TC_FORMAT_NTSC: printf("NTSC "); break; case DM_TC_FORMAT_PAL: printf("PAL "); break; case DM_TC_FORMAT_FILM: printf("FILM "); break; } if ((tc_type & DM_TC_FORMAT_MASK) == DM_TC_FORMAT_NTSC) { switch (tc_type & DM_TC_DROP_MASK) { case DM_TC_NODROP: printf("non-drop "); break; case DM_TC_DROPFRAME: printf("drop "); break; } } switch (tc_type & DM_TC_RATE_MASK) { case DM_TC_RATE_2997: printf("29.97 frame/sec"); break; case DM_TC_RATE_30: printf("30 frame/sec"); break; case DM_TC_RATE_24: printf("24 frame/sec"); break; case DM_TC_RATE_25: printf("25 frame/sec"); break; } printf(" (0x%x)", tc_type); } /* ** DC -- "DM Params Check". Wraps a call to a dmParams function that ** returns DM_FAILURE on error. */ #define DC(call) \ { \ if ( (call) != DM_SUCCESS ) \ error_exit("DM_FAILURE for call \"%s\"", #call); \ } /* main ------------------------------------------------------------- */ int main(void) { /* * LTC state */ DMLTCdecoder ltcdecoder; int tc_type; /* * AL state */ stamp_t last_frontier_msc; ALconfig config; ALport port; char *intrbuf; /* these describe the currently buffered data */ int nmscs; char *bufptr; int rate; int bytes_per_sample; float qseconds; /* first open audio path */ config = ALnewconfig(); ALsetsampfmt(config, AL_SAMPFMT_TWOSCOMP); ALsetwidth(config, AL_SAMPLE_16); bytes_per_sample = 2; ALsetchannels(config, 1); /* get rate */ { long pvbuf[2]; pvbuf[0] = AL_INPUT_RATE; ALgetparams(AL_DEFAULT_DEVICE, pvbuf, 2); rate = pvbuf[1]; } /* qseconds second queue size */ qseconds = 1.0; ALsetqueuesize(config, qseconds * ALgetchannels(config) * rate); intrbuf = malloc(ALgetqueuesize(config) * bytes_per_sample); printf("Audio sampfmt: TWOSCOMP\n"); printf("Audio width: %d bits\n", ALgetwidth(config) * 8); printf("Audio channels: %d\n", ALgetchannels(config)); printf("Audio rate: %d Hz\n", rate); printf("Audio queuesize: %d samples\n", ALgetqueuesize(config)); if (NULL == (port = ALopenport("ltc", "r", config))) error_exit("AL port open failed"); /* set up ltc decoder */ printf("LTC assuming code is DM_TC_30_ND\n"); tc_type = DM_TC_30_ND; DC( dmLTCDecoderCreate(<cdecoder, tc_type) ); { int width = ALgetwidth(config); int chans = ALgetchannels(config); DMparams *audioparams; DC( dmParamsCreate(&audioparams) ); DC( dmParamsSetInt(audioparams, DM_AUDIO_CHANNELS, chans) ); DC( dmParamsSetEnum(audioparams, DM_AUDIO_FORMAT, DM_AUDIO_TWOS_COMPLEMENT ) ); switch (width) { case AL_SAMPLE_8: DC( dmParamsSetInt(audioparams, DM_AUDIO_WIDTH, DM_AUDIO_WIDTH_8) ); break; case AL_SAMPLE_16: DC( dmParamsSetInt(audioparams, DM_AUDIO_WIDTH, DM_AUDIO_WIDTH_16) ); break; case AL_SAMPLE_24: DC( dmParamsSetInt(audioparams, DM_AUDIO_WIDTH, DM_AUDIO_WIDTH_24) ); break; } /* assumes first channel (0) */ dmLTCDecoderSetParams(ltcdecoder, audioparams, 0); dmParamsDestroy(audioparams); } /* clear out rb */ ALreadsamps(port, intrbuf, ALgetfilled(port)); last_frontier_msc = -1; nmscs = 0; /* no audio intially buffered up */ /* go! */ while (1) { int n; assert(nmscs == 0); /* ---- get a buffer of new audio data */ n = ALgetqueuesize(config); ALreadsamps(port, intrbuf, n); nmscs = n / ALgetchannels(config); bufptr = intrbuf; /* ---- check for overflow (optional but very good to do) */ { stamp_t frontier_msc; if (-1 == ALgetframenumber(port, (unsigned long long *)(&frontier_msc))) error_exit("ALgetframenumber failed."); if (last_frontier_msc != -1 && frontier_msc != last_frontier_msc + nmscs) { error("we dropped %d audio frames of data", frontier_msc - last_frontier_msc + nmscs); } last_frontier_msc = frontier_msc; } /* ---- parse as many codewords as we can from this buffer */ while (1) { DMLTCcode codeword; int nmscs_before, nmscs_eaten; DMstatus ret; if (nmscs == 0) { /* no more data to parse */ break; } nmscs_before = nmscs; /* dmLTCDecode increments pointer and decrements nmscs */ ret = dmLTCDecode(ltcdecoder, (void **)&bufptr, &nmscs, &codeword); nmscs_eaten = nmscs_before - nmscs; assert(nmscs_eaten <= nmscs_before && nmscs_eaten >= 0); if (DM_SUCCESS != ret) { /* consumed all nmscs, found no LTC codeword */ assert(nmscs_eaten == nmscs_before); assert(nmscs == 0); break; } /* got a codeword */ { char tcstring[40]; dmTCToString(tcstring, &codeword.tc); printf("got %s (", tcstring); print_tc_type_name(codeword.tc.tc_type); printf(")\n"); } } } ALcloseport(port); }