OSDN Git Service

Merged pcm2 branch.
[android-x86/external-alsa-lib.git] / src / pcm / pcm_misc.c
1 /*
2  *  PCM Interface - misc routines
3  *  Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
4  *
5  *
6  *   This library is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU Library General Public License as
8  *   published by the Free Software Foundation; either version 2 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 Library General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Library General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21   
22 #ifdef __KERNEL__
23 #include "../include/driver.h"
24 #include "../include/pcm.h"
25 #include "../include/pcm_plugin.h"
26 #else
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <byteswap.h>
32 #include <errno.h>
33 #include <endian.h>
34 #include <byteswap.h>
35 #include "pcm_local.h"
36 #endif
37
38 int snd_pcm_format_signed(int format)
39 {
40         switch (format) {
41         case SND_PCM_SFMT_S8:
42         case SND_PCM_SFMT_S16_LE:
43         case SND_PCM_SFMT_S16_BE:
44         case SND_PCM_SFMT_S24_LE:
45         case SND_PCM_SFMT_S24_BE:
46         case SND_PCM_SFMT_S32_LE:
47         case SND_PCM_SFMT_S32_BE:
48                 return 1;
49         case SND_PCM_SFMT_U8:
50         case SND_PCM_SFMT_U16_LE:
51         case SND_PCM_SFMT_U16_BE:
52         case SND_PCM_SFMT_U24_LE:
53         case SND_PCM_SFMT_U24_BE:
54         case SND_PCM_SFMT_U32_LE:
55         case SND_PCM_SFMT_U32_BE:
56                 return 0;
57         default:
58                 return -EINVAL;
59         }
60 }
61
62 int snd_pcm_format_unsigned(int format)
63 {
64         int val;
65
66         val = snd_pcm_format_signed(format);
67         if (val >= 0)
68                 val ^= 1;
69         return val;
70 }
71
72 int snd_pcm_format_linear(int format)
73 {
74         return snd_pcm_format_signed(format) >= 0;
75 }
76
77 int snd_pcm_format_little_endian(int format)
78 {
79         switch (format) {
80         case SND_PCM_SFMT_S16_LE:
81         case SND_PCM_SFMT_U16_LE:
82         case SND_PCM_SFMT_S24_LE:
83         case SND_PCM_SFMT_U24_LE:
84         case SND_PCM_SFMT_S32_LE:
85         case SND_PCM_SFMT_U32_LE:
86         case SND_PCM_SFMT_FLOAT_LE:
87         case SND_PCM_SFMT_FLOAT64_LE:
88         case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
89                 return 1;
90         case SND_PCM_SFMT_S16_BE:
91         case SND_PCM_SFMT_U16_BE:
92         case SND_PCM_SFMT_S24_BE:
93         case SND_PCM_SFMT_U24_BE:
94         case SND_PCM_SFMT_S32_BE:
95         case SND_PCM_SFMT_U32_BE:
96         case SND_PCM_SFMT_FLOAT_BE:
97         case SND_PCM_SFMT_FLOAT64_BE:
98         case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
99                 return 0;
100         default:
101                 return -EINVAL;
102         }
103 }
104
105 int snd_pcm_format_big_endian(int format)
106 {
107         int val;
108
109         val = snd_pcm_format_little_endian(format);
110         if (val < 0)
111                 return val;
112         return !val;
113 }
114
115 int snd_pcm_format_width(int format)
116 {
117         switch (format) {
118         case SND_PCM_SFMT_S8:
119         case SND_PCM_SFMT_U8:
120                 return 8;
121         case SND_PCM_SFMT_S16_LE:
122         case SND_PCM_SFMT_S16_BE:
123         case SND_PCM_SFMT_U16_LE:
124         case SND_PCM_SFMT_U16_BE:
125                 return 16;
126         case SND_PCM_SFMT_S24_LE:
127         case SND_PCM_SFMT_S24_BE:
128         case SND_PCM_SFMT_U24_LE:
129         case SND_PCM_SFMT_U24_BE:
130                 return 24;
131         case SND_PCM_SFMT_S32_LE:
132         case SND_PCM_SFMT_S32_BE:
133         case SND_PCM_SFMT_U32_LE:
134         case SND_PCM_SFMT_U32_BE:
135         case SND_PCM_SFMT_FLOAT_LE:
136         case SND_PCM_SFMT_FLOAT_BE:
137                 return 32;
138         case SND_PCM_SFMT_FLOAT64_LE:
139         case SND_PCM_SFMT_FLOAT64_BE:
140                 return 64;
141         case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
142         case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
143                 return 24;
144         case SND_PCM_SFMT_MU_LAW:
145         case SND_PCM_SFMT_A_LAW:
146                 return 8;
147         case SND_PCM_SFMT_IMA_ADPCM:
148                 return 4;
149         default:
150                 return -EINVAL;
151         }
152 }
153
154 int snd_pcm_format_physical_width(int format)
155 {
156         switch (format) {
157         case SND_PCM_SFMT_S8:
158         case SND_PCM_SFMT_U8:
159                 return 8;
160         case SND_PCM_SFMT_S16_LE:
161         case SND_PCM_SFMT_S16_BE:
162         case SND_PCM_SFMT_U16_LE:
163         case SND_PCM_SFMT_U16_BE:
164                 return 16;
165         case SND_PCM_SFMT_S24_LE:
166         case SND_PCM_SFMT_S24_BE:
167         case SND_PCM_SFMT_U24_LE:
168         case SND_PCM_SFMT_U24_BE:
169         case SND_PCM_SFMT_S32_LE:
170         case SND_PCM_SFMT_S32_BE:
171         case SND_PCM_SFMT_U32_LE:
172         case SND_PCM_SFMT_U32_BE:
173         case SND_PCM_SFMT_FLOAT_LE:
174         case SND_PCM_SFMT_FLOAT_BE:
175         case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
176         case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
177                 return 32;
178         case SND_PCM_SFMT_FLOAT64_LE:
179         case SND_PCM_SFMT_FLOAT64_BE:
180                 return 64;
181         case SND_PCM_SFMT_MU_LAW:
182         case SND_PCM_SFMT_A_LAW:
183                 return 8;
184         case SND_PCM_SFMT_IMA_ADPCM:
185                 return 4;
186         default:
187                 return -EINVAL;
188         }
189 }
190
191 ssize_t snd_pcm_format_size(int format, size_t samples)
192 {
193         switch (format) {
194         case SND_PCM_SFMT_S8:
195         case SND_PCM_SFMT_U8:
196                 return samples;
197         case SND_PCM_SFMT_S16_LE:
198         case SND_PCM_SFMT_S16_BE:
199         case SND_PCM_SFMT_U16_LE:
200         case SND_PCM_SFMT_U16_BE:
201                 return samples * 2;
202         case SND_PCM_SFMT_S24_LE:
203         case SND_PCM_SFMT_S24_BE:
204         case SND_PCM_SFMT_U24_LE:
205         case SND_PCM_SFMT_U24_BE:
206         case SND_PCM_SFMT_S32_LE:
207         case SND_PCM_SFMT_S32_BE:
208         case SND_PCM_SFMT_U32_LE:
209         case SND_PCM_SFMT_U32_BE:
210         case SND_PCM_SFMT_FLOAT_LE:
211         case SND_PCM_SFMT_FLOAT_BE:
212                 return samples * 4;
213         case SND_PCM_SFMT_FLOAT64_LE:
214         case SND_PCM_SFMT_FLOAT64_BE:
215                 return samples * 8;
216         case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
217         case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
218                 return samples * 4;
219         case SND_PCM_SFMT_MU_LAW:
220         case SND_PCM_SFMT_A_LAW:
221                 return samples;
222         case SND_PCM_SFMT_IMA_ADPCM:
223                 if (samples & 1)
224                         return -EINVAL;
225                 return samples / 2;
226         default:
227                 return -EINVAL;
228         }
229 }
230
231 ssize_t snd_pcm_format_bytes_per_second(snd_pcm_format_t *format)
232 {
233         return snd_pcm_format_size(format->format, format->voices * format->rate);
234 }
235
236 const char *snd_pcm_get_format_name(int format)
237 {
238         static char *formats[] = {
239                 "Signed 8-bit",
240                 "Unsigned 8-bit",
241                 "Signed 16-bit Little Endian",
242                 "Signed 16-bit Big Endian",
243                 "Unsigned 16-bit Little Endian",
244                 "Unsigned 16-bit Big Endian",
245                 "Signed 24-bit Little Endian",
246                 "Signed 24-bit Big Endian",
247                 "Unsigned 24-bit Little Endian",
248                 "Unsigned 24-bit Big Endian",
249                 "Signed 32-bit Little Endian",
250                 "Signed 32-bit Big Endian",
251                 "Unsigned 32-bit Little Endian",
252                 "Unsigned 32-bit Big Endian",
253                 "Float Little Endian",
254                 "Float Big Endian",
255                 "Float64 Little Endian",
256                 "Float64 Big Endian",
257                 "IEC-958 Little Endian",
258                 "IEC-958 Big Endian",
259                 "Mu-Law",
260                 "A-Law",
261                 "Ima-ADPCM",
262                 "MPEG",
263                 "GSM"
264         };
265         if (format == SND_PCM_SFMT_SPECIAL)
266                 return "Special";
267         if (format < 0 || format > SND_PCM_SFMT_GSM)
268                 return "Unknown";
269         return formats[format];
270 }
271
272 u_int64_t snd_pcm_format_silence_64(int format)
273 {
274         switch (format) {
275         case SND_PCM_SFMT_S8:
276         case SND_PCM_SFMT_S16_LE:
277         case SND_PCM_SFMT_S16_BE:
278         case SND_PCM_SFMT_S24_LE:
279         case SND_PCM_SFMT_S24_BE:
280         case SND_PCM_SFMT_S32_LE:
281         case SND_PCM_SFMT_S32_BE:
282                 return 0;
283         case SND_PCM_SFMT_U8:
284                 return 0x8080808080808080UL;
285         case SND_PCM_SFMT_U16_LE:
286         case SND_PCM_SFMT_U24_LE:
287         case SND_PCM_SFMT_U32_LE:
288 #if defined(LITTLE_ENDIAN)
289                 return 0x8000800080008000UL;
290 #elif defined(BIG_ENDIAN)
291                 return 0x0080008000800080UL;
292 #else
293 #error "endian"
294 #endif
295         case SND_PCM_SFMT_U16_BE:
296         case SND_PCM_SFMT_U24_BE:
297         case SND_PCM_SFMT_U32_BE:
298 #if defined(LITTLE_ENDIAN)
299                 return 0x0000008000000080UL;
300 #elif defined(BIG_ENDIAN)
301                 return 0x8000000080000000UL;
302 #else
303 #error "endian"
304 #endif
305         case SND_PCM_SFMT_FLOAT_LE:             
306 #if defined(LITTLE_ENDIAN)
307                 return (float)0.0;
308 #elif defined(BIG_ENDIAN)
309                 return bswap_32((u_int32_t)((float)0.0));
310 #else
311 #error "endian"
312 #endif
313         case SND_PCM_SFMT_FLOAT64_LE:
314 #if defined(LITTLE_ENDIAN)
315                 return (double)0.0;
316 #elif defined(BIG_ENDIAN)
317                 return bswap_64((u_int64_t)((double)0.0));
318 #else
319 #error "endian"
320 #endif
321         case SND_PCM_SFMT_FLOAT_BE:             
322 #if defined(LITTLE_ENDIAN)
323                 return bswap_32((u_int32_t)((float)0.0));
324 #elif defined(BIG_ENDIAN)
325                 return (float)0.0;
326 #else
327 #error "endian"
328 #endif
329         case SND_PCM_SFMT_FLOAT64_BE:
330 #if defined(LITTLE_ENDIAN)
331                 return bswap_64((u_int64_t)((double)0.0));
332 #elif defined(BIG_ENDIAN)
333                 return (double)0.0;
334 #else
335 #error "endian"
336 #endif
337         case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
338         case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
339                 return 0;       
340         case SND_PCM_SFMT_MU_LAW:
341                 return 0x7f7f7f7f7f7f7f7fUL;
342         case SND_PCM_SFMT_A_LAW:
343                 return 0x5555555555555555UL;
344         case SND_PCM_SFMT_IMA_ADPCM:    /* special case */
345         case SND_PCM_SFMT_MPEG:
346         case SND_PCM_SFMT_GSM:
347                 return 0;
348         }
349         return 0;
350 }
351
352 u_int32_t snd_pcm_format_silence_32(int format)
353 {
354         return (u_int32_t)snd_pcm_format_silence_64(format);
355 }
356
357 u_int16_t snd_pcm_format_silence_16(int format)
358 {
359         return (u_int16_t)snd_pcm_format_silence_64(format);
360 }
361
362 u_int8_t snd_pcm_format_silence(int format)
363 {
364         return (u_int8_t)snd_pcm_format_silence_64(format);
365 }
366
367 ssize_t snd_pcm_format_set_silence(int format, void *data, size_t count)
368 {
369         size_t count1;
370         
371         if (count == 0)
372                 return 0;
373         switch (snd_pcm_format_width(format)) {
374         case 4:
375         case 8: {
376                 u_int8_t silence = snd_pcm_format_silence_64(format);
377                 memset(data, silence, count);
378                 break;
379         }
380         case 16: {
381                 u_int16_t silence = snd_pcm_format_silence_64(format);
382                 if (count % 2)
383                         return -EINVAL;
384                 count1 = count / 2;
385                 while (count1-- > 0)
386                         *((u_int16_t *)data)++ = silence;
387                 break;
388         }
389         case 32: {
390                 u_int32_t silence = snd_pcm_format_silence_64(format);
391                 if (count % 4)
392                         return -EINVAL;
393                 count1 = count / 4;
394                 while (count1-- > 0)
395                         *((u_int32_t *)data)++ = silence;
396                 break;
397         }
398         case 64: {
399                 u_int64_t silence = snd_pcm_format_silence_64(format);
400                 if (count % 8)
401                         return -EINVAL;
402                 count1 = count / 8;
403                 while (count1-- > 0)
404                         *((u_int64_t *)data)++ = silence;
405         }
406         default:
407                 return -EINVAL;
408         }
409         return count;
410 }
411
412 static int linear_formats[4*2*2] = {
413         SND_PCM_SFMT_S8,
414         SND_PCM_SFMT_U8,
415         SND_PCM_SFMT_S8,
416         SND_PCM_SFMT_U8,
417         SND_PCM_SFMT_S16_LE,
418         SND_PCM_SFMT_S16_BE,
419         SND_PCM_SFMT_U16_LE,
420         SND_PCM_SFMT_U16_BE,
421         SND_PCM_SFMT_S24_LE,
422         SND_PCM_SFMT_S24_BE,
423         SND_PCM_SFMT_U24_LE,
424         SND_PCM_SFMT_U24_BE,
425         SND_PCM_SFMT_S32_LE,
426         SND_PCM_SFMT_S32_BE,
427         SND_PCM_SFMT_U32_LE,
428         SND_PCM_SFMT_U32_BE
429 };
430
431 int snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
432 {
433         switch (width) {
434         case 8:
435                 width = 0;
436                 break;
437         case 16:
438                 width = 1;
439                 break;
440         case 24:
441                 width = 2;
442                 break;
443         case 32:
444                 width = 3;
445                 break;
446         default:
447                 return -1;
448         }
449         return ((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian];
450 }