sndfile-util: fix format for 24bit depth wav files
[platform/upstream/pulseaudio.git] / src / pulsecore / sndfile-util.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2009 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 /* Shared between pacat/parec/paplay and the server */
27
28 #include <pulse/xmalloc.h>
29 #include <pulse/utf8.h>
30
31 #include <pulsecore/macro.h>
32
33 #include "sndfile-util.h"
34
35 int pa_sndfile_read_sample_spec(SNDFILE *sf, pa_sample_spec *ss) {
36     SF_INFO sfi;
37     int sf_errno;
38
39     pa_assert(sf);
40     pa_assert(ss);
41
42     pa_zero(sfi);
43     if ((sf_errno = sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)))) {
44         pa_log_error("sndfile: %s", sf_error_number(sf_errno));
45         return -1;
46     }
47
48     switch (sfi.format & SF_FORMAT_SUBMASK) {
49
50         case SF_FORMAT_PCM_16:
51         case SF_FORMAT_PCM_U8:
52         case SF_FORMAT_PCM_S8:
53             ss->format = PA_SAMPLE_S16NE;
54             break;
55
56         case SF_FORMAT_PCM_24:
57             ss->format = PA_SAMPLE_S24NE;
58             break;
59
60         case SF_FORMAT_PCM_32:
61             ss->format = PA_SAMPLE_S32NE;
62             break;
63
64         case SF_FORMAT_ULAW:
65             ss->format = PA_SAMPLE_ULAW;
66             break;
67
68         case SF_FORMAT_ALAW:
69             ss->format = PA_SAMPLE_ALAW;
70             break;
71
72         case SF_FORMAT_FLOAT:
73         case SF_FORMAT_DOUBLE:
74         default:
75             ss->format = PA_SAMPLE_FLOAT32NE;
76             break;
77     }
78
79     ss->rate = (uint32_t) sfi.samplerate;
80     ss->channels = (uint8_t) sfi.channels;
81
82     if (!pa_sample_spec_valid(ss))
83         return -1;
84
85     return 0;
86 }
87
88 int pa_sndfile_write_sample_spec(SF_INFO *sfi, pa_sample_spec *ss) {
89     pa_assert(sfi);
90     pa_assert(ss);
91
92     sfi->samplerate = (int) ss->rate;
93     sfi->channels = (int) ss->channels;
94
95     if (pa_sample_format_is_le(ss->format) > 0)
96         sfi->format = SF_ENDIAN_LITTLE;
97     else if (pa_sample_format_is_be(ss->format) > 0)
98         sfi->format = SF_ENDIAN_BIG;
99
100     switch (ss->format) {
101
102         case PA_SAMPLE_U8:
103             ss->format = PA_SAMPLE_S16NE;
104             sfi->format = SF_FORMAT_PCM_U8;
105             break;
106
107         case PA_SAMPLE_S16LE:
108         case PA_SAMPLE_S16BE:
109             ss->format = PA_SAMPLE_S16NE;
110             sfi->format |= SF_FORMAT_PCM_16;
111             break;
112
113         case PA_SAMPLE_S24LE:
114         case PA_SAMPLE_S24BE:
115             ss->format = PA_SAMPLE_S24NE;
116             sfi->format |= SF_FORMAT_PCM_24;
117             break;
118
119         case PA_SAMPLE_S24_32LE:
120         case PA_SAMPLE_S24_32BE:
121             ss->format = PA_SAMPLE_S24_32NE;
122             sfi->format |= SF_FORMAT_PCM_32;
123             break;
124
125         case PA_SAMPLE_S32LE:
126         case PA_SAMPLE_S32BE:
127             ss->format = PA_SAMPLE_S32NE;
128             sfi->format |= SF_FORMAT_PCM_32;
129             break;
130
131         case PA_SAMPLE_ULAW:
132             sfi->format = SF_FORMAT_ULAW;
133             break;
134
135         case PA_SAMPLE_ALAW:
136             sfi->format = SF_FORMAT_ALAW;
137             break;
138
139         case PA_SAMPLE_FLOAT32LE:
140         case PA_SAMPLE_FLOAT32BE:
141         default:
142             ss->format = PA_SAMPLE_FLOAT32NE;
143             sfi->format |= SF_FORMAT_FLOAT;
144             break;
145     }
146
147     if (!pa_sample_spec_valid(ss))
148         return -1;
149
150     return 0;
151 }
152
153 int pa_sndfile_read_channel_map(SNDFILE *sf, pa_channel_map *cm) {
154
155     static const pa_channel_position_t table[] = {
156         [SF_CHANNEL_MAP_MONO] =                  PA_CHANNEL_POSITION_MONO,
157         [SF_CHANNEL_MAP_LEFT] =                  PA_CHANNEL_POSITION_FRONT_LEFT, /* libsndfile distinguishes left and front-left, which we don't */
158         [SF_CHANNEL_MAP_RIGHT] =                 PA_CHANNEL_POSITION_FRONT_RIGHT,
159         [SF_CHANNEL_MAP_CENTER] =                PA_CHANNEL_POSITION_FRONT_CENTER,
160         [SF_CHANNEL_MAP_FRONT_LEFT] =            PA_CHANNEL_POSITION_FRONT_LEFT,
161         [SF_CHANNEL_MAP_FRONT_RIGHT] =           PA_CHANNEL_POSITION_FRONT_RIGHT,
162         [SF_CHANNEL_MAP_FRONT_CENTER] =          PA_CHANNEL_POSITION_FRONT_CENTER,
163         [SF_CHANNEL_MAP_REAR_CENTER] =           PA_CHANNEL_POSITION_REAR_CENTER,
164         [SF_CHANNEL_MAP_REAR_LEFT] =             PA_CHANNEL_POSITION_REAR_LEFT,
165         [SF_CHANNEL_MAP_REAR_RIGHT] =            PA_CHANNEL_POSITION_REAR_RIGHT,
166         [SF_CHANNEL_MAP_LFE] =                   PA_CHANNEL_POSITION_LFE,
167         [SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER] =  PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
168         [SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
169         [SF_CHANNEL_MAP_SIDE_LEFT] =             PA_CHANNEL_POSITION_SIDE_LEFT,
170         [SF_CHANNEL_MAP_SIDE_RIGHT] =            PA_CHANNEL_POSITION_SIDE_RIGHT,
171         [SF_CHANNEL_MAP_TOP_CENTER] =            PA_CHANNEL_POSITION_TOP_CENTER,
172         [SF_CHANNEL_MAP_TOP_FRONT_LEFT] =        PA_CHANNEL_POSITION_TOP_FRONT_LEFT,
173         [SF_CHANNEL_MAP_TOP_FRONT_RIGHT] =       PA_CHANNEL_POSITION_TOP_FRONT_RIGHT,
174         [SF_CHANNEL_MAP_TOP_FRONT_CENTER] =      PA_CHANNEL_POSITION_TOP_FRONT_CENTER,
175         [SF_CHANNEL_MAP_TOP_REAR_LEFT] =         PA_CHANNEL_POSITION_TOP_REAR_LEFT,
176         [SF_CHANNEL_MAP_TOP_REAR_RIGHT] =        PA_CHANNEL_POSITION_TOP_REAR_RIGHT,
177         [SF_CHANNEL_MAP_TOP_REAR_CENTER] =       PA_CHANNEL_POSITION_TOP_REAR_CENTER
178     };
179
180     SF_INFO sfi;
181     int sf_errno;
182     int *channels;
183     unsigned c;
184
185     pa_assert(sf);
186     pa_assert(cm);
187
188     pa_zero(sfi);
189     if ((sf_errno = sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)))) {
190         pa_log_error("sndfile: %s", sf_error_number(sf_errno));
191         return -1;
192     }
193
194     channels = pa_xnew(int, sfi.channels);
195     if (!sf_command(sf, SFC_GET_CHANNEL_MAP_INFO, channels, sizeof(channels[0]) * sfi.channels)) {
196         pa_xfree(channels);
197         return -1;
198     }
199
200     cm->channels = (uint8_t) sfi.channels;
201     for (c = 0; c < cm->channels; c++) {
202         if (channels[c] <= SF_CHANNEL_MAP_INVALID ||
203             (unsigned) channels[c] >= PA_ELEMENTSOF(table)) {
204             pa_xfree(channels);
205             return -1;
206         }
207
208         cm->map[c] = table[channels[c]];
209     }
210
211     pa_xfree(channels);
212
213     if (!pa_channel_map_valid(cm))
214         return -1;
215
216     return 0;
217 }
218
219 int pa_sndfile_write_channel_map(SNDFILE *sf, pa_channel_map *cm) {
220     static const int table[PA_CHANNEL_POSITION_MAX] = {
221         [PA_CHANNEL_POSITION_MONO] = SF_CHANNEL_MAP_MONO,
222
223         [PA_CHANNEL_POSITION_FRONT_LEFT] = SF_CHANNEL_MAP_FRONT_LEFT,
224         [PA_CHANNEL_POSITION_FRONT_RIGHT] = SF_CHANNEL_MAP_FRONT_RIGHT,
225         [PA_CHANNEL_POSITION_FRONT_CENTER] = SF_CHANNEL_MAP_FRONT_CENTER,
226
227         [PA_CHANNEL_POSITION_REAR_CENTER] = SF_CHANNEL_MAP_REAR_CENTER,
228         [PA_CHANNEL_POSITION_REAR_LEFT] = SF_CHANNEL_MAP_REAR_LEFT,
229         [PA_CHANNEL_POSITION_REAR_RIGHT] = SF_CHANNEL_MAP_REAR_RIGHT,
230
231         [PA_CHANNEL_POSITION_LFE] = SF_CHANNEL_MAP_LFE,
232
233         [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER,
234         [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER,
235
236         [PA_CHANNEL_POSITION_SIDE_LEFT] = SF_CHANNEL_MAP_SIDE_LEFT,
237         [PA_CHANNEL_POSITION_SIDE_RIGHT] = SF_CHANNEL_MAP_SIDE_RIGHT,
238
239         [PA_CHANNEL_POSITION_AUX0] = -1,
240         [PA_CHANNEL_POSITION_AUX1] = -1,
241         [PA_CHANNEL_POSITION_AUX2] = -1,
242         [PA_CHANNEL_POSITION_AUX3] = -1,
243         [PA_CHANNEL_POSITION_AUX4] = -1,
244         [PA_CHANNEL_POSITION_AUX5] = -1,
245         [PA_CHANNEL_POSITION_AUX6] = -1,
246         [PA_CHANNEL_POSITION_AUX7] = -1,
247         [PA_CHANNEL_POSITION_AUX8] = -1,
248         [PA_CHANNEL_POSITION_AUX9] = -1,
249         [PA_CHANNEL_POSITION_AUX10] = -1,
250         [PA_CHANNEL_POSITION_AUX11] = -1,
251         [PA_CHANNEL_POSITION_AUX12] = -1,
252         [PA_CHANNEL_POSITION_AUX13] = -1,
253         [PA_CHANNEL_POSITION_AUX14] = -1,
254         [PA_CHANNEL_POSITION_AUX15] = -1,
255         [PA_CHANNEL_POSITION_AUX16] = -1,
256         [PA_CHANNEL_POSITION_AUX17] = -1,
257         [PA_CHANNEL_POSITION_AUX18] = -1,
258         [PA_CHANNEL_POSITION_AUX19] = -1,
259         [PA_CHANNEL_POSITION_AUX20] = -1,
260         [PA_CHANNEL_POSITION_AUX21] = -1,
261         [PA_CHANNEL_POSITION_AUX22] = -1,
262         [PA_CHANNEL_POSITION_AUX23] = -1,
263         [PA_CHANNEL_POSITION_AUX24] = -1,
264         [PA_CHANNEL_POSITION_AUX25] = -1,
265         [PA_CHANNEL_POSITION_AUX26] = -1,
266         [PA_CHANNEL_POSITION_AUX27] = -1,
267         [PA_CHANNEL_POSITION_AUX28] = -1,
268         [PA_CHANNEL_POSITION_AUX29] = -1,
269         [PA_CHANNEL_POSITION_AUX30] = -1,
270         [PA_CHANNEL_POSITION_AUX31] = -1,
271
272         [PA_CHANNEL_POSITION_TOP_CENTER] = SF_CHANNEL_MAP_TOP_CENTER,
273
274         [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SF_CHANNEL_MAP_TOP_FRONT_LEFT,
275         [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SF_CHANNEL_MAP_TOP_FRONT_RIGHT,
276         [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SF_CHANNEL_MAP_TOP_FRONT_CENTER ,
277
278         [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SF_CHANNEL_MAP_TOP_REAR_LEFT,
279         [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SF_CHANNEL_MAP_TOP_REAR_RIGHT,
280         [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SF_CHANNEL_MAP_TOP_REAR_CENTER,
281     };
282
283     int *channels;
284     unsigned c;
285
286     pa_assert(sf);
287     pa_assert(cm);
288
289     /* Suppress channel mapping for the obvious cases */
290     if (cm->channels == 1 && cm->map[0] == PA_CHANNEL_POSITION_MONO)
291         return 0;
292
293     if (cm->channels == 2 &&
294         cm->map[0] == PA_CHANNEL_POSITION_FRONT_LEFT &&
295         cm->map[1] == PA_CHANNEL_POSITION_FRONT_RIGHT)
296         return 0;
297
298     channels = pa_xnew(int, cm->channels);
299     for (c = 0; c < cm->channels; c++) {
300
301         if (cm->map[c] < 0 ||
302             cm->map[c] >= PA_CHANNEL_POSITION_MAX ||
303             table[cm->map[c]] < 0) {
304             pa_xfree(channels);
305             return -1;
306         }
307
308         channels[c] = table[cm->map[c]];
309     }
310
311     if (!sf_command(sf, SFC_SET_CHANNEL_MAP_INFO, channels, sizeof(channels[0]) * cm->channels)) {
312         pa_xfree(channels);
313         return -1;
314     }
315
316     pa_xfree(channels);
317     return 0;
318 }
319
320 void pa_sndfile_init_proplist(SNDFILE *sf, pa_proplist *p) {
321
322     static const char* table[] = {
323         [SF_STR_TITLE] = PA_PROP_MEDIA_TITLE,
324         [SF_STR_COPYRIGHT] = PA_PROP_MEDIA_COPYRIGHT,
325         [SF_STR_SOFTWARE] = PA_PROP_MEDIA_SOFTWARE,
326         [SF_STR_ARTIST] = PA_PROP_MEDIA_ARTIST,
327         [SF_STR_COMMENT] = "media.comment",
328         [SF_STR_DATE] = "media.date"
329     };
330
331     SF_INFO sfi;
332     SF_FORMAT_INFO fi;
333     int sf_errno;
334     unsigned c;
335
336     pa_assert(sf);
337     pa_assert(p);
338
339     for (c = 0; c < PA_ELEMENTSOF(table); c++) {
340         const char *s;
341         char *t;
342
343         if (!table[c])
344             continue;
345
346         if (!(s = sf_get_string(sf, c)))
347             continue;
348
349         t = pa_utf8_filter(s);
350         pa_proplist_sets(p, table[c], t);
351         pa_xfree(t);
352     }
353
354     pa_zero(sfi);
355     if ((sf_errno = sf_command(sf, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)))) {
356         pa_log_error("sndfile: %s", sf_error_number(sf_errno));
357         return;
358     }
359
360     pa_zero(fi);
361     fi.format = sfi.format;
362     if (sf_command(sf, SFC_GET_FORMAT_INFO, &fi, sizeof(fi)) == 0 && fi.name) {
363         char *t;
364
365         t = pa_utf8_filter(fi.name);
366         pa_proplist_sets(p, "media.format", t);
367         pa_xfree(t);
368     }
369 }
370
371 pa_sndfile_readf_t pa_sndfile_readf_function(const pa_sample_spec *ss) {
372     pa_assert(ss);
373
374     switch (ss->format) {
375         case PA_SAMPLE_S16NE:
376             return (pa_sndfile_readf_t) sf_readf_short;
377
378         case PA_SAMPLE_S32NE:
379         case PA_SAMPLE_S24_32NE:
380             return (pa_sndfile_readf_t) sf_readf_int;
381
382         case PA_SAMPLE_FLOAT32NE:
383             return (pa_sndfile_readf_t) sf_readf_float;
384
385         case PA_SAMPLE_ULAW:
386         case PA_SAMPLE_ALAW:
387         case PA_SAMPLE_S24NE:
388             return NULL;
389
390         default:
391             pa_assert_not_reached();
392     }
393 }
394
395 pa_sndfile_writef_t pa_sndfile_writef_function(const pa_sample_spec *ss) {
396     pa_assert(ss);
397
398     switch (ss->format) {
399         case PA_SAMPLE_S16NE:
400             return (pa_sndfile_writef_t) sf_writef_short;
401
402         case PA_SAMPLE_S32NE:
403         case PA_SAMPLE_S24_32NE:
404             return (pa_sndfile_writef_t) sf_writef_int;
405
406         case PA_SAMPLE_FLOAT32NE:
407             return (pa_sndfile_writef_t) sf_writef_float;
408
409         case PA_SAMPLE_ULAW:
410         case PA_SAMPLE_ALAW:
411         case PA_SAMPLE_S24NE:
412             return NULL;
413
414         default:
415             pa_assert_not_reached();
416     }
417 }
418
419 int pa_sndfile_format_from_string(const char *name) {
420     int i, count = 0;
421
422     if (!name[0])
423         return -1;
424
425     pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(int)) == 0);
426
427     for (i = 0; i < count; i++) {
428         SF_FORMAT_INFO fi;
429         pa_zero(fi);
430         fi.format = i;
431
432         pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR, &fi, sizeof(fi)) == 0);
433
434         /* First try to match via full type string */
435         if (strcasecmp(name, fi.name) == 0)
436             return fi.format;
437
438         /* Then, try to match via the full extension */
439         if (strcasecmp(name, fi.extension) == 0)
440             return fi.format;
441
442         /* Then, try to match via the start of the type string */
443         if (strncasecmp(name, fi.name, strlen(name)) == 0)
444             return fi.format;
445     }
446
447     return -1;
448 }
449
450 void pa_sndfile_dump_formats(void) {
451     int i, count = 0;
452
453     pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(int)) == 0);
454
455     for (i = 0; i < count; i++) {
456         SF_FORMAT_INFO fi;
457         pa_zero(fi);
458         fi.format = i;
459
460         pa_assert_se(sf_command(NULL, SFC_GET_FORMAT_MAJOR, &fi, sizeof(fi)) == 0);
461         printf("%s\t%s\n", fi.extension, fi.name);
462     }
463 }