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