shithub: sox

Download patch

ref: 8ac1f3e7c6bc84e110f7597c6530aeb003804fbb
parent: 4e4b8ccde1699fc66113109b0795bdd71a5d284e
author: robs <robs>
date: Wed Jan 28 06:58:10 EST 2009

sinc updates

--- a/src/effects_i_dsp.c
+++ b/src/effects_i_dsp.c
@@ -248,19 +248,21 @@
   }
 }
 
-double * lsx_make_lpf(int num_taps, double Fc, double beta, double scale)
+double * lsx_make_lpf(int num_taps, double Fc, double beta, double scale, sox_bool dc_norm)
 {
-  double * h = malloc(num_taps * sizeof(*h)), sum = 0;
   int i, m = num_taps - 1;
+  double * h = malloc(num_taps * sizeof(*h)), sum = 0;
+  double mult = scale / lsx_bessel_I_0(beta);
   assert(Fc >= 0 && Fc <= 1);
+  lsx_debug("make_lpf(n=%i, Fc=%g beta=%g dc-norm=%i scale=%g)", num_taps, Fc, beta, dc_norm, scale);
   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;
-    sum += h[i] *= lsx_bessel_I_0(beta * sqrt(1 - y * y));
+    sum += h[i] *= lsx_bessel_I_0(beta * sqrt(1 - y * y)) * mult;
     if (m - i != i)
       sum += h[m - i] = h[i];
   }
-  for (i = 0; i < num_taps; ++i) h[i] *= scale / sum;
+  for (i = 0; dc_norm && i < num_taps; ++i) h[i] *= scale / sum;
   return h;
 }
 
@@ -298,12 +300,12 @@
   if (k)
     *num_taps = *num_taps * k - 1;
   else k = 1;
-  lsx_debug("%i %g %g %g %g", *num_taps, Fp, tr_bw, Fc, beta);
-  return lsx_make_lpf(*num_taps, (Fc - tr_bw) / k, beta, (double)k);
+  lsx_debug("%g %g %g", Fp, tr_bw, Fc);
+  return lsx_make_lpf(*num_taps, (Fc - tr_bw) / k, beta, (double)k, sox_true);
 }
 
 #if 0
-static void printf_vector(FILE * f, double h[], int num_points)
+static void printf_vector(double h[], int num_points)
 {
   int i;
   printf(
@@ -310,13 +312,22 @@
   "# name: b\n"
   "# type: matrix\n"
   "# rows: %i\n"
-  "# columns: 1\n", num_points);
-  for (i = 0; i < num_points; ++i)
-    printf("%24.16e\n", h[i]);
+  "# columns: 1\n", num_points / 2);
+  for (i = 0; i < num_points; i += 2)
+    printf("%24.16e\n", h[i + 1]);
   exit(0);
 }
 #endif
 
+static double safe_log(double x)
+{
+  assert(x >= 0);
+  if (x)
+    return log(x);
+  lsx_debug("log(0)");
+  return -26;
+}
+
 void lsx_fir_to_phase(double * * h, int * len,
     int * post_len, double phase0)
 {
@@ -329,7 +340,7 @@
   for (i = 0; i < *len; ++i) work[i] = (*h)[i];
 
   lsx_safe_rdft(work_len, 1, work); /* Cepstral: */
-  work[0] = safe_log(work[0]), work[1] = safe_log(work[1]);
+  work[0] = safe_log(fabs(work[0])), work[1] = safe_log(fabs(work[1]));
   for (i = 2; i < work_len; i += 2) {
     work[i] = safe_log(sqrt(sqr(work[i]) + sqr(work[i + 1])));
     work[i + 1] = 0;
@@ -344,11 +355,12 @@
 
   /* Some filters require phase unwrapping at this point.  Ours give dis-
    * continuities only in the stop band, so no need to unwrap in this case. */
+
 #if 0
-  UNPACK(work, work_len);
+  LSX_UNPACK(work, work_len);
   unwrap_phase(work, work_len);
-  PACK(work, work_len);
-  printf_vector(work, work_len);
+  printf_vector(work, work_len + 2);
+  LSX_PACK(work, work_len);
 #endif
 
   for (i = 2; i < work_len; i += 2) /* Interpolate between linear & min phase */
--- a/src/fft4g.h
+++ b/src/fft4g.h
@@ -29,3 +29,7 @@
 
 #define dft_br_len(l) (2 + (1 << (int)(log(l / 2 + .5) / log(2.)) / 2))
 #define dft_sc_len(l) (l / 2)
+
+/* Over-allocate h by 2 to use these macros */
+#define LSX_PACK(h, n)   h[1] = h[n]
+#define LSX_UNPACK(h, n) h[n] = h[1], h[n + 1] = h[1] = 0;
--- a/src/sinc.c
+++ b/src/sinc.c
@@ -21,9 +21,10 @@
 #include <string.h>
 
 typedef struct {
-  dft_filter_priv_t base;
-  double att, phase, freq0, freq1, tbw0, tbw1;
-  int num_taps[2];
+  dft_filter_priv_t  base;
+  double             att, beta, phase, Fc0, Fc1, tbw0, tbw1;
+  int                num_taps[2];
+  sox_bool           round;
 } priv_t;
 
 static int create(sox_effect_t * effp, int argc, char * * argv)
@@ -35,33 +36,36 @@
 
   b->filter_ptr = &b->filter;
   p->phase = 50;
-  p->att = 120;
+  p->beta = -1;
   while (i < 2) {
     int c = 1;
-    while (c && (c = getopt(argc, argv, "+a:p:t:n:MIL")) != -1) switch (c) {
-      GETOPT_NUMERIC('a', att,  40 , 200)
-      GETOPT_NUMERIC('p', phase, 0, 100);
-      GETOPT_NUMERIC('n', num_taps[1], 10, 32767);
-      case 't': p->tbw1 = lsx_parse_frequency(optarg, &parse_ptr);
-        if (p->tbw1 < 1 || *parse_ptr) return lsx_usage(effp);
-        break;
+    while (c && (c = getopt(argc, argv, "+ra:b:p:MILt:n:")) != -1) switch (c) {
+      char * parse_ptr;
+      case 'r': p->round = sox_true; break;
+      GETOPT_NUMERIC('a', att,  40 , 170)
+      GETOPT_NUMERIC('b', beta,  0 , 18)
+      GETOPT_NUMERIC('p', phase, 0, 100)
       case 'M': p->phase =  0; break;
       case 'I': p->phase = 25; break;
       case 'L': p->phase = 50; break;
+      GETOPT_NUMERIC('n', num_taps[1], 11, 32767)
+      case 't': p->tbw1 = lsx_parse_frequency(optarg, &parse_ptr);
+        if (p->tbw1 < 1 || *parse_ptr) return lsx_usage(effp);
+        break;
       default: c = 0;
     }
-    if (!i++ && !(p->tbw1 && p->num_taps[1])) {
+    if ((p->att && p->beta >= 0) || (p->tbw1 && p->num_taps[1]))
+      return lsx_usage(effp);
+    if (!i || !p->Fc1)
       p->tbw0 = p->tbw1, p->num_taps[0] = p->num_taps[1];
-      if (optind < argc) {
-        parse_ptr = argv[optind++];
-        if (*parse_ptr != '-')
-          p->freq0 = lsx_parse_frequency(parse_ptr, &parse_ptr);
-        if (*parse_ptr == '-')
-          p->freq1 = lsx_parse_frequency(parse_ptr+1, &parse_ptr);
-      }
+    if (!i++ && optind < argc) {
+      if (*(parse_ptr = argv[optind++]) != '-')
+        p->Fc0 = lsx_parse_frequency(parse_ptr, &parse_ptr);
+      if (*parse_ptr == '-')
+        p->Fc1 = lsx_parse_frequency(parse_ptr + 1, &parse_ptr);
     }
   }
-  return optind != argc || p->freq0 < 0 || p->freq1 < 0 || *parse_ptr ?
+  return optind != argc || p->Fc0 < 0 || p->Fc1 < 0 || *parse_ptr ?
       lsx_usage(effp) : SOX_SUCCESS;
 }
 
@@ -73,19 +77,23 @@
   h[(n - 1) / 2] += 1;
 }
 
-static double * lpf(sox_effect_t * effp, double Fc, double tbw, int * num_taps, double att, double phase)
+static double * lpf(double Fn, double Fc, double tbw, int * num_taps, double att, double * beta, double phase, sox_bool round)
 {
-  double Fn = effp->in_signal.rate * .5;
-  if (!Fc) {
+  if ((Fc /= Fn) <= 0 || Fc >= 1) {
     *num_taps = 0;
     return NULL;
   }
-  if (phase != 0 && phase != 50 && phase != 100)
-    att *= 34./33; /* negate degradation with intermediate phase */
-  *num_taps = *num_taps? *num_taps |= 1 :
-      min(32767, lsx_lpf_num_taps(att, (tbw? tbw / Fn : .05) * .5, 0));
-  lsx_report("num taps = %i", *num_taps);
-  return lsx_make_lpf(*num_taps, Fc / Fn, lsx_kaiser_beta(att), 1.);
+  att = att? att : 120;
+  att = phase && phase != 50 && phase != 100? 34./33 * att : att;
+  *beta = *beta < 0? lsx_kaiser_beta(att) : *beta;
+  if (!*num_taps) {
+    int n = lsx_lpf_num_taps(att, (tbw? tbw / Fn : .05) * .5, 0);
+    *num_taps = range_limit(n, 11, 32767);
+    if (round)
+      *num_taps = 1 + 2 * (int)((int)((*num_taps / 2) * Fc + .5) / Fc + .5);
+    lsx_report("num taps = %i (from %i)", *num_taps, n);
+  }
+  return lsx_make_lpf(*num_taps | 1, Fc, *beta, 1., sox_false);
 }
 
 static int start(sox_effect_t * effp)
@@ -94,11 +102,17 @@
   dft_filter_filter_t * f = p->base.filter_ptr;
 
   if (!f->num_taps) {
+    double Fn = effp->in_signal.rate * .5;
     double * h[2];
     int i, longer;
-    h[0] = lpf(effp, p->freq0, p->tbw0, &p->num_taps[0], p->att, p->phase);
-    h[1] = lpf(effp, p->freq1, p->tbw1, &p->num_taps[1], p->att, p->phase);
+
+    if (p->Fc0 >= Fn || p->Fc1 >= Fn) {
+      lsx_fail("filter frequency must be less than sample-rate / 2");
+      return SOX_EOF;
+    }
+    h[0] = lpf(Fn, p->Fc0, p->tbw0, &p->num_taps[0], p->att, &p->beta, p->phase, p->round);
     if (h[0]) invert(h[0], p->num_taps[0]);
+    h[1] = lpf(Fn, p->Fc1, p->tbw1, &p->num_taps[1], p->att, &p->beta, p->phase, p->round);
     longer = p->num_taps[1] > p->num_taps[0];
     f->num_taps = p->num_taps[longer];
     if (h[0] && h[1]) {
@@ -105,7 +119,7 @@
       for (i = 0; i < p->num_taps[!longer]; ++i)
         h[longer][i + (f->num_taps - p->num_taps[!longer])/2] += h[!longer][i];
       free(h[!longer]);
-      if (p->freq0 < p->freq1)
+      if (p->Fc0 < p->Fc1)
         invert(h[longer], f->num_taps);
     }
     if (p->phase != 50)
@@ -115,9 +129,9 @@
         100 - 100. * f->post_peak / (f->num_taps - 1));
     if (effp->global_info->plot != sox_plot_off) {
       char title[100];
-      sprintf(title, "SoX effect: sinc filter freq=%g-%g", p->freq0, p->freq1);
+      sprintf(title, "SoX effect: sinc filter freq=%g-%g", p->Fc0, p->Fc1? p->Fc1 : Fn);
       lsx_plot_fir(h[longer], f->num_taps, effp->in_signal.rate,
-          effp->global_info->plot, title, -p->att - 20, 10.);
+          effp->global_info->plot, title, -p->beta * 10 - 25, 5.);
       return SOX_EOF;
     }
     f->dft_length = lsx_set_dft_length(f->num_taps);
@@ -135,7 +149,7 @@
   static sox_effect_handler_t handler;
   handler = *sox_dft_filter_effect_fn();
   handler.name = "sinc";
-  handler.usage = "[-a att] [-p phase|-M|-I|-L] [-t tbw|-n taps] freq1[-freq2 [-t ...|-n ...]]";
+  handler.usage = "[-a att] [-p phase|-M|-I|-L] [-t tbw|-n taps] [freqHP][-freqLP [-t ...|-n ...]]";
   handler.getopts = create;
   handler.start = start;
   handler.priv_size = sizeof(priv_t);
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -107,7 +107,7 @@
 void lsx_apply_blackman_nutall(double h[], const int num_points);
 double lsx_kaiser_beta(double att);
 void lsx_apply_kaiser(double h[], const int num_points, double beta);
-double * lsx_make_lpf(int num_taps, double Fc, double beta, double scale);
+double * lsx_make_lpf(int num_taps, double Fc, double beta, double scale, sox_bool dc_norm);
 int lsx_lpf_num_taps(double att, double tr_bw, int k);
 double * lsx_design_lpf(
     double Fp,      /* End of pass-band; ~= 0.01dB point */
--- a/src/util.h
+++ b/src/util.h
@@ -114,7 +114,6 @@
 
 #define sqr(a) ((a) * (a))
 #define sign(x) ((x) < 0? -1 : 1)
-#define safe_log(x) ((x) <= 0? -99 : log(x)) /* exp --> 0 (for single prec.) */
 
 /* Numerical Recipes in C, p. 284 */
 #define ranqd1(x) ((x) = 1664525L * (x) + 1013904223L) /* int32_t x */