Home | History | Annotate | Line # | Download | only in ic
msm6258.c revision 1.25.2.1
      1 /*	$NetBSD: msm6258.c,v 1.25.2.1 2019/04/21 14:00:19 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  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * OKI MSM6258 ADPCM voice synthesizer codec.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.25.2.1 2019/04/21 14:00:19 isaki Exp $");
     34 
     35 #include <sys/systm.h>
     36 #include <sys/device.h>
     37 #include <sys/kmem.h>
     38 #include <sys/select.h>
     39 #include <sys/audioio.h>
     40 
     41 #include <dev/audio_if.h>
     42 #include <dev/audiovar.h>
     43 #include <dev/ic/msm6258var.h>
     44 
     45 static inline uint8_t	pcm2adpcm_step(struct msm6258_codecvar *, int16_t);
     46 static inline int16_t	adpcm2pcm_step(struct msm6258_codecvar *, uint8_t);
     47 
     48 static const int adpcm_estimindex[16] = {
     49 	 2,  6,  10,  14,  18,  22,  26,  30,
     50 	-2, -6, -10, -14, -18, -22, -26, -30
     51 };
     52 
     53 static const int adpcm_estim[49] = {
     54 	 16,  17,  19,  21,  23,  25,  28,  31,  34,  37,
     55 	 41,  45,  50,  55,  60,  66,  73,  80,  88,  97,
     56 	107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
     57 	279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
     58 	724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
     59 };
     60 
     61 static const int adpcm_estimstep[16] = {
     62 	-1, -1, -1, -1, 2, 4, 6, 8,
     63 	-1, -1, -1, -1, 2, 4, 6, 8
     64 };
     65 
     66 /*
     67  * signed 16bit linear PCM -> OkiADPCM
     68  */
     69 static inline uint8_t
     70 pcm2adpcm_step(struct msm6258_codecvar *mc, int16_t a)
     71 {
     72 	int estim = (int)mc->mc_estim;
     73 	int df;
     74 	short dl, c;
     75 	uint8_t b;
     76 	uint8_t s;
     77 
     78 	df = a - mc->mc_amp;
     79 	dl = adpcm_estim[estim];
     80 	c = (df / 16) * 8 / dl;
     81 	if (df < 0) {
     82 		b = (unsigned char)(-c) / 2;
     83 		s = 0x08;
     84 	} else {
     85 		b = (unsigned char)(c) / 2;
     86 		s = 0;
     87 	}
     88 	if (b > 7)
     89 		b = 7;
     90 	s |= b;
     91 	mc->mc_amp += (short)(adpcm_estimindex[(int)s] * dl);
     92 	estim += adpcm_estimstep[b];
     93 	if (estim < 0)
     94 		estim = 0;
     95 	else if (estim > 48)
     96 		estim = 48;
     97 
     98 	mc->mc_estim = estim;
     99 	return s;
    100 }
    101 
    102 void
    103 msm6258_internal_to_adpcm(audio_filter_arg_t *arg)
    104 {
    105 	struct msm6258_codecvar *mc;
    106 	const aint_t *src;
    107 	uint8_t *dst;
    108 	u_int sample_count;
    109 	u_int i;
    110 
    111 	KASSERT((arg->count & 1) == 0);
    112 
    113 	mc = arg->context;
    114 	src = arg->src;
    115 	dst = arg->dst;
    116 	sample_count = arg->count * arg->srcfmt->channels;
    117 	for (i = 0; i < sample_count / 2; i++) {
    118 		aint_t s;
    119 		uint8_t f;
    120 
    121 		s = *src++;
    122 		s >>= AUDIO_INTERNAL_BITS - 16;
    123 		f = pcm2adpcm_step(mc, s);
    124 
    125 		s = *src++;
    126 		s >>= AUDIO_INTERNAL_BITS - 16;
    127 		f |= pcm2adpcm_step(mc, s) << 4;
    128 
    129 		*dst++ = (uint8_t)f;
    130 	}
    131 }
    132 
    133 
    134 /*
    135  * OkiADPCM -> signed 16bit linear PCM
    136  */
    137 static inline int16_t
    138 adpcm2pcm_step(struct msm6258_codecvar *mc, uint8_t b)
    139 {
    140 	int estim = (int)mc->mc_estim;
    141 
    142 	mc->mc_amp += adpcm_estim[estim] * adpcm_estimindex[b];
    143 	estim += adpcm_estimstep[b];
    144 
    145 	if (estim < 0)
    146 		estim = 0;
    147 	else if (estim > 48)
    148 		estim = 48;
    149 
    150 	mc->mc_estim = estim;
    151 
    152 	return mc->mc_amp;
    153 }
    154 
    155 void
    156 msm6258_adpcm_to_internal(audio_filter_arg_t *arg)
    157 {
    158 	struct msm6258_codecvar *mc;
    159 	const uint8_t *src;
    160 	aint_t *dst;
    161 	u_int sample_count;
    162 	u_int i;
    163 
    164 	KASSERT((arg->count & 1) == 0);
    165 
    166 	mc = arg->context;
    167 	src = arg->src;
    168 	dst = arg->dst;
    169 	sample_count = arg->count * arg->srcfmt->channels;
    170 	for (i = 0; i < sample_count / 2; i++) {
    171 		uint8_t a = *src++;
    172 		aint_t s;
    173 
    174 		s = adpcm2pcm_step(mc, a & 0x0f);
    175 		s <<= AUDIO_INTERNAL_BITS - 16;
    176 		*dst++ = s;
    177 
    178 		s = adpcm2pcm_step(mc, a >> 4);
    179 		s <<= AUDIO_INTERNAL_BITS - 16;
    180 		*dst++ = s;
    181 	}
    182 }
    183