diff options
author | Adam Gashlin <agashlin@gmail.com> | 2008-02-25 21:47:56 +0000 |
---|---|---|
committer | Adam Gashlin <agashlin@gmail.com> | 2008-02-25 21:47:56 +0000 |
commit | 2668547a554da72093e28d69ea1294fb471e1c7e (patch) | |
tree | 3fc315a07996ba1805480f51f1620089ff10c609 /apps/codecs/adx.c | |
parent | 0380bec8aff48417256d12df162fb413d43506b6 (diff) | |
download | rockbox-2668547a554da72093e28d69ea1294fb471e1c7e.tar.gz rockbox-2668547a554da72093e28d69ea1294fb471e1c7e.zip |
Fix ADX decoder, old constant coefficients were for 44.1khz only, they
are now calculated at runtime.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16418 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/adx.c')
-rw-r--r-- | apps/codecs/adx.c | 185 |
1 files changed, 175 insertions, 10 deletions
diff --git a/apps/codecs/adx.c b/apps/codecs/adx.c index f558bae135..c3a64b1efe 100644 --- a/apps/codecs/adx.c +++ b/apps/codecs/adx.c | |||
@@ -6,7 +6,8 @@ | |||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * | 8 | * |
9 | * Copyright (C) 2006-2007 Adam Gashlin (hcs) | 9 | * Copyright (C) 2006-2008 Adam Gashlin (hcs) |
10 | * Copyright (C) 2006 Jens Arnold | ||
10 | * | 11 | * |
11 | * All files in this archive are subject to the GNU General Public License. | 12 | * All files in this archive are subject to the GNU General Public License. |
12 | * See the file COPYING in the source tree root for full license agreement. | 13 | * See the file COPYING in the source tree root for full license agreement. |
@@ -17,23 +18,145 @@ | |||
17 | ****************************************************************************/ | 18 | ****************************************************************************/ |
18 | #include "codeclib.h" | 19 | #include "codeclib.h" |
19 | #include "inttypes.h" | 20 | #include "inttypes.h" |
21 | #include "math.h" | ||
20 | 22 | ||
21 | CODEC_HEADER | 23 | CODEC_HEADER |
22 | 24 | ||
23 | /* Maximum number of bytes to process in one iteration */ | 25 | /* Maximum number of bytes to process in one iteration */ |
24 | #define WAV_CHUNK_SIZE (1024*2) | 26 | #define WAV_CHUNK_SIZE (1024*2) |
25 | 27 | ||
26 | /* Volume for ADX decoder */ | ||
27 | #define BASE_VOL 0x2000 | ||
28 | |||
29 | /* Number of times to loop looped tracks when repeat is disabled */ | 28 | /* Number of times to loop looped tracks when repeat is disabled */ |
30 | #define LOOP_TIMES 2 | 29 | #define LOOP_TIMES 2 |
31 | 30 | ||
32 | /* Length of fade-out for looped tracks (milliseconds) */ | 31 | /* Length of fade-out for looped tracks (milliseconds) */ |
33 | #define FADE_LENGTH 10000L | 32 | #define FADE_LENGTH 10000L |
34 | 33 | ||
34 | /* Default high pass filter cutoff frequency is 500 Hz. | ||
35 | * Others can be set, but the default is nearly always used, | ||
36 | * and there is no way to determine if another was used, anyway. | ||
37 | */ | ||
38 | const long cutoff = 500; | ||
39 | |||
35 | static int16_t samples[WAV_CHUNK_SIZE] IBSS_ATTR; | 40 | static int16_t samples[WAV_CHUNK_SIZE] IBSS_ATTR; |
36 | 41 | ||
42 | /* fixed point stuff from apps/plugins/lib/fixedpoint.c */ | ||
43 | |||
44 | /* Inverse gain of circular cordic rotation in s0.31 format. */ | ||
45 | static const long cordic_circular_gain = 0xb2458939; /* 0.607252929 */ | ||
46 | |||
47 | /* Table of values of atan(2^-i) in 0.32 format fractions of pi where pi = 0xffffffff / 2 */ | ||
48 | static const unsigned long atan_table[] = { | ||
49 | 0x1fffffff, /* +0.785398163 (or pi/4) */ | ||
50 | 0x12e4051d, /* +0.463647609 */ | ||
51 | 0x09fb385b, /* +0.244978663 */ | ||
52 | 0x051111d4, /* +0.124354995 */ | ||
53 | 0x028b0d43, /* +0.062418810 */ | ||
54 | 0x0145d7e1, /* +0.031239833 */ | ||
55 | 0x00a2f61e, /* +0.015623729 */ | ||
56 | 0x00517c55, /* +0.007812341 */ | ||
57 | 0x0028be53, /* +0.003906230 */ | ||
58 | 0x00145f2e, /* +0.001953123 */ | ||
59 | 0x000a2f98, /* +0.000976562 */ | ||
60 | 0x000517cc, /* +0.000488281 */ | ||
61 | 0x00028be6, /* +0.000244141 */ | ||
62 | 0x000145f3, /* +0.000122070 */ | ||
63 | 0x0000a2f9, /* +0.000061035 */ | ||
64 | 0x0000517c, /* +0.000030518 */ | ||
65 | 0x000028be, /* +0.000015259 */ | ||
66 | 0x0000145f, /* +0.000007629 */ | ||
67 | 0x00000a2f, /* +0.000003815 */ | ||
68 | 0x00000517, /* +0.000001907 */ | ||
69 | 0x0000028b, /* +0.000000954 */ | ||
70 | 0x00000145, /* +0.000000477 */ | ||
71 | 0x000000a2, /* +0.000000238 */ | ||
72 | 0x00000051, /* +0.000000119 */ | ||
73 | 0x00000028, /* +0.000000060 */ | ||
74 | 0x00000014, /* +0.000000030 */ | ||
75 | 0x0000000a, /* +0.000000015 */ | ||
76 | 0x00000005, /* +0.000000007 */ | ||
77 | 0x00000002, /* +0.000000004 */ | ||
78 | 0x00000001, /* +0.000000002 */ | ||
79 | 0x00000000, /* +0.000000001 */ | ||
80 | 0x00000000, /* +0.000000000 */ | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * Implements sin and cos using CORDIC rotation. | ||
85 | * | ||
86 | * @param phase has range from 0 to 0xffffffff, representing 0 and | ||
87 | * 2*pi respectively. | ||
88 | * @param cos return address for cos | ||
89 | * @return sin of phase, value is a signed value from LONG_MIN to LONG_MAX, | ||
90 | * representing -1 and 1 respectively. | ||
91 | */ | ||
92 | static long fsincos(unsigned long phase, long *cos) | ||
93 | { | ||
94 | int32_t x, x1, y, y1; | ||
95 | unsigned long z, z1; | ||
96 | int i; | ||
97 | |||
98 | /* Setup initial vector */ | ||
99 | x = cordic_circular_gain; | ||
100 | y = 0; | ||
101 | z = phase; | ||
102 | |||
103 | /* The phase has to be somewhere between 0..pi for this to work right */ | ||
104 | if (z < 0xffffffff / 4) { | ||
105 | /* z in first quadrant, z += pi/2 to correct */ | ||
106 | x = -x; | ||
107 | z += 0xffffffff / 4; | ||
108 | } else if (z < 3 * (0xffffffff / 4)) { | ||
109 | /* z in third quadrant, z -= pi/2 to correct */ | ||
110 | z -= 0xffffffff / 4; | ||
111 | } else { | ||
112 | /* z in fourth quadrant, z -= 3pi/2 to correct */ | ||
113 | x = -x; | ||
114 | z -= 3 * (0xffffffff / 4); | ||
115 | } | ||
116 | |||
117 | /* Each iteration adds roughly 1-bit of extra precision */ | ||
118 | for (i = 0; i < 31; i++) { | ||
119 | x1 = x >> i; | ||
120 | y1 = y >> i; | ||
121 | z1 = atan_table[i]; | ||
122 | |||
123 | /* Decided which direction to rotate vector. Pivot point is pi/2 */ | ||
124 | if (z >= 0xffffffff / 4) { | ||
125 | x -= y1; | ||
126 | y += x1; | ||
127 | z -= z1; | ||
128 | } else { | ||
129 | x += y1; | ||
130 | y -= x1; | ||
131 | z += z1; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | if (cos) | ||
136 | *cos = x; | ||
137 | |||
138 | return y; | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * Fixed point square root via Newton-Raphson. | ||
143 | * @param a square root argument. | ||
144 | * @param fracbits specifies number of fractional bits in argument. | ||
145 | * @return Square root of argument in same fixed point format as input. | ||
146 | */ | ||
147 | static long fsqrt(long a, unsigned int fracbits) | ||
148 | { | ||
149 | long b = a/2 + (1 << fracbits); /* initial approximation */ | ||
150 | unsigned n; | ||
151 | const unsigned iterations = 8; /* bumped up from 4 as it wasn't | ||
152 | nearly enough for 28 fractional bits */ | ||
153 | |||
154 | for (n = 0; n < iterations; ++n) | ||
155 | b = (b + (long)(((long long)(a) << fracbits)/b))/2; | ||
156 | |||
157 | return b; | ||
158 | } | ||
159 | |||
37 | /* this is the codec entry point */ | 160 | /* this is the codec entry point */ |
38 | enum codec_status codec_main(void) | 161 | enum codec_status codec_main(void) |
39 | { | 162 | { |
@@ -50,6 +173,8 @@ enum codec_status codec_main(void) | |||
50 | int fade_frames; /* length of fade in frames */ | 173 | int fade_frames; /* length of fade in frames */ |
51 | off_t start_adr, end_adr; /* loop points */ | 174 | off_t start_adr, end_adr; /* loop points */ |
52 | off_t chanstart, bufoff; | 175 | off_t chanstart, bufoff; |
176 | /*long coef1=0x7298L,coef2=-0x3350L;*/ | ||
177 | long coef1, coef2; | ||
53 | 178 | ||
54 | /* Generic codec initialisation */ | 179 | /* Generic codec initialisation */ |
55 | /* we only render 16 bits */ | 180 | /* we only render 16 bits */ |
@@ -90,6 +215,46 @@ next_track: | |||
90 | avgbytespersec = ci->id3->frequency * 18 * channels / 32; | 215 | avgbytespersec = ci->id3->frequency * 18 * channels / 32; |
91 | DEBUGF("avgbytespersec=%ld\n",(unsigned long)avgbytespersec); | 216 | DEBUGF("avgbytespersec=%ld\n",(unsigned long)avgbytespersec); |
92 | 217 | ||
218 | /* calculate filter coefficients */ | ||
219 | |||
220 | /** | ||
221 | * A simple table of these coefficients would be nice, but | ||
222 | * some very odd frequencies are used and if I'm going to | ||
223 | * interpolate I might as well just go all the way and | ||
224 | * calclate them precisely. | ||
225 | * Speed is not an issue as this only needs to be done once per file. | ||
226 | */ | ||
227 | { | ||
228 | const int64_t big28 = 0x10000000LL; | ||
229 | const int64_t big32 = 0x100000000LL; | ||
230 | int64_t frequency = ci->id3->frequency; | ||
231 | int64_t phasemultiple = cutoff*big32/frequency; | ||
232 | |||
233 | long z; | ||
234 | int64_t a; | ||
235 | const int64_t b = (M_SQRT2*big28)-big28; | ||
236 | int64_t c; | ||
237 | int64_t d; | ||
238 | |||
239 | fsincos((unsigned long)phasemultiple,&z); | ||
240 | |||
241 | a = (M_SQRT2*big28)-(z*big28/LONG_MAX); | ||
242 | |||
243 | /** | ||
244 | * In the long passed to fsqrt there are only 4 nonfractional bits, | ||
245 | * which is sufficient here, but this is the only reason why I don't | ||
246 | * use 32 fractional bits everywhere. | ||
247 | */ | ||
248 | d = fsqrt((a+b)*(a-b)/big28,28); | ||
249 | c = (a-d)*big28/b; | ||
250 | |||
251 | coef1 = (c*8192) >> 28; | ||
252 | coef2 = (c*c/big28*-4096) >> 28; | ||
253 | DEBUGF("ADX: samprate=%lld ",frequency); | ||
254 | DEBUGF("coef1 %04x ",(unsigned int)(coef1*4)); | ||
255 | DEBUGF("coef2 %04x\n",(unsigned int)(coef2*-4)); | ||
256 | } | ||
257 | |||
93 | /* Get loop data */ | 258 | /* Get loop data */ |
94 | 259 | ||
95 | looping = 0; start_adr = 0; end_adr = 0; | 260 | looping = 0; start_adr = 0; end_adr = 0; |
@@ -248,13 +413,13 @@ next_track: | |||
248 | return CODEC_ERROR; | 413 | return CODEC_ERROR; |
249 | } | 414 | } |
250 | 415 | ||
251 | scale = (((buf[0] << 8) | (buf[1])) +1) * BASE_VOL; | 416 | scale = ((buf[0] << 8) | (buf[1])) +1; |
252 | 417 | ||
253 | for (i = 2; i < 18; i++) | 418 | for (i = 2; i < 18; i++) |
254 | { | 419 | { |
255 | d = (buf[i] >> 4) & 15; | 420 | d = (buf[i] >> 4) & 15; |
256 | if (d & 8) d-= 16; | 421 | if (d & 8) d-= 16; |
257 | ch1_0 = (d*scale + 0x7298L*ch1_1 - 0x3350L*ch1_2) >> 14; | 422 | ch1_0 = d*scale + ((coef1*ch1_1 + coef2*ch1_2) >> 12); |
258 | if (ch1_0 > 32767) ch1_0 = 32767; | 423 | if (ch1_0 > 32767) ch1_0 = 32767; |
259 | else if (ch1_0 < -32768) ch1_0 = -32768; | 424 | else if (ch1_0 < -32768) ch1_0 = -32768; |
260 | samples[sampleswritten] = ch1_0; | 425 | samples[sampleswritten] = ch1_0; |
@@ -263,7 +428,7 @@ next_track: | |||
263 | 428 | ||
264 | d = buf[i] & 15; | 429 | d = buf[i] & 15; |
265 | if (d & 8) d -= 16; | 430 | if (d & 8) d -= 16; |
266 | ch1_0 = (d*scale + 0x7298L*ch1_1 - 0x3350L*ch1_2) >> 14; | 431 | ch1_0 = d*scale + ((coef1*ch1_1 + coef2*ch1_2) >> 12); |
267 | if (ch1_0 > 32767) ch1_0 = 32767; | 432 | if (ch1_0 > 32767) ch1_0 = 32767; |
268 | else if (ch1_0 < -32768) ch1_0 = -32768; | 433 | else if (ch1_0 < -32768) ch1_0 = -32768; |
269 | samples[sampleswritten] = ch1_0; | 434 | samples[sampleswritten] = ch1_0; |
@@ -286,7 +451,7 @@ next_track: | |||
286 | return CODEC_ERROR; | 451 | return CODEC_ERROR; |
287 | } | 452 | } |
288 | 453 | ||
289 | scale = (((buf[0] << 8)|(buf[1]))+1)*BASE_VOL; | 454 | scale = ((buf[0] << 8)|(buf[1]))+1; |
290 | 455 | ||
291 | sampleswritten-=63; | 456 | sampleswritten-=63; |
292 | 457 | ||
@@ -294,7 +459,7 @@ next_track: | |||
294 | { | 459 | { |
295 | d = (buf[i] >> 4) & 15; | 460 | d = (buf[i] >> 4) & 15; |
296 | if (d & 8) d-= 16; | 461 | if (d & 8) d-= 16; |
297 | ch2_0 = (d*scale + 0x7298L*ch2_1 - 0x3350L*ch2_2) >> 14; | 462 | ch2_0 = d*scale + ((coef1*ch2_1 + coef2*ch2_2) >> 12); |
298 | if (ch2_0 > 32767) ch2_0 = 32767; | 463 | if (ch2_0 > 32767) ch2_0 = 32767; |
299 | else if (ch2_0 < -32768) ch2_0 = -32768; | 464 | else if (ch2_0 < -32768) ch2_0 = -32768; |
300 | samples[sampleswritten] = ch2_0; | 465 | samples[sampleswritten] = ch2_0; |
@@ -303,7 +468,7 @@ next_track: | |||
303 | 468 | ||
304 | d = buf[i] & 15; | 469 | d = buf[i] & 15; |
305 | if (d & 8) d -= 16; | 470 | if (d & 8) d -= 16; |
306 | ch2_0 = (d*scale + 0x7298L*ch2_1 - 0x3350L*ch2_2) >> 14; | 471 | ch2_0 = d*scale + ((coef1*ch2_1 + coef2*ch2_2) >> 12); |
307 | if (ch2_0 > 32767) ch2_0 = 32767; | 472 | if (ch2_0 > 32767) ch2_0 = 32767; |
308 | else if (ch2_0 < -32768) ch2_0 = -32768; | 473 | else if (ch2_0 < -32768) ch2_0 = -32768; |
309 | samples[sampleswritten] = ch2_0; | 474 | samples[sampleswritten] = ch2_0; |