• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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