diff options
author | Thom Johansen <thomj@rockbox.org> | 2007-02-26 00:41:26 +0000 |
---|---|---|
committer | Thom Johansen <thomj@rockbox.org> | 2007-02-26 00:41:26 +0000 |
commit | a7fabf0741c91fb0a2c28b2d8357bcc4630300af (patch) | |
tree | e1528a67f63933aa23ebb7b5d809e1ce7e60b589 /apps/eq.c | |
parent | 1915c1099431294ca9c43bc11fb1bfa41bbd83cc (diff) |
Add software based bass/treble controls for targets which have no such functionality in hardware (currently only X5). They can also be used on any other SWCODEC target by adding #define HAVE_SW_TONE_CONTROLS in the relevant config-*.h file. Also remove some now unneeded zero checks when using get_replaygain_int(). Comments on sound quality are welcome as some parameters can still be fine-tuned.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12489 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/eq.c')
-rw-r--r-- | apps/eq.c | 60 |
1 files changed, 56 insertions, 4 deletions
@@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2006 Thom Johansen + * Copyright (C) 2006-2007 Thom Johansen * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. @@ -127,7 +127,7 @@ static long fsincos(unsigned long phase, long *cos) { * @param an gain at Nyquist frequency. s3.27 fixed point. * @param c pointer to coefficient storage. The coefs are s0.31 format. */ -void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) +void filter_shelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) { const long one = 1 << 27; long a0, a1; @@ -137,7 +137,7 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) cs = one + (cs >> 4); /* For max A = 4 (24 dB) */ - b0 = FRACMUL_SHL(an, cs, 4) + FRACMUL_SHL(ad, s, 4); + b0 = FRACMUL_SHL(ad, s, 4) + FRACMUL_SHL(an, cs, 4); b1 = FRACMUL_SHL(ad, s, 4) - FRACMUL_SHL(an, cs, 4); a0 = s + cs; a1 = s - cs; @@ -147,6 +147,58 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) c[2] = -DIV64(a1, a0, 31); } +/** + * Calculate second order section filter consisting of one low-shelf and one + * high-shelf section. + * @param cutoff_low low-shelf midpoint frequency. See eq_pk_coefs for format. + * @param cutoff_high high-shelf midpoint frequency. + * @param A_low decibel value multiplied by ten, describing gain/attenuation of + * low-shelf part. Max value is 24 dB. + * @param A_high decibel value multiplied by ten, describing gain/attenuation of + * high-shelf part. Max value is 24 dB. + * @param A decibel value multiplied by ten, describing additional overall gain. + * @param c pointer to coefficient storage. Coefficients are s4.27 format. + */ +void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high, + long A_low, long A_high, long A, int32_t *c) +{ + long sin1, cos2; /* s0.31 */ + long cos1, sin2; /* s3.28 */ + int32_t b0, b1, b2, b3; /* s3.28 */ + int32_t a0, a1, a2, a3; + const long gd = get_replaygain_int(A_low*5) << 4; /* 10^(db/40), s3.28 */ + const long gn = get_replaygain_int(A_high*5) << 4; /* 10^(db/40), s3.28 */ + const long g = get_replaygain_int(A*10) << 7; /* 10^(db/20), s0.31 */ + + sin1 = fsincos(cutoff_low/2, &cos1); + sin2 = fsincos(cutoff_high/2, &cos2) >> 3; + cos1 >>= 3; + + /* lowshelf filter, ranges listed are for all possible cutoffs */ + b0 = FRACMUL(sin1, gd) + cos1; /* 0.25 .. 4.10 */ + b1 = FRACMUL(sin1, gd) - cos1; /* -1 .. 3.98 */ + a0 = DIV64(sin1, gd, 25) + cos1; /* 0.25 .. 4.10 */ + a1 = DIV64(sin1, gd, 25) - cos1; /* -1 .. 3.98 */ + + /* highshelf filter */ + b2 = sin2 + FRACMUL(cos2, gn); /* 0.25 .. 4.10 */ + b3 = sin2 - FRACMUL(cos2, gn); /* -3.98 .. 1 */ + a2 = sin2 + DIV64(cos2, gn, 25); /* 0.25 .. 4.10 */ + a3 = sin2 - DIV64(cos2, gn, 25); /* -3.98 .. 1 */ + + /* now we cascade the two first order filters to one second order filter + * which can be used by eq_filter(). these resulting coefficients have a + * really wide numerical range, so we use a fixed point format which will + * work for the selected cutoff frequencies (in dsp.c) only. + */ + const int32_t rcp_a0 = DIV64(1, FRACMUL(a0, a2), 53); /* s3.28 */ + *c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b0, b2), rcp_a0, 5)); + *c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b0, b3) + FRACMUL(b1, b2), rcp_a0, 5)); + *c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b1, b3), rcp_a0, 5)); + *c++ = -FRACMUL_SHL(FRACMUL(a0, a3) + FRACMUL(a1, a2), rcp_a0, 5); + *c++ = -FRACMUL_SHL(FRACMUL(a1, a3), rcp_a0, 5); +} + /* Coef calculation taken from Audio-EQ-Cookbook.txt by Robert Bristow-Johnson. * Slightly faster calculation can be done by deriving forms which use tan() * instead of cos() and sin(), but the latter are far easier to use when doing @@ -162,7 +214,7 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) * @param Q Q factor value multiplied by ten. Lower bound is artificially set * at 0.5. * @param db decibel value multiplied by ten, describing gain/attenuation at - * peak freq. + * peak freq. Max value is 24 dB. * @param c pointer to coefficient storage. Coefficients are s3.28 format. */ void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c) |