xref: /netbsd-src/sys/dev/audio/alaw.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: alaw.c,v 1.3 2020/01/11 04:06:13 isaki Exp $	*/
2 
3 /*
4  * Copyright (C) 2018 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 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: alaw.c,v 1.3 2020/01/11 04:06:13 isaki Exp $");
30 
31 #include <sys/types.h>
32 #include <sys/systm.h>
33 #include <sys/device.h>
34 #include <dev/audio/audiovar.h>
35 #include <dev/audio/mulaw.h>
36 
37 static const uint16_t alaw_to_slinear16[256] = {
38 	0xea80, 0xeb80, 0xe880, 0xe980, 0xee80, 0xef80, 0xec80, 0xed80,
39 	0xe280, 0xe380, 0xe080, 0xe180, 0xe680, 0xe780, 0xe480, 0xe580,
40 	0xf540, 0xf5c0, 0xf440, 0xf4c0, 0xf740, 0xf7c0, 0xf640, 0xf6c0,
41 	0xf140, 0xf1c0, 0xf040, 0xf0c0, 0xf340, 0xf3c0, 0xf240, 0xf2c0,
42 	0xaa00, 0xae00, 0xa200, 0xa600, 0xba00, 0xbe00, 0xb200, 0xb600,
43 	0x8a00, 0x8e00, 0x8200, 0x8600, 0x9a00, 0x9e00, 0x9200, 0x9600,
44 	0xd500, 0xd700, 0xd100, 0xd300, 0xdd00, 0xdf00, 0xd900, 0xdb00,
45 	0xc500, 0xc700, 0xc100, 0xc300, 0xcd00, 0xcf00, 0xc900, 0xcb00,
46 	0xfea8, 0xfeb8, 0xfe88, 0xfe98, 0xfee8, 0xfef8, 0xfec8, 0xfed8,
47 	0xfe28, 0xfe38, 0xfe08, 0xfe18, 0xfe68, 0xfe78, 0xfe48, 0xfe58,
48 	0xffa8, 0xffb8, 0xff88, 0xff98, 0xffe8, 0xfff8, 0xffc8, 0xffd8,
49 	0xff28, 0xff38, 0xff08, 0xff18, 0xff68, 0xff78, 0xff48, 0xff58,
50 	0xfaa0, 0xfae0, 0xfa20, 0xfa60, 0xfba0, 0xfbe0, 0xfb20, 0xfb60,
51 	0xf8a0, 0xf8e0, 0xf820, 0xf860, 0xf9a0, 0xf9e0, 0xf920, 0xf960,
52 	0xfd50, 0xfd70, 0xfd10, 0xfd30, 0xfdd0, 0xfdf0, 0xfd90, 0xfdb0,
53 	0xfc50, 0xfc70, 0xfc10, 0xfc30, 0xfcd0, 0xfcf0, 0xfc90, 0xfcb0,
54 	0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280,
55 	0x1d80, 0x1c80, 0x1f80, 0x1e80, 0x1980, 0x1880, 0x1b80, 0x1a80,
56 	0x0ac0, 0x0a40, 0x0bc0, 0x0b40, 0x08c0, 0x0840, 0x09c0, 0x0940,
57 	0x0ec0, 0x0e40, 0x0fc0, 0x0f40, 0x0cc0, 0x0c40, 0x0dc0, 0x0d40,
58 	0x5600, 0x5200, 0x5e00, 0x5a00, 0x4600, 0x4200, 0x4e00, 0x4a00,
59 	0x7600, 0x7200, 0x7e00, 0x7a00, 0x6600, 0x6200, 0x6e00, 0x6a00,
60 	0x2b00, 0x2900, 0x2f00, 0x2d00, 0x2300, 0x2100, 0x2700, 0x2500,
61 	0x3b00, 0x3900, 0x3f00, 0x3d00, 0x3300, 0x3100, 0x3700, 0x3500,
62 	0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128,
63 	0x01d8, 0x01c8, 0x01f8, 0x01e8, 0x0198, 0x0188, 0x01b8, 0x01a8,
64 	0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028,
65 	0x00d8, 0x00c8, 0x00f8, 0x00e8, 0x0098, 0x0088, 0x00b8, 0x00a8,
66 	0x0560, 0x0520, 0x05e0, 0x05a0, 0x0460, 0x0420, 0x04e0, 0x04a0,
67 	0x0760, 0x0720, 0x07e0, 0x07a0, 0x0660, 0x0620, 0x06e0, 0x06a0,
68 	0x02b0, 0x0290, 0x02f0, 0x02d0, 0x0230, 0x0210, 0x0270, 0x0250,
69 	0x03b0, 0x0390, 0x03f0, 0x03d0, 0x0330, 0x0310, 0x0370, 0x0350,
70 };
71 
72 static const uint8_t slinear8_to_alaw[256] = {
73 	0xd5, 0xc5, 0xf5, 0xfd, 0xe5, 0xe1, 0xed, 0xe9,
74 	0x95, 0x97, 0x91, 0x93, 0x9d, 0x9f, 0x99, 0x9b,
75 	0x85, 0x84, 0x87, 0x86, 0x81, 0x80, 0x83, 0x82,
76 	0x8d, 0x8c, 0x8f, 0x8e, 0x89, 0x88, 0x8b, 0x8a,
77 	0xb5, 0xb5, 0xb4, 0xb4, 0xb7, 0xb7, 0xb6, 0xb6,
78 	0xb1, 0xb1, 0xb0, 0xb0, 0xb3, 0xb3, 0xb2, 0xb2,
79 	0xbd, 0xbd, 0xbc, 0xbc, 0xbf, 0xbf, 0xbe, 0xbe,
80 	0xb9, 0xb9, 0xb8, 0xb8, 0xbb, 0xbb, 0xba, 0xba,
81 	0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4,
82 	0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6,
83 	0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0,
84 	0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2,
85 	0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac,
86 	0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae,
87 	0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8,
88 	0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa,
89 	0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b,
90 	0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29,
91 	0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f,
92 	0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d,
93 	0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23,
94 	0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21,
95 	0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27,
96 	0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25,
97 	0x3a, 0x3a, 0x3b, 0x3b, 0x38, 0x38, 0x39, 0x39,
98 	0x3e, 0x3e, 0x3f, 0x3f, 0x3c, 0x3c, 0x3d, 0x3d,
99 	0x32, 0x32, 0x33, 0x33, 0x30, 0x30, 0x31, 0x31,
100 	0x36, 0x36, 0x37, 0x37, 0x34, 0x34, 0x35, 0x35,
101 	0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
102 	0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
103 	0x1a, 0x18, 0x1e, 0x1c, 0x12, 0x10, 0x16, 0x14,
104 	0x6a, 0x6e, 0x62, 0x66, 0x7a, 0x72, 0x4a, 0x5a,
105 };
106 
107 /*
108  * audio_alaw_to_internal:
109  *	This filter performs conversion from A-law to internal format.
110  */
111 void
112 audio_alaw_to_internal(audio_filter_arg_t *arg)
113 {
114 	const uint8_t *s;
115 	aint_t *d;
116 	u_int sample_count;
117 	u_int i;
118 
119 	DIAGNOSTIC_filter_arg(arg);
120 	KASSERT(arg->srcfmt->encoding == AUDIO_ENCODING_ALAW);
121 	KASSERT(arg->srcfmt->stride == 8);
122 	KASSERT(arg->srcfmt->precision == 8);
123 	KASSERT(audio_format2_is_internal(arg->dstfmt));
124 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
125 
126 	s = arg->src;
127 	d = arg->dst;
128 	sample_count = arg->count * arg->srcfmt->channels;
129 
130 	for (i = 0; i < sample_count; i++) {
131 		aint_t val;
132 		val = alaw_to_slinear16[*s++];
133 		val <<= AUDIO_INTERNAL_BITS - 16;
134 		*d++ = val;
135 	}
136 }
137 
138 /*
139  * audio_internal_to_alaw:
140  *	This filter performs conversion from internal format to A-law.
141  */
142 void
143 audio_internal_to_alaw(audio_filter_arg_t *arg)
144 {
145 	const aint_t *s;
146 	uint8_t *d;
147 	u_int sample_count;
148 	u_int i;
149 
150 	DIAGNOSTIC_filter_arg(arg);
151 	KASSERT(arg->dstfmt->encoding == AUDIO_ENCODING_ALAW);
152 	KASSERT(arg->dstfmt->stride == 8);
153 	KASSERT(arg->dstfmt->precision == 8);
154 	KASSERT(audio_format2_is_internal(arg->srcfmt));
155 	KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
156 
157 	s = arg->src;
158 	d = arg->dst;
159 	sample_count = arg->count * arg->srcfmt->channels;
160 
161 	for (i = 0; i < sample_count; i++) {
162 		uint8_t val;
163 		val = (*s++) >> (AUDIO_INTERNAL_BITS - 8);
164 		*d++ = slinear8_to_alaw[val];
165 	}
166 }
167