Add tinysndfile
Change-Id: Idc97a54f1e170fc06cc341fd1234c0635ada9757
diff --git a/audio_utils/Android.mk b/audio_utils/Android.mk
index e3f3e5e..b653f5a 100644
--- a/audio_utils/Android.mk
+++ b/audio_utils/Android.mk
@@ -21,3 +21,16 @@
libspeexresampler
include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsndfile
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ tinysndfile.c
+
+LOCAL_C_INCLUDES += \
+ $(call include-path-for, audio-utils)
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/audio_utils/include/audio_utils/sndfile.h b/audio_utils/include/audio_utils/sndfile.h
new file mode 100644
index 0000000..eff7067
--- /dev/null
+++ b/audio_utils/include/audio_utils/sndfile.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AUDIO_UTIL_SNDFILE_H
+#define __AUDIO_UTIL_SNDFILE_H
+
+// This is a C library for reading and writing PCM .wav files. It is
+// influenced by other libraries such as libsndfile and audiofile, except is
+// much smaller and has an Apache 2.0 license.
+// The API should be familiar to clients of similar libraries, but there is
+// no guarantee that it will stay exactly source-code compatible with other libraries.
+
+#include <stdio.h>
+
+// visible to clients
+typedef struct {
+ int samplerate;
+ int channels;
+ int format;
+} SF_INFO;
+
+// opaque to clients
+typedef struct SNDFILE_ SNDFILE;
+
+typedef unsigned sf_count_t;
+
+// Access modes
+#define SFM_READ 1
+
+// Format
+#define SF_FORMAT_TYPEMASK 1
+#define SF_FORMAT_WAV 1
+#define SF_FORMAT_SUBMASK 6
+#define SF_FORMAT_PCM_16 2
+#define SF_FORMAT_PCM_U8 4
+
+// Open stream
+SNDFILE *sf_open(const char *path, int mode, SF_INFO *info);
+
+// Close stream
+void sf_close(SNDFILE *handle);
+
+// Read interleaved frames and return actual number of frames read
+ssize_t sf_readf_short(SNDFILE *handle, short *ptr, size_t desired);
+
+#endif /* __AUDIO_UTIL_SNDFILE_H */
diff --git a/audio_utils/tinysndfile.c b/audio_utils/tinysndfile.c
new file mode 100644
index 0000000..b50ad72
--- /dev/null
+++ b/audio_utils/tinysndfile.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+#include <string.h>
+
+struct SNDFILE_ {
+ FILE *stream;
+ size_t bytesPerFrame;
+ size_t remaining;
+ SF_INFO info;
+};
+
+static unsigned little2u(unsigned char *ptr)
+{
+ return (ptr[1] << 8) + ptr[0];
+}
+
+static unsigned little4u(unsigned char *ptr)
+{
+ return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0];
+}
+
+static int isLittleEndian(void)
+{
+ static const short one = 1;
+ return *((const char *) &one) == 1;
+}
+
+static void swab(short *ptr, size_t numToSwap)
+{
+ while (numToSwap > 0) {
+ *ptr = little2u((unsigned char *) ptr);
+ --numToSwap;
+ ++ptr;
+ }
+}
+
+SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
+{
+ if (path == NULL || mode != SFM_READ || info == NULL)
+ return NULL;
+ FILE *stream = fopen(path, "rb");
+ if (stream == NULL)
+ return NULL;
+ // don't attempt to parse all valid forms, just the most common one
+ unsigned char wav[44];
+ size_t actual;
+ actual = fread(wav, sizeof(char), sizeof(wav), stream);
+ if (actual != sizeof(wav))
+ return NULL;
+ for (;;) {
+ if (memcmp(wav, "RIFF", 4))
+ break;
+ unsigned riffSize = little4u(&wav[4]);
+ if (riffSize < 44)
+ break;
+ if (memcmp(&wav[8], "WAVEfmt ", 8))
+ break;
+ unsigned fmtsize = little4u(&wav[16]);
+ if (fmtsize != 16)
+ break;
+ unsigned format = little2u(&wav[20]);
+ if (format != 1) // PCM
+ break;
+ unsigned channels = little2u(&wav[22]);
+ if (channels != 1 && channels != 2)
+ break;
+ unsigned samplerate = little4u(&wav[24]);
+ if (samplerate == 0)
+ break;
+ // ignore byte rate
+ // ignore block alignment
+ unsigned bitsPerSample = little2u(&wav[34]);
+ if (/*bitsPerSample != 8 &&*/ bitsPerSample != 16)
+ break;
+ unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
+ if (memcmp(&wav[36], "data", 4))
+ break;
+ unsigned dataSize = little4u(&wav[40]);
+ SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
+ handle->stream = stream;
+ handle->bytesPerFrame = bytesPerFrame;
+ handle->remaining = dataSize / bytesPerFrame;
+ handle->info.samplerate = samplerate;
+ handle->info.channels = channels;
+ handle->info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ *info = handle->info;
+ return handle;
+ }
+ return NULL;
+}
+
+void sf_close(SNDFILE *handle)
+{
+ if (handle == NULL)
+ return;
+ (void) fclose(handle->stream);
+ handle->stream = NULL;
+ handle->remaining = 0;
+}
+
+ssize_t sf_readf_short(SNDFILE *handle, short *ptr, size_t desiredFrames)
+{
+ if (handle == NULL || ptr == NULL || !handle->remaining)
+ return 0;
+ if (handle->remaining < desiredFrames)
+ desiredFrames = handle->remaining;
+ size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
+ // does not check for numeric overflow
+ size_t actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
+ size_t actualFrames = actualBytes / handle->bytesPerFrame;
+ handle->remaining -= actualFrames;
+ if (!isLittleEndian())
+ swab(ptr, actualFrames * handle->info.channels);
+ return actualFrames;
+}