shithub: sox

Download patch

ref: 1f3679dfcf9f07dda9a568e62e8004bebd1df4cd
parent: 18bb7971d61b882545c0a0623caf799bd96de464
author: robs <robs>
date: Tue Jun 10 13:54:22 EDT 2008

tune filters

--- a/src/effects_i.c
+++ b/src/effects_i.c
@@ -206,3 +206,14 @@
     }
     return NULL;
 }
+
+double bessel_I_0(double x)
+{
+  double term = 1, sum = 1, last_sum, x2 = x / 2;
+  int i = 1;
+  do {
+    double y = x2 / i++;
+    last_sum = sum, sum += term *= y * y;
+  } while (sum != last_sum);
+  return sum;
+}
--- a/src/filter.c
+++ b/src/filter.c
@@ -19,8 +19,7 @@
  *
  *
  * REMARKS: (Stan Brooks speaking)
- * This code is heavily based on the resample.c code which was
- * apparently itself a rewrite (by Lance Norskog?) of code originally
+ * This code is a rewrite of filterkit.c from the `resample' package
  * by Julius O. Smith, now distributed under the LGPL.
  */
 
@@ -31,6 +30,7 @@
 
 #define ISCALE 0x10000
 #define BUFFSIZE 8192
+#define MAXNWING  (80<<7)
 
 /* Private data for Lerp via LCM file */
 typedef struct {
@@ -45,9 +45,138 @@
         double *X, *Y;/* I/O buffers */
 } priv_t;
 
-/* lsx_makeFilter() declared in resample.c */
-extern int
-lsx_makeFilter(double Fp[], long Nwing, double Froll, double Beta, long Num, int Normalize);
+/* lsx_makeFilter is used by resample.c */
+int lsx_makeFilter(double Fp[], long Nwing, double Froll, double Beta, long Num, int Normalize);
+
+/* 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;
+   long 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);
+}
+
+static void LpFilter(double *c, long N, double frq, double Beta, long Num)
+{
+   long i;
+
+   /* Calculate filter coeffs: */
+   c[0] = frq;
+   for (i=1; i<N; i++) {
+      double x = M_PI*(double)i/(double)(Num);
+      c[i] = sin(x*frq)/x;
+   }
+
+   if (Beta>2) { /* Apply Kaiser window to filter coeffs: */
+      double IBeta = 1.0/Izero(Beta);
+      for (i=1; i<N; i++) {
+         double x = (double)i / (double)(N);
+         c[i] *= Izero(Beta*sqrt(1.0-x*x)) * IBeta;
+      }
+   } else { /* Apply Nuttall window: */
+      for(i = 0; i < N; i++) {
+         double x = M_PI*i / N;
+         c[i] *= 0.36335819 + 0.4891775*cos(x) + 0.1365995*cos(2*x) + 0.0106411*cos(3*x);
+      }
+   }
+}
+
+int lsx_makeFilter(double Imp[], long Nwing, double Froll, double Beta,
+               long Num, int Normalize)
+{
+   double *ImpR;
+   long Mwing, i;
+
+   if (Nwing > MAXNWING)                      /* Check for valid parameters */
+      return(-1);
+   if ((Froll<=0) || (Froll>1))
+      return(-2);
+
+   /* it does help accuracy a bit to have the window stop at
+    * a zero-crossing of the sinc function */
+   Mwing = floor((double)Nwing/(Num/Froll))*(Num/Froll) +0.5;
+   if (Mwing==0)
+      return(-4);
+
+   ImpR = lsx_malloc(sizeof(double) * Mwing);
+
+   /* Design a Nuttall or Kaiser windowed Sinc low-pass filter */
+   LpFilter(ImpR, Mwing, Froll, Beta, Num);
+
+   if (Normalize) { /* 'correct' the DC gain of the lowpass filter */
+      long Dh;
+      double DCgain;
+      DCgain = 0;
+      Dh = Num;                  /* Filter sampling period for factors>=1 */
+      for (i=Dh; i<Mwing; i+=Dh)
+         DCgain += ImpR[i];
+      DCgain = 2*DCgain + ImpR[0];    /* DC gain of real coefficients */
+      sox_debug("DCgain err=%.12f",DCgain-1.0);
+
+      DCgain = 1.0/DCgain;
+      for (i=0; i<Mwing; i++)
+         Imp[i] = ImpR[i]*DCgain;
+
+   } else {
+      for (i=0; i<Mwing; i++)
+         Imp[i] = ImpR[i];
+   }
+   free(ImpR);
+   for (i=Mwing; i<=Nwing; i++) Imp[i] = 0;
+   /* Imp[Mwing] and Imp[-1] needed for quadratic interpolation */
+   Imp[-1] = Imp[1];
+
+   return(Mwing);
+}
 
 static void FiltWin(priv_t * f, long Nx);
 
--- a/src/polyphas.c
+++ b/src/polyphas.c
@@ -621,7 +621,7 @@
   "       -width n       window width in samples [default 1024]\n"
   "\n"
   "       -cutoff float  frequency cutoff for base bandwidth [default 0.95]",
-  SOX_EFF_RATE,
+  SOX_EFF_RATE | SOX_EFF_DEPRECATED,
   sox_poly_getopts,
   sox_poly_start,
   sox_poly_flow,
--- a/src/rabbit.c
+++ b/src/rabbit.c
@@ -185,7 +185,7 @@
 {
   static sox_effect_handler_t handler = {
     "rabbit", "[-c0|-c1|-c2|-c3|-c4] [rate]",
-    SOX_EFF_RATE | SOX_EFF_MCHAN,
+    SOX_EFF_RATE | SOX_EFF_MCHAN | SOX_EFF_DEPRECATED,
     getopts, start, flow, drain, stop, NULL, sizeof(priv_t)
   };
 
--- a/src/rate.c
+++ b/src/rate.c
@@ -187,29 +187,19 @@
   }
 }
 
-static double bessel_I_0(double x)
-{
-  double term = 1, sum = 1, last_sum, x2 = x / 2;
-  int i = 1;
-  do {
-    double y = x2 / i++;
-    last_sum = sum, sum += term *= y * y;
-  } while (sum != last_sum);
-  return sum;
-}
-
 static double * make_lpf(int num_taps, double Fc, double beta, double scale)
 {
-  double * h = malloc(num_taps * sizeof(*h));
+  double * h = malloc(num_taps * sizeof(*h)), sum = 0;
   int i, m = num_taps - 1;
   assert(Fc >= 0 && Fc <= 1);
-  scale /= bessel_I_0(beta);
   for (i = 0; i <= m / 2; ++i) {
     double x = M_PI * (i - .5 * m), y = 2. * i / m - 1;
     h[i] = x? sin(Fc * x) / x : Fc;
-    h[i] *= bessel_I_0(beta * sqrt(1 - y * y)) * scale;
-    h[m - i] = h[i];
+    sum += h[i] *= bessel_I_0(beta * sqrt(1 - y * y));
+    if (m - i != i)
+      sum += h[m - i] = h[i];
   }
+  for (i = 0; i < num_taps; ++i) h[i] *= scale / sum;
   return h;
 }
 
@@ -380,7 +370,7 @@
     static filter_t const filters[] = {
       {2 * array_length(half_fir_coefs_low) - 1, half_fir_coefs_low, 0,0},
       {0, NULL, .986, 110}, {0, NULL, .986, 125},
-      {0, NULL, .996, 156}, {0, NULL, .999, 156},
+      {0, NULL, .996, 165}, {0, NULL, .999, 165},
     };
     filter_t const * f = &filters[quality - Low];
     assert((size_t)(quality - Low) < array_length(filters));
@@ -499,7 +489,7 @@
 static int create(sox_effect_t * effp, int argc, char **argv)
 {
   priv_t * p = (priv_t *) effp->priv;
-  char dummy, * found_at, * bws = "-qlmhvu", * nums = "01";
+  char dummy, * found_at, * bws = "-qlmhvu", * nums = "123";
 
   p->quality = p->coef_interp = -1;
   p->shared_ptr = &p->shared;
--- a/src/rate_filters.h
+++ b/src/rate_filters.h
@@ -18,13 +18,14 @@
 /* Generated by m4 */
 
 static const sample_t half_fir_coefs_25[] = {
-  4.9622034521467345e-001, 3.1227031280072459e-001, 3.5198986166898451e-003,
-  -8.9221427418232149e-002, -2.8372758530229671e-003, 3.9139593785072563e-002,
-  1.9671926007707326e-003, -1.7250462144826118e-002, -1.1596954982514773e-003,
-  6.8588796907120527e-003, 5.7031347966698574e-004, -2.3044720814877507e-003,
-  -2.2679857326247756e-004, 6.0962502224911946e-004, 6.9133289864740816e-005,
-  -1.1323492804087647e-004, -1.4554678571602767e-005, 1.1197369453748703e-005,
-  1.6171529855434563e-006,
+  4.9866643051942178e-001, 3.1333582318860204e-001, 1.2567743716165585e-003,
+ -9.2035726038137103e-002, -1.0507348255277846e-003, 4.2764945027796687e-002,
+  7.7661461450703555e-004, -2.0673365323361139e-002, -5.0429677622613805e-004,
+  9.4223774565849357e-003, 2.8491539998284476e-004, -3.8562347294894628e-003,
+ -1.3803431143314762e-004, 1.3634218103234187e-003, 5.6110366313398705e-005,
+ -3.9872042837864422e-004, -1.8501044952475473e-005, 9.0580351350892191e-005,
+  4.6764104835321042e-006, -1.4284332593063177e-005, -8.1340436298087893e-007,
+  1.1833367010222812e-006, 7.3979325233687461e-008,
 };
 static const sample_t half_fir_coefs_low[] = {
   4.2759802493108773e-001, 3.0939308096100709e-001, 6.9285325719540158e-002,
@@ -44,7 +45,7 @@
   -6.0893901283459912e-006, 1.4040363940567877e-005, 4.9834316581482789e-006,
 };
 #define FUNCTION half_sample_25 
-#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 #define COEFS half_fir_coefs_25 
 assert_static(!((array_length(COEFS)- 1) & 1), HALF_FIR_LENGTH_25 );
 #include "rate_half_fir.h"
@@ -61,18 +62,25 @@
 #include "rate_poly_fir0.h"
 #define FUNCTION d100_1
 #define COEF_INTERP 1
-#define PHASE_BITS 8
+#define PHASE_BITS 9
 #define FIR_LENGTH d100_l
 #define CONVOLVE poly_fir_convolve_d100
 #include "rate_poly_fir.h"
-#define d100_1_b 8
+#define d100_1_b 9
 #define FUNCTION d100_2
 #define COEF_INTERP 2
+#define PHASE_BITS 7
+#define FIR_LENGTH d100_l
+#define CONVOLVE poly_fir_convolve_d100
+#include "rate_poly_fir.h"
+#define d100_2_b 7
+#define FUNCTION d100_3
+#define COEF_INTERP 3
 #define PHASE_BITS 6
 #define FIR_LENGTH d100_l
 #define CONVOLVE poly_fir_convolve_d100
 #include "rate_poly_fir.h"
-#define d100_2_b 6
+#define d100_3_b 6
 #define d120_l 30
 #define poly_fir_convolve_d120 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 #define FUNCTION d120_0
@@ -88,11 +96,18 @@
 #define d120_1_b 10
 #define FUNCTION d120_2
 #define COEF_INTERP 2
+#define PHASE_BITS 9
+#define FIR_LENGTH d120_l
+#define CONVOLVE poly_fir_convolve_d120
+#include "rate_poly_fir.h"
+#define d120_2_b 9
+#define FUNCTION d120_3
+#define COEF_INTERP 3
 #define PHASE_BITS 7
 #define FIR_LENGTH d120_l
 #define CONVOLVE poly_fir_convolve_d120
 #include "rate_poly_fir.h"
-#define d120_2_b 7
+#define d120_3_b 7
 #define d150_l 38
 #define poly_fir_convolve_d150 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 #define FUNCTION d150_0
@@ -101,18 +116,25 @@
 #include "rate_poly_fir0.h"
 #define FUNCTION d150_1
 #define COEF_INTERP 1
-#define PHASE_BITS 11
+#define PHASE_BITS 12
 #define FIR_LENGTH d150_l
 #define CONVOLVE poly_fir_convolve_d150
 #include "rate_poly_fir.h"
-#define d150_1_b 11
+#define d150_1_b 12
 #define FUNCTION d150_2
 #define COEF_INTERP 2
+#define PHASE_BITS 10
+#define FIR_LENGTH d150_l
+#define CONVOLVE poly_fir_convolve_d150
+#include "rate_poly_fir.h"
+#define d150_2_b 10
+#define FUNCTION d150_3
+#define COEF_INTERP 3
 #define PHASE_BITS 8
 #define FIR_LENGTH d150_l
 #define CONVOLVE poly_fir_convolve_d150
 #include "rate_poly_fir.h"
-#define d150_2_b 8
+#define d150_3_b 8
 #define U100_l 42
 #define poly_fir_convolve_U100 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 #define FUNCTION U100_0
@@ -121,18 +143,25 @@
 #include "rate_poly_fir0.h"
 #define FUNCTION U100_1
 #define COEF_INTERP 1
-#define PHASE_BITS 9
+#define PHASE_BITS 10
 #define FIR_LENGTH U100_l
 #define CONVOLVE poly_fir_convolve_U100
 #include "rate_poly_fir.h"
-#define U100_1_b 9
+#define U100_1_b 10
 #define FUNCTION U100_2
 #define COEF_INTERP 2
+#define PHASE_BITS 8
+#define FIR_LENGTH U100_l
+#define CONVOLVE poly_fir_convolve_U100
+#include "rate_poly_fir.h"
+#define U100_2_b 8
+#define FUNCTION U100_3
+#define COEF_INTERP 3
 #define PHASE_BITS 6
 #define FIR_LENGTH U100_l
 #define CONVOLVE poly_fir_convolve_U100
 #include "rate_poly_fir.h"
-#define U100_2_b 6
+#define U100_3_b 6
 #define u100_l 10
 #define poly_fir_convolve_u100 _ _ _ _ _ _ _ _ _ _
 #define FUNCTION u100_0
@@ -141,18 +170,25 @@
 #include "rate_poly_fir0.h"
 #define FUNCTION u100_1
 #define COEF_INTERP 1
-#define PHASE_BITS 7
+#define PHASE_BITS 9
 #define FIR_LENGTH u100_l
 #define CONVOLVE poly_fir_convolve_u100
 #include "rate_poly_fir.h"
-#define u100_1_b 7
+#define u100_1_b 9
 #define FUNCTION u100_2
 #define COEF_INTERP 2
-#define PHASE_BITS 5
+#define PHASE_BITS 7
 #define FIR_LENGTH u100_l
 #define CONVOLVE poly_fir_convolve_u100
 #include "rate_poly_fir.h"
-#define u100_2_b 5
+#define u100_2_b 7
+#define FUNCTION u100_3
+#define COEF_INTERP 3
+#define PHASE_BITS 6
+#define FIR_LENGTH u100_l
+#define CONVOLVE poly_fir_convolve_u100
+#include "rate_poly_fir.h"
+#define u100_3_b 6
 #define u120_l 14
 #define poly_fir_convolve_u120 _ _ _ _ _ _ _ _ _ _ _ _ _ _
 #define FUNCTION u120_0
@@ -161,18 +197,25 @@
 #include "rate_poly_fir0.h"
 #define FUNCTION u120_1
 #define COEF_INTERP 1
-#define PHASE_BITS 8
+#define PHASE_BITS 10
 #define FIR_LENGTH u120_l
 #define CONVOLVE poly_fir_convolve_u120
 #include "rate_poly_fir.h"
-#define u120_1_b 8
+#define u120_1_b 10
 #define FUNCTION u120_2
 #define COEF_INTERP 2
+#define PHASE_BITS 8
+#define FIR_LENGTH u120_l
+#define CONVOLVE poly_fir_convolve_u120
+#include "rate_poly_fir.h"
+#define u120_2_b 8
+#define FUNCTION u120_3
+#define COEF_INTERP 3
 #define PHASE_BITS 6
 #define FIR_LENGTH u120_l
 #define CONVOLVE poly_fir_convolve_u120
 #include "rate_poly_fir.h"
-#define u120_2_b 6
+#define u120_3_b 6
 #define u150_l 20
 #define poly_fir_convolve_u150 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 #define FUNCTION u150_0
@@ -181,27 +224,34 @@
 #include "rate_poly_fir0.h"
 #define FUNCTION u150_1
 #define COEF_INTERP 1
-#define PHASE_BITS 10
+#define PHASE_BITS 11
 #define FIR_LENGTH u150_l
 #define CONVOLVE poly_fir_convolve_u150
 #include "rate_poly_fir.h"
-#define u150_1_b 10
+#define u150_1_b 11
 #define FUNCTION u150_2
 #define COEF_INTERP 2
+#define PHASE_BITS 9
+#define FIR_LENGTH u150_l
+#define CONVOLVE poly_fir_convolve_u150
+#include "rate_poly_fir.h"
+#define u150_2_b 9
+#define FUNCTION u150_3
+#define COEF_INTERP 3
 #define PHASE_BITS 7
 #define FIR_LENGTH u150_l
 #define CONVOLVE poly_fir_convolve_u150
 #include "rate_poly_fir.h"
-#define u150_2_b 7
+#define u150_3_b 7
 typedef struct {int phase_bits; stage_fn_t fn;} poly_fir1_t;
-typedef struct {int num_coefs; double pass, stop, att; poly_fir1_t interp[3];} poly_fir_t;
+typedef struct {int num_coefs; double pass, stop, att; poly_fir1_t interp[4];} poly_fir_t;
 static poly_fir_t const poly_firs[] = {
-  {d100_l, .75,1.5, 108, {{0, d100_0}, {d100_1_b, d100_1}, {d100_2_b, d100_2}}},
-  {d120_l,  1, 1.5, 133, {{0, d120_0}, {d120_1_b, d120_1}, {d120_2_b, d120_2}}},
-  {d150_l,  1, 1.5, 165, {{0, d150_0}, {d150_1_b, d150_1}, {d150_2_b, d150_2}}},
-  {U100_l, .724, 1, 105, {{0, U100_0}, {U100_1_b, U100_1}, {U100_2_b, U100_2}}},
-  {u100_l, .3, 1.5, 107, {{0, u100_0}, {u100_1_b, u100_1}, {u100_2_b, u100_2}}},
-  {u120_l, .5, 1.5, 125, {{0, u120_0}, {u120_1_b, u120_1}, {u120_2_b, u120_2}}},
-  {u150_l, .5, 1.5, 174, {{0, u150_0}, {u150_1_b, u150_1}, {u150_2_b, u150_2}}},
+  {d100_l, .75,1.5, 108, {{0, d100_0}, {d100_1_b, d100_1}, {d100_2_b, d100_2}, {d100_3_b, d100_3}}},
+  {d120_l,  1, 1.5, 133, {{0, d120_0}, {d120_1_b, d120_1}, {d120_2_b, d120_2}, {d120_3_b, d120_3}}},
+  {d150_l,  1, 1.5, 165, {{0, d150_0}, {d150_1_b, d150_1}, {d150_2_b, d150_2}, {d150_3_b, d150_3}}},
+  {U100_l, .724, 1, 105, {{0, U100_0}, {U100_1_b, U100_1}, {U100_2_b, U100_2}, {U100_3_b, U100_3}}},
+  {u100_l, .3, 1.5, 107, {{0, u100_0}, {u100_1_b, u100_1}, {u100_2_b, u100_2}, {u100_3_b, u100_3}}},
+  {u120_l, .5, 1.5, 125, {{0, u120_0}, {u120_1_b, u120_1}, {u120_2_b, u120_2}, {u120_3_b, u120_3}}},
+  {u150_l, .5, 1.5, 174, {{0, u150_0}, {u150_1_b, u150_1}, {u150_2_b, u150_2}, {u150_3_b, u150_3}}},
 };
 
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -48,6 +48,8 @@
 sox_sample_t lsx_gcd(sox_sample_t a, sox_sample_t b);
 sox_sample_t lsx_lcm(sox_sample_t a, sox_sample_t b);
 
+double bessel_I_0(double x);
+
 #ifndef HAVE_STRCASECMP
 int strcasecmp(const char *s1, const char *s2);
 int strncasecmp(char const * s1, char const * s2, size_t n);