msm6258.c revision 1.18.2.2 1 1.18.2.2 isaki /* $NetBSD: msm6258.c,v 1.18.2.2 2017/07/15 10:17:10 isaki Exp $ */
2 1.18.2.2 isaki
3 1.18.2.2 isaki /*
4 1.18.2.2 isaki * Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
5 1.18.2.2 isaki *
6 1.18.2.2 isaki * Redistribution and use in source and binary forms, with or without
7 1.18.2.2 isaki * modification, are permitted provided that the following conditions
8 1.18.2.2 isaki * are met:
9 1.18.2.2 isaki * 1. Redistributions of source code must retain the above copyright
10 1.18.2.2 isaki * notice, this list of conditions and the following disclaimer.
11 1.18.2.2 isaki * 2. Redistributions in binary form must reproduce the above copyright
12 1.18.2.2 isaki * notice, this list of conditions and the following disclaimer in the
13 1.18.2.2 isaki * documentation and/or other materials provided with the distribution.
14 1.18.2.2 isaki *
15 1.18.2.2 isaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.18.2.2 isaki * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.18.2.2 isaki * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.18.2.2 isaki * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.18.2.2 isaki * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 1.18.2.2 isaki * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 1.18.2.2 isaki * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 1.18.2.2 isaki * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 1.18.2.2 isaki * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.18.2.2 isaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.18.2.2 isaki * SUCH DAMAGE.
26 1.18.2.2 isaki */
27 1.18.2.2 isaki
28 1.18.2.2 isaki /*
29 1.18.2.2 isaki * OKI MSM6258 ADPCM voice synthesizer codec.
30 1.18.2.2 isaki */
31 1.18.2.2 isaki
32 1.18.2.2 isaki #include <sys/cdefs.h>
33 1.18.2.2 isaki __KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.18.2.2 2017/07/15 10:17:10 isaki Exp $");
34 1.18.2.2 isaki
35 1.18.2.2 isaki #include <sys/systm.h>
36 1.18.2.2 isaki #include <sys/device.h>
37 1.18.2.2 isaki #include <sys/kmem.h>
38 1.18.2.2 isaki #include <sys/select.h>
39 1.18.2.2 isaki #include <sys/audioio.h>
40 1.18.2.2 isaki
41 1.18.2.2 isaki #include <dev/audio_if.h>
42 1.18.2.2 isaki #include <dev/auconv.h>
43 1.18.2.2 isaki #include <dev/audiovar.h>
44 1.18.2.2 isaki #include <dev/mulaw.h>
45 1.18.2.2 isaki #include <dev/ic/msm6258var.h>
46 1.18.2.2 isaki
47 1.18.2.2 isaki struct msm6258_codecvar {
48 1.18.2.2 isaki stream_filter_t base;
49 1.18.2.2 isaki short mc_amp;
50 1.18.2.2 isaki char mc_estim;
51 1.18.2.2 isaki };
52 1.18.2.2 isaki
53 1.18.2.2 isaki static stream_filter_t *msm6258_factory
54 1.18.2.2 isaki (struct audio_softc *,
55 1.18.2.2 isaki int (*)(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int));
56 1.18.2.2 isaki static void msm6258_dtor(struct stream_filter *);
57 1.18.2.2 isaki static inline uint8_t pcm2adpcm_step(struct msm6258_codecvar *, int16_t);
58 1.18.2.2 isaki static inline int16_t adpcm2pcm_step(struct msm6258_codecvar *, uint8_t);
59 1.18.2.2 isaki
60 1.18.2.2 isaki static const int adpcm_estimindex[16] = {
61 1.18.2.2 isaki 2, 6, 10, 14, 18, 22, 26, 30,
62 1.18.2.2 isaki -2, -6, -10, -14, -18, -22, -26, -30
63 1.18.2.2 isaki };
64 1.18.2.2 isaki
65 1.18.2.2 isaki static const int adpcm_estim[49] = {
66 1.18.2.2 isaki 16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
67 1.18.2.2 isaki 41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
68 1.18.2.2 isaki 107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
69 1.18.2.2 isaki 279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
70 1.18.2.2 isaki 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
71 1.18.2.2 isaki };
72 1.18.2.2 isaki
73 1.18.2.2 isaki static const int adpcm_estimstep[16] = {
74 1.18.2.2 isaki -1, -1, -1, -1, 2, 4, 6, 8,
75 1.18.2.2 isaki -1, -1, -1, -1, 2, 4, 6, 8
76 1.18.2.2 isaki };
77 1.18.2.2 isaki
78 1.18.2.2 isaki static stream_filter_t *
79 1.18.2.2 isaki msm6258_factory(struct audio_softc *asc,
80 1.18.2.2 isaki int (*fetch_to)(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int))
81 1.18.2.2 isaki {
82 1.18.2.2 isaki struct msm6258_codecvar *this;
83 1.18.2.2 isaki
84 1.18.2.2 isaki this = kmem_alloc(sizeof(struct msm6258_codecvar), KM_SLEEP);
85 1.18.2.2 isaki this->base.base.fetch_to = fetch_to;
86 1.18.2.2 isaki this->base.dtor = msm6258_dtor;
87 1.18.2.2 isaki this->base.set_fetcher = stream_filter_set_fetcher;
88 1.18.2.2 isaki this->base.set_inputbuffer = stream_filter_set_inputbuffer;
89 1.18.2.2 isaki return &this->base;
90 1.18.2.2 isaki }
91 1.18.2.2 isaki
92 1.18.2.2 isaki static void
93 1.18.2.2 isaki msm6258_dtor(struct stream_filter *this)
94 1.18.2.2 isaki {
95 1.18.2.2 isaki if (this != NULL)
96 1.18.2.2 isaki kmem_free(this, sizeof(struct msm6258_codecvar));
97 1.18.2.2 isaki }
98 1.18.2.2 isaki
99 1.18.2.2 isaki /*
100 1.18.2.2 isaki * signed 16bit linear PCM -> OkiADPCM
101 1.18.2.2 isaki */
102 1.18.2.2 isaki static inline uint8_t
103 1.18.2.2 isaki pcm2adpcm_step(struct msm6258_codecvar *mc, int16_t a)
104 1.18.2.2 isaki {
105 1.18.2.2 isaki int estim = (int)mc->mc_estim;
106 1.18.2.2 isaki int df;
107 1.18.2.2 isaki short dl, c;
108 1.18.2.2 isaki uint8_t b;
109 1.18.2.2 isaki uint8_t s;
110 1.18.2.2 isaki
111 1.18.2.2 isaki df = a - mc->mc_amp;
112 1.18.2.2 isaki dl = adpcm_estim[estim];
113 1.18.2.2 isaki c = (df / 16) * 8 / dl;
114 1.18.2.2 isaki if (df < 0) {
115 1.18.2.2 isaki b = (unsigned char)(-c) / 2;
116 1.18.2.2 isaki s = 0x08;
117 1.18.2.2 isaki } else {
118 1.18.2.2 isaki b = (unsigned char)(c) / 2;
119 1.18.2.2 isaki s = 0;
120 1.18.2.2 isaki }
121 1.18.2.2 isaki if (b > 7)
122 1.18.2.2 isaki b = 7;
123 1.18.2.2 isaki s |= b;
124 1.18.2.2 isaki mc->mc_amp += (short)(adpcm_estimindex[(int)s] * dl);
125 1.18.2.2 isaki estim += adpcm_estimstep[b];
126 1.18.2.2 isaki if (estim < 0)
127 1.18.2.2 isaki estim = 0;
128 1.18.2.2 isaki else if (estim > 48)
129 1.18.2.2 isaki estim = 48;
130 1.18.2.2 isaki
131 1.18.2.2 isaki mc->mc_estim = estim;
132 1.18.2.2 isaki return s;
133 1.18.2.2 isaki }
134 1.18.2.2 isaki
135 1.18.2.2 isaki #define DEFINE_FILTER(name) \
136 1.18.2.2 isaki static int \
137 1.18.2.2 isaki name##_fetch_to(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int); \
138 1.18.2.2 isaki stream_filter_t * \
139 1.18.2.2 isaki name(struct audio_softc *sc, const audio_params_t *from, \
140 1.18.2.2 isaki const audio_params_t *to) \
141 1.18.2.2 isaki { \
142 1.18.2.2 isaki return msm6258_factory(sc, name##_fetch_to); \
143 1.18.2.2 isaki } \
144 1.18.2.2 isaki static int \
145 1.18.2.2 isaki name##_fetch_to(struct audio_softc *asc, stream_fetcher_t *self, audio_stream_t *dst, int max_used)
146 1.18.2.2 isaki
147 1.18.2.2 isaki DEFINE_FILTER(msm6258_slinear16_to_adpcm)
148 1.18.2.2 isaki {
149 1.18.2.2 isaki stream_filter_t *this;
150 1.18.2.2 isaki struct msm6258_codecvar *mc;
151 1.18.2.2 isaki uint8_t *d;
152 1.18.2.2 isaki const uint8_t *s;
153 1.18.2.2 isaki int m, err, enc_src;
154 1.18.2.2 isaki
155 1.18.2.2 isaki this = (stream_filter_t *)self;
156 1.18.2.2 isaki mc = (struct msm6258_codecvar *)self;
157 1.18.2.2 isaki if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used * 4)))
158 1.18.2.2 isaki return err;
159 1.18.2.2 isaki m = dst->end - dst->start;
160 1.18.2.2 isaki m = min(m, max_used);
161 1.18.2.2 isaki d = dst->inp;
162 1.18.2.2 isaki s = this->src->outp;
163 1.18.2.2 isaki enc_src = this->src->param.encoding;
164 1.18.2.2 isaki if (enc_src == AUDIO_ENCODING_SLINEAR_LE) {
165 1.18.2.2 isaki while (dst->used < m && this->src->used >= 4) {
166 1.18.2.2 isaki uint8_t f;
167 1.18.2.2 isaki int16_t ss;
168 1.18.2.2 isaki #if BYTE_ORDER == LITTLE_ENDIAN
169 1.18.2.2 isaki ss = *(const int16_t*)s;
170 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 2);
171 1.18.2.2 isaki f = pcm2adpcm_step(mc, ss);
172 1.18.2.2 isaki ss = *(const int16_t*)s;
173 1.18.2.2 isaki #else
174 1.18.2.2 isaki ss = (s[1] << 8) | s[0];
175 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 2);
176 1.18.2.2 isaki f = pcm2adpcm_step(mc, ss);
177 1.18.2.2 isaki ss = (s[1] << 8) | s[0];
178 1.18.2.2 isaki #endif
179 1.18.2.2 isaki f |= pcm2adpcm_step(mc, ss) << 4;
180 1.18.2.2 isaki *d = f;
181 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 1);
182 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 2);
183 1.18.2.2 isaki }
184 1.18.2.2 isaki #if defined(DIAGNOSTIC)
185 1.18.2.2 isaki } else if (enc_src == AUDIO_ENCODING_SLINEAR_BE) {
186 1.18.2.2 isaki #else
187 1.18.2.2 isaki } else {
188 1.18.2.2 isaki #endif
189 1.18.2.2 isaki while (dst->used < m && this->src->used >= 4) {
190 1.18.2.2 isaki uint8_t f;
191 1.18.2.2 isaki int16_t ss;
192 1.18.2.2 isaki #if BYTE_ORDER == BIG_ENDIAN
193 1.18.2.2 isaki ss = *(const int16_t*)s;
194 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 2);
195 1.18.2.2 isaki f = pcm2adpcm_step(mc, ss);
196 1.18.2.2 isaki ss = *(const int16_t*)s;
197 1.18.2.2 isaki #else
198 1.18.2.2 isaki ss = (s[0] << 8) | s[1];
199 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 2);
200 1.18.2.2 isaki f = pcm2adpcm_step(mc, ss);
201 1.18.2.2 isaki ss = (s[0] << 8) | s[1];
202 1.18.2.2 isaki #endif
203 1.18.2.2 isaki f |= pcm2adpcm_step(mc, ss) << 4;
204 1.18.2.2 isaki *d = f;
205 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 1);
206 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 2);
207 1.18.2.2 isaki }
208 1.18.2.2 isaki }
209 1.18.2.2 isaki #if defined(DIAGNOSTIC)
210 1.18.2.2 isaki else {
211 1.18.2.2 isaki panic("msm6258_slinear16_to_adpcm: unsupported enc_src(%d)", enc_src);
212 1.18.2.2 isaki }
213 1.18.2.2 isaki #endif
214 1.18.2.2 isaki dst->inp = d;
215 1.18.2.2 isaki this->src->outp = s;
216 1.18.2.2 isaki return 0;
217 1.18.2.2 isaki }
218 1.18.2.2 isaki
219 1.18.2.2 isaki DEFINE_FILTER(msm6258_linear8_to_adpcm)
220 1.18.2.2 isaki {
221 1.18.2.2 isaki stream_filter_t *this;
222 1.18.2.2 isaki struct msm6258_codecvar *mc;
223 1.18.2.2 isaki uint8_t *d;
224 1.18.2.2 isaki const uint8_t *s;
225 1.18.2.2 isaki int m, err, enc_src;
226 1.18.2.2 isaki
227 1.18.2.2 isaki this = (stream_filter_t *)self;
228 1.18.2.2 isaki mc = (struct msm6258_codecvar *)self;
229 1.18.2.2 isaki if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used * 2)))
230 1.18.2.2 isaki return err;
231 1.18.2.2 isaki m = dst->end - dst->start;
232 1.18.2.2 isaki m = min(m, max_used);
233 1.18.2.2 isaki d = dst->inp;
234 1.18.2.2 isaki s = this->src->outp;
235 1.18.2.2 isaki enc_src = this->src->param.encoding;
236 1.18.2.2 isaki if (enc_src == AUDIO_ENCODING_SLINEAR_LE) {
237 1.18.2.2 isaki while (dst->used < m && this->src->used >= 4) {
238 1.18.2.2 isaki uint8_t f;
239 1.18.2.2 isaki int16_t ss;
240 1.18.2.2 isaki ss = ((int16_t)s[0]) * 256;
241 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 1);
242 1.18.2.2 isaki f = pcm2adpcm_step(mc, ss);
243 1.18.2.2 isaki ss = ((int16_t)s[0]) * 256;
244 1.18.2.2 isaki f |= pcm2adpcm_step(mc, ss) << 4;
245 1.18.2.2 isaki *d = f;
246 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 1);
247 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 1);
248 1.18.2.2 isaki }
249 1.18.2.2 isaki #if defined(DIAGNOSTIC)
250 1.18.2.2 isaki } else if (enc_src == AUDIO_ENCODING_ULINEAR_LE) {
251 1.18.2.2 isaki #else
252 1.18.2.2 isaki } else {
253 1.18.2.2 isaki #endif
254 1.18.2.2 isaki while (dst->used < m && this->src->used >= 4) {
255 1.18.2.2 isaki uint8_t f;
256 1.18.2.2 isaki int16_t ss;
257 1.18.2.2 isaki ss = ((int16_t)(s[0] ^ 0x80)) * 256;
258 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 1);
259 1.18.2.2 isaki f = pcm2adpcm_step(mc, ss);
260 1.18.2.2 isaki ss = ((int16_t)(s[0] ^ 0x80)) * 256;
261 1.18.2.2 isaki f |= pcm2adpcm_step(mc, ss) << 4;
262 1.18.2.2 isaki *d = f;
263 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 1);
264 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 1);
265 1.18.2.2 isaki }
266 1.18.2.2 isaki }
267 1.18.2.2 isaki #if defined(DIAGNOSTIC)
268 1.18.2.2 isaki else {
269 1.18.2.2 isaki panic("msm6258_linear8_to_adpcm: unsupported enc_src(%d)", enc_src);
270 1.18.2.2 isaki }
271 1.18.2.2 isaki #endif
272 1.18.2.2 isaki dst->inp = d;
273 1.18.2.2 isaki this->src->outp = s;
274 1.18.2.2 isaki return 0;
275 1.18.2.2 isaki }
276 1.18.2.2 isaki
277 1.18.2.2 isaki /*
278 1.18.2.2 isaki * OkiADPCM -> signed 16bit linear PCM
279 1.18.2.2 isaki */
280 1.18.2.2 isaki static inline int16_t
281 1.18.2.2 isaki adpcm2pcm_step(struct msm6258_codecvar *mc, uint8_t b)
282 1.18.2.2 isaki {
283 1.18.2.2 isaki int estim = (int)mc->mc_estim;
284 1.18.2.2 isaki
285 1.18.2.2 isaki mc->mc_amp += adpcm_estim[estim] * adpcm_estimindex[b];
286 1.18.2.2 isaki estim += adpcm_estimstep[b];
287 1.18.2.2 isaki
288 1.18.2.2 isaki if (estim < 0)
289 1.18.2.2 isaki estim = 0;
290 1.18.2.2 isaki else if (estim > 48)
291 1.18.2.2 isaki estim = 48;
292 1.18.2.2 isaki
293 1.18.2.2 isaki mc->mc_estim = estim;
294 1.18.2.2 isaki
295 1.18.2.2 isaki return mc->mc_amp;
296 1.18.2.2 isaki }
297 1.18.2.2 isaki
298 1.18.2.2 isaki DEFINE_FILTER(msm6258_adpcm_to_slinear16)
299 1.18.2.2 isaki {
300 1.18.2.2 isaki stream_filter_t *this;
301 1.18.2.2 isaki struct msm6258_codecvar *mc;
302 1.18.2.2 isaki uint8_t *d;
303 1.18.2.2 isaki const uint8_t *s;
304 1.18.2.2 isaki int m, err, enc_dst;
305 1.18.2.2 isaki
306 1.18.2.2 isaki this = (stream_filter_t *)self;
307 1.18.2.2 isaki mc = (struct msm6258_codecvar *)self;
308 1.18.2.2 isaki max_used = (max_used + 3) & ~3; /* round up multiple of 4 */
309 1.18.2.2 isaki if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used / 4)))
310 1.18.2.2 isaki return err;
311 1.18.2.2 isaki m = (dst->end - dst->start) & ~3;
312 1.18.2.2 isaki m = min(m, max_used);
313 1.18.2.2 isaki d = dst->inp;
314 1.18.2.2 isaki s = this->src->outp;
315 1.18.2.2 isaki enc_dst = dst->param.encoding;
316 1.18.2.2 isaki if (enc_dst == AUDIO_ENCODING_SLINEAR_LE) {
317 1.18.2.2 isaki while (dst->used < m && this->src->used >= 1) {
318 1.18.2.2 isaki uint8_t a;
319 1.18.2.2 isaki int16_t s1, s2;
320 1.18.2.2 isaki a = s[0];
321 1.18.2.2 isaki s1 = adpcm2pcm_step(mc, a & 0x0f);
322 1.18.2.2 isaki s2 = adpcm2pcm_step(mc, a >> 4);
323 1.18.2.2 isaki #if BYTE_ORDER == LITTLE_ENDIAN
324 1.18.2.2 isaki *(int16_t*)d = s1;
325 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 2);
326 1.18.2.2 isaki *(int16_t*)d = s2;
327 1.18.2.2 isaki #else
328 1.18.2.2 isaki d[0] = s1;
329 1.18.2.2 isaki d[1] = s1 >> 8;
330 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 2);
331 1.18.2.2 isaki d[0] = s2;
332 1.18.2.2 isaki d[1] = s2 >> 8;
333 1.18.2.2 isaki #endif
334 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 2);
335 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 1);
336 1.18.2.2 isaki }
337 1.18.2.2 isaki #if defined(DIAGNOSTIC)
338 1.18.2.2 isaki } else if (enc_dst == AUDIO_ENCODING_SLINEAR_BE) {
339 1.18.2.2 isaki #else
340 1.18.2.2 isaki } else {
341 1.18.2.2 isaki #endif
342 1.18.2.2 isaki while (dst->used < m && this->src->used >= 1) {
343 1.18.2.2 isaki uint8_t a;
344 1.18.2.2 isaki int16_t s1, s2;
345 1.18.2.2 isaki a = s[0];
346 1.18.2.2 isaki s1 = adpcm2pcm_step(mc, a & 0x0f);
347 1.18.2.2 isaki s2 = adpcm2pcm_step(mc, a >> 4);
348 1.18.2.2 isaki #if BYTE_ORDER == BIG_ENDIAN
349 1.18.2.2 isaki *(int16_t*)d = s1;
350 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 2);
351 1.18.2.2 isaki *(int16_t*)d = s2;
352 1.18.2.2 isaki #else
353 1.18.2.2 isaki d[1] = s1;
354 1.18.2.2 isaki d[0] = s1 >> 8;
355 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 2);
356 1.18.2.2 isaki d[1] = s2;
357 1.18.2.2 isaki d[0] = s2 >> 8;
358 1.18.2.2 isaki #endif
359 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 2);
360 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 1);
361 1.18.2.2 isaki }
362 1.18.2.2 isaki }
363 1.18.2.2 isaki #if defined(DIAGNOSTIC)
364 1.18.2.2 isaki else {
365 1.18.2.2 isaki panic("msm6258_adpcm_to_slinear16: unsupported enc_dst(%d)", enc_dst);
366 1.18.2.2 isaki }
367 1.18.2.2 isaki #endif
368 1.18.2.2 isaki dst->inp = d;
369 1.18.2.2 isaki this->src->outp = s;
370 1.18.2.2 isaki return 0;
371 1.18.2.2 isaki }
372 1.18.2.2 isaki
373 1.18.2.2 isaki DEFINE_FILTER(msm6258_adpcm_to_linear8)
374 1.18.2.2 isaki {
375 1.18.2.2 isaki stream_filter_t *this;
376 1.18.2.2 isaki struct msm6258_codecvar *mc;
377 1.18.2.2 isaki uint8_t *d;
378 1.18.2.2 isaki const uint8_t *s;
379 1.18.2.2 isaki int m, err, enc_dst;
380 1.18.2.2 isaki
381 1.18.2.2 isaki this = (stream_filter_t *)self;
382 1.18.2.2 isaki mc = (struct msm6258_codecvar *)self;
383 1.18.2.2 isaki max_used = (max_used + 1) & ~1; /* round up multiple of 4 */
384 1.18.2.2 isaki if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used / 2)))
385 1.18.2.2 isaki return err;
386 1.18.2.2 isaki m = (dst->end - dst->start) & ~1;
387 1.18.2.2 isaki m = min(m, max_used);
388 1.18.2.2 isaki d = dst->inp;
389 1.18.2.2 isaki s = this->src->outp;
390 1.18.2.2 isaki enc_dst = dst->param.encoding;
391 1.18.2.2 isaki if (enc_dst == AUDIO_ENCODING_SLINEAR_LE) {
392 1.18.2.2 isaki while (dst->used < m && this->src->used >= 1) {
393 1.18.2.2 isaki uint8_t a;
394 1.18.2.2 isaki int16_t s1, s2;
395 1.18.2.2 isaki a = s[0];
396 1.18.2.2 isaki s1 = adpcm2pcm_step(mc, a & 0x0f);
397 1.18.2.2 isaki s2 = adpcm2pcm_step(mc, a >> 4);
398 1.18.2.2 isaki d[0] = s1 / 266;
399 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 1);
400 1.18.2.2 isaki d[0] = s2 / 266;
401 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 1);
402 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 1);
403 1.18.2.2 isaki }
404 1.18.2.2 isaki #if defined(DIAGNOSTIC)
405 1.18.2.2 isaki } else if (enc_dst == AUDIO_ENCODING_ULINEAR_LE) {
406 1.18.2.2 isaki #else
407 1.18.2.2 isaki } else {
408 1.18.2.2 isaki #endif
409 1.18.2.2 isaki while (dst->used < m && this->src->used >= 1) {
410 1.18.2.2 isaki uint8_t a;
411 1.18.2.2 isaki int16_t s1, s2;
412 1.18.2.2 isaki a = s[0];
413 1.18.2.2 isaki s1 = adpcm2pcm_step(mc, a & 0x0f);
414 1.18.2.2 isaki s2 = adpcm2pcm_step(mc, a >> 4);
415 1.18.2.2 isaki d[0] = (s1 / 266) ^ 0x80;
416 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 1);
417 1.18.2.2 isaki d[0] = (s2 / 266) ^ 0x80;
418 1.18.2.2 isaki d = audio_stream_add_inp(dst, d, 1);
419 1.18.2.2 isaki s = audio_stream_add_outp(this->src, s, 1);
420 1.18.2.2 isaki }
421 1.18.2.2 isaki }
422 1.18.2.2 isaki #if defined(DIAGNOSTIC)
423 1.18.2.2 isaki else {
424 1.18.2.2 isaki panic("msm6258_adpcm_to_linear8: unsupported enc_dst(%d)", enc_dst);
425 1.18.2.2 isaki }
426 1.18.2.2 isaki #endif
427 1.18.2.2 isaki dst->inp = d;
428 1.18.2.2 isaki this->src->outp = s;
429 1.18.2.2 isaki return 0;
430 1.18.2.2 isaki }
431