This is convert.c in view mode; [Download] [Up]
#include <math.h> #include <stdio.h> #include <carl/defaults.h> #include <carl/carl.h> /* #include <malloc.h> */ #define IBUF 1024 /*------------------------------------------------------------------ PROGRAM: Time-Varying Sample-Rate Conversion Program AUTHOR: Mark Dolson Center for Music Experiment Q-037 University of California, San Diego La Jolla, Ca. 92093 DATE: March 1, 1984 This is a straightforward program for performing arbitrary sample-rate conversion with high fidelity. The method is simply to step through the input at the desired sampling increment, and to compute the output points as appropriately weighted averages of the surrounding input points. There are three cases to consider: 1) sample rates are in a small-integer ratio - weights are obtained from table, 2) sample rates are in a large-integer ratio - weights are linearly interpolated from table, and 3) sample rates are in a time-varying ratio - weights are linearly interpolated from table, increment is recomputed. flags: r = output sample rate (must be specified) t = minimum time increment (time-varying only) Q = quality factor (1, 2, 3, or 4: default = 2) R = input sample rate (automatically read from stdin) b = starting sample (0) e = final sample (end of input) The time-varying specifications are input via a UNIX file (specified on the command line after whatever flags may be present) of x,y pairs where x is the time in seconds. The y values may either be desired_output_sample_rate_at_time_x, or input_sample_rate / desired_output_sample_rate_at_time_x). If the y values are of the first form (i.e., output_rate), then the -r flag has no real meaning. However, its presence is still mandatory. In this case, the -r flag MUST specify the minimum output sample rate (i.e., the minimum y value in the file). If the y values are of the second form (i.e., input_rate / output_rate) then the -r flag MUST be replaced by the -t flag. This is the only case in which the -r flag is not used and the only case in which the -t flag is used. Furthmore, the -t flag MUST specify the minimum y value in the file. The advantage to this second form is that when using this program after the phase vocoder to change a time-varying time-scaling into a time-varying pitch-transposition, the same x,y pairs can be used to control both programs. For example, to produce an upward glissando of one octave over four seconds: gen4 -L100 0 1 0 4 2 | btoa -t -R25 | atob > gliss sndin file | pvoc -T2 gliss | sndout temp sndin temp | convert -t1 gliss | sndout file ------------------------------------------------------------------*/ main(argc, argv) int argc; char **argv; { float *input, /* pointer to start of input buffer */ *nextIn, /* pointer to next empty word in input */ *window; /* pointer to center of analysis window */ int M = 2401, /* length of window impulse response */ N = 120, /* length of sinc period */ L = 120, /* internal sample rate is L*Rin */ m, /* current input sample in buffer */ o, /* current input at L*Rin mod L */ del, /* increment */ WinLen, /* half-length of window at L*Rin */ wLen, /* half-length of window at Rin */ jMin, /* initial offset in window */ mMax, /* maximum valid m */ IBUF2; /* IBUF / 2 */ long n, /* current input sample */ nMin = 0, /* first input sample */ nMax = 100000000; /* last input sample (unless EOF) */ char ch; /* needed for crack (commandline interpreter)*/ float Pi, /* 3.14159... */ TwoPi, /* 2*Pi */ beta = 6.8, /* parameter for Kaiser window */ sum, /* scale factor for renormalizing windows */ fdel, /* float del */ idel, /* float del */ fo, /* float o */ of, /* fractional o */ fL = 120., /* float L */ iw, /* interpolated window */ time, /* n / Rin */ tvx0, /* current x value of time-var function */ tvx1, /* next x value of time-var function */ tvdx, /* tvx1 - tvx0 */ tvy0, /* current y value of time-var function */ tvy1, /* next y value of time-var function */ tvdy, /* tvy1 - tvy0 */ frac, /* tvdy / tvdx */ invRin, /* 1. / Rin */ tmin, /* minimum time increment */ Rin = 0., /* input sampling rate */ Rout = 0.; /* output sample rate */ int i,j,k, /* index variables */ one = 1, /* for Kaiser calls */ Q = 0, /* quality factor */ tspec = 0, /* flag for time specification */ tvflg = 0, /* flag for time-varying time-scaling */ tvnxt, /* counter for stepping thru time-var func */ tvlen; /* length of time-varying function */ FUNCTION *tvpnt; /* pointer to structure for time-var function*/ /* call crack to interpret commandline */ if (isatty(0)) usage(1); { PROP *proplist; /* from header on stdin */ if ((proplist = getheader(stdin)) != NULL) { /* there is a header */ char *dbuf; noautocp(); /* suppress hdr copy */ if ((dbuf = getprop(stdin, H_SRATE)) != NULL) Rin = atof(dbuf); /* get input srate */ } } while ((ch = crack(argc,argv,"Q|R|r|t|b|e|h",0)) != NULL){ switch (ch) { case 'Q': Q = sfexpr(arg_option,1.0); break; case 'R': Rin = sfexpr(arg_option,1.0); break; case 'r': Rout = sfexpr(arg_option,1.0); break; case 't': tmin = sfexpr(arg_option,1.0); tspec = 1; break; case 'b': nMin = sfexpr(arg_option,1.0); break; case 'e': nMax = sfexpr(arg_option,1.0); break; case 'h': usage(0); /* then exits normally */ default: usage(1); /* this exits with error */ } } /* time-varying specification is contained in specially formatted file */ if (arg_index < argc) { tvpnt = read_func_file(argv[arg_index], H_XY_PAIRS); tvflg = 1; tvx0 = tvpnt->fxval[0]; tvx1 = tvpnt->fxval[1]; tvy0 = tvpnt->fyval[0]; tvy1 = tvpnt->fyval[1]; /* fprintf(stderr,"name=%s\n", tvpnt->fname); fprintf(stderr,"type=%s\n", tvpnt->ftype); fprintf(stderr,"len=%d\n", tvpnt->flen); fprintf(stderr,"x0: %f y0: %f x1: %f y1: %f\n",tvx0,tvy0,tvx1,tvy1); */ if (tvx0 != 0.){ fprintf(stderr,"convert: warning - first x value in func must be 0\n"); tvx0 = 0.; } if (tvy0 <= 0.){ fprintf(stderr,"convert: invalid initial y value in time-vary func\n"); exit(1); } tvdx = tvx1 - tvx0; if (tvdx <= 0.){ fprintf(stderr,"convert: invalid x values in time-vary function\n"); exit(1); } tvdy = tvy1 - tvy0; frac = tvdy / tvdx; tvnxt = 1; tvlen = tvpnt->flen; if (tspec) Rout = Rin / tmin; } /* calculate increment: if decimating, then window is impulse response of low- pass filter with cutoff frequency at half of Rout; if interpolating, then window is impulse response of lowpass filter with cutoff frequency at half of Rin. */ fdel = ((float) (L * Rin) / Rout); del = fdel; idel = del; if (del > L) N = del; if ((Q >= 1) && (Q <=4)) M = Q * N * 10 + 1; if (tvflg){ if (tspec) fdel = tvy0 * L; else fdel = ((float) (L * Rin) / tvy0); } IBUF2 = IBUF / 2; invRin = 1. / Rin; nMax -= nMin; /* make window: the window is the product of a kaiser and a sin(x)/x */ Pi = 4.*atan(1.); TwoPi = 2. * Pi; if ((window = (float *) calloc((M+1),sizeof(float))) == NULL) malerr("convert: insufficient memory",1); window += (WinLen = (M-1)/2); wLen = (M/2 - L) / L; kaiser(M,window,WinLen,one,beta); for (i = 1; i <= WinLen; i++) *(window - i) = *(window + i); for (i = 1; i <= WinLen; i++) *(window + i) = *(window - i) *= N * sin((double) Pi*i/N) / (Pi*i); sum = *window; for (i = L-1; i <= WinLen; i += L) sum += *(window - i) + *(window + i); sum = 1. / sum; *window *= sum; for (i = 1; i <= WinLen; i++) *(window + i) = *(window - i) *= sum; *(window + WinLen + 1) = 0.; /* set up input buffer: nextIn always points to the next empty word in the input buffer. If the buffer is full, then nextIn jumps back to the beginning, and the old values are written over. */ if ((input = (float *) calloc(IBUF,sizeof(float))) == NULL) malerr("convert: insufficient memory",1); nextIn = input; /* initialization: */ for (i = 0; i < nMin; i++) getfloat(nextIn); for (i = 0; i < IBUF; i++) if(getfloat(nextIn++) <= 0) *nextIn = 0.; jMin = -(wLen + 1) * L; mMax = IBUF; o = n = m = 0; fo = 0.; /* main loop: If nMax is not specified it is assumed to be very large and then readjusted when getfloat detects the end of input. */ while(n < nMax){ /* case 1: (Rin / Rout) * 120 = integer */ if ((tvflg == 0) && (idel == fdel)){ /* apply window (window is sampled at L * Rin) */ sum = 0.; j = jMin - o; k = m - wLen; if (k < 0) k += IBUF; for (i = -wLen; i <= wLen+1; i++){ j += L; if (++k >= IBUF) k = 0; sum += *(window + j) * *(input + k); } putfloat(&sum); /* move window (window advances by o samples at L * Rin sample rate) */ o += del; while (o >= L){ o -= L; n++; m++; if (m + wLen + 1 >= mMax){ mMax += IBUF2; if (nextIn >= (input + IBUF)) nextIn = input; for (i = 0; i < IBUF2; i++) if (getfloat(nextIn++) <= 0) break; if (i < IBUF2){ nMax = n + wLen + i; *(nextIn - 1) = 0.; } for (i += 1; i < IBUF2; i++) *(nextIn++) = 0.; } if (m >= IBUF){ m = 0; mMax = IBUF2; } } } /* case 2: (Rin / Rout) * 120 = non-integer constant */ else { /* apply window (window values are linearly interpolated) */ sum = 0.; o = fo; of = fo - o; j = jMin - o; k = m - wLen; if (k < 0) k += IBUF; for (i = -wLen; i <= wLen+1; i++){ j += L; if (++k >= IBUF) k = 0; iw = *(window+j) + of * (*(window+j+1) - *(window+j)); sum += iw * *(input + k); } putfloat(&sum); /* move window */ fo += fdel; while (fo >= fL){ fo -= fL; n++; m++; if (m + wLen + 1 >= mMax){ mMax += IBUF2; if (nextIn >= (input + IBUF)) nextIn = input; for (i = 0; i < IBUF2; i++) if (getfloat(nextIn++) <= 0) break; if (i < IBUF2){ nMax = n +wLen + i; *(nextIn - 1) = 0.; } for (i += 1; i < IBUF2; i++) *(nextIn++) = 0.; } if (m >= IBUF){ m = 0; mMax = IBUF2; } } /* case 3: time-varying - recompute fdel and use case 2 */ if (tvflg) { time = n * invRin; if (time >= tvx1) { if (++tvnxt >= tvlen) tvflg = 0; else { tvx0 = tvx1; tvx1 = tvpnt->fxval[tvnxt]; tvy0 = tvy1; tvy1 = tvpnt->fyval[tvnxt]; tvdx = tvx1 - tvx0; if (tvdx <= 0.){ fprintf(stderr,"convert: invalid x values in time-vary function\n"); exit(1); } tvdy = tvy1 - tvy0; frac = tvdy / tvdx; } } fdel = tvy0 + frac * (time - tvx0); if (tspec != 1) fdel = Rin / fdel; fdel *= L; } } } flushfloat(); exit(0); } usage(exitcode) int exitcode; { fprintf(stderr,"%s%s%s%s%s%s%s%s%s", "usage: convert [flags] [file] < floatsams > floatsams\n", "input and output must be files or pipes\n", "flags:\n", "r = output sample rate (must be specified)\n", "t = minimum increment time (time-varying only)\n", "Q = quality factor (1, 2, 3, or 4: default = 2)\n", "R = input sample rate (overrides input header rate)\n", "b = starting sample (0)\n", "e = final sample (end of input)\n" ); exit(exitcode); } malerr(str, ex) char *str; int ex; { fprintf(stderr, "%s\n", str); exit(ex); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.