Home | History | Annotate | Line # | Download | only in ic
msm6258.c revision 1.3
      1 /*	$NetBSD: msm6258.c,v 1.3 2001/05/03 02:09:11 minoura 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/systm.h>
     38 #include <sys/device.h>
     39 #include <sys/malloc.h>
     40 #include <sys/select.h>
     41 #include <sys/audioio.h>
     42 
     43 #include <dev/audio_if.h>
     44 #include <dev/audiovar.h>
     45 #include <dev/auconv.h>
     46 #include <dev/ic/msm6258var.h>
     47 
     48 
     49 static inline u_char pcm2adpcm_step(short, short *, char *);
     50 static inline void adpcm2pcm_step(u_char, short *, char *);
     51 
     52 
     53 static int adpcm_estimindex[16] = {
     54 	 125,  375,  625,  875,  1125,  1375,  1625,  1875,
     55 	-125, -375, -625, -875, -1125, -1375, -1625, -1875
     56 };
     57 
     58 static int adpcm_estim[49] = {
     59 	 16,  17,  19,  21,  23,  25,  28,  31,  34,  37,
     60 	 41,  45,  50,  55,  60,  66,  73,  80,  88,  97,
     61 	107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
     62 	279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
     63 	724, 796, 875, 963, 1060, 1166, 1282, 1411, 1552
     64 };
     65 
     66 static u_char adpcm_estimindex_correct[16] = {
     67 	-1, -1, -1, -1, 2, 4, 6, 8,
     68 	-1, -1, -1, -1, 2, 4, 6, 8
     69 };
     70 
     71 struct msm6258_codecvar {
     72 	short	mc_amp;
     73 	char	mc_estim;
     74 };
     75 
     76 struct msm6258_softc {
     77 	struct device sc_dev;
     78 	struct msm6258_codecvar *sc_mc;
     79 	/* MD vars follow */
     80 };
     81 
     82 void *
     83 msm6258_codec_init (void)
     84 {
     85 	struct msm6258_codecvar *r;
     86 
     87 	r = malloc (sizeof(*r), M_DEVBUF, M_NOWAIT);
     88 	if (r == 0)
     89 		return 0;
     90 	r->mc_amp = r->mc_estim = 0;
     91 
     92 	return r;
     93 }
     94 
     95 static inline u_char
     96 pcm2adpcm_step(short a, short *y, char *x)
     97 {
     98 	int c, d;
     99 	register unsigned char b;
    100 
    101 	a -= *y;
    102 	d = adpcm_estim[*x];
    103 	c = a * 4 * 1000;
    104 	c /= d;
    105 
    106 	if (c < 0) {
    107 		b = (unsigned char)(-c/1000);
    108 		if (b >= 8)
    109 			b = 7;
    110 		b |= 0x08;
    111 	} else {
    112 		b = (unsigned char)(c/1000);
    113 		if (b >= 8)
    114 			b = 7;
    115 	}
    116 
    117 	*y += (short)(adpcm_estimindex[b] * d / 1000);
    118 	*x += adpcm_estimindex_correct[b];
    119 	if (*x < 0)
    120 		*x = 0;
    121 	else if (*x > 48)
    122 		*x = 48;
    123 	return b;
    124 }
    125 
    126 void
    127 msm6258_ulinear8_to_adpcm(void *hdl, u_char *p, int cc)
    128 {
    129 	struct msm6258_softc *sc = hdl;
    130 	struct msm6258_codecvar *mc = sc->sc_mc;
    131 	char *x = &(mc->mc_estim);
    132 	short *y = &(mc->mc_amp);
    133 	register int i;
    134 	u_char f;
    135 
    136 	for (i = 0; i < cc; i++) {
    137 		f = pcm2adpcm_step(p[i], y, x);
    138 		p[i] = f + (pcm2adpcm_step(p[i], y, x) << 4);
    139 	}
    140 }
    141 
    142 void
    143 msm6258_mulaw_to_adpcm(void *hdl, u_char *p, int cc)
    144 {
    145 	mulaw_to_ulinear8(hdl, p, cc);
    146 	msm6258_ulinear8_to_adpcm(hdl, p, cc);
    147 }
    148 
    149 static inline void
    150 adpcm2pcm_step(u_char b, short *y, char *x)
    151 {
    152 	*y += (short)(adpcm_estimindex[b] * adpcm_estim[*x]);
    153 	*x += adpcm_estimindex_correct[b];
    154 	if (*x < 0)
    155 		*x = 0;
    156 	else if (*x > 48)
    157 		*x = 48;
    158 }
    159 
    160 /* ADPCM stream must be converted in order. */
    161 u_char tmpbuf[AU_RING_SIZE]; /* XXX */
    162 
    163 void
    164 msm6258_adpcm_to_ulinear8(void *hdl, u_char *p, int cc)
    165 {
    166 	struct msm6258_softc *sc = hdl;
    167 	struct msm6258_codecvar *mc = sc->sc_mc;
    168 	char *x = &(mc->mc_estim);
    169 	short *y = &(mc->mc_amp);
    170 	u_char a, b;
    171 	int i;
    172 
    173 	for (i = 0; i < cc;) {
    174 		a = *p;
    175 		p++;
    176 		b = a & 0x0f;
    177 		adpcm2pcm_step(b, y, x);
    178 		tmpbuf[i++] = *y;
    179 		b = a >> 4;
    180 		adpcm2pcm_step(b, y, x);
    181 		tmpbuf[i++] = *y;
    182 	}
    183 	memcpy(p, tmpbuf, cc*2);
    184 }
    185 
    186 void
    187 msm6258_adpcm_to_mulaw(void *hdl, u_char *p, int cc)
    188 {
    189 	msm6258_adpcm_to_ulinear8(hdl, p, cc);
    190 	ulinear8_to_mulaw(hdl, p, cc*2);
    191 }
    192