Home | History | Annotate | Line # | Download | only in ic
msm6258.c revision 1.7
      1 /*	$NetBSD: msm6258.c,v 1.7 2002/04/02 15:19:00 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.7 2002/04/02 15:19:00 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 static inline u_char
    100 pcm2adpcm_step(short a, short *y, char *x)
    101 {
    102 	int c, d;
    103 	register unsigned char b;
    104 
    105 	a -= *y;
    106 	d = adpcm_estim[(int) *x];
    107 	c = a * 4  / d;
    108 
    109 	if (c < 0) {
    110 		b = (unsigned char)-c;
    111 		if (b >= 8)
    112 			b = 7;
    113 		b |= 0x08;
    114 	} else {
    115 		b = (unsigned char)c;
    116 		if (b >= 8)
    117 			b = 7;
    118 	}
    119 
    120 	*y += (short)(adpcm_estimindex[b] * d / 8);
    121 	*x += adpcm_estimindex_correct[b];
    122 	if (*x < 0)
    123 		*x = 0;
    124 	else if (*x > 48)
    125 		*x = 48;
    126 	return b;
    127 }
    128 
    129 void
    130 msm6258_ulinear8_to_adpcm(void *hdl, u_char *p, int cc)
    131 {
    132 	struct msm6258_softc *sc = hdl;
    133 	struct msm6258_codecvar *mc = sc->sc_mc;
    134 	char *x = &(mc->mc_estim);
    135 	short *y = &(mc->mc_amp);
    136 	register int i;
    137 	u_char *d = p;
    138 	u_char f;
    139 
    140 	for (i = 0; i < cc; ) {
    141 		f = pcm2adpcm_step(p[i++], y, x);
    142 		*d++ = f + (pcm2adpcm_step(p[i++], y, x) << 4);
    143 	}
    144 }
    145 
    146 void
    147 msm6258_mulaw_to_adpcm(void *hdl, u_char *p, int cc)
    148 {
    149 	mulaw_to_ulinear8(hdl, p, cc);
    150 	msm6258_ulinear8_to_adpcm(hdl, p, cc);
    151 }
    152 
    153 static inline void
    154 adpcm2pcm_step(u_char b, short *y, char *x)
    155 {
    156 	short dl;
    157 	short pcm = *y;
    158 	int estim = *x;
    159 
    160 	dl = adpcm_estim[estim] * adpcm_estimindex[b] / 8;
    161 	pcm += dl;
    162 	*y = pcm / 256;
    163 
    164 	estim += adpcm_estimindex_correct[b];
    165 	if (estim < 0)
    166 		estim = 0;
    167 	if (estim > 48)
    168 		estim = 48;
    169 	*x = estim;
    170 }
    171 
    172 /* ADPCM stream must be converted in order. */
    173 u_char tmpbuf[AU_RING_SIZE]; /* XXX */
    174 
    175 void
    176 msm6258_adpcm_to_ulinear8(void *hdl, u_char *p, int cc)
    177 {
    178 	struct msm6258_softc *sc = hdl;
    179 	struct msm6258_codecvar *mc = sc->sc_mc;
    180 	char *x = &(mc->mc_estim);
    181 	short *y = &(mc->mc_amp);
    182 	u_char a, b;
    183 	int i;
    184 
    185 	/* cc may be even. XXX alignment? */
    186 	memcpy(tmpbuf, p, cc/2);
    187 	for (i = 0; i < cc/2;) {
    188 		a = tmpbuf[i++];
    189 		b = a & 0x0f;
    190 		adpcm2pcm_step(b, y, x);
    191 		*p++ = *y;
    192 		b = a >> 4;
    193 		adpcm2pcm_step(b, y, x);
    194 		*p++ = *y;
    195 	}
    196 }
    197 
    198 void
    199 msm6258_adpcm_to_mulaw(void *hdl, u_char *p, int cc)
    200 {
    201 	msm6258_adpcm_to_ulinear8(hdl, p, cc);
    202 	ulinear8_to_mulaw(hdl, p, cc*2);
    203 }
    204