diff options
Diffstat (limited to 'lib/rbcodec/codecs/demac/libdemac/filter.c')
-rw-r--r-- | lib/rbcodec/codecs/demac/libdemac/filter.c | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/demac/libdemac/filter.c b/lib/rbcodec/codecs/demac/libdemac/filter.c new file mode 100644 index 0000000000..903885cf00 --- /dev/null +++ b/lib/rbcodec/codecs/demac/libdemac/filter.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | |||
3 | libdemac - A Monkey's Audio decoder | ||
4 | |||
5 | $Id$ | ||
6 | |||
7 | Copyright (C) Dave Chapman 2007 | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA | ||
22 | |||
23 | */ | ||
24 | |||
25 | #include <string.h> | ||
26 | #include <inttypes.h> | ||
27 | |||
28 | #include "demac.h" | ||
29 | #include "filter.h" | ||
30 | #include "demac_config.h" | ||
31 | |||
32 | #if FILTER_BITS == 32 | ||
33 | |||
34 | #if defined(CPU_ARM) && (ARM_ARCH == 4) | ||
35 | #include "vector_math32_armv4.h" | ||
36 | #else | ||
37 | #include "vector_math_generic.h" | ||
38 | #endif | ||
39 | |||
40 | #else /* FILTER_BITS == 16 */ | ||
41 | |||
42 | #ifdef CPU_COLDFIRE | ||
43 | #include "vector_math16_cf.h" | ||
44 | #elif defined(CPU_ARM) && (ARM_ARCH >= 7) | ||
45 | #include "vector_math16_armv7.h" | ||
46 | #elif defined(CPU_ARM) && (ARM_ARCH >= 6) | ||
47 | #include "vector_math16_armv6.h" | ||
48 | #elif defined(CPU_ARM) && (ARM_ARCH >= 5) | ||
49 | /* Assume all our ARMv5 targets are ARMv5te(j) */ | ||
50 | #include "vector_math16_armv5te.h" | ||
51 | #elif (defined(__i386__) || defined(__i486__)) && defined(__MMX__) \ | ||
52 | || defined(__x86_64__) | ||
53 | #include "vector_math16_mmx.h" | ||
54 | #else | ||
55 | #include "vector_math_generic.h" | ||
56 | #endif | ||
57 | |||
58 | #endif /* FILTER_BITS */ | ||
59 | |||
60 | struct filter_t { | ||
61 | filter_int* coeffs; /* ORDER entries */ | ||
62 | |||
63 | /* We store all the filter delays in a single buffer */ | ||
64 | filter_int* history_end; | ||
65 | |||
66 | filter_int* delay; | ||
67 | filter_int* adaptcoeffs; | ||
68 | |||
69 | int avg; | ||
70 | }; | ||
71 | |||
72 | /* We name the functions according to the ORDER and FRACBITS | ||
73 | pre-processor symbols and build multiple .o files from this .c file | ||
74 | - this increases code-size but gives the compiler more scope for | ||
75 | optimising the individual functions, as well as replacing a lot of | ||
76 | variables with constants. | ||
77 | */ | ||
78 | |||
79 | #if FRACBITS == 11 | ||
80 | #if ORDER == 16 | ||
81 | #define INIT_FILTER init_filter_16_11 | ||
82 | #define APPLY_FILTER apply_filter_16_11 | ||
83 | #elif ORDER == 64 | ||
84 | #define INIT_FILTER init_filter_64_11 | ||
85 | #define APPLY_FILTER apply_filter_64_11 | ||
86 | #endif | ||
87 | #elif FRACBITS == 13 | ||
88 | #define INIT_FILTER init_filter_256_13 | ||
89 | #define APPLY_FILTER apply_filter_256_13 | ||
90 | #elif FRACBITS == 10 | ||
91 | #define INIT_FILTER init_filter_32_10 | ||
92 | #define APPLY_FILTER apply_filter_32_10 | ||
93 | #elif FRACBITS == 15 | ||
94 | #define INIT_FILTER init_filter_1280_15 | ||
95 | #define APPLY_FILTER apply_filter_1280_15 | ||
96 | #endif | ||
97 | |||
98 | /* Some macros to handle the fixed-point stuff */ | ||
99 | |||
100 | /* Convert from (32-FRACBITS).FRACBITS fixed-point format to an | ||
101 | integer (rounding to nearest). */ | ||
102 | #define FP_HALF (1 << (FRACBITS - 1)) /* 0.5 in fixed-point format. */ | ||
103 | #define FP_TO_INT(x) ((x + FP_HALF) >> FRACBITS) /* round(x) */ | ||
104 | |||
105 | #ifdef CPU_ARM | ||
106 | #if ARM_ARCH >= 6 | ||
107 | #define SATURATE(x) ({int __res; asm("ssat %0, #16, %1" : "=r"(__res) : "r"(x)); __res; }) | ||
108 | #else /* ARM_ARCH < 6 */ | ||
109 | /* Keeping the asr #31 outside of the asm allows loads to be scheduled between | ||
110 | it and the rest of the block on ARM9E, with the load's result latency filled | ||
111 | by the other calculations. */ | ||
112 | #define SATURATE(x) ({ \ | ||
113 | int __res = (x) >> 31; \ | ||
114 | asm volatile ( \ | ||
115 | "teq %0, %1, asr #15\n\t" \ | ||
116 | "moveq %0, %1\n\t" \ | ||
117 | "eorne %0, %0, #0xff\n\t" \ | ||
118 | "eorne %0, %0, #0x7f00" \ | ||
119 | : "+r" (__res) : "r" (x) : "cc" \ | ||
120 | ); \ | ||
121 | __res; \ | ||
122 | }) | ||
123 | #endif /* ARM_ARCH */ | ||
124 | #else /* CPU_ARM */ | ||
125 | #define SATURATE(x) (LIKELY((x) == (int16_t)(x)) ? (x) : ((x) >> 31) ^ 0x7FFF) | ||
126 | #endif | ||
127 | |||
128 | /* Apply the filter with state f to count entries in data[] */ | ||
129 | |||
130 | static void ICODE_ATTR_DEMAC do_apply_filter_3980(struct filter_t* f, | ||
131 | int32_t* data, int count) | ||
132 | { | ||
133 | int res; | ||
134 | int absres; | ||
135 | |||
136 | #ifdef PREPARE_SCALARPRODUCT | ||
137 | PREPARE_SCALARPRODUCT | ||
138 | #endif | ||
139 | |||
140 | while(LIKELY(count--)) | ||
141 | { | ||
142 | #ifdef FUSED_VECTOR_MATH | ||
143 | if (LIKELY(*data != 0)) { | ||
144 | if (*data < 0) | ||
145 | res = vector_sp_add(f->coeffs, f->delay - ORDER, | ||
146 | f->adaptcoeffs - ORDER); | ||
147 | else | ||
148 | res = vector_sp_sub(f->coeffs, f->delay - ORDER, | ||
149 | f->adaptcoeffs - ORDER); | ||
150 | } else { | ||
151 | res = scalarproduct(f->coeffs, f->delay - ORDER); | ||
152 | } | ||
153 | res = FP_TO_INT(res); | ||
154 | #else | ||
155 | res = FP_TO_INT(scalarproduct(f->coeffs, f->delay - ORDER)); | ||
156 | |||
157 | if (LIKELY(*data != 0)) { | ||
158 | if (*data < 0) | ||
159 | vector_add(f->coeffs, f->adaptcoeffs - ORDER); | ||
160 | else | ||
161 | vector_sub(f->coeffs, f->adaptcoeffs - ORDER); | ||
162 | } | ||
163 | #endif | ||
164 | |||
165 | res += *data; | ||
166 | |||
167 | *data++ = res; | ||
168 | |||
169 | /* Update the output history */ | ||
170 | *f->delay++ = SATURATE(res); | ||
171 | |||
172 | /* Version 3.98 and later files */ | ||
173 | |||
174 | /* Update the adaption coefficients */ | ||
175 | absres = (res < 0 ? -res : res); | ||
176 | |||
177 | if (UNLIKELY(absres > 3 * f->avg)) | ||
178 | *f->adaptcoeffs = ((res >> 25) & 64) - 32; | ||
179 | else if (3 * absres > 4 * f->avg) | ||
180 | *f->adaptcoeffs = ((res >> 26) & 32) - 16; | ||
181 | else if (LIKELY(absres > 0)) | ||
182 | *f->adaptcoeffs = ((res >> 27) & 16) - 8; | ||
183 | else | ||
184 | *f->adaptcoeffs = 0; | ||
185 | |||
186 | f->avg += (absres - f->avg) / 16; | ||
187 | |||
188 | f->adaptcoeffs[-1] >>= 1; | ||
189 | f->adaptcoeffs[-2] >>= 1; | ||
190 | f->adaptcoeffs[-8] >>= 1; | ||
191 | |||
192 | f->adaptcoeffs++; | ||
193 | |||
194 | /* Have we filled the history buffer? */ | ||
195 | if (UNLIKELY(f->delay == f->history_end)) { | ||
196 | memmove(f->coeffs + ORDER, f->delay - (ORDER*2), | ||
197 | (ORDER*2) * sizeof(filter_int)); | ||
198 | f->adaptcoeffs = f->coeffs + ORDER*2; | ||
199 | f->delay = f->coeffs + ORDER*3; | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | |||
204 | static void ICODE_ATTR_DEMAC do_apply_filter_3970(struct filter_t* f, | ||
205 | int32_t* data, int count) | ||
206 | { | ||
207 | int res; | ||
208 | |||
209 | #ifdef PREPARE_SCALARPRODUCT | ||
210 | PREPARE_SCALARPRODUCT | ||
211 | #endif | ||
212 | |||
213 | while(LIKELY(count--)) | ||
214 | { | ||
215 | #ifdef FUSED_VECTOR_MATH | ||
216 | if (LIKELY(*data != 0)) { | ||
217 | if (*data < 0) | ||
218 | res = vector_sp_add(f->coeffs, f->delay - ORDER, | ||
219 | f->adaptcoeffs - ORDER); | ||
220 | else | ||
221 | res = vector_sp_sub(f->coeffs, f->delay - ORDER, | ||
222 | f->adaptcoeffs - ORDER); | ||
223 | } else { | ||
224 | res = scalarproduct(f->coeffs, f->delay - ORDER); | ||
225 | } | ||
226 | res = FP_TO_INT(res); | ||
227 | #else | ||
228 | res = FP_TO_INT(scalarproduct(f->coeffs, f->delay - ORDER)); | ||
229 | |||
230 | if (LIKELY(*data != 0)) { | ||
231 | if (*data < 0) | ||
232 | vector_add(f->coeffs, f->adaptcoeffs - ORDER); | ||
233 | else | ||
234 | vector_sub(f->coeffs, f->adaptcoeffs - ORDER); | ||
235 | } | ||
236 | #endif | ||
237 | |||
238 | /* Convert res from (32-FRACBITS).FRACBITS fixed-point format to an | ||
239 | integer (rounding to nearest) and add the input value to | ||
240 | it */ | ||
241 | res += *data; | ||
242 | |||
243 | *data++ = res; | ||
244 | |||
245 | /* Update the output history */ | ||
246 | *f->delay++ = SATURATE(res); | ||
247 | |||
248 | /* Version ??? to < 3.98 files (untested) */ | ||
249 | f->adaptcoeffs[0] = (res == 0) ? 0 : ((res >> 28) & 8) - 4; | ||
250 | f->adaptcoeffs[-4] >>= 1; | ||
251 | f->adaptcoeffs[-8] >>= 1; | ||
252 | |||
253 | f->adaptcoeffs++; | ||
254 | |||
255 | /* Have we filled the history buffer? */ | ||
256 | if (UNLIKELY(f->delay == f->history_end)) { | ||
257 | memmove(f->coeffs + ORDER, f->delay - (ORDER*2), | ||
258 | (ORDER*2) * sizeof(filter_int)); | ||
259 | f->adaptcoeffs = f->coeffs + ORDER*2; | ||
260 | f->delay = f->coeffs + ORDER*3; | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static struct filter_t filter[2] IBSS_ATTR_DEMAC; | ||
266 | |||
267 | static void do_init_filter(struct filter_t* f, filter_int* buf) | ||
268 | { | ||
269 | f->coeffs = buf; | ||
270 | f->history_end = buf + ORDER*3 + FILTER_HISTORY_SIZE; | ||
271 | |||
272 | /* Init pointers */ | ||
273 | f->adaptcoeffs = f->coeffs + ORDER*2; | ||
274 | f->delay = f->coeffs + ORDER*3; | ||
275 | |||
276 | /* Zero coefficients and history buffer */ | ||
277 | memset(f->coeffs, 0, ORDER*3 * sizeof(filter_int)); | ||
278 | |||
279 | /* Zero the running average */ | ||
280 | f->avg = 0; | ||
281 | } | ||
282 | |||
283 | void INIT_FILTER(filter_int* buf) | ||
284 | { | ||
285 | do_init_filter(&filter[0], buf); | ||
286 | do_init_filter(&filter[1], buf + ORDER*3 + FILTER_HISTORY_SIZE); | ||
287 | } | ||
288 | |||
289 | void ICODE_ATTR_DEMAC APPLY_FILTER(int fileversion, int channel, | ||
290 | int32_t* data, int count) | ||
291 | { | ||
292 | if (fileversion >= 3980) | ||
293 | do_apply_filter_3980(&filter[channel], data, count); | ||
294 | else | ||
295 | do_apply_filter_3970(&filter[channel], data, count); | ||
296 | } | ||