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