msm6258.c revision 1.10 1 1.10 isaki /* $NetBSD: msm6258.c,v 1.10 2002/04/13 12:40:50 isaki Exp $ */
2 1.1 minoura
3 1.1 minoura /*
4 1.1 minoura * Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
5 1.1 minoura *
6 1.1 minoura * Redistribution and use in source and binary forms, with or without
7 1.1 minoura * modification, are permitted provided that the following conditions
8 1.1 minoura * are met:
9 1.1 minoura * 1. Redistributions of source code must retain the above copyright
10 1.1 minoura * notice, this list of conditions and the following disclaimer.
11 1.1 minoura * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 minoura * notice, this list of conditions and the following disclaimer in the
13 1.1 minoura * documentation and/or other materials provided with the distribution.
14 1.1 minoura * 3. All advertising materials mentioning features or use of this software
15 1.1 minoura * must display the following acknowledgement:
16 1.1 minoura * This product includes software developed by Tetsuya Isaki.
17 1.1 minoura * 4. The name of the author may not be used to endorse or promote products
18 1.1 minoura * derived from this software without specific prior written permission
19 1.1 minoura *
20 1.1 minoura * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 1.1 minoura * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 1.1 minoura * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 1.1 minoura * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 1.1 minoura * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 1.1 minoura * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 1.1 minoura * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 1.1 minoura * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 1.1 minoura * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 1.1 minoura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 1.1 minoura * SUCH DAMAGE.
31 1.1 minoura */
32 1.1 minoura
33 1.1 minoura /*
34 1.1 minoura * OKI MSM6258 ADPCM voice synthesizer codec.
35 1.1 minoura */
36 1.5 lukem
37 1.5 lukem #include <sys/cdefs.h>
38 1.10 isaki __KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.10 2002/04/13 12:40:50 isaki Exp $");
39 1.1 minoura
40 1.1 minoura #include <sys/systm.h>
41 1.1 minoura #include <sys/device.h>
42 1.1 minoura #include <sys/malloc.h>
43 1.1 minoura #include <sys/select.h>
44 1.1 minoura #include <sys/audioio.h>
45 1.1 minoura
46 1.1 minoura #include <dev/audio_if.h>
47 1.6 isaki #include <dev/auconv.h>
48 1.1 minoura #include <dev/audiovar.h>
49 1.4 minoura #include <dev/mulaw.h>
50 1.1 minoura #include <dev/ic/msm6258var.h>
51 1.1 minoura
52 1.9 isaki struct msm6258_codecvar {
53 1.9 isaki /* ADPCM stream must be converted in order. */
54 1.9 isaki u_char mc_buf[AU_RING_SIZE]; /* XXX */
55 1.1 minoura
56 1.9 isaki short mc_amp;
57 1.9 isaki char mc_estim;
58 1.9 isaki };
59 1.1 minoura
60 1.9 isaki struct msm6258_softc {
61 1.9 isaki struct device sc_dev;
62 1.9 isaki struct msm6258_codecvar *sc_mc;
63 1.9 isaki /* MD vars follow */
64 1.9 isaki };
65 1.9 isaki
66 1.9 isaki static inline u_char pcm2adpcm_step(struct msm6258_codecvar *, short);
67 1.9 isaki static inline short adpcm2pcm_step(struct msm6258_codecvar *, u_char);
68 1.1 minoura
69 1.1 minoura static int adpcm_estimindex[16] = {
70 1.9 isaki 2, 6, 10, 14, 18, 22, 26, 30,
71 1.9 isaki -2, -6, -10, -14, -18, -22, -26, -30
72 1.1 minoura };
73 1.1 minoura
74 1.1 minoura static int adpcm_estim[49] = {
75 1.1 minoura 16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
76 1.1 minoura 41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
77 1.1 minoura 107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
78 1.1 minoura 279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
79 1.10 isaki 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
80 1.1 minoura };
81 1.1 minoura
82 1.9 isaki static int adpcm_estimstep[16] = {
83 1.1 minoura -1, -1, -1, -1, 2, 4, 6, 8,
84 1.1 minoura -1, -1, -1, -1, 2, 4, 6, 8
85 1.1 minoura };
86 1.1 minoura
87 1.1 minoura void *
88 1.1 minoura msm6258_codec_init (void)
89 1.1 minoura {
90 1.1 minoura struct msm6258_codecvar *r;
91 1.1 minoura
92 1.1 minoura r = malloc (sizeof(*r), M_DEVBUF, M_NOWAIT);
93 1.1 minoura if (r == 0)
94 1.1 minoura return 0;
95 1.1 minoura r->mc_amp = r->mc_estim = 0;
96 1.1 minoura
97 1.1 minoura return r;
98 1.8 isaki }
99 1.8 isaki
100 1.8 isaki int
101 1.8 isaki msm6258_codec_open(void *hdl)
102 1.8 isaki {
103 1.8 isaki struct msm6258_softc *sc = hdl;
104 1.8 isaki struct msm6258_codecvar *mc = sc->sc_mc;
105 1.8 isaki
106 1.8 isaki mc->mc_amp = 0;
107 1.8 isaki mc->mc_estim = 0;
108 1.8 isaki
109 1.8 isaki return 0;
110 1.1 minoura }
111 1.1 minoura
112 1.9 isaki /*
113 1.9 isaki * signed 16bit linear PCM -> OkiADPCM
114 1.9 isaki */
115 1.1 minoura static inline u_char
116 1.9 isaki pcm2adpcm_step(struct msm6258_codecvar *mc, short a)
117 1.9 isaki {
118 1.9 isaki int estim = (int)mc->mc_estim;
119 1.9 isaki int df;
120 1.9 isaki short dl, c;
121 1.9 isaki unsigned char b;
122 1.9 isaki unsigned char s;
123 1.9 isaki
124 1.9 isaki df = a - mc->mc_amp;
125 1.9 isaki dl = adpcm_estim[estim];
126 1.9 isaki c = (df / 16) * 8 / dl;
127 1.9 isaki if (df < 0) {
128 1.9 isaki b = (unsigned char)(-c) / 2;
129 1.9 isaki s = 0x08;
130 1.9 isaki } else {
131 1.9 isaki b = (unsigned char)(c) / 2;
132 1.9 isaki s = 0;
133 1.9 isaki }
134 1.9 isaki if (b > 7)
135 1.9 isaki b = 7;
136 1.9 isaki s |= b;
137 1.9 isaki mc->mc_amp += (short)(adpcm_estimindex[(int)s] * dl);
138 1.9 isaki estim += adpcm_estimstep[b];
139 1.9 isaki if (estim < 0)
140 1.9 isaki estim = 0;
141 1.9 isaki else if (estim > 48)
142 1.9 isaki estim = 48;
143 1.9 isaki
144 1.9 isaki mc->mc_estim = estim;
145 1.9 isaki return s;
146 1.9 isaki }
147 1.9 isaki
148 1.9 isaki void
149 1.9 isaki msm6258_slinear16_host_to_adpcm(void *hdl, u_char *p, int cc)
150 1.1 minoura {
151 1.9 isaki struct msm6258_softc *sc = hdl;
152 1.9 isaki struct msm6258_codecvar *mc = sc->sc_mc;
153 1.9 isaki short *s = (short *)p;
154 1.9 isaki int i;
155 1.9 isaki u_char f;
156 1.1 minoura
157 1.9 isaki for (i = 0; i < cc; i += 4) {
158 1.9 isaki f = pcm2adpcm_step(mc, *s++);
159 1.9 isaki f |= pcm2adpcm_step(mc, *s++) << 4;
160 1.9 isaki *p++ = f;
161 1.1 minoura }
162 1.9 isaki }
163 1.9 isaki
164 1.9 isaki void
165 1.9 isaki msm6258_slinear16_le_to_adpcm(void *hdl, u_char *p, int cc)
166 1.9 isaki {
167 1.9 isaki #if BYTE_ORDER == BIG_ENDIAN
168 1.9 isaki swap_bytes(hdl, p, cc);
169 1.9 isaki #endif
170 1.9 isaki msm6258_slinear16_host_to_adpcm(hdl, p, cc);
171 1.9 isaki }
172 1.1 minoura
173 1.9 isaki void
174 1.9 isaki msm6258_slinear16_be_to_adpcm(void *hdl, u_char *p, int cc)
175 1.9 isaki {
176 1.9 isaki #if BYTE_ORDER == LITTLE_ENDIAN
177 1.9 isaki swap_bytes(hdl, p, cc);
178 1.9 isaki #endif
179 1.9 isaki msm6258_slinear16_host_to_adpcm(hdl, p, cc);
180 1.1 minoura }
181 1.1 minoura
182 1.1 minoura void
183 1.9 isaki msm6258_slinear8_to_adpcm(void *hdl, u_char *p, int cc)
184 1.1 minoura {
185 1.1 minoura struct msm6258_softc *sc = hdl;
186 1.1 minoura struct msm6258_codecvar *mc = sc->sc_mc;
187 1.9 isaki u_char *s = p;
188 1.9 isaki int i;
189 1.1 minoura u_char f;
190 1.1 minoura
191 1.9 isaki for (i = 0; i < cc; i += 2) {
192 1.9 isaki f = pcm2adpcm_step(mc, (short)(*s++) * 256);
193 1.9 isaki f |= pcm2adpcm_step(mc, (short)(*s++) * 256) << 4;
194 1.9 isaki *p++ = f;
195 1.1 minoura }
196 1.1 minoura }
197 1.1 minoura
198 1.1 minoura void
199 1.9 isaki msm6258_ulinear8_to_adpcm(void *hdl, u_char *p, int cc)
200 1.9 isaki {
201 1.9 isaki change_sign8(hdl, p, cc);
202 1.9 isaki msm6258_slinear8_to_adpcm(hdl, p, cc);
203 1.9 isaki }
204 1.9 isaki
205 1.9 isaki void
206 1.1 minoura msm6258_mulaw_to_adpcm(void *hdl, u_char *p, int cc)
207 1.1 minoura {
208 1.9 isaki mulaw_to_slinear8(hdl, p, cc);
209 1.9 isaki msm6258_slinear8_to_adpcm(hdl, p, cc);
210 1.1 minoura }
211 1.1 minoura
212 1.9 isaki
213 1.9 isaki /*
214 1.9 isaki * OkiADPCM -> signed 16bit linear PCM
215 1.9 isaki */
216 1.9 isaki static inline short
217 1.9 isaki adpcm2pcm_step(struct msm6258_codecvar *mc, u_char b)
218 1.1 minoura {
219 1.9 isaki int estim = (int)mc->mc_estim;
220 1.7 isaki
221 1.9 isaki mc->mc_amp += adpcm_estim[estim] * adpcm_estimindex[b];
222 1.9 isaki estim += adpcm_estimstep[b];
223 1.7 isaki
224 1.7 isaki if (estim < 0)
225 1.7 isaki estim = 0;
226 1.9 isaki else if (estim > 48)
227 1.7 isaki estim = 48;
228 1.9 isaki
229 1.9 isaki mc->mc_estim = estim;
230 1.9 isaki
231 1.9 isaki return mc->mc_amp;
232 1.1 minoura }
233 1.1 minoura
234 1.9 isaki void
235 1.9 isaki msm6258_adpcm_to_slinear16_host(void *hdl, u_char *p, int cc)
236 1.9 isaki {
237 1.9 isaki struct msm6258_softc *sc = hdl;
238 1.9 isaki struct msm6258_codecvar *mc = sc->sc_mc;
239 1.9 isaki short *d = (short *)p;
240 1.9 isaki int i;
241 1.9 isaki u_char a;
242 1.9 isaki
243 1.9 isaki /* XXX alignment ? */
244 1.9 isaki memcpy(mc->mc_buf, p, cc / 4);
245 1.9 isaki for (i = 0; i < cc / 4;) {
246 1.9 isaki a = mc->mc_buf[i++];
247 1.9 isaki
248 1.9 isaki *d++ = adpcm2pcm_step(mc, a & 0x0f);
249 1.9 isaki *d++ = adpcm2pcm_step(mc, (a >> 4) & 0x0f);
250 1.9 isaki }
251 1.9 isaki }
252 1.9 isaki
253 1.9 isaki void
254 1.9 isaki msm6258_adpcm_to_slinear16_le(void *hdl, u_char *p, int cc)
255 1.9 isaki {
256 1.9 isaki msm6258_adpcm_to_slinear16_host(hdl, p, cc);
257 1.9 isaki #if BYTE_ORDER == BIG_ENDIAN
258 1.9 isaki swap_bytes(hdl, p, cc);
259 1.9 isaki #endif
260 1.9 isaki }
261 1.9 isaki
262 1.9 isaki void
263 1.9 isaki msm6258_adpcm_to_slinear16_be(void *hdl, u_char *p, int cc)
264 1.9 isaki {
265 1.9 isaki msm6258_adpcm_to_slinear16_host(hdl, p, cc);
266 1.9 isaki #if BYTE_ORDER == LITTLE_ENDIAN
267 1.9 isaki swap_bytes(hdl, p, cc);
268 1.9 isaki #endif
269 1.9 isaki }
270 1.1 minoura
271 1.1 minoura void
272 1.9 isaki msm6258_adpcm_to_slinear8(void *hdl, u_char *p, int cc)
273 1.1 minoura {
274 1.1 minoura struct msm6258_softc *sc = hdl;
275 1.1 minoura struct msm6258_codecvar *mc = sc->sc_mc;
276 1.9 isaki char *d = (char *)p;
277 1.1 minoura int i;
278 1.9 isaki u_char a;
279 1.1 minoura
280 1.9 isaki /* cc may be even. XXX alignment ? */
281 1.9 isaki memcpy(mc->mc_buf, p, cc / 2);
282 1.9 isaki for (i = 0; i < cc / 2;) {
283 1.9 isaki a = mc->mc_buf[i++];
284 1.9 isaki
285 1.9 isaki *d++ = adpcm2pcm_step(mc, a & 0x0f) / 256;
286 1.9 isaki *d++ = adpcm2pcm_step(mc, (a >> 4) & 0x0f) / 256;
287 1.1 minoura }
288 1.1 minoura }
289 1.1 minoura
290 1.1 minoura void
291 1.9 isaki msm6258_adpcm_to_ulinear8(void *hdl, u_char *p, int cc)
292 1.9 isaki {
293 1.9 isaki msm6258_adpcm_to_slinear8(hdl, p, cc);
294 1.9 isaki change_sign8(hdl, p, cc);
295 1.9 isaki }
296 1.9 isaki
297 1.9 isaki void
298 1.1 minoura msm6258_adpcm_to_mulaw(void *hdl, u_char *p, int cc)
299 1.1 minoura {
300 1.9 isaki msm6258_adpcm_to_slinear8(hdl, p, cc);
301 1.9 isaki slinear8_to_mulaw(hdl, p, cc);
302 1.1 minoura }
303 1.9 isaki
304