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