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