xref: /netbsd-src/sys/dev/ic/msm6258.c (revision e622eac459adf11c2e710d7a4de0f05510bbbe61)
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
pcm2adpcm_step(struct msm6258_codecvar * mc,int16_t a)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
msm6258_internal_to_adpcm(audio_filter_arg_t * arg)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
adpcm2pcm_step(struct msm6258_codecvar * mc,uint8_t b)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
msm6258_adpcm_to_internal(audio_filter_arg_t * arg)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