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