OSDN Git Service

fixed compile warnings.
[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@suse.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 24;
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  * \return samples Samples count
545  */
546 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
547 {
548         if (samples == 0)
549                 return 0;
550         switch (snd_pcm_format_physical_width(format)) {
551         case 4: {
552                 u_int8_t silence = snd_pcm_format_silence_64(format);
553                 unsigned int samples1;
554                 if (samples % 2 != 0)
555                         return -EINVAL;
556                 samples1 = samples / 2;
557                 memset(data, silence, samples1);
558                 break;
559         }
560         case 8: {
561                 u_int8_t silence = snd_pcm_format_silence_64(format);
562                 memset(data, silence, samples);
563                 break;
564         }
565         case 16: {
566                 u_int16_t silence = snd_pcm_format_silence_64(format);
567                 u_int16_t *pdata = (u_int16_t *)data;
568                 if (! silence)
569                         memset(data, 0, samples * 2);
570                 else {
571                         while (samples-- > 0)
572                                 *pdata++ = silence;
573                 }
574                 break;
575         }
576         case 24: {
577                 u_int32_t silence = snd_pcm_format_silence_64(format);
578                 u_int8_t *pdata = (u_int8_t *)data;
579                 if (! silence)
580                         memset(data, 0, samples * 3);
581                 else {
582                         while (samples-- > 0) {
583 #ifdef SNDRV_LITTLE_ENDIAN
584                                 *pdata++ = silence >> 0;
585                                 *pdata++ = silence >> 8;
586                                 *pdata++ = silence >> 16;
587 #else
588                                 *pdata++ = silence >> 16;
589                                 *pdata++ = silence >> 8;
590                                 *pdata++ = silence >> 0;
591 #endif
592                         }
593                 }
594                 break;
595         }
596         case 32: {
597                 u_int32_t silence = snd_pcm_format_silence_64(format);
598                 u_int32_t *pdata = (u_int32_t *)data;
599                 if (! silence)
600                         memset(data, 0, samples * 4);
601                 else {
602                         while (samples-- > 0)
603                                 *pdata++ = silence;
604                 }
605                 break;
606         }
607         case 64: {
608                 u_int64_t silence = snd_pcm_format_silence_64(format);
609                 u_int64_t *pdata = (u_int64_t *)data;
610                 if (! silence)
611                         memset(data, 0, samples * 8);
612                 else {
613                         while (samples-- > 0)
614                                 *pdata++ = silence;
615                 }
616                 break;
617         }
618         default:
619                 assert(0);
620                 return -EINVAL;
621         }
622         return 0;
623 }
624
625 static int linear_formats[4*2*2] = {
626         SNDRV_PCM_FORMAT_S8,
627         SNDRV_PCM_FORMAT_S8,
628         SNDRV_PCM_FORMAT_U8,
629         SNDRV_PCM_FORMAT_U8,
630         SNDRV_PCM_FORMAT_S16_LE,
631         SNDRV_PCM_FORMAT_S16_BE,
632         SNDRV_PCM_FORMAT_U16_LE,
633         SNDRV_PCM_FORMAT_U16_BE,
634         SNDRV_PCM_FORMAT_S24_LE,
635         SNDRV_PCM_FORMAT_S24_BE,
636         SNDRV_PCM_FORMAT_U24_LE,
637         SNDRV_PCM_FORMAT_U24_BE,
638         SNDRV_PCM_FORMAT_S32_LE,
639         SNDRV_PCM_FORMAT_S32_BE,
640         SNDRV_PCM_FORMAT_U32_LE,
641         SNDRV_PCM_FORMAT_U32_BE
642 };
643
644 static int linear24_formats[3*2*2] = {
645         SNDRV_PCM_FORMAT_S24_3LE,
646         SNDRV_PCM_FORMAT_S24_3BE,
647         SNDRV_PCM_FORMAT_U24_3LE,
648         SNDRV_PCM_FORMAT_U24_3BE,
649         SNDRV_PCM_FORMAT_S20_3LE,
650         SNDRV_PCM_FORMAT_S20_3BE,
651         SNDRV_PCM_FORMAT_U20_3LE,
652         SNDRV_PCM_FORMAT_U20_3BE,
653         SNDRV_PCM_FORMAT_S18_3LE,
654         SNDRV_PCM_FORMAT_S18_3BE,
655         SNDRV_PCM_FORMAT_U18_3LE,
656         SNDRV_PCM_FORMAT_U18_3BE,
657 };
658
659 /**
660  * \brief Compose a PCM sample linear format
661  * \param width Nominal bits per sample
662  * \param pwidth Physical bit width of the format
663  * \param unsignd Sign: 0 signed, 1 unsigned
664  * \return big_endian Endian: 0 little endian, 1 big endian
665  */
666 snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian)
667 {
668         if (pwidth == 24) {
669                 switch (width) {
670                 case 24:
671                         width = 0;
672                         break;
673                 case 20:
674                         width = 1;
675                         break;
676                 case 18:
677                         width = 2;
678                         break;
679                 default:
680                         return SND_PCM_FORMAT_UNKNOWN;
681                 }
682                 return ((int(*)[2][2])linear24_formats)[width][!!unsignd][!!big_endian];
683         } else {
684                 switch (width) {
685                 case 8:
686                         width = 0;
687                         break;
688                 case 16:
689                         width = 1;
690                         break;
691                 case 24:
692                         width = 2;
693                         break;
694                 case 32:
695                         width = 3;
696                         break;
697                 default:
698                         return SND_PCM_FORMAT_UNKNOWN;
699                 }
700                 return ((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian];
701         }
702 }