Home | History | Annotate | Line # | Download | only in ic
msm6258.c revision 1.8
      1 /*	$NetBSD: msm6258.c,v 1.8 2002/04/02 15:22:38 isaki Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *      This product includes software developed by Tetsuya Isaki.
     17  * 4. The name of the author may not be used to endorse or promote products
     18  *    derived from this software without specific prior written permission
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * OKI MSM6258 ADPCM voice synthesizer codec.
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.8 2002/04/02 15:22:38 isaki Exp $");
     39 
     40 #include <sys/systm.h>
     41 #include <sys/device.h>
     42 #include <sys/malloc.h>
     43 #include <sys/select.h>
     44 #include <sys/audioio.h>
     45 
     46 #include <dev/audio_if.h>
     47 #include <dev/auconv.h>
     48 #include <dev/audiovar.h>
     49 #include <dev/mulaw.h>
     50 #include <dev/ic/msm6258var.h>
     51 
     52 
     53 static inline u_char pcm2adpcm_step(short, short *, char *);
     54 static inline void adpcm2pcm_step(u_char, short *, char *);
     55 
     56 
     57 static int adpcm_estimindex[16] = {
     58 	 1,  3,  5,  7,  9,  11,  13,  15,
     59 	-1, -3, -5, -7, -9, -11, -13, -15
     60 };
     61 
     62 static int adpcm_estim[49] = {
     63 	 16,  17,  19,  21,  23,  25,  28,  31,  34,  37,
     64 	 41,  45,  50,  55,  60,  66,  73,  80,  88,  97,
     65 	107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
     66 	279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
     67 	724, 796, 875, 963, 1060, 1166, 1282, 1411, 1552
     68 };
     69 
     70 static u_char adpcm_estimindex_correct[16] = {
     71 	-1, -1, -1, -1, 2, 4, 6, 8,
     72 	-1, -1, -1, -1, 2, 4, 6, 8
     73 };
     74 
     75 struct msm6258_codecvar {
     76 	short	mc_amp;
     77 	char	mc_estim;
     78 };
     79 
     80 struct msm6258_softc {
     81 	struct device sc_dev;
     82 	struct msm6258_codecvar *sc_mc;
     83 	/* MD vars follow */
     84 };
     85 
     86 void *
     87 msm6258_codec_init (void)
     88 {
     89 	struct msm6258_codecvar *r;
     90 
     91 	r = malloc (sizeof(*r), M_DEVBUF, M_NOWAIT);
     92 	if (r == 0)
     93 		return 0;
     94 	r->mc_amp = r->mc_estim = 0;
     95 
     96 	return r;
     97 }
     98 
     99 int
    100 msm6258_codec_open(void *hdl)
    101 {
    102 	struct msm6258_softc *sc = hdl;
    103 	struct msm6258_codecvar *mc = sc->sc_mc;
    104 
    105 	mc->mc_amp = 0;
    106 	mc->mc_estim = 0;
    107 
    108 	return 0;
    109 }
    110 
    111 static inline u_char
    112 pcm2adpcm_step(short a, short *y, char *x)
    113 {
    114 	int c, d;
    115 	register unsigned char b;
    116 
    117 	a -= *y;
    118 	d = adpcm_estim[(int) *x];
    119 	c = a * 4  / d;
    120 
    121 	if (c < 0) {
    122 		b = (unsigned char)-c;
    123 		if (b >= 8)
    124 			b = 7;
    125 		b |= 0x08;
    126 	} else {
    127 		b = (unsigned char)c;
    128 		if (b >= 8)
    129 			b = 7;
    130 	}
    131 
    132 	*y += (short)(adpcm_estimindex[b] * d / 8);
    133 	*x += adpcm_estimindex_correct[b];
    134 	if (*x < 0)
    135 		*x = 0;
    136 	else if (*x > 48)
    137 		*x = 48;
    138 	return b;
    139 }
    140 
    141 void
    142 msm6258_ulinear8_to_adpcm(void *hdl, u_char *p, int cc)
    143 {
    144 	struct msm6258_softc *sc = hdl;
    145 	struct msm6258_codecvar *mc = sc->sc_mc;
    146 	char *x = &(mc->mc_estim);
    147 	short *y = &(mc->mc_amp);
    148 	register int i;
    149 	u_char *d = p;
    150 	u_char f;
    151 
    152 	for (i = 0; i < cc; ) {
    153 		f = pcm2adpcm_step(p[i++], y, x);
    154 		*d++ = f + (pcm2adpcm_step(p[i++], y, x) << 4);
    155 	}
    156 }
    157 
    158 void
    159 msm6258_mulaw_to_adpcm(void *hdl, u_char *p, int cc)
    160 {
    161 	mulaw_to_ulinear8(hdl, p, cc);
    162 	msm6258_ulinear8_to_adpcm(hdl, p, cc);
    163 }
    164 
    165 static inline void
    166 adpcm2pcm_step(u_char b, short *y, char *x)
    167 {
    168 	short dl;
    169 	short pcm = *y;
    170 	int estim = *x;
    171 
    172 	dl = adpcm_estim[estim] * adpcm_estimindex[b] / 8;
    173 	pcm += dl;
    174 	*y = pcm / 256;
    175 
    176 	estim += adpcm_estimindex_correct[b];
    177 	if (estim < 0)
    178 		estim = 0;
    179 	if (estim > 48)
    180 		estim = 48;
    181 	*x = estim;
    182 }
    183 
    184 /* ADPCM stream must be converted in order. */
    185 u_char tmpbuf[AU_RING_SIZE]; /* XXX */
    186 
    187 void
    188 msm6258_adpcm_to_ulinear8(void *hdl, u_char *p, int cc)
    189 {
    190 	struct msm6258_softc *sc = hdl;
    191 	struct msm6258_codecvar *mc = sc->sc_mc;
    192 	char *x = &(mc->mc_estim);
    193 	short *y = &(mc->mc_amp);
    194 	u_char a, b;
    195 	int i;
    196 
    197 	/* cc may be even. XXX alignment? */
    198 	memcpy(tmpbuf, p, cc/2);
    199 	for (i = 0; i < cc/2;) {
    200 		a = tmpbuf[i++];
    201 		b = a & 0x0f;
    202 		adpcm2pcm_step(b, y, x);
    203 		*p++ = *y;
    204 		b = a >> 4;
    205 		adpcm2pcm_step(b, y, x);
    206 		*p++ = *y;
    207 	}
    208 }
    209 
    210 void
    211 msm6258_adpcm_to_mulaw(void *hdl, u_char *p, int cc)
    212 {
    213 	msm6258_adpcm_to_ulinear8(hdl, p, cc);
    214 	ulinear8_to_mulaw(hdl, p, cc*2);
    215 }
    216