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