ref: 3b1fd9df8568594a3b324e276f1e110a7a01f664
dir: /src/rate.c/
#ifndef USE_OLD_RATE /* * August 21, 1998 * Copyright 1998 Fabrice Bellard. * * [Rewrote completly the code of Lance Norskog And Sundry * Contributors with a more efficient algorithm.] * * This source code is freely redistributable and may be used for * any purpose. This copyright notice must be maintained. * Lance Norskog And Sundry Contributors are not responsible for * the consequences of using this software. */ /* * Sound Tools rate change effect file. */ #include <math.h> #include "st.h" /* * Linear Interpolation. * * The use of fractional increment allows us to use no buffer. It * avoid the problems at the end of the buffer we had with the old * method which stored a possibly big buffer of size * lcm(in_rate,out_rate). * * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If * the input & output frequencies are equal, a delay of one sample is * introduced. Limited to processing 32-bit count worth of samples. * * 1 << FRAC_BITS evaluating to zero in several places. Changed with * an (unsigned long) cast to make it safe. MarkMLl 2/1/99 */ #define FRAC_BITS 16 /* Private data */ typedef struct ratestuff { ULONG opos_frac; /* fractional position of the output stream in input stream unit */ ULONG opos; ULONG opos_inc_frac; /* fractional position increment in the output stream */ ULONG opos_inc; ULONG ipos; /* position in the input stream (integer) */ LONG ilast; /* last sample in the input stream */ } *rate_t; /* * Process options */ int st_rate_getopts(effp, n, argv) eff_t effp; int n; char **argv; { if (n) { st_fail("Rate effect takes no options."); return (ST_EOF); } return (ST_SUCCESS); } /* * Prepare processing. */ int st_rate_start(effp) eff_t effp; { rate_t rate = (rate_t) effp->priv; ULONG incr; if (effp->ininfo.rate >= 65535 || effp->outinfo.rate >= 65535) { st_fail("rate effect can only handle rates <= 65535"); return (ST_EOF); } if (effp->ininfo.size == ST_SIZE_DWORD || effp->ininfo.size == ST_SIZE_FLOAT) { st_warn("rate effect reduces data to 16 bits"); } rate->opos_frac=0; rate->opos=0; /* increment */ incr=(ULONG)((double)effp->ininfo.rate / (double)effp->outinfo.rate * (double) ((unsigned long) 1 << FRAC_BITS)); rate->opos_inc_frac = incr & (((unsigned long) 1 << FRAC_BITS)-1); rate->opos_inc = incr >> FRAC_BITS; rate->ipos=0; rate->ilast = 0; return (ST_SUCCESS); } /* * Processed signed long samples from ibuf to obuf. * Return number of samples processed. */ int st_rate_flow(effp, ibuf, obuf, isamp, osamp) eff_t effp; LONG *ibuf, *obuf; LONG *isamp, *osamp; { rate_t rate = (rate_t) effp->priv; LONG *istart,*iend; LONG *ostart,*oend; LONG ilast,icur,out; ULONG tmp; double t; ilast=rate->ilast; istart = ibuf; iend = ibuf + *isamp; ostart = obuf; oend = obuf + *osamp; while (obuf < oend) { /* Safety catch to make sure we have input samples. */ if (ibuf >= iend) goto the_end; /* read as many input samples so that ipos > opos */ while (rate->ipos <= rate->opos) { ilast = *ibuf++; rate->ipos++; /* See if we finished the input buffer yet */ if (ibuf >= iend) goto the_end; } icur = *ibuf; /* interpolate */ t=(double) rate->opos_frac / ((unsigned long) 1 << FRAC_BITS); out = (double) ilast * (1.0 - t) + (double) icur * t; /* output sample & increment position */ *obuf++=(LONG) out; tmp = rate->opos_frac + rate->opos_inc_frac; rate->opos = rate->opos + rate->opos_inc + (tmp >> FRAC_BITS); rate->opos_frac = tmp & (((unsigned long) 1 << FRAC_BITS)-1); } the_end: *isamp = ibuf - istart; *osamp = obuf - ostart; rate->ilast = ilast; return (ST_SUCCESS); } /* * Do anything required when you stop reading samples. * Don't close input file! */ int st_rate_stop(effp) eff_t effp; { /* nothing to do */ return (ST_SUCCESS); } #else /* USE_OLD_RATE */ /* * July 5, 1991 * Copyright 1991 Lance Norskog And Sundry Contributors * This source code is freely redistributable and may be used for * any purpose. This copyright notice must be maintained. * Lance Norskog And Sundry Contributors are not responsible for * the consequences of using this software. */ /* * Sound Tools rate change effect file. */ #include <math.h> #include "st.h" /* * Least Common Multiple Linear Interpolation * * Find least common multiple of the two sample rates. * Construct the signal at the LCM by interpolating successive * input samples as straight lines. Pull output samples from * this line at output rate. * * Of course, actually calculate only the output samples. * * LCM must be 32 bits or less. Two prime number sample rates * between 32768 and 65535 will yield a 32-bit LCM, so this is * stretching it. */ /* * Algorithm: * * Generate a master sample clock from the LCM of the two rates. * Interpolate linearly along it. Count up input and output skips. * * Input: |inskip | | | | | * * * * LCM: | | | | | | | | | | | * * * * Output: | outskip | | | * * */ /* Private data for Lerp via LCM file */ typedef struct ratestuff { ULONG lcmrate; /* least common multiple of rates */ ULONG inskip, outskip; /* LCM increments for I & O rates */ ULONG total; ULONG intot, outtot; /* total samples in LCM basis */ LONG lastsamp; /* history */ } *rate_t; /* * Process options */ int st_rate_getopts(effp, n, argv) eff_t effp; int n; char **argv; { if (n) { st_fail("Rate effect takes no options."); return (ST_EOF); } return (ST_SUCCESS); } /* * Prepare processing. */ int st_rate_start(effp) eff_t effp; { rate_t rate = (rate_t) effp->priv; rate->lcmrate = lcm((LONG)effp->ininfo.rate, (LONG)effp->outinfo.rate); /* Cursory check for LCM overflow. * If both rate are below 65k, there should be no problem. * 16 bits x 16 bits = 32 bits, which we can handle. */ rate->inskip = rate->lcmrate / effp->ininfo.rate; rate->outskip = rate->lcmrate / effp->outinfo.rate; rate->total = rate->intot = rate->outtot = 0; rate->lastsamp = 0; return (ST_SUCCESS); } /* * Processed signed long samples from ibuf to obuf. * Return number of samples processed. */ int st_rate_flow(effp, ibuf, obuf, isamp, osamp) eff_t effp; LONG *ibuf, *obuf; int *isamp, *osamp; { rate_t rate = (rate_t) effp->priv; int len, done; LONG *istart = ibuf; LONG last; done = 0; if (rate->total == 0) { /* Emit first sample. We know the fence posts meet. */ *obuf = *ibuf++; rate->lastsamp = *obuf++ / 65536L; done = 1; rate->total = 1; /* advance to second output */ rate->outtot += rate->outskip; /* advance input range to span next output */ while ((rate->intot + rate->inskip) <= rate->outtot){ last = *ibuf++ / 65536L; rate->intot += rate->inskip; } } /* start normal flow-through operation */ last = rate->lastsamp; /* number of output samples the input can feed */ len = (*isamp * rate->inskip) / rate->outskip; if (len > *osamp) len = *osamp; for(; done < len; done++) { *obuf = last; *obuf += ((float)((*ibuf / 65536L) - last)* ((float)rate->outtot - rate->intot))/rate->inskip; *obuf *= 65536L; obuf++; /* advance to next output */ rate->outtot += rate->outskip; /* advance input range to span next output */ while ((rate->intot + rate->inskip) <= rate->outtot){ last = *ibuf++ / 65536L; rate->intot += rate->inskip; if (ibuf - istart == *isamp) goto out; } /* long samples with high LCM's overrun counters! */ if (rate->outtot == rate->intot) rate->outtot = rate->intot = 0; } out: *isamp = ibuf - istart; *osamp = len; rate->lastsamp = last; return (ST_SUCCESS); } /* * Do anything required when you stop reading samples. * Don't close input file! */ int st_rate_stop(effp) eff_t effp; { /* nothing to do */ return (ST_SUCCESS); } #endif /* USE_OLD_RATE */