2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <audio_utils/sndfile.h>
18 #include <audio_utils/primitives.h>
23 #define WAVE_FORMAT_PCM 1
24 #define WAVE_FORMAT_IEEE_FLOAT 3
25 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
29 uint8_t *temp; // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping
32 size_t remaining; // frames unread for SFM_READ, frames written for SFM_WRITE
36 static unsigned little2u(unsigned char *ptr)
38 return (ptr[1] << 8) + ptr[0];
41 static unsigned little4u(unsigned char *ptr)
43 return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0];
46 static int isLittleEndian(void)
48 static const short one = 1;
49 return *((const char *) &one) == 1;
52 // "swab" conflicts with OS X <string.h>
53 static void my_swab(short *ptr, size_t numToSwap)
55 while (numToSwap > 0) {
56 *ptr = little2u((unsigned char *) ptr);
62 static SNDFILE *sf_open_read(const char *path, SF_INFO *info)
64 FILE *stream = fopen(path, "rb");
66 fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
70 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
71 handle->mode = SFM_READ;
73 handle->stream = stream;
74 handle->info.format = SF_FORMAT_WAV;
76 // don't attempt to parse all valid forms, just the most common ones
77 unsigned char wav[12];
79 actual = fread(wav, sizeof(char), sizeof(wav), stream);
81 fprintf(stderr, "actual %zu < 44\n", actual);
84 if (memcmp(wav, "RIFF", 4)) {
85 fprintf(stderr, "wav != RIFF\n");
88 unsigned riffSize = little4u(&wav[4]);
90 fprintf(stderr, "riffSize %u < 4\n", riffSize);
93 if (memcmp(&wav[8], "WAVE", 4)) {
94 fprintf(stderr, "missing WAVE\n");
97 size_t remaining = riffSize - 4;
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));
109 unsigned chunkSize = little4u(&chunk[4]);
110 if (chunkSize > remaining) {
111 fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining);
114 if (!memcmp(&chunk[0], "fmt ", 4)) {
116 fprintf(stderr, "multiple fmt\n");
120 fprintf(stderr, "chunkSize %u < 2\n", chunkSize);
123 unsigned char fmt[40];
124 actual = fread(fmt, sizeof(char), 2, stream);
126 fprintf(stderr, "actual %zu != 2\n", actual);
129 unsigned format = little2u(&fmt[0]);
132 case WAVE_FORMAT_PCM:
133 case WAVE_FORMAT_IEEE_FLOAT:
136 case WAVE_FORMAT_EXTENSIBLE:
140 fprintf(stderr, "unsupported format %u\n", format);
143 if (chunkSize < minSize) {
144 fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize);
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);
152 if (chunkSize > minSize) {
153 fseek(stream, (long) (chunkSize - minSize), SEEK_CUR);
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);
160 unsigned samplerate = little4u(&fmt[4]);
161 if (samplerate == 0) {
162 fprintf(stderr, "samplerate %u == 0\n", samplerate);
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);
172 unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
173 handle->bytesPerFrame = bytesPerFrame;
174 handle->info.samplerate = samplerate;
175 handle->info.channels = channels;
176 switch (bitsPerSample) {
178 handle->info.format |= SF_FORMAT_PCM_U8;
181 handle->info.format |= SF_FORMAT_PCM_16;
184 if (format == WAVE_FORMAT_IEEE_FLOAT)
185 handle->info.format |= SF_FORMAT_FLOAT;
187 handle->info.format |= SF_FORMAT_PCM_32;
191 } else if (!memcmp(&chunk[0], "data", 4)) {
193 fprintf(stderr, "data not preceded by fmt\n");
197 fprintf(stderr, "multiple data\n");
200 handle->remaining = chunkSize / handle->bytesPerFrame;
201 handle->info.frames = handle->remaining;
202 dataTell = ftell(stream);
204 fseek(stream, (long) chunkSize, SEEK_CUR);
207 } else if (!memcmp(&chunk[0], "fact", 4)) {
210 fseek(stream, (long) chunkSize, SEEK_CUR);
213 // ignore unknown chunk
214 fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n",
215 chunk[0], chunk[1], chunk[2], chunk[3]);
217 fseek(stream, (long) chunkSize, SEEK_CUR);
220 remaining -= chunkSize;
223 fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining);
227 fprintf(stderr, "missing data\n");
230 (void) fseek(stream, dataTell, SEEK_SET);
231 *info = handle->info;
240 static void write4u(unsigned char *ptr, unsigned u)
248 static SNDFILE *sf_open_write(const char *path, SF_INFO *info)
250 int sub = info->format & SF_FORMAT_SUBMASK;
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)
259 FILE *stream = fopen(path, "w+b");
260 if (stream == NULL) {
261 fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
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;
273 wav[4] = 36; // riffSize
274 wav[16] = 16; // fmtSize
275 wav[20] = WAVE_FORMAT_PCM;
277 wav[22] = info->channels;
278 write4u(&wav[24], info->samplerate);
279 unsigned bitsPerSample;
281 case SF_FORMAT_PCM_16:
284 case SF_FORMAT_PCM_U8:
287 case SF_FORMAT_FLOAT:
290 default: // not reachable
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;
300 if (sub == SF_FORMAT_FLOAT) {
301 memcpy(&wav[38], "fact", 4);
303 memcpy(&wav[50], "data", 4);
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;
312 handle->stream = stream;
313 handle->bytesPerFrame = blockAlignment;
314 handle->remaining = 0;
315 handle->info = *info;
319 SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
321 if (path == NULL || info == NULL) {
322 fprintf(stderr, "path=%p info=%p\n", path, info);
327 return sf_open_read(path, info);
329 return sf_open_write(path, info);
331 fprintf(stderr, "mode=%d\n", mode);
336 void sf_close(SNDFILE *handle)
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);
353 (void) fclose(handle->stream);
357 sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames)
359 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
360 desiredFrames <= 0) {
363 if (handle->remaining < (size_t) desiredFrames) {
364 desiredFrames = handle->remaining;
366 // does not check for numeric overflow
367 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
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);
375 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
377 size_t actualFrames = actualBytes / handle->bytesPerFrame;
378 handle->remaining -= actualFrames;
380 case SF_FORMAT_PCM_U8:
381 memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels);
383 case SF_FORMAT_PCM_16:
384 if (!isLittleEndian())
385 my_swab(ptr, actualFrames * handle->info.channels);
387 case SF_FORMAT_PCM_32:
388 memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels);
391 case SF_FORMAT_FLOAT:
392 memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels);
396 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short));
402 sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames)
404 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
405 desiredFrames <= 0) {
408 if (handle->remaining < (size_t) desiredFrames) {
409 desiredFrames = handle->remaining;
411 // does not check for numeric overflow
412 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
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);
420 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
422 size_t actualFrames = actualBytes / handle->bytesPerFrame;
423 handle->remaining -= actualFrames;
425 case SF_FORMAT_PCM_U8:
428 memcpy_to_float_from_u8(ptr, (const unsigned char *) temp,
429 actualFrames * handle->info.channels);
433 case SF_FORMAT_PCM_16:
434 memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
437 case SF_FORMAT_PCM_32:
438 memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels);
440 case SF_FORMAT_FLOAT:
443 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float));
449 sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames)
451 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
452 desiredFrames <= 0) {
455 if (handle->remaining < (size_t) desiredFrames) {
456 desiredFrames = handle->remaining;
458 // does not check for numeric overflow
459 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
461 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
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);
467 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
469 size_t actualFrames = actualBytes / handle->bytesPerFrame;
470 handle->remaining -= actualFrames;
472 case SF_FORMAT_PCM_U8:
475 memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp,
476 actualFrames * handle->info.channels);
480 case SF_FORMAT_PCM_16:
481 memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
484 case SF_FORMAT_PCM_32:
486 case SF_FORMAT_FLOAT:
487 memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels);
490 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int));
496 sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames)
498 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 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);
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);
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);
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);
528 size_t actualFrames = actualBytes / handle->bytesPerFrame;
529 handle->remaining += actualFrames;
533 sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames)
535 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 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);
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);
549 case SF_FORMAT_PCM_U8: // transcoding from float to byte not yet implemented
553 size_t actualFrames = actualBytes / handle->bytesPerFrame;
554 handle->remaining += actualFrames;