OSDN Git Service

am f8af8629: am 65720457: Merge "Fix "error: \'memset\' was not declared in this...
[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     long dataTell = 0L;
101     while (remaining >= 8) {
102         unsigned char chunk[8];
103         actual = fread(chunk, sizeof(char), sizeof(chunk), stream);
104         if (actual != sizeof(chunk)) {
105             fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk));
106             goto close;
107         }
108         remaining -= 8;
109         unsigned chunkSize = little4u(&chunk[4]);
110         if (chunkSize > remaining) {
111             fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining);
112             goto close;
113         }
114         if (!memcmp(&chunk[0], "fmt ", 4)) {
115             if (hadFmt) {
116                 fprintf(stderr, "multiple fmt\n");
117                 goto close;
118             }
119             if (chunkSize < 2) {
120                 fprintf(stderr, "chunkSize %u < 2\n", chunkSize);
121                 goto close;
122             }
123             unsigned char fmt[40];
124             actual = fread(fmt, sizeof(char), 2, stream);
125             if (actual != 2) {
126                 fprintf(stderr, "actual %zu != 2\n", actual);
127                 goto close;
128             }
129             unsigned format = little2u(&fmt[0]);
130             size_t minSize = 0;
131             switch (format) {
132             case WAVE_FORMAT_PCM:
133             case WAVE_FORMAT_IEEE_FLOAT:
134                 minSize = 16;
135                 break;
136             case WAVE_FORMAT_EXTENSIBLE:
137                 minSize = 40;
138                 break;
139             default:
140                 fprintf(stderr, "unsupported format %u\n", format);
141                 goto close;
142             }
143             if (chunkSize < minSize) {
144                 fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize);
145                 goto close;
146             }
147             actual = fread(&fmt[2], sizeof(char), minSize - 2, stream);
148             if (actual != minSize - 2) {
149                 fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16);
150                 goto close;
151             }
152             if (chunkSize > minSize) {
153                 fseek(stream, (long) (chunkSize - minSize), SEEK_CUR);
154             }
155             unsigned channels = little2u(&fmt[2]);
156             if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) {
157                 fprintf(stderr, "unsupported channels %u\n", channels);
158                 goto close;
159             }
160             unsigned samplerate = little4u(&fmt[4]);
161             if (samplerate == 0) {
162                 fprintf(stderr, "samplerate %u == 0\n", samplerate);
163                 goto close;
164             }
165             // ignore byte rate
166             // ignore block alignment
167             unsigned bitsPerSample = little2u(&fmt[14]);
168             if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32) {
169                 fprintf(stderr, "bitsPerSample %u != 8 or 16 or 32\n", bitsPerSample);
170                 goto close;
171             }
172             unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
173             handle->bytesPerFrame = bytesPerFrame;
174             handle->info.samplerate = samplerate;
175             handle->info.channels = channels;
176             switch (bitsPerSample) {
177             case 8:
178                 handle->info.format |= SF_FORMAT_PCM_U8;
179                 break;
180             case 16:
181                 handle->info.format |= SF_FORMAT_PCM_16;
182                 break;
183             case 32:
184                 if (format == WAVE_FORMAT_IEEE_FLOAT)
185                     handle->info.format |= SF_FORMAT_FLOAT;
186                 else
187                     handle->info.format |= SF_FORMAT_PCM_32;
188                 break;
189             }
190             hadFmt = 1;
191         } else if (!memcmp(&chunk[0], "data", 4)) {
192             if (!hadFmt) {
193                 fprintf(stderr, "data not preceded by fmt\n");
194                 goto close;
195             }
196             if (hadData) {
197                 fprintf(stderr, "multiple data\n");
198                 goto close;
199             }
200             handle->remaining = chunkSize / handle->bytesPerFrame;
201             handle->info.frames = handle->remaining;
202             dataTell = ftell(stream);
203             if (chunkSize > 0) {
204                 fseek(stream, (long) chunkSize, SEEK_CUR);
205             }
206             hadData = 1;
207         } else if (!memcmp(&chunk[0], "fact", 4)) {
208             // ignore fact
209             if (chunkSize > 0) {
210                 fseek(stream, (long) chunkSize, SEEK_CUR);
211             }
212         } else {
213             // ignore unknown chunk
214             fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n",
215                     chunk[0], chunk[1], chunk[2], chunk[3]);
216             if (chunkSize > 0) {
217                 fseek(stream, (long) chunkSize, SEEK_CUR);
218             }
219         }
220         remaining -= chunkSize;
221     }
222     if (remaining > 0) {
223         fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining);
224         goto close;
225     }
226     if (!hadData) {
227         fprintf(stderr, "missing data\n");
228         goto close;
229     }
230     (void) fseek(stream, dataTell, SEEK_SET);
231     *info = handle->info;
232     return handle;
233
234 close:
235     free(handle);
236     fclose(stream);
237     return NULL;
238 }
239
240 static void write4u(unsigned char *ptr, unsigned u)
241 {
242     ptr[0] = u;
243     ptr[1] = u >> 8;
244     ptr[2] = u >> 16;
245     ptr[3] = u >> 24;
246 }
247
248 static SNDFILE *sf_open_write(const char *path, SF_INFO *info)
249 {
250     int sub = info->format & SF_FORMAT_SUBMASK;
251     if (!(
252             (info->samplerate > 0) &&
253             (info->channels > 0 && info->channels <= 8) &&
254             ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) &&
255             (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT)
256           )) {
257         return NULL;
258     }
259     FILE *stream = fopen(path, "w+b");
260     if (stream == NULL) {
261         fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
262         return NULL;
263     }
264     unsigned char wav[58];
265     memset(wav, 0, sizeof(wav));
266     memcpy(wav, "RIFF", 4);
267     memcpy(&wav[8], "WAVEfmt ", 8);
268     if (sub == SF_FORMAT_FLOAT) {
269         wav[4] = 50;    // riffSize
270         wav[16] = 18;   // fmtSize
271         wav[20] = WAVE_FORMAT_IEEE_FLOAT;
272     } else {
273         wav[4] = 36;    // riffSize
274         wav[16] = 16;   // fmtSize
275         wav[20] = WAVE_FORMAT_PCM;
276     }
277     wav[22] = info->channels;
278     write4u(&wav[24], info->samplerate);
279     unsigned bitsPerSample;
280     switch (sub) {
281     case SF_FORMAT_PCM_16:
282         bitsPerSample = 16;
283         break;
284     case SF_FORMAT_PCM_U8:
285         bitsPerSample = 8;
286         break;
287     case SF_FORMAT_FLOAT:
288         bitsPerSample = 32;
289         break;
290     default:    // not reachable
291         bitsPerSample = 0;
292         break;
293     }
294     unsigned blockAlignment = (bitsPerSample >> 3) * info->channels;
295     unsigned byteRate = info->samplerate * blockAlignment;
296     write4u(&wav[28], byteRate);
297     wav[32] = blockAlignment;
298     wav[34] = bitsPerSample;
299     size_t extra = 0;
300     if (sub == SF_FORMAT_FLOAT) {
301         memcpy(&wav[38], "fact", 4);
302         wav[42] = 4;
303         memcpy(&wav[50], "data", 4);
304         extra = 14;
305     } else
306         memcpy(&wav[36], "data", 4);
307     // dataSize is initially zero
308     (void) fwrite(wav, 44 + extra, 1, stream);
309     SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
310     handle->mode = SFM_WRITE;
311     handle->temp = NULL;
312     handle->stream = stream;
313     handle->bytesPerFrame = blockAlignment;
314     handle->remaining = 0;
315     handle->info = *info;
316     return handle;
317 }
318
319 SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
320 {
321     if (path == NULL || info == NULL) {
322         fprintf(stderr, "path=%p info=%p\n", path, info);
323         return NULL;
324     }
325     switch (mode) {
326     case SFM_READ:
327         return sf_open_read(path, info);
328     case SFM_WRITE:
329         return sf_open_write(path, info);
330     default:
331         fprintf(stderr, "mode=%d\n", mode);
332         return NULL;
333     }
334 }
335
336 void sf_close(SNDFILE *handle)
337 {
338     if (handle == NULL)
339         return;
340     free(handle->temp);
341     if (handle->mode == SFM_WRITE) {
342         (void) fflush(handle->stream);
343         rewind(handle->stream);
344         unsigned char wav[58];
345         size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0;
346         (void) fread(wav, 44 + extra, 1, handle->stream);
347         unsigned dataSize = handle->remaining * handle->bytesPerFrame;
348         write4u(&wav[4], dataSize + 36 + extra);    // riffSize
349         write4u(&wav[40 + extra], dataSize);        // dataSize
350         rewind(handle->stream);
351         (void) fwrite(wav, 44 + extra, 1, handle->stream);
352     }
353     (void) fclose(handle->stream);
354     free(handle);
355 }
356
357 sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames)
358 {
359     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
360             desiredFrames <= 0) {
361         return 0;
362     }
363     if (handle->remaining < (size_t) desiredFrames) {
364         desiredFrames = handle->remaining;
365     }
366     // does not check for numeric overflow
367     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
368     size_t actualBytes;
369     void *temp = NULL;
370     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
371     if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT) {
372         temp = malloc(desiredBytes);
373         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
374     } else {
375         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
376     }
377     size_t actualFrames = actualBytes / handle->bytesPerFrame;
378     handle->remaining -= actualFrames;
379     switch (format) {
380     case SF_FORMAT_PCM_U8:
381         memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels);
382         break;
383     case SF_FORMAT_PCM_16:
384         if (!isLittleEndian())
385             my_swab(ptr, actualFrames * handle->info.channels);
386         break;
387     case SF_FORMAT_PCM_32:
388         memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels);
389         free(temp);
390         break;
391     case SF_FORMAT_FLOAT:
392         memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels);
393         free(temp);
394         break;
395     default:
396         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short));
397         break;
398     }
399     return actualFrames;
400 }
401
402 sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames)
403 {
404     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
405             desiredFrames <= 0) {
406         return 0;
407     }
408     if (handle->remaining < (size_t) desiredFrames) {
409         desiredFrames = handle->remaining;
410     }
411     // does not check for numeric overflow
412     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
413     size_t actualBytes;
414     void *temp = NULL;
415     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
416     if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
417         temp = malloc(desiredBytes);
418         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
419     } else {
420         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
421     }
422     size_t actualFrames = actualBytes / handle->bytesPerFrame;
423     handle->remaining -= actualFrames;
424     switch (format) {
425     case SF_FORMAT_PCM_U8:
426 #if 0
427         // TODO - implement
428         memcpy_to_float_from_u8(ptr, (const unsigned char *) temp,
429                 actualFrames * handle->info.channels);
430 #endif
431         free(temp);
432         break;
433     case SF_FORMAT_PCM_16:
434         memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
435         free(temp);
436         break;
437     case SF_FORMAT_PCM_32:
438         memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels);
439         break;
440     case SF_FORMAT_FLOAT:
441         break;
442     default:
443         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float));
444         break;
445     }
446     return actualFrames;
447 }
448
449 sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames)
450 {
451     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
452             desiredFrames <= 0) {
453         return 0;
454     }
455     if (handle->remaining < (size_t) desiredFrames) {
456         desiredFrames = handle->remaining;
457     }
458     // does not check for numeric overflow
459     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
460     void *temp = NULL;
461     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
462     size_t actualBytes;
463     if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
464         temp = malloc(desiredBytes);
465         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
466     } else {
467         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
468     }
469     size_t actualFrames = actualBytes / handle->bytesPerFrame;
470     handle->remaining -= actualFrames;
471     switch (format) {
472     case SF_FORMAT_PCM_U8:
473 #if 0
474         // TODO - implement
475         memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp,
476                 actualFrames * handle->info.channels);
477 #endif
478         free(temp);
479         break;
480     case SF_FORMAT_PCM_16:
481         memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
482         free(temp);
483         break;
484     case SF_FORMAT_PCM_32:
485         break;
486     case SF_FORMAT_FLOAT:
487         memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels);
488         break;
489     default:
490         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int));
491         break;
492     }
493     return actualFrames;
494 }
495
496 sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames)
497 {
498     if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
499         return 0;
500     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
501     size_t actualBytes = 0;
502     switch (handle->info.format & SF_FORMAT_SUBMASK) {
503     case SF_FORMAT_PCM_U8:
504         handle->temp = realloc(handle->temp, desiredBytes);
505         memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes);
506         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
507         break;
508     case SF_FORMAT_PCM_16:
509         // does not check for numeric overflow
510         if (isLittleEndian()) {
511             actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
512         } else {
513             handle->temp = realloc(handle->temp, desiredBytes);
514             memcpy(handle->temp, ptr, desiredBytes);
515             my_swab((short *) handle->temp, desiredFrames * handle->info.channels);
516             actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
517         }
518         break;
519     case SF_FORMAT_FLOAT:
520         handle->temp = realloc(handle->temp, desiredBytes);
521         memcpy_to_float_from_i16((float *) handle->temp, ptr,
522                 desiredFrames * handle->info.channels);
523         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
524         break;
525     default:
526         break;
527     }
528     size_t actualFrames = actualBytes / handle->bytesPerFrame;
529     handle->remaining += actualFrames;
530     return actualFrames;
531 }
532
533 sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames)
534 {
535     if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
536         return 0;
537     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
538     size_t actualBytes = 0;
539     switch (handle->info.format & SF_FORMAT_SUBMASK) {
540     case SF_FORMAT_FLOAT:
541         actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
542         break;
543     case SF_FORMAT_PCM_16:
544         handle->temp = realloc(handle->temp, desiredBytes);
545         memcpy_to_i16_from_float((short *) handle->temp, ptr,
546                 desiredFrames * handle->info.channels);
547         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
548         break;
549     case SF_FORMAT_PCM_U8:  // transcoding from float to byte not yet implemented
550     default:
551         break;
552     }
553     size_t actualFrames = actualBytes / handle->bytesPerFrame;
554     handle->remaining += actualFrames;
555     return actualFrames;
556 }