Initial Import
[profile/ivi/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                 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 }