diff options
Diffstat (limited to 'third_party/resample/src/resamplesubs.c')
-rw-r--r-- | third_party/resample/src/resamplesubs.c | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/third_party/resample/src/resamplesubs.c b/third_party/resample/src/resamplesubs.c new file mode 100644 index 00000000..920e56e6 --- /dev/null +++ b/third_party/resample/src/resamplesubs.c @@ -0,0 +1,520 @@ +/* resamplesubs.c - sampling rate conversion subroutines */ +// Altered version + +#include "resample.h" + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> + +#define IBUFFSIZE 4096 /* Input buffer size */ + +#include "smallfilter.h" +#include "largefilter.h" + +#include "filterkit.h" +#include "sndlibextra.h" + +#ifdef WITH_PJ +#include "resamplesubs.h" + +unsigned resample_LARGE_FILTER_NMULT = LARGE_FILTER_NMULT; +unsigned resample_LARGE_FILTER_NWING = LARGE_FILTER_NWING; +unsigned resample_LARGE_FILTER_SCALE = LARGE_FILTER_SCALE; +short* resample_LARGE_FILTER_IMP = LARGE_FILTER_IMP; +short* resample_LARGE_FILTER_IMPD = LARGE_FILTER_IMPD; + +unsigned resample_SMALL_FILTER_NMULT = SMALL_FILTER_NMULT; +unsigned resample_SMALL_FILTER_NWING = SMALL_FILTER_NWING; +unsigned resample_SMALL_FILTER_SCALE = SMALL_FILTER_SCALE; +short* resample_SMALL_FILTER_IMP = SMALL_FILTER_IMP; +short* resample_SMALL_FILTER_IMPD = SMALL_FILTER_IMPD; +#endif + + +/* CAUTION: Assumes we call this for only one resample job per program run! */ +/* return: 0 - notDone */ +/* >0 - index of last sample */ +static int +readData(int infd, /* input file descriptor */ + int inCount, /* _total_ number of frames in input file */ + HWORD *outPtr1, /* array receiving left chan samps */ + HWORD *outPtr2, /* array receiving right chan samps */ + int dataArraySize, /* size of these arrays */ + int nChans, + int Xoff) /* read into input array starting at this index */ +{ + int i, Nsamps, nret; + static unsigned int framecount; /* frames previously read */ + static mus_sample_t **ibufs = NULL; + + if (ibufs == NULL) { /* first time called, so allocate it */ + ibufs = sndlib_allocate_buffers(nChans, dataArraySize); + if (ibufs == NULL) { + fprintf(stderr, "readData: Can't allocate input buffers!\n"); + exit(1); + } + framecount = 0; /* init this too */ + } + + Nsamps = dataArraySize - Xoff; /* Calculate number of samples to get */ + outPtr1 += Xoff; /* Start at designated sample number */ + outPtr2 += Xoff; + + nret = mus_file_read(infd, 0, Nsamps - 1, nChans, ibufs); + if (nret < 0) { + fprintf(stderr, "readData: Can't read data!\n"); + exit(1); + } + + /* NB: sndlib pads ibufs with zeros if it reads past EOF. */ + if (nChans == 1) { + for (i = 0; i < Nsamps; i++) + *outPtr1++ = MUS_SAMPLE_TYPE_TO_HWORD(ibufs[0][i]); + } + else { + for (i = 0; i < Nsamps; i++) { + *outPtr1++ = MUS_SAMPLE_TYPE_TO_HWORD(ibufs[0][i]); + *outPtr2++ = MUS_SAMPLE_TYPE_TO_HWORD(ibufs[1][i]); + } + } + + framecount += Nsamps; + + if (framecount >= (unsigned)inCount) /* return index of last samp */ + return (((Nsamps - (framecount - inCount)) - 1) + Xoff); + else + return 0; +} + + +#ifdef DEBUG +static int pof = 0; /* positive overflow count */ +static int nof = 0; /* negative overflow count */ +#endif + +static INLINE HWORD WordToHword(WORD v, int scl) +{ + HWORD out; + WORD llsb = (1<<(scl-1)); + v += llsb; /* round */ + v >>= scl; + if (v>MAX_HWORD) { +#ifdef DEBUG + if (pof == 0) + fprintf(stderr, "*** resample: sound sample overflow\n"); + else if ((pof % 10000) == 0) + fprintf(stderr, "*** resample: another ten thousand overflows\n"); + pof++; +#endif + v = MAX_HWORD; + } else if (v < MIN_HWORD) { +#ifdef DEBUG + if (nof == 0) + fprintf(stderr, "*** resample: sound sample (-) overflow\n"); + else if ((nof % 1000) == 0) + fprintf(stderr, "*** resample: another thousand (-) overflows\n"); + nof++; +#endif + v = MIN_HWORD; + } + out = (HWORD) v; + return out; +} + +/* Sampling rate conversion using linear interpolation for maximum speed. + */ +STATIC int + SrcLinear(HWORD X[], HWORD Y[], double factor, UWORD *Time, UHWORD Nx) +{ + HWORD iconst; + HWORD *Xp, *Ystart; + WORD v,x1,x2; + + double dt; /* Step through input signal */ + UWORD dtb; /* Fixed-point version of Dt */ + UWORD endTime; /* When Time reaches EndTime, return to user */ + + dt = 1.0/factor; /* Output sampling period */ + dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */ + + Ystart = Y; + endTime = *Time + (1<<Np)*(WORD)Nx; + while (*Time < endTime) + { + iconst = (*Time) & Pmask; + Xp = &X[(*Time)>>Np]; /* Ptr to current input sample */ + x1 = *Xp++; + x2 = *Xp; + x1 *= ((1<<Np)-iconst); + x2 *= iconst; + v = x1 + x2; + *Y++ = WordToHword(v,Np); /* Deposit output */ + *Time += dtb; /* Move to next sample by time increment */ + } + return (Y - Ystart); /* Return number of output samples */ +} + +/* Sampling rate up-conversion only subroutine; + * Slightly faster than down-conversion; + */ +STATIC int SrcUp(HWORD X[], HWORD Y[], double factor, UWORD *Time, + UHWORD Nx, UHWORD Nwing, UHWORD LpScl, + HWORD Imp[], HWORD ImpD[], BOOL Interp) +{ + HWORD *Xp, *Ystart; + WORD v; + + double dt; /* Step through input signal */ + UWORD dtb; /* Fixed-point version of Dt */ + UWORD endTime; /* When Time reaches EndTime, return to user */ + + dt = 1.0/factor; /* Output sampling period */ + dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */ + + Ystart = Y; + endTime = *Time + (1<<Np)*(WORD)Nx; + while (*Time < endTime) + { + Xp = &X[*Time>>Np]; /* Ptr to current input sample */ + /* Perform left-wing inner product */ + v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask),-1); + /* Perform right-wing inner product */ + v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1, + /* previous (triggers warning): (HWORD)((-*Time)&Pmask),1); */ + (HWORD)((((*Time)^Pmask)+1)&Pmask),1); + v >>= Nhg; /* Make guard bits */ + v *= LpScl; /* Normalize for unity filter gain */ + *Y++ = WordToHword(v,NLpScl); /* strip guard bits, deposit output */ + *Time += dtb; /* Move to next sample by time increment */ + } + return (Y - Ystart); /* Return the number of output samples */ +} + + +/* Sampling rate conversion subroutine */ + +STATIC int SrcUD(HWORD X[], HWORD Y[], double factor, UWORD *Time, + UHWORD Nx, UHWORD Nwing, UHWORD LpScl, + HWORD Imp[], HWORD ImpD[], BOOL Interp) +{ + HWORD *Xp, *Ystart; + WORD v; + + double dh; /* Step through filter impulse response */ + double dt; /* Step through input signal */ + UWORD endTime; /* When Time reaches EndTime, return to user */ + UWORD dhb, dtb; /* Fixed-point versions of Dh,Dt */ + + dt = 1.0/factor; /* Output sampling period */ + dtb = dt*(1<<Np) + 0.5; /* Fixed-point representation */ + + dh = MIN(Npc, factor*Npc); /* Filter sampling period */ + dhb = dh*(1<<Na) + 0.5; /* Fixed-point representation */ + + Ystart = Y; + endTime = *Time + (1<<Np)*(WORD)Nx; + while (*Time < endTime) + { + Xp = &X[*Time>>Np]; /* Ptr to current input sample */ + v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HWORD)(*Time&Pmask), + -1, dhb); /* Perform left-wing inner product */ + v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, + /* previous (triggers warning): (HWORD)((-*Time)&Pmask), */ + (HWORD)((((*Time)^Pmask)+1)&Pmask), + 1, dhb); /* Perform right-wing inner product */ + v >>= Nhg; /* Make guard bits */ + v *= LpScl; /* Normalize for unity filter gain */ + *Y++ = WordToHword(v,NLpScl); /* strip guard bits, deposit output */ + *Time += dtb; /* Move to next sample by time increment */ + } + return (Y - Ystart); /* Return the number of output samples */ +} + +#ifndef WITH_PJ +static int err_ret(char *s) +{ + fprintf(stderr,"resample: %s \n\n",s); /* Display error message */ + return -1; +} + +static int resampleFast( /* number of output samples returned */ + double factor, /* factor = Sndout/Sndin */ + int infd, /* input and output file descriptors */ + int outfd, + int inCount, /* number of input samples to convert */ + int outCount, /* number of output samples to compute */ + int nChans) /* number of sound channels (1 or 2) */ +{ + UWORD Time, Time2; /* Current time/pos in input sample */ + UHWORD Xp, Ncreep, Xoff, Xread; + int OBUFFSIZE = (int)(((double)IBUFFSIZE)*factor+2.0); + HWORD X1[IBUFFSIZE], Y1[2]; /* I/O buffers */ + HWORD X2[IBUFFSIZE], Y2[OBUFFSIZE]; /* I/O buffers */ + UHWORD Nout, Nx; + int i, Ycount, last; + + mus_sample_t **obufs = sndlib_allocate_buffers(nChans, OBUFFSIZE); + if (obufs == NULL) + return err_ret("Can't allocate output buffers"); + + Xoff = 10; + + Nx = IBUFFSIZE - 2*Xoff; /* # of samples to process each iteration */ + last = 0; /* Have not read last input sample yet */ + Ycount = 0; /* Current sample and length of output file */ + + Xp = Xoff; /* Current "now"-sample pointer for input */ + Xread = Xoff; /* Position in input array to read into */ + Time = (Xoff<<Np); /* Current-time pointer for converter */ + + for (i=0; i<Xoff; X1[i++]=0); /* Need Xoff zeros at begining of sample */ + for (i=0; i<Xoff; X2[i++]=0); /* Need Xoff zeros at begining of sample */ + + do { + if (!last) /* If haven't read last sample yet */ + { + last = readData(infd, inCount, X1, X2, IBUFFSIZE, + nChans, (int)Xread); + if (last && (last-Xoff<Nx)) { /* If last sample has been read... */ + Nx = last-Xoff; /* ...calc last sample affected by filter */ + if (Nx <= 0) + break; + } + } + + /* Resample stuff in input buffer */ + Time2 = Time; + Nout=SrcLinear(X1,Y1,factor,&Time,Nx); + if (nChans==2) + Nout=SrcLinear(X2,Y2,factor,&Time2,Nx); + + Time -= (Nx<<Np); /* Move converter Nx samples back in time */ + Xp += Nx; /* Advance by number of samples processed */ + Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */ + if (Ncreep) { + Time -= (Ncreep<<Np); /* Remove time accumulation */ + Xp += Ncreep; /* and add it to read pointer */ + } + for (i=0; i<IBUFFSIZE-Xp+Xoff; i++) { /* Copy part of input signal */ + X1[i] = X1[i+Xp-Xoff]; /* that must be re-used */ + if (nChans==2) + X2[i] = X2[i+Xp-Xoff]; /* that must be re-used */ + } + if (last) { /* If near end of sample... */ + last -= Xp; /* ...keep track were it ends */ + if (!last) /* Lengthen input by 1 sample if... */ + last++; /* ...needed to keep flag TRUE */ + } + Xread = i; /* Pos in input buff to read new data into */ + Xp = Xoff; + + Ycount += Nout; + if (Ycount>outCount) { + Nout -= (Ycount-outCount); + Ycount = outCount; + } + + if (Nout > OBUFFSIZE) /* Check to see if output buff overflowed */ + return err_ret("Output array overflow"); + + if (nChans==1) { + for (i = 0; i < Nout; i++) + obufs[0][i] = HWORD_TO_MUS_SAMPLE_TYPE(Y1[i]); + } else { + for (i = 0; i < Nout; i++) { + obufs[0][i] = HWORD_TO_MUS_SAMPLE_TYPE(Y1[i]); + obufs[1][i] = HWORD_TO_MUS_SAMPLE_TYPE(Y2[i]); + } + } + /* NB: errors reported within sndlib */ + mus_file_write(outfd, 0, Nout - 1, nChans, obufs); + + printf("."); fflush(stdout); + + } while (Ycount<outCount); /* Continue until done */ + + return(Ycount); /* Return # of samples in output file */ +} + + +static int resampleWithFilter( /* number of output samples returned */ + double factor, /* factor = outSampleRate/inSampleRate */ + int infd, /* input and output file descriptors */ + int outfd, + int inCount, /* number of input samples to convert */ + int outCount, /* number of output samples to compute */ + int nChans, /* number of sound channels (1 or 2) */ + BOOL interpFilt, /* TRUE means interpolate filter coeffs */ + HWORD Imp[], HWORD ImpD[], + UHWORD LpScl, UHWORD Nmult, UHWORD Nwing) +{ + UWORD Time, Time2; /* Current time/pos in input sample */ + UHWORD Xp, Ncreep, Xoff, Xread; + int OBUFFSIZE = (int)(((double)IBUFFSIZE)*factor+2.0); + HWORD X1[IBUFFSIZE], Y1[OBUFFSIZE]; /* I/O buffers */ + HWORD X2[IBUFFSIZE], Y2[OBUFFSIZE]; /* I/O buffers */ + UHWORD Nout, Nx; + int i, Ycount, last; + + mus_sample_t **obufs = sndlib_allocate_buffers(nChans, OBUFFSIZE); + if (obufs == NULL) + return err_ret("Can't allocate output buffers"); + + /* Account for increased filter gain when using factors less than 1 */ + if (factor < 1) + LpScl = LpScl*factor + 0.5; + + /* Calc reach of LP filter wing & give some creeping room */ + Xoff = ((Nmult+1)/2.0) * MAX(1.0,1.0/factor) + 10; + + if (IBUFFSIZE < 2*Xoff) /* Check input buffer size */ + return err_ret("IBUFFSIZE (or factor) is too small"); + + Nx = IBUFFSIZE - 2*Xoff; /* # of samples to process each iteration */ + + last = 0; /* Have not read last input sample yet */ + Ycount = 0; /* Current sample and length of output file */ + Xp = Xoff; /* Current "now"-sample pointer for input */ + Xread = Xoff; /* Position in input array to read into */ + Time = (Xoff<<Np); /* Current-time pointer for converter */ + + for (i=0; i<Xoff; X1[i++]=0); /* Need Xoff zeros at begining of sample */ + for (i=0; i<Xoff; X2[i++]=0); /* Need Xoff zeros at begining of sample */ + + do { + if (!last) /* If haven't read last sample yet */ + { + last = readData(infd, inCount, X1, X2, IBUFFSIZE, + nChans, (int)Xread); + if (last && (last-Xoff<Nx)) { /* If last sample has been read... */ + Nx = last-Xoff; /* ...calc last sample affected by filter */ + if (Nx <= 0) + break; + } + } + /* Resample stuff in input buffer */ + Time2 = Time; + if (factor >= 1) { /* SrcUp() is faster if we can use it */ + Nout=SrcUp(X1,Y1,factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,interpFilt); + if (nChans==2) + Nout=SrcUp(X2,Y2,factor,&Time2,Nx,Nwing,LpScl,Imp,ImpD, + interpFilt); + } + else { + Nout=SrcUD(X1,Y1,factor,&Time,Nx,Nwing,LpScl,Imp,ImpD,interpFilt); + if (nChans==2) + Nout=SrcUD(X2,Y2,factor,&Time2,Nx,Nwing,LpScl,Imp,ImpD, + interpFilt); + } + + Time -= (Nx<<Np); /* Move converter Nx samples back in time */ + Xp += Nx; /* Advance by number of samples processed */ + Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */ + if (Ncreep) { + Time -= (Ncreep<<Np); /* Remove time accumulation */ + Xp += Ncreep; /* and add it to read pointer */ + } + for (i=0; i<IBUFFSIZE-Xp+Xoff; i++) { /* Copy part of input signal */ + X1[i] = X1[i+Xp-Xoff]; /* that must be re-used */ + if (nChans==2) + X2[i] = X2[i+Xp-Xoff]; /* that must be re-used */ + } + if (last) { /* If near end of sample... */ + last -= Xp; /* ...keep track were it ends */ + if (!last) /* Lengthen input by 1 sample if... */ + last++; /* ...needed to keep flag TRUE */ + } + Xread = i; /* Pos in input buff to read new data into */ + Xp = Xoff; + + Ycount += Nout; + if (Ycount>outCount) { + Nout -= (Ycount-outCount); + Ycount = outCount; + } + + if (Nout > OBUFFSIZE) /* Check to see if output buff overflowed */ + return err_ret("Output array overflow"); + + if (nChans==1) { + for (i = 0; i < Nout; i++) + obufs[0][i] = HWORD_TO_MUS_SAMPLE_TYPE(Y1[i]); + } else { + for (i = 0; i < Nout; i++) { + obufs[0][i] = HWORD_TO_MUS_SAMPLE_TYPE(Y1[i]); + obufs[1][i] = HWORD_TO_MUS_SAMPLE_TYPE(Y2[i]); + } + } + /* NB: errors reported within sndlib */ + mus_file_write(outfd, 0, Nout - 1, nChans, obufs); + + printf("."); fflush(stdout); + + } while (Ycount<outCount); /* Continue until done */ + + return(Ycount); /* Return # of samples in output file */ +} + + +int resample( /* number of output samples returned */ + double factor, /* factor = Sndout/Sndin */ + int infd, /* input and output file descriptors */ + int outfd, + int inCount, /* number of input samples to convert */ + int outCount, /* number of output samples to compute */ + int nChans, /* number of sound channels (1 or 2) */ + BOOL interpFilt, /* TRUE means interpolate filter coeffs */ + int fastMode, /* 0 = highest quality, slowest speed */ + BOOL largeFilter, /* TRUE means use 65-tap FIR filter */ + char *filterFile) /* NULL for internal filter, else filename */ +{ + UHWORD LpScl; /* Unity-gain scale factor */ + UHWORD Nwing; /* Filter table size */ + UHWORD Nmult; /* Filter length for up-conversions */ + HWORD *Imp=0; /* Filter coefficients */ + HWORD *ImpD=0; /* ImpD[n] = Imp[n+1]-Imp[n] */ + + if (fastMode) + return resampleFast(factor,infd,outfd,inCount,outCount,nChans); + +#ifdef DEBUG + /* Check for illegal constants */ + if (Np >= 16) + return err_ret("Error: Np>=16"); + if (Nb+Nhg+NLpScl >= 32) + return err_ret("Error: Nb+Nhg+NLpScl>=32"); + if (Nh+Nb > 32) + return err_ret("Error: Nh+Nb>32"); +#endif + + /* Set defaults */ + + if (filterFile != NULL && *filterFile != '\0') { + if (readFilter(filterFile, &Imp, &ImpD, &LpScl, &Nmult, &Nwing)) + return err_ret("could not find filter file, " + "or syntax error in contents of filter file"); + } else if (largeFilter) { + Nmult = LARGE_FILTER_NMULT; + Imp = LARGE_FILTER_IMP; /* Impulse response */ + ImpD = LARGE_FILTER_IMPD; /* Impulse response deltas */ + LpScl = LARGE_FILTER_SCALE; /* Unity-gain scale factor */ + Nwing = LARGE_FILTER_NWING; /* Filter table length */ + } else { + Nmult = SMALL_FILTER_NMULT; + Imp = SMALL_FILTER_IMP; /* Impulse response */ + ImpD = SMALL_FILTER_IMPD; /* Impulse response deltas */ + LpScl = SMALL_FILTER_SCALE; /* Unity-gain scale factor */ + Nwing = SMALL_FILTER_NWING; /* Filter table length */ + } +#if DEBUG + fprintf(stderr,"Attenuating resampler scale factor by 0.95 " + "to reduce probability of clipping\n"); +#endif + LpScl *= 0.95; + return resampleWithFilter(factor,infd,outfd,inCount,outCount,nChans, + interpFilt, Imp, ImpD, LpScl, Nmult, Nwing); +} +#endif /* WITH_PJ */ + |