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