/********************************************************************** resample.c Real-time library interface by Dominic Mazzoni Based on resample-1.7: http://www-ccrma.stanford.edu/~jos/resample/ License: LGPL - see the file LICENSE.txt for more information This is the main source file, implementing all of the API functions and handling all of the buffering logic. **********************************************************************/ /* External interface */ #include "../include/libresample.h" /* Definitions */ #include "resample_defs.h" #include "filterkit.h" #include #include #include #include typedef struct { float *Imp; float *ImpD; float LpScl; UWORD Nmult; UWORD Nwing; double minFactor; double maxFactor; UWORD XSize; float *X; UWORD Xp; /* Current "now"-sample pointer for input */ UWORD Xread; /* Position to put new samples */ UWORD Xoff; UWORD YSize; float *Y; UWORD Yp; double Time; } rsdata; void *resample_dup(const void * handle) { const rsdata *cpy = (const rsdata *)handle; rsdata *hp = (rsdata *)malloc(sizeof(rsdata)); hp->minFactor = cpy->minFactor; hp->maxFactor = cpy->maxFactor; hp->Nmult = cpy->Nmult; hp->LpScl = cpy->LpScl; hp->Nwing = cpy->Nwing; hp->Imp = (float *)malloc(hp->Nwing * sizeof(float)); memcpy(hp->Imp, cpy->Imp, hp->Nwing * sizeof(float)); hp->ImpD = (float *)malloc(hp->Nwing * sizeof(float)); memcpy(hp->ImpD, cpy->ImpD, hp->Nwing * sizeof(float)); hp->Xoff = cpy->Xoff; hp->XSize = cpy->XSize; hp->X = (float *)malloc((hp->XSize + hp->Xoff) * sizeof(float)); memcpy(hp->X, cpy->X, (hp->XSize + hp->Xoff) * sizeof(float)); hp->Xp = cpy->Xp; hp->Xread = cpy->Xread; hp->YSize = cpy->YSize; hp->Y = (float *)malloc(hp->YSize * sizeof(float)); memcpy(hp->Y, cpy->Y, hp->YSize * sizeof(float)); hp->Yp = cpy->Yp; hp->Time = cpy->Time; return (void *)hp; } void *resample_open(int highQuality, double minFactor, double maxFactor) { double *Imp64; double Rolloff, Beta; rsdata *hp; UWORD Xoff_min, Xoff_max; int i; /* Just exit if we get invalid factors */ if (minFactor <= 0.0 || maxFactor <= 0.0 || maxFactor < minFactor) { #if DEBUG fprintf(stderr, "libresample: " "minFactor and maxFactor must be positive real numbers,\n" "and maxFactor should be larger than minFactor.\n"); #endif return 0; } hp = (rsdata *)malloc(sizeof(rsdata)); hp->minFactor = minFactor; hp->maxFactor = maxFactor; if (highQuality) hp->Nmult = 35; else hp->Nmult = 11; hp->LpScl = 1.0; hp->Nwing = Npc*(hp->Nmult-1)/2; /* # of filter coeffs in right wing */ Rolloff = 0.90; Beta = 6; Imp64 = (double *)malloc(hp->Nwing * sizeof(double)); lrsLpFilter(Imp64, hp->Nwing, 0.5*Rolloff, Beta, Npc); hp->Imp = (float *)malloc(hp->Nwing * sizeof(float)); hp->ImpD = (float *)malloc(hp->Nwing * sizeof(float)); for(i=0; iNwing; i++) hp->Imp[i] = Imp64[i]; /* Storing deltas in ImpD makes linear interpolation of the filter coefficients faster */ for (i=0; iNwing-1; i++) hp->ImpD[i] = hp->Imp[i+1] - hp->Imp[i]; /* Last coeff. not interpolated */ hp->ImpD[hp->Nwing-1] = - hp->Imp[hp->Nwing-1]; free(Imp64); /* Calc reach of LP filter wing (plus some creeping room) */ Xoff_min = ((hp->Nmult+1)/2.0) * MAX(1.0, 1.0/minFactor) + 10; Xoff_max = ((hp->Nmult+1)/2.0) * MAX(1.0, 1.0/maxFactor) + 10; hp->Xoff = MAX(Xoff_min, Xoff_max); /* Make the inBuffer size at least 4096, but larger if necessary in order to store the minimum reach of the LP filter and then some. Then allocate the buffer an extra Xoff larger so that we can zero-pad up to Xoff zeros at the end when we reach the end of the input samples. */ hp->XSize = MAX(2*hp->Xoff+10, 4096); hp->X = (float *)malloc((hp->XSize + hp->Xoff) * sizeof(float)); hp->Xp = hp->Xoff; hp->Xread = hp->Xoff; /* Need Xoff zeros at begining of X buffer */ for(i=0; iXoff; i++) hp->X[i]=0; /* Make the outBuffer long enough to hold the entire processed output of one inBuffer */ hp->YSize = (int)(((double)hp->XSize)*maxFactor+2.0); hp->Y = (float *)malloc(hp->YSize * sizeof(float)); hp->Yp = 0; hp->Time = (double)hp->Xoff; /* Current-time pointer for converter */ return (void *)hp; } int resample_get_filter_width(const void *handle) { const rsdata *hp = (const rsdata *)handle; return hp->Xoff; } int resample_process(void *handle, double factor, float *inBuffer, int inBufferLen, int lastFlag, int *inBufferUsed, /* output param */ float *outBuffer, int outBufferLen) { rsdata *hp = (rsdata *)handle; float *Imp = hp->Imp; float *ImpD = hp->ImpD; float LpScl = hp->LpScl; UWORD Nwing = hp->Nwing; BOOL interpFilt = FALSE; /* TRUE means interpolate filter coeffs */ int outSampleCount; UWORD Nout, Ncreep, Nreuse; int Nx; int i, len; #if DEBUG fprintf(stderr, "resample_process: in=%d, out=%d lastFlag=%d\n", inBufferLen, outBufferLen, lastFlag); #endif /* Initialize inBufferUsed and outSampleCount to 0 */ *inBufferUsed = 0; outSampleCount = 0; if (factor < hp->minFactor || factor > hp->maxFactor) { #if DEBUG fprintf(stderr, "libresample: factor %f is not between " "minFactor=%f and maxFactor=%f", factor, hp->minFactor, hp->maxFactor); #endif return -1; } /* Start by copying any samples still in the Y buffer to the output buffer */ if (hp->Yp && (outBufferLen-outSampleCount)>0) { len = MIN(outBufferLen-outSampleCount, hp->Yp); for(i=0; iY[i]; outSampleCount += len; for(i=0; iYp-len; i++) hp->Y[i] = hp->Y[i+len]; hp->Yp -= len; } /* If there are still output samples left, return now - we need the full output buffer available to us... */ if (hp->Yp) return outSampleCount; /* Account for increased filter gain when using factors less than 1 */ if (factor < 1) LpScl = LpScl*factor; for(;;) { /* This is the maximum number of samples we can process per loop iteration */ #ifdef DEBUG printf("XSize: %d Xoff: %d Xread: %d Xp: %d lastFlag: %d\n", hp->XSize, hp->Xoff, hp->Xread, hp->Xp, lastFlag); #endif /* Copy as many samples as we can from the input buffer into X */ len = hp->XSize - hp->Xread; if (len >= (inBufferLen - (*inBufferUsed))) len = (inBufferLen - (*inBufferUsed)); for(i=0; iX[hp->Xread + i] = inBuffer[(*inBufferUsed) + i]; *inBufferUsed += len; hp->Xread += len; if (lastFlag && (*inBufferUsed == inBufferLen)) { /* If these are the last samples, zero-pad the end of the input buffer and make sure we process all the way to the end */ Nx = hp->Xread - hp->Xoff; for(i=0; iXoff; i++) hp->X[hp->Xread + i] = 0; } else Nx = hp->Xread - 2 * hp->Xoff; #ifdef DEBUG fprintf(stderr, "new len=%d Nx=%d\n", len, Nx); #endif if (Nx <= 0) break; /* Resample stuff in input buffer */ if (factor >= 1) { /* SrcUp() is faster if we can use it */ Nout = lrsSrcUp(hp->X, hp->Y, factor, &hp->Time, Nx, Nwing, LpScl, Imp, ImpD, interpFilt); } else { Nout = lrsSrcUD(hp->X, hp->Y, factor, &hp->Time, Nx, Nwing, LpScl, Imp, ImpD, interpFilt); } #ifdef DEBUG printf("Nout: %d\n", Nout); #endif hp->Time -= Nx; /* Move converter Nx samples back in time */ hp->Xp += Nx; /* Advance by number of samples processed */ /* Calc time accumulation in Time */ Ncreep = (int)(hp->Time) - hp->Xoff; if (Ncreep) { hp->Time -= Ncreep; /* Remove time accumulation */ hp->Xp += Ncreep; /* and add it to read pointer */ } /* Copy part of input signal that must be re-used */ Nreuse = hp->Xread - (hp->Xp - hp->Xoff); for (i=0; iX[i] = hp->X[i + (hp->Xp - hp->Xoff)]; #ifdef DEBUG printf("New Xread=%d\n", Nreuse); #endif hp->Xread = Nreuse; /* Pos in input buff to read new data into */ hp->Xp = hp->Xoff; /* Check to see if output buff overflowed (shouldn't happen!) */ if (Nout > hp->YSize) { #ifdef DEBUG printf("Nout: %d YSize: %d\n", Nout, hp->YSize); #endif fprintf(stderr, "libresample: Output array overflow!\n"); return -1; } hp->Yp = Nout; /* Copy as many samples as possible to the output buffer */ if (hp->Yp && (outBufferLen-outSampleCount)>0) { len = MIN(outBufferLen-outSampleCount, hp->Yp); for(i=0; iY[i]; outSampleCount += len; for(i=0; iYp-len; i++) hp->Y[i] = hp->Y[i+len]; hp->Yp -= len; } /* If there are still output samples left, return now, since we need the full output buffer available */ if (hp->Yp) break; } return outSampleCount; } void resample_close(void *handle) { rsdata *hp = (rsdata *)handle; free(hp->X); free(hp->Y); free(hp->Imp); free(hp->ImpD); free(hp); }