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