home *** CD-ROM | disk | FTP | other *** search
- /*
- * Resampler.cpp
- *
- * Original code from Julius O. Smith III< jos@ccrma.stanford.edu>
- *
- * Copyright (C) Alberto Vigata - January 2000
- *
- * This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
- *
- * FlasKMPEG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * FlasKMPEG 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Make; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
- // Resampler.cpp: implementation of the CResampler class.
- //
- //////////////////////////////////////////////////////////////////////
- #include <windows.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <math.h>
- #include <string.h>
-
- #include "Resampler.h"
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
-
- CResampler::CResampler()
- {
-
- }
-
- CResampler::~CResampler()
- {
-
- }
-
- CResampler::CResampler(
- double factor, /* factor = Sndout/Sndin */
- int nChans, /* number of sound channels (1 or 2) */
- CAsyncBuffer *ABuffer /* Buffer to read data from */
- )
- {
- CResampler::factor =factor;
- CResampler::ABuffer =ABuffer;
- CResampler::nChans =nChans;
- }
-
- int CResampler::read(char *buffer){
-
- ResampleFast((short *)buffer);
-
- return eosFlag ? ((nChans==1)? Nout*2 : Nout*4) : 0;
- }
-
-
- int CResampler::Resample( /* number of output samples returned */
- BOOL interpFilt, /* TRUE means interpolate filter coeffs */
- int fastMode, /* 0 = highest quality, slowest speed */
- BOOL largeFilter /* TRUE means use 65-tap FIR filter */
-
- )
- {
- UHRWORD LpScl; /* Unity-gain scale factor */
- UHRWORD Nwing; /* Filter table size */
- UHRWORD Nmult; /* Filter length for up-conversions */
- HRWORD *Imp=0; /* Filter coefficients */
- HRWORD *ImpD=0; /* ImpD[n] = Imp[n+1]-Imp[n] */
-
- // if (fastMode)
- // return ResampleFast();
-
- #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(interpFilt, Imp, ImpD, LpScl, Nmult, Nwing);
- }
-
- int CResampler::ResampleWithFilter( /* number of output samples returned */
- BOOL interpFilt, /* TRUE means interpolate filter coeffs */
- HRWORD Imp[], HRWORD ImpD[],
- UHRWORD LpScl, UHRWORD Nmult, UHRWORD Nwing)
- {
- URWORD Time, Time2; /* Current time/pos in input sample */
- UHRWORD Xp, Ncreep, Xoff, Xread;
- int OBUFFSIZE = (int)(((double)IBUFFSIZE)*factor+2.0);
- HRWORD X1[IBUFFSIZE]; /* I/O buffers */
- HRWORD X2[IBUFFSIZE]; /* I/O buffers */
- HRWORD *Y1=(HRWORD *)malloc(OBUFFSIZE*sizeof(HRWORD));
- HRWORD *Y2=(HRWORD *)malloc(OBUFFSIZE*sizeof(HRWORD));
-
- UHRWORD Nout, Nx;
- int i, Ycount, last;
-
- int **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(X1, X2, IBUFFSIZE,(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");
-
- write(Nout, Y1, Y2);
-
- printf("."); fflush(stdout);
-
- } while (Ycount<outCount); /* Continue until done */
- free(Y1);
- free(Y2);
- return(Ycount); /* Return # of samples in output file */
- }
- void CResampler::ResampleFastStart(){
- int OBUFFSIZE = (int)(((double)IBUFFSIZE)*factor+2.0);
- Y1=(HRWORD *)malloc(OBUFFSIZE*sizeof(HRWORD));
- Y2=(HRWORD *)malloc(OBUFFSIZE*sizeof(HRWORD));
-
- 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 */
-
- }
- void CResampler::ResampleFastStop(){
- free(Y1);
- free(Y2);
- }
- int CResampler::ResampleFast( short *oData /* number of output samples returned */
- )
- {
-
- readData(X1, X2, IBUFFSIZE,(int)Xread);
-
-
- /* 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");
-
- write(Nout,Y1,Y2,oData);
-
- return 0; /* Return # of samples in output file */
- }
- /* Sampling rate conversion subroutine */
-
- int CResampler::SrcUD(HRWORD X[], HRWORD Y[], double factor, URWORD *Time,
- UHRWORD Nx, UHRWORD Nwing, UHRWORD LpScl,
- HRWORD Imp[], HRWORD ImpD[], BOOL Interp)
- {
- HRWORD *Xp, *Ystart;
- RWORD v;
-
- double dh; /* Step through filter impulse response */
- double dt; /* Step through input signal */
- URWORD endTime; /* When Time reaches EndTime, return to user */
- URWORD 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)*(RWORD)Nx;
- while (*Time < endTime)
- {
- Xp = &X[*Time>>Np]; /* Ptr to current input sample */
- v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (HRWORD)(*Time&Pmask),
- -1, dhb); /* Perform left-wing inner product */
- v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (HRWORD)((-*Time)&Pmask),
- 1, dhb); /* Perform right-wing inner product */
- v >>= Nhg; /* Make guard bits */
- v *= LpScl; /* Normalize for unity filter gain */
- *Y++ = RWORDToHRWORD(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 up-conversion only subroutine;
- * Slightly faster than down-conversion;
- */
- int CResampler::SrcUp(HRWORD X[], HRWORD Y[], double factor, URWORD *Time,
- UHRWORD Nx, UHRWORD Nwing, UHRWORD LpScl,
- HRWORD Imp[], HRWORD ImpD[], BOOL Interp)
- {
- HRWORD *Xp, *Ystart;
- RWORD v;
-
- double dt; /* Step through input signal */
- URWORD dtb; /* Fixed-point version of Dt */
- URWORD 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)*(RWORD)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, (HRWORD)(*Time&Pmask),-1);
- /* Perform right-wing inner product */
- v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1,
- (HRWORD)((-*Time)&Pmask),1);
- v >>= Nhg; /* Make guard bits */
- v *= LpScl; /* Normalize for unity filter gain */
- *Y++ = RWORDToHRWORD(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 using linear interpolation for maximum speed.
- */
- int
- CResampler::SrcLinear(HRWORD X[], HRWORD Y[], double factor, URWORD *Time, UHRWORD Nx)
- {
- HRWORD iconst;
- HRWORD *Xp, *Ystart;
- RWORD v,x1,x2;
-
- double dt; /* Step through input signal */
- URWORD dtb; /* Fixed-point version of Dt */
- URWORD 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)*(RWORD)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++ = RWORDToHRWORD(v,Np); /* Deposit output */
- *Time += dtb; /* Move to next sample by time increment */
- }
- return (Y - Ystart); /* Return number of output samples */
- }
-
- #ifdef DEBUG
- static int pof = 0; /* positive overflow count */
- static int nof = 0; /* negative overflow count */
- #endif
-
- INLINE HRWORD CResampler::RWORDToHRWORD(RWORD v, int scl)
- {
- HRWORD out;
- RWORD llsb = (1<<(scl-1));
- v += llsb; /* round */
- v >>= scl;
- if (v>MAX_HRWORD) {
- #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_HRWORD;
- } else if (v < MIN_HRWORD) {
- #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_HRWORD;
- }
- out = (HRWORD) v;
- return out;
- }
-
- /* CAUTION: Assumes we call this for only one resample job per program run! */
- /* return: 0 - notDone */
- /* >0 - index of last sample */
- int INLINE CResampler::readData(
- HRWORD *outPtr1, /* array receiving left chan samps */
- HRWORD *outPtr2, /* array receiving right chan samps */
- int dataArraySize, /* size of these arrays */
- int Xoff) /* read into input array starting at this index */
- {
- int i, Nsamps,Top,val;
- short *iData;
-
- Nsamps = dataArraySize - Xoff; /* Calculate number of samples to get */
- outPtr1 += Xoff; /* Start at designated sample number */
- outPtr2 += Xoff;
-
- /* NOTE: doesn't return an error code! */
- if(nChans==1)
- eosFlag=ABuffer->ReadBuffer((char **)&iData, Nsamps*2);
- else if(nChans==2)
- eosFlag=ABuffer->ReadBuffer((char **)&iData, Nsamps*4);
-
- // if( (framecount+Nsamps)> inCount) /* if this is the last iteration */
- // Top= inCount - framecount;
- // else
- Top= Nsamps;
-
- if (nChans == 1) {
- for (i = 0; i < Top; i++)
- *outPtr1++ = (HRWORD) iData[i];
- }
- else {
- for (i = 0; i < Top; i++) {
- *outPtr1++ = (HRWORD) iData[(2*i)];
- *outPtr2++ = (HRWORD) iData[(2*i)+1];
- }
- }
-
-
- //framecount += Nsamps;
-
- //if (framecount >= inCount) /* return index of last samp */
- // return (((Nsamps - (framecount - inCount)) - 1) + Xoff);
- //else
- return 0;
- }
-
-
- int CResampler::err_ret(char *s)
- {
- fprintf(stderr,"resample: %s \n\n",s); /* Display error message */
- return -1;
- };
-
- RWORD CResampler::FilterUD( HRWORD Imp[], HRWORD ImpD[],
- UHRWORD Nwing, BOOL Interp,
- HRWORD *Xp, HRWORD Ph, HRWORD Inc, UHRWORD dhb)
- {
- HRWORD a;
- HRWORD *Hp, *Hdp, *End;
- RWORD v, t;
- URWORD Ho;
-
- v=0;
- Ho = (Ph*(URWORD)dhb)>>Np;
- End = &Imp[Nwing];
- if (Inc == 1) /* If doing right wing... */
- { /* ...drop extra coeff, so when Ph is */
- End--; /* 0.5, we don't do too many mult's */
- if (Ph == 0) /* If the phase is zero... */
- Ho += dhb; /* ...then we've already skipped the */
- } /* first sample, so we must also */
- /* skip ahead in Imp[] and ImpD[] */
- if (Interp)
- while ((Hp = &Imp[Ho>>Na]) < End) {
- t = *Hp; /* Get IR sample */
- Hdp = &ImpD[Ho>>Na]; /* get interp (lower Na) bits from diff table*/
- a = Ho & Amask; /* a is logically between 0 and 1 */
- t += (((RWORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
- t *= *Xp; /* Mult coeff by input sample */
- if (t & 1<<(Nhxn-1)) /* Round, if needed */
- t += 1<<(Nhxn-1);
- t >>= Nhxn; /* Leave some guard bits, but come back some */
- v += t; /* The filter output */
- Ho += dhb; /* IR step */
- Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
- }
- else
- while ((Hp = &Imp[Ho>>Na]) < End) {
- t = *Hp; /* Get IR sample */
- t *= *Xp; /* Mult coeff by input sample */
- if (t & 1<<(Nhxn-1)) /* Round, if needed */
- t += 1<<(Nhxn-1);
- t >>= Nhxn; /* Leave some guard bits, but come back some */
- v += t; /* The filter output */
- Ho += dhb; /* IR step */
- Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
- }
- return(v);
- }
-
-
- RWORD CResampler::FilterUp(HRWORD Imp[], HRWORD ImpD[],
- UHRWORD Nwing, BOOL Interp,
- HRWORD *Xp, HRWORD Ph, HRWORD Inc)
- {
- HRWORD *Hp, *Hdp = NULL, *End;
- HRWORD a = 0;
- RWORD v, t;
-
- v=0;
- Hp = &Imp[Ph>>Na];
- End = &Imp[Nwing];
- if (Interp) {
- Hdp = &ImpD[Ph>>Na];
- a = Ph & Amask;
- }
- if (Inc == 1) /* If doing right wing... */
- { /* ...drop extra coeff, so when Ph is */
- End--; /* 0.5, we don't do too many mult's */
- if (Ph == 0) /* If the phase is zero... */
- { /* ...then we've already skipped the */
- Hp += Npc; /* first sample, so we must also */
- Hdp += Npc; /* skip ahead in Imp[] and ImpD[] */
- }
- }
- if (Interp)
- while (Hp < End) {
- t = *Hp; /* Get filter coeff */
- t += (((RWORD)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
- Hdp += Npc; /* Filter coeff differences step */
- t *= *Xp; /* Mult coeff by input sample */
- if (t & (1<<(Nhxn-1))) /* Round, if needed */
- t += (1<<(Nhxn-1));
- t >>= Nhxn; /* Leave some guard bits, but come back some */
- v += t; /* The filter output */
- Hp += Npc; /* Filter coeff step */
- Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
- }
- else
- while (Hp < End) {
- t = *Hp; /* Get filter coeff */
- t *= *Xp; /* Mult coeff by input sample */
- if (t & (1<<(Nhxn-1))) /* Round, if needed */
- t += (1<<(Nhxn-1));
- t >>= Nhxn; /* Leave some guard bits, but come back some */
- v += t; /* The filter output */
- Hp += Npc; /* Filter coeff step */
- Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
- }
- return(v);
- }
- void INLINE CResampler::write(int samples, HRWORD *Y1, HRWORD *Y2, short *oData){
- //writes interleaved audio
- int i;
- if (nChans==1) {
- for (i = 0; i < samples; i++)
- oData[i] = Y1[i];
- } else {
- for (i = 0; i < samples; i++) {
- oData[2*i] = Y1[i];
- oData[(2*i)+1] = Y2[i];
- }
- }
- }
-
- void INLINE CResampler::write(int samples, HRWORD *Y1, HRWORD *Y2)
- {
- }
-