summaryrefslogtreecommitdiff
path: root/third_party/resample/src/filterkit.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/resample/src/filterkit.c')
-rw-r--r--third_party/resample/src/filterkit.c631
1 files changed, 0 insertions, 631 deletions
diff --git a/third_party/resample/src/filterkit.c b/third_party/resample/src/filterkit.c
deleted file mode 100644
index 5171b5ea..00000000
--- a/third_party/resample/src/filterkit.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * filterkit.c (library "filterkit.a"): Kaiser-windowed low-pass filter support.
- */
-
-/* filterkit.c
- *
- * LpFilter() - Calculates the filter coeffs for a Kaiser-windowed low-pass
- * filter with a given roll-off frequency. These coeffs
- * are stored into a array of doubles.
- * writeFilter() - Writes a filter to a file.
- * makeFilter() - Calls LpFilter() to create a filter, then scales the double
- * coeffs into an array of half words.
- * readFilter() - Reads a filter from a file.
- * FilterUp() - Applies a filter to a given sample when up-converting.
- * FilterUD() - Applies a filter to a given sample when up- or down-
- * converting.
- * initZerox() - Initialization routine for the zerox() function. Must
- * be called before zerox() is called. This routine loads
- * the correct filter so zerox() can use it.
- * zerox() - Given a pointer into a sample, finds a zero-crossing on the
- * interval [pointer-1:pointer+2] by iteration.
- * Query() - Ask the user for a yes/no question with prompt, default,
- * and optional help.
- * GetUShort() - Ask the user for a unsigned short with prompt, default,
- * and optional help.
- * GetDouble() - Ask the user for a double with prompt, default, and
- * optional help.
- * GetString() - Ask the user for a string with prompt, default, and
- * optional help.
- */
-
-#include "resample.h"
-#include "filterkit.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-
-/*
- * Getstr() will print the passed "prompt" as a message to the user, and
- * wait for the user to type an input string. The string is
- * then copied into "answer". If the user types just a carriage
- * return, then the string "defaultAnswer" is copied into "answer".
- * ???
- * "Answer" and "defaultAnswer" may be the same string, in which case,
- * the defaultAnswer value will be the original contents of "answer".
- * ???
- */
-static void getstr(char *prompt, char *defaultAnswer, char *answer)
-{
- char *p,s[200];
-
- printf("%s (defaultAnswer = %s):",prompt,defaultAnswer);
- strcpy(s, prompt);
- if (!(*s))
- strcpy(s, "input:");
- p = s;
- while (*p && *p != '(')
- p++;
- p--;
- while (*p == ' ')
- p--;
- *(++p) = '\0';
-
- /* gets(answer); */
- fgets(answer,sizeof(answer),stdin);
- answer[strlen(answer)-1] = '\0';
-
- if (answer[0] == '\0') {
- strcpy(answer, defaultAnswer);
- printf("\t%s = %s\n",s,answer);
- } else {
- printf("\t%s set to %s\n",s,answer);
- }
-}
-
-
-/* LpFilter()
- *
- * reference: "Digital Filters, 2nd edition"
- * R.W. Hamming, pp. 178-179
- *
- * Izero() computes the 0th order modified bessel function of the first kind.
- * (Needed to compute Kaiser window).
- *
- * LpFilter() computes the coeffs of a Kaiser-windowed low pass filter with
- * the following characteristics:
- *
- * c[] = array in which to store computed coeffs
- * frq = roll-off frequency of filter
- * N = Half the window length in number of coeffs
- * Beta = parameter of Kaiser window
- * Num = number of coeffs before 1/frq
- *
- * Beta trades the rejection of the lowpass filter against the transition
- * width from passband to stopband. Larger Beta means a slower
- * transition and greater stopband rejection. See Rabiner and Gold
- * (Theory and Application of DSP) under Kaiser windows for more about
- * Beta. The following table from Rabiner and Gold gives some feel
- * for the effect of Beta:
- *
- * All ripples in dB, width of transition band = D*N where N = window length
- *
- * BETA D PB RIP SB RIP
- * 2.120 1.50 +-0.27 -30
- * 3.384 2.23 0.0864 -40
- * 4.538 2.93 0.0274 -50
- * 5.658 3.62 0.00868 -60
- * 6.764 4.32 0.00275 -70
- * 7.865 5.0 0.000868 -80
- * 8.960 5.7 0.000275 -90
- * 10.056 6.4 0.000087 -100
- */
-
-
-#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */
-
-static double Izero(double x)
-{
- double sum, u, halfx, temp;
- int n;
-
- sum = u = n = 1;
- halfx = x/2.0;
- do {
- temp = halfx/(double)n;
- n += 1;
- temp *= temp;
- u *= temp;
- sum += u;
- } while (u >= IzeroEPSILON*sum);
- return(sum);
-}
-
-
-void LpFilter(double c[], int N, double frq, double Beta, int Num)
-{
- double IBeta, temp, inm1;
- int i;
-
- /* Calculate ideal lowpass filter impulse response coefficients: */
- c[0] = 2.0*frq;
- for (i=1; i<N; i++) {
- temp = PI*(double)i/(double)Num;
- c[i] = sin(2.0*temp*frq)/temp; /* Analog sinc function, cutoff = frq */
- }
-
- /*
- * Calculate and Apply Kaiser window to ideal lowpass filter.
- * Note: last window value is IBeta which is NOT zero.
- * You're supposed to really truncate the window here, not ramp
- * it to zero. This helps reduce the first sidelobe.
- */
- IBeta = 1.0/Izero(Beta);
- inm1 = 1.0/((double)(N-1));
- for (i=1; i<N; i++) {
- temp = (double)i * inm1;
- c[i] *= Izero(Beta*sqrt(1.0-temp*temp)) * IBeta;
- }
-}
-
-
-/* Write a filter to a file
- * Filter file format:
- * file name: "F" Nmult "T" Nhc ".filter"
- * 1st line: the string "ScaleFactor" followed by its value.
- * 2nd line: the string "Length" followed by Nwing's value.
- * 3rd line: the string "Nmult" followed by Nmult's value.
- * 4th line: the string "Coeffs:" on a separate line.
- * following lines: Nwing number of 16-bit impulse response values
- * in the right wing of the impulse response (the Imp[] array).
- * (Nwing is equal to Npc*(Nmult+1)/2+1, where Npc is defined in the
- * file "resample.h".) Each coefficient is on a separate line.
- * next line: the string "Differences:" on a separate line.
- * following lines: Nwing number of 16-bit impulse-response
- * successive differences: ImpD[i] = Imp[i+1] - Imp[i].
- * ERROR codes:
- * 0 - no error
- * 1 - could not open file
- */
-
-int writeFilter(HWORD Imp[], HWORD ImpD[], UHWORD LpScl, UHWORD Nmult,
- UHWORD Nwing)
-{
- char fname[30];
- FILE *fp;
- int i;
-
- sprintf(fname, "F%dT%d.filter", Nmult, Nhc);
- fp = fopen(fname, "w");
- if (!fp)
- return(1);
- fprintf(fp, "ScaleFactor %d\n", LpScl);
- fprintf(fp, "Length %d\n", Nwing);
- fprintf(fp, "Nmult %d\n", Nmult);
- fprintf(fp, "Coeffs:\n");
- for (i=0; i<Nwing; i++) /* Put array of 16-bit filter coefficients */
- fprintf(fp, "%d\n", Imp[i]);
- fprintf(fp, "Differences:\n");
- for (i=0; i<Nwing; i++) /* Put array of 16-bit filter coeff differences */
- fprintf(fp, "%d\n", ImpD[i]);
- fclose(fp);
- printf("Wrote filter file '%s' in current directory.\n",fname);
- return(0);
-}
-
-
-/* ERROR return codes:
- * 0 - no error
- * 1 - Nwing too large (Nwing is > MAXNWING)
- * 2 - Froll is not in interval [0:1)
- * 3 - Beta is < 1.0
- * 4 - LpScl will not fit in 16-bits
- *
- * Made following global to avoid stack problems in Sun3 compilation: */
-
-#define MAXNWING 8192
-static double ImpR[MAXNWING];
-
-int makeFilter(HWORD Imp[], HWORD ImpD[], UHWORD *LpScl, UHWORD Nwing,
- double Froll, double Beta)
-{
- double DCgain, Scl, Maxh;
- HWORD Dh;
- int i, temp;
-
- if (Nwing > MAXNWING) /* Check for valid parameters */
- return(1);
- if ((Froll<=0) || (Froll>1))
- return(2);
- if (Beta < 1)
- return(3);
-
- /*
- * Design Kaiser-windowed sinc-function low-pass filter
- */
- LpFilter(ImpR, (int)Nwing, 0.5*Froll, Beta, Npc);
-
- /* Compute the DC gain of the lowpass filter, and its maximum coefficient
- * magnitude. Scale the coefficients so that the maximum coeffiecient just
- * fits in Nh-bit fixed-point, and compute LpScl as the NLpScl-bit (signed)
- * scale factor which when multiplied by the output of the lowpass filter
- * gives unity gain. */
- DCgain = 0;
- Dh = Npc; /* Filter sampling period for factors>=1 */
- for (i=Dh; i<Nwing; i+=Dh)
- DCgain += ImpR[i];
- DCgain = 2*DCgain + ImpR[0]; /* DC gain of real coefficients */
-
- for (Maxh=i=0; i<Nwing; i++)
- Maxh = MAX(Maxh, fabs(ImpR[i]));
-
- Scl = ((1<<(Nh-1))-1)/Maxh; /* Map largest coeff to 16-bit maximum */
- temp = fabs((1<<(NLpScl+Nh))/(DCgain*Scl));
- if (temp >= 1<<16)
- return(4); /* Filter scale factor overflows UHWORD */
- *LpScl = temp;
-
- /* Scale filter coefficients for Nh bits and convert to integer */
- if (ImpR[0] < 0) /* Need pos 1st value for LpScl storage */
- Scl = -Scl;
- for (i=0; i<Nwing; i++) /* Scale them */
- ImpR[i] *= Scl;
- for (i=0; i<Nwing; i++) /* Round them */
- Imp[i] = ImpR[i] + 0.5;
-
- /* ImpD makes linear interpolation of the filter coefficients faster */
- for (i=0; i<Nwing-1; i++)
- ImpD[i] = Imp[i+1] - Imp[i];
- ImpD[Nwing-1] = - Imp[Nwing-1]; /* Last coeff. not interpolated */
-
- return(0);
-}
-
-
-/* Read-in a filter
- * Filter file format:
- * file name: "F" Nmult "T" Nhc ".filter"
- * 1st line: the string "ScaleFactor" followed by its value.
- * 2nd line: the string "Length" followed by Nwing's value.
- * 3rd line: the string "Coeffs:" on separate line.
- * Nwing number of 16-bit impulse response values in the right
- * wing of the impulse response. (Length=Npc*(Nmult+1)/2+1,
- * where originally Npc=2^9, and Nmult=13.) Each on separate line.
- * The string "Differences:" on separate line.
- * Nwing number of 16-bit impulse-response successive differences:
- * ImpDiff[i] = Imp[i+1] - Imp[i].
- *
- * ERROR return codes:
- * 0 - no error
- * 1 - file not found
- * 2 - invalid ScaleFactor in file
- * 3 - invalid Length in file
- * 4 - invalid Nmult in file
- */
-int readFilter(char *filterFile, HWORD **ImpP, HWORD **ImpDP, UHWORD *LpScl,
- UHWORD *Nmult, UHWORD *Nwing)
-{
- char *fname;
- FILE *fp;
- int i, temp;
- HWORD *Imp,*ImpD;
-
- if (!filterFile || !(*filterFile)) {
- fname = (char *) malloc(32);
- if ((*Nmult)>0 && ((*Nmult)&1))
- sprintf(fname, "F%dT%d.filter", *Nmult, Nhc);
- else
- sprintf(fname, "F65dT%d.filter", Nhc);
- } else
- fname = filterFile;
-
- fp = fopen(fname, "r");
- if (fp == NULL)
- return(1);
-
- fscanf(fp, "ScaleFactor ");
- if (1 != fscanf(fp,"%d",&temp))
- return(2);
- *LpScl = temp;
-
- fscanf(fp, "\nLength ");
- if (1 != fscanf(fp,"%d",&temp))
- return(3);
- *Nwing = temp;
-
- fscanf(fp, "\nNmult ");
- if (1 != fscanf(fp,"%d",&temp))
- return(4);
- *Nmult = temp;
-
- Imp = (HWORD *) malloc(*Nwing * sizeof(HWORD));
-
- fscanf(fp, "\nCoeffs:\n");
- for (i=0; i<*Nwing; i++) { /* Get array of 16-bit filter coefficients */
- fscanf(fp, "%d\n", &temp);
- Imp[i] = temp;
- }
-
- ImpD = (HWORD *) malloc(*Nwing * sizeof(HWORD));
-
- fscanf(fp, "\nDifferences:\n");
- for (i=0; i<*Nwing; i++) { /* Get array of 16bit filter coeff differences */
- fscanf(fp, "%d\n", &temp);
- ImpD[i] = temp;
- }
-
- fclose(fp);
- if (!filterFile || !(*filterFile))
- free(fname);
- *ImpP = Imp;
- *ImpDP = ImpD;
- return(0);
-}
-
-
-WORD FilterUp(HWORD Imp[], HWORD ImpD[],
- UHWORD Nwing, BOOL Interp,
- HWORD *Xp, HWORD Ph, HWORD Inc)
-{
- HWORD *Hp, *Hdp = NULL, *End;
- HWORD a = 0;
- WORD 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 += (((WORD)*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);
-}
-
-WORD FilterUD( HWORD Imp[], HWORD ImpD[],
- UHWORD Nwing, BOOL Interp,
- HWORD *Xp, HWORD Ph, HWORD Inc, UHWORD dhb)
-{
- HWORD a;
- HWORD *Hp, *Hdp, *End;
- WORD v, t;
- UWORD Ho;
-
- v=0;
- Ho = (Ph*(UWORD)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 += (((WORD)*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);
-}
-
-/*
- * double zerox(Data, Factor)
- * HWORD *Data;
- * double Factor;
- * Given a pointer into a sound sample, this function uses a low-pass
- * filter to estimate the x coordinate of the zero-crossing which must ocurr
- * between Data[0] and Data[1]. This value is returned as the value of the
- * function. A return value of -100 indicates there was no zero-crossing in
- * the x interval [-1,2]. Factor is the resampling factor: Rate(out) /
- * Rate(in). Nmult (which determines which filter is used) is passed the
- * zerox's initialization routine: initZerox(Nmult)
- * UHWORD Nmult;
- */
-
-static UHWORD LpScl, Nmult, Nwing;
-static HWORD *Imp;
-static HWORD *ImpD;
-
-/* ERROR return values:
- * 0 - no error
- * 1 - Nmult is even (should be odd)
- * 2 - filter file not found
- * 3 - invalid ScaleFactor in input file
- * 4 - invalid Length in file
- * 5 - invalid Nmult in file
- */
-int initZerox(UHWORD tempNmult)
-{
- int err;
-
- /* Check for illegal input values */
- if (!(tempNmult % 2))
- return(1);
- err = readFilter(NULL, (HWORD **)&Imp, (HWORD **)&ImpD,
- &LpScl, &tempNmult, &Nwing);
- if (err)
- return(1+err);
-
- Nmult = tempNmult;
- return(0);
-}
-
-#define MAXITER 64
-#define ZeroxEPSILON (1E-4)
-#define ZeroxMAXERROR (5.0)
-
-double zerox(HWORD *Data, double Factor)
-{
- double x, out;
- double lo, hi;
- double dh;
- UWORD dhb;
- WORD v;
- int i;
-
- if (!Data[0])
- return (0.0);
- if (!Data[1])
- return (1.0);
-
- if (Data[0] < Data[1])
- {
- lo = -1.0;
- hi = 2.0;
- }
- else
- {
- lo = 2.0;
- hi = -1.0;
- }
- dh = (Factor<1) ? (Factor*Npc) : (Npc);
- dhb = dh * (1<<Na) + 0.5;
-
- for (i=0; i<MAXITER; i++)
- {
- x = (hi+lo)/2.0;
- v = FilterUD(Imp,ImpD,Nwing,TRUE,Data, (HWORD)(x*Pmask), -1,dhb);
- v += FilterUD(Imp,ImpD,Nwing,TRUE,Data+1,(HWORD)((1-x)*Pmask), 1,dhb);
- v >>= Nhg;
- v *= LpScl;
- out = (double)v / (double)(1<<NLpScl);
- if (out < 0.0)
- lo = x;
- else
- hi = x;
- if (ABS(out) <= ZeroxEPSILON)
- return(x);
- }
- printf("|ZeroX Error| x:%g, \t Data[x]:%d, \t Data[x+1]:%d\n",
- x, *Data, *(Data+1));
- printf("|\tABS(out):%g \t EPSILON:%g\n", ABS(out),ZeroxEPSILON);
- if (ABS(out) <= ZeroxMAXERROR)
- return(x);
- return(-100.0);
-}
-
-
-BOOL Query(char *prompt, BOOL deflt, char *help)
-{
- char s[80];
-
- while (TRUE)
- {
- sprintf(s,"\n%s%s", prompt, (*help) ? " (Type ? for help)" : "");
- getstr(s,(deflt)?"yes":"no",s);
- if (*s=='?' && *help)
- printf(help);
- if (*s=='Y' || *s=='y')
- return(TRUE);
- if (*s=='N' || *s=='n')
- return(FALSE);
- }
-}
-
-
-char *GetString(char *prompt, char *deflt, char *help)
-{
- static char s[200];
-
- while (TRUE)
- {
- sprintf(s,"\n%s%s",prompt, (*help) ? " (Type ? for Help)" : "");
- getstr(s,deflt,s);
- if (*s=='?' && *help)
- printf(help);
- else
- return(s);
- }
-}
-
-
-double GetDouble(char *title, double deflt, char *help)
-{
- char s[80],sdeflt[80];
- double newval;
-
- while (TRUE)
- {
- sprintf(s,"\n%s:%s",title, (*help) ? " (Type ? for Help)" : "");
- sprintf(sdeflt,"%g",deflt);
- getstr(s,sdeflt,s);
- if (*s=='?' && *help)
- printf(help);
- else
- {
- if (!sscanf(s,"%lf",&newval))
- return(deflt);
- return(newval);
- }
- }
-}
-
-
-unsigned short GetUShort(char *title, unsigned short deflt, char *help)
-{
- char s[80],sdeflt[80];
- int newval;
-
- while (TRUE)
- {
- sprintf(s,"\n%s:%s",title, (*help) ? " (Type ? for Help)" : "");
- sprintf(sdeflt,"%d",deflt);
- getstr(s,sdeflt,s);
- if (*s=='?' && *help)
- printf(help);
- else
- {
- if (!sscanf(s,"%d",&newval))
- printf("unchanged (%d)\n",(newval=deflt));
- if (newval < 0)
- printf("Error: value must be >= zero\n");
- else
- return(newval);
- }
- }
-}