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