1 /* $NetBSD: linear.c,v 1.3 2020/01/11 04:06:13 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.3 2020/01/11 04:06:13 isaki 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