1 /* $NetBSD: linear.c,v 1.4 2021/07/21 06:35:44 skrll 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.4 2021/07/21 06:35:44 skrll 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 rerely 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