1/*	$NetBSD: mulaw.c,v 1.6 2024/02/02 22:39:10 andvar Exp $	*/
2
3/*
4 * Copyright (C) 2017 Tetsuya Isaki. All rights reserved.
5 * Copyright (C) 2017 Y.Sugahara (moveccr). All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: mulaw.c,v 1.6 2024/02/02 22:39:10 andvar Exp $");
31
32#include <sys/param.h>
33#include <sys/types.h>
34#include <sys/systm.h>
35#include <sys/device.h>
36#include <dev/audio/audiovar.h>
37#include <dev/audio/mulaw.h>
38
39/*
40 * audio_internal_to_mulaw has two implementations.
41 *
42 * 1. Use 8bit table (MULAW_LQ_ENC)
43 *  It's traditional implementation and its precision is 8bit.
44 *  It's faster but the size is larger.  And you can hear a little noise
45 *  in silent part.
46 *
47 * 2. Calculation (default)
48 *  It calculates mu-law with full spec and its precision is 14bit.
49 *  It's about 3 times slower but the size is less than a half (on m68k,
50 *  for example).
51 *
52 * mu-law is no longer a popular format.  I think size-optimized is better.
53 */
54/* #define MULAW_LQ_ENC */
55
56/*
57 * About mulaw32 format.
58 *
59 * The format which I call ``mulaw32'' is only used in dev/tc/bba.c .
60 * It is 8bit mu-law but 16bit left-shifted and its container is 32bit.
61 * Not mu-law calculated in 32bit.
62 *
63 * When MULAW32 is not defined (it's default), this file outputs
64 * audio_internal_to_mulaw() and audio_mulaw_to_internal().  When
65 * MULAW32 is defined, this file outputs audio_internal_to_mulaw32()
66 * and audio_mulaw32_to_internal() instead.
67 *
68 * Since mu-law is used as userland format and is mandatory, all audio
69 * drivers (including tc/bba) link this mulaw.c in ordinary procedure.
70 * On the other hand, only tc/bba also needs audio_internal_to_mulaw32()
71 * and audio_mulaw32_to_internal() as its hardware drivers codec, so
72 * define MULAW32 and include this file.  It's a bit tricky but I think
73 * this is the simplest way.
74 */
75
76#if 0
77#define MPRINTF(fmt, ...)	printf(fmt, ## __VA_ARGS__)
78#else
79#define MPRINTF(fmt, ...)	/**/
80#endif
81
82static const int16_t mulaw_to_slinear16[256] = {
83	0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
84	0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
85	0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
86	0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
87	0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
88	0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
89	0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
90	0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
91	0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
92	0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
93	0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
94	0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
95	0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
96	0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
97	0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
98	0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0xfffc,
99	0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
100	0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
101	0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
102	0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
103	0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
104	0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
105	0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
106	0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
107	0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
108	0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
109	0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
110	0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
111	0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
112	0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
113	0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
114	0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000,
115};
116
117#if defined(MULAW_LQ_ENC)
118static const uint8_t slinear8_to_mulaw[256] = {
119	0xff, 0xe7, 0xdb, 0xd3, 0xcd, 0xc9, 0xc5, 0xc1,
120	0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0,
121	0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8,
122	0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
123	0x9f, 0x9f, 0x9e, 0x9e, 0x9d, 0x9d, 0x9c, 0x9c,
124	0x9b, 0x9b, 0x9a, 0x9a, 0x99, 0x99, 0x98, 0x98,
125	0x97, 0x97, 0x96, 0x96, 0x95, 0x95, 0x94, 0x94,
126	0x93, 0x93, 0x92, 0x92, 0x91, 0x91, 0x90, 0x90,
127	0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e,
128	0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c,
129	0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a,
130	0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88,
131	0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86,
132	0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84,
133	0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82,
134	0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80,
135	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
136	0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
137	0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05,
138	0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07,
139	0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09,
140	0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b,
141	0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d,
142	0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f,
143	0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13,
144	0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x17,
145	0x17, 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b,
146	0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f,
147	0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
148	0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
149	0x2f, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c,
150	0x3e, 0x41, 0x45, 0x49, 0x4d, 0x53, 0x5b, 0x67,
151};
152#endif
153
154/*
155 * audio_mulaw_to_internal:
156 *	This filter performs conversion from mu-law to internal format.
157 *
158 * audio_mulaw32_to_internal:
159 *	This filter performs conversion from mulaw32 used only in tc/bba.c
160 *	to internal format.
161 */
162void
163#if !defined(MULAW32)
164audio_mulaw_to_internal(audio_filter_arg_t *arg)
165#else
166audio_mulaw32_to_internal(audio_filter_arg_t *arg)
167#endif
168{
169#if defined(MULAW32)
170	const uint32_t *s;
171#else
172	const uint8_t *s;
173#endif
174	aint_t *d;
175	u_int sample_count;
176	u_int i;
177
178	DIAGNOSTIC_filter_arg(arg);
179#if !defined(MULAW32)
180	KASSERT(arg->srcfmt->encoding == AUDIO_ENCODING_ULAW);
181	KASSERT(arg->srcfmt->stride == 8);
182	KASSERT(arg->srcfmt->precision == 8);
183#endif
184	KASSERT(audio_format2_is_internal(arg->dstfmt));
185	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
186
187	s = arg->src;
188	d = arg->dst;
189	sample_count = arg->count * arg->srcfmt->channels;
190
191	for (i = 0; i < sample_count; i++) {
192		aint_t val;
193		uint m;
194		m = *s++;
195#if defined(MULAW32)
196		/* 32bit container used only in tc/bba.c */
197		m = (m >> 16) & 0xff;
198#endif
199		val = mulaw_to_slinear16[m];
200		val <<= AUDIO_INTERNAL_BITS - 16;
201		*d++ = val;
202	}
203}
204
205/*
206 * audio_internal_to_mulaw:
207 *	This filter performs conversion from internal format to mu-law.
208 *
209 * audio_internal_to_mulaw32:
210 *	This filter performs conversion from internal format to mulaw32
211 *	used only in tc/bba.c.
212 */
213void
214#if !defined(MULAW32)
215audio_internal_to_mulaw(audio_filter_arg_t *arg)
216#else
217audio_internal_to_mulaw32(audio_filter_arg_t *arg)
218#endif
219{
220	const aint_t *s;
221#if defined(MULAW32)
222	uint32_t *d;
223#else
224	uint8_t *d;
225#endif
226	u_int sample_count;
227	u_int i;
228
229	DIAGNOSTIC_filter_arg(arg);
230#if !defined(MULAW32)
231	KASSERT(arg->dstfmt->encoding == AUDIO_ENCODING_ULAW);
232	KASSERT(arg->dstfmt->stride == 8);
233	KASSERT(arg->dstfmt->precision == 8);
234#endif
235	KASSERT(audio_format2_is_internal(arg->srcfmt));
236	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
237
238	s = arg->src;
239	d = arg->dst;
240	sample_count = arg->count * arg->srcfmt->channels;
241
242	for (i = 0; i < sample_count; i++) {
243		uint8_t m;
244#if defined(MULAW_LQ_ENC)
245		/* 8bit (low quality, fast but fat) encoder */
246		uint8_t val;
247		val = (*s++) >> (AUDIO_INTERNAL_BITS - 8);
248		m = slinear8_to_mulaw[val];
249#else
250		/* 14bit (fullspec, slow but small) encoder */
251		uint16_t val;
252		int c;
253
254		val = *s++ >> (AUDIO_INTERNAL_BITS - 16);
255		if ((int16_t)val < 0) {
256			m = 0;
257		} else {
258			val = ~val;
259			m = 0x80;
260		}
261		/* limit */
262		if ((int16_t)val < -8158 * 4)
263			val = -8158 * 4;
264		val -= 33 * 4;	/* bias */
265
266		// Before(1)         Before(2)         Before(3)
267		// S0MMMMxx_xxxxxxxx 0MMMMxxx_xxxxxxx0 c=0,v=0MMMMxxx_xxxxxxx0
268		// S10MMMMx_xxxxxxxx 10MMMMxx_xxxxxxx0 c=1,v=0MMMMxxx_xxxxxx00
269		// S110MMMM_xxxxxxxx 110MMMMx_xxxxxxx0 c=2,v=0MMMMxxx_xxxxx000
270		// :                 :                 :
271		// S1111110_MMMMxxxx 1111110M_MMMxxxx0 c=6,v=0MMMMxxx_x0000000
272
273		// (1) Push out sign bit
274		val <<= 1;
275
276		// (2) Find first zero (and align val to left)
277		c = 0;
278		if (val >= 0xf000) c += 4, val <<= 4;
279		if (val >= 0xc000) c += 2, val <<= 2;
280		if (val >= 0x8000) c += 1, val <<= 1;
281
282		// (3)
283		m += (c << 4);
284		m += (val >> 11) & 0x0f;
285#endif
286
287#if defined(MULAW32)
288		/* 8bit mu-law in 32bit container used only in tc/bba.c */
289		*d++ = m << 16;
290#else
291		*d++ = m;
292#endif
293	}
294}
295