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