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