ref: 263a35a699e2369e07c63d17d912f4e973567541
parent: 9f2bf1b9e38d51e6aa9d6fd15094cd389d23f24f
author: Ulrich Klauer <ulrich@chirlu.de>
date: Mon Dec 5 04:48:27 EST 2011
New hilbert effect A new effect that implements an odd-tap Hilbert transform filter, phase-shifting a signal by 90 degrees.
--- a/ChangeLog
+++ b/ChangeLog
@@ -45,6 +45,7 @@
o Fix crashes in compand and mcompand effects. [3420893] (Ulrich Klauer)
o Let the delay effect gracefully handle the special case that a delay can
be more than the input length. [3055399] (Ulrich Klauer)
+ o New hilbert effect. (Ulrich Klauer)
Misc:
--- a/FEATURES.in
+++ b/FEATURES.in
@@ -59,6 +59,7 @@
** fir: FFT convolution FIR filter using externally provided coefficients
** firfit+: FFT convolution FIR filter using given freq. response (W.I.P.)
** highpass: High-pass filter: Single pole or RBJ biquad IIR
+** hilbert: Hilbert transform filter (90 degrees phase shift)
** lowpass: Low-pass filter: single pole or RBJ biquad IIR
** sinc: Sinc-windowed low/high-pass/band-pass/reject FIR
** treble: Tone control: RBJ shelving biquad IIR filter
--- a/sox.1
+++ b/sox.1
@@ -2317,6 +2317,22 @@
.SP
See also \fBsinc\fR for filters with a steeper roll-off.
.TP
+\fBhilbert\fR [\fB\-n \fItaps\fR]
+Apply an odd-tap Hilbert transform filter, phase-shifting the signal
+by 90 degrees.
+.SP
+This is used in many matrix coding schemes and for analytic signal
+generation. The process is often written as a multiplication by \fIi\fR
+(or \fIj\fR), the imaginary unit.
+.SP
+An odd-tap Hilbert transform filter has a bandpass characteristic,
+attenuating the lowest and highest frequencies. Its bandwidth can be
+controlled by the number of filter taps, which can be specified with
+\fB-n\fR. By default, the number of taps is chosen for a cutoff
+frequency of about 75 Hz.
+.SP
+This effect supports the \fB\-\-plot\fR global option.
+.TP
\fBladspa\fR \fBmodule\fR [\fBplugin\fR] [\fBargument\fR...]
Apply a LADSPA [5] (Linux Audio Developer's Simple Plugin API) plugin.
Despite the name, LADSPA is not Linux-specific, and a wide range of
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -77,7 +77,7 @@
rate_poly_fir.h remix.c repeat.c reverb.c reverse.c silence.c \
sinc.c skeleff.c speed.c speexdsp.c splice.c stat.c stats.c \
stretch.c swap.c synth.c tempo.c tremolo.c trim.c vad.c vol.c \
- ignore-warning.h upsample.c
+ ignore-warning.h upsample.c hilbert.c
if HAVE_PNG
libsox_la_SOURCES += spectrogram.c
endif
--- a/src/effects.h
+++ b/src/effects.h
@@ -44,6 +44,7 @@
EFFECT(flanger)
EFFECT(gain)
EFFECT(highpass)
+ EFFECT(hilbert)
EFFECT(input)
EFFECT(key)
#ifdef HAVE_LADSPA_H
--- /dev/null
+++ b/src/hilbert.c
@@ -1,0 +1,104 @@
+/* libSoX effect: Hilbert transform filter
+ *
+ * First version of this effect written 11/2011 by Ulrich Klauer, using maths
+ * from "Understanding digital signal processing" by Richard G. Lyons.
+ *
+ * Copyright 2011 Chris Bagwell and SoX Contributors
+ *
+ * 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 <math.h>
+
+#include "sox_i.h"
+#include "dft_filter.h"
+
+typedef struct {
+ dft_filter_priv_t base;
+ double *h;
+ int taps;
+} priv_t;
+
+static int getopts(sox_effect_t *effp, int argc, char **argv)
+{
+ lsx_getopt_t optstate;
+ int c;
+ priv_t *p = (priv_t*)effp->priv;
+ dft_filter_priv_t *b = &p->base;
+
+ b->filter_ptr = &b->filter;
+
+ lsx_getopt_init(argc, argv, "+n:", NULL, lsx_getopt_flag_none, 1, &optstate);
+
+ while ((c = lsx_getopt(&optstate)) != -1) switch (c) {
+ GETOPT_NUMERIC(optstate, 'n', taps, 3, 32767)
+ default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp);
+ }
+ if (p->taps && p->taps%2 == 0) {
+ lsx_fail("only filters with an odd number of taps are supported");
+ return SOX_EOF;
+ }
+ return optstate.ind != 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;
+
+ if (!f->num_taps) {
+ int i;
+ if (!p->taps) {
+ p->taps = effp->in_signal.rate/100 + 2;
+ p->taps += 1 - (p->taps%2);
+ /* results in a cutoff frequency of about 75 Hz */
+ lsx_debug("choosing number of taps = %d (override with -n)", p->taps);
+ }
+ lsx_valloc(p->h, p->taps);
+ for (i = 0; i < p->taps; i++) {
+ int k = -(p->taps/2) + i;
+ if (k%2 == 0) {
+ p->h[i] = 0.0;
+ } else {
+ double pk = M_PI * k;
+ p->h[i] = (1 - cos(pk))/pk;
+ }
+ }
+ lsx_apply_hamming(p->h, p->taps);
+
+ if (effp->global_info->plot != sox_plot_off) {
+ char title[100];
+ sprintf(title, "SoX effect: hilbert (%d taps)", p->taps);
+ lsx_plot_fir(p->h, p->taps, effp->in_signal.rate,
+ effp->global_info->plot, title, -20., 5.);
+ free(p->h);
+ return SOX_EOF;
+ }
+ lsx_set_dft_filter(f, p->h, p->taps, p->taps/2);
+ }
+ return lsx_dft_filter_effect_fn()->start(effp);
+}
+
+sox_effect_handler_t const *lsx_hilbert_effect_fn(void)
+{
+ static sox_effect_handler_t handler;
+ handler = *lsx_dft_filter_effect_fn();
+ handler.name = "hilbert";
+ handler.usage = "[-n taps]";
+ handler.getopts = getopts;
+ handler.start = start;
+ handler.priv_size = sizeof(priv_t);
+ return &handler;
+}