1 /* 2 * PCM Interface - misc routines 3 * Copyright (c) 1998 by Jaroslav Kysela <perex (at) perex.cz> 4 * 5 * 6 * This library is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as 8 * published by the Free Software Foundation; either version 2.1 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <unistd.h> 25 #include <string.h> 26 #include <byteswap.h> 27 #include "pcm_local.h" 28 29 30 /** 31 * \brief Return sign info for a PCM sample linear format 32 * \param format Format 33 * \return 0 unsigned, 1 signed, a negative error code if format is not linear 34 */ 35 int snd_pcm_format_signed(snd_pcm_format_t format) 36 { 37 switch (format) { 38 case SNDRV_PCM_FORMAT_S8: 39 case SNDRV_PCM_FORMAT_S16_LE: 40 case SNDRV_PCM_FORMAT_S16_BE: 41 case SNDRV_PCM_FORMAT_S24_LE: 42 case SNDRV_PCM_FORMAT_S24_BE: 43 case SNDRV_PCM_FORMAT_S32_LE: 44 case SNDRV_PCM_FORMAT_S32_BE: 45 case SNDRV_PCM_FORMAT_S24_3LE: 46 case SNDRV_PCM_FORMAT_S24_3BE: 47 case SNDRV_PCM_FORMAT_S20_3LE: 48 case SNDRV_PCM_FORMAT_S20_3BE: 49 case SNDRV_PCM_FORMAT_S18_3LE: 50 case SNDRV_PCM_FORMAT_S18_3BE: 51 return 1; 52 case SNDRV_PCM_FORMAT_U8: 53 case SNDRV_PCM_FORMAT_U16_LE: 54 case SNDRV_PCM_FORMAT_U16_BE: 55 case SNDRV_PCM_FORMAT_U24_LE: 56 case SNDRV_PCM_FORMAT_U24_BE: 57 case SNDRV_PCM_FORMAT_U32_LE: 58 case SNDRV_PCM_FORMAT_U32_BE: 59 case SNDRV_PCM_FORMAT_U24_3LE: 60 case SNDRV_PCM_FORMAT_U24_3BE: 61 case SNDRV_PCM_FORMAT_U20_3LE: 62 case SNDRV_PCM_FORMAT_U20_3BE: 63 case SNDRV_PCM_FORMAT_U18_3LE: 64 case SNDRV_PCM_FORMAT_U18_3BE: 65 return 0; 66 default: 67 return -EINVAL; 68 } 69 } 70 71 /** 72 * \brief Return sign info for a PCM sample linear format 73 * \param format Format 74 * \return 0 signed, 1 unsigned, a negative error code if format is not linear 75 */ 76 int snd_pcm_format_unsigned(snd_pcm_format_t format) 77 { 78 int val; 79 80 val = snd_pcm_format_signed(format); 81 if (val < 0) 82 return val; 83 return !val; 84 } 85 86 /** 87 * \brief Return linear info for a PCM sample format 88 * \param format Format 89 * \return 0 non linear, 1 linear 90 */ 91 int snd_pcm_format_linear(snd_pcm_format_t format) 92 { 93 return snd_pcm_format_signed(format) >= 0; 94 } 95 96 /** 97 * \brief Return float info for a PCM sample format 98 * \param format Format 99 * \return 0 non float, 1 float 100 */ 101 int snd_pcm_format_float(snd_pcm_format_t format) 102 { 103 switch (format) { 104 case SNDRV_PCM_FORMAT_FLOAT_LE: 105 case SNDRV_PCM_FORMAT_FLOAT_BE: 106 case SNDRV_PCM_FORMAT_FLOAT64_LE: 107 case SNDRV_PCM_FORMAT_FLOAT64_BE: 108 return 1; 109 default: 110 return 0; 111 } 112 } 113 114 /** 115 * \brief Return endian info for a PCM sample format 116 * \param format Format 117 * \return 0 big endian, 1 little endian, a negative error code if endian independent 118 */ 119 int snd_pcm_format_little_endian(snd_pcm_format_t format) 120 { 121 switch (format) { 122 case SNDRV_PCM_FORMAT_S16_LE: 123 case SNDRV_PCM_FORMAT_U16_LE: 124 case SNDRV_PCM_FORMAT_S24_LE: 125 case SNDRV_PCM_FORMAT_U24_LE: 126 case SNDRV_PCM_FORMAT_S32_LE: 127 case SNDRV_PCM_FORMAT_U32_LE: 128 case SNDRV_PCM_FORMAT_FLOAT_LE: 129 case SNDRV_PCM_FORMAT_FLOAT64_LE: 130 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: 131 case SNDRV_PCM_FORMAT_S24_3LE: 132 case SNDRV_PCM_FORMAT_S20_3LE: 133 case SNDRV_PCM_FORMAT_S18_3LE: 134 case SNDRV_PCM_FORMAT_U24_3LE: 135 case SNDRV_PCM_FORMAT_U20_3LE: 136 case SNDRV_PCM_FORMAT_U18_3LE: 137 return 1; 138 case SNDRV_PCM_FORMAT_S16_BE: 139 case SNDRV_PCM_FORMAT_U16_BE: 140 case SNDRV_PCM_FORMAT_S24_BE: 141 case SNDRV_PCM_FORMAT_U24_BE: 142 case SNDRV_PCM_FORMAT_S32_BE: 143 case SNDRV_PCM_FORMAT_U32_BE: 144 case SNDRV_PCM_FORMAT_FLOAT_BE: 145 case SNDRV_PCM_FORMAT_FLOAT64_BE: 146 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: 147 case SNDRV_PCM_FORMAT_S24_3BE: 148 case SNDRV_PCM_FORMAT_S20_3BE: 149 case SNDRV_PCM_FORMAT_S18_3BE: 150 case SNDRV_PCM_FORMAT_U24_3BE: 151 case SNDRV_PCM_FORMAT_U20_3BE: 152 case SNDRV_PCM_FORMAT_U18_3BE: 153 return 0; 154 default: 155 return -EINVAL; 156 } 157 } 158 159 /** 160 * \brief Return endian info for a PCM sample format 161 * \param format Format 162 * \return 0 little endian, 1 big endian, a negative error code if endian independent 163 */ 164 int snd_pcm_format_big_endian(snd_pcm_format_t format) 165 { 166 int val; 167 168 val = snd_pcm_format_little_endian(format); 169 if (val < 0) 170 return val; 171 return !val; 172 } 173 174 /** 175 * \brief Return endian info for a PCM sample format 176 * \param format Format 177 * \return 0 swapped, 1 CPU endian, a negative error code if endian independent 178 */ 179 int snd_pcm_format_cpu_endian(snd_pcm_format_t format) 180 { 181 #ifdef SNDRV_LITTLE_ENDIAN 182 return snd_pcm_format_little_endian(format); 183 #else 184 return snd_pcm_format_big_endian(format); 185 #endif 186 } 187 188 /** 189 * \brief Return nominal bits per a PCM sample 190 * \param format Sample format 191 * \return bits per sample, a negative error code if not applicable 192 */ 193 int snd_pcm_format_width(snd_pcm_format_t format) 194 { 195 switch (format) { 196 case SNDRV_PCM_FORMAT_S8: 197 case SNDRV_PCM_FORMAT_U8: 198 return 8; 199 case SNDRV_PCM_FORMAT_S16_LE: 200 case SNDRV_PCM_FORMAT_S16_BE: 201 case SNDRV_PCM_FORMAT_U16_LE: 202 case SNDRV_PCM_FORMAT_U16_BE: 203 return 16; 204 case SNDRV_PCM_FORMAT_S18_3LE: 205 case SNDRV_PCM_FORMAT_S18_3BE: 206 case SNDRV_PCM_FORMAT_U18_3LE: 207 case SNDRV_PCM_FORMAT_U18_3BE: 208 return 18; 209 case SNDRV_PCM_FORMAT_S20_3LE: 210 case SNDRV_PCM_FORMAT_S20_3BE: 211 case SNDRV_PCM_FORMAT_U20_3LE: 212 case SNDRV_PCM_FORMAT_U20_3BE: 213 return 20; 214 case SNDRV_PCM_FORMAT_S24_LE: 215 case SNDRV_PCM_FORMAT_S24_BE: 216 case SNDRV_PCM_FORMAT_U24_LE: 217 case SNDRV_PCM_FORMAT_U24_BE: 218 case SNDRV_PCM_FORMAT_S24_3LE: 219 case SNDRV_PCM_FORMAT_S24_3BE: 220 case SNDRV_PCM_FORMAT_U24_3LE: 221 case SNDRV_PCM_FORMAT_U24_3BE: 222 return 24; 223 case SNDRV_PCM_FORMAT_S32_LE: 224 case SNDRV_PCM_FORMAT_S32_BE: 225 case SNDRV_PCM_FORMAT_U32_LE: 226 case SNDRV_PCM_FORMAT_U32_BE: 227 case SNDRV_PCM_FORMAT_FLOAT_LE: 228 case SNDRV_PCM_FORMAT_FLOAT_BE: 229 return 32; 230 case SNDRV_PCM_FORMAT_FLOAT64_LE: 231 case SNDRV_PCM_FORMAT_FLOAT64_BE: 232 return 64; 233 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: 234 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: 235 return 32; 236 case SNDRV_PCM_FORMAT_MU_LAW: 237 case SNDRV_PCM_FORMAT_A_LAW: 238 return 8; 239 case SNDRV_PCM_FORMAT_IMA_ADPCM: 240 return 4; 241 default: 242 return -EINVAL; 243 } 244 } 245 246 /** 247 * \brief Return bits needed to store a PCM sample 248 * \param format Sample format 249 * \return bits per sample, a negative error code if not applicable 250 */ 251 int snd_pcm_format_physical_width(snd_pcm_format_t format) 252 { 253 switch (format) { 254 case SNDRV_PCM_FORMAT_S8: 255 case SNDRV_PCM_FORMAT_U8: 256 return 8; 257 case SNDRV_PCM_FORMAT_S16_LE: 258 case SNDRV_PCM_FORMAT_S16_BE: 259 case SNDRV_PCM_FORMAT_U16_LE: 260 case SNDRV_PCM_FORMAT_U16_BE: 261 return 16; 262 case SNDRV_PCM_FORMAT_S18_3LE: 263 case SNDRV_PCM_FORMAT_S18_3BE: 264 case SNDRV_PCM_FORMAT_U18_3LE: 265 case SNDRV_PCM_FORMAT_U18_3BE: 266 case SNDRV_PCM_FORMAT_S20_3LE: 267 case SNDRV_PCM_FORMAT_S20_3BE: 268 case SNDRV_PCM_FORMAT_U20_3LE: 269 case SNDRV_PCM_FORMAT_U20_3BE: 270 case SNDRV_PCM_FORMAT_S24_3LE: 271 case SNDRV_PCM_FORMAT_S24_3BE: 272 case SNDRV_PCM_FORMAT_U24_3LE: 273 case SNDRV_PCM_FORMAT_U24_3BE: 274 return 24; 275 case SNDRV_PCM_FORMAT_S24_LE: 276 case SNDRV_PCM_FORMAT_S24_BE: 277 case SNDRV_PCM_FORMAT_U24_LE: 278 case SNDRV_PCM_FORMAT_U24_BE: 279 case SNDRV_PCM_FORMAT_S32_LE: 280 case SNDRV_PCM_FORMAT_S32_BE: 281 case SNDRV_PCM_FORMAT_U32_LE: 282 case SNDRV_PCM_FORMAT_U32_BE: 283 case SNDRV_PCM_FORMAT_FLOAT_LE: 284 case SNDRV_PCM_FORMAT_FLOAT_BE: 285 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: 286 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: 287 return 32; 288 case SNDRV_PCM_FORMAT_FLOAT64_LE: 289 case SNDRV_PCM_FORMAT_FLOAT64_BE: 290 return 64; 291 case SNDRV_PCM_FORMAT_MU_LAW: 292 case SNDRV_PCM_FORMAT_A_LAW: 293 return 8; 294 case SNDRV_PCM_FORMAT_IMA_ADPCM: 295 return 4; 296 default: 297 return -EINVAL; 298 } 299 } 300 301 /** 302 * \brief Return bytes needed to store a quantity of PCM sample 303 * \param format Sample format 304 * \param samples Samples count 305 * \return bytes needed, a negative error code if not integer or unknown 306 */ 307 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) 308 { 309 switch (format) { 310 case SNDRV_PCM_FORMAT_S8: 311 case SNDRV_PCM_FORMAT_U8: 312 return samples; 313 case SNDRV_PCM_FORMAT_S16_LE: 314 case SNDRV_PCM_FORMAT_S16_BE: 315 case SNDRV_PCM_FORMAT_U16_LE: 316 case SNDRV_PCM_FORMAT_U16_BE: 317 return samples * 2; 318 case SNDRV_PCM_FORMAT_S18_3LE: 319 case SNDRV_PCM_FORMAT_S18_3BE: 320 case SNDRV_PCM_FORMAT_U18_3LE: 321 case SNDRV_PCM_FORMAT_U18_3BE: 322 case SNDRV_PCM_FORMAT_S20_3LE: 323 case SNDRV_PCM_FORMAT_S20_3BE: 324 case SNDRV_PCM_FORMAT_U20_3LE: 325 case SNDRV_PCM_FORMAT_U20_3BE: 326 case SNDRV_PCM_FORMAT_S24_3LE: 327 case SNDRV_PCM_FORMAT_S24_3BE: 328 case SNDRV_PCM_FORMAT_U24_3LE: 329 case SNDRV_PCM_FORMAT_U24_3BE: 330 return samples * 3; 331 case SNDRV_PCM_FORMAT_S24_LE: 332 case SNDRV_PCM_FORMAT_S24_BE: 333 case SNDRV_PCM_FORMAT_U24_LE: 334 case SNDRV_PCM_FORMAT_U24_BE: 335 case SNDRV_PCM_FORMAT_S32_LE: 336 case SNDRV_PCM_FORMAT_S32_BE: 337 case SNDRV_PCM_FORMAT_U32_LE: 338 case SNDRV_PCM_FORMAT_U32_BE: 339 case SNDRV_PCM_FORMAT_FLOAT_LE: 340 case SNDRV_PCM_FORMAT_FLOAT_BE: 341 return samples * 4; 342 case SNDRV_PCM_FORMAT_FLOAT64_LE: 343 case SNDRV_PCM_FORMAT_FLOAT64_BE: 344 return samples * 8; 345 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: 346 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: 347 return samples * 4; 348 case SNDRV_PCM_FORMAT_MU_LAW: 349 case SNDRV_PCM_FORMAT_A_LAW: 350 return samples; 351 case SNDRV_PCM_FORMAT_IMA_ADPCM: 352 if (samples & 1) 353 return -EINVAL; 354 return samples / 2; 355 default: 356 assert(0); 357 return -EINVAL; 358 } 359 } 360 361 /** 362 * \brief Return 64 bit expressing silence for a PCM sample format 363 * \param format Sample format 364 * \return silence 64 bit word 365 */ 366 u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) 367 { 368 switch (format) { 369 case SNDRV_PCM_FORMAT_S8: 370 case SNDRV_PCM_FORMAT_S16_LE: 371 case SNDRV_PCM_FORMAT_S16_BE: 372 case SNDRV_PCM_FORMAT_S24_LE: 373 case SNDRV_PCM_FORMAT_S24_BE: 374 case SNDRV_PCM_FORMAT_S32_LE: 375 case SNDRV_PCM_FORMAT_S32_BE: 376 case SNDRV_PCM_FORMAT_S24_3LE: 377 case SNDRV_PCM_FORMAT_S24_3BE: 378 case SNDRV_PCM_FORMAT_S20_3LE: 379 case SNDRV_PCM_FORMAT_S20_3BE: 380 case SNDRV_PCM_FORMAT_S18_3LE: 381 case SNDRV_PCM_FORMAT_S18_3BE: 382 return 0; 383 case SNDRV_PCM_FORMAT_U8: 384 return 0x8080808080808080ULL; 385 #ifdef SNDRV_LITTLE_ENDIAN 386 case SNDRV_PCM_FORMAT_U16_LE: 387 return 0x8000800080008000ULL; 388 case SNDRV_PCM_FORMAT_U24_LE: 389 return 0x0080000000800000ULL; 390 case SNDRV_PCM_FORMAT_U32_LE: 391 return 0x8000000080000000ULL; 392 case SNDRV_PCM_FORMAT_U16_BE: 393 return 0x0080008000800080ULL; 394 case SNDRV_PCM_FORMAT_U24_BE: 395 return 0x0000800000008000ULL; 396 case SNDRV_PCM_FORMAT_U32_BE: 397 return 0x0000008000000080ULL; 398 case SNDRV_PCM_FORMAT_U24_3LE: 399 return 0x0000800000800000ULL; 400 case SNDRV_PCM_FORMAT_U24_3BE: 401 return 0x0080000080000080ULL; 402 case SNDRV_PCM_FORMAT_U20_3LE: 403 return 0x0000080000080000ULL; 404 case SNDRV_PCM_FORMAT_U20_3BE: 405 return 0x0008000008000008ULL; 406 case SNDRV_PCM_FORMAT_U18_3LE: 407 return 0x0000020000020000ULL; 408 case SNDRV_PCM_FORMAT_U18_3BE: 409 return 0x0002000002000002ULL; 410 #else 411 case SNDRV_PCM_FORMAT_U16_LE: 412 return 0x0080008000800080ULL; 413 case SNDRV_PCM_FORMAT_U24_LE: 414 return 0x0000800000008000ULL; 415 case SNDRV_PCM_FORMAT_U32_LE: 416 return 0x0000008000000080ULL; 417 case SNDRV_PCM_FORMAT_U16_BE: 418 return 0x8000800080008000ULL; 419 case SNDRV_PCM_FORMAT_U24_BE: 420 return 0x0080000000800000ULL; 421 case SNDRV_PCM_FORMAT_U32_BE: 422 return 0x8000000080000000ULL; 423 case SNDRV_PCM_FORMAT_U24_3LE: 424 return 0x0080000080000080ULL; 425 case SNDRV_PCM_FORMAT_U24_3BE: 426 return 0x0000800000800000ULL; 427 case SNDRV_PCM_FORMAT_U20_3LE: 428 return 0x0008000008000008ULL; 429 case SNDRV_PCM_FORMAT_U20_3BE: 430 return 0x0000080000080000ULL; 431 case SNDRV_PCM_FORMAT_U18_3LE: 432 return 0x0002000002000002ULL; 433 case SNDRV_PCM_FORMAT_U18_3BE: 434 return 0x0000020000020000ULL; 435 #endif 436 case SNDRV_PCM_FORMAT_FLOAT_LE: 437 { 438 union { 439 float f[2]; 440 u_int64_t i; 441 } u; 442 u.f[0] = u.f[1] = 0.0; 443 #ifdef SNDRV_LITTLE_ENDIAN 444 return u.i; 445 #else 446 return bswap_64(u.i); 447 #endif 448 } 449 case SNDRV_PCM_FORMAT_FLOAT64_LE: 450 { 451 union { 452 double f; 453 u_int64_t i; 454 } u; 455 u.f = 0.0; 456 #ifdef SNDRV_LITTLE_ENDIAN 457 return u.i; 458 #else 459 return bswap_64(u.i); 460 #endif 461 } 462 case SNDRV_PCM_FORMAT_FLOAT_BE: 463 { 464 union { 465 float f[2]; 466 u_int64_t i; 467 } u; 468 u.f[0] = u.f[1] = 0.0; 469 #ifdef SNDRV_LITTLE_ENDIAN 470 return bswap_64(u.i); 471 #else 472 return u.i; 473 #endif 474 } 475 case SNDRV_PCM_FORMAT_FLOAT64_BE: 476 { 477 union { 478 double f; 479 u_int64_t i; 480 } u; 481 u.f = 0.0; 482 #ifdef SNDRV_LITTLE_ENDIAN 483 return bswap_64(u.i); 484 #else 485 return u.i; 486 #endif 487 } 488 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: 489 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: 490 return 0; 491 case SNDRV_PCM_FORMAT_MU_LAW: 492 return 0x7f7f7f7f7f7f7f7fULL; 493 case SNDRV_PCM_FORMAT_A_LAW: 494 return 0x5555555555555555ULL; 495 case SNDRV_PCM_FORMAT_IMA_ADPCM: /* special case */ 496 case SNDRV_PCM_FORMAT_MPEG: 497 case SNDRV_PCM_FORMAT_GSM: 498 case SNDRV_PCM_FORMAT_SPECIAL: 499 return 0; 500 default: 501 assert(0); 502 return 0; 503 } 504 return 0; 505 } 506 507 /** 508 * \brief Return 32 bit expressing silence for a PCM sample format 509 * \param format Sample format 510 * \return silence 32 bit word 511 */ 512 u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format) 513 { 514 assert(snd_pcm_format_physical_width(format) <= 32); 515 return (u_int32_t)snd_pcm_format_silence_64(format); 516 } 517 518 /** 519 * \brief Return 16 bit expressing silence for a PCM sample format 520 * \param format Sample format 521 * \return silence 16 bit word 522 */ 523 u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format) 524 { 525 assert(snd_pcm_format_physical_width(format) <= 16); 526 return (u_int16_t)snd_pcm_format_silence_64(format); 527 } 528 529 /** 530 * \brief Return 8 bit expressing silence for a PCM sample format 531 * \param format Sample format 532 * \return silence 8 bit word 533 */ 534 u_int8_t snd_pcm_format_silence(snd_pcm_format_t format) 535 { 536 assert(snd_pcm_format_physical_width(format) <= 8); 537 return (u_int8_t)snd_pcm_format_silence_64(format); 538 } 539 540 /** 541 * \brief Silence a PCM samples buffer 542 * \param format Sample format 543 * \param data Buffer 544 * \param samples Samples count 545 * \return 0 if successful or a negative error code 546 */ 547 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) 548 { 549 if (samples == 0) 550 return 0; 551 switch (snd_pcm_format_physical_width(format)) { 552 case 4: { 553 u_int8_t silence = snd_pcm_format_silence_64(format); 554 unsigned int samples1; 555 if (samples % 2 != 0) 556 return -EINVAL; 557 samples1 = samples / 2; 558 memset(data, silence, samples1); 559 break; 560 } 561 case 8: { 562 u_int8_t silence = snd_pcm_format_silence_64(format); 563 memset(data, silence, samples); 564 break; 565 } 566 case 16: { 567 u_int16_t silence = snd_pcm_format_silence_64(format); 568 u_int16_t *pdata = (u_int16_t *)data; 569 if (! silence) 570 memset(data, 0, samples * 2); 571 else { 572 while (samples-- > 0) 573 *pdata++ = silence; 574 } 575 break; 576 } 577 case 24: { 578 u_int32_t silence = snd_pcm_format_silence_64(format); 579 u_int8_t *pdata = (u_int8_t *)data; 580 if (! silence) 581 memset(data, 0, samples * 3); 582 else { 583 while (samples-- > 0) { 584 #ifdef SNDRV_LITTLE_ENDIAN 585 *pdata++ = silence >> 0; 586 *pdata++ = silence >> 8; 587 *pdata++ = silence >> 16; 588 #else 589 *pdata++ = silence >> 16; 590 *pdata++ = silence >> 8; 591 *pdata++ = silence >> 0; 592 #endif 593 } 594 } 595 break; 596 } 597 case 32: { 598 u_int32_t silence = snd_pcm_format_silence_64(format); 599 u_int32_t *pdata = (u_int32_t *)data; 600 if (! silence) 601 memset(data, 0, samples * 4); 602 else { 603 while (samples-- > 0) 604 *pdata++ = silence; 605 } 606 break; 607 } 608 case 64: { 609 u_int64_t silence = snd_pcm_format_silence_64(format); 610 u_int64_t *pdata = (u_int64_t *)data; 611 if (! silence) 612 memset(data, 0, samples * 8); 613 else { 614 while (samples-- > 0) 615 *pdata++ = silence; 616 } 617 break; 618 } 619 default: 620 assert(0); 621 return -EINVAL; 622 } 623 return 0; 624 } 625 626 static const int linear_formats[4][2][2] = { 627 { { SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8 }, 628 { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8 } }, 629 { { SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE }, 630 { SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE } }, 631 { { SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE }, 632 { SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE } }, 633 { { SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE }, 634 { SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE } } 635 }; 636 637 static const int linear24_formats[3][2][2] = { 638 { { SNDRV_PCM_FORMAT_S24_3LE, SNDRV_PCM_FORMAT_S24_3BE }, 639 { SNDRV_PCM_FORMAT_U24_3LE, SNDRV_PCM_FORMAT_U24_3BE } }, 640 { { SNDRV_PCM_FORMAT_S20_3LE, SNDRV_PCM_FORMAT_S20_3BE }, 641 { SNDRV_PCM_FORMAT_U20_3LE, SNDRV_PCM_FORMAT_U20_3BE } }, 642 { { SNDRV_PCM_FORMAT_S18_3LE, SNDRV_PCM_FORMAT_S18_3BE }, 643 { SNDRV_PCM_FORMAT_U18_3LE, SNDRV_PCM_FORMAT_U18_3BE } }, 644 }; 645 646 /** 647 * \brief Compose a PCM sample linear format 648 * \param width Nominal bits per sample 649 * \param pwidth Physical bit width of the format 650 * \param unsignd Sign: 0 signed, 1 unsigned 651 * \param big_endian Endian: 0 little endian, 1 big endian 652 * \return The matching format type, or #SND_PCM_FORMAT_UNKNOWN if no match 653 */ 654 snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian) 655 { 656 if (pwidth == 24) { 657 switch (width) { 658 case 24: 659 width = 0; 660 break; 661 case 20: 662 width = 1; 663 break; 664 case 18: 665 width = 2; 666 break; 667 default: 668 return SND_PCM_FORMAT_UNKNOWN; 669 } 670 return linear24_formats[width][!!unsignd][!!big_endian]; 671 } else { 672 switch (width) { 673 case 8: 674 width = 0; 675 break; 676 case 16: 677 width = 1; 678 break; 679 case 24: 680 width = 2; 681 break; 682 case 32: 683 width = 3; 684 break; 685 default: 686 return SND_PCM_FORMAT_UNKNOWN; 687 } 688 return linear_formats[width][!!unsignd][!!big_endian]; 689 } 690 } 691 692 /** 693 * \brief Parse control element id from the config 694 * \param conf the config tree to parse 695 * \param ctl_id the pointer to store the resultant control element id 696 * \param cardp the pointer to store the card index 697 * \param cchannelsp the pointer to store the number of channels (optional) 698 * \param hwctlp the pointer to store the h/w control flag (optional) 699 * \return 0 if successful, or a negative error code 700 * 701 * This function parses the given config tree to retrieve the control element id 702 * and the card index. It's used by softvol. External PCM plugins can use this 703 * function for creating or assigining their controls. 704 * 705 * cchannelsp and hwctlp arguments are optional. Set NULL if not necessary. 706 */ 707 int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp, 708 int *cchannelsp, int *hwctlp) 709 { 710 snd_config_iterator_t i, next; 711 int iface = SND_CTL_ELEM_IFACE_MIXER; 712 const char *name = NULL; 713 long index = 0; 714 long device = -1; 715 long subdevice = -1; 716 int err; 717 718 assert(ctl_id && cardp); 719 720 *cardp = -1; 721 if (cchannelsp) 722 *cchannelsp = 2; 723 snd_config_for_each(i, next, conf) { 724 snd_config_t *n = snd_config_iterator_entry(i); 725 const char *id; 726 if (snd_config_get_id(n, &id) < 0) 727 continue; 728 if (strcmp(id, "comment") == 0) 729 continue; 730 if (strcmp(id, "card") == 0) { 731 const char *str; 732 long v; 733 if ((err = snd_config_get_integer(n, &v)) < 0) { 734 if ((err = snd_config_get_string(n, &str)) < 0) { 735 SNDERR("Invalid field %s", id); 736 goto _err; 737 } 738 *cardp = snd_card_get_index(str); 739 if (*cardp < 0) { 740 SNDERR("Cannot get index for %s", str); 741 err = *cardp; 742 goto _err; 743 } 744 } else 745 *cardp = v; 746 continue; 747 } 748 if (strcmp(id, "iface") == 0 || strcmp(id, "interface") == 0) { 749 const char *ptr; 750 if ((err = snd_config_get_string(n, &ptr)) < 0) { 751 SNDERR("field %s is not a string", id); 752 goto _err; 753 } 754 if ((err = snd_config_get_ctl_iface_ascii(ptr)) < 0) { 755 SNDERR("Invalid value for '%s'", id); 756 goto _err; 757 } 758 iface = err; 759 continue; 760 } 761 if (strcmp(id, "name") == 0) { 762 if ((err = snd_config_get_string(n, &name)) < 0) { 763 SNDERR("field %s is not a string", id); 764 goto _err; 765 } 766 continue; 767 } 768 if (strcmp(id, "index") == 0) { 769 if ((err = snd_config_get_integer(n, &index)) < 0) { 770 SNDERR("field %s is not an integer", id); 771 goto _err; 772 } 773 continue; 774 } 775 if (strcmp(id, "device") == 0) { 776 if ((err = snd_config_get_integer(n, &device)) < 0) { 777 SNDERR("field %s is not an integer", id); 778 goto _err; 779 } 780 continue; 781 } 782 if (strcmp(id, "subdevice") == 0) { 783 if ((err = snd_config_get_integer(n, &subdevice)) < 0) { 784 SNDERR("field %s is not an integer", id); 785 goto _err; 786 } 787 continue; 788 } 789 if (cchannelsp && strcmp(id, "count") == 0) { 790 long v; 791 if ((err = snd_config_get_integer(n, &v)) < 0) { 792 SNDERR("field %s is not an integer", id); 793 goto _err; 794 } 795 if (v < 1 || v > 2) { 796 SNDERR("Invalid count %ld", v); 797 goto _err; 798 } 799 *cchannelsp = v; 800 continue; 801 } 802 if (hwctlp && strcmp(id, "hwctl") == 0) { 803 if ((err = snd_config_get_bool(n)) < 0) { 804 SNDERR("The field %s must be a boolean type", id); 805 return err; 806 } 807 *hwctlp = err; 808 continue; 809 } 810 SNDERR("Unknown field %s", id); 811 return -EINVAL; 812 } 813 if (name == NULL) { 814 SNDERR("Missing control name"); 815 err = -EINVAL; 816 goto _err; 817 } 818 if (device < 0) 819 device = 0; 820 if (subdevice < 0) 821 subdevice = 0; 822 823 snd_ctl_elem_id_set_interface(ctl_id, iface); 824 snd_ctl_elem_id_set_name(ctl_id, name); 825 snd_ctl_elem_id_set_index(ctl_id, index); 826 snd_ctl_elem_id_set_device(ctl_id, device); 827 snd_ctl_elem_id_set_subdevice(ctl_id, subdevice); 828 829 return 0; 830 831 _err: 832 return err; 833 } 834