1 /* $NetBSD: msm6258.c,v 1.5 2001/11/13 13:14:42 lukem 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.5 2001/11/13 13:14:42 lukem 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/audiovar.h> 48 #include <dev/auconv.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 125, 375, 625, 875, 1125, 1375, 1625, 1875, 59 -125, -375, -625, -875, -1125, -1375, -1625, -1875 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 * 1000; 108 c /= d; 109 110 if (c < 0) { 111 b = (unsigned char)(-c/1000); 112 if (b >= 8) 113 b = 7; 114 b |= 0x08; 115 } else { 116 b = (unsigned char)(c/1000); 117 if (b >= 8) 118 b = 7; 119 } 120 121 *y += (short)(adpcm_estimindex[b] * d / 1000); 122 *x += adpcm_estimindex_correct[b]; 123 if (*x < 0) 124 *x = 0; 125 else if (*x > 48) 126 *x = 48; 127 return b; 128 } 129 130 void 131 msm6258_ulinear8_to_adpcm(void *hdl, u_char *p, int cc) 132 { 133 struct msm6258_softc *sc = hdl; 134 struct msm6258_codecvar *mc = sc->sc_mc; 135 char *x = &(mc->mc_estim); 136 short *y = &(mc->mc_amp); 137 register int i; 138 u_char f; 139 140 for (i = 0; i < cc; i++) { 141 f = pcm2adpcm_step(p[i], y, x); 142 p[i] = 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 *y += (short)(adpcm_estimindex[b] * adpcm_estim[(int) *x]); 157 *x += adpcm_estimindex_correct[b]; 158 if (*x < 0) 159 *x = 0; 160 else if (*x > 48) 161 *x = 48; 162 } 163 164 /* ADPCM stream must be converted in order. */ 165 u_char tmpbuf[AU_RING_SIZE]; /* XXX */ 166 167 void 168 msm6258_adpcm_to_ulinear8(void *hdl, u_char *p, int cc) 169 { 170 struct msm6258_softc *sc = hdl; 171 struct msm6258_codecvar *mc = sc->sc_mc; 172 char *x = &(mc->mc_estim); 173 short *y = &(mc->mc_amp); 174 u_char a, b; 175 int i; 176 177 for (i = 0; i < cc;) { 178 a = *p; 179 p++; 180 b = a & 0x0f; 181 adpcm2pcm_step(b, y, x); 182 tmpbuf[i++] = *y; 183 b = a >> 4; 184 adpcm2pcm_step(b, y, x); 185 tmpbuf[i++] = *y; 186 } 187 memcpy(p, tmpbuf, cc*2); 188 } 189 190 void 191 msm6258_adpcm_to_mulaw(void *hdl, u_char *p, int cc) 192 { 193 msm6258_adpcm_to_ulinear8(hdl, p, cc); 194 ulinear8_to_mulaw(hdl, p, cc*2); 195 } 196