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>
25 #define WAVE_FORMAT_PCM 1
26 #define WAVE_FORMAT_IEEE_FLOAT 3
27 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
31 uint8_t *temp; // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping
34 size_t remaining; // frames unread for SFM_READ, frames written for SFM_WRITE
38 static unsigned little2u(unsigned char *ptr)
40 return (ptr[1] << 8) + ptr[0];
43 static unsigned little4u(unsigned char *ptr)
45 return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0];
48 static int isLittleEndian(void)
50 static const short one = 1;
51 return *((const char *) &one) == 1;
54 // "swab" conflicts with OS X <string.h>
55 static void my_swab(short *ptr, size_t numToSwap)
57 while (numToSwap > 0) {
58 *ptr = little2u((unsigned char *) ptr);
64 static SNDFILE *sf_open_read(const char *path, SF_INFO *info)
66 FILE *stream = fopen(path, "rb");
69 fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
74 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
75 handle->mode = SFM_READ;
77 handle->stream = stream;
78 handle->info.format = SF_FORMAT_WAV;
80 // don't attempt to parse all valid forms, just the most common ones
81 unsigned char wav[12];
83 actual = fread(wav, sizeof(char), sizeof(wav), stream);
86 fprintf(stderr, "actual %zu < 44\n", actual);
90 if (memcmp(wav, "RIFF", 4)) {
92 fprintf(stderr, "wav != RIFF\n");
96 unsigned riffSize = little4u(&wav[4]);
99 fprintf(stderr, "riffSize %u < 4\n", riffSize);
103 if (memcmp(&wav[8], "WAVE", 4)) {
105 fprintf(stderr, "missing WAVE\n");
109 size_t remaining = riffSize - 4;
113 while (remaining >= 8) {
114 unsigned char chunk[8];
115 actual = fread(chunk, sizeof(char), sizeof(chunk), stream);
116 if (actual != sizeof(chunk)) {
118 fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk));
123 unsigned chunkSize = little4u(&chunk[4]);
124 if (chunkSize > remaining) {
126 fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining);
130 if (!memcmp(&chunk[0], "fmt ", 4)) {
133 fprintf(stderr, "multiple fmt\n");
139 fprintf(stderr, "chunkSize %u < 2\n", chunkSize);
143 unsigned char fmt[40];
144 actual = fread(fmt, sizeof(char), 2, stream);
147 fprintf(stderr, "actual %zu != 2\n", actual);
151 unsigned format = little2u(&fmt[0]);
154 case WAVE_FORMAT_PCM:
155 case WAVE_FORMAT_IEEE_FLOAT:
158 case WAVE_FORMAT_EXTENSIBLE:
163 fprintf(stderr, "unsupported format %u\n", format);
167 if (chunkSize < minSize) {
169 fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize);
173 actual = fread(&fmt[2], sizeof(char), minSize - 2, stream);
174 if (actual != minSize - 2) {
176 fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16);
180 if (chunkSize > minSize) {
181 fseek(stream, (long) (chunkSize - minSize), SEEK_CUR);
183 unsigned channels = little2u(&fmt[2]);
185 if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) {
187 fprintf(stderr, "unsupported channels %u\n", channels);
191 unsigned samplerate = little4u(&fmt[4]);
192 if (samplerate == 0) {
194 fprintf(stderr, "samplerate %u == 0\n", samplerate);
199 // ignore block alignment
200 unsigned bitsPerSample = little2u(&fmt[14]);
201 if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 &&
202 bitsPerSample != 32) {
204 fprintf(stderr, "bitsPerSample %u != 8 or 16 or 24 or 32\n", bitsPerSample);
208 unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
209 handle->bytesPerFrame = bytesPerFrame;
210 handle->info.samplerate = samplerate;
211 handle->info.channels = channels;
212 switch (bitsPerSample) {
214 handle->info.format |= SF_FORMAT_PCM_U8;
217 handle->info.format |= SF_FORMAT_PCM_16;
220 handle->info.format |= SF_FORMAT_PCM_24;
223 if (format == WAVE_FORMAT_IEEE_FLOAT)
224 handle->info.format |= SF_FORMAT_FLOAT;
226 handle->info.format |= SF_FORMAT_PCM_32;
230 } else if (!memcmp(&chunk[0], "data", 4)) {
233 fprintf(stderr, "data not preceded by fmt\n");
239 fprintf(stderr, "multiple data\n");
243 handle->remaining = chunkSize / handle->bytesPerFrame;
244 handle->info.frames = handle->remaining;
245 dataTell = ftell(stream);
247 fseek(stream, (long) chunkSize, SEEK_CUR);
250 } else if (!memcmp(&chunk[0], "fact", 4)) {
253 fseek(stream, (long) chunkSize, SEEK_CUR);
256 // ignore unknown chunk
258 fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n",
259 chunk[0], chunk[1], chunk[2], chunk[3]);
262 fseek(stream, (long) chunkSize, SEEK_CUR);
265 remaining -= chunkSize;
269 fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining);
275 fprintf(stderr, "missing data\n");
279 (void) fseek(stream, dataTell, SEEK_SET);
280 *info = handle->info;
289 static void write4u(unsigned char *ptr, unsigned u)
297 static SNDFILE *sf_open_write(const char *path, SF_INFO *info)
299 int sub = info->format & SF_FORMAT_SUBMASK;
301 (info->samplerate > 0) &&
303 (info->channels > 0 && info->channels <= 8) &&
304 ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) &&
305 (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT ||
306 sub == SF_FORMAT_PCM_24)
310 FILE *stream = fopen(path, "w+b");
311 if (stream == NULL) {
313 fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
317 unsigned char wav[58];
318 memset(wav, 0, sizeof(wav));
319 memcpy(wav, "RIFF", 4);
320 memcpy(&wav[8], "WAVEfmt ", 8);
321 if (sub == SF_FORMAT_FLOAT) {
322 wav[4] = 50; // riffSize
323 wav[16] = 18; // fmtSize
324 wav[20] = WAVE_FORMAT_IEEE_FLOAT;
326 wav[4] = 36; // riffSize
327 wav[16] = 16; // fmtSize
328 wav[20] = WAVE_FORMAT_PCM;
330 wav[22] = info->channels;
331 write4u(&wav[24], info->samplerate);
332 unsigned bitsPerSample;
334 case SF_FORMAT_PCM_16:
337 case SF_FORMAT_PCM_U8:
340 case SF_FORMAT_FLOAT:
343 case SF_FORMAT_PCM_24:
346 default: // not reachable
350 unsigned blockAlignment = (bitsPerSample >> 3) * info->channels;
351 unsigned byteRate = info->samplerate * blockAlignment;
352 write4u(&wav[28], byteRate);
353 wav[32] = blockAlignment;
354 wav[34] = bitsPerSample;
356 if (sub == SF_FORMAT_FLOAT) {
357 memcpy(&wav[38], "fact", 4);
359 memcpy(&wav[50], "data", 4);
362 memcpy(&wav[36], "data", 4);
363 // dataSize is initially zero
364 (void) fwrite(wav, 44 + extra, 1, stream);
365 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
366 handle->mode = SFM_WRITE;
368 handle->stream = stream;
369 handle->bytesPerFrame = blockAlignment;
370 handle->remaining = 0;
371 handle->info = *info;
375 SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
377 if (path == NULL || info == NULL) {
379 fprintf(stderr, "path=%p info=%p\n", path, info);
385 return sf_open_read(path, info);
387 return sf_open_write(path, info);
390 fprintf(stderr, "mode=%d\n", mode);
396 void sf_close(SNDFILE *handle)
401 if (handle->mode == SFM_WRITE) {
402 (void) fflush(handle->stream);
403 rewind(handle->stream);
404 unsigned char wav[58];
405 size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0;
406 (void) fread(wav, 44 + extra, 1, handle->stream);
407 unsigned dataSize = handle->remaining * handle->bytesPerFrame;
408 write4u(&wav[4], dataSize + 36 + extra); // riffSize
409 write4u(&wav[40 + extra], dataSize); // dataSize
410 rewind(handle->stream);
411 (void) fwrite(wav, 44 + extra, 1, handle->stream);
413 (void) fclose(handle->stream);
417 sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames)
419 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
420 desiredFrames <= 0) {
423 if (handle->remaining < (size_t) desiredFrames) {
424 desiredFrames = handle->remaining;
426 // does not check for numeric overflow
427 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
430 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
431 if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT || format == SF_FORMAT_PCM_24) {
432 temp = malloc(desiredBytes);
433 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
435 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
437 size_t actualFrames = actualBytes / handle->bytesPerFrame;
438 handle->remaining -= actualFrames;
440 case SF_FORMAT_PCM_U8:
441 memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels);
443 case SF_FORMAT_PCM_16:
444 if (!isLittleEndian())
445 my_swab(ptr, actualFrames * handle->info.channels);
447 case SF_FORMAT_PCM_32:
448 memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels);
451 case SF_FORMAT_FLOAT:
452 memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels);
455 case SF_FORMAT_PCM_24:
456 memcpy_to_i16_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
460 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short));
466 sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames)
468 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
469 desiredFrames <= 0) {
472 if (handle->remaining < (size_t) desiredFrames) {
473 desiredFrames = handle->remaining;
475 // does not check for numeric overflow
476 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
479 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
480 if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8 || format == SF_FORMAT_PCM_24) {
481 temp = malloc(desiredBytes);
482 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
484 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
486 size_t actualFrames = actualBytes / handle->bytesPerFrame;
487 handle->remaining -= actualFrames;
489 case SF_FORMAT_PCM_U8:
492 memcpy_to_float_from_u8(ptr, (const unsigned char *) temp,
493 actualFrames * handle->info.channels);
497 case SF_FORMAT_PCM_16:
498 memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
501 case SF_FORMAT_PCM_32:
502 memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels);
504 case SF_FORMAT_FLOAT:
506 case SF_FORMAT_PCM_24:
507 memcpy_to_float_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
511 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float));
517 sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames)
519 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
520 desiredFrames <= 0) {
523 if (handle->remaining < (size_t) desiredFrames) {
524 desiredFrames = handle->remaining;
526 // does not check for numeric overflow
527 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
529 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
531 if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8 || format == SF_FORMAT_PCM_24) {
532 temp = malloc(desiredBytes);
533 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
535 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
537 size_t actualFrames = actualBytes / handle->bytesPerFrame;
538 handle->remaining -= actualFrames;
540 case SF_FORMAT_PCM_U8:
543 memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp,
544 actualFrames * handle->info.channels);
548 case SF_FORMAT_PCM_16:
549 memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
552 case SF_FORMAT_PCM_32:
554 case SF_FORMAT_FLOAT:
555 memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels);
557 case SF_FORMAT_PCM_24:
558 memcpy_to_i32_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
562 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int));
568 sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames)
570 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
572 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
573 size_t actualBytes = 0;
574 switch (handle->info.format & SF_FORMAT_SUBMASK) {
575 case SF_FORMAT_PCM_U8:
576 handle->temp = realloc(handle->temp, desiredBytes);
577 memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes);
578 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
580 case SF_FORMAT_PCM_16:
581 // does not check for numeric overflow
582 if (isLittleEndian()) {
583 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
585 handle->temp = realloc(handle->temp, desiredBytes);
586 memcpy(handle->temp, ptr, desiredBytes);
587 my_swab((short *) handle->temp, desiredFrames * handle->info.channels);
588 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
591 case SF_FORMAT_FLOAT:
592 handle->temp = realloc(handle->temp, desiredBytes);
593 memcpy_to_float_from_i16((float *) handle->temp, ptr,
594 desiredFrames * handle->info.channels);
595 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
600 size_t actualFrames = actualBytes / handle->bytesPerFrame;
601 handle->remaining += actualFrames;
605 sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames)
607 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
609 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
610 size_t actualBytes = 0;
611 switch (handle->info.format & SF_FORMAT_SUBMASK) {
612 case SF_FORMAT_FLOAT:
613 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
615 case SF_FORMAT_PCM_16:
616 handle->temp = realloc(handle->temp, desiredBytes);
617 memcpy_to_i16_from_float((short *) handle->temp, ptr,
618 desiredFrames * handle->info.channels);
619 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
621 case SF_FORMAT_PCM_U8: // transcoding from float to byte not yet implemented
625 size_t actualFrames = actualBytes / handle->bytesPerFrame;
626 handle->remaining += actualFrames;