diff --git a/libs/xwax/lut.c b/libs/xwax/lut.c index a914272..7ae7733 100644 --- a/libs/xwax/lut.c +++ b/libs/xwax/lut.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Mark Hills + * Copyright (C) 2012 Mark Hills * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,25 +34,25 @@ /* Initialise an empty hash lookup table to store the given number * of timecode -> position lookups */ -int lut_init(struct lut_t *lut, int nslots) +int lut_init(struct lut *lut, int nslots) { int n, hashes; size_t bytes; hashes = 1 << HASH_BITS; - bytes = sizeof(struct slot_t) * nslots + sizeof(slot_no_t) * hashes; + bytes = sizeof(struct slot) * nslots + sizeof(slot_no_t) * hashes; fprintf(stderr, "Lookup table has %d hashes to %d slots" " (%d slots per hash, %zuKb)\n", hashes, nslots, nslots / hashes, bytes / 1024); - lut->slot = (struct slot_t*)malloc(sizeof(struct slot_t) * nslots); + lut->slot = malloc(sizeof(struct slot) * nslots); if (lut->slot == NULL) { perror("malloc"); return -1; } - lut->table = (slot_no_t*)malloc(sizeof(slot_no_t) * hashes); + lut->table = malloc(sizeof(slot_no_t) * hashes); if (lut->table == NULL) { perror("malloc"); return -1; @@ -67,17 +67,18 @@ int lut_init(struct lut_t *lut, int nslots) } -void lut_clear(struct lut_t *lut) +void lut_clear(struct lut *lut) { free(lut->table); + free(lut->slot); } -void lut_push(struct lut_t *lut, unsigned int timecode) +void lut_push(struct lut *lut, unsigned int timecode) { unsigned int hash; slot_no_t slot_no; - struct slot_t *slot; + struct slot *slot; slot_no = lut->avail++; /* take the next available slot */ @@ -90,11 +91,11 @@ void lut_push(struct lut_t *lut, unsigned int timecode) } -unsigned int lut_lookup(struct lut_t *lut, unsigned int timecode) +unsigned int lut_lookup(struct lut *lut, unsigned int timecode) { unsigned int hash; slot_no_t slot_no; - struct slot_t *slot; + struct slot *slot; hash = HASH(timecode); slot_no = lut->table[hash]; diff --git a/libs/xwax/lut.cpp b/libs/xwax/lut.cpp deleted file mode 100644 index a914272..0000000 --- a/libs/xwax/lut.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2010 Mark Hills - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * 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 - * General Public License version 2 for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include -#include - -#include "lut.h" - -/* The number of bits to form the hash, which governs the overall size - * of the hash lookup table, and hence the amount of chaining */ - -#define HASH_BITS 16 - -#define HASH(timecode) ((timecode) & ((1 << HASH_BITS) - 1)) -#define NO_SLOT ((unsigned)-1) - - -/* Initialise an empty hash lookup table to store the given number - * of timecode -> position lookups */ - -int lut_init(struct lut_t *lut, int nslots) -{ - int n, hashes; - size_t bytes; - - hashes = 1 << HASH_BITS; - bytes = sizeof(struct slot_t) * nslots + sizeof(slot_no_t) * hashes; - - fprintf(stderr, "Lookup table has %d hashes to %d slots" - " (%d slots per hash, %zuKb)\n", - hashes, nslots, nslots / hashes, bytes / 1024); - - lut->slot = (struct slot_t*)malloc(sizeof(struct slot_t) * nslots); - if (lut->slot == NULL) { - perror("malloc"); - return -1; - } - - lut->table = (slot_no_t*)malloc(sizeof(slot_no_t) * hashes); - if (lut->table == NULL) { - perror("malloc"); - return -1; - } - - for (n = 0; n < hashes; n++) - lut->table[n] = NO_SLOT; - - lut->avail = 0; - - return 0; -} - - -void lut_clear(struct lut_t *lut) -{ - free(lut->table); -} - - -void lut_push(struct lut_t *lut, unsigned int timecode) -{ - unsigned int hash; - slot_no_t slot_no; - struct slot_t *slot; - - slot_no = lut->avail++; /* take the next available slot */ - - slot = &lut->slot[slot_no]; - slot->timecode = timecode; - - hash = HASH(timecode); - slot->next = lut->table[hash]; - lut->table[hash] = slot_no; -} - - -unsigned int lut_lookup(struct lut_t *lut, unsigned int timecode) -{ - unsigned int hash; - slot_no_t slot_no; - struct slot_t *slot; - - hash = HASH(timecode); - slot_no = lut->table[hash]; - - while (slot_no != NO_SLOT) { - slot = &lut->slot[slot_no]; - if (slot->timecode == timecode) - return slot_no; - slot_no = slot->next; - } - - return (unsigned)-1; -} diff --git a/libs/xwax/lut.h b/libs/xwax/lut.h index 46c4bd3..a156f49 100644 --- a/libs/xwax/lut.h +++ b/libs/xwax/lut.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Mark Hills + * Copyright (C) 2012 Mark Hills * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,21 +22,21 @@ typedef unsigned int slot_no_t; -struct slot_t { +struct slot { unsigned int timecode; slot_no_t next; /* next slot with the same hash */ }; -struct lut_t { - struct slot_t *slot; +struct lut { + struct slot *slot; slot_no_t *table, /* hash -> slot lookup */ avail; /* next available slot */ }; -int lut_init(struct lut_t *lut, int nslots); -void lut_clear(struct lut_t *lut); +int lut_init(struct lut *lut, int nslots); +void lut_clear(struct lut *lut); -void lut_push(struct lut_t *lut, unsigned int timecode); -unsigned int lut_lookup(struct lut_t *lut, unsigned int timecode); +void lut_push(struct lut *lut, unsigned int timecode); +unsigned int lut_lookup(struct lut *lut, unsigned int timecode); #endif diff --git a/libs/xwax/pitch.h b/libs/xwax/pitch.h index 076af71..ab0cad5 100644 --- a/libs/xwax/pitch.h +++ b/libs/xwax/pitch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Mark Hills + * Copyright (C) 2012 Mark Hills * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -23,17 +23,17 @@ /* Values for the filter concluded experimentally */ #define ALPHA (1.0/512) -#define BETA (ALPHA/1024) +#define BETA (ALPHA/256) /* State of the pitch calculation filter */ -struct pitch_t { - float dt, x, v; +struct pitch { + double dt, x, v; }; /* Prepare the filter for observations every dt seconds */ -static inline void pitch_init(struct pitch_t *p, float dt) +static inline void pitch_init(struct pitch *p, double dt) { p->dt = dt; p->x = 0.0; @@ -46,9 +46,9 @@ static inline void pitch_init(struct pitch_t *p, float dt) * Because the vinyl uses timestamps, the values for dx are discrete * rather than smooth. */ -static inline void pitch_dt_observation(struct pitch_t *p, float dx) +static inline void pitch_dt_observation(struct pitch *p, double dx) { - float predicted_x, predicted_v, residual_x; + double predicted_x, predicted_v, residual_x; predicted_x = p->x + p->v * p->dt; predicted_v = p->v; @@ -63,7 +63,7 @@ static inline void pitch_dt_observation(struct pitch_t *p, float dx) /* Get the pitch after filtering */ -static inline float pitch_current(struct pitch_t *p) +static inline double pitch_current(struct pitch *p) { return p->v; } diff --git a/libs/xwax/timecoder.c b/libs/xwax/timecoder.c index 2bf0f2a..2174a7b 100644 --- a/libs/xwax/timecoder.c +++ b/libs/xwax/timecoder.c @@ -1,15 +1,15 @@ /* - * Copyright (C) 2010 Mark Hills + * Copyright (C) 2012 Mark Hills * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2, as published by the Free Software Foundation. - * + * * 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 * General Public License version 2 for more details. - * + * * You should have received a copy of the GNU General Public License * version 2 along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, @@ -31,16 +31,16 @@ #define REF_PEAKS_AVG 48 /* in wave cycles */ -/* The number of correct bits which come in before the timecode - * is declared valid. Set this too low, and risk the record skipping around - * (often to blank areas of track) during scratching */ +/* The number of correct bits which come in before the timecode is + * declared valid. Set this too low, and risk the record skipping + * around (often to blank areas of track) during scratching */ #define VALID_BITS 24 #define MONITOR_DECAY_EVERY 512 /* in samples */ #define SQ(x) ((x)*(x)) - +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) /* Timecode definitions */ @@ -48,8 +48,7 @@ #define SWITCH_PRIMARY 0x2 /* use left channel (not right) as primary */ #define SWITCH_POLARITY 0x4 /* read bit values in negative (not positive) */ - -static struct timecode_def_t timecode_def[] = { +static struct timecode_def timecodes[] = { { .name = "serato_2a", .desc = "Serato 2nd Ed., side A", @@ -59,7 +58,7 @@ static struct timecode_def_t timecode_def[] = { .seed = 0x59017, .taps = 0x361e4, .length = 712000, - .safe = 625000, + .safe = 707000, .lookup = false }, { @@ -71,7 +70,7 @@ static struct timecode_def_t timecode_def[] = { .seed = 0x8f3c6, .taps = 0x4f0d8, /* reverse of side A */ .length = 922000, - .safe = 905000, + .safe = 917000, .lookup = false }, { @@ -83,7 +82,7 @@ static struct timecode_def_t timecode_def[] = { .seed = 0xd8b40, .taps = 0x34d54, .length = 950000, - .safe = 890000, + .safe = 940000, .lookup = false }, { @@ -95,8 +94,8 @@ static struct timecode_def_t timecode_def[] = { .seed = 0x134503, .taps = 0x041040, .length = 1500000, - .safe = 1214000, - .lookup = false + .safe = 1480000, + .lookup = false }, { .name = "traktor_b", @@ -107,7 +106,7 @@ static struct timecode_def_t timecode_def[] = { .seed = 0x32066c, .taps = 0x041040, /* same as side A */ .length = 2110000, - .safe = 1814000, + .safe = 2090000, .lookup = false }, { @@ -134,361 +133,443 @@ static struct timecode_def_t timecode_def[] = { .safe = 310000, .lookup = false }, - { - .name = NULL - } }; - -/* Linear Feeback Shift Register in the forward direction. New values - * are generated at the least-significant bit. */ +/* + * Calculate LFSR bit + */ static inline bits_t lfsr(bits_t code, bits_t taps) { bits_t taken; int xrs; - + taken = code & taps; xrs = 0; while (taken != 0x0) { xrs += taken & 0x1; taken >>= 1; } - + return xrs & 0x1; } +/* + * Linear Feedback Shift Register in the forward direction. New values + * are generated at the least-significant bit. + */ -static inline bits_t fwd(bits_t current, struct timecode_def_t *def) +static inline bits_t fwd(bits_t current, struct timecode_def *def) { bits_t l; - + /* New bits are added at the MSB; shift right by one */ - + l = lfsr(current, def->taps | 0x1); return (current >> 1) | (l << (def->bits - 1)); } +/* + * Linear Feedback Shift Register in the reverse direction + */ -static inline bits_t rev(bits_t current, struct timecode_def_t *def) +static inline bits_t rev(bits_t current, struct timecode_def *def) { bits_t l, mask; - + /* New bits are added at the LSB; shift left one and mask */ - + mask = (1 << def->bits) - 1; l = lfsr(current, (def->taps >> 1) | (0x1 << (def->bits - 1))); return ((current << 1) & mask) | l; } +/* + * Where necessary, build the lookup table required for this timecode + * + * Return: -1 if not enough memory could be allocated, otherwise 0 + */ -static struct timecode_def_t* find_definition(const char *name) -{ - struct timecode_def_t *def; - - def = &timecode_def[0]; - while (def->name) { - if (!strcmp(def->name, name)) - return def; - def++; - } - return NULL; -} - - -/* Where necessary, build the lookup table required for this timecode */ - -static int build_lookup(struct timecode_def_t *def) +static int build_lookup(struct timecode_def *def) { unsigned int n; bits_t current, last; - + if (def->lookup) return 0; - + fprintf(stderr, "Building LUT for %d bit %dHz timecode (%s)\n", def->bits, def->resolution, def->desc); - + if (lut_init(&def->lut, def->length) == -1) - return -1; - + return -1; + current = def->seed; for (n = 0; n < def->length; n++) { /* timecode must not wrap */ - assert(lut_lookup(&def->lut, current) == (unsigned)-1); - lut_push(&def->lut, current); - last = current; - current = fwd(current, def); - assert(rev(current, def) == last); + if(lut_lookup(&def->lut, current) == (unsigned)-1){ + + lut_push(&def->lut, current); + last = current; + current = fwd(current, def); + if(rev(current, def) == last){ + + } + } } - + def->lookup = true; - return 0; + return 0; } +/* + * Find a timecode definition by name + * + * Return: pointer to timecode definition, or NULL if not found + */ -/* Free the timecoder lookup tables when they are no longer needed */ +struct timecode_def* timecoder_find_definition(const char *name) +{ + struct timecode_def *def, *end; + + def = &timecodes[0]; + end = def + ARRAY_SIZE(timecodes); + + for (;;) { + if (!strcmp(def->name, name)) + break; + + def++; + + if (def == end) + return NULL; + } + + if (build_lookup(def) == -1) + return NULL; + + return def; +} -void timecoder_free_lookup(void) { - struct timecode_def_t *def; +/* + * Free the timecoder lookup tables when they are no longer needed + */ - def = &timecode_def[0]; - while (def->name) { +void timecoder_free_lookup(void) { + struct timecode_def *def, *end; + + def = &timecodes[0]; + end = def + ARRAY_SIZE(timecodes); + + while (def < end) { if (def->lookup) lut_clear(&def->lut); def++; } } +/* + * Initialise filter values for one channel + */ -static void init_channel(struct timecoder_channel_t *ch) +static void init_channel(struct timecoder_channel *ch) { - ch->positive = 0; + ch->positive = false; ch->zero = 0; } +/* + * Initialise a timecode decoder at the given reference speed + * + * Return: -1 if the timecoder could not be initialised, otherwise 0 + */ -/* Initialise a timecode decoder at the given reference speed */ - -int timecoder_init(struct timecoder_t *tc, const char *def_name, double speed, - unsigned int sample_rate) +void timecoder_init(struct timecoder *tc, struct timecode_def *def, + double speed, unsigned int sample_rate) { - /* A definition contains a lookup table which can be shared - * across multiple timecoders */ - - tc->def = find_definition(def_name); - if (tc->def == NULL) { - fprintf(stderr, "Timecode definition '%s' is not known.\n", def_name); - return -1; + if(def != NULL){ + + /* A definition contains a lookup table which can be shared + * across multiple timecoders */ + + if(def->lookup){ + tc->def = def; + tc->speed = speed; + + tc->dt = 1.0 / sample_rate; + tc->zero_alpha = tc->dt / (ZERO_RC + tc->dt); + + tc->forwards = 1; + init_channel(&tc->primary); + init_channel(&tc->secondary); + pitch_init(&tc->pitch, tc->dt); + + tc->ref_level = 32768.0; + tc->bitstream = 0; + tc->timecode = 0; + tc->valid_counter = 0; + tc->timecode_ticker = 0; + + tc->mon = NULL; + } } - if (build_lookup(tc->def) == -1) - return -1; - tc->speed = speed; - - tc->dt = 1.0 / sample_rate; - tc->zero_alpha = tc->dt / (ZERO_RC + tc->dt); - - tc->forwards = 1; - init_channel(&tc->primary); - init_channel(&tc->secondary); - pitch_init(&tc->pitch, tc->dt); - - tc->ref_level = 32768.0; - tc->bitstream = 0; - tc->timecode = 0; - tc->valid_counter = 0; - tc->timecode_ticker = 0; - - tc->mon = NULL; - - return 0; } +/* + * Clear resources associated with a timecode decoder + */ -/* Clear a timecode decoder */ - -void timecoder_clear(struct timecoder_t *tc) +void timecoder_clear(struct timecoder *tc) { timecoder_monitor_clear(tc); } +/* + * Initialise a raster display of the incoming audio + * + * The monitor (otherwise known as 'scope' in the interface) is an x-y + * display of the post-calibrated incoming audio. + * + * Return: -1 if not enough memory could be allocated, otherwise 0 + */ -/* The monitor (otherwise known as 'scope' in the interface) is the - * display of the incoming audio. Initialise one for the given - * timecoder */ - -int timecoder_monitor_init(struct timecoder_t *tc, int size) +int timecoder_monitor_init(struct timecoder *tc, int size) { - tc->mon_size = size; - tc->mon = malloc(SQ(tc->mon_size)); - if (tc->mon == NULL) { - perror("malloc"); - return -1; + if(tc->mon == NULL){ + tc->mon_size = size; + tc->mon = malloc(SQ(tc->mon_size)); + if (tc->mon == NULL) { + perror("malloc"); + return -1; + } + memset(tc->mon, 0, SQ(tc->mon_size)); + tc->mon_counter = 0; } - memset(tc->mon, 0, SQ(tc->mon_size)); - tc->mon_counter = 0; return 0; } +/* + * Clear the monitor on the given timecoder + */ -/* Clear the monitor on the given timecoder */ - -void timecoder_monitor_clear(struct timecoder_t *tc) +void timecoder_monitor_clear(struct timecoder *tc) { - if (tc->mon) { + if(tc->mon != NULL){ free(tc->mon); tc->mon = NULL; } } +/* + * Update channel information with axis-crossings + */ -static void detect_zero_crossing(struct timecoder_channel_t *ch, - signed int v, float alpha) +static void detect_zero_crossing(struct timecoder_channel *ch, + signed int v, double alpha) { ch->crossing_ticker++; - - ch->swapped = 0; + + ch->swapped = false; if (v > ch->zero + ZERO_THRESHOLD && !ch->positive) { - ch->swapped = 1; - ch->positive = 1; + ch->swapped = true; + ch->positive = true; ch->crossing_ticker = 0; } else if (v < ch->zero - ZERO_THRESHOLD && ch->positive) { - ch->swapped = 1; - ch->positive = 0; + ch->swapped = true; + ch->positive = false; ch->crossing_ticker = 0; } ch->zero += alpha * (v - ch->zero); } +/* + * Plot the given sample value in the x-y monitor + */ -/* Plot the given sample value in the monitor (scope) */ - -static void update_monitor(struct timecoder_t *tc, signed int x, signed int y) +static void update_monitor(struct timecoder *tc, signed int x, signed int y) { int px, py, p; - float v, w; - + double v, w; + if (!tc->mon) return; - + /* Decay the pixels already in the montior */ - + if (++tc->mon_counter % MONITOR_DECAY_EVERY == 0) { for (p = 0; p < SQ(tc->mon_size); p++) { - if (tc->mon[p]) + if (tc->mon[p]){ tc->mon[p] = tc->mon[p] * 7 / 8; + } } } - - v = (float)x / tc->ref_level / 2; - w = (float)y / tc->ref_level / 2; - + + v = (double)x / tc->ref_level / 2; + w = (double)y / tc->ref_level / 2; + px = tc->mon_size / 2 + (v * tc->mon_size / 2); py = tc->mon_size / 2 + (w * tc->mon_size / 2); - + /* Set the pixel value to white */ - + if (px > 0 && px < tc->mon_size && py > 0 && py < tc->mon_size) tc->mon[py * tc->mon_size + px] = 0xff; } +/* + * Extract the bitstream from the sample value + */ -/* Process a single bitstream reading */ - -static void process_bitstream(struct timecoder_t *tc, signed int m) +static void process_bitstream(struct timecoder *tc, signed int m) { bits_t b; - + b = m > tc->ref_level; - + /* Add it to the bitstream, and work out what we were expecting * (timecode). */ - + /* tc->bitstream is always in the order it is physically placed on * the vinyl, regardless of the direction. */ - + if (tc->forwards) { - tc->timecode = fwd(tc->timecode, tc->def); - tc->bitstream = (tc->bitstream >> 1) + tc->timecode = fwd(tc->timecode, tc->def); + tc->bitstream = (tc->bitstream >> 1) + (b << (tc->def->bits - 1)); - + } else { - bits_t mask; - - mask = ((1 << tc->def->bits) - 1); - tc->timecode = rev(tc->timecode, tc->def); - tc->bitstream = ((tc->bitstream << 1) & mask) + b; + bits_t mask; + + mask = ((1 << tc->def->bits) - 1); + tc->timecode = rev(tc->timecode, tc->def); + tc->bitstream = ((tc->bitstream << 1) & mask) + b; } - + if (tc->timecode == tc->bitstream) - tc->valid_counter++; + tc->valid_counter++; else { - tc->timecode = tc->bitstream; - tc->valid_counter = 0; + tc->timecode = tc->bitstream; + tc->valid_counter = 0; } - + /* Take note of the last time we read a valid timecode */ tc->timecode_ticker = 0; - + /* Adjust the reference level based on this new peak */ - + tc->ref_level = (tc->ref_level * (REF_PEAKS_AVG - 1) + m) / REF_PEAKS_AVG; - -#ifdef DEBUG_BITSTREAM - fprintf(stderr, "%+6d zero, %+6d (ref %+6d)\t= %d%c (%5d)\n", - tc->primary.zero, - m, - tc->ref_level, - b, - tc->valid_counter == 0 ? 'x' : ' ', - tc->valid_counter); -#endif + + } +/* + * Process a single sample from the incoming audio + */ -/* Process a single sample from the incoming audio */ - -static void process_sample(struct timecoder_t *tc, - signed int primary, signed int secondary) +static void process_sample(struct timecoder *tc, + signed int primary, signed int secondary) { signed int m; /* pcm sample, sum of two shorts */ - + detect_zero_crossing(&tc->primary, primary, tc->zero_alpha); detect_zero_crossing(&tc->secondary, secondary, tc->zero_alpha); - + m = abs(primary - tc->primary.zero); - + /* If an axis has been crossed, use the direction of the crossing * to work out the direction of the vinyl */ - - if (tc->primary.swapped) { - tc->forwards = (tc->primary.positive != tc->secondary.positive); - if (tc->def->flags & SWITCH_PHASE) - tc->forwards = !tc->forwards; - } if (tc->secondary.swapped) { - tc->forwards = (tc->primary.positive == tc->secondary.positive); - if (tc->def->flags & SWITCH_PHASE) - tc->forwards = !tc->forwards; + + if (tc->primary.swapped || tc->secondary.swapped) { + bool forwards; + + if (tc->primary.swapped) { + forwards = (tc->primary.positive != tc->secondary.positive); + } else { + forwards = (tc->primary.positive == tc->secondary.positive); + } + + if (tc->def->flags & SWITCH_PHASE) + forwards = !forwards; + + if (forwards != tc->forwards) { /* direction has changed */ + tc->forwards = forwards; + tc->valid_counter = 0; + } } - + /* If any axis has been crossed, register movement using the pitch * counters */ - + if (!tc->primary.swapped && !tc->secondary.swapped) - pitch_dt_observation(&tc->pitch, 0.0); + pitch_dt_observation(&tc->pitch, 0.0); else { - float dx; - - dx = 1.0 / tc->def->resolution / 4; - if (!tc->forwards) - dx = -dx; - pitch_dt_observation(&tc->pitch, dx); + double dx; + + dx = 1.0 / tc->def->resolution / 4; + if (!tc->forwards) + dx = -dx; + pitch_dt_observation(&tc->pitch, dx); } - + /* If we have crossed the primary channel in the right polarity, * it's time to read off a timecode 0 or 1 value */ - + if (tc->secondary.swapped && - tc->primary.positive == ((tc->def->flags & SWITCH_POLARITY) == 0)) + tc->primary.positive == ((tc->def->flags & SWITCH_POLARITY) == 0)) { - process_bitstream(tc, m); + process_bitstream(tc, m); } - + tc->timecode_ticker++; } +/* + * Cycle to the next timecode definition which has a valid lookup + * + * Return: pointer to timecode definition + */ -/* Submit and decode a block of PCM audio data to the timecoder */ +static struct timecode_def* next_definition(struct timecode_def *def) +{ + if(def != NULL){ + + do { + def++; + + if (def > timecodes + ARRAY_SIZE(timecodes)) + def = timecodes; + + } while (!def->lookup); + + } + + return def; +} + +/* + * Change the timecode definition to the next available + */ -void timecoder_submit(struct timecoder_t *tc, const signed short *pcm, size_t npcm) +void timecoder_cycle_definition(struct timecoder *tc) { - while (npcm--) { - signed int primary, secondary; + tc->def = next_definition(tc->def); + tc->valid_counter = 0; + tc->timecode_ticker = 0; +} + +/* + * Submit and decode a block of PCM audio data to the timecode decoder + */ +void timecoder_submit(struct timecoder *tc, signed short *pcm, size_t npcm) +{ + while (npcm--) { + signed int primary, secondary; + if (tc->def->flags & SWITCH_PRIMARY) { primary = pcm[0]; secondary = pcm[1]; @@ -496,30 +577,34 @@ void timecoder_submit(struct timecoder_t *tc, const signed short *pcm, size_t np primary = pcm[1]; secondary = pcm[0]; } - - process_sample(tc, primary, secondary); - - update_monitor(tc, pcm[0], pcm[1]); + + process_sample(tc, primary, secondary); + + //update_monitor(tc, pcm[0], pcm[1]); pcm += TIMECODER_CHANNELS; } } +/* + * Get the last-known position of the timecode + * + * If now data is available or if too few bits have been error + * checked, then this counts as invalid. The last known position is + * given along with the time elapsed since the position stamp was + * read. + * + * Return: the known position of the timecode, or -1 if not known + * Post: if when != NULL, *when is the elapsed time in seconds + */ -/* Return the known position in the timecode, or -1 if not known. If - * two few bits have been error-checked, then this also counts as - * invalid. If 'when' is given, return the time, in seconds since this - * value was read. */ - -signed int timecoder_get_position(struct timecoder_t *tc, float *when) +signed int timecoder_get_position(struct timecoder *tc, double *when) { signed int r; - + if (tc->valid_counter > VALID_BITS) { r = lut_lookup(&tc->def->lut, tc->bitstream); - + if (r >= 0) { - //normalize position to milliseconds, not timecode steps -- Owen - r = (float)r * (1000.0 / (tc->def->resolution * tc->speed)); if (when) *when = tc->timecode_ticker * tc->dt; return r; diff --git a/libs/xwax/timecoder.h b/libs/xwax/timecoder.h index ccc475c..0002789 100644 --- a/libs/xwax/timecoder.h +++ b/libs/xwax/timecoder.h @@ -1,15 +1,15 @@ -/* - * Copyright (C) 2010 Mark Hills +/* + * Copyright (C) 2012 Mark Hills * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2, as published by the Free Software Foundation. - * + * * 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 * General Public License version 2 for more details. - * + * * You should have received a copy of the GNU General Public License * version 2 along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, @@ -20,21 +20,16 @@ #ifndef TIMECODER_H #define TIMECODER_H -#ifndef _MSC_VER #include -#endif -/* #include "device.h" */ #include "lut.h" #include "pitch.h" #define TIMECODER_CHANNELS 2 - typedef unsigned int bits_t; - -struct timecode_def_t { +struct timecode_def { char *name, *desc; int bits, /* number of bits in string */ resolution, /* wave cycles per second */ @@ -44,31 +39,29 @@ struct timecode_def_t { unsigned int length, /* in cycles */ safe; /* last 'safe' timecode number (for auto disconnect) */ bool lookup; /* true if lut has been generated */ - struct lut_t lut; + struct lut lut; }; - -struct timecoder_channel_t { - int positive, /* wave is in positive part of cycle */ +struct timecoder_channel { + bool positive, /* wave is in positive part of cycle */ swapped; /* wave recently swapped polarity */ signed int zero; unsigned int crossing_ticker; /* samples since we last crossed zero */ }; - -struct timecoder_t { - struct timecode_def_t *def; +struct timecoder { + struct timecode_def *def; double speed; /* Precomputed values */ - float dt, zero_alpha; + double dt, zero_alpha; /* Pitch information */ - int forwards; - struct timecoder_channel_t primary, secondary; - struct pitch_t pitch; + bool forwards; + struct timecoder_channel primary, secondary; + struct pitch pitch; /* Numerical timecode */ @@ -84,52 +77,65 @@ struct timecoder_t { int mon_size, mon_counter; }; - +struct timecode_def* timecoder_find_definition(const char *name); void timecoder_free_lookup(void); -int timecoder_init(struct timecoder_t *tc, const char *def_name, double speed, - unsigned int sample_rate); -void timecoder_clear(struct timecoder_t *tc); +void timecoder_init(struct timecoder *tc, struct timecode_def *def, + double speed, unsigned int sample_rate); +void timecoder_clear(struct timecoder *tc); -int timecoder_monitor_init(struct timecoder_t *tc, int size); -void timecoder_monitor_clear(struct timecoder_t *tc); +int timecoder_monitor_init(struct timecoder *tc, int size); +void timecoder_monitor_clear(struct timecoder *tc); -void timecoder_submit(struct timecoder_t *tc, const signed short *pcm, size_t npcm); +void timecoder_cycle_definition(struct timecoder *tc); +void timecoder_submit(struct timecoder *tc, signed short *pcm, size_t npcm); +signed int timecoder_get_position(struct timecoder *tc, double *when); -signed int timecoder_get_position(struct timecoder_t *tc, float *when); +/* + * The timecode definition currently in use by this decoder + */ +static inline struct timecode_def* timecoder_get_definition(struct timecoder *tc) +{ + return tc->def; +} -/* Return the pitch relative to reference playback speed */ +/* + * Return the pitch relative to reference playback speed + */ -static inline float timecoder_get_pitch(struct timecoder_t *tc) +static inline double timecoder_get_pitch(struct timecoder *tc) { return pitch_current(&tc->pitch) / tc->speed; } - -/* The last 'safe' timecode value on the record. Beyond this value, we +/* + * The last 'safe' timecode value on the record. Beyond this value, we * probably want to ignore the timecode values, as we will hit the - * label of the record. */ + * label of the record. + */ -static inline unsigned int timecoder_get_safe(struct timecoder_t *tc) +static inline unsigned int timecoder_get_safe(struct timecoder *tc) { - return tc->def->safe * 1000 / (tc->def->resolution * tc->speed); + return tc->def->safe; } +/* + * The resolution of the timecode. This is the number of bits per + * second at reference playback speed + */ -/* The resolution of the timecode. This is the number of bits per - * second at reference playback speed */ - -static inline double timecoder_get_resolution(struct timecoder_t *tc) +static inline double timecoder_get_resolution(struct timecoder *tc) { return tc->def->resolution * tc->speed; } +/* + * The number of revolutions per second of the timecode vinyl, + * used only for visual display + */ -/* The number of revolutions per second of the timecode vinyl, - * used only for visual display */ - -static inline double timecoder_revs_per_sec(struct timecoder_t *tc) +static inline double timecoder_revs_per_sec(struct timecoder *tc) { return (33.0 + 1.0 / 3) * tc->speed / 60; } diff --git a/src/ofxXwax.cpp b/src/ofxXwax.cpp index 8d5e079..3a7df88 100644 --- a/src/ofxXwax.cpp +++ b/src/ofxXwax.cpp @@ -13,7 +13,7 @@ ofxXwax::ofxXwax() ofxXwax::~ofxXwax() { timecoder_clear(&timecoder); // class - timecoder_free_lookup(); // static + //timecoder_free_lookup(); // static } void ofxXwax::setup(unsigned int sampleRate, unsigned int bufferSize, string format) { @@ -22,22 +22,24 @@ void ofxXwax::setup(unsigned int sampleRate, unsigned int bufferSize, string for this->format = format; float speed = 1.0; // 1.0 is 33 1/3, 1.35 is 45 rpm - timecoder_init(&timecoder, format.c_str(), speed, sampleRate); + struct timecode_def *timecoderDef; + timecoderDef = timecoder_find_definition(format.c_str()); + timecoder_init(&timecoder, timecoderDef, speed, sampleRate); + //timecoder_init(&timecoder, <#struct timecode_def *def#>, speed, sampleRate); shortBuffer.resize(nChannels * bufferSize); } void ofxXwax::update(float* input) { // convert from -1 to 1 to a 16-byte signed short integer - for (int i = 0; i < bufferSize * nChannels; i++) { + for (int i = 0; i < bufferSize*nChannels; i++) { shortBuffer[i] = input[i] * (1<<15); } timecoder_submit(&timecoder, &shortBuffer[0], bufferSize); - float when; + double when; float curPosition = timecoder_get_position(&timecoder, &when); - pitch = timecoder_get_pitch(&timecoder); velocity = (msPerSecond * bufferSize / sampleRate) * pitch; relativePosition += velocity; @@ -77,4 +79,4 @@ bool ofxXwax::isAbsoluteValid() const { float ofxXwax::millisToDegrees(float millis) { return (millis / msPerRotation) * 360; -} \ No newline at end of file +} diff --git a/src/ofxXwax.h b/src/ofxXwax.h index be3e152..7456aed 100644 --- a/src/ofxXwax.h +++ b/src/ofxXwax.h @@ -52,7 +52,7 @@ class ofxXwax { static float millisToDegrees(float millis); protected: - struct timecoder_t timecoder; + struct timecoder timecoder; unsigned int sampleRate, bufferSize; vector shortBuffer; float pitch, velocity, relativePosition, absolutePosition;