shithub: sox

Download patch

ref: c6ceb7f6ad6f535119c7f16cc7190bf532326448
parent: 230fa2c37c4bd9252ee9e5d8ccdf5862f93acd7d
author: robs <robs>
date: Wed Feb 4 17:01:17 EST 2009

new fir effect

--- a/ChangeLog
+++ b/ChangeLog
@@ -70,6 +70,7 @@
 Effects:
 
   o New `sinc' FFT filter effect; replacement for `filter'.  (robs)
+  o New `fir' filter effect using external coefficients file.  (robs)
   o New `overdrive' effect.  (robs)
   o New `pluck' and `tpdf' types for `synth'.  (robs)
   o Can now set common parameters for multiple `synth' channels.  (robs)
--- a/sox.1
+++ b/sox.1
@@ -1763,6 +1763,32 @@
 .SP
 An optional \fItype\fR can be specified to change the type of envelope.  Choices are \fBq\fR for quarter of a sine wave, \fBh\fR for half a sine wave, \fBt\fR for linear slope, \fBl\fR for logarithmic, and \fBp\fR for inverted parabola.  The default is logarithmic.
 .TP
+\fBfir\fR [\fIcoefs-file\fR\^|\^\fIcoefs\fR]
+Use SoX's FFT convolution engine with given FIR filter
+coefficients.
+If a single argument is given then this is treated as the name of a file
+containing the filter coefficients (white-space separated; may contain
+`#' comments).  If the given filename is `\-', or if no argument is
+given, then the coefficients are read from the `standard input' (stdin);
+otherwise, coefficients may be given on the command line.
+Examples:
+.EX
+  sox infile outfile fir 0.0195 -0.082 0.234 0.891 -0.145 0.043
+.EE
+.EX
+  sox infile outfile fir coefs.txt
+.EE
+with coefs.txt containing
+.EX
+  # HP filter
+  # freq=10000
+    1.2311233052619888e-01
+   -4.4777096106211783e-01
+    5.1031563346705155e-01
+   -6.6502926320995331e-02
+  ...
+.EE
+.TP
 \fBflanger\fR [\fIdelay depth regen width speed shape phase interp\fR]
 Apply a flanging effect to the audio.
 See [3] for a detailed description of flanging.
@@ -1852,7 +1878,7 @@
 .B \-B
 and
 .B \-b
-are synonomous.
+are synonymous.
 .SP
 The
 .B \-r
@@ -1882,7 +1908,7 @@
 option invokes a simple limiter, e.g.
 .EX
 	sox infile outfile gain -l 6
-.SP
+.EE
 will apply 6dB of gain but never clip.  Note that limiting more than a
 few dBs more than occasionally (in a piece of audio) is not recommended
 as it can cause audible distortion.
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -28,16 +28,16 @@
 
 # Format with: !xargs echo|tr ' ' '\n'|sort|column|expand|sed 's/^/  /'
 set(effects_srcs
-  bend            dither          loudness        rate            stat
-  biquad          earwax          mcompand        remix           stretch
-  biquads         echo            mixer           repeat          swap
-  chorus          echos           noiseprof       reverb          synth
-  compand         fade            noisered        reverse         tempo
-  compandt        fft4g           output          silence         tremolo
-  contrast        filter          overdrive       sinc            trim
-  dcshift         flanger         pad             skeleff         vol
-  delay           gain            pan             speed
-  dft_filter      input           phaser          splice
+  bend            dither          gain            pan             speed
+  biquad          earwax          input           phaser          splice
+  biquads         echo            loudness        rate            stat
+  chorus          echos           mcompand        remix           stretch
+  compand         fade            mixer           repeat          swap
+  compandt        fft4g           noiseprof       reverb          synth
+  contrast        filter          noisered        reverse         tempo
+  dcshift         fir             output          silence         tremolo
+  delay           firfit          overdrive       sinc            trim
+  dft_filter      flanger         pad             skeleff         vol
 )
 set(formats_srcs
   8svx            dat             ima-fmt         s3-fmt          u3-fmt
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -270,16 +270,16 @@
 # Effects source
 libsox_la_SOURCES += \
 	band.h bend.c biquad.c biquad.h biquads.c chorus.c compand.c \
-	compandt.c compandt.h contrast.c dcshift.c delay.c dither.c \
-	dither_fir.h dither_iir.h earwax.c echo.c echos.c effects.c effects.h \
-	effects_i.c fade.c fft4g.c fft4g.h fifo.h filter.c flanger.c input.c \
+	compandt.c compandt.h contrast.c dcshift.c delay.c dft_filter.c \
+	dft_filter.h dither.c dither_fir.h dither_iir.h earwax.c echo.c \
+	echos.c effects.c effects.h effects_i.c effects_i_dsp.c fade.c fft4g.c \
+	fft4g.h fifo.h filter.c fir.c firfit.c flanger.c gain.c input.c \
 	ladspa.c loudness.c mcompand.c mcompand_xover.h mixer.c noiseprof.c \
-	noisered.c noisered.h gain.c output.c pad.c pan.c phaser.c \
-	rate.c rate_filters.h rate_half_fir.h \
-	rate_poly_fir0.h rate_poly_fir.h remix.c repeat.c reverb.c \
-	reverse.c silence.c skeleff.c speed.c splice.c stat.c swap.c stretch.c \
-	synth.c tempo.c tremolo.c trim.c vol.c overdrive.c effects_i_dsp.c \
-	dft_filter.c dft_filter.h sinc.c
+	noisered.c noisered.h output.c overdrive.c pad.c pan.c phaser.c rate.c \
+	rate_filters.h rate_half_fir.h rate_poly_fir0.h rate_poly_fir.h \
+	remix.c repeat.c reverb.c reverse.c silence.c sinc.c skeleff.c speed.c \
+	splice.c stat.c stretch.c swap.c synth.c tempo.c tremolo.c trim.c \
+	vol.c
 if HAVE_PNG
     libsox_la_SOURCES += spectrogram.c
 endif
--- a/src/dft_filter.c
+++ b/src/dft_filter.c
@@ -20,8 +20,21 @@
 #include "dft_filter.h"
 #include <string.h>
 
-typedef dft_filter_filter_t filter_t;
+typedef dft_filter_t filter_t;
 typedef dft_filter_priv_t priv_t;
+
+void lsx_set_dft_filter(dft_filter_t *f, double *h, int n, int post_peak)
+{
+  int i;
+  f->num_taps = n;
+  f->post_peak = post_peak;
+  f->dft_length = lsx_set_dft_length(f->num_taps);
+  f->coefs = lsx_calloc(f->dft_length, sizeof(*f->coefs));
+  for (i = 0; i < f->num_taps; ++i)
+    f->coefs[(i + f->dft_length - f->num_taps + 1) & (f->dft_length - 1)] = h[i] / f->dft_length * 2;
+  lsx_safe_rdft(f->dft_length, 1, f->coefs);
+  free(h);
+}
 
 static int start(sox_effect_t * effp)
 {
--- a/src/dft_filter.h
+++ b/src/dft_filter.h
@@ -4,12 +4,13 @@
 
 typedef struct {
   int        dft_length, num_taps, post_peak;
-  double   * coefs;
-} dft_filter_filter_t;
+  double     * coefs;
+} dft_filter_t;
 
 typedef struct {
   size_t     samples_in, samples_out;
   fifo_t     input_fifo, output_fifo;
-  dft_filter_filter_t   filter, * filter_ptr;
+  dft_filter_t   filter, * filter_ptr;
 } dft_filter_priv_t;
 
+void lsx_set_dft_filter(dft_filter_t * f, double * h, int n, int post_peak);
--- a/src/effects.h
+++ b/src/effects.h
@@ -35,6 +35,8 @@
   EFFECT(equalizer)
   EFFECT(fade)
   EFFECT(filter)
+  EFFECT(fir)
+  EFFECT(firfit)
   EFFECT(flanger)
   EFFECT(gain)
   EFFECT(highpass)
--- a/src/effects_i.c
+++ b/src/effects_i.c
@@ -306,6 +306,25 @@
   return result < 0 ? -1 : result;
 }
 
+FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename)
+{
+  FILE * file;
+
+  if (!filename || !strcmp(filename, "-")) {
+    if (effp->global_info->global_info->stdin_in_use_by) {
+      lsx_fail("stdin already in use by '%s'", effp->global_info->global_info->stdin_in_use_by);
+      return NULL;
+    }
+    effp->global_info->global_info->stdin_in_use_by = effp->handler.name;
+    file = stdin;
+  }
+  else if (!(file = fopen(filename, "r"))) {
+    lsx_fail("couldn't open file %s: %s", filename, strerror(errno));
+    return NULL;
+  }
+  return file;
+}
+
 int lsx_effects_init(void)
 {
   init_fft_cache();
--- /dev/null
+++ b/src/fir.c
@@ -1,0 +1,83 @@
+/* Effect: fir filter from coefs   Copyright (c) 2009 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "sox_i.h"
+#include "dft_filter.h"
+
+typedef struct {
+  dft_filter_priv_t  base;
+  char const         * filename;
+  double             * h;
+  int                n;
+} priv_t;
+
+static int create(sox_effect_t * effp, int argc, char * * argv)
+{
+  priv_t             * p = (priv_t *)effp->priv;
+  dft_filter_priv_t  * b = &p->base;
+  double             d;
+  char               c;
+
+  b->filter_ptr = &b->filter;
+  --argc, ++argv;
+  if (argc == 1)
+    p->filename = argv[0], --argc;
+  else for (; argc && sscanf(*argv, "%lf%c", &d, &c) == 1; --argc, ++argv)
+    (p->h = lsx_realloc(p->h, ++p->n * sizeof(*p->h)))[p->n - 1] = d;
+  return argc? lsx_usage(effp) : SOX_SUCCESS;
+}
+
+static int start(sox_effect_t * effp)
+{
+  priv_t        * p = (priv_t *)effp->priv;
+  dft_filter_t  * f = p->base.filter_ptr;
+  double        d;
+  char          c;
+  int           i;
+
+  if (!f->num_taps) {
+    if (!p->n) {
+      FILE * file = lsx_open_input_file(effp, p->filename);
+      if (!file)
+        return SOX_EOF;
+      while (fscanf(file, " #%*[^\n]%c", &c) + (i = fscanf(file, "%lf", &d)) >0)
+        if (i > 0)
+          (p->h = lsx_realloc(p->h, ++p->n * sizeof(*p->h)))[p->n - 1] = d;
+      lsx_report("%i coefficients", p->n);
+      if (!feof(file)) {
+        lsx_fail("error reading coefficient file");
+        if (file != stdin) fclose(file);
+        return SOX_EOF;
+      }
+      if (file != stdin) fclose(file);
+    }
+    lsx_set_dft_filter(f, p->h, p->n, p->n >> 1);
+  }
+  return sox_dft_filter_effect_fn()->start(effp);
+}
+
+sox_effect_handler_t const * sox_fir_effect_fn(void)
+{
+  static sox_effect_handler_t handler;
+  handler = *sox_dft_filter_effect_fn();
+  handler.name = "fir";
+  handler.usage = "[coef-file|coefs]";
+  handler.getopts = create;
+  handler.start = start;
+  handler.priv_size = sizeof(priv_t);
+  return &handler;
+}
--- /dev/null
+++ b/src/firfit.c
@@ -1,0 +1,134 @@
+/* Effect: firfit filter     Copyright (c) 2009 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* This is W.I.P. hence marked SOX_EFF_DEPRECATED for now.
+ * Need to add other interpolation types e.g. linear, bspline, window types,
+ * and filter length, maybe phase response type too.
+ */
+
+#include "sox_i.h"
+#include "dft_filter.h"
+
+typedef struct {
+  dft_filter_priv_t base;
+  char const         * filename;
+  struct {double f, gain;} * knots;
+  int        num_knots, n;
+} priv_t;
+
+static int create(sox_effect_t * effp, int argc, char **argv)
+{
+  priv_t * p = (priv_t *)effp->priv;
+  dft_filter_priv_t * b = &p->base;
+  b->filter_ptr = &b->filter;
+  --argc, ++argv;
+  if (argc == 1)
+    p->filename = argv[0], --argc;
+  p->n = 2047;
+  return argc? lsx_usage(effp) : SOX_SUCCESS;
+}
+
+static double * make_filter(sox_effect_t * effp)
+{
+  priv_t * p = (priv_t *)effp->priv;
+  double * log_freqs, * gains, * d, * work, * h;
+  sox_rate_t rate = effp->in_signal.rate;
+  int i, work_len;
+  
+  lsx_valloc(log_freqs , p->num_knots);
+  lsx_valloc(gains, p->num_knots);
+  lsx_valloc(d  , p->num_knots);
+  for (i = 0; i < p->num_knots; ++i) {
+    log_freqs[i] = log(max(p->knots[i].f, 1));
+    gains[i] = p->knots[i].gain;
+  }
+  lsx_prepare_spline3(log_freqs, gains, p->num_knots, HUGE_VAL, HUGE_VAL, d);
+
+  for (work_len = 8192; work_len < rate / 2; work_len <<= 1);
+  work = lsx_calloc(work_len + 2, sizeof(*work));
+  lsx_valloc(h, p->n);
+
+  for (i = 0; i <= work_len; i += 2) {
+    double f = rate * 0.5 * i / work_len;
+    double spl1 = f < max(p->knots[0].f, 1)? gains[0] : 
+                  f > p->knots[p->num_knots - 1].f? gains[p->num_knots - 1] :
+                  lsx_spline3(log_freqs, gains, d, p->num_knots, log(f));
+    work[i] = dB_to_linear(spl1);
+  }
+  LSX_PACK(work, work_len);
+  lsx_safe_rdft(work_len, -1, work);
+  for (i = 0; i < p->n; ++i)
+    h[i] = work[(work_len - p->n / 2 + i) % work_len] * 2. / work_len;
+  lsx_apply_blackman_nutall(h, p->n);
+
+  free(work);
+  return h;
+}
+
+static sox_bool read_knots(sox_effect_t * effp)
+{
+  priv_t * p = (priv_t *) effp->priv;
+  FILE * file = lsx_open_input_file(effp, p->filename);
+  sox_bool result = sox_false;
+  int num_converted;
+  char c;
+
+  if (file) {
+    lsx_valloc(p->knots, 1);
+    while (fscanf(file, " #%*[^\n]%c", &c) >= 0) {
+      num_converted = fscanf(file, "%lf %lf",
+          &p->knots[p->num_knots].f, &p->knots[p->num_knots].gain);
+      if (num_converted == 2)
+        lsx_revalloc(p->knots, ++p->num_knots + 1);
+      else if (num_converted != 0)
+        break;
+    }
+    lsx_report("%i knots", p->num_knots);
+    if (feof(file) && num_converted != 1)
+      result = sox_true;
+    else lsx_fail("error reading knot file");
+    if (file != stdin)
+      fclose(file);
+  }
+  return result;
+}
+
+static int start(sox_effect_t * effp)
+{
+  priv_t * p = (priv_t *) effp->priv;
+  dft_filter_t * f = p->base.filter_ptr;
+
+  if (!f->num_taps) {
+    if (!p->num_knots && !read_knots(effp))
+      return SOX_EOF;
+    lsx_set_dft_filter(f, make_filter(effp), p->n, p->n >> 1);
+  }
+  return sox_dft_filter_effect_fn()->start(effp);
+}
+
+sox_effect_handler_t const * sox_firfit_effect_fn(void)
+{
+  static sox_effect_handler_t handler;
+  handler = *sox_dft_filter_effect_fn();
+  handler.name = "firfit";
+  handler.usage = "[knots-file]";
+  handler.flags |= SOX_EFF_DEPRECATED;
+  handler.getopts = create;
+  handler.start = start;
+  handler.priv_size = sizeof(priv_t);
+  return &handler;
+}
--- a/src/loudness.c
+++ b/src/loudness.c
@@ -78,7 +78,7 @@
   work = lsx_calloc(work_len, sizeof(*work));
   h = lsx_calloc(n, sizeof(*h));
 
-  for (i = 1; i <= work_len / 2; ++i) {
+  for (i = 0; i <= work_len / 2; ++i) {
     double f = rate * i / work_len;
     double spl1 = f < 1? spl[0] : lsx_spline3(fs, spl, d, (int)LEN, log(f));
     work[i < work_len / 2 ? 2 * i : 1] = dB_to_linear(spl1);
@@ -97,7 +97,7 @@
 static int start(sox_effect_t * effp)
 {
   priv_t * p = (priv_t *) effp->priv;
-  dft_filter_filter_t * f = p->base.filter_ptr;
+  dft_filter_t * f = p->base.filter_ptr;
 
   if (p->delta == 0)
     return SOX_EFF_NULL;
@@ -104,16 +104,14 @@
 
   if (!f->num_taps) {
     double * h = make_filter(p->n, p->start, p->delta, effp->in_signal.rate);
-    int i, dft_length = lsx_set_dft_length(p->n);
-    f->coefs = lsx_calloc(dft_length, sizeof(*f->coefs));
-    for (i = 0; i < p->n; ++i)
-      f->coefs[(i + dft_length - p->n + 1) & (dft_length - 1)]
-          = h[i] / dft_length * 2;
-    free(h);
-    f->num_taps = p->n;
-    f->post_peak = f->num_taps / 2;
-    f->dft_length = dft_length;
-    lsx_safe_rdft(dft_length, 1, f->coefs);
+    if (effp->global_info->plot != sox_plot_off) {
+      char title[100];
+      sprintf(title, "SoX effect: loudness %g (%g)", p->delta, p->start);
+      lsx_plot_fir(h, p->n, effp->in_signal.rate,
+          effp->global_info->plot, title, p->delta - 5, 0.);
+      return SOX_EOF;
+    }
+    lsx_set_dft_filter(f, h, p->n, p->n >> 1);
   }
   return sox_dft_filter_effect_fn()->start(effp);
 }
--- a/src/noisered.c
+++ b/src/noisered.c
@@ -86,8 +86,11 @@
     size_t fchannels = 0;
     size_t channels = effp->in_signal.channels;
     size_t i;
-    FILE* ifp;
+    FILE * ifp = lsx_open_input_file(effp, data->profile_filename);
 
+    if (!ifp)
+      return SOX_EOF;
+
     data->chandata = lsx_calloc(channels, sizeof(*(data->chandata)));
     data->bufdata = 0;
     for (i = 0; i < channels; i ++) {
@@ -95,22 +98,6 @@
         data->chandata[i].smoothing = lsx_calloc(FREQCOUNT, sizeof(float));
         data->chandata[i].lastwindow = NULL;
     }
-
-    /* Here we actually open the input file. */
-    if (!data->profile_filename || !strcmp(data->profile_filename, "-")) {
-      if (effp->global_info->global_info->stdin_in_use_by) {
-        lsx_fail("stdin already in use by '%s'", effp->global_info->global_info->stdin_in_use_by);
-        return SOX_EOF;
-      }
-      effp->global_info->global_info->stdin_in_use_by = effp->handler.name;
-      ifp = stdin;
-    }
-    else if ((ifp = fopen(data->profile_filename, "r")) == NULL) {
-        lsx_fail("Couldn't open profile file %s: %s",
-                data->profile_filename, strerror(errno));
-        return SOX_EOF;
-    }
-
     while (1) {
         unsigned long i1_ul;
         size_t i1;
@@ -127,7 +114,7 @@
         data->chandata[fchannels].noisegate[0] = f1;
         for (i = 1; i < FREQCOUNT; i ++) {
             if (1 != fscanf(ifp, ", %f", &f1)) {
-                lsx_fail("noisered: Not enough datums for channel %lu "
+                lsx_fail("noisered: Not enough data for channel %lu "
                         "(expected %d, got %lu)", (unsigned long)fchannels, FREQCOUNT, (unsigned long)i);
                 return SOX_EOF;
             }
--- a/src/rate.c
+++ b/src/rate.c
@@ -26,8 +26,7 @@
 #include "sox_i.h"
 #include "fft4g.h"
 #include "getopt.h"
-#define  FIFO_SIZE_T int
-#include "fifo.h"
+#include "dft_filter.h"
 #include <assert.h>
 #include <string.h>
 
@@ -69,14 +68,9 @@
   return result;
 }
 
-typedef struct {
-  int        dft_length, num_taps, post_peak;
-  sample_t   * coefs;
-} half_band_t;      /* Note: not half-band as in symmetric about Fn/2 (Fs/4) */
-
 typedef struct {    /* Data that are shared between channels and filters */
   sample_t   * poly_fir_coefs;
-  half_band_t half_band[2];    /* [0]: halve; [1]: down/up: halve/double */
+  dft_filter_t half_band[2];    /* [0]: halve; [1]: down/up: halve/double */
 } rate_shared_t;
 
 struct stage;
@@ -130,7 +124,7 @@
   sample_t * output;
   int i, j, num_in = max(0, fifo_occupancy(&p->fifo));
   rate_shared_t const * s = p->shared;
-  half_band_t const * f = &s->half_band[p->which];
+  dft_filter_t const * f = &s->half_band[p->which];
   int const overlap = f->num_taps - 1;
 
   while (num_in >= f->dft_length) {
@@ -162,7 +156,7 @@
   sample_t * output;
   int i, j, num_in = max(0, fifo_occupancy(&p->fifo));
   rate_shared_t const * s = p->shared;
-  half_band_t const * f = &s->half_band[1];
+  dft_filter_t const * f = &s->half_band[1];
   int const overlap = f->num_taps - 1;
 
   while (num_in > f->dft_length >> 1) {
@@ -191,7 +185,7 @@
     int num_taps, sample_t const h[], double Fp, double att, int multiplier,
     double phase, sox_bool allow_aliasing)
 {
-  half_band_t * f = &p->half_band[which];
+  dft_filter_t * f = &p->half_band[which];
   int dft_length, i;
 
   if (f->num_taps)
--- a/src/sinc.c
+++ b/src/sinc.c
@@ -98,12 +98,12 @@
 static int start(sox_effect_t * effp)
 {
   priv_t * p = (priv_t *)effp->priv;
-  dft_filter_filter_t * f = p->base.filter_ptr;
+  dft_filter_t * f = p->base.filter_ptr;
 
   if (!f->num_taps) {
     double Fn = effp->in_signal.rate * .5;
     double * h[2];
-    int i, longer;
+    int i, n, post_peak, longer;
 
     if (p->Fc0 >= Fn || p->Fc1 >= Fn) {
       lsx_fail("filter frequency must be less than sample-rate / 2");
@@ -110,38 +110,34 @@
       return SOX_EOF;
     }
     h[0] = lpf(Fn, p->Fc0, p->tbw0, &p->num_taps[0], p->att, &p->beta,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->round);
+    if (h[0])
+      invert(h[0], p->num_taps[0]);
 
     longer = p->num_taps[1] > p->num_taps[0];
-    f->num_taps = p->num_taps[longer];
+    n = p->num_taps[longer];
     if (h[0] && h[1]) {
       for (i = 0; i < p->num_taps[!longer]; ++i)
-        h[longer][i + (f->num_taps - p->num_taps[!longer])/2] += h[!longer][i];
+        h[longer][i + (n - p->num_taps[!longer])/2] += h[!longer][i];
 
       if (p->Fc0 < p->Fc1)
-        invert(h[longer], f->num_taps);
+        invert(h[longer], n);
 
       free(h[!longer]);
     }
     if (p->phase != 50)
-      lsx_fir_to_phase(&h[longer], &f->num_taps, &f->post_peak, p->phase);
-    else f->post_peak = f->num_taps / 2;
+      lsx_fir_to_phase(&h[longer], &n, &post_peak, p->phase);
+    else post_peak = n >> 1;
 
     if (effp->global_info->plot != sox_plot_off) {
       char title[100];
       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,
+      lsx_plot_fir(h[longer], n, effp->in_signal.rate,
           effp->global_info->plot, title, -p->beta * 10 - 25, 5.);
       return SOX_EOF;
     }
-    f->dft_length = lsx_set_dft_length(f->num_taps);
-    f->coefs = lsx_calloc(f->dft_length, sizeof(*f->coefs));
-    for (i = 0; i < f->num_taps; ++i)
-      f->coefs[(i + f->dft_length - f->num_taps + 1) & (f->dft_length - 1)] = h[longer][i] / f->dft_length * 2;
-    free(h[longer]);
-    lsx_safe_rdft(f->dft_length, 1, f->coefs);
+    lsx_set_dft_filter(f, h[longer], n, post_peak);
   }
   return sox_dft_filter_effect_fn()->start(effp);
 }
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -83,6 +83,7 @@
     double phase);      /* Phase at 1st point; 0..2pi. (e.g. pi/2 for cosine) */
 char const * lsx_parsesamples(sox_rate_t rate, const char *str, size_t *samples, int def);
 double lsx_parse_frequency(char const * text, char * * end_ptr);
+FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename);
 
 void lsx_prepare_spline3(double const * x, double const * y, int n,
     double start_1d, double end_1d, double * y_2d);
--- a/src/xmalloc.h
+++ b/src/xmalloc.h
@@ -28,5 +28,7 @@
 #define lsx_calloc(n,s) ((n)*(s)? memset(lsx_malloc((n)*(s)),0,(n)*(s)) : NULL)
 #define lsx_strdup(p) ((p)? strcpy((char *)lsx_malloc(strlen(p) + 1), p) : NULL)
 #define lsx_memdup(p,s) ((p)? memcpy(lsx_malloc(s), p, s) : NULL)
+#define lsx_valloc(v,n)  v = lsx_malloc((n)*sizeof(*(v)))
+#define lsx_revalloc(v,n)  v = lsx_realloc(v, (n)*sizeof(*(v)))
 
 #endif