diff options
Diffstat (limited to 'misc/tlininterp.c')
| -rw-r--r-- | misc/tlininterp.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/misc/tlininterp.c b/misc/tlininterp.c new file mode 100644 index 0000000..7db6791 --- /dev/null +++ b/misc/tlininterp.c @@ -0,0 +1,153 @@ +/* + tlininterp.c + David Rowe + Jan 2017 + + Fast linear interpolator for high oversampling rates. Upsample + with a decent filter first such that the signal is "low pass" wrt + to the input sample rate. + + build: gcc tlininterp.c -o tlininterp -Wall -O2 + +*/ + +#include <assert.h> +#include <getopt.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + +#define NBUF 1000 +#define SIGNED_16BIT 0 +#define SIGNED_8BIT 1 + +void display_help(void) { + fprintf(stderr, "\nusage: tlininterp inputRawFile OutputRawFile OverSampleRatio [-c]\n"); + fprintf(stderr, "\nUse - for stdin/stdout\n\n"); + fprintf(stderr, "-c complex signed 16 bit input and output\n"); + fprintf(stderr, "-d complex signed 16 bit input, complex signed 8 bit output\n"); + fprintf(stderr, "-f +Fs/4 freq shift\n\n"); +} + +int main(int argc, char *argv[]) { + FILE *fin, *fout; + short left[2], right[2], out[2*NBUF], i; + float oversample, t; + int8_t out_s8[2*NBUF]; + int lo_i[3], lo_q[3]; + + if (argc < 3) { + display_help(); + exit(1); + } + + if (strcmp(argv[1], "-") == 0) + fin = stdin; + else + fin = fopen(argv[1], "rb"); + assert(fin != NULL); + + if (strcmp(argv[2], "-") == 0) + fout = stdout; + else + fout = fopen(argv[2], "wb"); + assert(fout != NULL); + + oversample = atof(argv[3]); + if (oversample <= 1) { + display_help(); + exit(1); + } + + int channels = 1; + int freq_shift = 0; + lo_i[0] = -1; lo_i[1] = 0; + lo_q[0] = 0; lo_q[1] = -1; + int format = SIGNED_16BIT; + int opt; + while ((opt = getopt(argc, argv, "cdf")) != -1) { + switch (opt) { + case 'c': channels = 2; break; + case 'd': channels = 2; format = SIGNED_8BIT; break; + case 'f': freq_shift = 1; break; + default: + display_help(); + exit(1); + } + } + + for (i=0; i<channels; i++) + left[i] = 0; + t = 0.0; + int j = 0; + while(fread(&right, sizeof(short)*channels, 1, fin) == 1) { + while (t < 1.0) { + + for (i=0; i<channels; i++) { + out[2*j+i] = (1.0 - t)*left[i] + t*right[i]; + } + + if (freq_shift) { + + /* update local osc recursion */ + + lo_i[2] = -lo_i[0]; lo_q[2] = -lo_q[0]; + + /* complex mixer to up-shift complex samples */ + + int a = out[2*j]; + int b = out[2*j+1]; + int c = lo_i[2]; + int d = lo_q[2]; + + out[2*j] = a*c - b*d; + out[2*j+1] = b*c + a*d; + + //fprintf(stderr, "% d % d % 5d % 5d\n", lo_i[2], lo_q[2], out[0], out[1]); + + /* update LO memory */ + + lo_i[0] = lo_i[1]; lo_i[1] = lo_i[2]; + lo_q[0] = lo_q[1]; lo_q[1] = lo_q[2]; + } + + /* once we have enough samples write to disk */ + + j++; + if (j == NBUF) { + if (format == SIGNED_16BIT) { + fwrite(&out, sizeof(short)*channels, NBUF, fout); + } else { + for (i=0; i<channels*NBUF; i++) { + out_s8[i] = out[i] >> 8; + } + fwrite(&out_s8, sizeof(int8_t)*channels, NBUF, fout); + } + j = 0; + } + + t += 1.0/oversample; + } + + t -= 1.0; + for (i=0; i<channels; i++) + left[i] = right[i]; + } + + /* write remaining samples to disk */ + + if (format == SIGNED_16BIT) { + fwrite(&out, sizeof(short), j, fout); + } else { + for (i=0; i<j; i++) { + out_s8[i] = out[i] >> 8; + } + fwrite(&out_s8, sizeof(int8_t)*channels, j, fout); + } + + fclose(fout); + fclose(fin); + + return 0; +} |
