summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/demac/libdemac/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/demac/libdemac/filter.c')
-rw-r--r--lib/rbcodec/codecs/demac/libdemac/filter.c296
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
3libdemac - A Monkey's Audio decoder
4
5$Id$
6
7Copyright (C) Dave Chapman 2007
8
9This program is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2 of the License, or
12(at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, 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
60struct 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
130static 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
204static 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
265static struct filter_t filter[2] IBSS_ATTR_DEMAC;
266
267static 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
283void 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
289void 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}