aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/main/libresample/src/resample.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/main/libresample/src/resample.c')
-rw-r--r--trunk/main/libresample/src/resample.c347
1 files changed, 347 insertions, 0 deletions
diff --git a/trunk/main/libresample/src/resample.c b/trunk/main/libresample/src/resample.c
new file mode 100644
index 000000000..85ff75f76
--- /dev/null
+++ b/trunk/main/libresample/src/resample.c
@@ -0,0 +1,347 @@
+/**********************************************************************
+
+ 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 <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+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 defined(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; i<hp->Nwing; i++)
+ hp->Imp[i] = Imp64[i];
+
+ /* Storing deltas in ImpD makes linear interpolation
+ of the filter coefficients faster */
+ for (i=0; i<hp->Nwing-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; i<hp->Xoff; 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 defined(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 defined(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; i<len; i++)
+ outBuffer[outSampleCount+i] = hp->Y[i];
+ outSampleCount += len;
+ for(i=0; i<hp->Yp-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 */
+
+ #if defined(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; i<len; i++)
+ hp->X[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; i<hp->Xoff; i++)
+ hp->X[hp->Xread + i] = 0;
+ }
+ else
+ Nx = hp->Xread - 2 * hp->Xoff;
+
+ #if defined(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);
+ }
+
+ #if defined(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; i<Nreuse; i++)
+ hp->X[i] = hp->X[i + (hp->Xp - hp->Xoff)];
+
+ #if defined(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) {
+ #if defined(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; i<len; i++)
+ outBuffer[outSampleCount+i] = hp->Y[i];
+ outSampleCount += len;
+ for(i=0; i<hp->Yp-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);
+}
+