You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.1 KiB
102 lines
3.1 KiB
/* 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 "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/76.5 + 2;
|
|
p->taps += 1 - (p->taps%2);
|
|
/* results in a cutoff frequency of about 75 Hz with a Blackman window */
|
|
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_blackman(p->h, p->taps, .16);
|
|
|
|
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;
|
|
}
|
|
|