aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/main/libresample/src/filterkit.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/main/libresample/src/filterkit.c')
-rw-r--r--trunk/main/libresample/src/filterkit.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/trunk/main/libresample/src/filterkit.c b/trunk/main/libresample/src/filterkit.c
new file mode 100644
index 000000000..bc92285f2
--- /dev/null
+++ b/trunk/main/libresample/src/filterkit.c
@@ -0,0 +1,215 @@
+/**********************************************************************
+
+ resamplesubs.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 file provides Kaiser-windowed low-pass filter support,
+ including a function to create the filter coefficients, and
+ two functions to apply the filter at a particular point.
+
+**********************************************************************/
+
+/* Definitions */
+#include "resample_defs.h"
+
+#include "filterkit.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+/* 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 lrsLpFilter(double c[], int N, double frq, double Beta, int Num)
+{
+ double IBeta, temp, temp1, 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;
+ temp1 = 1.0 - temp*temp;
+ temp1 = (temp1<0? 0: temp1); /* make sure it's not negative since
+ we're taking the square root - this
+ happens on Pentium 4's due to tiny
+ roundoff errors */
+ c[i] *= Izero(Beta*sqrt(temp1)) * IBeta;
+ }
+}
+
+float lrsFilterUp(float Imp[], /* impulse response */
+ float ImpD[], /* impulse response deltas */
+ UWORD Nwing, /* len of one wing of filter */
+ BOOL Interp, /* Interpolate coefs using deltas? */
+ float *Xp, /* Current sample */
+ double Ph, /* Phase */
+ int Inc) /* increment (1 for right wing or -1 for left) */
+{
+ float *Hp, *Hdp = NULL, *End;
+ double a = 0;
+ float v, t;
+
+ Ph *= Npc; /* Npc is number of values per 1/delta in impulse response */
+
+ v = 0.0; /* The output value */
+ Hp = &Imp[(int)Ph];
+ End = &Imp[Nwing];
+ if (Interp) {
+ Hdp = &ImpD[(int)Ph];
+ a = Ph - floor(Ph); /* fractional part of Phase */
+ }
+
+ 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 += (*Hdp)*a; /* t is now interp'd filter coeff */
+ Hdp += Npc; /* Filter coeff differences step */
+ t *= *Xp; /* Mult coeff by input sample */
+ 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 */
+ v += t; /* The filter output */
+ Hp += Npc; /* Filter coeff step */
+ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
+ }
+
+ return v;
+}
+
+float lrsFilterUD(float Imp[], /* impulse response */
+ float ImpD[], /* impulse response deltas */
+ UWORD Nwing, /* len of one wing of filter */
+ BOOL Interp, /* Interpolate coefs using deltas? */
+ float *Xp, /* Current sample */
+ double Ph, /* Phase */
+ int Inc, /* increment (1 for right wing or -1 for left) */
+ double dhb) /* filter sampling period */
+{
+ float a;
+ float *Hp, *Hdp, *End;
+ float v, t;
+ double Ho;
+
+ v = 0.0; /* The output value */
+ Ho = Ph*dhb;
+ 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[(int)Ho]) < End) {
+ t = *Hp; /* Get IR sample */
+ Hdp = &ImpD[(int)Ho]; /* get interp bits from diff table*/
+ a = Ho - floor(Ho); /* a is logically between 0 and 1 */
+ t += (*Hdp)*a; /* t is now interp'd filter coeff */
+ t *= *Xp; /* Mult coeff by input sample */
+ v += t; /* The filter output */
+ Ho += dhb; /* IR step */
+ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
+ }
+ else
+ while ((Hp = &Imp[(int)Ho]) < End) {
+ t = *Hp; /* Get IR sample */
+ t *= *Xp; /* Mult coeff by input sample */
+ v += t; /* The filter output */
+ Ho += dhb; /* IR step */
+ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
+ }
+
+ return v;
+}