OSDN Git Service

Fix shortened floating point WAV file write
[android-x86/system-media.git] / audio_utils / tinysndfile.c
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <audio_utils/sndfile.h>
18 #include <audio_utils/primitives.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22
23 #define WAVE_FORMAT_PCM         1
24 #define WAVE_FORMAT_IEEE_FLOAT  3
25 #define WAVE_FORMAT_EXTENSIBLE  0xFFFE
26
27 struct SNDFILE_ {
28     int mode;
29     uint8_t *temp;  // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping
30     FILE *stream;
31     size_t bytesPerFrame;
32     size_t remaining;   // frames unread for SFM_READ, frames written for SFM_WRITE
33     SF_INFO info;
34 };
35
36 static unsigned little2u(unsigned char *ptr)
37 {
38     return (ptr[1] << 8) + ptr[0];
39 }
40
41 static unsigned little4u(unsigned char *ptr)
42 {
43     return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0];
44 }
45
46 static int isLittleEndian(void)
47 {
48     static const short one = 1;
49     return *((const char *) &one) == 1;
50 }
51
52 // "swab" conflicts with OS X <string.h>
53 static void my_swab(short *ptr, size_t numToSwap)
54 {
55     while (numToSwap > 0) {
56         *ptr = little2u((unsigned char *) ptr);
57         --numToSwap;
58         ++ptr;
59     }
60 }
61
62 static SNDFILE *sf_open_read(const char *path, SF_INFO *info)
63 {
64     FILE *stream = fopen(path, "rb");
65     if (stream == NULL) {
66         fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
67         return NULL;
68     }
69
70     SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
71     handle->mode = SFM_READ;
72     handle->temp = NULL;
73     handle->stream = stream;
74     handle->info.format = SF_FORMAT_WAV;
75
76     // don't attempt to parse all valid forms, just the most common ones
77     unsigned char wav[12];
78     size_t actual;
79     actual = fread(wav, sizeof(char), sizeof(wav), stream);
80     if (actual < 12) {
81         fprintf(stderr, "actual %zu < 44\n", actual);
82         goto close;
83     }
84     if (memcmp(wav, "RIFF", 4)) {
85         fprintf(stderr, "wav != RIFF\n");
86         goto close;
87     }
88     unsigned riffSize = little4u(&wav[4]);
89     if (riffSize < 4) {
90         fprintf(stderr, "riffSize %u < 4\n", riffSize);
91         goto close;
92     }
93     if (memcmp(&wav[8], "WAVE", 4)) {
94         fprintf(stderr, "missing WAVE\n");
95         goto close;
96     }
97     size_t remaining = riffSize - 4;
98     int hadFmt = 0;
99     int hadData = 0;
100     while (remaining >= 8) {
101         unsigned char chunk[8];
102         actual = fread(chunk, sizeof(char), sizeof(chunk), stream);
103         if (actual != sizeof(chunk)) {
104             fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk));
105             goto close;
106         }
107         remaining -= 8;
108         unsigned chunkSize = little4u(&chunk[4]);
109         if (chunkSize > remaining) {
110             fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining);
111             goto close;
112         }
113         if (!memcmp(&chunk[0], "fmt ", 4)) {
114             if (hadFmt) {
115                 fprintf(stderr, "multiple fmt\n");
116                 goto close;
117             }
118             if (chunkSize < 2) {
119                 fprintf(stderr, "chunkSize %u < 2\n", chunkSize);
120                 goto close;
121             }
122             unsigned char fmt[40];
123             actual = fread(fmt, sizeof(char), 2, stream);
124             if (actual != 2) {
125                 fprintf(stderr, "actual %zu != 2\n", actual);
126                 goto close;
127             }
128             unsigned format = little2u(&fmt[0]);
129             size_t minSize = 0;
130             switch (format) {
131             case WAVE_FORMAT_PCM:
132             case WAVE_FORMAT_IEEE_FLOAT:
133                 minSize = 16;
134                 break;
135             case WAVE_FORMAT_EXTENSIBLE:
136                 minSize = 40;
137                 break;
138             default:
139                 fprintf(stderr, "unsupported format %u\n", format);
140                 goto close;
141             }
142             if (chunkSize < minSize) {
143                 fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize);
144                 goto close;
145             }
146             actual = fread(&fmt[2], sizeof(char), minSize - 2, stream);
147             if (actual != minSize - 2) {
148                 fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16);
149                 goto close;
150             }
151             if (chunkSize > minSize) {
152                 fseek(stream, (long) (chunkSize - minSize), SEEK_CUR);
153             }
154             unsigned channels = little2u(&fmt[2]);
155             if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) {
156                 fprintf(stderr, "unsupported channels %u\n", channels);
157                 goto close;
158             }
159             unsigned samplerate = little4u(&fmt[4]);
160             if (samplerate == 0) {
161                 fprintf(stderr, "samplerate %u == 0\n", samplerate);
162                 goto close;
163             }
164             // ignore byte rate
165             // ignore block alignment
166             unsigned bitsPerSample = little2u(&fmt[14]);
167             if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32) {
168                 fprintf(stderr, "bitsPerSample %u != 8 or 16 or 32\n", bitsPerSample);
169                 goto close;
170             }
171             unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
172             handle->bytesPerFrame = bytesPerFrame;
173             handle->info.samplerate = samplerate;
174             handle->info.channels = channels;
175             switch (bitsPerSample) {
176             case 8:
177                 handle->info.format |= SF_FORMAT_PCM_U8;
178                 break;
179             case 16:
180                 handle->info.format |= SF_FORMAT_PCM_16;
181                 break;
182             case 32:
183                 if (format == WAVE_FORMAT_IEEE_FLOAT)
184                     handle->info.format |= SF_FORMAT_FLOAT;
185                 else
186                     handle->info.format |= SF_FORMAT_PCM_32;
187                 break;
188             }
189             hadFmt = 1;
190         } else if (!memcmp(&chunk[0], "data", 4)) {
191             if (!hadFmt) {
192                 fprintf(stderr, "data not preceded by fmt\n");
193                 goto close;
194             }
195             if (hadData) {
196                 fprintf(stderr, "multiple data\n");
197                 goto close;
198             }
199             handle->remaining = chunkSize / handle->bytesPerFrame;
200             handle->info.frames = handle->remaining;
201             hadData = 1;
202         } else if (!memcmp(&chunk[0], "fact", 4)) {
203             // ignore fact
204             if (chunkSize > 0) {
205                 fseek(stream, (long) chunkSize, SEEK_CUR);
206             }
207         } else {
208             // ignore unknown chunk
209             fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n",
210                     chunk[0], chunk[1], chunk[2], chunk[3]);
211             if (chunkSize > 0) {
212                 fseek(stream, (long) chunkSize, SEEK_CUR);
213             }
214         }
215         remaining -= chunkSize;
216     }
217     if (remaining > 0) {
218         fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining);
219         goto close;
220     }
221     if (!hadData) {
222         fprintf(stderr, "missing data\n");
223         goto close;
224     }
225     *info = handle->info;
226     return handle;
227
228 close:
229     free(handle);
230     fclose(stream);
231     return NULL;
232 }
233
234 static void write4u(unsigned char *ptr, unsigned u)
235 {
236     ptr[0] = u;
237     ptr[1] = u >> 8;
238     ptr[2] = u >> 16;
239     ptr[3] = u >> 24;
240 }
241
242 static SNDFILE *sf_open_write(const char *path, SF_INFO *info)
243 {
244     int sub = info->format & SF_FORMAT_SUBMASK;
245     if (!(
246             (info->samplerate > 0) &&
247             (info->channels > 0 && info->channels <= 8) &&
248             ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) &&
249             (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT)
250           )) {
251         return NULL;
252     }
253     FILE *stream = fopen(path, "w+b");
254     if (stream == NULL) {
255         fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
256         return NULL;
257     }
258     unsigned char wav[58];
259     memset(wav, 0, sizeof(wav));
260     memcpy(wav, "RIFF", 4);
261     memcpy(&wav[8], "WAVEfmt ", 8);
262     if (sub == SF_FORMAT_FLOAT) {
263         wav[4] = 50;    // riffSize
264         wav[16] = 18;   // fmtSize
265         wav[20] = WAVE_FORMAT_IEEE_FLOAT;
266     } else {
267         wav[4] = 36;    // riffSize
268         wav[16] = 16;   // fmtSize
269         wav[20] = WAVE_FORMAT_PCM;
270     }
271     wav[22] = info->channels;
272     write4u(&wav[24], info->samplerate);
273     unsigned bitsPerSample;
274     switch (sub) {
275     case SF_FORMAT_PCM_16:
276         bitsPerSample = 16;
277         break;
278     case SF_FORMAT_PCM_U8:
279         bitsPerSample = 8;
280         break;
281     case SF_FORMAT_FLOAT:
282         bitsPerSample = 32;
283         break;
284     default:    // not reachable
285         bitsPerSample = 0;
286         break;
287     }
288     unsigned blockAlignment = (bitsPerSample >> 3) * info->channels;
289     unsigned byteRate = info->samplerate * blockAlignment;
290     write4u(&wav[28], byteRate);
291     wav[32] = blockAlignment;
292     wav[34] = bitsPerSample;
293     size_t extra = 0;
294     if (sub == SF_FORMAT_FLOAT) {
295         memcpy(&wav[38], "fact", 4);
296         wav[42] = 4;
297         memcpy(&wav[50], "data", 4);
298         extra = 14;
299     } else
300         memcpy(&wav[36], "data", 4);
301     // dataSize is initially zero
302     (void) fwrite(wav, 44 + extra, 1, stream);
303     SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
304     handle->mode = SFM_WRITE;
305     handle->temp = NULL;
306     handle->stream = stream;
307     handle->bytesPerFrame = blockAlignment;
308     handle->remaining = 0;
309     handle->info = *info;
310     return handle;
311 }
312
313 SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
314 {
315     if (path == NULL || info == NULL) {
316         fprintf(stderr, "path=%p info=%p\n", path, info);
317         return NULL;
318     }
319     switch (mode) {
320     case SFM_READ:
321         return sf_open_read(path, info);
322     case SFM_WRITE:
323         return sf_open_write(path, info);
324     default:
325         fprintf(stderr, "mode=%d\n", mode);
326         return NULL;
327     }
328 }
329
330 void sf_close(SNDFILE *handle)
331 {
332     if (handle == NULL)
333         return;
334     free(handle->temp);
335     if (handle->mode == SFM_WRITE) {
336         (void) fflush(handle->stream);
337         rewind(handle->stream);
338         unsigned char wav[58];
339         size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0;
340         (void) fread(wav, 44 + extra, 1, handle->stream);
341         unsigned dataSize = handle->remaining * handle->bytesPerFrame;
342         write4u(&wav[4], dataSize + 36 + extra);    // riffSize
343         write4u(&wav[40 + extra], dataSize);        // dataSize
344         rewind(handle->stream);
345         (void) fwrite(wav, 44 + extra, 1, handle->stream);
346     }
347     (void) fclose(handle->stream);
348     free(handle);
349 }
350
351 sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames)
352 {
353     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
354             desiredFrames <= 0) {
355         return 0;
356     }
357     if (handle->remaining < (size_t) desiredFrames) {
358         desiredFrames = handle->remaining;
359     }
360     // does not check for numeric overflow
361     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
362     size_t actualBytes;
363     void *temp = NULL;
364     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
365     if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT) {
366         temp = malloc(desiredBytes);
367         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
368     } else {
369         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
370     }
371     size_t actualFrames = actualBytes / handle->bytesPerFrame;
372     handle->remaining -= actualFrames;
373     switch (format) {
374     case SF_FORMAT_PCM_U8:
375         memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels);
376         break;
377     case SF_FORMAT_PCM_16:
378         if (!isLittleEndian())
379             my_swab(ptr, actualFrames * handle->info.channels);
380         break;
381     case SF_FORMAT_PCM_32:
382         memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels);
383         free(temp);
384         break;
385     case SF_FORMAT_FLOAT:
386         memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels);
387         free(temp);
388         break;
389     default:
390         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short));
391         break;
392     }
393     return actualFrames;
394 }
395
396 sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames)
397 {
398     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
399             desiredFrames <= 0) {
400         return 0;
401     }
402     if (handle->remaining < (size_t) desiredFrames) {
403         desiredFrames = handle->remaining;
404     }
405     // does not check for numeric overflow
406     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
407     size_t actualBytes;
408     void *temp = NULL;
409     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
410     if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
411         temp = malloc(desiredBytes);
412         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
413     } else {
414         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
415     }
416     size_t actualFrames = actualBytes / handle->bytesPerFrame;
417     handle->remaining -= actualFrames;
418     switch (format) {
419     case SF_FORMAT_PCM_U8:
420 #if 0
421         // TODO - implement
422         memcpy_to_float_from_u8(ptr, (const unsigned char *) temp,
423                 actualFrames * handle->info.channels);
424 #endif
425         free(temp);
426         break;
427     case SF_FORMAT_PCM_16:
428         memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
429         free(temp);
430         break;
431     case SF_FORMAT_PCM_32:
432         memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels);
433         break;
434     case SF_FORMAT_FLOAT:
435         break;
436     default:
437         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float));
438         break;
439     }
440     return actualFrames;
441 }
442
443 sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames)
444 {
445     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
446             desiredFrames <= 0) {
447         return 0;
448     }
449     if (handle->remaining < (size_t) desiredFrames) {
450         desiredFrames = handle->remaining;
451     }
452     // does not check for numeric overflow
453     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
454     void *temp = NULL;
455     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
456     size_t actualBytes;
457     if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
458         temp = malloc(desiredBytes);
459         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
460     } else {
461         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
462     }
463     size_t actualFrames = actualBytes / handle->bytesPerFrame;
464     handle->remaining -= actualFrames;
465     switch (format) {
466     case SF_FORMAT_PCM_U8:
467 #if 0
468         // TODO - implement
469         memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp,
470                 actualFrames * handle->info.channels);
471 #endif
472         free(temp);
473         break;
474     case SF_FORMAT_PCM_16:
475         memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
476         free(temp);
477         break;
478     case SF_FORMAT_PCM_32:
479         break;
480     case SF_FORMAT_FLOAT:
481         memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels);
482         break;
483     default:
484         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int));
485         break;
486     }
487     return actualFrames;
488 }
489
490 sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames)
491 {
492     if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
493         return 0;
494     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
495     size_t actualBytes = 0;
496     switch (handle->info.format & SF_FORMAT_SUBMASK) {
497     case SF_FORMAT_PCM_U8:
498         handle->temp = realloc(handle->temp, desiredBytes);
499         memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes);
500         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
501         break;
502     case SF_FORMAT_PCM_16:
503         // does not check for numeric overflow
504         if (isLittleEndian()) {
505             actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
506         } else {
507             handle->temp = realloc(handle->temp, desiredBytes);
508             memcpy(handle->temp, ptr, desiredBytes);
509             my_swab((short *) handle->temp, desiredFrames * handle->info.channels);
510             actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
511         }
512         break;
513     case SF_FORMAT_FLOAT:
514         handle->temp = realloc(handle->temp, desiredBytes);
515         memcpy_to_float_from_i16((float *) handle->temp, ptr,
516                 desiredFrames * handle->info.channels);
517         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
518         break;
519     default:
520         break;
521     }
522     size_t actualFrames = actualBytes / handle->bytesPerFrame;
523     handle->remaining += actualFrames;
524     return actualFrames;
525 }
526
527 sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames)
528 {
529     if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
530         return 0;
531     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
532     size_t actualBytes = 0;
533     switch (handle->info.format & SF_FORMAT_SUBMASK) {
534     case SF_FORMAT_FLOAT:
535         actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
536         break;
537     case SF_FORMAT_PCM_16:
538         handle->temp = realloc(handle->temp, desiredBytes);
539         memcpy_to_i16_from_float((short *) handle->temp, ptr,
540                 desiredFrames * handle->info.channels);
541         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
542         break;
543     case SF_FORMAT_PCM_U8:  // transcoding from float to byte not yet implemented
544     default:
545         break;
546     }
547     size_t actualFrames = actualBytes / handle->bytesPerFrame;
548     handle->remaining += actualFrames;
549     return actualFrames;
550 }