Home | History | Annotate | Line # | Download | only in ic
      1 /*	$NetBSD: msm6258.c,v 1.26 2019/05/08 13:40:18 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.26 2019/05/08 13:40:18 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/audio_if.h>
     42 #include <dev/ic/msm6258var.h>
     43 
     44 static inline uint8_t	pcm2adpcm_step(struct msm6258_codecvar *, int16_t);
     45 static inline int16_t	adpcm2pcm_step(struct msm6258_codecvar *, uint8_t);
     46 
     47 static const int adpcm_estimindex[16] = {
     48 	 2,  6,  10,  14,  18,  22,  26,  30,
     49 	-2, -6, -10, -14, -18, -22, -26, -30
     50 };
     51 
     52 static const int adpcm_estim[49] = {
     53 	 16,  17,  19,  21,  23,  25,  28,  31,  34,  37,
     54 	 41,  45,  50,  55,  60,  66,  73,  80,  88,  97,
     55 	107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
     56 	279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
     57 	724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
     58 };
     59 
     60 static const int adpcm_estimstep[16] = {
     61 	-1, -1, -1, -1, 2, 4, 6, 8,
     62 	-1, -1, -1, -1, 2, 4, 6, 8
     63 };
     64 
     65 /*
     66  * signed 16bit linear PCM -> OkiADPCM
     67  */
     68 static inline uint8_t
     69 pcm2adpcm_step(struct msm6258_codecvar *mc, int16_t a)
     70 {
     71 	int estim = (int)mc->mc_estim;
     72 	int df;
     73 	short dl, c;
     74 	uint8_t b;
     75 	uint8_t s;
     76 
     77 	df = a - mc->mc_amp;
     78 	dl = adpcm_estim[estim];
     79 	c = (df / 16) * 8 / dl;
     80 	if (df < 0) {
     81 		b = (unsigned char)(-c) / 2;
     82 		s = 0x08;
     83 	} else {
     84 		b = (unsigned char)(c) / 2;
     85 		s = 0;
     86 	}
     87 	if (b > 7)
     88 		b = 7;
     89 	s |= b;
     90 	mc->mc_amp += (short)(adpcm_estimindex[(int)s] * dl);
     91 	estim += adpcm_estimstep[b];
     92 	if (estim < 0)
     93 		estim = 0;
     94 	else if (estim > 48)
     95 		estim = 48;
     96 
     97 	mc->mc_estim = estim;
     98 	return s;
     99 }
    100 
    101 void
    102 msm6258_internal_to_adpcm(audio_filter_arg_t *arg)
    103 {
    104 	struct msm6258_codecvar *mc;
    105 	const aint_t *src;
    106 	uint8_t *dst;
    107 	u_int sample_count;
    108 	u_int i;
    109 
    110 	KASSERT((arg->count & 1) == 0);
    111 
    112 	mc = arg->context;
    113 	src = arg->src;
    114 	dst = arg->dst;
    115 	sample_count = arg->count * arg->srcfmt->channels;
    116 	for (i = 0; i < sample_count / 2; i++) {
    117 		aint_t s;
    118 		uint8_t f;
    119 
    120 		s = *src++;
    121 		s >>= AUDIO_INTERNAL_BITS - 16;
    122 		f = pcm2adpcm_step(mc, s);
    123 
    124 		s = *src++;
    125 		s >>= AUDIO_INTERNAL_BITS - 16;
    126 		f |= pcm2adpcm_step(mc, s) << 4;
    127 
    128 		*dst++ = (uint8_t)f;
    129 	}
    130 }
    131 
    132 
    133 /*
    134  * OkiADPCM -> signed 16bit linear PCM
    135  */
    136 static inline int16_t
    137 adpcm2pcm_step(struct msm6258_codecvar *mc, uint8_t b)
    138 {
    139 	int estim = (int)mc->mc_estim;
    140 
    141 	mc->mc_amp += adpcm_estim[estim] * adpcm_estimindex[b];
    142 	estim += adpcm_estimstep[b];
    143 
    144 	if (estim < 0)
    145 		estim = 0;
    146 	else if (estim > 48)
    147 		estim = 48;
    148 
    149 	mc->mc_estim = estim;
    150 
    151 	return mc->mc_amp;
    152 }
    153 
    154 void
    155 msm6258_adpcm_to_internal(audio_filter_arg_t *arg)
    156 {
    157 	struct msm6258_codecvar *mc;
    158 	const uint8_t *src;
    159 	aint_t *dst;
    160 	u_int sample_count;
    161 	u_int i;
    162 
    163 	KASSERT((arg->count & 1) == 0);
    164 
    165 	mc = arg->context;
    166 	src = arg->src;
    167 	dst = arg->dst;
    168 	sample_count = arg->count * arg->srcfmt->channels;
    169 	for (i = 0; i < sample_count / 2; i++) {
    170 		uint8_t a = *src++;
    171 		aint_t s;
    172 
    173 		s = adpcm2pcm_step(mc, a & 0x0f);
    174 		s <<= AUDIO_INTERNAL_BITS - 16;
    175 		*dst++ = s;
    176 
    177 		s = adpcm2pcm_step(mc, a >> 4);
    178 		s <<= AUDIO_INTERNAL_BITS - 16;
    179 		*dst++ = s;
    180 	}
    181 }
    182