summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Perry <avaglir@gmail.com>2017-07-28 02:06:08 -0400
committerNathan Perry <avaglir@gmail.com>2017-07-28 02:06:31 -0400
commit2b1b07806bde7206d15ce87b9f05f1176c965b2f (patch)
tree645cb3460bca7635292cd0c1bf3153146ec4e3f4
parent47877a3045c745e70b2e77a91e1f59e6f432c5df (diff)
initial wav impl
-rw-r--r--downloader/downloader.go10
-rw-r--r--wav/dr_wav.h1960
-rw-r--r--wav/wav.go190
-rw-r--r--wav/wav_test.go14
4 files changed, 2013 insertions, 161 deletions
diff --git a/downloader/downloader.go b/downloader/downloader.go
index 1ebaa1d..cba9b6a 100644
--- a/downloader/downloader.go
+++ b/downloader/downloader.go
@@ -72,9 +72,15 @@ func Download(inUrl string, startTime time.Duration, duration time.Duration) err
return err
}
- wav.NewReader(file, )
-
+ info, err := os.Stat(file.Name())
+ if err != nil {
+ return err
+ }
+ _, err = wav.NewReader(file, info.Size())
+ if err != nil {
+ return err
+ }
return nil
}
diff --git a/wav/dr_wav.h b/wav/dr_wav.h
new file mode 100644
index 0000000..6aea4a3
--- /dev/null
+++ b/wav/dr_wav.h
@@ -0,0 +1,1960 @@
+// WAV audio loader. Public domain. See "unlicense" statement at the end of this file.
+// dr_wav - v0.5g - 2017-06-16
+//
+// David Reid - mackron@gmail.com
+
+// USAGE
+//
+// This is a single-file library. To use it, do something like the following in one .c file.
+// #define DR_WAV_IMPLEMENTATION
+// #include "dr_wav.h"
+//
+// You can then #include this file in other parts of the program as you would with any other header file. Do something
+// like the following to read audio data:
+//
+// drwav wav;
+// if (!drwav_init_file(&wav, "my_song.wav")) {
+// // Error opening WAV file.
+// }
+//
+// dr_int32* pDecodedInterleavedSamples = malloc(wav.totalSampleCount * sizeof(dr_int32));
+// size_t numberOfSamplesActuallyDecoded = drwav_read_s32(&wav, wav.totalSampleCount, pDecodedInterleavedSamples);
+//
+// ...
+//
+// drwav_uninit(&wav);
+//
+// You can also use drwav_open() to allocate and initialize the loader for you:
+//
+// drwav* pWav = drwav_open_file("my_song.wav");
+// if (pWav == NULL) {
+// // Error opening WAV file.
+// }
+//
+// ...
+//
+// drwav_close(pWav);
+//
+// If you just want to quickly open and read the audio data in a single operation you can do something like this:
+//
+// unsigned int channels;
+// unsigned int sampleRate;
+// dr_uint64 totalSampleCount;
+// float* pSampleData = drwav_open_and_read_file_s32("my_song.wav", &channels, &sampleRate, &totalSampleCount);
+// if (pSampleData == NULL) {
+// // Error opening and reading WAV file.
+// }
+//
+// ...
+//
+// drwav_free(pSampleData);
+//
+// The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in
+// this case), but you can still output the audio data in it's internal format (see notes below for supported formats):
+//
+// size_t samplesRead = drwav_read(&wav, wav.totalSampleCount, pDecodedInterleavedSamples);
+//
+// You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for
+// a particular data format:
+//
+// size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer);
+//
+//
+// dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work
+// without any manual intervention.
+//
+//
+//
+// OPTIONS
+// #define these options before including this file.
+//
+// #define DR_WAV_NO_CONVERSION_API
+// Disables conversion APIs such as drwav_read_f32() and drwav_s16_to_f32().
+//
+// #define DR_WAV_NO_STDIO
+// Disables drwav_open_file().
+//
+//
+//
+// QUICK NOTES
+// - Samples are always interleaved.
+// - The default read function does not do any data conversion. Use drwav_read_f32() to read and convert audio data
+// to IEEE 32-bit floating point samples. Likewise, use drwav_read_s32() to read and convert auto data to signed
+// 32-bit PCM. Tested and supported internal formats include the following:
+// - Unsigned 8-bit PCM
+// - Signed 12-bit PCM
+// - Signed 16-bit PCM
+// - Signed 24-bit PCM
+// - Signed 32-bit PCM
+// - IEEE 32-bit floating point.
+// - IEEE 64-bit floating point.
+// - A-law and u-law
+// - Microsoft ADPCM is not currently supported.
+// - dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format.
+
+
+#ifndef dr_wav_h
+#define dr_wav_h
+
+#include <stddef.h>
+
+#ifndef DR_SIZED_TYPES_DEFINED
+#define DR_SIZED_TYPES_DEFINED
+#if defined(_MSC_VER) && _MSC_VER < 1600
+typedef signed char dr_int8;
+typedef unsigned char dr_uint8;
+typedef signed short dr_int16;
+typedef unsigned short dr_uint16;
+typedef signed int dr_int32;
+typedef unsigned int dr_uint32;
+typedef signed __int64 dr_int64;
+typedef unsigned __int64 dr_uint64;
+#else
+#include <stdint.h>
+typedef int8_t dr_int8;
+typedef uint8_t dr_uint8;
+typedef int16_t dr_int16;
+typedef uint16_t dr_uint16;
+typedef int32_t dr_int32;
+typedef uint32_t dr_uint32;
+typedef int64_t dr_int64;
+typedef uint64_t dr_uint64;
+#endif
+typedef dr_uint8 dr_bool8;
+typedef dr_uint32 dr_bool32;
+#define DR_TRUE 1
+#define DR_FALSE 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Common data formats.
+#define DR_WAVE_FORMAT_PCM 0x1
+#define DR_WAVE_FORMAT_ADPCM 0x2 // Not currently supported.
+#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3
+#define DR_WAVE_FORMAT_ALAW 0x6
+#define DR_WAVE_FORMAT_MULAW 0x7
+#define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE
+
+typedef enum
+{
+ drwav_seek_origin_start,
+ drwav_seek_origin_current
+} drwav_seek_origin;
+
+typedef enum
+{
+ drwav_container_riff,
+ drwav_container_w64
+} drwav_container;
+
+// Callback for when data is read. Return value is the number of bytes actually read.
+typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
+
+// Callback for when data needs to be seeked. Return value is true on success; false on failure.
+typedef dr_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
+
+// Structure for internal use. Only used for loaders opened with drwav_open_memory.
+typedef struct
+{
+ const unsigned char* data;
+ size_t dataSize;
+ size_t currentReadPos;
+} drwav__memory_stream;
+
+typedef struct
+{
+ // The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
+ // that require support for data formats not natively supported by dr_wav.
+ unsigned short formatTag;
+
+ // The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc.
+ unsigned short channels;
+
+ // The sample rate. Usually set to something like 44100.
+ unsigned int sampleRate;
+
+ // Average bytes per second. You probably don't need this, but it's left here for informational purposes.
+ unsigned int avgBytesPerSec;
+
+ // Block align. This is equal to the number of channels * bytes per sample.
+ unsigned short blockAlign;
+
+ // Bit's per sample.
+ unsigned short bitsPerSample;
+
+ // The size of the extended data. Only used internally for validation, but left here for informational purposes.
+ unsigned short extendedSize;
+
+ // The number of valid bits per sample. When <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample>
+ // is always rounded up to the nearest multiple of 8. This variable contains information about exactly how
+ // many bits a valid per sample. Mainly used for informational purposes.
+ unsigned short validBitsPerSample;
+
+ // The channel mask. Not used at the moment.
+ unsigned int channelMask;
+
+ // The sub-format, exactly as specified by the wave file.
+ unsigned char subFormat[16];
+} drwav_fmt;
+
+typedef struct
+{
+ // A pointer to the function to call when more data is needed.
+ drwav_read_proc onRead;
+
+ // A pointer to the function to call when the wav file needs to be seeked.
+ drwav_seek_proc onSeek;
+
+ // The user data to pass to callbacks.
+ void* pUserData;
+
+
+ // Whether or not the WAV file is formatted as a standard RIFF file or W64.
+ drwav_container container;
+
+
+ // Structure containing format information exactly as specified by the wav file.
+ drwav_fmt fmt;
+
+ // The sample rate. Will be set to something like 44100.
+ unsigned int sampleRate;
+
+ // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc.
+ unsigned short channels;
+
+ // The bits per sample. Will be set to somthing like 16, 24, etc.
+ unsigned short bitsPerSample;
+
+ // The number of bytes per sample.
+ unsigned short bytesPerSample;
+
+ // Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE).
+ unsigned short translatedFormatTag;
+
+ // The total number of samples making up the audio data. Use <totalSampleCount> * <bytesPerSample> to calculate
+ // the required size of a buffer to hold the entire audio data.
+ dr_uint64 totalSampleCount;
+
+
+ // The number of bytes remaining in the data chunk.
+ dr_uint64 bytesRemaining;
+
+
+ // A hack to avoid a malloc() when opening a decoder with drwav_open_memory().
+ drwav__memory_stream memoryStream;
+} drwav;
+
+
+// Initializes a pre-allocated drwav object.
+//
+// Returns true if successful; false otherwise.
+dr_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData);
+
+// Uninitializes the given drwav object. Use this only for objects initialized with drwav_init().
+void drwav_uninit(drwav* pWav);
+
+
+// Opens a wav file using the given callbacks.
+//
+// Returns null on error. Close the loader with drwav_close().
+//
+// This is different from drwav_init() in that it will allocate the drwav object for you via malloc() before
+// initializing it.
+drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData);
+
+// Uninitializes and deletes the the given drwav object. Use this only for objects created with drwav_open().
+void drwav_close(drwav* pWav);
+
+
+// Reads raw audio data.
+//
+// This is the lowest level function for reading audio data. It simply reads the given number of
+// bytes of the raw internal sample data.
+//
+// Returns the number of bytes actually read.
+size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
+
+// Reads a chunk of audio data in the native internal format.
+//
+// This is typically the most efficient way to retrieve audio data, but it does not do any format
+// conversions which means you'll need to convert the data manually if required.
+//
+// If the return value is less than <samplesToRead> it means the end of the file has been reached or
+// you have requested more samples than can possibly fit in the output buffer.
+//
+// This function will only work when sample data is of a fixed size. If you are using an unusual
+// format which uses variable sized samples, consider using drwav_read_raw(), but don't combine them.
+dr_uint64 drwav_read(drwav* pWav, dr_uint64 samplesToRead, void* pBufferOut);
+
+// Seeks to the given sample.
+//
+// The return value is DR_FALSE if an error occurs, DR_TRUE if successful.
+dr_bool32 drwav_seek_to_sample(drwav* pWav, dr_uint64 sample);
+
+
+
+//// Convertion Utilities ////
+#ifndef DR_WAV_NO_CONVERSION_API
+
+// Reads a chunk of audio data and converts it to signed 16-bit PCM samples.
+//
+// Returns the number of samples actually read.
+//
+// If the return value is less than <samplesToRead> it means the end of the file has been reached.
+dr_uint64 drwav_read_s16(drwav* pWav, dr_uint64 samplesToRead, dr_int16* pBufferOut);
+
+
+// Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples.
+//
+// Returns the number of samples actually read.
+//
+// If the return value is less than <samplesToRead> it means the end of the file has been reached.
+dr_uint64 drwav_read_f32(drwav* pWav, dr_uint64 samplesToRead, float* pBufferOut);
+
+// Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples.
+void drwav_u8_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples.
+void drwav_s16_to_f32(float* pOut, const dr_int16* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples.
+void drwav_s24_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples.
+void drwav_s32_to_f32(float* pOut, const dr_int32* pIn, size_t sampleCount);
+
+// Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples.
+void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
+
+// Low-level function for converting A-law samples to IEEE 32-bit floating point samples.
+void drwav_alaw_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting u-law samples to IEEE 32-bit floating point samples.
+void drwav_ulaw_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount);
+
+
+// Reads a chunk of audio data and converts it to signed 32-bit PCM samples.
+//
+// Returns the number of samples actually read.
+//
+// If the return value is less than <samplesToRead> it means the end of the file has been reached.
+dr_uint64 drwav_read_s32(drwav* pWav, dr_uint64 samplesToRead, dr_int32* pBufferOut);
+
+// Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples.
+void drwav_u8_to_s32(dr_int32* pOut, const dr_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples.
+void drwav_s16_to_s32(dr_int32* pOut, const dr_int16* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples.
+void drwav_s24_to_s32(dr_int32* pOut, const dr_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples.
+void drwav_f32_to_s32(dr_int32* pOut, const float* pIn, size_t sampleCount);
+
+// Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples.
+void drwav_f64_to_s32(dr_int32* pOut, const double* pIn, size_t sampleCount);
+
+// Low-level function for converting A-law samples to signed 32-bit PCM samples.
+void drwav_alaw_to_s32(dr_int32* pOut, const dr_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting u-law samples to signed 32-bit PCM samples.
+void drwav_ulaw_to_s32(dr_int32* pOut, const dr_uint8* pIn, size_t sampleCount);
+
+#endif //DR_WAV_NO_CONVERSION_API
+
+
+//// High-Level Convenience Helpers ////
+
+#ifndef DR_WAV_NO_STDIO
+
+// Helper for initializing a wave file using stdio.
+//
+// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
+// objects because the operating system may restrict the number of file handles an application can have open at
+// any given time.
+dr_bool32 drwav_init_file(drwav* pWav, const char* filename);
+
+// Helper for opening a wave file using stdio.
+//
+// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav
+// objects because the operating system may restrict the number of file handles an application can have open at
+// any given time.
+drwav* drwav_open_file(const char* filename);
+
+#endif //DR_WAV_NO_STDIO
+
+// Helper for initializing a file from a pre-allocated memory buffer.
+//
+// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
+// the lifetime of the drwav object.
+//
+// The buffer should contain the contents of the entire wave file, not just the sample data.
+dr_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize);
+
+// Helper for opening a file from a pre-allocated memory buffer.
+//
+// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
+// the lifetime of the drwav object.
+//
+// The buffer should contain the contents of the entire wave file, not just the sample data.
+drwav* drwav_open_memory(const void* data, size_t dataSize);
+
+
+
+#ifndef DR_WAV_NO_CONVERSION_API
+// Opens and reads a wav file in a single operation.
+dr_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+dr_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+#ifndef DR_WAV_NO_STDIO
+// Opens an decodes a wav file in a single operation.
+dr_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+dr_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+#endif
+
+// Opens an decodes a wav file from a block of memory in a single operation.
+dr_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+dr_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount);
+#endif
+
+// Frees data that was allocated internally by dr_wav.
+void drwav_free(void* pDataReturnedByOpenAndRead);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // dr_wav_h
+
+
+/////////////////////////////////////////////////////
+//
+// IMPLEMENTATION
+//
+/////////////////////////////////////////////////////
+
+#ifdef DR_WAV_IMPLEMENTATION
+#include <stdlib.h>
+#include <string.h> // For memcpy()
+#include <limits.h>
+#include <assert.h>
+
+#ifndef DR_WAV_NO_STDIO
+#include <stdio.h>
+#endif
+
+static const dr_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; // 66666972-912E-11CF-A5D6-28DB04C10000
+static const dr_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 65766177-ACF3-11D3-8CD1-00C04F8EDB8A
+static const dr_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A
+static const dr_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A
+static const dr_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 61746164-ACF3-11D3-8CD1-00C04F8EDB8A
+
+static dr_bool32 drwav__guid_equal(const dr_uint8 a[16], const dr_uint8 b[16])
+{
+ const dr_uint32* a32 = (const dr_uint32*)a;
+ const dr_uint32* b32 = (const dr_uint32*)b;
+
+ return
+ a32[0] == b32[0] &&
+ a32[1] == b32[1] &&
+ a32[2] == b32[2] &&
+ a32[3] == b32[3];
+}
+
+static dr_bool32 drwav__fourcc_equal(const unsigned char* a, const char* b)
+{
+ return
+ a[0] == b[0] &&
+ a[1] == b[1] &&
+ a[2] == b[2] &&
+ a[3] == b[3];
+}
+
+
+
+
+static int drwav__is_little_endian()
+{
+ int n = 1;
+ return (*(char*)&n) == 1;
+}
+
+static unsigned short drwav__bytes_to_u16(const unsigned char* data)
+{
+ if (drwav__is_little_endian()) {
+ return (data[0] << 0) | (data[1] << 8);
+ } else {
+ return (data[1] << 0) | (data[0] << 8);
+ }
+}
+
+static unsigned int drwav__bytes_to_u32(const unsigned char* data)
+{
+ if (drwav__is_little_endian()) {
+ return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+ } else {
+ return (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
+ }
+}
+
+static dr_uint64 drwav__bytes_to_u64(const unsigned char* data)
+{
+ if (drwav__is_little_endian()) {
+ return
+ ((dr_uint64)data[0] << 0ULL) | ((dr_uint64)data[1] << 8ULL) | ((dr_uint64)data[2] << 16ULL) | ((dr_uint64)data[3] << 24ULL) |
+ ((dr_uint64)data[4] << 32ULL) | ((dr_uint64)data[5] << 40ULL) | ((dr_uint64)data[6] << 48ULL) | ((dr_uint64)data[7] << 56ULL);
+ } else {
+ return
+ ((dr_uint64)data[7] << 0ULL) | ((dr_uint64)data[6] << 8ULL) | ((dr_uint64)data[5] << 16ULL) | ((dr_uint64)data[4] << 24ULL) |
+ ((dr_uint64)data[3] << 32ULL) | ((dr_uint64)data[2] << 40ULL) | ((dr_uint64)data[1] << 48ULL) | ((dr_uint64)data[0] << 56ULL);
+ }
+}
+
+static void drwav__bytes_to_guid(const unsigned char* data, dr_uint8* guid)
+{
+ for (int i = 0; i < 16; ++i) {
+ guid[i] = data[i];
+ }
+}
+
+
+typedef struct
+{
+ union
+ {
+ dr_uint8 fourcc[4];
+ dr_uint8 guid[16];
+ } id;
+
+ // The size in bytes of the chunk.
+ dr_uint64 sizeInBytes;
+
+ // RIFF = 2 byte alignment.
+ // W64 = 8 byte alignment.
+ unsigned int paddingSize;
+
+} drwav__chunk_header;
+
+static dr_bool32 drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav__chunk_header* pHeaderOut)
+{
+ if (container == drwav_container_riff) {
+ if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ unsigned char sizeInBytes[4];
+ if (onRead(pUserData, sizeInBytes, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes);
+ pHeaderOut->paddingSize = pHeaderOut->sizeInBytes % 2;
+ } else {
+ if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
+ return DR_FALSE;
+ }
+
+ unsigned char sizeInBytes[8];
+ if (onRead(pUserData, sizeInBytes, 8) != 8) {
+ return DR_FALSE;
+ }
+
+ pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; // <-- Subtract 24 because w64 includes the size of the header.
+ pHeaderOut->paddingSize = pHeaderOut->sizeInBytes % 8;
+ }
+
+ return DR_TRUE;
+}
+
+static dr_bool32 drwav__seek_forward(drwav_seek_proc onSeek, dr_uint64 offset, void* pUserData)
+{
+ dr_uint64 bytesRemainingToSeek = offset;
+ while (bytesRemainingToSeek > 0) {
+ if (bytesRemainingToSeek > 0x7FFFFFFF) {
+ if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ bytesRemainingToSeek -= 0x7FFFFFFF;
+ } else {
+ if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ bytesRemainingToSeek = 0;
+ }
+ }
+
+ return DR_TRUE;
+}
+
+
+static dr_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_fmt* fmtOut)
+{
+ drwav__chunk_header header;
+ if (!drwav__read_chunk_header(onRead, pUserData, container, &header)) {
+ return DR_FALSE;
+ }
+
+
+ // Skip junk chunks.
+ if ((container == drwav_container_riff && drwav__fourcc_equal(header.id.fourcc, "JUNK")) || (container == drwav_container_w64 && drwav__guid_equal(header.id.guid, drwavGUID_W64_JUNK))) {
+ if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
+ return DR_FALSE;
+ }
+
+ return drwav__read_fmt(onRead, onSeek, pUserData, container, fmtOut);
+ }
+
+
+ // Validation.
+ if (container == drwav_container_riff) {
+ if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) {
+ return DR_FALSE;
+ }
+ } else {
+ if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
+ return DR_FALSE;
+ }
+ }
+
+
+ unsigned char fmt[16];
+ if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
+ return DR_FALSE;
+ }
+
+ fmtOut->formatTag = drwav__bytes_to_u16(fmt + 0);
+ fmtOut->channels = drwav__bytes_to_u16(fmt + 2);
+ fmtOut->sampleRate = drwav__bytes_to_u32(fmt + 4);
+ fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8);
+ fmtOut->blockAlign = drwav__bytes_to_u16(fmt + 12);
+ fmtOut->bitsPerSample = drwav__bytes_to_u16(fmt + 14);
+
+ fmtOut->extendedSize = 0;
+ fmtOut->validBitsPerSample = 0;
+ fmtOut->channelMask = 0;
+ memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
+
+ if (header.sizeInBytes > 16) {
+ unsigned char fmt_cbSize[2];
+ if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
+ return DR_FALSE; // Expecting more data.
+ }
+
+ int bytesReadSoFar = 18;
+
+ fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize);
+ if (fmtOut->extendedSize > 0) {
+ if (fmtOut->extendedSize != 22) {
+ return DR_FALSE; // The extended size should be equal to 22.
+ }
+
+ unsigned char fmtext[22];
+ if (onRead(pUserData, fmtext, sizeof(fmtext)) != sizeof(fmtext)) {
+ return DR_FALSE; // Expecting more data.
+ }
+
+ fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0);
+ fmtOut->channelMask = drwav__bytes_to_u32(fmtext + 2);
+ drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat);
+
+ bytesReadSoFar += 22;
+ }
+
+ // Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size.
+ if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+
+ if (header.paddingSize > 0) {
+ if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+
+ return DR_TRUE;
+}
+
+
+#ifndef DR_WAV_NO_STDIO
+static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
+{
+ return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
+}
+
+static dr_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
+{
+ return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
+}
+
+dr_bool32 drwav_init_file(drwav* pWav, const char* filename)
+{
+ FILE* pFile;
+#ifdef _MSC_VER
+ if (fopen_s(&pFile, filename, "rb") != 0) {
+ return DR_FALSE;
+ }
+#else
+ pFile = fopen(filename, "rb");
+ if (pFile == NULL) {
+ return DR_FALSE;
+ }
+#endif
+
+ return drwav_init(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile);
+}
+
+drwav* drwav_open_file(const char* filename)
+{
+ FILE* pFile;
+#ifdef _MSC_VER
+ if (fopen_s(&pFile, filename, "rb") != 0) {
+ return NULL;
+ }
+#else
+ pFile = fopen(filename, "rb");
+ if (pFile == NULL) {
+ return NULL;
+ }
+#endif
+
+ drwav* pWav = drwav_open(drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile);
+ if (pWav == NULL) {
+ fclose(pFile);
+ return NULL;
+ }
+
+ return pWav;
+}
+#endif //DR_WAV_NO_STDIO
+
+
+static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
+{
+ drwav__memory_stream* memory = (drwav__memory_stream*)pUserData;
+ assert(memory != NULL);
+ assert(memory->dataSize >= memory->currentReadPos);
+
+ size_t bytesRemaining = memory->dataSize - memory->currentReadPos;
+ if (bytesToRead > bytesRemaining) {
+ bytesToRead = bytesRemaining;
+ }
+
+ if (bytesToRead > 0) {
+ memcpy(pBufferOut, memory->data + memory->currentReadPos, bytesToRead);
+ memory->currentReadPos += bytesToRead;
+ }
+
+ return bytesToRead;
+}
+
+static dr_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
+{
+ drwav__memory_stream* memory = (drwav__memory_stream*)pUserData;
+ assert(memory != NULL);
+
+ if (origin == drwav_seek_origin_current) {
+ if (offset > 0) {
+ if (memory->currentReadPos + offset > memory->dataSize) {
+ offset = (int)(memory->dataSize - memory->currentReadPos); // Trying to seek too far forward.
+ }
+ } else {
+ if (memory->currentReadPos < (size_t)-offset) {
+ offset = -(int)memory->currentReadPos; // Trying to seek too far backwards.
+ }
+ }
+ } else {
+ if ((dr_uint32)offset <= memory->dataSize) {
+ memory->currentReadPos = offset;
+ } else {
+ memory->currentReadPos = memory->dataSize; // Trying to seek too far forward.
+ }
+ }
+
+ // This will never underflow thanks to the clamps above.
+ memory->currentReadPos += offset;
+ return DR_TRUE;
+}
+
+dr_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize)
+{
+ drwav__memory_stream memoryStream;
+ memoryStream.data = (const unsigned char*)data;
+ memoryStream.dataSize = dataSize;
+ memoryStream.currentReadPos = 0;
+
+ if (!drwav_init(pWav, drwav__on_read_memory, drwav__on_seek_memory, (void*)&memoryStream)) {
+ return DR_FALSE;
+ }
+
+ pWav->memoryStream = memoryStream;
+ pWav->pUserData = &pWav->memoryStream;
+ return DR_TRUE;
+}
+
+drwav* drwav_open_memory(const void* data, size_t dataSize)
+{
+ drwav__memory_stream memoryStream;
+ memoryStream.data = (const unsigned char*)data;
+ memoryStream.dataSize = dataSize;
+ memoryStream.currentReadPos = 0;
+
+ drwav* pWav = drwav_open(drwav__on_read_memory, drwav__on_seek_memory, (void*)&memoryStream);
+ if (pWav == NULL) {
+ return NULL;
+ }
+
+ pWav->memoryStream = memoryStream;
+ pWav->pUserData = &pWav->memoryStream;
+ return pWav;
+}
+
+
+dr_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData)
+{
+ if (onRead == NULL || onSeek == NULL) {
+ return DR_FALSE;
+ }
+
+
+ // The first 4 bytes should be the RIFF identifier.
+ unsigned char riff[4];
+ if (onRead(pUserData, riff, sizeof(riff)) != sizeof(riff)) {
+ return DR_FALSE; // Failed to read data.
+ }
+
+ // The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for
+ // w64 it will start with "riff".
+ if (drwav__fourcc_equal(riff, "RIFF")) {
+ pWav->container = drwav_container_riff;
+ } else if (drwav__fourcc_equal(riff, "riff")) {
+ pWav->container = drwav_container_w64;
+
+ // Check the rest of the GUID for validity.
+ dr_uint8 riff2[12];
+ if (onRead(pUserData, riff2, sizeof(riff2)) != sizeof(riff2)) {
+ return DR_FALSE;
+ }
+
+ for (int i = 0; i < 12; ++i) {
+ if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
+ return DR_FALSE;
+ }
+ }
+ } else {
+ return DR_FALSE; // Unknown or unsupported container.
+ }
+
+
+ if (pWav->container == drwav_container_riff) {
+ // RIFF/WAVE
+ unsigned char chunkSizeBytes[4];
+ if (onRead(pUserData, chunkSizeBytes, sizeof(chunkSizeBytes)) != sizeof(chunkSizeBytes)) {
+ return DR_FALSE;
+ }
+
+ unsigned int chunkSize = drwav__bytes_to_u32(chunkSizeBytes);
+ if (chunkSize < 36) {
+ return DR_FALSE; // Chunk size should always be at least 36 bytes.
+ }
+
+ unsigned char wave[4];
+ if (onRead(pUserData, wave, sizeof(wave)) != sizeof(wave)) {
+ return DR_FALSE;
+ }
+
+ if (!drwav__fourcc_equal(wave, "WAVE")) {
+ return DR_FALSE; // Expecting "WAVE".
+ }
+ } else {
+ // W64
+ unsigned char chunkSize[8];
+ if (onRead(pUserData, chunkSize, sizeof(chunkSize)) != sizeof(chunkSize)) {
+ return DR_FALSE;
+ }
+
+ if (drwav__bytes_to_u64(chunkSize) < 84) {
+ return DR_FALSE;
+ }
+
+ dr_uint8 wave[16];
+ if (onRead(pUserData, wave, sizeof(wave)) != sizeof(wave)) {
+ return DR_FALSE;
+ }
+
+ if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) {
+ return DR_FALSE;
+ }
+ }
+
+
+ // The next 24 bytes should be the "fmt " chunk.
+ drwav_fmt fmt;
+ if (!drwav__read_fmt(onRead, onSeek, pUserData, pWav->container, &fmt)) {
+ return DR_FALSE; // Failed to read the "fmt " chunk.
+ }
+
+
+ // Translate the internal format.
+ unsigned short translatedFormatTag = fmt.formatTag;
+ if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
+ translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0);
+ }
+
+
+ // The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop.
+ dr_uint64 dataSize;
+ for (;;)
+ {
+ drwav__chunk_header header;
+ if (!drwav__read_chunk_header(onRead, pUserData, pWav->container, &header)) {
+ return DR_FALSE;
+ }
+
+ dataSize = header.sizeInBytes;
+ if (pWav->container == drwav_container_riff) {
+ if (drwav__fourcc_equal(header.id.fourcc, "data")) {
+ break;
+ }
+ } else {
+ if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
+ break;
+ }
+ }
+
+ // If we get here it means we didn't find the "data" chunk. Seek past it.
+
+ // Make sure we seek past the padding.
+ dataSize += header.paddingSize;
+ drwav__seek_forward(onSeek, dataSize, pUserData);
+ }
+
+ // At this point we should be sitting on the first byte of the raw audio data.
+
+ pWav->onRead = onRead;
+ pWav->onSeek = onSeek;
+ pWav->pUserData = pUserData;
+ pWav->fmt = fmt;
+ pWav->sampleRate = fmt.sampleRate;
+ pWav->channels = fmt.channels;
+ pWav->bitsPerSample = fmt.bitsPerSample;
+ pWav->bytesPerSample = (unsigned int)(fmt.blockAlign / fmt.channels);
+ pWav->translatedFormatTag = translatedFormatTag;
+ pWav->totalSampleCount = dataSize / pWav->bytesPerSample;
+ pWav->bytesRemaining = dataSize;
+
+ return DR_TRUE;
+}
+
+void drwav_uninit(drwav* pWav)
+{
+ if (pWav == NULL) {
+ return;
+ }
+
+#ifndef DR_WAV_NO_STDIO
+ // If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file()
+ // was used by looking at the onRead and onSeek callbacks.
+ if (pWav->onRead == drwav__on_read_stdio) {
+ fclose((FILE*)pWav->pUserData);
+ }
+#endif
+}
+
+
+drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData)
+{
+ drwav* pWav = (drwav*)malloc(sizeof(*pWav));
+ if (pWav == NULL) {
+ return NULL;
+ }
+
+ if (!drwav_init(pWav, onRead, onSeek, pUserData)) {
+ free(pWav);
+ return NULL;
+ }
+
+ return pWav;
+}
+
+void drwav_close(drwav* pWav)
+{
+ drwav_uninit(pWav);
+ free(pWav);
+}
+
+
+size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
+{
+ if (pWav == NULL || bytesToRead == 0 || pBufferOut == NULL) {
+ return 0;
+ }
+
+ if (bytesToRead > pWav->bytesRemaining) {
+ bytesToRead = (size_t)pWav->bytesRemaining;
+ }
+
+ size_t bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
+
+ pWav->bytesRemaining -= bytesRead;
+ return bytesRead;
+}
+
+dr_uint64 drwav_read(drwav* pWav, dr_uint64 samplesToRead, void* pBufferOut)
+{
+ if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) {
+ return 0;
+ }
+
+ // Don't try to read more samples than can potentially fit in the output buffer.
+ if (samplesToRead * pWav->bytesPerSample > SIZE_MAX) {
+ samplesToRead = SIZE_MAX / pWav->bytesPerSample;
+ }
+
+ size_t bytesRead = drwav_read_raw(pWav, (size_t)(samplesToRead * pWav->bytesPerSample), pBufferOut);
+ return bytesRead / pWav->bytesPerSample;
+}
+
+dr_bool32 drwav_seek_to_sample(drwav* pWav, dr_uint64 sample)
+{
+ // Seeking should be compatible with wave files > 2GB.
+
+ if (pWav == NULL || pWav->onSeek == NULL) {
+ return 0;
+ }
+
+ // If there are no samples, just return DR_TRUE without doing anything.
+ if (pWav->totalSampleCount == 0) {
+ return 1;
+ }
+
+ // Make sure the sample is clamped.
+ if (sample >= pWav->totalSampleCount) {
+ sample = pWav->totalSampleCount - 1;
+ }
+
+
+ dr_uint64 totalSizeInBytes = pWav->totalSampleCount * pWav->bytesPerSample;
+ assert(totalSizeInBytes >= pWav->bytesRemaining);
+
+ dr_uint64 currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
+ dr_uint64 targetBytePos = sample * pWav->bytesPerSample;
+
+ dr_uint64 offset;
+ int direction;
+ if (currentBytePos < targetBytePos) {
+ // Offset forward.
+ offset = targetBytePos - currentBytePos;
+ direction = 1;
+ } else {
+ // Offset backwards.
+ offset = currentBytePos - targetBytePos;
+ direction = -1;
+ }
+
+ while (offset > 0)
+ {
+ int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
+ pWav->onSeek(pWav->pUserData, offset32 * direction, drwav_seek_origin_current);
+
+ pWav->bytesRemaining -= (offset32 * direction);
+ offset -= offset32;
+ }
+
+ return 1;
+}
+
+
+#ifndef DR_WAV_NO_CONVERSION_API
+#define drwav_min(a, b) (((a) < (b)) ? (a) : (b))
+
+static unsigned short g_drwavAlawTable[256] = {
+ 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
+ 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
+ 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
+ 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
+ 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
+ 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
+ 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
+ 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
+ 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
+ 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
+ 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
+ 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
+ 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
+ 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
+ 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
+ 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
+};
+
+static unsigned short g_drwavMulawTable[256] = {
+ 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
+ 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
+ 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
+ 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
+ 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
+ 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
+ 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
+ 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
+ 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
+ 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
+ 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
+ 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
+ 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
+ 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
+ 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
+ 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
+};
+
+
+dr_uint64 drwav_read_s16(drwav* pWav, dr_uint64 samplesToRead, dr_int16* pBufferOut)
+{
+ // TODO: Optimize me. This is a temporary implementation for the moment.
+ dr_uint64 totalSamplesRead = 0;
+
+ while (samplesToRead > 0) {
+ dr_int32 samples32[4096];
+ dr_uint64 samplesJustRead = drwav_read_s32(pWav, (samplesToRead > 4096) ? 4096 : samplesToRead, samples32);
+ if (samplesJustRead == 0) {
+ break; // Reached the end.
+ }
+
+ // s32 -> s16
+ for (dr_uint64 i = 0; i < samplesJustRead; ++i) {
+ pBufferOut[i] = (dr_int16)(samples32[i] >> 16);
+ }
+
+ totalSamplesRead += samplesJustRead;
+ samplesToRead -= samplesJustRead;
+ pBufferOut += samplesJustRead;
+ }
+
+ return totalSamplesRead;
+}
+
+
+static int drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned short bytesPerSample)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return 0;
+ }
+
+ // Special case for 8-bit sample data because it's treated as unsigned.
+ if (bytesPerSample == 1) {
+ drwav_u8_to_f32(pOut, pIn, sampleCount);
+ return 1;
+ }
+
+
+ // Slightly more optimal implementation for common formats.
+ if (bytesPerSample == 2) {
+ drwav_s16_to_f32(pOut, (const dr_int16*)pIn, sampleCount);
+ return 1;
+ }
+ if (bytesPerSample == 3) {
+ drwav_s24_to_f32(pOut, pIn, sampleCount);
+ return 1;
+ }
+ if (bytesPerSample == 4) {
+ drwav_s32_to_f32(pOut, (const dr_int32*)pIn, sampleCount);
+ return 1;
+ }
+
+
+ // Generic, slow converter.
+ for (unsigned int i = 0; i < sampleCount; ++i)
+ {
+ unsigned int sample = 0;
+ unsigned int shift = (8 - bytesPerSample) * 8;
+ for (unsigned short j = 0; j < bytesPerSample && j < 4; ++j) {
+ sample |= (unsigned int)(pIn[j]) << shift;
+ shift += 8;
+ }
+
+ pIn += bytesPerSample;
+ *pOut++ = (float)((int)sample / 2147483648.0);
+ }
+
+ return 1;
+}
+
+static int drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned short bytesPerSample)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return 0;
+ }
+
+ if (bytesPerSample == 4) {
+ for (unsigned int i = 0; i < sampleCount; ++i) {
+ *pOut++ = ((float*)pIn)[i];
+ }
+ return 1;
+ } else {
+ drwav_f64_to_f32(pOut, (double*)pIn, sampleCount);
+ return 1;
+ }
+}
+
+
+dr_uint64 drwav_read_f32(drwav* pWav, dr_uint64 samplesToRead, float* pBufferOut)
+{
+ if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) {
+ return 0;
+ }
+
+ // Fast path.
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bytesPerSample == 4) {
+ return drwav_read(pWav, samplesToRead, pBufferOut);
+ }
+
+
+ // Don't try to read more samples than can potentially fit in the output buffer.
+ if (samplesToRead * sizeof(float) > SIZE_MAX) {
+ samplesToRead = SIZE_MAX / sizeof(float);
+ }
+
+
+ // Slow path. Need to read and convert.
+ dr_uint64 totalSamplesRead = 0;
+
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM)
+ {
+ unsigned char sampleData[4096];
+ while (samplesToRead > 0)
+ {
+ dr_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+ if (samplesRead == 0) {
+ break;
+ }
+
+ drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+ pBufferOut += samplesRead;
+
+ samplesToRead -= samplesRead;
+ totalSamplesRead += samplesRead;
+ }
+
+ return totalSamplesRead;
+ }
+
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT)
+ {
+ unsigned char sampleData[4096];
+ while (samplesToRead > 0)
+ {
+ dr_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+ if (samplesRead == 0) {
+ break;
+ }
+
+ drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+ pBufferOut += samplesRead;
+
+ samplesToRead -= samplesRead;
+ totalSamplesRead += samplesRead;
+ }
+
+ return totalSamplesRead;
+ }
+
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW)
+ {
+ unsigned char sampleData[4096];
+ while (samplesToRead > 0)
+ {
+ dr_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+ if (samplesRead == 0) {
+ break;
+ }
+
+ drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
+ pBufferOut += samplesRead;
+
+ samplesToRead -= samplesRead;
+ totalSamplesRead += samplesRead;
+ }
+
+ return totalSamplesRead;
+ }
+
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW)
+ {
+ unsigned char sampleData[4096];
+ while (samplesToRead > 0)
+ {
+ dr_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+ if (samplesRead == 0) {
+ break;
+ }
+
+ drwav_ulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
+ pBufferOut += samplesRead;
+
+ samplesToRead -= samplesRead;
+ totalSamplesRead += samplesRead;
+ }
+
+ return totalSamplesRead;
+ }
+
+ return totalSamplesRead;
+}
+
+void drwav_u8_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = (pIn[i] / 255.0f) * 2 - 1;
+ }
+}
+
+void drwav_s16_to_f32(float* pOut, const dr_int16* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = pIn[i] / 32768.0f;
+ }
+}
+
+void drwav_s24_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ unsigned int s0 = pIn[i*3 + 0];
+ unsigned int s1 = pIn[i*3 + 1];
+ unsigned int s2 = pIn[i*3 + 2];
+
+ int sample32 = (int)((s0 << 8) | (s1 << 16) | (s2 << 24));
+ *pOut++ = (float)(sample32 / 2147483648.0);
+ }
+}
+
+void drwav_s32_to_f32(float* pOut, const dr_int32* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = (float)(pIn[i] / 2147483648.0);
+ }
+}
+
+void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = (float)pIn[i];
+ }
+}
+
+void drwav_alaw_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = g_drwavAlawTable[pIn[i]] / 32768.0f;
+ }
+}
+
+void drwav_ulaw_to_f32(float* pOut, const dr_uint8* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = g_drwavMulawTable[pIn[i]] / 32768.0f;
+ }
+}
+
+
+
+static int drwav__pcm_to_s32(dr_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return 0;
+ }
+
+ // Special case for 8-bit sample data because it's treated as unsigned.
+ if (bytesPerSample == 1) {
+ drwav_u8_to_s32(pOut, pIn, totalSampleCount);
+ return 1;
+ }
+
+
+ // Slightly more optimal implementation for common formats.
+ if (bytesPerSample == 2) {
+ drwav_s16_to_s32(pOut, (const dr_int16*)pIn, totalSampleCount);
+ return 1;
+ }
+ if (bytesPerSample == 3) {
+ drwav_s24_to_s32(pOut, pIn, totalSampleCount);
+ return 1;
+ }
+ if (bytesPerSample == 4) {
+ for (unsigned int i = 0; i < totalSampleCount; ++i) {
+ *pOut++ = ((dr_int32*)pIn)[i];
+ }
+ return 1;
+ }
+
+
+ // Generic, slow converter.
+ for (unsigned int i = 0; i < totalSampleCount; ++i)
+ {
+ unsigned int sample = 0;
+ unsigned int shift = (8 - bytesPerSample) * 8;
+ for (unsigned short j = 0; j < bytesPerSample && j < 4; ++j) {
+ sample |= (unsigned int)(pIn[j]) << shift;
+ shift += 8;
+ }
+
+ pIn += bytesPerSample;
+ *pOut++ = sample;
+ }
+
+ return 1;
+}
+
+static int drwav__ieee_to_s32(dr_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return 0;
+ }
+
+ if (bytesPerSample == 4) {
+ drwav_f32_to_s32(pOut, (float*)pIn, totalSampleCount);
+ return 1;
+ } else {
+ drwav_f64_to_s32(pOut, (double*)pIn, totalSampleCount);
+ return 1;
+ }
+}
+
+dr_uint64 drwav_read_s32(drwav* pWav, dr_uint64 samplesToRead, dr_int32* pBufferOut)
+{
+ if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) {
+ return 0;
+ }
+
+ // Fast path.
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bytesPerSample == 4) {
+ return drwav_read(pWav, samplesToRead, pBufferOut);
+ }
+
+
+ // Don't try to read more samples than can potentially fit in the output buffer.
+ if (samplesToRead * sizeof(dr_int32) > SIZE_MAX) {
+ samplesToRead = SIZE_MAX / sizeof(dr_int32);
+ }
+
+
+ // Slow path. Need to read and convert.
+ dr_uint64 totalSamplesRead = 0;
+
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM)
+ {
+ unsigned char sampleData[4096];
+ while (samplesToRead > 0)
+ {
+ dr_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+ if (samplesRead == 0) {
+ break;
+ }
+
+ drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+ pBufferOut += samplesRead;
+
+ samplesToRead -= samplesRead;
+ totalSamplesRead += samplesRead;
+ }
+
+ return totalSamplesRead;
+ }
+
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT)
+ {
+ unsigned char sampleData[4096];
+ while (samplesToRead > 0)
+ {
+ dr_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+ if (samplesRead == 0) {
+ break;
+ }
+
+ drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+ pBufferOut += samplesRead;
+
+ samplesToRead -= samplesRead;
+ totalSamplesRead += samplesRead;
+ }
+
+ return totalSamplesRead;
+ }
+
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW)
+ {
+ unsigned char sampleData[4096];
+ while (samplesToRead > 0)
+ {
+ dr_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+ if (samplesRead == 0) {
+ break;
+ }
+
+ drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
+ pBufferOut += samplesRead;
+
+ samplesToRead -= samplesRead;
+ totalSamplesRead += samplesRead;
+ }
+
+ return totalSamplesRead;
+ }
+
+ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW)
+ {
+ unsigned char sampleData[4096];
+ while (samplesToRead > 0)
+ {
+ dr_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+ if (samplesRead == 0) {
+ break;
+ }
+
+ drwav_ulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
+ pBufferOut += samplesRead;
+
+ samplesToRead -= samplesRead;
+ totalSamplesRead += samplesRead;
+ }
+
+ return totalSamplesRead;
+ }
+
+ return totalSamplesRead;
+}
+
+void drwav_u8_to_s32(dr_int32* pOut, const dr_uint8* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = ((int)pIn[i] - 128) << 24;
+ }
+}
+
+void drwav_s16_to_s32(dr_int32* pOut, const dr_int16* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = pIn[i] << 16;
+ }
+}
+
+void drwav_s24_to_s32(dr_int32* pOut, const dr_uint8* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ unsigned int s0 = pIn[i*3 + 0];
+ unsigned int s1 = pIn[i*3 + 1];
+ unsigned int s2 = pIn[i*3 + 2];
+
+ dr_int32 sample32 = (dr_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
+ *pOut++ = sample32;
+ }
+}
+
+void drwav_f32_to_s32(dr_int32* pOut, const float* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = (dr_int32)(2147483648.0 * pIn[i]);
+ }
+}
+
+void drwav_f64_to_s32(dr_int32* pOut, const double* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = (dr_int32)(2147483648.0 * pIn[i]);
+ }
+}
+
+void drwav_alaw_to_s32(dr_int32* pOut, const dr_uint8* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < sampleCount; ++i) {
+ *pOut++ = ((dr_int32)g_drwavAlawTable[pIn[i]]) << 16;
+ }
+}
+
+void drwav_ulaw_to_s32(dr_int32* pOut, const dr_uint8* pIn, size_t sampleCount)
+{
+ if (pOut == NULL || pIn == NULL) {
+ return;
+ }
+
+ for (size_t i= 0; i < sampleCount; ++i) {
+ *pOut++ = ((dr_int32)g_drwavMulawTable[pIn[i]]) << 16;
+ }
+}
+
+
+
+dr_int16* drwav__read_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ assert(pWav != NULL);
+
+ dr_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(dr_int16);
+ if (sampleDataSize > SIZE_MAX) {
+ drwav_uninit(pWav);
+ return NULL; // File's too big.
+ }
+
+ dr_int16* pSampleData = (dr_int16*)malloc((size_t)sampleDataSize); // <-- Safe cast due to the check above.
+ if (pSampleData == NULL) {
+ drwav_uninit(pWav);
+ return NULL; // Failed to allocate memory.
+ }
+
+ dr_uint64 samplesRead = drwav_read_s16(pWav, (size_t)pWav->totalSampleCount, pSampleData);
+ if (samplesRead != pWav->totalSampleCount) {
+ free(pSampleData);
+ drwav_uninit(pWav);
+ return NULL; // There was an error reading the samples.
+ }
+
+ drwav_uninit(pWav);
+
+ if (sampleRate) *sampleRate = pWav->sampleRate;
+ if (channels) *channels = pWav->channels;
+ if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount;
+ return pSampleData;
+}
+
+float* drwav__read_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ assert(pWav != NULL);
+
+ dr_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(float);
+ if (sampleDataSize > SIZE_MAX) {
+ drwav_uninit(pWav);
+ return NULL; // File's too big.
+ }
+
+ float* pSampleData = (float*)malloc((size_t)sampleDataSize); // <-- Safe cast due to the check above.
+ if (pSampleData == NULL) {
+ drwav_uninit(pWav);
+ return NULL; // Failed to allocate memory.
+ }
+
+ dr_uint64 samplesRead = drwav_read_f32(pWav, (size_t)pWav->totalSampleCount, pSampleData);
+ if (samplesRead != pWav->totalSampleCount) {
+ free(pSampleData);
+ drwav_uninit(pWav);
+ return NULL; // There was an error reading the samples.
+ }
+
+ drwav_uninit(pWav);
+
+ if (sampleRate) *sampleRate = pWav->sampleRate;
+ if (channels) *channels = pWav->channels;
+ if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount;
+ return pSampleData;
+}
+
+dr_int32* drwav__read_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ assert(pWav != NULL);
+
+ dr_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(dr_int32);
+ if (sampleDataSize > SIZE_MAX) {
+ drwav_uninit(pWav);
+ return NULL; // File's too big.
+ }
+
+ dr_int32* pSampleData = (dr_int32*)malloc((size_t)sampleDataSize); // <-- Safe cast due to the check above.
+ if (pSampleData == NULL) {
+ drwav_uninit(pWav);
+ return NULL; // Failed to allocate memory.
+ }
+
+ dr_uint64 samplesRead = drwav_read_s32(pWav, (size_t)pWav->totalSampleCount, pSampleData);
+ if (samplesRead != pWav->totalSampleCount) {
+ free(pSampleData);
+ drwav_uninit(pWav);
+ return NULL; // There was an error reading the samples.
+ }
+
+ drwav_uninit(pWav);
+
+ if (sampleRate) *sampleRate = pWav->sampleRate;
+ if (channels) *channels = pWav->channels;
+ if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount;
+ return pSampleData;
+}
+
+
+dr_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init(&wav, onRead, onSeek, pUserData)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount);
+}
+
+float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init(&wav, onRead, onSeek, pUserData)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount);
+}
+
+dr_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init(&wav, onRead, onSeek, pUserData)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount);
+}
+
+#ifndef DR_WAV_NO_STDIO
+dr_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init_file(&wav, filename)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount);
+}
+
+float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init_file(&wav, filename)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount);
+}
+
+dr_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init_file(&wav, filename)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount);
+}
+#endif
+
+dr_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init_memory(&wav, data, dataSize)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount);
+}
+
+float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init_memory(&wav, data, dataSize)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount);
+}
+
+dr_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, dr_uint64* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drwav wav;
+ if (!drwav_init_memory(&wav, data, dataSize)) {
+ return NULL;
+ }
+
+ return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount);
+}
+#endif //DR_WAV_NO_CONVERSION_API
+
+
+void drwav_free(void* pDataReturnedByOpenAndRead)
+{
+ free(pDataReturnedByOpenAndRead);
+}
+
+#endif //DR_WAV_IMPLEMENTATION
+
+
+// REVISION HISTORY
+//
+// v0.5g - 2017-07-16
+// - Change underlying type for booleans to unsigned.
+//
+// v0.5f - 2017-04-04
+// - Fix a minor bug with drwav_open_and_read_s16() and family.
+//
+// v0.5e - 2016-12-29
+// - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this.
+// - Minor fixes to documentation.
+//
+// v0.5d - 2016-12-28
+// - Use dr_int*/dr_uint* sized types to improve compiler support.
+//
+// v0.5c - 2016-11-11
+// - Properly handle JUNK chunks that come before the FMT chunk.
+//
+// v0.5b - 2016-10-23
+// - A minor change to dr_bool8 and dr_bool32 types.
+//
+// v0.5a - 2016-10-11
+// - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering.
+// - Improve A-law and mu-law efficiency.
+//
+// v0.5 - 2016-09-29
+// - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to
+// keep it consistent with dr_audio and dr_flac.
+//
+// v0.4b - 2016-09-18
+// - Fixed a typo in documentation.
+//
+// v0.4a - 2016-09-18
+// - Fixed a typo.
+// - Change date format to ISO 8601 (YYYY-MM-DD)
+//
+// v0.4 - 2016-07-13
+// - API CHANGE. Make onSeek consistent with dr_flac.
+// - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac.
+// - Added support for Sony Wave64.
+//
+// v0.3a - 2016-05-28
+// - API CHANGE. Return dr_bool32 instead of int in onSeek callback.
+// - Fixed a memory leak.
+//
+// v0.3 - 2016-05-22
+// - Lots of API changes for consistency.
+//
+// v0.2a - 2016-05-16
+// - Fixed Linux/GCC build.
+//
+// v0.2 - 2016-05-11
+// - Added support for reading data as signed 32-bit PCM for consistency with dr_flac.
+//
+// v0.1a - 2016-05-07
+// - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize.
+//
+// v0.1 - 2016-05-04
+// - Initial versioned release.
+
+
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
+*/ \ No newline at end of file
diff --git a/wav/wav.go b/wav/wav.go
index b82ec16..5650a2d 100644
--- a/wav/wav.go
+++ b/wav/wav.go
@@ -1,177 +1,53 @@
package wav
+// #define DR_WAV_IMPLEMENTATION
+// #include "dr_wav.h"
+import "C"
import (
- "bytes"
- "encoding/binary"
"fmt"
- "io"
- "io/ioutil"
- "os"
)
-type WavFile struct {
- Header Header
- Format FormatChunk
- Data DataChunk
-}
-
-type Header struct {
- GroupID [4]uint8
- FileLength uint32
- RiffType [4]uint8
-}
-
-type FormatChunk struct {
- GroupID [4]uint8
- ChunkSize uint32
- FormatTag uint16
- Channels uint16
- SampleRate uint32
- ByteRate uint32
- Alignment uint16
- BitDensity uint32
-}
-
-type DataChunk struct {
- GroupID [4]uint8
- ChunkSize uint32
- Samples io.Reader
-}
-
-func Load(filename string) (*WavFile, error) {
- file, err := os.Open(filename)
-
- if err != nil {
- return nil, err
- }
-
- load16 := func(b []byte) (uint16, error) {
- var out uint16
- err := binary.Read(bytes.NewBuffer(b), binary.LittleEndian, &out)
- return out, err
- }
+const batchSize = 64
- load32 := func(b []byte) (uint32, error) {
- var out uint32
- err := binary.Read(bytes.NewBuffer(b), binary.LittleEndian, &out)
- return out, err
-
- }
-
- b, err := ioutil.ReadAll(io.LimitReader(file, 40))
- if err != nil {
- return nil, err
+func Load(filename string) (<-chan [2]int16, error) {
+ cfname := C.CString(filename)
+ wav := C.drwav_open_file(cfname)
+ if wav == nil {
+ return nil, fmt.Errorf("Unable to initialize drwav.")
}
- h := Header{}
- h.FileLength, err = load32(b[4:36])
- if err != nil {
- return nil, err
+ if int(wav.channels) != 2 {
+ C.drwav_close(wav)
+ return nil, fmt.Errorf("Wrong number of channels!")
}
- h.FileLength -= 8 // subtract RIFF/WAVE markers
-
- for i := 0; i < 4; i++ {
- h.GroupID[i] = b[i]
- h.RiffType[i] = b[i+36]
- }
-
- fmt.Println(h)
- fmt.Println(string(h.RiffType[:]))
- if string(h.GroupID[:]) != "RIFF" { // || string(h.RiffType[:]) != "WAVE" {
- return nil, fmt.Errorf("invalid header!")
+ if int(wav.sampleRate) != 44100 {
+ C.drwav_close(wav)
+ return nil, fmt.Errorf("Wrong sample rate.")
}
- f := FormatChunk{}
+ ch := make(chan [2]int16, 1024*32)
- file.Seek(40, io.SeekStart)
- b, err = ioutil.ReadAll(io.LimitReader(file, 36))
- if err != nil {
- return nil, err
- }
-
- for i := 0; i < 4; i++ {
- f.GroupID[i] = b[i]
- }
+ go func() {
+ buf := C.malloc(C.size_t(batchSize * wav.bytesPerSample))
+ defer C.free(buf)
+ defer C.drwav_close(wav)
- f.ChunkSize, err = load32(b[4:36])
- if err != nil {
- return nil, err
- }
+ for i := 0; i < int(wav.totalSampleCount)/batchSize; i++ {
+ readSamples := C.drwav_read_s16(wav, batchSize, (*C.dr_int16)(buf))
- file.Seek(76, io.SeekStart)
- b, err = ioutil.ReadAll(io.LimitReader(file, int64(f.ChunkSize)))
- if err != nil {
- return nil, err
- }
+ slc := (*[1 << 30]int16)(buf)[:readSamples:readSamples]
- f.FormatTag, err = load16(b[36:52])
- if err != nil {
- return nil, err
- }
-
- f.Channels, err = load16(b[52:68])
- if err != nil {
- return nil, err
- }
-
- f.SampleRate, err = load32(b[68:100])
- if err != nil {
- return nil, err
- }
-
- f.ByteRate, err = load32(b[100:132])
- if err != nil {
- return nil, err
- }
-
- f.Alignment, err = load16(b[132:148])
- if err != nil {
- return nil, err
- }
-
- f.BitDensity, err = load32(b[138:180])
- if err != nil {
- return nil, err
- }
-
- if string(f.GroupID[:]) != "fmt " ||
- f.FormatTag != 1 ||
- f.Alignment != uint16((uint32(f.Channels)*f.BitDensity/8)&0xff) {
- return nil, fmt.Errorf("invalid format block!")
- }
-
- if f.BitDensity != 16 || f.Channels != 2 || f.SampleRate != 44100 {
- return nil, fmt.Errorf("wrong pcm format!")
- }
-
- d := DataChunk{}
-
- file.Seek(220, io.SeekStart)
- b, err = ioutil.ReadAll(io.LimitReader(file, 36))
- if err != nil {
- return nil, err
- }
-
- for i := 0; i < 4; i++ {
- d.GroupID[i] = b[i]
- }
-
- d.ChunkSize, err = load32(b[4:])
- if err != nil {
- return nil, err
- }
-
- if string(f.GroupID[:]) != "fmt " {
- return nil, fmt.Errorf("invalid data block!")
- }
+ for i := 0; i < int(readSamples); i += 2 {
+ ch <- [2]int16{slc[i], slc[i+1]}
+ }
- file.Seek(256, io.SeekStart)
- d.Samples = io.LimitReader(file, int64(d.ChunkSize))
+ if readSamples < batchSize {
+ break
+ }
+ }
+ close(ch)
+ }()
- return &WavFile{
- Header: h,
- Format: f,
- Data: d,
- }, nil
+ return ch, nil
}
diff --git a/wav/wav_test.go b/wav/wav_test.go
index 4fa64db..a641b8f 100644
--- a/wav/wav_test.go
+++ b/wav/wav_test.go
@@ -6,10 +6,20 @@ import (
)
func TestLoad(t *testing.T) {
- wf, err := Load("../downloader/out.wav")
+ ch, err := Load("../downloader/out.wav")
if err != nil {
t.Error(err)
}
- fmt.Println(wf)
+ ct := 0
+
+ for _ = range ch {
+ //fmt.Println(i)
+ ct++
+ if ct%10000 == 0 {
+ fmt.Println(ct)
+ }
+ }
+
+ fmt.Println("COUNT: ", ct)
}