1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006-2007 Thom Johansen
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
26 #include "replaygain.h"
28 /* Inverse gain of circular cordic rotation in s0.31 format. */
29 static const long cordic_circular_gain
= 0xb2458939; /* 0.607252929 */
31 /* Table of values of atan(2^-i) in 0.32 format fractions of pi where pi = 0xffffffff / 2 */
32 static const unsigned long atan_table
[] = {
33 0x1fffffff, /* +0.785398163 (or pi/4) */
34 0x12e4051d, /* +0.463647609 */
35 0x09fb385b, /* +0.244978663 */
36 0x051111d4, /* +0.124354995 */
37 0x028b0d43, /* +0.062418810 */
38 0x0145d7e1, /* +0.031239833 */
39 0x00a2f61e, /* +0.015623729 */
40 0x00517c55, /* +0.007812341 */
41 0x0028be53, /* +0.003906230 */
42 0x00145f2e, /* +0.001953123 */
43 0x000a2f98, /* +0.000976562 */
44 0x000517cc, /* +0.000488281 */
45 0x00028be6, /* +0.000244141 */
46 0x000145f3, /* +0.000122070 */
47 0x0000a2f9, /* +0.000061035 */
48 0x0000517c, /* +0.000030518 */
49 0x000028be, /* +0.000015259 */
50 0x0000145f, /* +0.000007629 */
51 0x00000a2f, /* +0.000003815 */
52 0x00000517, /* +0.000001907 */
53 0x0000028b, /* +0.000000954 */
54 0x00000145, /* +0.000000477 */
55 0x000000a2, /* +0.000000238 */
56 0x00000051, /* +0.000000119 */
57 0x00000028, /* +0.000000060 */
58 0x00000014, /* +0.000000030 */
59 0x0000000a, /* +0.000000015 */
60 0x00000005, /* +0.000000007 */
61 0x00000002, /* +0.000000004 */
62 0x00000001, /* +0.000000002 */
63 0x00000000, /* +0.000000001 */
64 0x00000000, /* +0.000000000 */
68 * Implements sin and cos using CORDIC rotation.
70 * @param phase has range from 0 to 0xffffffff, representing 0 and
72 * @param cos return address for cos
73 * @return sin of phase, value is a signed value from LONG_MIN to LONG_MAX,
74 * representing -1 and 1 respectively.
76 static long fsincos(unsigned long phase
, long *cos
) {
81 /* Setup initial vector */
82 x
= cordic_circular_gain
;
86 /* The phase has to be somewhere between 0..pi for this to work right */
87 if (z
< 0xffffffff / 4) {
88 /* z in first quadrant, z += pi/2 to correct */
91 } else if (z
< 3 * (0xffffffff / 4)) {
92 /* z in third quadrant, z -= pi/2 to correct */
95 /* z in fourth quadrant, z -= 3pi/2 to correct */
97 z
-= 3 * (0xffffffff / 4);
100 /* Each iteration adds roughly 1-bit of extra precision */
101 for (i
= 0; i
< 31; i
++) {
106 /* Decided which direction to rotate vector. Pivot point is pi/2 */
107 if (z
>= 0xffffffff / 4) {
124 * Calculate first order shelving filter. Filter is not directly usable by the
125 * eq_filter() function.
126 * @param cutoff shelf midpoint frequency. See eq_pk_coefs for format.
127 * @param A decibel value multiplied by ten, describing gain/attenuation of
128 * shelf. Max value is 24 dB.
129 * @param low true for low-shelf filter, false for high-shelf filter.
130 * @param c pointer to coefficient storage. Coefficients are s4.27 format.
132 void filter_shelf_coefs(unsigned long cutoff
, long A
, bool low
, int32_t *c
)
135 int32_t b0
, b1
, a0
, a1
; /* s3.28 */
136 const long g
= get_replaygain_int(A
*5) << 4; /* 10^(db/40), s3.28 */
138 sin
= fsincos(cutoff
/2, &cos
);
140 const int32_t sin_div_g
= DIV64(sin
, g
, 25);
142 b0
= FRACMUL(sin
, g
) + cos
; /* 0.25 .. 4.10 */
143 b1
= FRACMUL(sin
, g
) - cos
; /* -1 .. 3.98 */
144 a0
= sin_div_g
+ cos
; /* 0.25 .. 4.10 */
145 a1
= sin_div_g
- cos
; /* -1 .. 3.98 */
147 const int32_t cos_div_g
= DIV64(cos
, g
, 25);
149 b0
= sin
+ FRACMUL(cos
, g
); /* 0.25 .. 4.10 */
150 b1
= sin
- FRACMUL(cos
, g
); /* -3.98 .. 1 */
151 a0
= sin
+ cos_div_g
; /* 0.25 .. 4.10 */
152 a1
= sin
- cos_div_g
; /* -3.98 .. 1 */
155 const int32_t rcp_a0
= DIV64(1, a0
, 57); /* 0.24 .. 3.98, s2.29 */
156 *c
++ = FRACMUL_SHL(b0
, rcp_a0
, 1); /* 0.063 .. 15.85 */
157 *c
++ = FRACMUL_SHL(b1
, rcp_a0
, 1); /* -15.85 .. 15.85 */
158 *c
++ = -FRACMUL_SHL(a1
, rcp_a0
, 1); /* -1 .. 1 */
161 #ifdef HAVE_SW_TONE_CONTROLS
163 * Calculate second order section filter consisting of one low-shelf and one
164 * high-shelf section.
165 * @param cutoff_low low-shelf midpoint frequency. See eq_pk_coefs for format.
166 * @param cutoff_high high-shelf midpoint frequency.
167 * @param A_low decibel value multiplied by ten, describing gain/attenuation of
168 * low-shelf part. Max value is 24 dB.
169 * @param A_high decibel value multiplied by ten, describing gain/attenuation of
170 * high-shelf part. Max value is 24 dB.
171 * @param A decibel value multiplied by ten, describing additional overall gain.
172 * @param c pointer to coefficient storage. Coefficients are s4.27 format.
174 void filter_bishelf_coefs(unsigned long cutoff_low
, unsigned long cutoff_high
,
175 long A_low
, long A_high
, long A
, int32_t *c
)
177 const long g
= get_replaygain_int(A
*10) << 7; /* 10^(db/20), s0.31 */
178 int32_t c_ls
[3], c_hs
[3];
180 filter_shelf_coefs(cutoff_low
, A_low
, true, c_ls
);
181 filter_shelf_coefs(cutoff_high
, A_high
, false, c_hs
);
182 c_ls
[0] = FRACMUL(g
, c_ls
[0]);
183 c_ls
[1] = FRACMUL(g
, c_ls
[1]);
185 /* now we cascade the two first order filters to one second order filter
186 * which can be used by eq_filter(). these resulting coefficients have a
187 * really wide numerical range, so we use a fixed point format which will
188 * work for the selected cutoff frequencies (in dsp.c) only.
190 const int32_t b0
= c_ls
[0], b1
= c_ls
[1], b2
= c_hs
[0], b3
= c_hs
[1];
191 const int32_t a0
= c_ls
[2], a1
= c_hs
[2];
192 *c
++ = FRACMUL_SHL(b0
, b2
, 4);
193 *c
++ = FRACMUL_SHL(b0
, b3
, 4) + FRACMUL_SHL(b1
, b2
, 4);
194 *c
++ = FRACMUL_SHL(b1
, b3
, 4);
196 *c
++ = -FRACMUL_SHL(a0
, a1
, 4);
200 /* Coef calculation taken from Audio-EQ-Cookbook.txt by Robert Bristow-Johnson.
201 * Slightly faster calculation can be done by deriving forms which use tan()
202 * instead of cos() and sin(), but the latter are far easier to use when doing
203 * fixed point math, and performance is not a big point in the calculation part.
204 * All the 'a' filter coefficients are negated so we can use only additions
205 * in the filtering equation.
209 * Calculate second order section peaking filter coefficients.
210 * @param cutoff a value from 0 to 0x80000000, where 0 represents 0 Hz and
211 * 0x80000000 represents the Nyquist frequency (samplerate/2).
212 * @param Q Q factor value multiplied by ten. Lower bound is artificially set
214 * @param db decibel value multiplied by ten, describing gain/attenuation at
215 * peak freq. Max value is 24 dB.
216 * @param c pointer to coefficient storage. Coefficients are s3.28 format.
218 void eq_pk_coefs(unsigned long cutoff
, unsigned long Q
, long db
, int32_t *c
)
221 const long one
= 1 << 28; /* s3.28 */
222 const long A
= get_replaygain_int(db
*5) << 5; /* 10^(db/40), s2.29 */
223 const long alpha
= fsincos(cutoff
, &cs
)/(2*Q
)*10 >> 1; /* s1.30 */
224 int32_t a0
, a1
, a2
; /* these are all s3.28 format */
226 const long alphadivA
= DIV64(alpha
, A
, 27);
228 /* possible numerical ranges are in comments by each coef */
229 b0
= one
+ FRACMUL(alpha
, A
); /* [1 .. 5] */
230 b1
= a1
= -2*(cs
>> 3); /* [-2 .. 2] */
231 b2
= one
- FRACMUL(alpha
, A
); /* [-3 .. 1] */
232 a0
= one
+ alphadivA
; /* [1 .. 5] */
233 a2
= one
- alphadivA
; /* [-3 .. 1] */
235 /* range of this is roughly [0.2 .. 1], but we'll never hit 1 completely */
236 const long rcp_a0
= DIV64(1, a0
, 59); /* s0.31 */
237 *c
++ = FRACMUL(b0
, rcp_a0
); /* [0.25 .. 4] */
238 *c
++ = FRACMUL(b1
, rcp_a0
); /* [-2 .. 2] */
239 *c
++ = FRACMUL(b2
, rcp_a0
); /* [-2.4 .. 1] */
240 *c
++ = FRACMUL(-a1
, rcp_a0
); /* [-2 .. 2] */
241 *c
++ = FRACMUL(-a2
, rcp_a0
); /* [-0.6 .. 1] */
245 * Calculate coefficients for lowshelf filter. Parameters are as for
246 * eq_pk_coefs, but the coefficient format is s5.26 fixed point.
248 void eq_ls_coefs(unsigned long cutoff
, unsigned long Q
, long db
, int32_t *c
)
251 const long one
= 1 << 25; /* s6.25 */
252 const long sqrtA
= get_replaygain_int(db
*5/2) << 2; /* 10^(db/80), s5.26 */
253 const long A
= FRACMUL_SHL(sqrtA
, sqrtA
, 8); /* s2.29 */
254 const long alpha
= fsincos(cutoff
, &cs
)/(2*Q
)*10 >> 1; /* s1.30 */
255 const long ap1
= (A
>> 4) + one
;
256 const long am1
= (A
>> 4) - one
;
257 const long twosqrtalpha
= 2*FRACMUL(sqrtA
, alpha
);
258 int32_t a0
, a1
, a2
; /* these are all s6.25 format */
262 b0
= FRACMUL_SHL(A
, ap1
- FRACMUL(am1
, cs
) + twosqrtalpha
, 2);
264 b1
= FRACMUL_SHL(A
, am1
- FRACMUL(ap1
, cs
), 3);
266 b2
= FRACMUL_SHL(A
, ap1
- FRACMUL(am1
, cs
) - twosqrtalpha
, 2);
268 a0
= ap1
+ FRACMUL(am1
, cs
) + twosqrtalpha
;
270 a1
= -2*((am1
+ FRACMUL(ap1
, cs
)));
272 a2
= ap1
+ FRACMUL(am1
, cs
) - twosqrtalpha
;
275 const long rcp_a0
= DIV64(1, a0
, 55); /* s1.30 */
276 *c
++ = FRACMUL_SHL(b0
, rcp_a0
, 2); /* [0.06 .. 15.9] */
277 *c
++ = FRACMUL_SHL(b1
, rcp_a0
, 2); /* [-2 .. 31.7] */
278 *c
++ = FRACMUL_SHL(b2
, rcp_a0
, 2); /* [0 .. 15.9] */
279 *c
++ = FRACMUL_SHL(-a1
, rcp_a0
, 2); /* [-2 .. 2] */
280 *c
++ = FRACMUL_SHL(-a2
, rcp_a0
, 2); /* [0 .. 1] */
284 * Calculate coefficients for highshelf filter. Parameters are as for
285 * eq_pk_coefs, but the coefficient format is s5.26 fixed point.
287 void eq_hs_coefs(unsigned long cutoff
, unsigned long Q
, long db
, int32_t *c
)
290 const long one
= 1 << 25; /* s6.25 */
291 const long sqrtA
= get_replaygain_int(db
*5/2) << 2; /* 10^(db/80), s5.26 */
292 const long A
= FRACMUL_SHL(sqrtA
, sqrtA
, 8); /* s2.29 */
293 const long alpha
= fsincos(cutoff
, &cs
)/(2*Q
)*10 >> 1; /* s1.30 */
294 const long ap1
= (A
>> 4) + one
;
295 const long am1
= (A
>> 4) - one
;
296 const long twosqrtalpha
= 2*FRACMUL(sqrtA
, alpha
);
297 int32_t a0
, a1
, a2
; /* these are all s6.25 format */
301 b0
= FRACMUL_SHL(A
, ap1
+ FRACMUL(am1
, cs
) + twosqrtalpha
, 2);
303 b1
= -FRACMUL_SHL(A
, am1
+ FRACMUL(ap1
, cs
), 3);
305 b2
= FRACMUL_SHL(A
, ap1
+ FRACMUL(am1
, cs
) - twosqrtalpha
, 2);
307 a0
= ap1
- FRACMUL(am1
, cs
) + twosqrtalpha
;
309 a1
= 2*((am1
- FRACMUL(ap1
, cs
)));
311 a2
= ap1
- FRACMUL(am1
, cs
) - twosqrtalpha
;
314 const long rcp_a0
= DIV64(1, a0
, 55); /* s1.30 */
315 *c
++ = FRACMUL_SHL(b0
, rcp_a0
, 2); /* [0 .. 16] */
316 *c
++ = FRACMUL_SHL(b1
, rcp_a0
, 2); /* [-31.7 .. 2] */
317 *c
++ = FRACMUL_SHL(b2
, rcp_a0
, 2); /* [0 .. 16] */
318 *c
++ = FRACMUL_SHL(-a1
, rcp_a0
, 2); /* [-2 .. 2] */
319 *c
++ = FRACMUL_SHL(-a2
, rcp_a0
, 2); /* [0 .. 1] */
322 /* We realise the filters as a second order direct form 1 structure. Direct
323 * form 1 was chosen because of better numerical properties for fixed point
327 #if (!defined(CPU_COLDFIRE) && !defined(CPU_ARM))
328 void eq_filter(int32_t **x
, struct eqfilter
*f
, unsigned num
,
329 unsigned channels
, unsigned shift
)
334 /* Direct form 1 filtering code.
335 y[n] = b0*x[i] + b1*x[i - 1] + b2*x[i - 2] + a1*y[i - 1] + a2*y[i - 2],
336 where y[] is output and x[] is input.
339 for (c
= 0; c
< channels
; c
++) {
340 for (i
= 0; i
< num
; i
++) {
341 acc
= (long long) x
[c
][i
] * f
->coefs
[0];
342 acc
+= (long long) f
->history
[c
][0] * f
->coefs
[1];
343 acc
+= (long long) f
->history
[c
][1] * f
->coefs
[2];
344 acc
+= (long long) f
->history
[c
][2] * f
->coefs
[3];
345 acc
+= (long long) f
->history
[c
][3] * f
->coefs
[4];
346 f
->history
[c
][1] = f
->history
[c
][0];
347 f
->history
[c
][0] = x
[c
][i
];
348 f
->history
[c
][3] = f
->history
[c
][2];
349 x
[c
][i
] = (acc
<< shift
) >> 32;
350 f
->history
[c
][2] = x
[c
][i
];