1*b950503fSisaki /* $NetBSD: linear.c,v 1.2 2019/05/08 13:40:17 isaki Exp $ */ 2*b950503fSisaki 3*b950503fSisaki /* 4*b950503fSisaki * Copyright (C) 2017 Tetsuya Isaki. All rights reserved. 5*b950503fSisaki * Copyright (C) 2017 Y.Sugahara (moveccr). All rights reserved. 6*b950503fSisaki * 7*b950503fSisaki * Redistribution and use in source and binary forms, with or without 8*b950503fSisaki * modification, are permitted provided that the following conditions 9*b950503fSisaki * are met: 10*b950503fSisaki * 1. Redistributions of source code must retain the above copyright 11*b950503fSisaki * notice, this list of conditions and the following disclaimer. 12*b950503fSisaki * 2. Redistributions in binary form must reproduce the above copyright 13*b950503fSisaki * notice, this list of conditions and the following disclaimer in the 14*b950503fSisaki * documentation and/or other materials provided with the distribution. 15*b950503fSisaki * 16*b950503fSisaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17*b950503fSisaki * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18*b950503fSisaki * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19*b950503fSisaki * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20*b950503fSisaki * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21*b950503fSisaki * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22*b950503fSisaki * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23*b950503fSisaki * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24*b950503fSisaki * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*b950503fSisaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*b950503fSisaki * SUCH DAMAGE. 27*b950503fSisaki */ 28*b950503fSisaki 29*b950503fSisaki #if defined(_KERNEL) 30*b950503fSisaki #include <sys/cdefs.h> 31*b950503fSisaki __KERNEL_RCSID(0, "$NetBSD: linear.c,v 1.2 2019/05/08 13:40:17 isaki Exp $"); 32*b950503fSisaki 33*b950503fSisaki #include <sys/types.h> 34*b950503fSisaki #include <sys/systm.h> 35*b950503fSisaki #include <sys/device.h> 36*b950503fSisaki #include <dev/audio/audiovar.h> 37*b950503fSisaki #include <dev/audio/linear.h> 38*b950503fSisaki #else 39*b950503fSisaki #include <stdint.h> 40*b950503fSisaki #include <stdbool.h> 41*b950503fSisaki #include "compat.h" 42*b950503fSisaki #include "audiovar.h" 43*b950503fSisaki #endif /* _KERNEL */ 44*b950503fSisaki 45*b950503fSisaki /* 46*b950503fSisaki * audio_linear8_to_internal: 47*b950503fSisaki * This filter performs conversion from [US]LINEAR8 to internal format. 48*b950503fSisaki */ 49*b950503fSisaki void 50*b950503fSisaki audio_linear8_to_internal(audio_filter_arg_t *arg) 51*b950503fSisaki { 52*b950503fSisaki const uint8_t *s; 53*b950503fSisaki aint_t *d; 54*b950503fSisaki uint8_t xor; 55*b950503fSisaki u_int sample_count; 56*b950503fSisaki u_int i; 57*b950503fSisaki 58*b950503fSisaki DIAGNOSTIC_filter_arg(arg); 59*b950503fSisaki KASSERT(audio_format2_is_linear(arg->srcfmt)); 60*b950503fSisaki KASSERT(arg->srcfmt->precision == 8); 61*b950503fSisaki KASSERT(arg->srcfmt->stride == 8); 62*b950503fSisaki KASSERT(audio_format2_is_internal(arg->dstfmt)); 63*b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); 64*b950503fSisaki 65*b950503fSisaki s = arg->src; 66*b950503fSisaki d = arg->dst; 67*b950503fSisaki sample_count = arg->count * arg->srcfmt->channels; 68*b950503fSisaki xor = audio_format2_is_signed(arg->srcfmt) ? 0 : 0x80; 69*b950503fSisaki 70*b950503fSisaki for (i = 0; i < sample_count; i++) { 71*b950503fSisaki uint8_t val; 72*b950503fSisaki val = *s++; 73*b950503fSisaki val ^= xor; 74*b950503fSisaki *d++ = (auint_t)val << (AUDIO_INTERNAL_BITS - 8); 75*b950503fSisaki } 76*b950503fSisaki } 77*b950503fSisaki 78*b950503fSisaki /* 79*b950503fSisaki * audio_internal_to_linear8: 80*b950503fSisaki * This filter performs conversion from internal format to [US]LINEAR8. 81*b950503fSisaki */ 82*b950503fSisaki void 83*b950503fSisaki audio_internal_to_linear8(audio_filter_arg_t *arg) 84*b950503fSisaki { 85*b950503fSisaki const aint_t *s; 86*b950503fSisaki uint8_t *d; 87*b950503fSisaki uint8_t xor; 88*b950503fSisaki u_int sample_count; 89*b950503fSisaki u_int i; 90*b950503fSisaki 91*b950503fSisaki DIAGNOSTIC_filter_arg(arg); 92*b950503fSisaki KASSERT(audio_format2_is_linear(arg->dstfmt)); 93*b950503fSisaki KASSERT(arg->dstfmt->precision == 8); 94*b950503fSisaki KASSERT(arg->dstfmt->stride == 8); 95*b950503fSisaki KASSERT(audio_format2_is_internal(arg->srcfmt)); 96*b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); 97*b950503fSisaki 98*b950503fSisaki s = arg->src; 99*b950503fSisaki d = arg->dst; 100*b950503fSisaki sample_count = arg->count * arg->srcfmt->channels; 101*b950503fSisaki xor = audio_format2_is_signed(arg->dstfmt) ? 0 : 0x80; 102*b950503fSisaki 103*b950503fSisaki for (i = 0; i < sample_count; i++) { 104*b950503fSisaki uint8_t val; 105*b950503fSisaki val = (*s++) >> (AUDIO_INTERNAL_BITS - 8); 106*b950503fSisaki val ^= xor; 107*b950503fSisaki *d++ = val; 108*b950503fSisaki } 109*b950503fSisaki } 110*b950503fSisaki 111*b950503fSisaki /* 112*b950503fSisaki * audio_linear16_to_internal: 113*b950503fSisaki * This filter performs conversion from [US]LINEAR16{LE,BE} to internal 114*b950503fSisaki * format. 115*b950503fSisaki */ 116*b950503fSisaki void 117*b950503fSisaki audio_linear16_to_internal(audio_filter_arg_t *arg) 118*b950503fSisaki { 119*b950503fSisaki const uint16_t *s; 120*b950503fSisaki aint_t *d; 121*b950503fSisaki uint16_t xor; 122*b950503fSisaki u_int sample_count; 123*b950503fSisaki u_int shift; 124*b950503fSisaki u_int i; 125*b950503fSisaki bool is_src_NE; 126*b950503fSisaki 127*b950503fSisaki DIAGNOSTIC_filter_arg(arg); 128*b950503fSisaki KASSERT(audio_format2_is_linear(arg->srcfmt)); 129*b950503fSisaki KASSERT(arg->srcfmt->precision == 16); 130*b950503fSisaki KASSERT(arg->srcfmt->stride == 16); 131*b950503fSisaki KASSERT(audio_format2_is_internal(arg->dstfmt)); 132*b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); 133*b950503fSisaki 134*b950503fSisaki s = arg->src; 135*b950503fSisaki d = arg->dst; 136*b950503fSisaki sample_count = arg->count * arg->srcfmt->channels; 137*b950503fSisaki 138*b950503fSisaki shift = AUDIO_INTERNAL_BITS - 16; 139*b950503fSisaki xor = audio_format2_is_signed(arg->srcfmt) ? 0 : 0x8000; 140*b950503fSisaki is_src_NE = (audio_format2_endian(arg->srcfmt) == BYTE_ORDER); 141*b950503fSisaki 142*b950503fSisaki /* 143*b950503fSisaki * Since slinear16_OppositeEndian to slinear_NativeEndian is used 144*b950503fSisaki * so much especially on big endian machines, so it's expanded. 145*b950503fSisaki * Other conversions are rarely used, so they are compressed. 146*b950503fSisaki */ 147*b950503fSisaki if (__predict_true(xor == 0) && is_src_NE == false) { 148*b950503fSisaki /* slinear16_OE to slinear<AI>_NE */ 149*b950503fSisaki for (i = 0; i < sample_count; i++) { 150*b950503fSisaki uint16_t val; 151*b950503fSisaki val = *s++; 152*b950503fSisaki val = bswap16(val); 153*b950503fSisaki *d++ = (auint_t)val << shift; 154*b950503fSisaki } 155*b950503fSisaki } else { 156*b950503fSisaki /* slinear16_NE to slinear<AI>_NE */ 157*b950503fSisaki /* ulinear16_{NE,OE} to slinear<AI>_NE */ 158*b950503fSisaki for (i = 0; i < sample_count; i++) { 159*b950503fSisaki uint16_t val; 160*b950503fSisaki val = *s++; 161*b950503fSisaki if (!is_src_NE) 162*b950503fSisaki val = bswap16(val); 163*b950503fSisaki val ^= xor; 164*b950503fSisaki *d++ = (auint_t)val << shift; 165*b950503fSisaki } 166*b950503fSisaki } 167*b950503fSisaki } 168*b950503fSisaki 169*b950503fSisaki /* 170*b950503fSisaki * audio_internal_to_linear16: 171*b950503fSisaki * This filter performs conversion from internal format to 172*b950503fSisaki * [US]LINEAR16{LE,BE}. 173*b950503fSisaki */ 174*b950503fSisaki void 175*b950503fSisaki audio_internal_to_linear16(audio_filter_arg_t *arg) 176*b950503fSisaki { 177*b950503fSisaki const aint_t *s; 178*b950503fSisaki uint16_t *d; 179*b950503fSisaki uint16_t xor; 180*b950503fSisaki u_int sample_count; 181*b950503fSisaki u_int shift; 182*b950503fSisaki u_int i; 183*b950503fSisaki bool is_dst_NE; 184*b950503fSisaki 185*b950503fSisaki DIAGNOSTIC_filter_arg(arg); 186*b950503fSisaki KASSERT(audio_format2_is_linear(arg->dstfmt)); 187*b950503fSisaki KASSERT(arg->dstfmt->precision == 16); 188*b950503fSisaki KASSERT(arg->dstfmt->stride == 16); 189*b950503fSisaki KASSERT(audio_format2_is_internal(arg->srcfmt)); 190*b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); 191*b950503fSisaki 192*b950503fSisaki s = arg->src; 193*b950503fSisaki d = arg->dst; 194*b950503fSisaki sample_count = arg->count * arg->srcfmt->channels; 195*b950503fSisaki 196*b950503fSisaki shift = AUDIO_INTERNAL_BITS - 16; 197*b950503fSisaki xor = audio_format2_is_signed(arg->dstfmt) ? 0 : 0x8000; 198*b950503fSisaki is_dst_NE = (audio_format2_endian(arg->dstfmt) == BYTE_ORDER); 199*b950503fSisaki 200*b950503fSisaki /* 201*b950503fSisaki * Since slinear_NativeEndian to slinear16_OppositeEndian is used 202*b950503fSisaki * so much especially on big endian machines, so it's expanded. 203*b950503fSisaki * Other conversions are rarely used, so they are compressed. 204*b950503fSisaki */ 205*b950503fSisaki if (__predict_true(xor == 0) && is_dst_NE == false) { 206*b950503fSisaki /* slinear<AI>_NE -> slinear16_OE */ 207*b950503fSisaki for (i = 0; i < sample_count; i++) { 208*b950503fSisaki uint16_t val; 209*b950503fSisaki val = (*s++) >> shift; 210*b950503fSisaki val = bswap16(val); 211*b950503fSisaki *d++ = val; 212*b950503fSisaki } 213*b950503fSisaki } else { 214*b950503fSisaki /* slinear<AI>_NE -> slinear16_NE */ 215*b950503fSisaki /* slinear<AI>_NE -> ulinear16_{NE,OE} */ 216*b950503fSisaki for (i = 0; i < sample_count; i++) { 217*b950503fSisaki uint16_t val; 218*b950503fSisaki val = (*s++) >> shift; 219*b950503fSisaki val ^= xor; 220*b950503fSisaki if (!is_dst_NE) 221*b950503fSisaki val = bswap16(val); 222*b950503fSisaki *d++ = val; 223*b950503fSisaki } 224*b950503fSisaki } 225*b950503fSisaki } 226*b950503fSisaki 227*b950503fSisaki #if defined(AUDIO_SUPPORT_LINEAR24) 228*b950503fSisaki /* 229*b950503fSisaki * audio_linear24_to_internal: 230*b950503fSisaki * This filter performs conversion from [US]LINEAR24/24{LE,BE} to 231*b950503fSisaki * internal format. Since it's rerely used, it's size optimized. 232*b950503fSisaki */ 233*b950503fSisaki void 234*b950503fSisaki audio_linear24_to_internal(audio_filter_arg_t *arg) 235*b950503fSisaki { 236*b950503fSisaki const uint8_t *s; 237*b950503fSisaki aint_t *d; 238*b950503fSisaki auint_t xor; 239*b950503fSisaki u_int sample_count; 240*b950503fSisaki u_int i; 241*b950503fSisaki bool is_src_LE; 242*b950503fSisaki 243*b950503fSisaki DIAGNOSTIC_filter_arg(arg); 244*b950503fSisaki KASSERT(audio_format2_is_linear(arg->srcfmt)); 245*b950503fSisaki KASSERT(arg->srcfmt->precision == 24); 246*b950503fSisaki KASSERT(arg->srcfmt->stride == 24); 247*b950503fSisaki KASSERT(audio_format2_is_internal(arg->dstfmt)); 248*b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); 249*b950503fSisaki 250*b950503fSisaki s = arg->src; 251*b950503fSisaki d = arg->dst; 252*b950503fSisaki sample_count = arg->count * arg->srcfmt->channels; 253*b950503fSisaki xor = audio_format2_is_signed(arg->srcfmt) 254*b950503fSisaki ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1)); 255*b950503fSisaki is_src_LE = (audio_format2_endian(arg->srcfmt) == LITTLE_ENDIAN); 256*b950503fSisaki 257*b950503fSisaki for (i = 0; i < sample_count; i++) { 258*b950503fSisaki uint32_t val; 259*b950503fSisaki if (is_src_LE) { 260*b950503fSisaki val = s[0] | (s[1] << 8) | (s[2] << 16); 261*b950503fSisaki } else { 262*b950503fSisaki val = (s[0] << 16) | (s[1] << 8) | s[2]; 263*b950503fSisaki } 264*b950503fSisaki s += 3; 265*b950503fSisaki 266*b950503fSisaki #if AUDIO_INTERNAL_BITS < 24 267*b950503fSisaki val >>= 24 - AUDIO_INTERNAL_BITS; 268*b950503fSisaki #else 269*b950503fSisaki val <<= AUDIO_INTERNAL_BITS - 24; 270*b950503fSisaki #endif 271*b950503fSisaki val ^= xor; 272*b950503fSisaki *d++ = val; 273*b950503fSisaki } 274*b950503fSisaki } 275*b950503fSisaki 276*b950503fSisaki /* 277*b950503fSisaki * audio_internal_to_linear24: 278*b950503fSisaki * This filter performs conversion from internal format to 279*b950503fSisaki * [US]LINEAR24/24{LE,BE}. Since it's rarely used, it's size optimized. 280*b950503fSisaki */ 281*b950503fSisaki void 282*b950503fSisaki audio_internal_to_linear24(audio_filter_arg_t *arg) 283*b950503fSisaki { 284*b950503fSisaki const aint_t *s; 285*b950503fSisaki uint8_t *d; 286*b950503fSisaki auint_t xor; 287*b950503fSisaki u_int sample_count; 288*b950503fSisaki u_int i; 289*b950503fSisaki bool is_dst_LE; 290*b950503fSisaki 291*b950503fSisaki DIAGNOSTIC_filter_arg(arg); 292*b950503fSisaki KASSERT(audio_format2_is_linear(arg->dstfmt)); 293*b950503fSisaki KASSERT(arg->dstfmt->precision == 24); 294*b950503fSisaki KASSERT(arg->dstfmt->stride == 24); 295*b950503fSisaki KASSERT(audio_format2_is_internal(arg->srcfmt)); 296*b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); 297*b950503fSisaki 298*b950503fSisaki s = arg->src; 299*b950503fSisaki d = arg->dst; 300*b950503fSisaki sample_count = arg->count * arg->srcfmt->channels; 301*b950503fSisaki xor = audio_format2_is_signed(arg->dstfmt) 302*b950503fSisaki ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1)); 303*b950503fSisaki is_dst_LE = (audio_format2_endian(arg->dstfmt) == LITTLE_ENDIAN); 304*b950503fSisaki 305*b950503fSisaki for (i = 0; i < sample_count; i++) { 306*b950503fSisaki uint32_t val; 307*b950503fSisaki val = *s++; 308*b950503fSisaki val ^= xor; 309*b950503fSisaki #if AUDIO_INTERNAL_BITS < 24 310*b950503fSisaki val <<= 24 - AUDIO_INTERNAL_BITS; 311*b950503fSisaki #else 312*b950503fSisaki val >>= AUDIO_INTERNAL_BITS - 24; 313*b950503fSisaki #endif 314*b950503fSisaki if (is_dst_LE) { 315*b950503fSisaki d[0] = val & 0xff; 316*b950503fSisaki d[1] = (val >> 8) & 0xff; 317*b950503fSisaki d[2] = (val >> 16) & 0xff; 318*b950503fSisaki } else { 319*b950503fSisaki d[0] = (val >> 16) & 0xff; 320*b950503fSisaki d[1] = (val >> 8) & 0xff; 321*b950503fSisaki d[2] = val & 0xff; 322*b950503fSisaki } 323*b950503fSisaki d += 3; 324*b950503fSisaki } 325*b950503fSisaki } 326*b950503fSisaki #endif /* AUDIO_SUPPORT_LINEAR24 */ 327*b950503fSisaki 328*b950503fSisaki /* 329*b950503fSisaki * audio_linear32_to_internal: 330*b950503fSisaki * This filter performs conversion from [US]LINEAR32{LE,BE} to internal 331*b950503fSisaki * format. Since it's rarely used, it's size optimized. 332*b950503fSisaki */ 333*b950503fSisaki void 334*b950503fSisaki audio_linear32_to_internal(audio_filter_arg_t *arg) 335*b950503fSisaki { 336*b950503fSisaki const uint32_t *s; 337*b950503fSisaki aint_t *d; 338*b950503fSisaki auint_t xor; 339*b950503fSisaki u_int sample_count; 340*b950503fSisaki u_int i; 341*b950503fSisaki bool is_src_NE; 342*b950503fSisaki 343*b950503fSisaki DIAGNOSTIC_filter_arg(arg); 344*b950503fSisaki KASSERT(audio_format2_is_linear(arg->srcfmt)); 345*b950503fSisaki KASSERT(arg->srcfmt->precision == 32); 346*b950503fSisaki KASSERT(arg->srcfmt->stride == 32); 347*b950503fSisaki KASSERT(audio_format2_is_internal(arg->dstfmt)); 348*b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); 349*b950503fSisaki 350*b950503fSisaki s = arg->src; 351*b950503fSisaki d = arg->dst; 352*b950503fSisaki sample_count = arg->count * arg->srcfmt->channels; 353*b950503fSisaki xor = audio_format2_is_signed(arg->srcfmt) 354*b950503fSisaki ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1)); 355*b950503fSisaki is_src_NE = (audio_format2_endian(arg->srcfmt) == BYTE_ORDER); 356*b950503fSisaki 357*b950503fSisaki for (i = 0; i < sample_count; i++) { 358*b950503fSisaki uint32_t val; 359*b950503fSisaki val = *s++; 360*b950503fSisaki if (!is_src_NE) 361*b950503fSisaki val = bswap32(val); 362*b950503fSisaki val >>= 32 - AUDIO_INTERNAL_BITS; 363*b950503fSisaki val ^= xor; 364*b950503fSisaki *d++ = val; 365*b950503fSisaki } 366*b950503fSisaki } 367*b950503fSisaki 368*b950503fSisaki /* 369*b950503fSisaki * audio_internal_to_linear32: 370*b950503fSisaki * This filter performs conversion from internal format to 371*b950503fSisaki * [US]LINEAR32{LE,BE}. Since it's rarely used, it's size optimized. 372*b950503fSisaki */ 373*b950503fSisaki void 374*b950503fSisaki audio_internal_to_linear32(audio_filter_arg_t *arg) 375*b950503fSisaki { 376*b950503fSisaki const aint_t *s; 377*b950503fSisaki uint32_t *d; 378*b950503fSisaki auint_t xor; 379*b950503fSisaki u_int sample_count; 380*b950503fSisaki u_int i; 381*b950503fSisaki bool is_dst_NE; 382*b950503fSisaki 383*b950503fSisaki DIAGNOSTIC_filter_arg(arg); 384*b950503fSisaki KASSERT(audio_format2_is_linear(arg->dstfmt)); 385*b950503fSisaki KASSERT(arg->dstfmt->precision == 32); 386*b950503fSisaki KASSERT(arg->dstfmt->stride == 32); 387*b950503fSisaki KASSERT(audio_format2_is_internal(arg->srcfmt)); 388*b950503fSisaki KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); 389*b950503fSisaki 390*b950503fSisaki s = arg->src; 391*b950503fSisaki d = arg->dst; 392*b950503fSisaki sample_count = arg->count * arg->srcfmt->channels; 393*b950503fSisaki xor = audio_format2_is_signed(arg->dstfmt) 394*b950503fSisaki ? 0 : (1 << (AUDIO_INTERNAL_BITS - 1)); 395*b950503fSisaki is_dst_NE = (audio_format2_endian(arg->dstfmt) == BYTE_ORDER); 396*b950503fSisaki 397*b950503fSisaki for (i = 0; i < sample_count; i++) { 398*b950503fSisaki uint32_t val; 399*b950503fSisaki val = *s++; 400*b950503fSisaki val ^= xor; 401*b950503fSisaki val <<= 32 - AUDIO_INTERNAL_BITS; 402*b950503fSisaki if (!is_dst_NE) 403*b950503fSisaki val = bswap32(val); 404*b950503fSisaki *d++ = val; 405*b950503fSisaki } 406*b950503fSisaki } 407