1 /* $NetBSD: linear.c,v 1.5 2024/04/20 05:38:40 isaki 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: linear.c,v 1.5 2024/04/20 05:38:40 isaki 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/linear.h>
38
39 /*
40 * audio_linear8_to_internal:
41 * This filter performs conversion from [US]LINEAR8 to internal format.
42 */
43 void
audio_linear8_to_internal(audio_filter_arg_t * arg)44 audio_linear8_to_internal(audio_filter_arg_t *arg)
45 {
46 const uint8_t *s;
47 aint_t *d;
48 uint8_t xor;
49 u_int sample_count;
50 u_int i;
51
52 DIAGNOSTIC_filter_arg(arg);
53 KASSERT(audio_format2_is_linear(arg->srcfmt));
54 KASSERT(arg->srcfmt->precision == 8);
55 KASSERT(arg->srcfmt->stride == 8);
56 KASSERT(audio_format2_is_internal(arg->dstfmt));
57 KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
58
59 s = arg->src;
60 d = arg->dst;
61 sample_count = arg->count * arg->srcfmt->channels;
62 xor = audio_format2_is_signed(arg->srcfmt) ? 0 : 0x80;
63
64 for (i = 0; i < sample_count; i++) {
65 uint8_t val;
66 val = *s++;
67 val ^= xor;
68 *d++ = (auint_t)val << (AUDIO_INTERNAL_BITS - 8);
69 }
70 }
71
72 /*
73 * audio_internal_to_linear8:
74 * This filter performs conversion from internal format to [US]LINEAR8.
75 */
76 void
audio_internal_to_linear8(audio_filter_arg_t * arg)77 audio_internal_to_linear8(audio_filter_arg_t *arg)
78 {
79 const aint_t *s;
80 uint8_t *d;
81 uint8_t xor;
82 u_int sample_count;
83 u_int i;
84
85 DIAGNOSTIC_filter_arg(arg);
86 KASSERT(audio_format2_is_linear(arg->dstfmt));
87 KASSERT(arg->dstfmt->precision == 8);
88 KASSERT(arg->dstfmt->stride == 8);
89 KASSERT(audio_format2_is_internal(arg->srcfmt));
90 KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
91
92 s = arg->src;
93 d = arg->dst;
94 sample_count = arg->count * arg->srcfmt->channels;
95 xor = audio_format2_is_signed(arg->dstfmt) ? 0 : 0x80;
96
97 for (i = 0; i < sample_count; i++) {
98 uint8_t val;
99 val = (*s++) >> (AUDIO_INTERNAL_BITS - 8);
100 val ^= xor;
101 *d++ = val;
102 }
103 }
104
105 /*
106 * audio_linear16_to_internal:
107 * This filter performs conversion from [US]LINEAR16{LE,BE} to internal
108 * format.
109 */
110 void
audio_linear16_to_internal(audio_filter_arg_t * arg)111 audio_linear16_to_internal(audio_filter_arg_t *arg)
112 {
113 const uint16_t *s;
114 aint_t *d;
115 uint16_t xor;
116 u_int sample_count;
117 u_int shift;
118 u_int i;
119 bool is_src_NE;
120
121 DIAGNOSTIC_filter_arg(arg);
122 KASSERT(audio_format2_is_linear(arg->srcfmt));
123 KASSERT(arg->srcfmt->precision == 16);
124 KASSERT(arg->srcfmt->stride == 16);
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 shift = AUDIO_INTERNAL_BITS - 16;
133 xor = audio_format2_is_signed(arg->srcfmt) ? 0 : 0x8000;
134 is_src_NE = (audio_format2_endian(arg->srcfmt) == BYTE_ORDER);
135
136 /*
137 * Since slinear16_OppositeEndian to slinear_NativeEndian is used
138 * so much especially on big endian machines, so it's expanded.
139 * Other conversions are rarely used, so they are compressed.
140 */
141 if (__predict_true(xor == 0) && is_src_NE == false) {
142 /* slinear16_OE to slinear<AI>_NE */
143 for (i = 0; i < sample_count; i++) {
144 uint16_t val;
145 val = *s++;
146 val = bswap16(val);
147 *d++ = (auint_t)val << shift;
148 }
149 } else {
150 /* slinear16_NE to slinear<AI>_NE */
151 /* ulinear16_{NE,OE} to slinear<AI>_NE */
152 for (i = 0; i < sample_count; i++) {
153 uint16_t val;
154 val = *s++;
155 if (!is_src_NE)
156 val = bswap16(val);
157 val ^= xor;
158 *d++ = (auint_t)val << shift;
159 }
160 }
161 }
162
163 /*
164 * audio_internal_to_linear16:
165 * This filter performs conversion from internal format to
166 * [US]LINEAR16{LE,BE}.
167 */
168 void
audio_internal_to_linear16(audio_filter_arg_t * arg)169 audio_internal_to_linear16(audio_filter_arg_t *arg)
170 {
171 const aint_t *s;
172 uint16_t *d;
173 uint16_t xor;
174 u_int sample_count;
175 u_int shift;
176 u_int i;
177 bool is_dst_NE;
178
179 DIAGNOSTIC_filter_arg(arg);
180 KASSERT(audio_format2_is_linear(arg->dstfmt));
181 KASSERT(arg->dstfmt->precision == 16);
182 KASSERT(arg->dstfmt->stride == 16);
183 KASSERT(audio_format2_is_internal(arg->srcfmt));
184 KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
185
186 s = arg->src;
187 d = arg->dst;
188 sample_count = arg->count * arg->srcfmt->channels;
189
190 shift = AUDIO_INTERNAL_BITS - 16;
191 xor = audio_format2_is_signed(arg->dstfmt) ? 0 : 0x8000;
192 is_dst_NE = (audio_format2_endian(arg->dstfmt) == BYTE_ORDER);
193
194 /*
195 * Since slinear_NativeEndian to slinear16_OppositeEndian is used
196 * so much especially on big endian machines, so it's expanded.
197 * Other conversions are rarely used, so they are compressed.
198 */
199 if (__predict_true(xor == 0) && is_dst_NE == false) {
200 /* slinear<AI>_NE -> slinear16_OE */
201 for (i = 0; i < sample_count; i++) {
202 uint16_t val;
203 val = (*s++) >> shift;
204 val = bswap16(val);
205 *d++ = val;
206 }
207 } else {
208 /* slinear<AI>_NE -> slinear16_NE */
209 /* slinear<AI>_NE -> ulinear16_{NE,OE} */
210 for (i = 0; i < sample_count; i++) {
211 uint16_t val;
212 val = (*s++) >> shift;
213 val ^= xor;
214 if (!is_dst_NE)
215 val = bswap16(val);
216 *d++ = val;
217 }
218 }
219 }
220
221 #if defined(AUDIO_SUPPORT_LINEAR24)
222 /*
223 * audio_linear24_to_internal:
224 * This filter performs conversion from [US]LINEAR24/24{LE,BE} to
225 * internal format. Since it's rarely used, it's size optimized.
226 */
227 void
audio_linear24_to_internal(audio_filter_arg_t * arg)228 audio_linear24_to_internal(audio_filter_arg_t *arg)
229 {
230 const uint8_t *s;
231 aint_t *d;
232 auint_t xor;
233 u_int sample_count;
234 u_int i;
235 bool is_src_LE;
236
237 DIAGNOSTIC_filter_arg(arg);
238 KASSERT(audio_format2_is_linear(arg->srcfmt));
239 KASSERT(arg->srcfmt->precision == 24);
240 KASSERT(arg->srcfmt->stride == 24);
241 KASSERT(audio_format2_is_internal(arg->dstfmt));
242 KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
243
244 s = arg->src;
245 d = arg->dst;
246 sample_count = arg->count * arg->srcfmt->channels;
247 xor = audio_format2_is_signed(arg->srcfmt)
248 ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
249 is_src_LE = (audio_format2_endian(arg->srcfmt) == LITTLE_ENDIAN);
250
251 for (i = 0; i < sample_count; i++) {
252 uint32_t val;
253 if (is_src_LE) {
254 val = s[0] | (s[1] << 8) | (s[2] << 16);
255 } else {
256 val = (s[0] << 16) | (s[1] << 8) | s[2];
257 }
258 s += 3;
259
260 #if AUDIO_INTERNAL_BITS < 24
261 val >>= 24 - AUDIO_INTERNAL_BITS;
262 #else
263 val <<= AUDIO_INTERNAL_BITS - 24;
264 #endif
265 val ^= xor;
266 *d++ = val;
267 }
268 }
269
270 /*
271 * audio_internal_to_linear24:
272 * This filter performs conversion from internal format to
273 * [US]LINEAR24/24{LE,BE}. Since it's rarely used, it's size optimized.
274 */
275 void
audio_internal_to_linear24(audio_filter_arg_t * arg)276 audio_internal_to_linear24(audio_filter_arg_t *arg)
277 {
278 const aint_t *s;
279 uint8_t *d;
280 auint_t xor;
281 u_int sample_count;
282 u_int i;
283 bool is_dst_LE;
284
285 DIAGNOSTIC_filter_arg(arg);
286 KASSERT(audio_format2_is_linear(arg->dstfmt));
287 KASSERT(arg->dstfmt->precision == 24);
288 KASSERT(arg->dstfmt->stride == 24);
289 KASSERT(audio_format2_is_internal(arg->srcfmt));
290 KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
291
292 s = arg->src;
293 d = arg->dst;
294 sample_count = arg->count * arg->srcfmt->channels;
295 xor = audio_format2_is_signed(arg->dstfmt)
296 ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
297 is_dst_LE = (audio_format2_endian(arg->dstfmt) == LITTLE_ENDIAN);
298
299 for (i = 0; i < sample_count; i++) {
300 uint32_t val;
301 val = *s++;
302 val ^= xor;
303 #if AUDIO_INTERNAL_BITS < 24
304 val <<= 24 - AUDIO_INTERNAL_BITS;
305 #else
306 val >>= AUDIO_INTERNAL_BITS - 24;
307 #endif
308 if (is_dst_LE) {
309 d[0] = val & 0xff;
310 d[1] = (val >> 8) & 0xff;
311 d[2] = (val >> 16) & 0xff;
312 } else {
313 d[0] = (val >> 16) & 0xff;
314 d[1] = (val >> 8) & 0xff;
315 d[2] = val & 0xff;
316 }
317 d += 3;
318 }
319 }
320 #endif /* AUDIO_SUPPORT_LINEAR24 */
321
322 /*
323 * audio_linear32_to_internal:
324 * This filter performs conversion from [US]LINEAR32{LE,BE} to internal
325 * format. Since it's rarely used, it's size optimized.
326 */
327 void
audio_linear32_to_internal(audio_filter_arg_t * arg)328 audio_linear32_to_internal(audio_filter_arg_t *arg)
329 {
330 const uint32_t *s;
331 aint_t *d;
332 auint_t xor;
333 u_int sample_count;
334 u_int i;
335 bool is_src_NE;
336
337 DIAGNOSTIC_filter_arg(arg);
338 KASSERT(audio_format2_is_linear(arg->srcfmt));
339 KASSERT(arg->srcfmt->precision == 32);
340 KASSERT(arg->srcfmt->stride == 32);
341 KASSERT(audio_format2_is_internal(arg->dstfmt));
342 KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
343
344 s = arg->src;
345 d = arg->dst;
346 sample_count = arg->count * arg->srcfmt->channels;
347 xor = audio_format2_is_signed(arg->srcfmt)
348 ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
349 is_src_NE = (audio_format2_endian(arg->srcfmt) == BYTE_ORDER);
350
351 for (i = 0; i < sample_count; i++) {
352 uint32_t val;
353 val = *s++;
354 if (!is_src_NE)
355 val = bswap32(val);
356 val >>= 32 - AUDIO_INTERNAL_BITS;
357 val ^= xor;
358 *d++ = val;
359 }
360 }
361
362 /*
363 * audio_internal_to_linear32:
364 * This filter performs conversion from internal format to
365 * [US]LINEAR32{LE,BE}. Since it's rarely used, it's size optimized.
366 */
367 void
audio_internal_to_linear32(audio_filter_arg_t * arg)368 audio_internal_to_linear32(audio_filter_arg_t *arg)
369 {
370 const aint_t *s;
371 uint32_t *d;
372 auint_t xor;
373 u_int sample_count;
374 u_int i;
375 bool is_dst_NE;
376
377 DIAGNOSTIC_filter_arg(arg);
378 KASSERT(audio_format2_is_linear(arg->dstfmt));
379 KASSERT(arg->dstfmt->precision == 32);
380 KASSERT(arg->dstfmt->stride == 32);
381 KASSERT(audio_format2_is_internal(arg->srcfmt));
382 KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
383
384 s = arg->src;
385 d = arg->dst;
386 sample_count = arg->count * arg->srcfmt->channels;
387 xor = audio_format2_is_signed(arg->dstfmt)
388 ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
389 is_dst_NE = (audio_format2_endian(arg->dstfmt) == BYTE_ORDER);
390
391 for (i = 0; i < sample_count; i++) {
392 uint32_t val;
393 val = *s++;
394 val ^= xor;
395 val <<= 32 - AUDIO_INTERNAL_BITS;
396 if (!is_dst_NE)
397 val = bswap32(val);
398 *d++ = val;
399 }
400 }
401