* limitations under the License.
*/
+#include <system/audio.h>
#include <audio_utils/sndfile.h>
#include <audio_utils/primitives.h>
+#ifdef HAVE_STDERR
#include <stdio.h>
+#endif
#include <string.h>
#include <errno.h>
{
FILE *stream = fopen(path, "rb");
if (stream == NULL) {
+#ifdef HAVE_STDERR
fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
+#endif
return NULL;
}
size_t actual;
actual = fread(wav, sizeof(char), sizeof(wav), stream);
if (actual < 12) {
+#ifdef HAVE_STDERR
fprintf(stderr, "actual %zu < 44\n", actual);
+#endif
goto close;
}
if (memcmp(wav, "RIFF", 4)) {
+#ifdef HAVE_STDERR
fprintf(stderr, "wav != RIFF\n");
+#endif
goto close;
}
unsigned riffSize = little4u(&wav[4]);
if (riffSize < 4) {
+#ifdef HAVE_STDERR
fprintf(stderr, "riffSize %u < 4\n", riffSize);
+#endif
goto close;
}
if (memcmp(&wav[8], "WAVE", 4)) {
+#ifdef HAVE_STDERR
fprintf(stderr, "missing WAVE\n");
+#endif
goto close;
}
size_t remaining = riffSize - 4;
unsigned char chunk[8];
actual = fread(chunk, sizeof(char), sizeof(chunk), stream);
if (actual != sizeof(chunk)) {
+#ifdef HAVE_STDERR
fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk));
+#endif
goto close;
}
remaining -= 8;
unsigned chunkSize = little4u(&chunk[4]);
if (chunkSize > remaining) {
+#ifdef HAVE_STDERR
fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining);
+#endif
goto close;
}
if (!memcmp(&chunk[0], "fmt ", 4)) {
if (hadFmt) {
+#ifdef HAVE_STDERR
fprintf(stderr, "multiple fmt\n");
+#endif
goto close;
}
if (chunkSize < 2) {
+#ifdef HAVE_STDERR
fprintf(stderr, "chunkSize %u < 2\n", chunkSize);
+#endif
goto close;
}
unsigned char fmt[40];
actual = fread(fmt, sizeof(char), 2, stream);
if (actual != 2) {
+#ifdef HAVE_STDERR
fprintf(stderr, "actual %zu != 2\n", actual);
+#endif
goto close;
}
unsigned format = little2u(&fmt[0]);
minSize = 40;
break;
default:
+#ifdef HAVE_STDERR
fprintf(stderr, "unsupported format %u\n", format);
+#endif
goto close;
}
if (chunkSize < minSize) {
+#ifdef HAVE_STDERR
fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize);
+#endif
goto close;
}
actual = fread(&fmt[2], sizeof(char), minSize - 2, stream);
if (actual != minSize - 2) {
+#ifdef HAVE_STDERR
fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16);
+#endif
goto close;
}
if (chunkSize > minSize) {
fseek(stream, (long) (chunkSize - minSize), SEEK_CUR);
}
unsigned channels = little2u(&fmt[2]);
- if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) {
+ if ((channels < 1) || (channels > FCC_8)) {
+#ifdef HAVE_STDERR
fprintf(stderr, "unsupported channels %u\n", channels);
+#endif
goto close;
}
unsigned samplerate = little4u(&fmt[4]);
if (samplerate == 0) {
+#ifdef HAVE_STDERR
fprintf(stderr, "samplerate %u == 0\n", samplerate);
+#endif
goto close;
}
// ignore byte rate
// ignore block alignment
unsigned bitsPerSample = little2u(&fmt[14]);
- if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32) {
- fprintf(stderr, "bitsPerSample %u != 8 or 16 or 32\n", bitsPerSample);
+ if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 &&
+ bitsPerSample != 32) {
+#ifdef HAVE_STDERR
+ fprintf(stderr, "bitsPerSample %u != 8 or 16 or 24 or 32\n", bitsPerSample);
+#endif
goto close;
}
unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
case 16:
handle->info.format |= SF_FORMAT_PCM_16;
break;
+ case 24:
+ handle->info.format |= SF_FORMAT_PCM_24;
+ break;
case 32:
if (format == WAVE_FORMAT_IEEE_FLOAT)
handle->info.format |= SF_FORMAT_FLOAT;
hadFmt = 1;
} else if (!memcmp(&chunk[0], "data", 4)) {
if (!hadFmt) {
+#ifdef HAVE_STDERR
fprintf(stderr, "data not preceded by fmt\n");
+#endif
goto close;
}
if (hadData) {
+#ifdef HAVE_STDERR
fprintf(stderr, "multiple data\n");
+#endif
goto close;
}
handle->remaining = chunkSize / handle->bytesPerFrame;
}
} else {
// ignore unknown chunk
+#ifdef HAVE_STDERR
fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n",
chunk[0], chunk[1], chunk[2], chunk[3]);
+#endif
if (chunkSize > 0) {
fseek(stream, (long) chunkSize, SEEK_CUR);
}
remaining -= chunkSize;
}
if (remaining > 0) {
+#ifdef HAVE_STDERR
fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining);
+#endif
goto close;
}
if (!hadData) {
+#ifdef HAVE_STDERR
fprintf(stderr, "missing data\n");
+#endif
goto close;
}
(void) fseek(stream, dataTell, SEEK_SET);
int sub = info->format & SF_FORMAT_SUBMASK;
if (!(
(info->samplerate > 0) &&
- (info->channels > 0 && info->channels <= 8) &&
+ (info->channels > 0 && info->channels <= FCC_8) &&
((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) &&
- (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT)
+ (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT ||
+ sub == SF_FORMAT_PCM_24 || sub == SF_FORMAT_PCM_32)
)) {
return NULL;
}
FILE *stream = fopen(path, "w+b");
if (stream == NULL) {
+#ifdef HAVE_STDERR
fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
+#endif
return NULL;
}
unsigned char wav[58];
case SF_FORMAT_FLOAT:
bitsPerSample = 32;
break;
+ case SF_FORMAT_PCM_24:
+ bitsPerSample = 24;
+ break;
+ case SF_FORMAT_PCM_32:
+ bitsPerSample = 32;
+ break;
default: // not reachable
bitsPerSample = 0;
break;
SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
{
if (path == NULL || info == NULL) {
+#ifdef HAVE_STDERR
fprintf(stderr, "path=%p info=%p\n", path, info);
+#endif
return NULL;
}
switch (mode) {
case SFM_WRITE:
return sf_open_write(path, info);
default:
+#ifdef HAVE_STDERR
fprintf(stderr, "mode=%d\n", mode);
+#endif
return NULL;
}
}
size_t actualBytes;
void *temp = NULL;
unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
- if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT) {
+ if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT || format == SF_FORMAT_PCM_24) {
temp = malloc(desiredBytes);
actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
} else {
memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels);
free(temp);
break;
+ case SF_FORMAT_PCM_24:
+ memcpy_to_i16_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
+ free(temp);
+ break;
default:
memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short));
break;
size_t actualBytes;
void *temp = NULL;
unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
- if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
+ if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8 || format == SF_FORMAT_PCM_24) {
temp = malloc(desiredBytes);
actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
} else {
handle->remaining -= actualFrames;
switch (format) {
case SF_FORMAT_PCM_U8:
-#if 0
- // TODO - implement
memcpy_to_float_from_u8(ptr, (const unsigned char *) temp,
actualFrames * handle->info.channels);
-#endif
free(temp);
break;
case SF_FORMAT_PCM_16:
break;
case SF_FORMAT_FLOAT:
break;
+ case SF_FORMAT_PCM_24:
+ memcpy_to_float_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
+ free(temp);
+ break;
default:
memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float));
break;
void *temp = NULL;
unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
size_t actualBytes;
- if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
+ if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8 || format == SF_FORMAT_PCM_24) {
temp = malloc(desiredBytes);
actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
} else {
handle->remaining -= actualFrames;
switch (format) {
case SF_FORMAT_PCM_U8:
-#if 0
- // TODO - implement
memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp,
actualFrames * handle->info.channels);
-#endif
free(temp);
break;
case SF_FORMAT_PCM_16:
case SF_FORMAT_FLOAT:
memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels);
break;
+ case SF_FORMAT_PCM_24:
+ memcpy_to_i32_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
+ free(temp);
+ break;
default:
memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int));
break;
handle->remaining += actualFrames;
return actualFrames;
}
+
+sf_count_t sf_writef_int(SNDFILE *handle, const int *ptr, sf_count_t desiredFrames)
+{
+ if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
+ return 0;
+ size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
+ size_t actualBytes = 0;
+ switch (handle->info.format & SF_FORMAT_SUBMASK) {
+ case SF_FORMAT_PCM_32:
+ actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
+ break;
+ default: // transcoding from other formats not yet implemented
+ break;
+ }
+ size_t actualFrames = actualBytes / handle->bytesPerFrame;
+ handle->remaining += actualFrames;
+ return actualFrames;
+}