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