1*007c1f91Sskrll /* $NetBSD: linear.c,v 1.4 2021/07/21 06:35:44 skrll Exp $ */
2b950503fSisaki
3b950503fSisaki /*
4b950503fSisaki * Copyright (C) 2017 Tetsuya Isaki. All rights reserved.
5b950503fSisaki * Copyright (C) 2017 Y.Sugahara (moveccr). All rights reserved.
6b950503fSisaki *
7b950503fSisaki * Redistribution and use in source and binary forms, with or without
8b950503fSisaki * modification, are permitted provided that the following conditions
9b950503fSisaki * are met:
10b950503fSisaki * 1. Redistributions of source code must retain the above copyright
11b950503fSisaki * notice, this list of conditions and the following disclaimer.
12b950503fSisaki * 2. Redistributions in binary form must reproduce the above copyright
13b950503fSisaki * notice, this list of conditions and the following disclaimer in the
14b950503fSisaki * documentation and/or other materials provided with the distribution.
15b950503fSisaki *
16b950503fSisaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17b950503fSisaki * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18b950503fSisaki * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19b950503fSisaki * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20b950503fSisaki * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21b950503fSisaki * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22b950503fSisaki * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23b950503fSisaki * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24b950503fSisaki * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25b950503fSisaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26b950503fSisaki * SUCH DAMAGE.
27b950503fSisaki */
28b950503fSisaki
29b950503fSisaki #include <sys/cdefs.h>
30*007c1f91Sskrll __KERNEL_RCSID(0, "$NetBSD: linear.c,v 1.4 2021/07/21 06:35:44 skrll Exp $");
31b950503fSisaki
32*007c1f91Sskrll #include <sys/param.h>
33b950503fSisaki #include <sys/types.h>
34b950503fSisaki #include <sys/systm.h>
35b950503fSisaki #include <sys/device.h>
36b950503fSisaki #include <dev/audio/audiovar.h>
37b950503fSisaki #include <dev/audio/linear.h>
38b950503fSisaki
39b950503fSisaki /*
40b950503fSisaki * audio_linear8_to_internal:
41b950503fSisaki * This filter performs conversion from [US]LINEAR8 to internal format.
42b950503fSisaki */
43b950503fSisaki void
audio_linear8_to_internal(audio_filter_arg_t * arg)44b950503fSisaki audio_linear8_to_internal(audio_filter_arg_t *arg)
45b950503fSisaki {
46b950503fSisaki const uint8_t *s;
47b950503fSisaki aint_t *d;
48b950503fSisaki uint8_t xor;
49b950503fSisaki u_int sample_count;
50b950503fSisaki u_int i;
51b950503fSisaki
52b950503fSisaki DIAGNOSTIC_filter_arg(arg);
53b950503fSisaki KASSERT(audio_format2_is_linear(arg->srcfmt));
54b950503fSisaki KASSERT(arg->srcfmt->precision == 8);
55b950503fSisaki KASSERT(arg->srcfmt->stride == 8);
56b950503fSisaki KASSERT(audio_format2_is_internal(arg->dstfmt));
57b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
58b950503fSisaki
59b950503fSisaki s = arg->src;
60b950503fSisaki d = arg->dst;
61b950503fSisaki sample_count = arg->count * arg->srcfmt->channels;
62b950503fSisaki xor = audio_format2_is_signed(arg->srcfmt) ? 0 : 0x80;
63b950503fSisaki
64b950503fSisaki for (i = 0; i < sample_count; i++) {
65b950503fSisaki uint8_t val;
66b950503fSisaki val = *s++;
67b950503fSisaki val ^= xor;
68b950503fSisaki *d++ = (auint_t)val << (AUDIO_INTERNAL_BITS - 8);
69b950503fSisaki }
70b950503fSisaki }
71b950503fSisaki
72b950503fSisaki /*
73b950503fSisaki * audio_internal_to_linear8:
74b950503fSisaki * This filter performs conversion from internal format to [US]LINEAR8.
75b950503fSisaki */
76b950503fSisaki void
audio_internal_to_linear8(audio_filter_arg_t * arg)77b950503fSisaki audio_internal_to_linear8(audio_filter_arg_t *arg)
78b950503fSisaki {
79b950503fSisaki const aint_t *s;
80b950503fSisaki uint8_t *d;
81b950503fSisaki uint8_t xor;
82b950503fSisaki u_int sample_count;
83b950503fSisaki u_int i;
84b950503fSisaki
85b950503fSisaki DIAGNOSTIC_filter_arg(arg);
86b950503fSisaki KASSERT(audio_format2_is_linear(arg->dstfmt));
87b950503fSisaki KASSERT(arg->dstfmt->precision == 8);
88b950503fSisaki KASSERT(arg->dstfmt->stride == 8);
89b950503fSisaki KASSERT(audio_format2_is_internal(arg->srcfmt));
90b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
91b950503fSisaki
92b950503fSisaki s = arg->src;
93b950503fSisaki d = arg->dst;
94b950503fSisaki sample_count = arg->count * arg->srcfmt->channels;
95b950503fSisaki xor = audio_format2_is_signed(arg->dstfmt) ? 0 : 0x80;
96b950503fSisaki
97b950503fSisaki for (i = 0; i < sample_count; i++) {
98b950503fSisaki uint8_t val;
99b950503fSisaki val = (*s++) >> (AUDIO_INTERNAL_BITS - 8);
100b950503fSisaki val ^= xor;
101b950503fSisaki *d++ = val;
102b950503fSisaki }
103b950503fSisaki }
104b950503fSisaki
105b950503fSisaki /*
106b950503fSisaki * audio_linear16_to_internal:
107b950503fSisaki * This filter performs conversion from [US]LINEAR16{LE,BE} to internal
108b950503fSisaki * format.
109b950503fSisaki */
110b950503fSisaki void
audio_linear16_to_internal(audio_filter_arg_t * arg)111b950503fSisaki audio_linear16_to_internal(audio_filter_arg_t *arg)
112b950503fSisaki {
113b950503fSisaki const uint16_t *s;
114b950503fSisaki aint_t *d;
115b950503fSisaki uint16_t xor;
116b950503fSisaki u_int sample_count;
117b950503fSisaki u_int shift;
118b950503fSisaki u_int i;
119b950503fSisaki bool is_src_NE;
120b950503fSisaki
121b950503fSisaki DIAGNOSTIC_filter_arg(arg);
122b950503fSisaki KASSERT(audio_format2_is_linear(arg->srcfmt));
123b950503fSisaki KASSERT(arg->srcfmt->precision == 16);
124b950503fSisaki KASSERT(arg->srcfmt->stride == 16);
125b950503fSisaki KASSERT(audio_format2_is_internal(arg->dstfmt));
126b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
127b950503fSisaki
128b950503fSisaki s = arg->src;
129b950503fSisaki d = arg->dst;
130b950503fSisaki sample_count = arg->count * arg->srcfmt->channels;
131b950503fSisaki
132b950503fSisaki shift = AUDIO_INTERNAL_BITS - 16;
133b950503fSisaki xor = audio_format2_is_signed(arg->srcfmt) ? 0 : 0x8000;
134b950503fSisaki is_src_NE = (audio_format2_endian(arg->srcfmt) == BYTE_ORDER);
135b950503fSisaki
136b950503fSisaki /*
137b950503fSisaki * Since slinear16_OppositeEndian to slinear_NativeEndian is used
138b950503fSisaki * so much especially on big endian machines, so it's expanded.
139b950503fSisaki * Other conversions are rarely used, so they are compressed.
140b950503fSisaki */
141b950503fSisaki if (__predict_true(xor == 0) && is_src_NE == false) {
142b950503fSisaki /* slinear16_OE to slinear<AI>_NE */
143b950503fSisaki for (i = 0; i < sample_count; i++) {
144b950503fSisaki uint16_t val;
145b950503fSisaki val = *s++;
146b950503fSisaki val = bswap16(val);
147b950503fSisaki *d++ = (auint_t)val << shift;
148b950503fSisaki }
149b950503fSisaki } else {
150b950503fSisaki /* slinear16_NE to slinear<AI>_NE */
151b950503fSisaki /* ulinear16_{NE,OE} to slinear<AI>_NE */
152b950503fSisaki for (i = 0; i < sample_count; i++) {
153b950503fSisaki uint16_t val;
154b950503fSisaki val = *s++;
155b950503fSisaki if (!is_src_NE)
156b950503fSisaki val = bswap16(val);
157b950503fSisaki val ^= xor;
158b950503fSisaki *d++ = (auint_t)val << shift;
159b950503fSisaki }
160b950503fSisaki }
161b950503fSisaki }
162b950503fSisaki
163b950503fSisaki /*
164b950503fSisaki * audio_internal_to_linear16:
165b950503fSisaki * This filter performs conversion from internal format to
166b950503fSisaki * [US]LINEAR16{LE,BE}.
167b950503fSisaki */
168b950503fSisaki void
audio_internal_to_linear16(audio_filter_arg_t * arg)169b950503fSisaki audio_internal_to_linear16(audio_filter_arg_t *arg)
170b950503fSisaki {
171b950503fSisaki const aint_t *s;
172b950503fSisaki uint16_t *d;
173b950503fSisaki uint16_t xor;
174b950503fSisaki u_int sample_count;
175b950503fSisaki u_int shift;
176b950503fSisaki u_int i;
177b950503fSisaki bool is_dst_NE;
178b950503fSisaki
179b950503fSisaki DIAGNOSTIC_filter_arg(arg);
180b950503fSisaki KASSERT(audio_format2_is_linear(arg->dstfmt));
181b950503fSisaki KASSERT(arg->dstfmt->precision == 16);
182b950503fSisaki KASSERT(arg->dstfmt->stride == 16);
183b950503fSisaki KASSERT(audio_format2_is_internal(arg->srcfmt));
184b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
185b950503fSisaki
186b950503fSisaki s = arg->src;
187b950503fSisaki d = arg->dst;
188b950503fSisaki sample_count = arg->count * arg->srcfmt->channels;
189b950503fSisaki
190b950503fSisaki shift = AUDIO_INTERNAL_BITS - 16;
191b950503fSisaki xor = audio_format2_is_signed(arg->dstfmt) ? 0 : 0x8000;
192b950503fSisaki is_dst_NE = (audio_format2_endian(arg->dstfmt) == BYTE_ORDER);
193b950503fSisaki
194b950503fSisaki /*
195b950503fSisaki * Since slinear_NativeEndian to slinear16_OppositeEndian is used
196b950503fSisaki * so much especially on big endian machines, so it's expanded.
197b950503fSisaki * Other conversions are rarely used, so they are compressed.
198b950503fSisaki */
199b950503fSisaki if (__predict_true(xor == 0) && is_dst_NE == false) {
200b950503fSisaki /* slinear<AI>_NE -> slinear16_OE */
201b950503fSisaki for (i = 0; i < sample_count; i++) {
202b950503fSisaki uint16_t val;
203b950503fSisaki val = (*s++) >> shift;
204b950503fSisaki val = bswap16(val);
205b950503fSisaki *d++ = val;
206b950503fSisaki }
207b950503fSisaki } else {
208b950503fSisaki /* slinear<AI>_NE -> slinear16_NE */
209b950503fSisaki /* slinear<AI>_NE -> ulinear16_{NE,OE} */
210b950503fSisaki for (i = 0; i < sample_count; i++) {
211b950503fSisaki uint16_t val;
212b950503fSisaki val = (*s++) >> shift;
213b950503fSisaki val ^= xor;
214b950503fSisaki if (!is_dst_NE)
215b950503fSisaki val = bswap16(val);
216b950503fSisaki *d++ = val;
217b950503fSisaki }
218b950503fSisaki }
219b950503fSisaki }
220b950503fSisaki
221b950503fSisaki #if defined(AUDIO_SUPPORT_LINEAR24)
222b950503fSisaki /*
223b950503fSisaki * audio_linear24_to_internal:
224b950503fSisaki * This filter performs conversion from [US]LINEAR24/24{LE,BE} to
225b950503fSisaki * internal format. Since it's rerely used, it's size optimized.
226b950503fSisaki */
227b950503fSisaki void
audio_linear24_to_internal(audio_filter_arg_t * arg)228b950503fSisaki audio_linear24_to_internal(audio_filter_arg_t *arg)
229b950503fSisaki {
230b950503fSisaki const uint8_t *s;
231b950503fSisaki aint_t *d;
232b950503fSisaki auint_t xor;
233b950503fSisaki u_int sample_count;
234b950503fSisaki u_int i;
235b950503fSisaki bool is_src_LE;
236b950503fSisaki
237b950503fSisaki DIAGNOSTIC_filter_arg(arg);
238b950503fSisaki KASSERT(audio_format2_is_linear(arg->srcfmt));
239b950503fSisaki KASSERT(arg->srcfmt->precision == 24);
240b950503fSisaki KASSERT(arg->srcfmt->stride == 24);
241b950503fSisaki KASSERT(audio_format2_is_internal(arg->dstfmt));
242b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
243b950503fSisaki
244b950503fSisaki s = arg->src;
245b950503fSisaki d = arg->dst;
246b950503fSisaki sample_count = arg->count * arg->srcfmt->channels;
247b950503fSisaki xor = audio_format2_is_signed(arg->srcfmt)
248b950503fSisaki ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
249b950503fSisaki is_src_LE = (audio_format2_endian(arg->srcfmt) == LITTLE_ENDIAN);
250b950503fSisaki
251b950503fSisaki for (i = 0; i < sample_count; i++) {
252b950503fSisaki uint32_t val;
253b950503fSisaki if (is_src_LE) {
254b950503fSisaki val = s[0] | (s[1] << 8) | (s[2] << 16);
255b950503fSisaki } else {
256b950503fSisaki val = (s[0] << 16) | (s[1] << 8) | s[2];
257b950503fSisaki }
258b950503fSisaki s += 3;
259b950503fSisaki
260b950503fSisaki #if AUDIO_INTERNAL_BITS < 24
261b950503fSisaki val >>= 24 - AUDIO_INTERNAL_BITS;
262b950503fSisaki #else
263b950503fSisaki val <<= AUDIO_INTERNAL_BITS - 24;
264b950503fSisaki #endif
265b950503fSisaki val ^= xor;
266b950503fSisaki *d++ = val;
267b950503fSisaki }
268b950503fSisaki }
269b950503fSisaki
270b950503fSisaki /*
271b950503fSisaki * audio_internal_to_linear24:
272b950503fSisaki * This filter performs conversion from internal format to
273b950503fSisaki * [US]LINEAR24/24{LE,BE}. Since it's rarely used, it's size optimized.
274b950503fSisaki */
275b950503fSisaki void
audio_internal_to_linear24(audio_filter_arg_t * arg)276b950503fSisaki audio_internal_to_linear24(audio_filter_arg_t *arg)
277b950503fSisaki {
278b950503fSisaki const aint_t *s;
279b950503fSisaki uint8_t *d;
280b950503fSisaki auint_t xor;
281b950503fSisaki u_int sample_count;
282b950503fSisaki u_int i;
283b950503fSisaki bool is_dst_LE;
284b950503fSisaki
285b950503fSisaki DIAGNOSTIC_filter_arg(arg);
286b950503fSisaki KASSERT(audio_format2_is_linear(arg->dstfmt));
287b950503fSisaki KASSERT(arg->dstfmt->precision == 24);
288b950503fSisaki KASSERT(arg->dstfmt->stride == 24);
289b950503fSisaki KASSERT(audio_format2_is_internal(arg->srcfmt));
290b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
291b950503fSisaki
292b950503fSisaki s = arg->src;
293b950503fSisaki d = arg->dst;
294b950503fSisaki sample_count = arg->count * arg->srcfmt->channels;
295b950503fSisaki xor = audio_format2_is_signed(arg->dstfmt)
296b950503fSisaki ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
297b950503fSisaki is_dst_LE = (audio_format2_endian(arg->dstfmt) == LITTLE_ENDIAN);
298b950503fSisaki
299b950503fSisaki for (i = 0; i < sample_count; i++) {
300b950503fSisaki uint32_t val;
301b950503fSisaki val = *s++;
302b950503fSisaki val ^= xor;
303b950503fSisaki #if AUDIO_INTERNAL_BITS < 24
304b950503fSisaki val <<= 24 - AUDIO_INTERNAL_BITS;
305b950503fSisaki #else
306b950503fSisaki val >>= AUDIO_INTERNAL_BITS - 24;
307b950503fSisaki #endif
308b950503fSisaki if (is_dst_LE) {
309b950503fSisaki d[0] = val & 0xff;
310b950503fSisaki d[1] = (val >> 8) & 0xff;
311b950503fSisaki d[2] = (val >> 16) & 0xff;
312b950503fSisaki } else {
313b950503fSisaki d[0] = (val >> 16) & 0xff;
314b950503fSisaki d[1] = (val >> 8) & 0xff;
315b950503fSisaki d[2] = val & 0xff;
316b950503fSisaki }
317b950503fSisaki d += 3;
318b950503fSisaki }
319b950503fSisaki }
320b950503fSisaki #endif /* AUDIO_SUPPORT_LINEAR24 */
321b950503fSisaki
322b950503fSisaki /*
323b950503fSisaki * audio_linear32_to_internal:
324b950503fSisaki * This filter performs conversion from [US]LINEAR32{LE,BE} to internal
325b950503fSisaki * format. Since it's rarely used, it's size optimized.
326b950503fSisaki */
327b950503fSisaki void
audio_linear32_to_internal(audio_filter_arg_t * arg)328b950503fSisaki audio_linear32_to_internal(audio_filter_arg_t *arg)
329b950503fSisaki {
330b950503fSisaki const uint32_t *s;
331b950503fSisaki aint_t *d;
332b950503fSisaki auint_t xor;
333b950503fSisaki u_int sample_count;
334b950503fSisaki u_int i;
335b950503fSisaki bool is_src_NE;
336b950503fSisaki
337b950503fSisaki DIAGNOSTIC_filter_arg(arg);
338b950503fSisaki KASSERT(audio_format2_is_linear(arg->srcfmt));
339b950503fSisaki KASSERT(arg->srcfmt->precision == 32);
340b950503fSisaki KASSERT(arg->srcfmt->stride == 32);
341b950503fSisaki KASSERT(audio_format2_is_internal(arg->dstfmt));
342b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
343b950503fSisaki
344b950503fSisaki s = arg->src;
345b950503fSisaki d = arg->dst;
346b950503fSisaki sample_count = arg->count * arg->srcfmt->channels;
347b950503fSisaki xor = audio_format2_is_signed(arg->srcfmt)
348b950503fSisaki ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
349b950503fSisaki is_src_NE = (audio_format2_endian(arg->srcfmt) == BYTE_ORDER);
350b950503fSisaki
351b950503fSisaki for (i = 0; i < sample_count; i++) {
352b950503fSisaki uint32_t val;
353b950503fSisaki val = *s++;
354b950503fSisaki if (!is_src_NE)
355b950503fSisaki val = bswap32(val);
356b950503fSisaki val >>= 32 - AUDIO_INTERNAL_BITS;
357b950503fSisaki val ^= xor;
358b950503fSisaki *d++ = val;
359b950503fSisaki }
360b950503fSisaki }
361b950503fSisaki
362b950503fSisaki /*
363b950503fSisaki * audio_internal_to_linear32:
364b950503fSisaki * This filter performs conversion from internal format to
365b950503fSisaki * [US]LINEAR32{LE,BE}. Since it's rarely used, it's size optimized.
366b950503fSisaki */
367b950503fSisaki void
audio_internal_to_linear32(audio_filter_arg_t * arg)368b950503fSisaki audio_internal_to_linear32(audio_filter_arg_t *arg)
369b950503fSisaki {
370b950503fSisaki const aint_t *s;
371b950503fSisaki uint32_t *d;
372b950503fSisaki auint_t xor;
373b950503fSisaki u_int sample_count;
374b950503fSisaki u_int i;
375b950503fSisaki bool is_dst_NE;
376b950503fSisaki
377b950503fSisaki DIAGNOSTIC_filter_arg(arg);
378b950503fSisaki KASSERT(audio_format2_is_linear(arg->dstfmt));
379b950503fSisaki KASSERT(arg->dstfmt->precision == 32);
380b950503fSisaki KASSERT(arg->dstfmt->stride == 32);
381b950503fSisaki KASSERT(audio_format2_is_internal(arg->srcfmt));
382b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
383b950503fSisaki
384b950503fSisaki s = arg->src;
385b950503fSisaki d = arg->dst;
386b950503fSisaki sample_count = arg->count * arg->srcfmt->channels;
387b950503fSisaki xor = audio_format2_is_signed(arg->dstfmt)
388b950503fSisaki ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1));
389b950503fSisaki is_dst_NE = (audio_format2_endian(arg->dstfmt) == BYTE_ORDER);
390b950503fSisaki
391b950503fSisaki for (i = 0; i < sample_count; i++) {
392b950503fSisaki uint32_t val;
393b950503fSisaki val = *s++;
394b950503fSisaki val ^= xor;
395b950503fSisaki val <<= 32 - AUDIO_INTERNAL_BITS;
396b950503fSisaki if (!is_dst_NE)
397b950503fSisaki val = bswap32(val);
398b950503fSisaki *d++ = val;
399b950503fSisaki }
400b950503fSisaki }
401