xref: /third_party/alsa-lib/src/pcm/pcm_misc.c (revision d5ac70f0)
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 "pcm_local.h"
23#include "bswap.h"
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <string.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 */
35int 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 */
85int 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 */
100int 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 */
110int 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 */
128int 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 */
181int 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 */
196int 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 the bit-width of the format
207 * \param format Sample format
208 * \return the bit-width of the format, or a negative error code if not applicable
209 */
210int 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 the physical bit-width of the format (bits needed to store a PCM sample)
274 * \param format Sample format
275 * \return the physical bit-width of the format, or a negative error code if not applicable
276 */
277int 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 */
342ssize_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 */
410uint64_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 */
572uint32_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 */
583uint16_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 */
594uint8_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 */
607int 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
686static 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
699static 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 */
716snd_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 */
773int 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