1 /* libSoX Compander Crossover Filter (c) 2008 robs@users.sourceforge.net
3 * This library is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or (at
6 * your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11 * General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #define N 4 /* 4th order Linkwitz-Riley IIRs */
19 #define CONVOLVE _ _ _ _
21 typedef struct {double in
, out_low
, out_high
;} previous_t
[N
* 2];
24 previous_t
* previous
;
26 double coefs
[3 *(N
+1)];
29 static void square_quadratic(char const * name
, double const * x
, double * y
)
33 y
[1] = 2 * x
[0] * x
[1];
34 y
[2] = 2 * x
[0] * x
[2] + x
[1] * x
[1];
35 y
[3] = 2 * x
[1] * x
[2];
37 lsx_debug("%s=[%.16g %.16g %.16g %.16g %.16g];", name
,
38 y
[0], y
[1], y
[2], y
[3], y
[4]);
41 static int crossover_setup(sox_effect_t
* effp
, crossover_t
* p
, double frequency
)
43 double w0
= 2 * M_PI
* frequency
/ effp
->in_signal
.rate
;
44 double Q
= sqrt(.5), alpha
= sin(w0
)/(2*Q
);
49 lsx_fail("frequency must not exceed half the sample-rate (Nyquist rate)");
52 x
[0] = (1 - cos(w0
))/2; /* Cf. filter_LPF in biquads.c */
54 x
[2] = (1 - cos(w0
))/2;
55 x
[3] = (1 + cos(w0
))/2; /* Cf. filter_HPF in biquads.c */
56 x
[4] = -(1 + cos(w0
));
57 x
[5] = (1 + cos(w0
))/2;
61 for (norm
= x
[6], i
= 0; i
< 9; ++i
) x
[i
] /= norm
;
62 square_quadratic("lb", x
, p
->coefs
);
63 square_quadratic("hb", x
+ 3, p
->coefs
+ 5);
64 square_quadratic("a" , x
+ 6, p
->coefs
+ 10);
66 p
->previous
= lsx_calloc(effp
->in_signal
.channels
, sizeof(*p
->previous
));
70 static int crossover_flow(sox_effect_t
* effp
, crossover_t
* p
, sox_sample_t
71 *ibuf
, sox_sample_t
*obuf_low
, sox_sample_t
*obuf_high
, size_t len0
)
73 double out_low
, out_high
;
74 size_t c
, len
= len0
/ effp
->in_signal
.channels
;
75 assert(len
* effp
->in_signal
.channels
== len0
);
78 p
->pos
= p
->pos
? p
->pos
- 1 : N
- 1;
79 for (c
= 0; c
< effp
->in_signal
.channels
; ++c
) {
80 #define _ out_low += p->coefs[j] * p->previous[c][p->pos + j].in \
81 - p->coefs[2*N+2 + j] * p->previous[c][p->pos + j].out_low, ++j;
84 out_low
= p
->coefs
[0] * *ibuf
;
87 *obuf_low
++ = SOX_ROUND_CLIP_COUNT(out_low
, effp
->clips
);
90 #define _ out_high += p->coefs[j+N+1] * p->previous[c][p->pos + j].in \
91 - p->coefs[2*N+2 + j] * p->previous[c][p->pos + j].out_high, ++j;
94 out_high
= p
->coefs
[N
+1] * *ibuf
;
97 *obuf_high
++ = SOX_ROUND_CLIP_COUNT(out_high
, effp
->clips
);
99 p
->previous
[c
][p
->pos
+ N
].in
= p
->previous
[c
][p
->pos
].in
= *ibuf
++;
100 p
->previous
[c
][p
->pos
+ N
].out_low
= p
->previous
[c
][p
->pos
].out_low
= out_low
;
101 p
->previous
[c
][p
->pos
+ N
].out_high
= p
->previous
[c
][p
->pos
].out_high
= out_high
;