ref: 1fd5a4013de02f96e3b59514c745c67354ab33c3
parent: fa80a671a7ce6198fb0f904a7cc1b4d716d70d7e
author: robs <robs>
date: Mon Jan 26 13:36:28 EST 2009
new sinc filter effect
--- a/ChangeLog
+++ b/ChangeLog
@@ -26,6 +26,7 @@
ated in [F(ormat)] [E(ffect)] Replacement due after
------- ---------------------- ---------------------- -------
14.3.0 E norm -b, norm -i gain -B, gain -en 14.3.0 + 1 year
+ 14.3.0 E filter ~=sinc 14.3.0 + 1 year
14.3.0 F flac: libFLAC 1.1.2,3 libFLAC > 1.1.3 14.3.0 + 6 months
Previously deprecated features (to be removed in future):
@@ -68,6 +69,7 @@
Effects:
+ o New `sinc' FFT filter effect; replacement for `filter'. (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/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 phaser stat
- biquad earwax lowfir rate stretch
- biquads echo mcompand remix swap
- chorus echos mixer repeat synth
- compand fade noiseprof reverb tempo
- compandt fft4g noisered reverse tremolo
- contrast filter output silence trim
- dcshift flanger overdrive skeleff vol
- delay gain pad speed
- dft_filter input pan splice
+ 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
)
set(formats_srcs
8svx dat ima-fmt s3-fmt u3-fmt
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -279,7 +279,7 @@
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 lowfir.c
+ dft_filter.c dft_filter.h sinc.c
if HAVE_PNG
libsox_la_SOURCES += spectrogram.c
endif
--- a/src/effects.h
+++ b/src/effects.h
@@ -44,7 +44,6 @@
EFFECT(ladspa)
#endif
EFFECT(loudness)
- EFFECT(lowfir)
EFFECT(lowpass)
EFFECT(mcompand)
EFFECT(mixer)
@@ -68,6 +67,7 @@
EFFECT(reverse)
EFFECT(riaa)
EFFECT(silence)
+ EFFECT(sinc)
#ifdef HAVE_PNG
EFFECT(spectrogram)
#endif
--- a/src/effects_i_dsp.c
+++ b/src/effects_i_dsp.c
@@ -264,6 +264,18 @@
return h;
}
+int lsx_lpf_num_taps(double att, double tr_bw, int k)
+{ /* TODO this could be cleaner, esp. for k != 0 */
+ int n;
+ if (att <= 80)
+ n = .25 / M_PI * (att - 7.95) / (2.285 * tr_bw) + .5;
+ else {
+ double n160 = (.0425* att - 1.4) / tr_bw; /* Half order for att = 160 */
+ n = n160 * (16.556 / (att - 39.6) + .8625) + .5; /* For att [80,160) */
+ }
+ return k? 2 * n : 2 * (n + (n & 1)) + 1; /* =1 %4 (0 phase 1/2 band) */
+}
+
double * lsx_design_lpf(
double Fp, /* End of pass-band; ~= 0.01dB point */
double Fc, /* Start of stop-band */
@@ -280,18 +292,9 @@
Fp /= Fn, Fc /= Fn; /* Normalise to Fn = 1 */
tr_bw = LSX_TO_6dB * (Fc-Fp); /* Transition band-width: 6dB to stop points */
- if (*num_taps == 0) { /* TODO this could be cleaner, esp. for k != 0 */
- int n;
- if (att <= 80)
- n = .25 / M_PI * (att - 7.95) / (2.285 * tr_bw) + .5;
- else {
- double n160 = (.0425* att - 1.4) / tr_bw; /* Half order for att = 160 */
- n = n160 * (16.556 / (att - 39.6) + .8625) + .5; /* For att [80,160) */
- }
- *num_taps = k? 2 * n : 2 * (n + (n & 1)) + 1; /* =1 %4 (0 phase 1/2 band) */
- }
- beta = att < 21 ? 0 : att < 50 ? .5842 * pow((att - 21), .4) + .07886 *
- (att - 21) : att < 100 ? .1102 * (att - 8.7) : .1117 * att - 1.11;
+ if (!*num_taps)
+ *num_taps = lsx_lpf_num_taps(att, tr_bw, k);
+ beta = lsx_kaiser_beta(att);
if (k)
*num_taps = *num_taps * k - 1;
else k = 1;
@@ -299,11 +302,27 @@
return lsx_make_lpf(*num_taps, (Fc - tr_bw) / k, beta, (double)k);
}
+#if 0
+static void printf_vector(FILE * f, double h[], int num_points)
+{
+ int i;
+ printf(
+ "# 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]);
+ exit(0);
+}
+#endif
+
void lsx_fir_to_phase(double * * h, int * len,
int * post_len, double phase0)
{
double * work, phase = (phase0 > 50 ? 100 - phase0 : phase0) / 50;
- int work_len, begin, end, peak = 0, i = *len;
+ int work_len, begin, end, abs_peak = 0, peak = 0, i = *len;
+ double sum = 0, peak_sum = 0;
for (work_len = 32; i > 1; work_len <<= 1, i >>= 1);
work = calloc((size_t)work_len /* + 2 */, sizeof(*work)); /* +2: (UN)PACK */
@@ -310,9 +329,9 @@
for (i = 0; i < *len; ++i) work[i] = (*h)[i];
lsx_safe_rdft(work_len, 1, work); /* Cepstral: */
- work[0] = log(fabs(work[0])), work[1] = log(fabs(work[1]));
+ work[0] = safe_log(work[0]), work[1] = safe_log(work[1]);
for (i = 2; i < work_len; i += 2) {
- work[i] = log(sqrt(sqr(work[i]) + sqr(work[i + 1])));
+ work[i] = safe_log(sqrt(sqr(work[i]) + sqr(work[i + 1])));
work[i + 1] = 0;
}
lsx_safe_rdft(work_len, -1, work);
@@ -329,7 +348,7 @@
UNPACK(work, work_len);
unwrap_phase(work, work_len);
PACK(work, work_len);
- octave_out(stdout, work, work_len);
+ printf_vector(work, work_len);
#endif
for (i = 2; i < work_len; i += 2) /* Interpolate between linear & min phase */
@@ -344,10 +363,19 @@
lsx_safe_rdft(work_len, -1, work);
for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len;
- for (i = 1; i < work_len; ++i) if (work[i] > work[peak]) /* Find peak pos. */
- peak = i; /* N.B. peak val. > 0 */
-
- lsx_debug("peak-pos=%i", peak);
+ for (i = 0; i < work_len; ++i) { /* Find peak pos. */
+ sum += work[i];
+ if (fabs(sum) > peak_sum) {
+ peak_sum = fabs(sum);
+ peak = i;
+ }
+ if (work[i] > work[abs_peak]) /* For debug check only */
+ abs_peak = i;
+ }
+ while (fabs(work[peak-1]) > fabs(work[peak]) && work[peak-1] * work[peak] > 0)
+ --peak;
+ lsx_debug("peak: sum@work[%i]=%g (val@work[%i]=%g)",
+ peak, peak_sum, abs_peak, work[abs_peak]);
if (phase == 0)
begin = 0;
else if (phase == 1)
@@ -369,4 +397,56 @@
(*h)[i] = work[begin + (phase0 > 50 ? *len - 1 - i : i)];
*post_len = phase0 > 50 ? peak - begin : begin + *len - (peak + 1);
free(work);
+}
+
+void lsx_plot_fir(double * h, int num_points, sox_rate_t rate, sox_plot_t type, char const * title, double y1, double y2)
+{
+ int i, N = lsx_set_dft_length(num_points);
+ if (type == sox_plot_gnuplot) {
+ double * h1 = lsx_calloc(N, sizeof(*h1));
+ double * H = lsx_malloc((N / 2 + 1) * sizeof(*H));
+ memcpy(h1, h, sizeof(*h1) * num_points);
+ lsx_power_spectrum(N, h1, H);
+ printf(
+ "# gnuplot file\n"
+ "set title '%s'\n"
+ "set xlabel 'Frequency (Hz)'\n"
+ "set ylabel 'Amplitude Response (dB)'\n"
+ "set grid xtics ytics\n"
+ "set key off\n"
+ "plot '-' with lines\n"
+ , title);
+ for (i = 0; i <= N/2; ++i)
+ printf("%g %g\n", i * rate / N, 10 * log10(H[i]));
+ printf(
+ "e\n"
+ "pause -1 'Hit return to continue'\n");
+ free(H);
+ free(h1);
+ }
+ else if (type == sox_plot_octave) {
+ printf("%% GNU Octave file (may also work with MATLAB(R) )\nb=[");
+ for (i = 0; i < num_points; ++i)
+ printf("%24.16e\n", h[i]);
+ printf("];\n"
+ "[h,w]=freqz(b,1,%i);\n"
+ "plot(%g*w/pi,20*log10(h))\n"
+ "title('%s')\n"
+ "xlabel('Frequency (Hz)')\n"
+ "ylabel('Amplitude Response (dB)')\n"
+ "grid on\n"
+ "axis([0 %g %g %g])\n"
+ "disp('Hit return to continue')\n"
+ "pause\n"
+ , N, rate * .5, title, rate * .5, y1, y2);
+ }
+ else if (type == sox_plot_data) {
+ printf("# %s\n"
+ "# name: b\n"
+ "# type: matrix\n"
+ "# rows: %i\n"
+ "# columns: 1\n", title, num_points);
+ for (i = 0; i < num_points; ++i)
+ printf("%24.16e\n", h[i]);
+ }
}
--- a/src/filter.c
+++ b/src/filter.c
@@ -200,13 +200,6 @@
return (SOX_SUCCESS);
}
-static int p2(long n)
-{
- int N;
- for (N = 1; n; n >>= 1, N <<= 1);
- return max(N, 1024);
-}
-
/*
* Prepare processing.
*/
@@ -277,53 +270,20 @@
f->Xh = Xh;
f->Xt = Xh;
- if (effp->global_info->plot == sox_plot_gnuplot) {
- int N = p2(2 * Xh + 1);
- double * h = lsx_calloc(N, sizeof(*h));
- double * H = lsx_malloc((N / 2 + 1) * sizeof(*H));
+ if (effp->global_info->plot != sox_plot_off) {
+ int n = 2 * Xh + 1;
+ double * h = lsx_malloc(n * sizeof(*h));
+ char title[100];
+ sprintf(title, "SoX effect: filter frequency=%g-%g", f->freq0, f->freq1);
for (i = 1; i < Xh + 1; ++i)
h[i - 1] = f->Fp[Xh + 1 - i];
for (i = 0; i < Xh + 1; ++i)
h[Xh + i] = f->Fp[i];
- lsx_power_spectrum(N, h, H);
+ lsx_plot_fir(h, n, effp->in_signal.rate, effp->global_info->plot, title, -f->beta * 10 - 20, 10.);
free(h);
- printf(
- "# gnuplot file\n"
- "set title 'SoX effect: filter frequency=%g-%g'\n"
- "set xlabel 'Frequency (Hz)'\n"
- "set ylabel 'Amplitude Response (dB)'\n"
- "set grid xtics ytics\n"
- "set key off\n"
- "plot '-' with lines\n"
- , f->freq0, f->freq1);
- for (i = 0; i <= N/2; ++i)
- printf("%g %g\n", i * effp->in_signal.rate / N, 10 * log10(H[i]));
- printf(
- "e\n"
- "pause -1 'Hit return to continue'\n");
- free(H);
return SOX_EOF;
}
- if (effp->global_info->plot == sox_plot_octave) {
- printf("%% GNU Octave file (may also work with MATLAB(R) )\nb=[");
- for (i = 1; i < Xh + 1; ++i)
- printf("%24.16e\n", f->Fp[Xh + 1 - i]);
- for (i = 0; i < Xh + 1; ++i)
- printf("%24.16e\n", f->Fp[i]);
- printf("];\n"
- "[h,w]=freqz(b);\n"
- "plot(%g*w/pi,20*log10(h))\n"
- "title('SoX effect: filter frequency=%g-%g')\n"
- "xlabel('Frequency (Hz)')\n"
- "ylabel('Amplitude Response (dB)')\n"
- "grid on\n"
- "disp('Hit return to continue')\n"
- "pause\n"
- , effp->in_signal.rate / 2, f->freq0, f->freq1);
- return SOX_EOF;
- }
-
f->X = lsx_malloc(sizeof(double) * (2*BUFFSIZE + 2*Xh));
f->Y = f->X + BUFFSIZE + 2*Xh;
@@ -469,7 +429,7 @@
static sox_effect_handler_t sox_filter_effect = {
"filter",
"low-high [ windowlength [ beta ] ]",
- 0,
+ SOX_EFF_DEPRECATED,
sox_filter_getopts,
sox_filter_start,
sox_filter_flow,
--- a/src/gain.c
+++ b/src/gain.c
@@ -227,8 +227,23 @@
sox_effect_handler_t const * sox_gain_effect_fn(void)
{
static sox_effect_handler_t handler = {
- "gain", "[-e|-b|-B|-r] [-n] [-l|-h] [gain-dB]", SOX_EFF_GAIN,
+ "gain", NULL, SOX_EFF_GAIN,
create, start, flow, drain, stop, NULL, sizeof(priv_t)};
+ static char const * lines[] = {
+ "[-e|-b|-B|-r] [-n] [-l|-h] [gain-dB]",
+ "-e\tEqualise channels: peak to that with max peak;",
+ "-B\tBalance channels: rms to that with max rms; no clip protection",
+ "-b\tBalance channels: rms to that with max rms; clip protection",
+ "\t Note -Bn = -bn",
+ "-r\tReclaim headroom (as much as possible without clipping); see -h",
+ "-n\tNorm file to 0dBfs(output precision); gain-dB, if present, usually <0",
+ "-l\tUse simple limiter",
+ "-h\tApply attenuation for headroom for subsequent effects;",
+ "\t gain-dB, if present is subject to reclaim by a subsequent gain -r",
+ "gain-dB\tApply gain in dB",
+ };
+ static char * usage;
+ handler.usage = lsx_usage_lines(&usage, lines, array_length(lines));
return &handler;
}
--- a/src/getopt.c
+++ b/src/getopt.c
@@ -900,7 +900,7 @@
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
- if (*nextchar == '\0')
+ if (temp && *nextchar == '\0') /* SoX */
++optind;
if (temp == NULL || c == ':')
@@ -944,6 +944,7 @@
}
#endif
}
+ nextchar = (char *) ""; /* SoX */
optopt = c;
return '?';
}
--- a/src/lowfir.c
+++ /dev/null
@@ -1,85 +1,0 @@
-/* Effect: lowfir filter Copyright (c) 2008 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 filter types (and rename file), and add a decent
- * user interface. When this is done, it should be a more user-friendly
- * & more capable version of the `filter' effect.
- */
-
-#include "sox_i.h"
-#include "dft_filter.h"
-#include <string.h>
-
-typedef struct {
- dft_filter_priv_t base;
- double Fp, Fc, Fn, att, phase;
- int allow_aliasing, num_taps, k;
-} 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;
- dft_filter_filter_t * f = &b->filter;
- double * h;
- int i;
- b->filter_ptr = &b->filter;
- --argc, ++argv;
- do { /* break-able block */
- NUMERIC_PARAMETER(Fp, 0, 100);
- NUMERIC_PARAMETER(Fc, 0, 100);
- NUMERIC_PARAMETER(Fn, 0, 100);
- NUMERIC_PARAMETER(allow_aliasing, 0, 1);
- NUMERIC_PARAMETER(att, 80, 200);
- NUMERIC_PARAMETER(num_taps, 0, 65536);
- NUMERIC_PARAMETER(k, 0, 512);
- NUMERIC_PARAMETER(phase, 0, 100);
- } while (0);
-
- if (p->phase != 0 && p->phase != 50 && p->phase != 100)
- p->att *= 34./33; /* negate degradation with intermediate phase */
- h = lsx_design_lpf(
- p->Fp, p->Fc, p->Fn, p->allow_aliasing, p->att, &p->num_taps, p->k);
- f->num_taps = p->num_taps;
-
- if (p->phase != 50)
- lsx_fir_to_phase(&h, &f->num_taps, &f->post_peak, p->phase);
- else f->post_peak = f->num_taps / 2;
- lsx_debug("%i %i %g%%",
- f->num_taps, f->post_peak, 100 - 100. * f->post_peak / (f->num_taps - 1));
-
- 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;
- free(h);
- lsx_safe_rdft(f->dft_length, 1, f->coefs);
- return argc? lsx_usage(effp) : SOX_SUCCESS;
-}
-
-sox_effect_handler_t const * sox_lowfir_effect_fn(void)
-{
- static sox_effect_handler_t handler;
- handler = *sox_dft_filter_effect_fn();
- handler.name = "lowfir";
- handler.usage = "[options]";
- handler.flags |= SOX_EFF_DEPRECATED;
- handler.getopts = create;
- handler.priv_size = sizeof(priv_t);
- return &handler;
-}
--- /dev/null
+++ b/src/sinc.c
@@ -1,0 +1,143 @@
+/* Effect: sinc filters Copyright (c) 2008-9 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"
+#include "getopt.h"
+#include <string.h>
+
+typedef struct {
+ dft_filter_priv_t base;
+ double att, phase, freq0, freq1, tbw0, tbw1;
+ int num_taps[2];
+} 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;
+ char * parse_ptr = argv[0];
+ int i = 0;
+
+ b->filter_ptr = &b->filter;
+ p->phase = 50;
+ p->att = 120;
+ 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;
+ case 'M': p->phase = 0; break;
+ case 'I': p->phase = 25; break;
+ case 'L': p->phase = 50; break;
+ default: c = 0;
+ }
+ if (!i++ && !(p->tbw1 && p->num_taps[1])) {
+ 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);
+ }
+ }
+ }
+ return optind != argc || p->freq0 < 0 || p->freq1 < 0 || *parse_ptr ?
+ lsx_usage(effp) : SOX_SUCCESS;
+}
+
+static void invert(double * h, int n)
+{
+ int i;
+ for (i = 0; i < n; ++i)
+ h[i] = -h[i];
+ h[(n - 1) / 2] += 1;
+}
+
+static double * lpf(sox_effect_t * effp, double Fc, double tbw, int * num_taps, double att, double phase)
+{
+ double Fn = effp->in_signal.rate * .5;
+ if (!Fc) {
+ *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.);
+}
+
+static int start(sox_effect_t * effp)
+{
+ priv_t * p = (priv_t *)effp->priv;
+ dft_filter_filter_t * f = p->base.filter_ptr;
+
+ if (!f->num_taps) {
+ 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 (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];
+ 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];
+ free(h[!longer]);
+ if (p->freq0 < p->freq1)
+ invert(h[longer], f->num_taps);
+ }
+ 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_debug("%i %i %g%%", f->num_taps, f->post_peak,
+ 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);
+ lsx_plot_fir(h[longer], f->num_taps, effp->in_signal.rate,
+ effp->global_info->plot, title, -p->att - 20, 10.);
+ 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);
+ }
+ return sox_dft_filter_effect_fn()->start(effp);
+}
+
+sox_effect_handler_t const * sox_sinc_effect_fn(void)
+{
+ 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.getopts = create;
+ handler.start = start;
+ handler.priv_size = sizeof(priv_t);
+ return &handler;
+}
--- a/src/sox.c
+++ b/src/sox.c
@@ -2005,6 +2005,7 @@
LSX_ENUM_ITEM(sox_plot_,off)
LSX_ENUM_ITEM(sox_plot_,octave)
LSX_ENUM_ITEM(sox_plot_,gnuplot)
+ LSX_ENUM_ITEM(sox_plot_,data)
{0, 0}};
enum {
--- a/src/sox.h
+++ b/src/sox.h
@@ -451,7 +451,7 @@
#define SOX_EFF_GAIN 128 /* Effect does not support gain -r */
#define SOX_EFF_MODIFY 256 /* Effect does not modify samples */
-typedef enum {sox_plot_off, sox_plot_octave, sox_plot_gnuplot} sox_plot_t;
+typedef enum {sox_plot_off, sox_plot_octave, sox_plot_gnuplot, sox_plot_data} sox_plot_t;
typedef struct sox_effect sox_effect_t;
struct sox_effects_globals { /* Global parameters (for effects) */
sox_plot_t plot; /* To help the user choose effect & options */
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -108,6 +108,7 @@
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);
+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 */
double Fc, /* Start of stop-band */
@@ -124,6 +125,7 @@
#define LSX_MAX_TBW0A (LSX_MAX_TBW0 / (1 + LSX_TO_3dB))
#define LSX_MAX_TBW3 floor(LSX_MAX_TBW0 * LSX_TO_3dB)
#define LSX_MAX_TBW3A floor(LSX_MAX_TBW0A * LSX_TO_3dB)
+void lsx_plot_fir(double * h, int num_points, sox_rate_t rate, sox_plot_t type, char const * title, double y1, double y2);
#ifndef HAVE_STRCASECMP
int strcasecmp(const char *s1, const char *s2);
--- a/src/util.h
+++ b/src/util.h
@@ -19,6 +19,8 @@
#include "xmalloc.h"
+/*---------------------------- Portability stuff -----------------------------*/
+
#ifdef __GNUC__
#define NORET __attribute__((noreturn))
#define PRINTF __attribute__ ((format (printf, 1, 2)))
@@ -64,29 +66,39 @@
#define SET_BINARY_MODE(file)
#endif
-#ifdef min
-#undef min
+#ifdef WORDS_BIGENDIAN
+#define MACHINE_IS_BIGENDIAN 1
+#define MACHINE_IS_LITTLEENDIAN 0
+#else
+#define MACHINE_IS_BIGENDIAN 0
+#define MACHINE_IS_LITTLEENDIAN 1
#endif
-#define min(a, b) ((a) <= (b) ? (a) : (b))
-#ifdef max
-#undef max
-#endif
-#define max(a, b) ((a) >= (b) ? (a) : (b))
+/*--------------------------- Language extensions ----------------------------*/
/* Compile-time ("static") assertion */
/* e.g. assert_static(sizeof(int) >= 4, int_type_too_small) */
#define assert_static(e,f) enum {assert_static__##f = 1/(e)}
-#define range_limit(x, lower, upper) (min(max(x, lower), upper))
#define array_length(a) (sizeof(a)/sizeof(a[0]))
#define field_offset(type, field) ((size_t)&(((type *)0)->field))
-#define sqr(a) ((a) * (a))
+#define unless(x) if (!(x))
-#define dB_to_linear(x) exp((x) * M_LN10 * 0.05)
-#define linear_to_dB(x) (log10(x) * 20)
+/*------------------------------- Maths stuff --------------------------------*/
#include <math.h>
+#ifdef min
+#undef min
+#endif
+#define min(a, b) ((a) <= (b) ? (a) : (b))
+
+#ifdef max
+#undef max
+#endif
+#define max(a, b) ((a) >= (b) ? (a) : (b))
+
+#define range_limit(x, lower, upper) (min(max(x, lower), upper))
+
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
@@ -100,16 +112,13 @@
#define M_SQRT2 sqrt(2.)
#endif
+#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 */
#define dranqd1(x) (ranqd1(x) * (1. / (65536. * 32768.))) /* [-1,1) */
-#ifdef WORDS_BIGENDIAN
-#define MACHINE_IS_BIGENDIAN 1
-#define MACHINE_IS_LITTLEENDIAN 0
-#else
-#define MACHINE_IS_BIGENDIAN 0
-#define MACHINE_IS_LITTLEENDIAN 1
-#endif
+#define dB_to_linear(x) exp((x) * M_LN10 * 0.05)
+#define linear_to_dB(x) (log10(x) * 20)