Lines Matching defs:*
2 * PCM Interface - misc routines
3 * Copyright (c) 1998 by Jaroslav Kysela <perex@perex.cz>
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.
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.
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
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"
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
35 int snd_pcm_format_signed(snd_pcm_format_t format)
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;
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
76 int snd_pcm_format_unsigned(snd_pcm_format_t format)
78 int val;
80 val = snd_pcm_format_signed(format);
81 if (val < 0)
82 return val;
83 return !val;
87 * \brief Return linear info for a PCM sample format
88 * \param format Format
89 * \return 0 non linear, 1 linear
91 int snd_pcm_format_linear(snd_pcm_format_t format)
93 return snd_pcm_format_signed(format) >= 0;
97 * \brief Return float info for a PCM sample format
98 * \param format Format
99 * \return 0 non float, 1 float
101 int snd_pcm_format_float(snd_pcm_format_t format)
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;
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
119 int snd_pcm_format_little_endian(snd_pcm_format_t format)
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;
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
164 int snd_pcm_format_big_endian(snd_pcm_format_t format)
166 int val;
168 val = snd_pcm_format_little_endian(format);
169 if (val < 0)
170 return val;
171 return !val;
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
179 int snd_pcm_format_cpu_endian(snd_pcm_format_t format)
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
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
193 int snd_pcm_format_width(snd_pcm_format_t format)
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;
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
251 int snd_pcm_format_physical_width(snd_pcm_format_t format)
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;
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
307 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
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;
362 * \brief Return 64 bit expressing silence for a PCM sample format
363 * \param format Sample format
364 * \return silence 64 bit word
366 u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
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:
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
449 case SNDRV_PCM_FORMAT_FLOAT64_LE:
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
462 case SNDRV_PCM_FORMAT_FLOAT_BE:
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
475 case SNDRV_PCM_FORMAT_FLOAT64_BE:
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
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;
504 return 0;
508 * \brief Return 32 bit expressing silence for a PCM sample format
509 * \param format Sample format
510 * \return silence 32 bit word
512 u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format)
514 assert(snd_pcm_format_physical_width(format) <= 32);
515 return (u_int32_t)snd_pcm_format_silence_64(format);
519 * \brief Return 16 bit expressing silence for a PCM sample format
520 * \param format Sample format
521 * \return silence 16 bit word
523 u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format)
525 assert(snd_pcm_format_physical_width(format) <= 16);
526 return (u_int16_t)snd_pcm_format_silence_64(format);
530 * \brief Return 8 bit expressing silence for a PCM sample format
531 * \param format Sample format
532 * \return silence 8 bit word
534 u_int8_t snd_pcm_format_silence(snd_pcm_format_t format)
536 assert(snd_pcm_format_physical_width(format) <= 8);
537 return (u_int8_t)snd_pcm_format_silence_64(format);
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
547 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
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;
561 case 8: {
562 u_int8_t silence = snd_pcm_format_silence_64(format);
563 memset(data, silence, samples);
564 break;
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;
575 break;
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
595 break;
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;
606 break;
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;
617 break;
619 default:
620 assert(0);
621 return -EINVAL;
623 return 0;
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 } }
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 } },
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
654 snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian)
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;
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;
688 return linear_formats[width][!!unsignd][!!big_endian];
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
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.
705 * cchannelsp and hwctlp arguments are optional. Set NULL if not necessary.
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)
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;
718 assert(ctl_id && cardp);
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;
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;
744 } else
745 *cardp = v;
746 continue;
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;
754 if ((err = snd_config_get_ctl_iface_ascii(ptr)) < 0) {
755 SNDERR("Invalid value for '%s'", id);
756 goto _err;
758 iface = err;
759 continue;
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;
766 continue;
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;
773 continue;
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;
780 continue;
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;
787 continue;
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;
795 if (v < 1 || v > 2) {
796 SNDERR("Invalid count %ld", v);
797 goto _err;
799 *cchannelsp = v;
800 continue;
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;
807 *hwctlp = err;
808 continue;
810 SNDERR("Unknown field %s", id);
811 return -EINVAL;
813 if (name == NULL) {
814 SNDERR("Missing control name");
815 err = -EINVAL;
816 goto _err;
818 if (device < 0)
819 device = 0;
820 if (subdevice < 0)
821 subdevice = 0;
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);
829 return 0;
831 _err:
832 return err;