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