OSDN Git Service

pcm: Fix DSD formats userland usability
[android-x86/external-alsa-lib.git] / src / pcm / pcm_misc.c
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., 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         case SNDRV_PCM_FORMAT_DSD_U8:
199                 return 8;
200         case SNDRV_PCM_FORMAT_S16_LE:
201         case SNDRV_PCM_FORMAT_S16_BE:
202         case SNDRV_PCM_FORMAT_U16_LE:
203         case SNDRV_PCM_FORMAT_U16_BE:
204         case SNDRV_PCM_FORMAT_DSD_U16_LE:
205                 return 16;
206         case SNDRV_PCM_FORMAT_S18_3LE:
207         case SNDRV_PCM_FORMAT_S18_3BE:
208         case SNDRV_PCM_FORMAT_U18_3LE:
209         case SNDRV_PCM_FORMAT_U18_3BE:
210                 return 18;
211         case SNDRV_PCM_FORMAT_S20_3LE:
212         case SNDRV_PCM_FORMAT_S20_3BE:
213         case SNDRV_PCM_FORMAT_U20_3LE:
214         case SNDRV_PCM_FORMAT_U20_3BE:
215                 return 20;
216         case SNDRV_PCM_FORMAT_S24_LE:
217         case SNDRV_PCM_FORMAT_S24_BE:
218         case SNDRV_PCM_FORMAT_U24_LE:
219         case SNDRV_PCM_FORMAT_U24_BE:
220         case SNDRV_PCM_FORMAT_S24_3LE:
221         case SNDRV_PCM_FORMAT_S24_3BE:
222         case SNDRV_PCM_FORMAT_U24_3LE:
223         case SNDRV_PCM_FORMAT_U24_3BE:
224                 return 24;
225         case SNDRV_PCM_FORMAT_S32_LE:
226         case SNDRV_PCM_FORMAT_S32_BE:
227         case SNDRV_PCM_FORMAT_U32_LE:
228         case SNDRV_PCM_FORMAT_U32_BE:
229         case SNDRV_PCM_FORMAT_FLOAT_LE:
230         case SNDRV_PCM_FORMAT_FLOAT_BE:
231                 return 32;
232         case SNDRV_PCM_FORMAT_FLOAT64_LE:
233         case SNDRV_PCM_FORMAT_FLOAT64_BE:
234                 return 64;
235         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
236         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
237                 return 32;
238         case SNDRV_PCM_FORMAT_MU_LAW:
239         case SNDRV_PCM_FORMAT_A_LAW:
240                 return 8;
241         case SNDRV_PCM_FORMAT_IMA_ADPCM:
242                 return 4;
243         default:
244                 return -EINVAL;
245         }
246 }
247
248 /**
249  * \brief Return bits needed to store a PCM sample
250  * \param format Sample format
251  * \return bits per sample, a negative error code if not applicable
252  */
253 int snd_pcm_format_physical_width(snd_pcm_format_t format)
254 {
255         switch (format) {
256         case SNDRV_PCM_FORMAT_S8:
257         case SNDRV_PCM_FORMAT_U8:
258         case SNDRV_PCM_FORMAT_DSD_U8:
259                 return 8;
260         case SNDRV_PCM_FORMAT_S16_LE:
261         case SNDRV_PCM_FORMAT_S16_BE:
262         case SNDRV_PCM_FORMAT_U16_LE:
263         case SNDRV_PCM_FORMAT_U16_BE:
264         case SNDRV_PCM_FORMAT_DSD_U16_LE:
265                 return 16;
266         case SNDRV_PCM_FORMAT_S18_3LE:
267         case SNDRV_PCM_FORMAT_S18_3BE:
268         case SNDRV_PCM_FORMAT_U18_3LE:
269         case SNDRV_PCM_FORMAT_U18_3BE:
270         case SNDRV_PCM_FORMAT_S20_3LE:
271         case SNDRV_PCM_FORMAT_S20_3BE:
272         case SNDRV_PCM_FORMAT_U20_3LE:
273         case SNDRV_PCM_FORMAT_U20_3BE:
274         case SNDRV_PCM_FORMAT_S24_3LE:
275         case SNDRV_PCM_FORMAT_S24_3BE:
276         case SNDRV_PCM_FORMAT_U24_3LE:
277         case SNDRV_PCM_FORMAT_U24_3BE:
278                 return 24;
279         case SNDRV_PCM_FORMAT_S24_LE:
280         case SNDRV_PCM_FORMAT_S24_BE:
281         case SNDRV_PCM_FORMAT_U24_LE:
282         case SNDRV_PCM_FORMAT_U24_BE:
283         case SNDRV_PCM_FORMAT_S32_LE:
284         case SNDRV_PCM_FORMAT_S32_BE:
285         case SNDRV_PCM_FORMAT_U32_LE:
286         case SNDRV_PCM_FORMAT_U32_BE:
287         case SNDRV_PCM_FORMAT_FLOAT_LE:
288         case SNDRV_PCM_FORMAT_FLOAT_BE:
289         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
290         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
291                 return 32;
292         case SNDRV_PCM_FORMAT_FLOAT64_LE:
293         case SNDRV_PCM_FORMAT_FLOAT64_BE:
294                 return 64;
295         case SNDRV_PCM_FORMAT_MU_LAW:
296         case SNDRV_PCM_FORMAT_A_LAW:
297                 return 8;
298         case SNDRV_PCM_FORMAT_IMA_ADPCM:
299                 return 4;
300         default:
301                 return -EINVAL;
302         }
303 }
304
305 /**
306  * \brief Return bytes needed to store a quantity of PCM sample
307  * \param format Sample format
308  * \param samples Samples count
309  * \return bytes needed, a negative error code if not integer or unknown
310  */
311 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
312 {
313         switch (format) {
314         case SNDRV_PCM_FORMAT_S8:
315         case SNDRV_PCM_FORMAT_U8:
316                 return samples;
317         case SNDRV_PCM_FORMAT_S16_LE:
318         case SNDRV_PCM_FORMAT_S16_BE:
319         case SNDRV_PCM_FORMAT_U16_LE:
320         case SNDRV_PCM_FORMAT_U16_BE:
321                 return samples * 2;
322         case SNDRV_PCM_FORMAT_S18_3LE:
323         case SNDRV_PCM_FORMAT_S18_3BE:
324         case SNDRV_PCM_FORMAT_U18_3LE:
325         case SNDRV_PCM_FORMAT_U18_3BE:
326         case SNDRV_PCM_FORMAT_S20_3LE:
327         case SNDRV_PCM_FORMAT_S20_3BE:
328         case SNDRV_PCM_FORMAT_U20_3LE:
329         case SNDRV_PCM_FORMAT_U20_3BE:
330         case SNDRV_PCM_FORMAT_S24_3LE:
331         case SNDRV_PCM_FORMAT_S24_3BE:
332         case SNDRV_PCM_FORMAT_U24_3LE:
333         case SNDRV_PCM_FORMAT_U24_3BE:
334                 return samples * 3;
335         case SNDRV_PCM_FORMAT_S24_LE:
336         case SNDRV_PCM_FORMAT_S24_BE:
337         case SNDRV_PCM_FORMAT_U24_LE:
338         case SNDRV_PCM_FORMAT_U24_BE:
339         case SNDRV_PCM_FORMAT_S32_LE:
340         case SNDRV_PCM_FORMAT_S32_BE:
341         case SNDRV_PCM_FORMAT_U32_LE:
342         case SNDRV_PCM_FORMAT_U32_BE:
343         case SNDRV_PCM_FORMAT_FLOAT_LE:
344         case SNDRV_PCM_FORMAT_FLOAT_BE:
345                 return samples * 4;
346         case SNDRV_PCM_FORMAT_FLOAT64_LE:
347         case SNDRV_PCM_FORMAT_FLOAT64_BE:
348                 return samples * 8;
349         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
350         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
351                 return samples * 4;
352         case SNDRV_PCM_FORMAT_MU_LAW:
353         case SNDRV_PCM_FORMAT_A_LAW:
354                 return samples;
355         case SNDRV_PCM_FORMAT_IMA_ADPCM:
356                 if (samples & 1)
357                         return -EINVAL;
358                 return samples / 2;
359         default:
360                 assert(0);
361                 return -EINVAL;
362         }
363 }
364
365 /**
366  * \brief Return 64 bit expressing silence for a PCM sample format
367  * \param format Sample format
368  * \return silence 64 bit word
369  */
370 u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
371 {
372         switch (format) {
373         case SNDRV_PCM_FORMAT_S8:
374         case SNDRV_PCM_FORMAT_S16_LE:
375         case SNDRV_PCM_FORMAT_S16_BE:
376         case SNDRV_PCM_FORMAT_S24_LE:
377         case SNDRV_PCM_FORMAT_S24_BE:
378         case SNDRV_PCM_FORMAT_S32_LE:
379         case SNDRV_PCM_FORMAT_S32_BE:
380         case SNDRV_PCM_FORMAT_S24_3LE:
381         case SNDRV_PCM_FORMAT_S24_3BE:
382         case SNDRV_PCM_FORMAT_S20_3LE:
383         case SNDRV_PCM_FORMAT_S20_3BE:
384         case SNDRV_PCM_FORMAT_S18_3LE:
385         case SNDRV_PCM_FORMAT_S18_3BE:
386                 return 0;
387         case SNDRV_PCM_FORMAT_U8:
388                 return 0x8080808080808080ULL;
389 #ifdef SNDRV_LITTLE_ENDIAN
390         case SNDRV_PCM_FORMAT_U16_LE:
391                 return 0x8000800080008000ULL;
392         case SNDRV_PCM_FORMAT_U24_LE:
393                 return 0x0080000000800000ULL;
394         case SNDRV_PCM_FORMAT_U32_LE:
395                 return 0x8000000080000000ULL;
396         case SNDRV_PCM_FORMAT_U16_BE:
397                 return 0x0080008000800080ULL;
398         case SNDRV_PCM_FORMAT_U24_BE:
399                 return 0x0000800000008000ULL;
400         case SNDRV_PCM_FORMAT_U32_BE:
401                 return 0x0000008000000080ULL;
402         case SNDRV_PCM_FORMAT_U24_3LE:
403                 return 0x0000800000800000ULL;
404         case SNDRV_PCM_FORMAT_U24_3BE:
405                 return 0x0080000080000080ULL;
406         case SNDRV_PCM_FORMAT_U20_3LE:
407                 return 0x0000080000080000ULL;
408         case SNDRV_PCM_FORMAT_U20_3BE:
409                 return 0x0008000008000008ULL;
410         case SNDRV_PCM_FORMAT_U18_3LE:
411                 return 0x0000020000020000ULL;
412         case SNDRV_PCM_FORMAT_U18_3BE:
413                 return 0x0002000002000002ULL;
414 #else
415         case SNDRV_PCM_FORMAT_U16_LE:
416                 return 0x0080008000800080ULL;
417         case SNDRV_PCM_FORMAT_U24_LE:
418                 return 0x0000800000008000ULL;
419         case SNDRV_PCM_FORMAT_U32_LE:
420                 return 0x0000008000000080ULL;
421         case SNDRV_PCM_FORMAT_U16_BE:
422                 return 0x8000800080008000ULL;
423         case SNDRV_PCM_FORMAT_U24_BE:
424                 return 0x0080000000800000ULL;
425         case SNDRV_PCM_FORMAT_U32_BE:
426                 return 0x8000000080000000ULL;
427         case SNDRV_PCM_FORMAT_U24_3LE:
428                 return 0x0080000080000080ULL;
429         case SNDRV_PCM_FORMAT_U24_3BE:
430                 return 0x0000800000800000ULL;
431         case SNDRV_PCM_FORMAT_U20_3LE:
432                 return 0x0008000008000008ULL;
433         case SNDRV_PCM_FORMAT_U20_3BE:
434                 return 0x0000080000080000ULL;
435         case SNDRV_PCM_FORMAT_U18_3LE:
436                 return 0x0002000002000002ULL;
437         case SNDRV_PCM_FORMAT_U18_3BE:
438                 return 0x0000020000020000ULL;
439 #endif
440         case SNDRV_PCM_FORMAT_FLOAT_LE:
441         {
442                 union {
443                         float f[2];
444                         u_int64_t i;
445                 } u;
446                 u.f[0] = u.f[1] = 0.0;
447 #ifdef SNDRV_LITTLE_ENDIAN
448                 return u.i;
449 #else
450                 return bswap_64(u.i);
451 #endif
452         }
453         case SNDRV_PCM_FORMAT_FLOAT64_LE:
454         {
455                 union {
456                         double f;
457                         u_int64_t i;
458                 } u;
459                 u.f = 0.0;
460 #ifdef SNDRV_LITTLE_ENDIAN
461                 return u.i;
462 #else
463                 return bswap_64(u.i);
464 #endif
465         }
466         case SNDRV_PCM_FORMAT_FLOAT_BE:         
467         {
468                 union {
469                         float f[2];
470                         u_int64_t i;
471                 } u;
472                 u.f[0] = u.f[1] = 0.0;
473 #ifdef SNDRV_LITTLE_ENDIAN
474                 return bswap_64(u.i);
475 #else
476                 return u.i;
477 #endif
478         }
479         case SNDRV_PCM_FORMAT_FLOAT64_BE:
480         {
481                 union {
482                         double f;
483                         u_int64_t i;
484                 } u;
485                 u.f = 0.0;
486 #ifdef SNDRV_LITTLE_ENDIAN
487                 return bswap_64(u.i);
488 #else
489                 return u.i;
490 #endif
491         }
492         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
493         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
494                 return 0;       
495         case SNDRV_PCM_FORMAT_MU_LAW:
496                 return 0x7f7f7f7f7f7f7f7fULL;
497         case SNDRV_PCM_FORMAT_A_LAW:
498                 return 0x5555555555555555ULL;
499         case SNDRV_PCM_FORMAT_IMA_ADPCM:        /* special case */
500         case SNDRV_PCM_FORMAT_MPEG:
501         case SNDRV_PCM_FORMAT_GSM:
502         case SNDRV_PCM_FORMAT_SPECIAL:
503                 return 0;
504         default:
505                 assert(0);
506                 return 0;
507         }
508         return 0;
509 }
510
511 /**
512  * \brief Return 32 bit expressing silence for a PCM sample format
513  * \param format Sample format
514  * \return silence 32 bit word
515  */
516 u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format)
517 {
518         assert(snd_pcm_format_physical_width(format) <= 32);
519         return (u_int32_t)snd_pcm_format_silence_64(format);
520 }
521
522 /**
523  * \brief Return 16 bit expressing silence for a PCM sample format
524  * \param format Sample format
525  * \return silence 16 bit word
526  */
527 u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format)
528 {
529         assert(snd_pcm_format_physical_width(format) <= 16);
530         return (u_int16_t)snd_pcm_format_silence_64(format);
531 }
532
533 /**
534  * \brief Return 8 bit expressing silence for a PCM sample format
535  * \param format Sample format
536  * \return silence 8 bit word
537  */
538 u_int8_t snd_pcm_format_silence(snd_pcm_format_t format)
539 {
540         assert(snd_pcm_format_physical_width(format) <= 8);
541         return (u_int8_t)snd_pcm_format_silence_64(format);
542 }
543
544 /**
545  * \brief Silence a PCM samples buffer
546  * \param format Sample format
547  * \param data Buffer
548  * \param samples Samples count
549  * \return 0 if successful or a negative error code
550  */
551 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
552 {
553         if (samples == 0)
554                 return 0;
555         switch (snd_pcm_format_physical_width(format)) {
556         case 4: {
557                 u_int8_t silence = snd_pcm_format_silence_64(format);
558                 unsigned int samples1;
559                 if (samples % 2 != 0)
560                         return -EINVAL;
561                 samples1 = samples / 2;
562                 memset(data, silence, samples1);
563                 break;
564         }
565         case 8: {
566                 u_int8_t silence = snd_pcm_format_silence_64(format);
567                 memset(data, silence, samples);
568                 break;
569         }
570         case 16: {
571                 u_int16_t silence = snd_pcm_format_silence_64(format);
572                 u_int16_t *pdata = (u_int16_t *)data;
573                 if (! silence)
574                         memset(data, 0, samples * 2);
575                 else {
576                         while (samples-- > 0)
577                                 *pdata++ = silence;
578                 }
579                 break;
580         }
581         case 24: {
582                 u_int32_t silence = snd_pcm_format_silence_64(format);
583                 u_int8_t *pdata = (u_int8_t *)data;
584                 if (! silence)
585                         memset(data, 0, samples * 3);
586                 else {
587                         while (samples-- > 0) {
588 #ifdef SNDRV_LITTLE_ENDIAN
589                                 *pdata++ = silence >> 0;
590                                 *pdata++ = silence >> 8;
591                                 *pdata++ = silence >> 16;
592 #else
593                                 *pdata++ = silence >> 16;
594                                 *pdata++ = silence >> 8;
595                                 *pdata++ = silence >> 0;
596 #endif
597                         }
598                 }
599                 break;
600         }
601         case 32: {
602                 u_int32_t silence = snd_pcm_format_silence_64(format);
603                 u_int32_t *pdata = (u_int32_t *)data;
604                 if (! silence)
605                         memset(data, 0, samples * 4);
606                 else {
607                         while (samples-- > 0)
608                                 *pdata++ = silence;
609                 }
610                 break;
611         }
612         case 64: {
613                 u_int64_t silence = snd_pcm_format_silence_64(format);
614                 u_int64_t *pdata = (u_int64_t *)data;
615                 if (! silence)
616                         memset(data, 0, samples * 8);
617                 else {
618                         while (samples-- > 0)
619                                 *pdata++ = silence;
620                 }
621                 break;
622         }
623         default:
624                 assert(0);
625                 return -EINVAL;
626         }
627         return 0;
628 }
629
630 static const int linear_formats[4][2][2] = {
631         { { SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8 },
632           { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8 } },
633         { { SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE },
634           { SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE } },
635         { { SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE },
636           { SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE } },
637         { { SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE },
638           { SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE } }
639 };
640
641 static const int linear24_formats[3][2][2] = {
642         { { SNDRV_PCM_FORMAT_S24_3LE, SNDRV_PCM_FORMAT_S24_3BE },
643           { SNDRV_PCM_FORMAT_U24_3LE, SNDRV_PCM_FORMAT_U24_3BE } },
644         { { SNDRV_PCM_FORMAT_S20_3LE, SNDRV_PCM_FORMAT_S20_3BE },
645           { SNDRV_PCM_FORMAT_U20_3LE, SNDRV_PCM_FORMAT_U20_3BE } },
646         { { SNDRV_PCM_FORMAT_S18_3LE, SNDRV_PCM_FORMAT_S18_3BE },
647           { SNDRV_PCM_FORMAT_U18_3LE, SNDRV_PCM_FORMAT_U18_3BE } },
648 };
649
650 /**
651  * \brief Compose a PCM sample linear format
652  * \param width Nominal bits per sample
653  * \param pwidth Physical bit width of the format
654  * \param unsignd Sign: 0 signed, 1 unsigned
655  * \param big_endian Endian: 0 little endian, 1 big endian
656  * \return The matching format type, or #SND_PCM_FORMAT_UNKNOWN if no match
657  */
658 snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian)
659 {
660         if (pwidth == 24) {
661                 switch (width) {
662                 case 24:
663                         width = 0;
664                         break;
665                 case 20:
666                         width = 1;
667                         break;
668                 case 18:
669                         width = 2;
670                         break;
671                 default:
672                         return SND_PCM_FORMAT_UNKNOWN;
673                 }
674                 return linear24_formats[width][!!unsignd][!!big_endian];
675         } else {
676                 switch (width) {
677                 case 8:
678                         width = 0;
679                         break;
680                 case 16:
681                         width = 1;
682                         break;
683                 case 24:
684                         width = 2;
685                         break;
686                 case 32:
687                         width = 3;
688                         break;
689                 default:
690                         return SND_PCM_FORMAT_UNKNOWN;
691                 }
692                 return linear_formats[width][!!unsignd][!!big_endian];
693         }
694 }
695
696 /**
697  * \brief Parse control element id from the config
698  * \param conf the config tree to parse
699  * \param ctl_id the pointer to store the resultant control element id
700  * \param cardp the pointer to store the card index
701  * \param cchannelsp the pointer to store the number of channels (optional)
702  * \param hwctlp the pointer to store the h/w control flag (optional)
703  * \return 0 if successful, or a negative error code
704  *
705  * This function parses the given config tree to retrieve the control element id
706  * and the card index.  It's used by softvol.  External PCM plugins can use this
707  * function for creating or assigining their controls.
708  *
709  * cchannelsp and hwctlp arguments are optional.  Set NULL if not necessary.
710  */
711 int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp,
712                              int *cchannelsp, int *hwctlp)
713 {
714         snd_config_iterator_t i, next;
715         int iface = SND_CTL_ELEM_IFACE_MIXER;
716         const char *name = NULL;
717         long index = 0;
718         long device = -1;
719         long subdevice = -1;
720         int err;
721
722         assert(ctl_id && cardp);
723
724         *cardp = -1;
725         if (cchannelsp)
726                 *cchannelsp = 2;
727         snd_config_for_each(i, next, conf) {
728                 snd_config_t *n = snd_config_iterator_entry(i);
729                 const char *id;
730                 if (snd_config_get_id(n, &id) < 0)
731                         continue;
732                 if (strcmp(id, "comment") == 0)
733                         continue;
734                 if (strcmp(id, "card") == 0) {
735                         const char *str;
736                         long v;
737                         if ((err = snd_config_get_integer(n, &v)) < 0) {
738                                 if ((err = snd_config_get_string(n, &str)) < 0) {
739                                         SNDERR("Invalid field %s", id);
740                                         goto _err;
741                                 }
742                                 *cardp = snd_card_get_index(str);
743                                 if (*cardp < 0) {
744                                         SNDERR("Cannot get index for %s", str);
745                                         err = *cardp;
746                                         goto _err;
747                                 }
748                         } else
749                                 *cardp = v;
750                         continue;
751                 }
752                 if (strcmp(id, "iface") == 0 || strcmp(id, "interface") == 0) {
753                         const char *ptr;
754                         if ((err = snd_config_get_string(n, &ptr)) < 0) {
755                                 SNDERR("field %s is not a string", id);
756                                 goto _err;
757                         }
758                         if ((err = snd_config_get_ctl_iface_ascii(ptr)) < 0) {
759                                 SNDERR("Invalid value for '%s'", id);
760                                 goto _err;
761                         }
762                         iface = err;
763                         continue;
764                 }
765                 if (strcmp(id, "name") == 0) {
766                         if ((err = snd_config_get_string(n, &name)) < 0) {
767                                 SNDERR("field %s is not a string", id);
768                                 goto _err;
769                         }
770                         continue;
771                 }
772                 if (strcmp(id, "index") == 0) {
773                         if ((err = snd_config_get_integer(n, &index)) < 0) {
774                                 SNDERR("field %s is not an integer", id);
775                                 goto _err;
776                         }
777                         continue;
778                 }
779                 if (strcmp(id, "device") == 0) {
780                         if ((err = snd_config_get_integer(n, &device)) < 0) {
781                                 SNDERR("field %s is not an integer", id);
782                                 goto _err;
783                         }
784                         continue;
785                 }
786                 if (strcmp(id, "subdevice") == 0) {
787                         if ((err = snd_config_get_integer(n, &subdevice)) < 0) {
788                                 SNDERR("field %s is not an integer", id);
789                                 goto _err;
790                         }
791                         continue;
792                 }
793                 if (cchannelsp && strcmp(id, "count") == 0) {
794                         long v;
795                         if ((err = snd_config_get_integer(n, &v)) < 0) {
796                                 SNDERR("field %s is not an integer", id);
797                                 goto _err;
798                         }
799                         if (v < 1 || v > 2) {
800                                 SNDERR("Invalid count %ld", v);
801                                 goto _err;
802                         }
803                         *cchannelsp = v;
804                         continue;
805                 }
806                 if (hwctlp && strcmp(id, "hwctl") == 0) {
807                         if ((err = snd_config_get_bool(n)) < 0) {
808                                 SNDERR("The field %s must be a boolean type", id);
809                                 return err;
810                         }
811                         *hwctlp = err;
812                         continue;
813                 }
814                 SNDERR("Unknown field %s", id);
815                 return -EINVAL;
816         }
817         if (name == NULL) {
818                 SNDERR("Missing control name");
819                 err = -EINVAL;
820                 goto _err;
821         }
822         if (device < 0)
823                 device = 0;
824         if (subdevice < 0)
825                 subdevice = 0;
826
827         snd_ctl_elem_id_set_interface(ctl_id, iface);
828         snd_ctl_elem_id_set_name(ctl_id, name);
829         snd_ctl_elem_id_set_index(ctl_id, index);
830         snd_ctl_elem_id_set_device(ctl_id, device);
831         snd_ctl_elem_id_set_subdevice(ctl_id, subdevice);
832
833         return 0;
834
835  _err:
836         return err;
837 }