OSDN Git Service

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