yum-archive/TaSTT-Whisper

High-performance GPGPU inference of OpenAI's Whisper automatic speech recognition (ASR) model

git clone https://git.yummers.dev/yum-archive/TaSTT-Whisper

KonstantinSource codes8c4603c

master
235.7 KiB6434 linesraw
1/*
2WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
3dr_wav - v0.12.16 - 2020-12-02
4
5David Reid - mackron@gmail.com
6
7GitHub: https://github.com/mackron/dr_libs
8*/
9
10/*
11RELEASE NOTES - VERSION 0.12
12============================
13Version 0.12 includes breaking changes to custom chunk handling.
14
15
16Changes to Chunk Callback
17-------------------------
18dr_wav supports the ability to fire a callback when a chunk is encounted (except for WAVE and FMT chunks). The callback has been updated to include both the
19container (RIFF or Wave64) and the FMT chunk which contains information about the format of the data in the wave file.
20
21Previously, there was no direct way to determine the container, and therefore no way to discriminate against the different IDs in the chunk header (RIFF and
22Wave64 containers encode chunk ID's differently). The `container` parameter can be used to know which ID to use.
23
24Sometimes it can be useful to know the data format at the time the chunk callback is fired. A pointer to a `drwav_fmt` object is now passed into the chunk
25callback which will give you information about the data format. To determine the sample format, use `drwav_fmt_get_format()`. This will return one of the
26`DR_WAVE_FORMAT_*` tokens.
27*/
28
29/*
30Introduction
31============
32This is a single file library. To use it, do something like the following in one .c file.
33    
34    ```c
35    #define DR_WAV_IMPLEMENTATION
36    #include "dr_wav.h"
37    ```
38
39You 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:
40
41    ```c
42    drwav wav;
43    if (!drwav_init_file(&wav, "my_song.wav", NULL)) {
44        // Error opening WAV file.
45    }
46
47    drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32));
48    size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
49
50    ...
51
52    drwav_uninit(&wav);
53    ```
54
55If you just want to quickly open and read the audio data in a single operation you can do something like this:
56
57    ```c
58    unsigned int channels;
59    unsigned int sampleRate;
60    drwav_uint64 totalPCMFrameCount;
61    float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount, NULL);
62    if (pSampleData == NULL) {
63        // Error opening and reading WAV file.
64    }
65
66    ...
67
68    drwav_free(pSampleData);
69    ```
70
71The 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
72audio data in its internal format (see notes below for supported formats):
73
74    ```c
75    size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
76    ```
77
78You 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:
79
80    ```c
81    size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer);
82    ```
83
84dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at `drwav_init_write()`,
85`drwav_init_file_write()`, etc. Use `drwav_write_pcm_frames()` to write samples, or `drwav_write_raw()` to write raw data in the "data" chunk.
86
87    ```c
88    drwav_data_format format;
89    format.container = drwav_container_riff;     // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
90    format.format = DR_WAVE_FORMAT_PCM;          // <-- Any of the DR_WAVE_FORMAT_* codes.
91    format.channels = 2;
92    format.sampleRate = 44100;
93    format.bitsPerSample = 16;
94    drwav_init_file_write(&wav, "data/recording.wav", &format, NULL);
95
96    ...
97
98    drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples);
99    ```
100
101dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work without any manual intervention.
102
103
104Build Options
105=============
106#define these options before including this file.
107
108#define DR_WAV_NO_CONVERSION_API
109  Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`.
110
111#define DR_WAV_NO_STDIO
112  Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc.
113
114
115
116Notes
117=====
118- Samples are always interleaved.
119- The default read function does not do any data conversion. Use `drwav_read_pcm_frames_f32()`, `drwav_read_pcm_frames_s32()` and `drwav_read_pcm_frames_s16()`
120  to read and convert audio data to 32-bit floating point, signed 32-bit integer and signed 16-bit integer samples respectively. Tested and supported internal
121  formats include the following:
122  - Unsigned 8-bit PCM
123  - Signed 12-bit PCM
124  - Signed 16-bit PCM
125  - Signed 24-bit PCM
126  - Signed 32-bit PCM
127  - IEEE 32-bit floating point
128  - IEEE 64-bit floating point
129  - A-law and u-law
130  - Microsoft ADPCM
131  - IMA ADPCM (DVI, format code 0x11)
132- dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format.
133*/
134
135#ifndef dr_wav_h
136#define dr_wav_h
137
138#ifdef __cplusplus
139extern "C" {
140#endif
141
142#define DRWAV_STRINGIFY(x)      #x
143#define DRWAV_XSTRINGIFY(x)     DRWAV_STRINGIFY(x)
144
145#define DRWAV_VERSION_MAJOR     0
146#define DRWAV_VERSION_MINOR     12
147#define DRWAV_VERSION_REVISION  16
148#define DRWAV_VERSION_STRING    DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
149
150#include <stddef.h> /* For size_t. */
151
152/* Sized types. */
153typedef   signed char           drwav_int8;
154typedef unsigned char           drwav_uint8;
155typedef   signed short          drwav_int16;
156typedef unsigned short          drwav_uint16;
157typedef   signed int            drwav_int32;
158typedef unsigned int            drwav_uint32;
159#if defined(_MSC_VER)
160    typedef   signed __int64    drwav_int64;
161    typedef unsigned __int64    drwav_uint64;
162#else
163    #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
164        #pragma GCC diagnostic push
165        #pragma GCC diagnostic ignored "-Wlong-long"
166        #if defined(__clang__)
167            #pragma GCC diagnostic ignored "-Wc++11-long-long"
168        #endif
169    #endif
170    typedef   signed long long  drwav_int64;
171    typedef unsigned long long  drwav_uint64;
172    #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
173        #pragma GCC diagnostic pop
174    #endif
175#endif
176#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
177    typedef drwav_uint64        drwav_uintptr;
178#else
179    typedef drwav_uint32        drwav_uintptr;
180#endif
181typedef drwav_uint8             drwav_bool8;
182typedef drwav_uint32            drwav_bool32;
183#define DRWAV_TRUE              1
184#define DRWAV_FALSE             0
185
186#if !defined(DRWAV_API)
187    #if defined(DRWAV_DLL)
188        #if defined(_WIN32)
189            #define DRWAV_DLL_IMPORT  __declspec(dllimport)
190            #define DRWAV_DLL_EXPORT  __declspec(dllexport)
191            #define DRWAV_DLL_PRIVATE static
192        #else
193            #if defined(__GNUC__) && __GNUC__ >= 4
194                #define DRWAV_DLL_IMPORT  __attribute__((visibility("default")))
195                #define DRWAV_DLL_EXPORT  __attribute__((visibility("default")))
196                #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden")))
197            #else
198                #define DRWAV_DLL_IMPORT
199                #define DRWAV_DLL_EXPORT
200                #define DRWAV_DLL_PRIVATE static
201            #endif
202        #endif
203
204        #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
205            #define DRWAV_API  DRWAV_DLL_EXPORT
206        #else
207            #define DRWAV_API  DRWAV_DLL_IMPORT
208        #endif
209        #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE
210    #else
211        #define DRWAV_API extern
212        #define DRWAV_PRIVATE static
213    #endif
214#endif
215
216typedef drwav_int32 drwav_result;
217#define DRWAV_SUCCESS                        0
218#define DRWAV_ERROR                         -1   /* A generic error. */
219#define DRWAV_INVALID_ARGS                  -2
220#define DRWAV_INVALID_OPERATION             -3
221#define DRWAV_OUT_OF_MEMORY                 -4
222#define DRWAV_OUT_OF_RANGE                  -5
223#define DRWAV_ACCESS_DENIED                 -6
224#define DRWAV_DOES_NOT_EXIST                -7
225#define DRWAV_ALREADY_EXISTS                -8
226#define DRWAV_TOO_MANY_OPEN_FILES           -9
227#define DRWAV_INVALID_FILE                  -10
228#define DRWAV_TOO_BIG                       -11
229#define DRWAV_PATH_TOO_LONG                 -12
230#define DRWAV_NAME_TOO_LONG                 -13
231#define DRWAV_NOT_DIRECTORY                 -14
232#define DRWAV_IS_DIRECTORY                  -15
233#define DRWAV_DIRECTORY_NOT_EMPTY           -16
234#define DRWAV_END_OF_FILE                   -17
235#define DRWAV_NO_SPACE                      -18
236#define DRWAV_BUSY                          -19
237#define DRWAV_IO_ERROR                      -20
238#define DRWAV_INTERRUPT                     -21
239#define DRWAV_UNAVAILABLE                   -22
240#define DRWAV_ALREADY_IN_USE                -23
241#define DRWAV_BAD_ADDRESS                   -24
242#define DRWAV_BAD_SEEK                      -25
243#define DRWAV_BAD_PIPE                      -26
244#define DRWAV_DEADLOCK                      -27
245#define DRWAV_TOO_MANY_LINKS                -28
246#define DRWAV_NOT_IMPLEMENTED               -29
247#define DRWAV_NO_MESSAGE                    -30
248#define DRWAV_BAD_MESSAGE                   -31
249#define DRWAV_NO_DATA_AVAILABLE             -32
250#define DRWAV_INVALID_DATA                  -33
251#define DRWAV_TIMEOUT                       -34
252#define DRWAV_NO_NETWORK                    -35
253#define DRWAV_NOT_UNIQUE                    -36
254#define DRWAV_NOT_SOCKET                    -37
255#define DRWAV_NO_ADDRESS                    -38
256#define DRWAV_BAD_PROTOCOL                  -39
257#define DRWAV_PROTOCOL_UNAVAILABLE          -40
258#define DRWAV_PROTOCOL_NOT_SUPPORTED        -41
259#define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42
260#define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED  -43
261#define DRWAV_SOCKET_NOT_SUPPORTED          -44
262#define DRWAV_CONNECTION_RESET              -45
263#define DRWAV_ALREADY_CONNECTED             -46
264#define DRWAV_NOT_CONNECTED                 -47
265#define DRWAV_CONNECTION_REFUSED            -48
266#define DRWAV_NO_HOST                       -49
267#define DRWAV_IN_PROGRESS                   -50
268#define DRWAV_CANCELLED                     -51
269#define DRWAV_MEMORY_ALREADY_MAPPED         -52
270#define DRWAV_AT_END                        -53
271
272/* Common data formats. */
273#define DR_WAVE_FORMAT_PCM          0x1
274#define DR_WAVE_FORMAT_ADPCM        0x2
275#define DR_WAVE_FORMAT_IEEE_FLOAT   0x3
276#define DR_WAVE_FORMAT_ALAW         0x6
277#define DR_WAVE_FORMAT_MULAW        0x7
278#define DR_WAVE_FORMAT_DVI_ADPCM    0x11
279#define DR_WAVE_FORMAT_EXTENSIBLE   0xFFFE
280
281/* Constants. */
282#ifndef DRWAV_MAX_SMPL_LOOPS
283#define DRWAV_MAX_SMPL_LOOPS        1
284#endif
285
286/* Flags to pass into drwav_init_ex(), etc. */
287#define DRWAV_SEQUENTIAL            0x00000001
288
289DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
290DRWAV_API const char* drwav_version_string(void);
291
292typedef enum
293{
294    drwav_seek_origin_start,
295    drwav_seek_origin_current
296} drwav_seek_origin;
297
298typedef enum
299{
300    drwav_container_riff,
301    drwav_container_w64,
302    drwav_container_rf64
303} drwav_container;
304
305typedef struct
306{
307    union
308    {
309        drwav_uint8 fourcc[4];
310        drwav_uint8 guid[16];
311    } id;
312
313    /* The size in bytes of the chunk. */
314    drwav_uint64 sizeInBytes;
315
316    /*
317    RIFF = 2 byte alignment.
318    W64  = 8 byte alignment.
319    */
320    unsigned int paddingSize;
321} drwav_chunk_header;
322
323typedef struct
324{
325    /*
326    The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
327    that require support for data formats not natively supported by dr_wav.
328    */
329    drwav_uint16 formatTag;
330
331    /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */
332    drwav_uint16 channels;
333
334    /* The sample rate. Usually set to something like 44100. */
335    drwav_uint32 sampleRate;
336
337    /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */
338    drwav_uint32 avgBytesPerSec;
339
340    /* Block align. This is equal to the number of channels * bytes per sample. */
341    drwav_uint16 blockAlign;
342
343    /* Bits per sample. */
344    drwav_uint16 bitsPerSample;
345
346    /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */
347    drwav_uint16 extendedSize;
348
349    /*
350    The number of valid bits per sample. When <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample>
351    is always rounded up to the nearest multiple of 8. This variable contains information about exactly how
352    many bits are valid per sample. Mainly used for informational purposes.
353    */
354    drwav_uint16 validBitsPerSample;
355
356    /* The channel mask. Not used at the moment. */
357    drwav_uint32 channelMask;
358
359    /* The sub-format, exactly as specified by the wave file. */
360    drwav_uint8 subFormat[16];
361} drwav_fmt;
362
363DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
364
365
366/*
367Callback for when data is read. Return value is the number of bytes actually read.
368
369pUserData   [in]  The user data that was passed to drwav_init() and family.
370pBufferOut  [out] The output buffer.
371bytesToRead [in]  The number of bytes to read.
372
373Returns the number of bytes actually read.
374
375A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until
376either the entire bytesToRead is filled or you have reached the end of the stream.
377*/
378typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
379
380/*
381Callback for when data is written. Returns value is the number of bytes actually written.
382
383pUserData    [in]  The user data that was passed to drwav_init_write() and family.
384pData        [out] A pointer to the data to write.
385bytesToWrite [in]  The number of bytes to write.
386
387Returns the number of bytes actually written.
388
389If the return value differs from bytesToWrite, it indicates an error.
390*/
391typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
392
393/*
394Callback for when data needs to be seeked.
395
396pUserData [in] The user data that was passed to drwav_init() and family.
397offset    [in] The number of bytes to move, relative to the origin. Will never be negative.
398origin    [in] The origin of the seek - the current position or the start of the stream.
399
400Returns whether or not the seek was successful.
401
402Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either drwav_seek_origin_start or
403drwav_seek_origin_current.
404*/
405typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
406
407/*
408Callback for when drwav_init_ex() finds a chunk.
409
410pChunkUserData    [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family.
411onRead            [in] A pointer to the function to call when reading.
412onSeek            [in] A pointer to the function to call when seeking.
413pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family.
414pChunkHeader      [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk.
415container         [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF.
416pFMT              [in] A pointer to the object containing the contents of the "fmt" chunk.
417
418Returns the number of bytes read + seeked.
419
420To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same for seeking with onSeek(). The return value must
421be the total number of bytes you have read _plus_ seeked.
422
423Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should
424use `id.fourcc`, otherwise you should use `id.guid`.
425
426The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the
427`DR_WAVE_FORMAT_*` identifiers. 
428
429The read pointer will be sitting on the first byte after the chunk's header. You must not attempt to read beyond the boundary of the chunk.
430*/
431typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT);
432
433typedef struct
434{
435    void* pUserData;
436    void* (* onMalloc)(size_t sz, void* pUserData);
437    void* (* onRealloc)(void* p, size_t sz, void* pUserData);
438    void  (* onFree)(void* p, void* pUserData);
439} drwav_allocation_callbacks;
440
441/* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */
442typedef struct
443{
444    const drwav_uint8* data;
445    size_t dataSize;
446    size_t currentReadPos;
447} drwav__memory_stream;
448
449/* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */
450typedef struct
451{
452    void** ppData;
453    size_t* pDataSize;
454    size_t dataSize;
455    size_t dataCapacity;
456    size_t currentWritePos;
457} drwav__memory_stream_write;
458
459typedef struct
460{
461    drwav_container container;  /* RIFF, W64. */
462    drwav_uint32 format;        /* DR_WAVE_FORMAT_* */
463    drwav_uint32 channels;
464    drwav_uint32 sampleRate;
465    drwav_uint32 bitsPerSample;
466} drwav_data_format;
467
468
469/* See the following for details on the 'smpl' chunk: https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl */
470typedef struct
471{
472    drwav_uint32 cuePointId;
473    drwav_uint32 type;
474    drwav_uint32 start;
475    drwav_uint32 end;
476    drwav_uint32 fraction;
477    drwav_uint32 playCount;
478} drwav_smpl_loop;
479
480 typedef struct
481{
482    drwav_uint32 manufacturer;
483    drwav_uint32 product;
484    drwav_uint32 samplePeriod;
485    drwav_uint32 midiUnityNotes;
486    drwav_uint32 midiPitchFraction;
487    drwav_uint32 smpteFormat;
488    drwav_uint32 smpteOffset;
489    drwav_uint32 numSampleLoops;
490    drwav_uint32 samplerData;
491    drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS];
492} drwav_smpl;
493
494typedef struct
495{
496    /* A pointer to the function to call when more data is needed. */
497    drwav_read_proc onRead;
498
499    /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */
500    drwav_write_proc onWrite;
501
502    /* A pointer to the function to call when the wav file needs to be seeked. */
503    drwav_seek_proc onSeek;
504
505    /* The user data to pass to callbacks. */
506    void* pUserData;
507
508    /* Allocation callbacks. */
509    drwav_allocation_callbacks allocationCallbacks;
510
511
512    /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */
513    drwav_container container;
514
515
516    /* Structure containing format information exactly as specified by the wav file. */
517    drwav_fmt fmt;
518
519    /* The sample rate. Will be set to something like 44100. */
520    drwav_uint32 sampleRate;
521
522    /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */
523    drwav_uint16 channels;
524
525    /* The bits per sample. Will be set to something like 16, 24, etc. */
526    drwav_uint16 bitsPerSample;
527
528    /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */
529    drwav_uint16 translatedFormatTag;
530
531    /* The total number of PCM frames making up the audio data. */
532    drwav_uint64 totalPCMFrameCount;
533
534
535    /* The size in bytes of the data chunk. */
536    drwav_uint64 dataChunkDataSize;
537    
538    /* The position in the stream of the first byte of the data chunk. This is used for seeking. */
539    drwav_uint64 dataChunkDataPos;
540
541    /* The number of bytes remaining in the data chunk. */
542    drwav_uint64 bytesRemaining;
543
544
545    /*
546    Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always
547    set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation.
548    */
549    drwav_uint64 dataChunkDataSizeTargetWrite;
550
551    /* Keeps track of whether or not the wav writer was initialized in sequential mode. */
552    drwav_bool32 isSequentialWrite;
553
554
555    /* smpl chunk. */
556    drwav_smpl smpl;
557
558
559    /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */
560    drwav__memory_stream memoryStream;
561    drwav__memory_stream_write memoryStreamWrite;
562
563    /* Generic data for compressed formats. This data is shared across all block-compressed formats. */
564    struct
565    {
566        drwav_uint64 iCurrentPCMFrame;  /* The index of the next PCM frame that will be read by drwav_read_*(). This is used with "totalPCMFrameCount" to ensure we don't read excess samples at the end of the last block. */
567    } compressed;
568    
569    /* Microsoft ADPCM specific data. */
570    struct
571    {
572        drwav_uint32 bytesRemainingInBlock;
573        drwav_uint16 predictor[2];
574        drwav_int32  delta[2];
575        drwav_int32  cachedFrames[4];  /* Samples are stored in this cache during decoding. */
576        drwav_uint32 cachedFrameCount;
577        drwav_int32  prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */
578    } msadpcm;
579
580    /* IMA ADPCM specific data. */
581    struct
582    {
583        drwav_uint32 bytesRemainingInBlock;
584        drwav_int32  predictor[2];
585        drwav_int32  stepIndex[2];
586        drwav_int32  cachedFrames[16]; /* Samples are stored in this cache during decoding. */
587        drwav_uint32 cachedFrameCount;
588    } ima;
589} drwav;
590
591
592/*
593Initializes a pre-allocated drwav object for reading.
594
595pWav                         [out]          A pointer to the drwav object being initialized.
596onRead                       [in]           The function to call when data needs to be read from the client.
597onSeek                       [in]           The function to call when the read position of the client data needs to move.
598onChunk                      [in, optional] The function to call when a chunk is enumerated at initialized time.
599pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
600pChunkUserData               [in, optional] A pointer to application defined data that will be passed to onChunk.
601flags                        [in, optional] A set of flags for controlling how things are loaded.
602
603Returns true if successful; false otherwise.
604
605Close the loader with drwav_uninit().
606
607This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory()
608to open the stream from a file or from a block of memory respectively.
609
610Possible values for flags:
611  DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function
612                    to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored.
613
614drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);".
615
616The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt
617after the function returns.
618
619See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
620*/
621DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
622DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
623
624/*
625Initializes a pre-allocated drwav object for writing.
626
627onWrite   [in]           The function to call when data needs to be written.
628onSeek    [in]           The function to call when the write position needs to move.
629pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek.
630
631Returns true if successful; false otherwise.
632
633Close the writer with drwav_uninit().
634
635This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write()
636to open the stream from a file or from a block of memory respectively.
637
638If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform
639a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek.
640
641See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit()
642*/
643DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
644DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
645DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
646
647/*
648Utility function to determine the target size of the entire data to be written (including all headers and chunks).
649
650Returns the target size in bytes.
651
652Useful if the application needs to know the size to allocate.
653
654Only writing to the RIFF chunk and one data chunk is currently supported.
655
656See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write()
657*/
658DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
659
660/*
661Uninitializes the given drwav object.
662
663Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()).
664*/
665DRWAV_API drwav_result drwav_uninit(drwav* pWav);
666
667
668/*
669Reads raw audio data.
670
671This is the lowest level function for reading audio data. It simply reads the given number of
672bytes of the raw internal sample data.
673
674Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for
675reading sample data in a consistent format.
676
677pBufferOut can be NULL in which case a seek will be performed.
678
679Returns the number of bytes actually read.
680*/
681DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
682
683/*
684Reads up to the specified number of PCM frames from the WAV file.
685
686The output data will be in the file's internal format, converted to native-endian byte order. Use
687drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format.
688
689If the return value is less than <framesToRead> it means the end of the file has been reached or
690you have requested more PCM frames than can possibly fit in the output buffer.
691
692This function will only work when sample data is of a fixed size and uncompressed. If you are
693using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32().
694
695pBufferOut can be NULL in which case a seek will be performed.
696*/
697DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
698DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
699DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
700
701/*
702Seeks to the given PCM frame.
703
704Returns true if successful; false otherwise.
705*/
706DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
707
708
709/*
710Writes raw audio data.
711
712Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error.
713*/
714DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
715
716/*
717Writes PCM frames.
718
719Returns the number of PCM frames written.
720
721Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to
722little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion.
723*/
724DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
725DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
726DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
727
728
729/* Conversion Utilities */
730#ifndef DR_WAV_NO_CONVERSION_API
731
732/*
733Reads a chunk of audio data and converts it to signed 16-bit PCM samples.
734
735pBufferOut can be NULL in which case a seek will be performed.
736
737Returns the number of PCM frames actually read.
738
739If the return value is less than <framesToRead> it means the end of the file has been reached.
740*/
741DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
742DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
743DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
744
745/* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */
746DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
747
748/* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */
749DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
750
751/* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */
752DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
753
754/* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */
755DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
756
757/* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */
758DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
759
760/* Low-level function for converting A-law samples to signed 16-bit PCM samples. */
761DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
762
763/* Low-level function for converting u-law samples to signed 16-bit PCM samples. */
764DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
765
766
767/*
768Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples.
769
770pBufferOut can be NULL in which case a seek will be performed.
771
772Returns the number of PCM frames actually read.
773
774If the return value is less than <framesToRead> it means the end of the file has been reached.
775*/
776DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
777DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
778DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
779
780/* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */
781DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
782
783/* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */
784DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
785
786/* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */
787DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
788
789/* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */
790DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
791
792/* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */
793DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
794
795/* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */
796DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
797
798/* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */
799DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
800
801
802/*
803Reads a chunk of audio data and converts it to signed 32-bit PCM samples.
804
805pBufferOut can be NULL in which case a seek will be performed.
806
807Returns the number of PCM frames actually read.
808
809If the return value is less than <framesToRead> it means the end of the file has been reached.
810*/
811DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
812DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
813DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
814
815/* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */
816DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
817
818/* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */
819DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
820
821/* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */
822DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
823
824/* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */
825DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
826
827/* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */
828DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
829
830/* Low-level function for converting A-law samples to signed 32-bit PCM samples. */
831DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
832
833/* Low-level function for converting u-law samples to signed 32-bit PCM samples. */
834DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
835
836#endif  /* DR_WAV_NO_CONVERSION_API */
837
838
839/* High-Level Convenience Helpers */
840
841#ifndef DR_WAV_NO_STDIO
842/*
843Helper for initializing a wave file for reading using stdio.
844
845This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
846objects because the operating system may restrict the number of file handles an application can have open at
847any given time.
848*/
849DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
850DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
851DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
852DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
853
854/*
855Helper for initializing a wave file for writing using stdio.
856
857This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
858objects because the operating system may restrict the number of file handles an application can have open at
859any given time.
860*/
861DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
862DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
863DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
864DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
865DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
866DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
867#endif  /* DR_WAV_NO_STDIO */
868
869/*
870Helper for initializing a loader from a pre-allocated memory buffer.
871
872This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
873the lifetime of the drwav object.
874
875The buffer should contain the contents of the entire wave file, not just the sample data.
876*/
877DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
878DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
879
880/*
881Helper for initializing a writer which outputs data to a memory buffer.
882
883dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
884
885The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid
886until after drwav_uninit() has been called.
887*/
888DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
889DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
890DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
891
892
893#ifndef DR_WAV_NO_CONVERSION_API
894/*
895Opens and reads an entire wav file in a single operation.
896
897The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
898*/
899DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
900DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
901DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
902#ifndef DR_WAV_NO_STDIO
903/*
904Opens and decodes an entire wav file in a single operation.
905
906The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
907*/
908DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
909DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
910DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
911DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
912DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
913DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
914#endif
915/*
916Opens and decodes an entire wav file from a block of memory in a single operation.
917
918The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
919*/
920DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
921DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
922DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
923#endif
924
925/* Frees data that was allocated internally by dr_wav. */
926DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
927
928/* Converts bytes from a wav stream to a sized type of native endian. */
929DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data);
930DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data);
931DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data);
932DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data);
933DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data);
934DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data);
935
936/* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */
937DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
938
939/* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */
940DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
941
942#ifdef __cplusplus
943}
944#endif
945#endif  /* dr_wav_h */
946
947
948/************************************************************************************************************************************************************
949 ************************************************************************************************************************************************************
950
951 IMPLEMENTATION
952
953 ************************************************************************************************************************************************************
954 ************************************************************************************************************************************************************/
955#if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
956#ifndef dr_wav_c
957#define dr_wav_c
958
959#include <stdlib.h>
960#include <string.h> /* For memcpy(), memset() */
961#include <limits.h> /* For INT_MAX */
962
963#ifndef DR_WAV_NO_STDIO
964#include <stdio.h>
965#include <wchar.h>
966#endif
967
968/* Standard library stuff. */
969#ifndef DRWAV_ASSERT
970#include <assert.h>
971#define DRWAV_ASSERT(expression)           assert(expression)
972#endif
973#ifndef DRWAV_MALLOC
974#define DRWAV_MALLOC(sz)                   malloc((sz))
975#endif
976#ifndef DRWAV_REALLOC
977#define DRWAV_REALLOC(p, sz)               realloc((p), (sz))
978#endif
979#ifndef DRWAV_FREE
980#define DRWAV_FREE(p)                      free((p))
981#endif
982#ifndef DRWAV_COPY_MEMORY
983#define DRWAV_COPY_MEMORY(dst, src, sz)    memcpy((dst), (src), (sz))
984#endif
985#ifndef DRWAV_ZERO_MEMORY
986#define DRWAV_ZERO_MEMORY(p, sz)           memset((p), 0, (sz))
987#endif
988#ifndef DRWAV_ZERO_OBJECT
989#define DRWAV_ZERO_OBJECT(p)               DRWAV_ZERO_MEMORY((p), sizeof(*p))
990#endif
991
992#define drwav_countof(x)                   (sizeof(x) / sizeof(x[0]))
993#define drwav_align(x, a)                  ((((x) + (a) - 1) / (a)) * (a))
994#define drwav_min(a, b)                    (((a) < (b)) ? (a) : (b))
995#define drwav_max(a, b)                    (((a) > (b)) ? (a) : (b))
996#define drwav_clamp(x, lo, hi)             (drwav_max((lo), drwav_min((hi), (x))))
997
998#define DRWAV_MAX_SIMD_VECTOR_SIZE         64  /* 64 for AVX-512 in the future. */
999
1000/* CPU architecture. */
1001#if defined(__x86_64__) || defined(_M_X64)
1002    #define DRWAV_X64
1003#elif defined(__i386) || defined(_M_IX86)
1004    #define DRWAV_X86
1005#elif defined(__arm__) || defined(_M_ARM)
1006    #define DRWAV_ARM
1007#endif
1008
1009#ifdef _MSC_VER
1010    #define DRWAV_INLINE __forceinline
1011#elif defined(__GNUC__)
1012    /*
1013    I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
1014    the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
1015    case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
1016    command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
1017    I am using "__inline__" only when we're compiling in strict ANSI mode.
1018    */
1019    #if defined(__STRICT_ANSI__)
1020        #define DRWAV_INLINE __inline__ __attribute__((always_inline))
1021    #else
1022        #define DRWAV_INLINE inline __attribute__((always_inline))
1023    #endif
1024#elif defined(__WATCOMC__)
1025    #define DRWAV_INLINE __inline
1026#else
1027    #define DRWAV_INLINE
1028#endif
1029
1030#if defined(SIZE_MAX)
1031    #define DRWAV_SIZE_MAX  SIZE_MAX
1032#else
1033    #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
1034        #define DRWAV_SIZE_MAX  ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
1035    #else
1036        #define DRWAV_SIZE_MAX  0xFFFFFFFF
1037    #endif
1038#endif
1039
1040#if defined(_MSC_VER) && _MSC_VER >= 1400
1041    #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1042    #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1043    #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1044#elif defined(__clang__)
1045    #if defined(__has_builtin)
1046        #if __has_builtin(__builtin_bswap16)
1047            #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1048        #endif
1049        #if __has_builtin(__builtin_bswap32)
1050            #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1051        #endif
1052        #if __has_builtin(__builtin_bswap64)
1053            #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1054        #endif
1055    #endif
1056#elif defined(__GNUC__)
1057    #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
1058        #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1059        #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1060    #endif
1061    #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
1062        #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1063    #endif
1064#endif
1065
1066DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision)
1067{
1068    if (pMajor) {
1069        *pMajor = DRWAV_VERSION_MAJOR;
1070    }
1071
1072    if (pMinor) {
1073        *pMinor = DRWAV_VERSION_MINOR;
1074    }
1075
1076    if (pRevision) {
1077        *pRevision = DRWAV_VERSION_REVISION;
1078    }
1079}
1080
1081DRWAV_API const char* drwav_version_string(void)
1082{
1083    return DRWAV_VERSION_STRING;
1084}
1085
1086/*
1087These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are
1088you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation.
1089*/
1090#ifndef DRWAV_MAX_SAMPLE_RATE
1091#define DRWAV_MAX_SAMPLE_RATE       384000
1092#endif
1093#ifndef DRWAV_MAX_CHANNELS
1094#define DRWAV_MAX_CHANNELS          256
1095#endif
1096#ifndef DRWAV_MAX_BITS_PER_SAMPLE
1097#define DRWAV_MAX_BITS_PER_SAMPLE   64
1098#endif
1099
1100static const drwav_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 */
1101static const drwav_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 */
1102/*static const drwav_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 */
1103static const drwav_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 */
1104static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};    /* 74636166-ACF3-11D3-8CD1-00C04F8EDB8A */
1105static const drwav_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 */
1106static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};    /* 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A */
1107
1108static DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
1109{
1110    int i;
1111    for (i = 0; i < 16; i += 1) {
1112        if (a[i] != b[i]) {
1113            return DRWAV_FALSE;
1114        }
1115    }
1116
1117    return DRWAV_TRUE;
1118}
1119
1120static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const drwav_uint8* a, const char* b)
1121{
1122    return
1123        a[0] == b[0] &&
1124        a[1] == b[1] &&
1125        a[2] == b[2] &&
1126        a[3] == b[3];
1127}
1128
1129
1130
1131static DRWAV_INLINE int drwav__is_little_endian(void)
1132{
1133#if defined(DRWAV_X86) || defined(DRWAV_X64)
1134    return DRWAV_TRUE;
1135#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
1136    return DRWAV_TRUE;
1137#else
1138    int n = 1;
1139    return (*(char*)&n) == 1;
1140#endif
1141}
1142
1143static DRWAV_INLINE drwav_uint16 drwav__bytes_to_u16(const drwav_uint8* data)
1144{
1145    return (data[0] << 0) | (data[1] << 8);
1146}
1147
1148static DRWAV_INLINE drwav_int16 drwav__bytes_to_s16(const drwav_uint8* data)
1149{
1150    return (short)drwav__bytes_to_u16(data);
1151}
1152
1153static DRWAV_INLINE drwav_uint32 drwav__bytes_to_u32(const drwav_uint8* data)
1154{
1155    return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
1156}
1157
1158static DRWAV_INLINE drwav_int32 drwav__bytes_to_s32(const drwav_uint8* data)
1159{
1160    return (drwav_int32)drwav__bytes_to_u32(data);
1161}
1162
1163static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const drwav_uint8* data)
1164{
1165    return
1166        ((drwav_uint64)data[0] <<  0) | ((drwav_uint64)data[1] <<  8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
1167        ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
1168}
1169
1170static DRWAV_INLINE drwav_int64 drwav__bytes_to_s64(const drwav_uint8* data)
1171{
1172    return (drwav_int64)drwav__bytes_to_u64(data);
1173}
1174
1175static DRWAV_INLINE void drwav__bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid)
1176{
1177    int i;
1178    for (i = 0; i < 16; ++i) {
1179        guid[i] = data[i];
1180    }
1181}
1182
1183
1184static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n)
1185{
1186#ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC
1187    #if defined(_MSC_VER)
1188        return _byteswap_ushort(n);
1189    #elif defined(__GNUC__) || defined(__clang__)
1190        return __builtin_bswap16(n);
1191    #else
1192        #error "This compiler does not support the byte swap intrinsic."
1193    #endif
1194#else
1195    return ((n & 0xFF00) >> 8) |
1196           ((n & 0x00FF) << 8);
1197#endif
1198}
1199
1200static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n)
1201{
1202#ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC
1203    #if defined(_MSC_VER)
1204        return _byteswap_ulong(n);
1205    #elif defined(__GNUC__) || defined(__clang__)
1206        #if defined(DRWAV_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRWAV_64BIT)   /* <-- 64-bit inline assembly has not been tested, so disabling for now. */
1207            /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
1208            drwav_uint32 r;
1209            __asm__ __volatile__ (
1210            #if defined(DRWAV_64BIT)
1211                "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n)   /* <-- This is untested. If someone in the community could test this, that would be appreciated! */
1212            #else
1213                "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
1214            #endif
1215            );
1216            return r;
1217        #else
1218            return __builtin_bswap32(n);
1219        #endif
1220    #else
1221        #error "This compiler does not support the byte swap intrinsic."
1222    #endif
1223#else
1224    return ((n & 0xFF000000) >> 24) |
1225           ((n & 0x00FF0000) >>  8) |
1226           ((n & 0x0000FF00) <<  8) |
1227           ((n & 0x000000FF) << 24);
1228#endif
1229}
1230
1231static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
1232{
1233#ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC
1234    #if defined(_MSC_VER)
1235        return _byteswap_uint64(n);
1236    #elif defined(__GNUC__) || defined(__clang__)
1237        return __builtin_bswap64(n);
1238    #else
1239        #error "This compiler does not support the byte swap intrinsic."
1240    #endif
1241#else
1242    /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
1243    return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) |
1244           ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) |
1245           ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) |
1246           ((n & ((drwav_uint64)0x000000FF << 32)) >>  8) |
1247           ((n & ((drwav_uint64)0xFF000000      )) <<  8) |
1248           ((n & ((drwav_uint64)0x00FF0000      )) << 24) |
1249           ((n & ((drwav_uint64)0x0000FF00      )) << 40) |
1250           ((n & ((drwav_uint64)0x000000FF      )) << 56);
1251#endif
1252}
1253
1254
1255static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
1256{
1257    return (drwav_int16)drwav__bswap16((drwav_uint16)n);
1258}
1259
1260static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount)
1261{
1262    drwav_uint64 iSample;
1263    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1264        pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]);
1265    }
1266}
1267
1268
1269static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p)
1270{
1271    drwav_uint8 t;
1272    t = p[0];
1273    p[0] = p[2];
1274    p[2] = t;
1275}
1276
1277static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount)
1278{
1279    drwav_uint64 iSample;
1280    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1281        drwav_uint8* pSample = pSamples + (iSample*3);
1282        drwav__bswap_s24(pSample);
1283    }
1284}
1285
1286
1287static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n)
1288{
1289    return (drwav_int32)drwav__bswap32((drwav_uint32)n);
1290}
1291
1292static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount)
1293{
1294    drwav_uint64 iSample;
1295    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1296        pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]);
1297    }
1298}
1299
1300
1301static DRWAV_INLINE float drwav__bswap_f32(float n)
1302{
1303    union {
1304        drwav_uint32 i;
1305        float f;
1306    } x;
1307    x.f = n;
1308    x.i = drwav__bswap32(x.i);
1309
1310    return x.f;
1311}
1312
1313static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount)
1314{
1315    drwav_uint64 iSample;
1316    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1317        pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]);
1318    }
1319}
1320
1321
1322static DRWAV_INLINE double drwav__bswap_f64(double n)
1323{
1324    union {
1325        drwav_uint64 i;
1326        double f;
1327    } x;
1328    x.f = n;
1329    x.i = drwav__bswap64(x.i);
1330
1331    return x.f;
1332}
1333
1334static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount)
1335{
1336    drwav_uint64 iSample;
1337    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1338        pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]);
1339    }
1340}
1341
1342
1343static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1344{
1345    /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */
1346    switch (bytesPerSample)
1347    {
1348        case 2: /* s16, s12 (loosely packed) */
1349        {
1350            drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1351        } break;
1352        case 3: /* s24 */
1353        {
1354            drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount);
1355        } break;
1356        case 4: /* s32 */
1357        {
1358            drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount);
1359        } break;
1360        default:
1361        {
1362            /* Unsupported format. */
1363            DRWAV_ASSERT(DRWAV_FALSE);
1364        } break;
1365    }
1366}
1367
1368static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1369{
1370    switch (bytesPerSample)
1371    {
1372    #if 0   /* Contributions welcome for f16 support. */
1373        case 2: /* f16 */
1374        {
1375            drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount);
1376        } break;
1377    #endif
1378        case 4: /* f32 */
1379        {
1380            drwav__bswap_samples_f32((float*)pSamples, sampleCount);
1381        } break;
1382        case 8: /* f64 */
1383        {
1384            drwav__bswap_samples_f64((double*)pSamples, sampleCount);
1385        } break;
1386        default:
1387        {
1388            /* Unsupported format. */
1389            DRWAV_ASSERT(DRWAV_FALSE);
1390        } break;
1391    }
1392}
1393
1394static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format)
1395{
1396    switch (format)
1397    {
1398        case DR_WAVE_FORMAT_PCM:
1399        {
1400            drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample);
1401        } break;
1402
1403        case DR_WAVE_FORMAT_IEEE_FLOAT:
1404        {
1405            drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample);
1406        } break;
1407
1408        case DR_WAVE_FORMAT_ALAW:
1409        case DR_WAVE_FORMAT_MULAW:
1410        {
1411            drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1412        } break;
1413
1414        case DR_WAVE_FORMAT_ADPCM:
1415        case DR_WAVE_FORMAT_DVI_ADPCM:
1416        default:
1417        {
1418            /* Unsupported format. */
1419            DRWAV_ASSERT(DRWAV_FALSE);
1420        } break;
1421    }
1422}
1423
1424
1425static void* drwav__malloc_default(size_t sz, void* pUserData)
1426{
1427    (void)pUserData;
1428    return DRWAV_MALLOC(sz);
1429}
1430
1431static void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
1432{
1433    (void)pUserData;
1434    return DRWAV_REALLOC(p, sz);
1435}
1436
1437static void drwav__free_default(void* p, void* pUserData)
1438{
1439    (void)pUserData;
1440    DRWAV_FREE(p);
1441}
1442
1443
1444static void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
1445{
1446    if (pAllocationCallbacks == NULL) {
1447        return NULL;
1448    }
1449
1450    if (pAllocationCallbacks->onMalloc != NULL) {
1451        return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
1452    }
1453
1454    /* Try using realloc(). */
1455    if (pAllocationCallbacks->onRealloc != NULL) {
1456        return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
1457    }
1458
1459    return NULL;
1460}
1461
1462static void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
1463{
1464    if (pAllocationCallbacks == NULL) {
1465        return NULL;
1466    }
1467
1468    if (pAllocationCallbacks->onRealloc != NULL) {
1469        return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
1470    }
1471
1472    /* Try emulating realloc() in terms of malloc()/free(). */
1473    if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
1474        void* p2;
1475
1476        p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
1477        if (p2 == NULL) {
1478            return NULL;
1479        }
1480
1481        if (p != NULL) {
1482            DRWAV_COPY_MEMORY(p2, p, szOld);
1483            pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1484        }
1485
1486        return p2;
1487    }
1488
1489    return NULL;
1490}
1491
1492static void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
1493{
1494    if (p == NULL || pAllocationCallbacks == NULL) {
1495        return;
1496    }
1497
1498    if (pAllocationCallbacks->onFree != NULL) {
1499        pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1500    }
1501}
1502
1503
1504static drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
1505{
1506    if (pAllocationCallbacks != NULL) {
1507        /* Copy. */
1508        return *pAllocationCallbacks;
1509    } else {
1510        /* Defaults. */
1511        drwav_allocation_callbacks allocationCallbacks;
1512        allocationCallbacks.pUserData = NULL;
1513        allocationCallbacks.onMalloc  = drwav__malloc_default;
1514        allocationCallbacks.onRealloc = drwav__realloc_default;
1515        allocationCallbacks.onFree    = drwav__free_default;
1516        return allocationCallbacks;
1517    }
1518}
1519
1520
1521static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
1522{
1523    return
1524        formatTag == DR_WAVE_FORMAT_ADPCM ||
1525        formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
1526}
1527
1528static unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
1529{
1530    return (unsigned int)(chunkSize % 2);
1531}
1532
1533static unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
1534{
1535    return (unsigned int)(chunkSize % 8);
1536}
1537
1538static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1539static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1540static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
1541
1542static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
1543{
1544    if (container == drwav_container_riff || container == drwav_container_rf64) {
1545        drwav_uint8 sizeInBytes[4];
1546
1547        if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
1548            return DRWAV_AT_END;
1549        }
1550
1551        if (onRead(pUserData, sizeInBytes, 4) != 4) {
1552            return DRWAV_INVALID_FILE;
1553        }
1554
1555        pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes);
1556        pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes);
1557        *pRunningBytesReadOut += 8;
1558    } else {
1559        drwav_uint8 sizeInBytes[8];
1560
1561        if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
1562            return DRWAV_AT_END;
1563        }
1564
1565        if (onRead(pUserData, sizeInBytes, 8) != 8) {
1566            return DRWAV_INVALID_FILE;
1567        }
1568
1569        pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24;    /* <-- Subtract 24 because w64 includes the size of the header. */
1570        pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
1571        *pRunningBytesReadOut += 24;
1572    }
1573
1574    return DRWAV_SUCCESS;
1575}
1576
1577static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1578{
1579    drwav_uint64 bytesRemainingToSeek = offset;
1580    while (bytesRemainingToSeek > 0) {
1581        if (bytesRemainingToSeek > 0x7FFFFFFF) {
1582            if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1583                return DRWAV_FALSE;
1584            }
1585            bytesRemainingToSeek -= 0x7FFFFFFF;
1586        } else {
1587            if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
1588                return DRWAV_FALSE;
1589            }
1590            bytesRemainingToSeek = 0;
1591        }
1592    }
1593
1594    return DRWAV_TRUE;
1595}
1596
1597static drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1598{
1599    if (offset <= 0x7FFFFFFF) {
1600        return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
1601    }
1602
1603    /* Larger than 32-bit seek. */
1604    if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
1605        return DRWAV_FALSE;
1606    }
1607    offset -= 0x7FFFFFFF;
1608
1609    for (;;) {
1610        if (offset <= 0x7FFFFFFF) {
1611            return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
1612        }
1613
1614        if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1615            return DRWAV_FALSE;
1616        }
1617        offset -= 0x7FFFFFFF;
1618    }
1619
1620    /* Should never get here. */
1621    /*return DRWAV_TRUE; */
1622}
1623
1624
1625static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut)
1626{
1627    drwav_chunk_header header;
1628    drwav_uint8 fmt[16];
1629
1630    if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
1631        return DRWAV_FALSE;
1632    }
1633
1634
1635    /* Skip non-fmt chunks. */
1636    while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
1637        if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
1638            return DRWAV_FALSE;
1639        }
1640        *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize;
1641
1642        /* Try the next header. */
1643        if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
1644            return DRWAV_FALSE;
1645        }
1646    }
1647
1648
1649    /* Validation. */
1650    if (container == drwav_container_riff || container == drwav_container_rf64) {
1651        if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) {
1652            return DRWAV_FALSE;
1653        }
1654    } else {
1655        if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
1656            return DRWAV_FALSE;
1657        }
1658    }
1659
1660
1661    if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
1662        return DRWAV_FALSE;
1663    }
1664    *pRunningBytesReadOut += sizeof(fmt);
1665
1666    fmtOut->formatTag      = drwav__bytes_to_u16(fmt + 0);
1667    fmtOut->channels       = drwav__bytes_to_u16(fmt + 2);
1668    fmtOut->sampleRate     = drwav__bytes_to_u32(fmt + 4);
1669    fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8);
1670    fmtOut->blockAlign     = drwav__bytes_to_u16(fmt + 12);
1671    fmtOut->bitsPerSample  = drwav__bytes_to_u16(fmt + 14);
1672
1673    fmtOut->extendedSize       = 0;
1674    fmtOut->validBitsPerSample = 0;
1675    fmtOut->channelMask        = 0;
1676    memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
1677
1678    if (header.sizeInBytes > 16) {
1679        drwav_uint8 fmt_cbSize[2];
1680        int bytesReadSoFar = 0;
1681
1682        if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
1683            return DRWAV_FALSE;    /* Expecting more data. */
1684        }
1685        *pRunningBytesReadOut += sizeof(fmt_cbSize);
1686
1687        bytesReadSoFar = 18;
1688
1689        fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize);
1690        if (fmtOut->extendedSize > 0) {
1691            /* Simple validation. */
1692            if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1693                if (fmtOut->extendedSize != 22) {
1694                    return DRWAV_FALSE;
1695                }
1696            }
1697
1698            if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1699                drwav_uint8 fmtext[22];
1700                if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) {
1701                    return DRWAV_FALSE;    /* Expecting more data. */
1702                }
1703
1704                fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0);
1705                fmtOut->channelMask        = drwav__bytes_to_u32(fmtext + 2);
1706                drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat);
1707            } else {
1708                if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) {
1709                    return DRWAV_FALSE;
1710                }
1711            }
1712            *pRunningBytesReadOut += fmtOut->extendedSize;
1713
1714            bytesReadSoFar += fmtOut->extendedSize;
1715        }
1716
1717        /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */
1718        if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) {
1719            return DRWAV_FALSE;
1720        }
1721        *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
1722    }
1723
1724    if (header.paddingSize > 0) {
1725        if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
1726            return DRWAV_FALSE;
1727        }
1728        *pRunningBytesReadOut += header.paddingSize;
1729    }
1730
1731    return DRWAV_TRUE;
1732}
1733
1734
1735static size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
1736{
1737    size_t bytesRead;
1738
1739    DRWAV_ASSERT(onRead != NULL);
1740    DRWAV_ASSERT(pCursor != NULL);
1741
1742    bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
1743    *pCursor += bytesRead;
1744    return bytesRead;
1745}
1746
1747#if 0
1748static drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
1749{
1750    DRWAV_ASSERT(onSeek != NULL);
1751    DRWAV_ASSERT(pCursor != NULL);
1752
1753    if (!onSeek(pUserData, offset, origin)) {
1754        return DRWAV_FALSE;
1755    }
1756
1757    if (origin == drwav_seek_origin_start) {
1758        *pCursor = offset;
1759    } else {
1760        *pCursor += offset;
1761    }
1762
1763    return DRWAV_TRUE;
1764}
1765#endif
1766
1767
1768
1769static drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
1770{
1771    /*
1772    The bytes per frame is a bit ambiguous. It can be either be based on the bits per sample, or the block align. The way I'm doing it here
1773    is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align.
1774    */
1775    if ((pWav->bitsPerSample & 0x7) == 0) {
1776        /* Bits per sample is a multiple of 8. */
1777        return (pWav->bitsPerSample * pWav->fmt.channels) >> 3;
1778    } else {
1779        return pWav->fmt.blockAlign;
1780    }
1781}
1782
1783DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
1784{
1785    if (pFMT == NULL) {
1786        return 0;
1787    }
1788
1789    if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) {
1790        return pFMT->formatTag;
1791    } else {
1792        return drwav__bytes_to_u16(pFMT->subFormat);    /* Only the first two bytes are required. */
1793    }
1794}
1795
1796static drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
1797{
1798    if (pWav == NULL || onRead == NULL || onSeek == NULL) {
1799        return DRWAV_FALSE;
1800    }
1801
1802    DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
1803    pWav->onRead    = onRead;
1804    pWav->onSeek    = onSeek;
1805    pWav->pUserData = pReadSeekUserData;
1806    pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
1807
1808    if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
1809        return DRWAV_FALSE;    /* Invalid allocation callbacks. */
1810    }
1811
1812    return DRWAV_TRUE;
1813}
1814
1815static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
1816{
1817    /* This function assumes drwav_preinit() has been called beforehand. */
1818
1819    drwav_uint64 cursor;    /* <-- Keeps track of the byte position so we can seek to specific locations. */
1820    drwav_bool32 sequential;
1821    drwav_uint8 riff[4];
1822    drwav_fmt fmt;
1823    unsigned short translatedFormatTag;
1824    drwav_bool32 foundDataChunk;
1825    drwav_uint64 dataChunkSize = 0; /* <-- Important! Don't explicitly set this to 0 anywhere else. Calculation of the size of the data chunk is performed in different paths depending on the container. */
1826    drwav_uint64 sampleCountFromFactChunk = 0;  /* Same as dataChunkSize - make sure this is the only place this is initialized to 0. */
1827    drwav_uint64 chunkSize;
1828
1829    cursor = 0;
1830    sequential = (flags & DRWAV_SEQUENTIAL) != 0;
1831
1832    /* The first 4 bytes should be the RIFF identifier. */
1833    if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) {
1834        return DRWAV_FALSE;
1835    }
1836
1837    /*
1838    The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for
1839    w64 it will start with "riff".
1840    */
1841    if (drwav__fourcc_equal(riff, "RIFF")) {
1842        pWav->container = drwav_container_riff;
1843    } else if (drwav__fourcc_equal(riff, "riff")) {
1844        int i;
1845        drwav_uint8 riff2[12];
1846
1847        pWav->container = drwav_container_w64;
1848
1849        /* Check the rest of the GUID for validity. */
1850        if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) {
1851            return DRWAV_FALSE;
1852        }
1853
1854        for (i = 0; i < 12; ++i) {
1855            if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
1856                return DRWAV_FALSE;
1857            }
1858        }
1859    } else if (drwav__fourcc_equal(riff, "RF64")) {
1860        pWav->container = drwav_container_rf64;
1861    } else {
1862        return DRWAV_FALSE;   /* Unknown or unsupported container. */
1863    }
1864
1865
1866    if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
1867        drwav_uint8 chunkSizeBytes[4];
1868        drwav_uint8 wave[4];
1869
1870        /* RIFF/WAVE */
1871        if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
1872            return DRWAV_FALSE;
1873        }
1874
1875        if (pWav->container == drwav_container_riff) {
1876            if (drwav__bytes_to_u32(chunkSizeBytes) < 36) {
1877                return DRWAV_FALSE;    /* Chunk size should always be at least 36 bytes. */
1878            }
1879        } else {
1880            if (drwav__bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) {
1881                return DRWAV_FALSE;    /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */
1882            }
1883        }
1884
1885        if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
1886            return DRWAV_FALSE;
1887        }
1888
1889        if (!drwav__fourcc_equal(wave, "WAVE")) {
1890            return DRWAV_FALSE;    /* Expecting "WAVE". */
1891        }
1892    } else {
1893        drwav_uint8 chunkSizeBytes[8];
1894        drwav_uint8 wave[16];
1895
1896        /* W64 */
1897        if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
1898            return DRWAV_FALSE;
1899        }
1900
1901        if (drwav__bytes_to_u64(chunkSizeBytes) < 80) {
1902            return DRWAV_FALSE;
1903        }
1904
1905        if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
1906            return DRWAV_FALSE;
1907        }
1908
1909        if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) {
1910            return DRWAV_FALSE;
1911        }
1912    }
1913
1914
1915    /* For RF64, the "ds64" chunk must come next, before the "fmt " chunk. */
1916    if (pWav->container == drwav_container_rf64) {
1917        drwav_uint8 sizeBytes[8];
1918        drwav_uint64 bytesRemainingInChunk;
1919        drwav_chunk_header header;
1920        drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
1921        if (result != DRWAV_SUCCESS) {
1922            return DRWAV_FALSE;
1923        }
1924
1925        if (!drwav__fourcc_equal(header.id.fourcc, "ds64")) {
1926            return DRWAV_FALSE; /* Expecting "ds64". */
1927        }
1928
1929        bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
1930
1931        /* We don't care about the size of the RIFF chunk - skip it. */
1932        if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
1933            return DRWAV_FALSE;
1934        }
1935        bytesRemainingInChunk -= 8;
1936        cursor += 8;
1937
1938
1939        /* Next 8 bytes is the size of the "data" chunk. */
1940        if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
1941            return DRWAV_FALSE;
1942        }
1943        bytesRemainingInChunk -= 8;
1944        dataChunkSize = drwav__bytes_to_u64(sizeBytes);
1945
1946
1947        /* Next 8 bytes is the same count which we would usually derived from the FACT chunk if it was available. */
1948        if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
1949            return DRWAV_FALSE;
1950        }
1951        bytesRemainingInChunk -= 8;
1952        sampleCountFromFactChunk = drwav__bytes_to_u64(sizeBytes);
1953
1954
1955        /* Skip over everything else. */
1956        if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
1957            return DRWAV_FALSE;
1958        }
1959        cursor += bytesRemainingInChunk;
1960    }
1961
1962
1963    /* The next bytes should be the "fmt " chunk. */
1964    if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) {
1965        return DRWAV_FALSE;    /* Failed to read the "fmt " chunk. */
1966    }
1967
1968    /* Basic validation. */
1969    if ((fmt.sampleRate    == 0 || fmt.sampleRate    > DRWAV_MAX_SAMPLE_RATE)     ||
1970        (fmt.channels      == 0 || fmt.channels      > DRWAV_MAX_CHANNELS)        ||
1971        (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) ||
1972        fmt.blockAlign == 0) {
1973        return DRWAV_FALSE; /* Probably an invalid WAV file. */
1974    }
1975
1976
1977    /* Translate the internal format. */
1978    translatedFormatTag = fmt.formatTag;
1979    if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1980        translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0);
1981    }
1982
1983
1984    /*
1985    We need to enumerate over each chunk for two reasons:
1986      1) The "data" chunk may not be the next one
1987      2) We may want to report each chunk back to the client
1988    
1989    In order to correctly report each chunk back to the client we will need to keep looping until the end of the file.
1990    */
1991    foundDataChunk = DRWAV_FALSE;
1992
1993    /* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */
1994    for (;;)
1995    {
1996        drwav_chunk_header header;
1997        drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
1998        if (result != DRWAV_SUCCESS) {
1999            if (!foundDataChunk) {
2000                return DRWAV_FALSE;
2001            } else {
2002                break;  /* Probably at the end of the file. Get out of the loop. */
2003            }
2004        }
2005
2006        /* Tell the client about this chunk. */
2007        if (!sequential && onChunk != NULL) {
2008            drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt);
2009
2010            /*
2011            dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before
2012            we called the callback.
2013            */
2014            if (callbackBytesRead > 0) {
2015                if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
2016                    return DRWAV_FALSE;
2017                }
2018            }
2019        }
2020        
2021
2022        if (!foundDataChunk) {
2023            pWav->dataChunkDataPos = cursor;
2024        }
2025
2026        chunkSize = header.sizeInBytes;
2027        if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
2028            if (drwav__fourcc_equal(header.id.fourcc, "data")) {
2029                foundDataChunk = DRWAV_TRUE;
2030                if (pWav->container != drwav_container_rf64) {  /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */
2031                    dataChunkSize = chunkSize;
2032                }
2033            }
2034        } else {
2035            if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
2036                foundDataChunk = DRWAV_TRUE;
2037                dataChunkSize = chunkSize;
2038            }
2039        }
2040
2041        /*
2042        If at this point we have found the data chunk and we're running in sequential mode, we need to break out of this loop. The reason for
2043        this is that we would otherwise require a backwards seek which sequential mode forbids.
2044        */
2045        if (foundDataChunk && sequential) {
2046            break;
2047        }
2048
2049        /* Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. */
2050        if (pWav->container == drwav_container_riff) {
2051            if (drwav__fourcc_equal(header.id.fourcc, "fact")) {
2052                drwav_uint32 sampleCount;
2053                if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) {
2054                    return DRWAV_FALSE;
2055                }
2056                chunkSize -= 4;
2057
2058                if (!foundDataChunk) {
2059                    pWav->dataChunkDataPos = cursor;
2060                }
2061
2062                /*
2063                The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this
2064                for Microsoft ADPCM formats.
2065                */
2066                if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
2067                    sampleCountFromFactChunk = sampleCount;
2068                } else {
2069                    sampleCountFromFactChunk = 0;
2070                }
2071            }
2072        } else if (pWav->container == drwav_container_w64) {
2073            if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
2074                if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
2075                    return DRWAV_FALSE;
2076                }
2077                chunkSize -= 8;
2078
2079                if (!foundDataChunk) {
2080                    pWav->dataChunkDataPos = cursor;
2081                }
2082            }
2083        } else if (pWav->container == drwav_container_rf64) {
2084            /* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */
2085        }
2086
2087        /* "smpl" chunk. */
2088        if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
2089            if (drwav__fourcc_equal(header.id.fourcc, "smpl")) {
2090                drwav_uint8 smplHeaderData[36];    /* 36 = size of the smpl header section, not including the loop data. */
2091                if (chunkSize >= sizeof(smplHeaderData)) {
2092                    drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor);
2093                    chunkSize -= bytesJustRead;
2094
2095                    if (bytesJustRead == sizeof(smplHeaderData)) {
2096                        drwav_uint32 iLoop;
2097
2098                        pWav->smpl.manufacturer      = drwav__bytes_to_u32(smplHeaderData+0);
2099                        pWav->smpl.product           = drwav__bytes_to_u32(smplHeaderData+4);
2100                        pWav->smpl.samplePeriod      = drwav__bytes_to_u32(smplHeaderData+8);
2101                        pWav->smpl.midiUnityNotes    = drwav__bytes_to_u32(smplHeaderData+12);
2102                        pWav->smpl.midiPitchFraction = drwav__bytes_to_u32(smplHeaderData+16);
2103                        pWav->smpl.smpteFormat       = drwav__bytes_to_u32(smplHeaderData+20);
2104                        pWav->smpl.smpteOffset       = drwav__bytes_to_u32(smplHeaderData+24);
2105                        pWav->smpl.numSampleLoops    = drwav__bytes_to_u32(smplHeaderData+28);
2106                        pWav->smpl.samplerData       = drwav__bytes_to_u32(smplHeaderData+32);
2107
2108                        for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) {
2109                            drwav_uint8 smplLoopData[24];  /* 24 = size of a loop section in the smpl chunk. */
2110                            bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor);
2111                            chunkSize -= bytesJustRead;
2112
2113                            if (bytesJustRead == sizeof(smplLoopData)) {
2114                                pWav->smpl.loops[iLoop].cuePointId = drwav__bytes_to_u32(smplLoopData+0);
2115                                pWav->smpl.loops[iLoop].type       = drwav__bytes_to_u32(smplLoopData+4);
2116                                pWav->smpl.loops[iLoop].start      = drwav__bytes_to_u32(smplLoopData+8);
2117                                pWav->smpl.loops[iLoop].end        = drwav__bytes_to_u32(smplLoopData+12);
2118                                pWav->smpl.loops[iLoop].fraction   = drwav__bytes_to_u32(smplLoopData+16);
2119                                pWav->smpl.loops[iLoop].playCount  = drwav__bytes_to_u32(smplLoopData+20);
2120                            } else {
2121                                break;  /* Break from the smpl loop for loop. */
2122                            }
2123                        }
2124                    }
2125                } else {
2126                    /* Looks like invalid data. Ignore the chunk. */
2127                }
2128            }
2129        } else {
2130            if (drwav__guid_equal(header.id.guid, drwavGUID_W64_SMPL)) {
2131                /*
2132                This path will be hit when a W64 WAV file contains a smpl chunk. I don't have a sample file to test this path, so a contribution
2133                is welcome to add support for this.
2134                */
2135            }
2136        }
2137
2138        /* Make sure we seek past the padding. */
2139        chunkSize += header.paddingSize;
2140        if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) {
2141            break;
2142        }
2143        cursor += chunkSize;
2144
2145        if (!foundDataChunk) {
2146            pWav->dataChunkDataPos = cursor;
2147        }
2148    }
2149
2150    /* If we haven't found a data chunk, return an error. */
2151    if (!foundDataChunk) {
2152        return DRWAV_FALSE;
2153    }
2154
2155    /* We may have moved passed the data chunk. If so we need to move back. If running in sequential mode we can assume we are already sitting on the data chunk. */
2156    if (!sequential) {
2157        if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) {
2158            return DRWAV_FALSE;
2159        }
2160        cursor = pWav->dataChunkDataPos;
2161    }
2162    
2163
2164    /* At this point we should be sitting on the first byte of the raw audio data. */
2165
2166    pWav->fmt                 = fmt;
2167    pWav->sampleRate          = fmt.sampleRate;
2168    pWav->channels            = fmt.channels;
2169    pWav->bitsPerSample       = fmt.bitsPerSample;
2170    pWav->bytesRemaining      = dataChunkSize;
2171    pWav->translatedFormatTag = translatedFormatTag;
2172    pWav->dataChunkDataSize   = dataChunkSize;
2173
2174    if (sampleCountFromFactChunk != 0) {
2175        pWav->totalPCMFrameCount = sampleCountFromFactChunk;
2176    } else {
2177        pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav);
2178
2179        if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
2180            drwav_uint64 totalBlockHeaderSizeInBytes;
2181            drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2182
2183            /* Make sure any trailing partial block is accounted for. */
2184            if ((blockCount * fmt.blockAlign) < dataChunkSize) {
2185                blockCount += 1;
2186            }
2187
2188            /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */
2189            totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
2190            pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
2191        }
2192        if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2193            drwav_uint64 totalBlockHeaderSizeInBytes;
2194            drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2195
2196            /* Make sure any trailing partial block is accounted for. */
2197            if ((blockCount * fmt.blockAlign) < dataChunkSize) {
2198                blockCount += 1;
2199            }
2200
2201            /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */
2202            totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
2203            pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
2204
2205            /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */
2206            pWav->totalPCMFrameCount += blockCount;
2207        }
2208    }
2209
2210    /* Some formats only support a certain number of channels. */
2211    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2212        if (pWav->channels > 2) {
2213            return DRWAV_FALSE;
2214        }
2215    }
2216
2217#ifdef DR_WAV_LIBSNDFILE_COMPAT
2218    /*
2219    I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website),
2220    it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count
2221    from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct
2222    way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should
2223    always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my
2224    correctness tests against libsndfile, and is disabled by default.
2225    */
2226    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
2227        drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2228        pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels;  /* x2 because two samples per byte. */
2229    }
2230    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2231        drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2232        pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
2233    }
2234#endif
2235
2236    return DRWAV_TRUE;
2237}
2238
2239DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2240{
2241    return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
2242}
2243
2244DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
2245{
2246    if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
2247        return DRWAV_FALSE;
2248    }
2249
2250    return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
2251}
2252
2253
2254static drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize)
2255{
2256    drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. */
2257    if (chunkSize > 0xFFFFFFFFUL) {
2258        chunkSize = 0xFFFFFFFFUL;
2259    }
2260
2261    return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */
2262}
2263
2264static drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
2265{
2266    if (dataChunkSize <= 0xFFFFFFFFUL) {
2267        return (drwav_uint32)dataChunkSize;
2268    } else {
2269        return 0xFFFFFFFFUL;
2270    }
2271}
2272
2273static drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
2274{
2275    drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
2276
2277    return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize;   /* +24 because W64 includes the size of the GUID and size fields. */
2278}
2279
2280static drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
2281{
2282    return 24 + dataChunkSize;        /* +24 because W64 includes the size of the GUID and size fields. */
2283}
2284
2285static drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize)
2286{
2287    drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. */
2288    if (chunkSize > 0xFFFFFFFFUL) {
2289        chunkSize = 0xFFFFFFFFUL;
2290    }
2291
2292    return chunkSize;
2293}
2294
2295static drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
2296{
2297    return dataChunkSize;
2298}
2299
2300
2301static size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
2302{
2303    DRWAV_ASSERT(pWav          != NULL);
2304    DRWAV_ASSERT(pWav->onWrite != NULL);
2305
2306    /* Generic write. Assumes no byte reordering required. */
2307    return pWav->onWrite(pWav->pUserData, pData, dataSize);
2308}
2309
2310static size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value)
2311{
2312    DRWAV_ASSERT(pWav          != NULL);
2313    DRWAV_ASSERT(pWav->onWrite != NULL);
2314
2315    if (!drwav__is_little_endian()) {
2316        value = drwav__bswap16(value);
2317    }
2318
2319    return drwav__write(pWav, &value, 2);
2320}
2321
2322static size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value)
2323{
2324    DRWAV_ASSERT(pWav          != NULL);
2325    DRWAV_ASSERT(pWav->onWrite != NULL);
2326
2327    if (!drwav__is_little_endian()) {
2328        value = drwav__bswap32(value);
2329    }
2330
2331    return drwav__write(pWav, &value, 4);
2332}
2333
2334static size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value)
2335{
2336    DRWAV_ASSERT(pWav          != NULL);
2337    DRWAV_ASSERT(pWav->onWrite != NULL);
2338
2339    if (!drwav__is_little_endian()) {
2340        value = drwav__bswap64(value);
2341    }
2342
2343    return drwav__write(pWav, &value, 8);
2344}
2345
2346
2347static drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2348{
2349    if (pWav == NULL || onWrite == NULL) {
2350        return DRWAV_FALSE;
2351    }
2352
2353    if (!isSequential && onSeek == NULL) {
2354        return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */
2355    }
2356
2357    /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */
2358    if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
2359        return DRWAV_FALSE;
2360    }
2361    if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
2362        return DRWAV_FALSE;
2363    }
2364
2365    DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
2366    pWav->onWrite   = onWrite;
2367    pWav->onSeek    = onSeek;
2368    pWav->pUserData = pUserData;
2369    pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
2370
2371    if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
2372        return DRWAV_FALSE;    /* Invalid allocation callbacks. */
2373    }
2374
2375    pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
2376    pWav->fmt.channels = (drwav_uint16)pFormat->channels;
2377    pWav->fmt.sampleRate = pFormat->sampleRate;
2378    pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8);
2379    pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8);
2380    pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
2381    pWav->fmt.extendedSize = 0;
2382    pWav->isSequentialWrite = isSequential;
2383
2384    return DRWAV_TRUE;
2385}
2386
2387static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
2388{
2389    /* The function assumes drwav_preinit_write() was called beforehand. */
2390
2391    size_t runningPos = 0;
2392    drwav_uint64 initialDataChunkSize = 0;
2393    drwav_uint64 chunkSizeFMT;
2394
2395    /*
2396    The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In
2397    sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non-
2398    sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek.
2399    */
2400    if (pWav->isSequentialWrite) {
2401        initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
2402
2403        /*
2404        The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64
2405        so for the sake of simplicity I'm not doing any validation for that.
2406        */
2407        if (pFormat->container == drwav_container_riff) {
2408            if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
2409                return DRWAV_FALSE; /* Not enough room to store every sample. */
2410            }
2411        }
2412    }
2413
2414    pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
2415
2416
2417    /* "RIFF" chunk. */
2418    if (pFormat->container == drwav_container_riff) {
2419        drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize;   /* +28 = "WAVE" + [sizeof "fmt " chunk] */
2420        runningPos += drwav__write(pWav, "RIFF", 4);
2421        runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
2422        runningPos += drwav__write(pWav, "WAVE", 4);
2423    } else if (pFormat->container == drwav_container_w64) {
2424        drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize;            /* +24 because W64 includes the size of the GUID and size fields. */
2425        runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
2426        runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
2427        runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
2428    } else if (pFormat->container == drwav_container_rf64) {
2429        runningPos += drwav__write(pWav, "RF64", 4);
2430        runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);               /* Always 0xFFFFFFFF for RF64. Set to a proper value in the "ds64" chunk. */
2431        runningPos += drwav__write(pWav, "WAVE", 4);
2432    }
2433
2434    
2435    /* "ds64" chunk (RF64 only). */
2436    if (pFormat->container == drwav_container_rf64) {
2437        drwav_uint32 initialds64ChunkSize = 28;                                 /* 28 = [Size of RIFF (8 bytes)] + [Size of DATA (8 bytes)] + [Sample Count (8 bytes)] + [Table Length (4 bytes)]. Table length always set to 0. */
2438        drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize;    /* +8 for the ds64 header. */
2439
2440        runningPos += drwav__write(pWav, "ds64", 4);
2441        runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize);     /* Size of ds64. */
2442        runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize);     /* Size of RIFF. Set to true value at the end. */
2443        runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize);     /* Size of DATA. Set to true value at the end. */
2444        runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount);         /* Sample count. */
2445        runningPos += drwav__write_u32ne_to_le(pWav, 0);                        /* Table length. Always set to zero in our case since we're not doing any other chunks than "DATA". */
2446    }
2447
2448
2449    /* "fmt " chunk. */
2450    if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
2451        chunkSizeFMT = 16;
2452        runningPos += drwav__write(pWav, "fmt ", 4);
2453        runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
2454    } else if (pFormat->container == drwav_container_w64) {
2455        chunkSizeFMT = 40;
2456        runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
2457        runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
2458    }
2459
2460    runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag);
2461    runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels);
2462    runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate);
2463    runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec);
2464    runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign);
2465    runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample);
2466
2467    pWav->dataChunkDataPos = runningPos;
2468
2469    /* "data" chunk. */
2470    if (pFormat->container == drwav_container_riff) {
2471        drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
2472        runningPos += drwav__write(pWav, "data", 4);
2473        runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
2474    } else if (pFormat->container == drwav_container_w64) {
2475        drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize;     /* +24 because W64 includes the size of the GUID and size fields. */
2476        runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
2477        runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
2478    } else if (pFormat->container == drwav_container_rf64) {
2479        runningPos += drwav__write(pWav, "data", 4);
2480        runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);   /* Always set to 0xFFFFFFFF for RF64. The true size of the data chunk is specified in the ds64 chunk. */
2481    }
2482
2483    /*
2484    The runningPos variable is incremented in the section above but is left unused which is causing some static analysis tools to detect it
2485    as a dead store. I'm leaving this as-is for safety just in case I want to expand this function later to include other tags and want to
2486    keep track of the running position for whatever reason. The line below should silence the static analysis tools.
2487    */
2488    (void)runningPos;
2489
2490    /* Set some properties for the client's convenience. */
2491    pWav->container = pFormat->container;
2492    pWav->channels = (drwav_uint16)pFormat->channels;
2493    pWav->sampleRate = pFormat->sampleRate;
2494    pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
2495    pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
2496
2497    return DRWAV_TRUE;
2498}
2499
2500
2501DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2502{
2503    if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
2504        return DRWAV_FALSE;
2505    }
2506
2507    return drwav_init_write__internal(pWav, pFormat, 0);               /* DRWAV_FALSE = Not Sequential */
2508}
2509
2510DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2511{
2512    if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
2513        return DRWAV_FALSE;
2514    }
2515
2516    return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */
2517}
2518
2519DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2520{
2521    if (pFormat == NULL) {
2522        return DRWAV_FALSE;
2523    }
2524
2525    return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
2526}
2527
2528DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
2529{
2530    /* Casting totalSampleCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */
2531    drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0);
2532    drwav_uint64 riffChunkSizeBytes;
2533    drwav_uint64 fileSizeBytes = 0;
2534
2535    if (pFormat->container == drwav_container_riff) {
2536        riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes);
2537        fileSizeBytes = (8 + riffChunkSizeBytes);   /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
2538    } else if (pFormat->container == drwav_container_w64) {
2539        riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
2540        fileSizeBytes = riffChunkSizeBytes;
2541    } else if (pFormat->container == drwav_container_rf64) {
2542        riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes);
2543        fileSizeBytes = (8 + riffChunkSizeBytes);   /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
2544    }
2545
2546    return fileSizeBytes;
2547}
2548
2549
2550#ifndef DR_WAV_NO_STDIO
2551
2552/* drwav_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */
2553#include <errno.h>
2554static drwav_result drwav_result_from_errno(int e)
2555{
2556    switch (e)
2557    {
2558        case 0: return DRWAV_SUCCESS;
2559    #ifdef EPERM
2560        case EPERM: return DRWAV_INVALID_OPERATION;
2561    #endif
2562    #ifdef ENOENT
2563        case ENOENT: return DRWAV_DOES_NOT_EXIST;
2564    #endif
2565    #ifdef ESRCH
2566        case ESRCH: return DRWAV_DOES_NOT_EXIST;
2567    #endif
2568    #ifdef EINTR
2569        case EINTR: return DRWAV_INTERRUPT;
2570    #endif
2571    #ifdef EIO
2572        case EIO: return DRWAV_IO_ERROR;
2573    #endif
2574    #ifdef ENXIO
2575        case ENXIO: return DRWAV_DOES_NOT_EXIST;
2576    #endif
2577    #ifdef E2BIG
2578        case E2BIG: return DRWAV_INVALID_ARGS;
2579    #endif
2580    #ifdef ENOEXEC
2581        case ENOEXEC: return DRWAV_INVALID_FILE;
2582    #endif
2583    #ifdef EBADF
2584        case EBADF: return DRWAV_INVALID_FILE;
2585    #endif
2586    #ifdef ECHILD
2587        case ECHILD: return DRWAV_ERROR;
2588    #endif
2589    #ifdef EAGAIN
2590        case EAGAIN: return DRWAV_UNAVAILABLE;
2591    #endif
2592    #ifdef ENOMEM
2593        case ENOMEM: return DRWAV_OUT_OF_MEMORY;
2594    #endif
2595    #ifdef EACCES
2596        case EACCES: return DRWAV_ACCESS_DENIED;
2597    #endif
2598    #ifdef EFAULT
2599        case EFAULT: return DRWAV_BAD_ADDRESS;
2600    #endif
2601    #ifdef ENOTBLK
2602        case ENOTBLK: return DRWAV_ERROR;
2603    #endif
2604    #ifdef EBUSY
2605        case EBUSY: return DRWAV_BUSY;
2606    #endif
2607    #ifdef EEXIST
2608        case EEXIST: return DRWAV_ALREADY_EXISTS;
2609    #endif
2610    #ifdef EXDEV
2611        case EXDEV: return DRWAV_ERROR;
2612    #endif
2613    #ifdef ENODEV
2614        case ENODEV: return DRWAV_DOES_NOT_EXIST;
2615    #endif
2616    #ifdef ENOTDIR
2617        case ENOTDIR: return DRWAV_NOT_DIRECTORY;
2618    #endif
2619    #ifdef EISDIR
2620        case EISDIR: return DRWAV_IS_DIRECTORY;
2621    #endif
2622    #ifdef EINVAL
2623        case EINVAL: return DRWAV_INVALID_ARGS;
2624    #endif
2625    #ifdef ENFILE
2626        case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES;
2627    #endif
2628    #ifdef EMFILE
2629        case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES;
2630    #endif
2631    #ifdef ENOTTY
2632        case ENOTTY: return DRWAV_INVALID_OPERATION;
2633    #endif
2634    #ifdef ETXTBSY
2635        case ETXTBSY: return DRWAV_BUSY;
2636    #endif
2637    #ifdef EFBIG
2638        case EFBIG: return DRWAV_TOO_BIG;
2639    #endif
2640    #ifdef ENOSPC
2641        case ENOSPC: return DRWAV_NO_SPACE;
2642    #endif
2643    #ifdef ESPIPE
2644        case ESPIPE: return DRWAV_BAD_SEEK;
2645    #endif
2646    #ifdef EROFS
2647        case EROFS: return DRWAV_ACCESS_DENIED;
2648    #endif
2649    #ifdef EMLINK
2650        case EMLINK: return DRWAV_TOO_MANY_LINKS;
2651    #endif
2652    #ifdef EPIPE
2653        case EPIPE: return DRWAV_BAD_PIPE;
2654    #endif
2655    #ifdef EDOM
2656        case EDOM: return DRWAV_OUT_OF_RANGE;
2657    #endif
2658    #ifdef ERANGE
2659        case ERANGE: return DRWAV_OUT_OF_RANGE;
2660    #endif
2661    #ifdef EDEADLK
2662        case EDEADLK: return DRWAV_DEADLOCK;
2663    #endif
2664    #ifdef ENAMETOOLONG
2665        case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG;
2666    #endif
2667    #ifdef ENOLCK
2668        case ENOLCK: return DRWAV_ERROR;
2669    #endif
2670    #ifdef ENOSYS
2671        case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
2672    #endif
2673    #ifdef ENOTEMPTY
2674        case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
2675    #endif
2676    #ifdef ELOOP
2677        case ELOOP: return DRWAV_TOO_MANY_LINKS;
2678    #endif
2679    #ifdef ENOMSG
2680        case ENOMSG: return DRWAV_NO_MESSAGE;
2681    #endif
2682    #ifdef EIDRM
2683        case EIDRM: return DRWAV_ERROR;
2684    #endif
2685    #ifdef ECHRNG
2686        case ECHRNG: return DRWAV_ERROR;
2687    #endif
2688    #ifdef EL2NSYNC
2689        case EL2NSYNC: return DRWAV_ERROR;
2690    #endif
2691    #ifdef EL3HLT
2692        case EL3HLT: return DRWAV_ERROR;
2693    #endif
2694    #ifdef EL3RST
2695        case EL3RST: return DRWAV_ERROR;
2696    #endif
2697    #ifdef ELNRNG
2698        case ELNRNG: return DRWAV_OUT_OF_RANGE;
2699    #endif
2700    #ifdef EUNATCH
2701        case EUNATCH: return DRWAV_ERROR;
2702    #endif
2703    #ifdef ENOCSI
2704        case ENOCSI: return DRWAV_ERROR;
2705    #endif
2706    #ifdef EL2HLT
2707        case EL2HLT: return DRWAV_ERROR;
2708    #endif
2709    #ifdef EBADE
2710        case EBADE: return DRWAV_ERROR;
2711    #endif
2712    #ifdef EBADR
2713        case EBADR: return DRWAV_ERROR;
2714    #endif
2715    #ifdef EXFULL
2716        case EXFULL: return DRWAV_ERROR;
2717    #endif
2718    #ifdef ENOANO
2719        case ENOANO: return DRWAV_ERROR;
2720    #endif
2721    #ifdef EBADRQC
2722        case EBADRQC: return DRWAV_ERROR;
2723    #endif
2724    #ifdef EBADSLT
2725        case EBADSLT: return DRWAV_ERROR;
2726    #endif
2727    #ifdef EBFONT
2728        case EBFONT: return DRWAV_INVALID_FILE;
2729    #endif
2730    #ifdef ENOSTR
2731        case ENOSTR: return DRWAV_ERROR;
2732    #endif
2733    #ifdef ENODATA
2734        case ENODATA: return DRWAV_NO_DATA_AVAILABLE;
2735    #endif
2736    #ifdef ETIME
2737        case ETIME: return DRWAV_TIMEOUT;
2738    #endif
2739    #ifdef ENOSR
2740        case ENOSR: return DRWAV_NO_DATA_AVAILABLE;
2741    #endif
2742    #ifdef ENONET
2743        case ENONET: return DRWAV_NO_NETWORK;
2744    #endif
2745    #ifdef ENOPKG
2746        case ENOPKG: return DRWAV_ERROR;
2747    #endif
2748    #ifdef EREMOTE
2749        case EREMOTE: return DRWAV_ERROR;
2750    #endif
2751    #ifdef ENOLINK
2752        case ENOLINK: return DRWAV_ERROR;
2753    #endif
2754    #ifdef EADV
2755        case EADV: return DRWAV_ERROR;
2756    #endif
2757    #ifdef ESRMNT
2758        case ESRMNT: return DRWAV_ERROR;
2759    #endif
2760    #ifdef ECOMM
2761        case ECOMM: return DRWAV_ERROR;
2762    #endif
2763    #ifdef EPROTO
2764        case EPROTO: return DRWAV_ERROR;
2765    #endif
2766    #ifdef EMULTIHOP
2767        case EMULTIHOP: return DRWAV_ERROR;
2768    #endif
2769    #ifdef EDOTDOT
2770        case EDOTDOT: return DRWAV_ERROR;
2771    #endif
2772    #ifdef EBADMSG
2773        case EBADMSG: return DRWAV_BAD_MESSAGE;
2774    #endif
2775    #ifdef EOVERFLOW
2776        case EOVERFLOW: return DRWAV_TOO_BIG;
2777    #endif
2778    #ifdef ENOTUNIQ
2779        case ENOTUNIQ: return DRWAV_NOT_UNIQUE;
2780    #endif
2781    #ifdef EBADFD
2782        case EBADFD: return DRWAV_ERROR;
2783    #endif
2784    #ifdef EREMCHG
2785        case EREMCHG: return DRWAV_ERROR;
2786    #endif
2787    #ifdef ELIBACC
2788        case ELIBACC: return DRWAV_ACCESS_DENIED;
2789    #endif
2790    #ifdef ELIBBAD
2791        case ELIBBAD: return DRWAV_INVALID_FILE;
2792    #endif
2793    #ifdef ELIBSCN
2794        case ELIBSCN: return DRWAV_INVALID_FILE;
2795    #endif
2796    #ifdef ELIBMAX
2797        case ELIBMAX: return DRWAV_ERROR;
2798    #endif
2799    #ifdef ELIBEXEC
2800        case ELIBEXEC: return DRWAV_ERROR;
2801    #endif
2802    #ifdef EILSEQ
2803        case EILSEQ: return DRWAV_INVALID_DATA;
2804    #endif
2805    #ifdef ERESTART
2806        case ERESTART: return DRWAV_ERROR;
2807    #endif
2808    #ifdef ESTRPIPE
2809        case ESTRPIPE: return DRWAV_ERROR;
2810    #endif
2811    #ifdef EUSERS
2812        case EUSERS: return DRWAV_ERROR;
2813    #endif
2814    #ifdef ENOTSOCK
2815        case ENOTSOCK: return DRWAV_NOT_SOCKET;
2816    #endif
2817    #ifdef EDESTADDRREQ
2818        case EDESTADDRREQ: return DRWAV_NO_ADDRESS;
2819    #endif
2820    #ifdef EMSGSIZE
2821        case EMSGSIZE: return DRWAV_TOO_BIG;
2822    #endif
2823    #ifdef EPROTOTYPE
2824        case EPROTOTYPE: return DRWAV_BAD_PROTOCOL;
2825    #endif
2826    #ifdef ENOPROTOOPT
2827        case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE;
2828    #endif
2829    #ifdef EPROTONOSUPPORT
2830        case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED;
2831    #endif
2832    #ifdef ESOCKTNOSUPPORT
2833        case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED;
2834    #endif
2835    #ifdef EOPNOTSUPP
2836        case EOPNOTSUPP: return DRWAV_INVALID_OPERATION;
2837    #endif
2838    #ifdef EPFNOSUPPORT
2839        case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED;
2840    #endif
2841    #ifdef EAFNOSUPPORT
2842        case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED;
2843    #endif
2844    #ifdef EADDRINUSE
2845        case EADDRINUSE: return DRWAV_ALREADY_IN_USE;
2846    #endif
2847    #ifdef EADDRNOTAVAIL
2848        case EADDRNOTAVAIL: return DRWAV_ERROR;
2849    #endif
2850    #ifdef ENETDOWN
2851        case ENETDOWN: return DRWAV_NO_NETWORK;
2852    #endif
2853    #ifdef ENETUNREACH
2854        case ENETUNREACH: return DRWAV_NO_NETWORK;
2855    #endif
2856    #ifdef ENETRESET
2857        case ENETRESET: return DRWAV_NO_NETWORK;
2858    #endif
2859    #ifdef ECONNABORTED
2860        case ECONNABORTED: return DRWAV_NO_NETWORK;
2861    #endif
2862    #ifdef ECONNRESET
2863        case ECONNRESET: return DRWAV_CONNECTION_RESET;
2864    #endif
2865    #ifdef ENOBUFS
2866        case ENOBUFS: return DRWAV_NO_SPACE;
2867    #endif
2868    #ifdef EISCONN
2869        case EISCONN: return DRWAV_ALREADY_CONNECTED;
2870    #endif
2871    #ifdef ENOTCONN
2872        case ENOTCONN: return DRWAV_NOT_CONNECTED;
2873    #endif
2874    #ifdef ESHUTDOWN
2875        case ESHUTDOWN: return DRWAV_ERROR;
2876    #endif
2877    #ifdef ETOOMANYREFS
2878        case ETOOMANYREFS: return DRWAV_ERROR;
2879    #endif
2880    #ifdef ETIMEDOUT
2881        case ETIMEDOUT: return DRWAV_TIMEOUT;
2882    #endif
2883    #ifdef ECONNREFUSED
2884        case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED;
2885    #endif
2886    #ifdef EHOSTDOWN
2887        case EHOSTDOWN: return DRWAV_NO_HOST;
2888    #endif
2889    #ifdef EHOSTUNREACH
2890        case EHOSTUNREACH: return DRWAV_NO_HOST;
2891    #endif
2892    #ifdef EALREADY
2893        case EALREADY: return DRWAV_IN_PROGRESS;
2894    #endif
2895    #ifdef EINPROGRESS
2896        case EINPROGRESS: return DRWAV_IN_PROGRESS;
2897    #endif
2898    #ifdef ESTALE
2899        case ESTALE: return DRWAV_INVALID_FILE;
2900    #endif
2901    #ifdef EUCLEAN
2902        case EUCLEAN: return DRWAV_ERROR;
2903    #endif
2904    #ifdef ENOTNAM
2905        case ENOTNAM: return DRWAV_ERROR;
2906    #endif
2907    #ifdef ENAVAIL
2908        case ENAVAIL: return DRWAV_ERROR;
2909    #endif
2910    #ifdef EISNAM
2911        case EISNAM: return DRWAV_ERROR;
2912    #endif
2913    #ifdef EREMOTEIO
2914        case EREMOTEIO: return DRWAV_IO_ERROR;
2915    #endif
2916    #ifdef EDQUOT
2917        case EDQUOT: return DRWAV_NO_SPACE;
2918    #endif
2919    #ifdef ENOMEDIUM
2920        case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST;
2921    #endif
2922    #ifdef EMEDIUMTYPE
2923        case EMEDIUMTYPE: return DRWAV_ERROR;
2924    #endif
2925    #ifdef ECANCELED
2926        case ECANCELED: return DRWAV_CANCELLED;
2927    #endif
2928    #ifdef ENOKEY
2929        case ENOKEY: return DRWAV_ERROR;
2930    #endif
2931    #ifdef EKEYEXPIRED
2932        case EKEYEXPIRED: return DRWAV_ERROR;
2933    #endif
2934    #ifdef EKEYREVOKED
2935        case EKEYREVOKED: return DRWAV_ERROR;
2936    #endif
2937    #ifdef EKEYREJECTED
2938        case EKEYREJECTED: return DRWAV_ERROR;
2939    #endif
2940    #ifdef EOWNERDEAD
2941        case EOWNERDEAD: return DRWAV_ERROR;
2942    #endif
2943    #ifdef ENOTRECOVERABLE
2944        case ENOTRECOVERABLE: return DRWAV_ERROR;
2945    #endif
2946    #ifdef ERFKILL
2947        case ERFKILL: return DRWAV_ERROR;
2948    #endif
2949    #ifdef EHWPOISON
2950        case EHWPOISON: return DRWAV_ERROR;
2951    #endif
2952        default: return DRWAV_ERROR;
2953    }
2954}
2955
2956static drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
2957{
2958#if _MSC_VER && _MSC_VER >= 1400
2959    errno_t err;
2960#endif
2961
2962    if (ppFile != NULL) {
2963        *ppFile = NULL;  /* Safety. */
2964    }
2965
2966    if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
2967        return DRWAV_INVALID_ARGS;
2968    }
2969
2970#if _MSC_VER && _MSC_VER >= 1400
2971    err = fopen_s(ppFile, pFilePath, pOpenMode);
2972    if (err != 0) {
2973        return drwav_result_from_errno(err);
2974    }
2975#else
2976#if defined(_WIN32) || defined(__APPLE__)
2977    *ppFile = fopen(pFilePath, pOpenMode);
2978#else
2979    #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
2980        *ppFile = fopen64(pFilePath, pOpenMode);
2981    #else
2982        *ppFile = fopen(pFilePath, pOpenMode);
2983    #endif
2984#endif
2985    if (*ppFile == NULL) {
2986        drwav_result result = drwav_result_from_errno(errno);
2987        if (result == DRWAV_SUCCESS) {
2988            result = DRWAV_ERROR;   /* Just a safety check to make sure we never ever return success when pFile == NULL. */
2989        }
2990
2991        return result;
2992    }
2993#endif
2994
2995    return DRWAV_SUCCESS;
2996}
2997
2998/*
2999_wfopen() isn't always available in all compilation environments.
3000
3001    * Windows only.
3002    * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
3003    * MinGW-64 (both 32- and 64-bit) seems to support it.
3004    * MinGW wraps it in !defined(__STRICT_ANSI__).
3005    * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
3006
3007This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
3008fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
3009*/
3010#if defined(_WIN32)
3011    #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
3012        #define DRWAV_HAS_WFOPEN
3013    #endif
3014#endif
3015
3016static drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
3017{
3018    if (ppFile != NULL) {
3019        *ppFile = NULL;  /* Safety. */
3020    }
3021
3022    if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
3023        return DRWAV_INVALID_ARGS;
3024    }
3025
3026#if defined(DRWAV_HAS_WFOPEN)
3027    {
3028        /* Use _wfopen() on Windows. */
3029    #if defined(_MSC_VER) && _MSC_VER >= 1400
3030        errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
3031        if (err != 0) {
3032            return drwav_result_from_errno(err);
3033        }
3034    #else
3035        *ppFile = _wfopen(pFilePath, pOpenMode);
3036        if (*ppFile == NULL) {
3037            return drwav_result_from_errno(errno);
3038        }
3039    #endif
3040        (void)pAllocationCallbacks;
3041    }
3042#else
3043    /*
3044    Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
3045    think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
3046    maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
3047    */
3048    {
3049        mbstate_t mbs;
3050        size_t lenMB;
3051        const wchar_t* pFilePathTemp = pFilePath;
3052        char* pFilePathMB = NULL;
3053        char pOpenModeMB[32] = {0};
3054
3055        /* Get the length first. */
3056        DRWAV_ZERO_OBJECT(&mbs);
3057        lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
3058        if (lenMB == (size_t)-1) {
3059            return drwav_result_from_errno(errno);
3060        }
3061
3062        pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
3063        if (pFilePathMB == NULL) {
3064            return DRWAV_OUT_OF_MEMORY;
3065        }
3066
3067        pFilePathTemp = pFilePath;
3068        DRWAV_ZERO_OBJECT(&mbs);
3069        wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
3070
3071        /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
3072        {
3073            size_t i = 0;
3074            for (;;) {
3075                if (pOpenMode[i] == 0) {
3076                    pOpenModeMB[i] = '\0';
3077                    break;
3078                }
3079
3080                pOpenModeMB[i] = (char)pOpenMode[i];
3081                i += 1;
3082            }
3083        }
3084
3085        *ppFile = fopen(pFilePathMB, pOpenModeMB);
3086
3087        drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
3088    }
3089
3090    if (*ppFile == NULL) {
3091        return DRWAV_ERROR;
3092    }
3093#endif
3094
3095    return DRWAV_SUCCESS;
3096}
3097
3098
3099static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
3100{
3101    return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
3102}
3103
3104static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
3105{
3106    return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
3107}
3108
3109static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
3110{
3111    return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
3112}
3113
3114DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
3115{
3116    return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
3117}
3118
3119
3120static drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
3121{
3122    drwav_bool32 result;
3123
3124    result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
3125    if (result != DRWAV_TRUE) {
3126        fclose(pFile);
3127        return result;
3128    }
3129
3130    result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
3131    if (result != DRWAV_TRUE) {
3132        fclose(pFile);
3133        return result;
3134    }
3135
3136    return DRWAV_TRUE;
3137}
3138
3139DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
3140{
3141    FILE* pFile;
3142    if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
3143        return DRWAV_FALSE;
3144    }
3145
3146    /* This takes ownership of the FILE* object. */
3147    return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
3148}
3149
3150DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
3151{
3152    return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
3153}
3154
3155DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
3156{
3157    FILE* pFile;
3158    if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
3159        return DRWAV_FALSE;
3160    }
3161
3162    /* This takes ownership of the FILE* object. */
3163    return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
3164}
3165
3166
3167static drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
3168{
3169    drwav_bool32 result;
3170
3171    result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
3172    if (result != DRWAV_TRUE) {
3173        fclose(pFile);
3174        return result;
3175    }
3176
3177    result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
3178    if (result != DRWAV_TRUE) {
3179        fclose(pFile);
3180        return result;
3181    }
3182
3183    return DRWAV_TRUE;
3184}
3185
3186static drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
3187{
3188    FILE* pFile;
3189    if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
3190        return DRWAV_FALSE;
3191    }
3192
3193    /* This takes ownership of the FILE* object. */
3194    return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
3195}
3196
3197static drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
3198{
3199    FILE* pFile;
3200    if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
3201        return DRWAV_FALSE;
3202    }
3203
3204    /* This takes ownership of the FILE* object. */
3205    return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
3206}
3207
3208DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
3209{
3210    return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3211}
3212
3213DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
3214{
3215    return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3216}
3217
3218DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
3219{
3220    if (pFormat == NULL) {
3221        return DRWAV_FALSE;
3222    }
3223
3224    return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3225}
3226
3227DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
3228{
3229    return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3230}
3231
3232DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
3233{
3234    return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3235}
3236
3237DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
3238{
3239    if (pFormat == NULL) {
3240        return DRWAV_FALSE;
3241    }
3242
3243    return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3244}
3245#endif  /* DR_WAV_NO_STDIO */
3246
3247
3248static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
3249{
3250    drwav* pWav = (drwav*)pUserData;
3251    size_t bytesRemaining;
3252
3253    DRWAV_ASSERT(pWav != NULL);
3254    DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
3255
3256    bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
3257    if (bytesToRead > bytesRemaining) {
3258        bytesToRead = bytesRemaining;
3259    }
3260
3261    if (bytesToRead > 0) {
3262        DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
3263        pWav->memoryStream.currentReadPos += bytesToRead;
3264    }
3265
3266    return bytesToRead;
3267}
3268
3269static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
3270{
3271    drwav* pWav = (drwav*)pUserData;
3272    DRWAV_ASSERT(pWav != NULL);
3273
3274    if (origin == drwav_seek_origin_current) {
3275        if (offset > 0) {
3276            if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
3277                return DRWAV_FALSE; /* Trying to seek too far forward. */
3278            }
3279        } else {
3280            if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
3281                return DRWAV_FALSE; /* Trying to seek too far backwards. */
3282            }
3283        }
3284
3285        /* This will never underflow thanks to the clamps above. */
3286        pWav->memoryStream.currentReadPos += offset;
3287    } else {
3288        if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
3289            pWav->memoryStream.currentReadPos = offset;
3290        } else {
3291            return DRWAV_FALSE; /* Trying to seek too far forward. */
3292        }
3293    }
3294    
3295    return DRWAV_TRUE;
3296}
3297
3298static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
3299{
3300    drwav* pWav = (drwav*)pUserData;
3301    size_t bytesRemaining;
3302
3303    DRWAV_ASSERT(pWav != NULL);
3304    DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
3305
3306    bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos;
3307    if (bytesRemaining < bytesToWrite) {
3308        /* Need to reallocate. */
3309        void* pNewData;
3310        size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2;
3311
3312        /* If doubling wasn't enough, just make it the minimum required size to write the data. */
3313        if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) {
3314            newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite;
3315        }
3316
3317        pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
3318        if (pNewData == NULL) {
3319            return 0;
3320        }
3321
3322        *pWav->memoryStreamWrite.ppData = pNewData;
3323        pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
3324    }
3325
3326    DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
3327
3328    pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
3329    if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
3330        pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
3331    }
3332
3333    *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
3334
3335    return bytesToWrite;
3336}
3337
3338static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
3339{
3340    drwav* pWav = (drwav*)pUserData;
3341    DRWAV_ASSERT(pWav != NULL);
3342
3343    if (origin == drwav_seek_origin_current) {
3344        if (offset > 0) {
3345            if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
3346                offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos);  /* Trying to seek too far forward. */
3347            }
3348        } else {
3349            if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
3350                offset = -(int)pWav->memoryStreamWrite.currentWritePos;  /* Trying to seek too far backwards. */
3351            }
3352        }
3353
3354        /* This will never underflow thanks to the clamps above. */
3355        pWav->memoryStreamWrite.currentWritePos += offset;
3356    } else {
3357        if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
3358            pWav->memoryStreamWrite.currentWritePos = offset;
3359        } else {
3360            pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize;  /* Trying to seek too far forward. */
3361        }
3362    }
3363    
3364    return DRWAV_TRUE;
3365}
3366
3367DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
3368{
3369    return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
3370}
3371
3372DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
3373{
3374    if (data == NULL || dataSize == 0) {
3375        return DRWAV_FALSE;
3376    }
3377
3378    if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
3379        return DRWAV_FALSE;
3380    }
3381
3382    pWav->memoryStream.data = (const drwav_uint8*)data;
3383    pWav->memoryStream.dataSize = dataSize;
3384    pWav->memoryStream.currentReadPos = 0;
3385
3386    return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
3387}
3388
3389
3390static drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
3391{
3392    if (ppData == NULL || pDataSize == NULL) {
3393        return DRWAV_FALSE;
3394    }
3395
3396    *ppData = NULL; /* Important because we're using realloc()! */
3397    *pDataSize = 0;
3398
3399    if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
3400        return DRWAV_FALSE;
3401    }
3402
3403    pWav->memoryStreamWrite.ppData = ppData;
3404    pWav->memoryStreamWrite.pDataSize = pDataSize;
3405    pWav->memoryStreamWrite.dataSize = 0;
3406    pWav->memoryStreamWrite.dataCapacity = 0;
3407    pWav->memoryStreamWrite.currentWritePos = 0;
3408
3409    return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
3410}
3411
3412DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
3413{
3414    return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3415}
3416
3417DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
3418{
3419    return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3420}
3421
3422DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
3423{
3424    if (pFormat == NULL) {
3425        return DRWAV_FALSE;
3426    }
3427
3428    return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3429}
3430
3431
3432
3433DRWAV_API drwav_result drwav_uninit(drwav* pWav)
3434{
3435    drwav_result result = DRWAV_SUCCESS;
3436
3437    if (pWav == NULL) {
3438        return DRWAV_INVALID_ARGS;
3439    }
3440
3441    /*
3442    If the drwav object was opened in write mode we'll need to finalize a few things:
3443      - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers.
3444      - Set the size of the "data" chunk.
3445    */
3446    if (pWav->onWrite != NULL) {
3447        drwav_uint32 paddingSize = 0;
3448
3449        /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */
3450        if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
3451            paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
3452        } else {
3453            paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
3454        }
3455        
3456        if (paddingSize > 0) {
3457            drwav_uint64 paddingData = 0;
3458            drwav__write(pWav, &paddingData, paddingSize);  /* Byte order does not matter for this. */
3459        }
3460
3461        /*
3462        Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need
3463        to do this when using non-sequential mode.
3464        */
3465        if (pWav->onSeek && !pWav->isSequentialWrite) {
3466            if (pWav->container == drwav_container_riff) {
3467                /* The "RIFF" chunk size. */
3468                if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
3469                    drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize);
3470                    drwav__write_u32ne_to_le(pWav, riffChunkSize);
3471                }
3472
3473                /* the "data" chunk size. */
3474                if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) {
3475                    drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
3476                    drwav__write_u32ne_to_le(pWav, dataChunkSize);
3477                }
3478            } else if (pWav->container == drwav_container_w64) {
3479                /* The "RIFF" chunk size. */
3480                if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
3481                    drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
3482                    drwav__write_u64ne_to_le(pWav, riffChunkSize);
3483                }
3484
3485                /* The "data" chunk size. */
3486                if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) {
3487                    drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
3488                    drwav__write_u64ne_to_le(pWav, dataChunkSize);
3489                }
3490            } else if (pWav->container == drwav_container_rf64) {
3491                /* We only need to update the ds64 chunk. The "RIFF" and "data" chunks always have their sizes set to 0xFFFFFFFF for RF64. */
3492                int ds64BodyPos = 12 + 8;
3493
3494                /* The "RIFF" chunk size. */
3495                if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
3496                    drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize);
3497                    drwav__write_u64ne_to_le(pWav, riffChunkSize);
3498                }
3499
3500                /* The "data" chunk size. */
3501                if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
3502                    drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
3503                    drwav__write_u64ne_to_le(pWav, dataChunkSize);
3504                }
3505            }
3506        }
3507
3508        /* Validation for sequential mode. */
3509        if (pWav->isSequentialWrite) {
3510            if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
3511                result = DRWAV_INVALID_FILE;
3512            }
3513        }
3514    }
3515
3516#ifndef DR_WAV_NO_STDIO
3517    /*
3518    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()
3519    was used by looking at the onRead and onSeek callbacks.
3520    */
3521    if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
3522        fclose((FILE*)pWav->pUserData);
3523    }
3524#endif
3525
3526    return result;
3527}
3528
3529
3530
3531DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
3532{
3533    size_t bytesRead;
3534
3535    if (pWav == NULL || bytesToRead == 0) {
3536        return 0;
3537    }
3538
3539    if (bytesToRead > pWav->bytesRemaining) {
3540        bytesToRead = (size_t)pWav->bytesRemaining;
3541    }
3542
3543    if (pBufferOut != NULL) {
3544        bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
3545    } else {
3546        /* We need to seek. If we fail, we need to read-and-discard to make sure we get a good byte count. */
3547        bytesRead = 0;
3548        while (bytesRead < bytesToRead) {
3549            size_t bytesToSeek = (bytesToRead - bytesRead);
3550            if (bytesToSeek > 0x7FFFFFFF) {
3551                bytesToSeek = 0x7FFFFFFF;
3552            }
3553
3554            if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) {
3555                break;
3556            }
3557
3558            bytesRead += bytesToSeek;
3559        }
3560
3561        /* When we get here we may need to read-and-discard some data. */
3562        while (bytesRead < bytesToRead) {
3563            drwav_uint8 buffer[4096];
3564            size_t bytesSeeked;
3565            size_t bytesToSeek = (bytesToRead - bytesRead);
3566            if (bytesToSeek > sizeof(buffer)) {
3567                bytesToSeek = sizeof(buffer);
3568            }
3569
3570            bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek);
3571            bytesRead += bytesSeeked;
3572
3573            if (bytesSeeked < bytesToSeek) {
3574                break;  /* Reached the end. */
3575            }
3576        }
3577    }
3578
3579    pWav->bytesRemaining -= bytesRead;
3580    return bytesRead;
3581}
3582
3583
3584
3585DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3586{
3587    drwav_uint32 bytesPerFrame;
3588    drwav_uint64 bytesToRead;   /* Intentionally uint64 instead of size_t so we can do a check that we're not reading too much on 32-bit builds. */
3589
3590    if (pWav == NULL || framesToRead == 0) {
3591        return 0;
3592    }
3593
3594    /* Cannot use this function for compressed formats. */
3595    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3596        return 0;
3597    }
3598
3599    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
3600    if (bytesPerFrame == 0) {
3601        return 0;
3602    }
3603
3604    /* Don't try to read more samples than can potentially fit in the output buffer. */
3605    bytesToRead = framesToRead * bytesPerFrame;
3606    if (bytesToRead > DRWAV_SIZE_MAX) {
3607        bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame; /* Round the number of bytes to read to a clean frame boundary. */
3608    }
3609
3610    /*
3611    Doing an explicit check here just to make it clear that we don't want to be attempt to read anything if there's no bytes to read. There
3612    *could* be a time where it evaluates to 0 due to overflowing.
3613    */
3614    if (bytesToRead == 0) {
3615        return 0;
3616    }
3617
3618    return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame;
3619}
3620
3621DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3622{
3623    drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
3624
3625    if (pBufferOut != NULL) {
3626        drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag);
3627    }
3628
3629    return framesRead;
3630}
3631
3632DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3633{
3634    if (drwav__is_little_endian()) {
3635        return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
3636    } else {
3637        return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
3638    }
3639}
3640
3641
3642
3643DRWAV_API drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
3644{
3645    if (pWav->onWrite != NULL) {
3646        return DRWAV_FALSE; /* No seeking in write mode. */
3647    }
3648
3649    if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
3650        return DRWAV_FALSE;
3651    }
3652
3653    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3654        pWav->compressed.iCurrentPCMFrame = 0;
3655
3656        /* Cached data needs to be cleared for compressed formats. */
3657        if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3658            DRWAV_ZERO_OBJECT(&pWav->msadpcm);
3659        } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3660            DRWAV_ZERO_OBJECT(&pWav->ima);
3661        } else {
3662            DRWAV_ASSERT(DRWAV_FALSE);  /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */
3663        }
3664    }
3665    
3666    pWav->bytesRemaining = pWav->dataChunkDataSize;
3667    return DRWAV_TRUE;
3668}
3669
3670DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex)
3671{
3672    /* Seeking should be compatible with wave files > 2GB. */
3673
3674    if (pWav == NULL || pWav->onSeek == NULL) {
3675        return DRWAV_FALSE;
3676    }
3677
3678    /* No seeking in write mode. */
3679    if (pWav->onWrite != NULL) {
3680        return DRWAV_FALSE;
3681    }
3682
3683    /* If there are no samples, just return DRWAV_TRUE without doing anything. */
3684    if (pWav->totalPCMFrameCount == 0) {
3685        return DRWAV_TRUE;
3686    }
3687
3688    /* Make sure the sample is clamped. */
3689    if (targetFrameIndex >= pWav->totalPCMFrameCount) {
3690        targetFrameIndex  = pWav->totalPCMFrameCount - 1;
3691    }
3692
3693    /*
3694    For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need
3695    to seek back to the start.
3696    */
3697    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3698        /* TODO: This can be optimized. */
3699        
3700        /*
3701        If we're seeking forward it's simple - just keep reading samples until we hit the sample we're requesting. If we're seeking backwards,
3702        we first need to seek back to the start and then just do the same thing as a forward seek.
3703        */
3704        if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) {
3705            if (!drwav_seek_to_first_pcm_frame(pWav)) {
3706                return DRWAV_FALSE;
3707            }
3708        }
3709
3710        if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) {
3711            drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame;
3712
3713            drwav_int16 devnull[2048];
3714            while (offsetInFrames > 0) {
3715                drwav_uint64 framesRead = 0;
3716                drwav_uint64 framesToRead = offsetInFrames;
3717                if (framesToRead > drwav_countof(devnull)/pWav->channels) {
3718                    framesToRead = drwav_countof(devnull)/pWav->channels;
3719                }
3720
3721                if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3722                    framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull);
3723                } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3724                    framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull);
3725                } else {
3726                    DRWAV_ASSERT(DRWAV_FALSE);  /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */
3727                }
3728
3729                if (framesRead != framesToRead) {
3730                    return DRWAV_FALSE;
3731                }
3732
3733                offsetInFrames -= framesRead;
3734            }
3735        }
3736    } else {
3737        drwav_uint64 totalSizeInBytes;
3738        drwav_uint64 currentBytePos;
3739        drwav_uint64 targetBytePos;
3740        drwav_uint64 offset;
3741
3742        totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav);
3743        DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);
3744
3745        currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
3746        targetBytePos  = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav);
3747
3748        if (currentBytePos < targetBytePos) {
3749            /* Offset forwards. */
3750            offset = (targetBytePos - currentBytePos);
3751        } else {
3752            /* Offset backwards. */
3753            if (!drwav_seek_to_first_pcm_frame(pWav)) {
3754                return DRWAV_FALSE;
3755            }
3756            offset = targetBytePos;
3757        }
3758
3759        while (offset > 0) {
3760            int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
3761            if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
3762                return DRWAV_FALSE;
3763            }
3764
3765            pWav->bytesRemaining -= offset32;
3766            offset -= offset32;
3767        }
3768    }
3769
3770    return DRWAV_TRUE;
3771}
3772
3773
3774DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
3775{
3776    size_t bytesWritten;
3777
3778    if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
3779        return 0;
3780    }
3781
3782    bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
3783    pWav->dataChunkDataSize += bytesWritten;
3784
3785    return bytesWritten;
3786}
3787
3788
3789DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3790{
3791    drwav_uint64 bytesToWrite;
3792    drwav_uint64 bytesWritten;
3793    const drwav_uint8* pRunningData;
3794
3795    if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
3796        return 0;
3797    }
3798
3799    bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
3800    if (bytesToWrite > DRWAV_SIZE_MAX) {
3801        return 0;
3802    }
3803
3804    bytesWritten = 0;
3805    pRunningData = (const drwav_uint8*)pData;
3806
3807    while (bytesToWrite > 0) {
3808        size_t bytesJustWritten;
3809        drwav_uint64 bytesToWriteThisIteration;
3810
3811        bytesToWriteThisIteration = bytesToWrite;
3812        DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX);  /* <-- This is checked above. */
3813
3814        bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData);
3815        if (bytesJustWritten == 0) {
3816            break;
3817        }
3818
3819        bytesToWrite -= bytesJustWritten;
3820        bytesWritten += bytesJustWritten;
3821        pRunningData += bytesJustWritten;
3822    }
3823
3824    return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
3825}
3826
3827DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3828{
3829    drwav_uint64 bytesToWrite;
3830    drwav_uint64 bytesWritten;
3831    drwav_uint32 bytesPerSample;
3832    const drwav_uint8* pRunningData;
3833
3834    if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
3835        return 0;
3836    }
3837
3838    bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
3839    if (bytesToWrite > DRWAV_SIZE_MAX) {
3840        return 0;
3841    }
3842
3843    bytesWritten = 0;
3844    pRunningData = (const drwav_uint8*)pData;
3845
3846    bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels;
3847    
3848    while (bytesToWrite > 0) {
3849        drwav_uint8 temp[4096];
3850        drwav_uint32 sampleCount;
3851        size_t bytesJustWritten;
3852        drwav_uint64 bytesToWriteThisIteration;
3853
3854        bytesToWriteThisIteration = bytesToWrite;
3855        DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX);  /* <-- This is checked above. */
3856
3857        /*
3858        WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need
3859        to use an intermediary buffer for the conversion.
3860        */
3861        sampleCount = sizeof(temp)/bytesPerSample;
3862
3863        if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) {
3864            bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample;
3865        }
3866
3867        DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration);
3868        drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag);
3869
3870        bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp);
3871        if (bytesJustWritten == 0) {
3872            break;
3873        }
3874
3875        bytesToWrite -= bytesJustWritten;
3876        bytesWritten += bytesJustWritten;
3877        pRunningData += bytesJustWritten;
3878    }
3879
3880    return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
3881}
3882
3883DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3884{
3885    if (drwav__is_little_endian()) {
3886        return drwav_write_pcm_frames_le(pWav, framesToWrite, pData);
3887    } else {
3888        return drwav_write_pcm_frames_be(pWav, framesToWrite, pData);
3889    }
3890}
3891
3892
3893static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
3894{
3895    drwav_uint64 totalFramesRead = 0;
3896
3897    DRWAV_ASSERT(pWav != NULL);
3898    DRWAV_ASSERT(framesToRead > 0);
3899
3900    /* TODO: Lots of room for optimization here. */
3901
3902    while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
3903        /* If there are no cached frames we need to load a new block. */
3904        if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) {
3905            if (pWav->channels == 1) {
3906                /* Mono. */
3907                drwav_uint8 header[7];
3908                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
3909                    return totalFramesRead;
3910                }
3911                pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
3912
3913                pWav->msadpcm.predictor[0]     = header[0];
3914                pWav->msadpcm.delta[0]         = drwav__bytes_to_s16(header + 1);
3915                pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 3);
3916                pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 5);
3917                pWav->msadpcm.cachedFrames[2]  = pWav->msadpcm.prevFrames[0][0];
3918                pWav->msadpcm.cachedFrames[3]  = pWav->msadpcm.prevFrames[0][1];
3919                pWav->msadpcm.cachedFrameCount = 2;
3920            } else {
3921                /* Stereo. */
3922                drwav_uint8 header[14];
3923                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
3924                    return totalFramesRead;
3925                }
3926                pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
3927
3928                pWav->msadpcm.predictor[0] = header[0];
3929                pWav->msadpcm.predictor[1] = header[1];
3930                pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 2);
3931                pWav->msadpcm.delta[1] = drwav__bytes_to_s16(header + 4);
3932                pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 6);
3933                pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav__bytes_to_s16(header + 8);
3934                pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 10);
3935                pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav__bytes_to_s16(header + 12);
3936
3937                pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0];
3938                pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0];
3939                pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
3940                pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
3941                pWav->msadpcm.cachedFrameCount = 2;
3942            }
3943        }
3944
3945        /* Output anything that's cached. */
3946        while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
3947            if (pBufferOut != NULL) {
3948                drwav_uint32 iSample = 0;
3949                for (iSample = 0; iSample < pWav->channels; iSample += 1) {
3950                    pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample];
3951                }
3952
3953                pBufferOut += pWav->channels;
3954            }
3955
3956            framesToRead    -= 1;
3957            totalFramesRead += 1;
3958            pWav->compressed.iCurrentPCMFrame += 1;
3959            pWav->msadpcm.cachedFrameCount -= 1;
3960        }
3961
3962        if (framesToRead == 0) {
3963            return totalFramesRead;
3964        }
3965
3966
3967        /*
3968        If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next
3969        loop iteration which will trigger the loading of a new block.
3970        */
3971        if (pWav->msadpcm.cachedFrameCount == 0) {
3972            if (pWav->msadpcm.bytesRemainingInBlock == 0) {
3973                continue;
3974            } else {
3975                static drwav_int32 adaptationTable[] = { 
3976                    230, 230, 230, 230, 307, 409, 512, 614, 
3977                    768, 614, 512, 409, 307, 230, 230, 230 
3978                };
3979                static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460,  392 };
3980                static drwav_int32 coeff2Table[] = { 0,  -256, 0, 64,  0,  -208, -232 };
3981
3982                drwav_uint8 nibbles;
3983                drwav_int32 nibble0;
3984                drwav_int32 nibble1;
3985
3986                if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
3987                    return totalFramesRead;
3988                }
3989                pWav->msadpcm.bytesRemainingInBlock -= 1;
3990
3991                /* TODO: Optimize away these if statements. */
3992                nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; }
3993                nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; }
3994
3995                if (pWav->channels == 1) {
3996                    /* Mono. */
3997                    drwav_int32 newSample0;
3998                    drwav_int32 newSample1;
3999
4000                    newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
4001                    newSample0 += nibble0 * pWav->msadpcm.delta[0];
4002                    newSample0  = drwav_clamp(newSample0, -32768, 32767);
4003
4004                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
4005                    if (pWav->msadpcm.delta[0] < 16) {
4006                        pWav->msadpcm.delta[0] = 16;
4007                    }
4008
4009                    pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
4010                    pWav->msadpcm.prevFrames[0][1] = newSample0;
4011
4012
4013                    newSample1  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
4014                    newSample1 += nibble1 * pWav->msadpcm.delta[0];
4015                    newSample1  = drwav_clamp(newSample1, -32768, 32767);
4016
4017                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
4018                    if (pWav->msadpcm.delta[0] < 16) {
4019                        pWav->msadpcm.delta[0] = 16;
4020                    }
4021
4022                    pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
4023                    pWav->msadpcm.prevFrames[0][1] = newSample1;
4024
4025
4026                    pWav->msadpcm.cachedFrames[2] = newSample0;
4027                    pWav->msadpcm.cachedFrames[3] = newSample1;
4028                    pWav->msadpcm.cachedFrameCount = 2;
4029                } else {
4030                    /* Stereo. */
4031                    drwav_int32 newSample0;
4032                    drwav_int32 newSample1;
4033
4034                    /* Left. */
4035                    newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
4036                    newSample0 += nibble0 * pWav->msadpcm.delta[0];
4037                    newSample0  = drwav_clamp(newSample0, -32768, 32767);
4038
4039                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
4040                    if (pWav->msadpcm.delta[0] < 16) {
4041                        pWav->msadpcm.delta[0] = 16;
4042                    }
4043
4044                    pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
4045                    pWav->msadpcm.prevFrames[0][1] = newSample0;
4046
4047
4048                    /* Right. */
4049                    newSample1  = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
4050                    newSample1 += nibble1 * pWav->msadpcm.delta[1];
4051                    newSample1  = drwav_clamp(newSample1, -32768, 32767);
4052
4053                    pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
4054                    if (pWav->msadpcm.delta[1] < 16) {
4055                        pWav->msadpcm.delta[1] = 16;
4056                    }
4057
4058                    pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
4059                    pWav->msadpcm.prevFrames[1][1] = newSample1;
4060
4061                    pWav->msadpcm.cachedFrames[2] = newSample0;
4062                    pWav->msadpcm.cachedFrames[3] = newSample1;
4063                    pWav->msadpcm.cachedFrameCount = 1;
4064                }
4065            }
4066        }
4067    }
4068
4069    return totalFramesRead;
4070}
4071
4072
4073static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4074{
4075    drwav_uint64 totalFramesRead = 0;
4076    drwav_uint32 iChannel;
4077
4078    static drwav_int32 indexTable[16] = {
4079        -1, -1, -1, -1, 2, 4, 6, 8,
4080        -1, -1, -1, -1, 2, 4, 6, 8
4081    };
4082
4083    static drwav_int32 stepTable[89] = {
4084        7,     8,     9,     10,    11,    12,    13,    14,    16,    17, 
4085        19,    21,    23,    25,    28,    31,    34,    37,    41,    45, 
4086        50,    55,    60,    66,    73,    80,    88,    97,    107,   118, 
4087        130,   143,   157,   173,   190,   209,   230,   253,   279,   307,
4088        337,   371,   408,   449,   494,   544,   598,   658,   724,   796,
4089        876,   963,   1060,  1166,  1282,  1411,  1552,  1707,  1878,  2066, 
4090        2272,  2499,  2749,  3024,  3327,  3660,  4026,  4428,  4871,  5358,
4091        5894,  6484,  7132,  7845,  8630,  9493,  10442, 11487, 12635, 13899, 
4092        15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 
4093    };
4094
4095    DRWAV_ASSERT(pWav != NULL);
4096    DRWAV_ASSERT(framesToRead > 0);
4097
4098    /* TODO: Lots of room for optimization here. */
4099
4100    while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
4101        /* If there are no cached samples we need to load a new block. */
4102        if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) {
4103            if (pWav->channels == 1) {
4104                /* Mono. */
4105                drwav_uint8 header[4];
4106                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
4107                    return totalFramesRead;
4108                }
4109                pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
4110
4111                if (header[2] >= drwav_countof(stepTable)) {
4112                    pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
4113                    pWav->ima.bytesRemainingInBlock = 0;
4114                    return totalFramesRead; /* Invalid data. */
4115                }
4116
4117                pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0);
4118                pWav->ima.stepIndex[0] = header[2];
4119                pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0];
4120                pWav->ima.cachedFrameCount = 1;
4121            } else {
4122                /* Stereo. */
4123                drwav_uint8 header[8];
4124                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
4125                    return totalFramesRead;
4126                }
4127                pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
4128
4129                if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
4130                    pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
4131                    pWav->ima.bytesRemainingInBlock = 0;
4132                    return totalFramesRead; /* Invalid data. */
4133                }
4134
4135                pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0);
4136                pWav->ima.stepIndex[0] = header[2];
4137                pWav->ima.predictor[1] = drwav__bytes_to_s16(header + 4);
4138                pWav->ima.stepIndex[1] = header[6];
4139
4140                pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0];
4141                pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1];
4142                pWav->ima.cachedFrameCount = 1;
4143            }
4144        }
4145
4146        /* Output anything that's cached. */
4147        while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
4148            if (pBufferOut != NULL) {
4149                drwav_uint32 iSample;
4150                for (iSample = 0; iSample < pWav->channels; iSample += 1) {
4151                    pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample];
4152                }
4153                pBufferOut += pWav->channels;
4154            }
4155
4156            framesToRead    -= 1;
4157            totalFramesRead += 1;
4158            pWav->compressed.iCurrentPCMFrame += 1;
4159            pWav->ima.cachedFrameCount -= 1;
4160        }
4161
4162        if (framesToRead == 0) {
4163            return totalFramesRead;
4164        }
4165
4166        /*
4167        If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next
4168        loop iteration which will trigger the loading of a new block.
4169        */
4170        if (pWav->ima.cachedFrameCount == 0) {
4171            if (pWav->ima.bytesRemainingInBlock == 0) {
4172                continue;
4173            } else {
4174                /*
4175                From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the
4176                left channel, 4 bytes for the right channel.
4177                */
4178                pWav->ima.cachedFrameCount = 8;
4179                for (iChannel = 0; iChannel < pWav->channels; ++iChannel) {
4180                    drwav_uint32 iByte;
4181                    drwav_uint8 nibbles[4];
4182                    if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) {
4183                        pWav->ima.cachedFrameCount = 0;
4184                        return totalFramesRead;
4185                    }
4186                    pWav->ima.bytesRemainingInBlock -= 4;
4187
4188                    for (iByte = 0; iByte < 4; ++iByte) {
4189                        drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
4190                        drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
4191
4192                        drwav_int32 step      = stepTable[pWav->ima.stepIndex[iChannel]];
4193                        drwav_int32 predictor = pWav->ima.predictor[iChannel];
4194
4195                        drwav_int32      diff  = step >> 3;
4196                        if (nibble0 & 1) diff += step >> 2;
4197                        if (nibble0 & 2) diff += step >> 1;
4198                        if (nibble0 & 4) diff += step;
4199                        if (nibble0 & 8) diff  = -diff;
4200
4201                        predictor = drwav_clamp(predictor + diff, -32768, 32767);
4202                        pWav->ima.predictor[iChannel] = predictor;
4203                        pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1);
4204                        pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor;
4205
4206
4207                        step      = stepTable[pWav->ima.stepIndex[iChannel]];
4208                        predictor = pWav->ima.predictor[iChannel];
4209
4210                                         diff  = step >> 3;
4211                        if (nibble1 & 1) diff += step >> 2;
4212                        if (nibble1 & 2) diff += step >> 1;
4213                        if (nibble1 & 4) diff += step;
4214                        if (nibble1 & 8) diff  = -diff;
4215
4216                        predictor = drwav_clamp(predictor + diff, -32768, 32767);
4217                        pWav->ima.predictor[iChannel] = predictor;
4218                        pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1);
4219                        pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor;
4220                    }
4221                }
4222            }
4223        }
4224    }
4225
4226    return totalFramesRead;
4227}
4228
4229
4230#ifndef DR_WAV_NO_CONVERSION_API
4231static unsigned short g_drwavAlawTable[256] = {
4232    0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, 
4233    0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, 
4234    0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, 
4235    0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, 
4236    0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, 
4237    0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, 
4238    0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, 
4239    0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, 
4240    0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, 
4241    0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, 
4242    0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, 
4243    0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, 
4244    0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, 
4245    0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, 
4246    0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, 
4247    0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
4248};
4249
4250static unsigned short g_drwavMulawTable[256] = {
4251    0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, 
4252    0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, 
4253    0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, 
4254    0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, 
4255    0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, 
4256    0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, 
4257    0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, 
4258    0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, 
4259    0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, 
4260    0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, 
4261    0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, 
4262    0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, 
4263    0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, 
4264    0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, 
4265    0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, 
4266    0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
4267};
4268
4269static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
4270{
4271    return (short)g_drwavAlawTable[sampleIn];
4272}
4273
4274static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
4275{
4276    return (short)g_drwavMulawTable[sampleIn];
4277}
4278
4279
4280
4281static void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4282{
4283    unsigned int i;
4284
4285    /* Special case for 8-bit sample data because it's treated as unsigned. */
4286    if (bytesPerSample == 1) {
4287        drwav_u8_to_s16(pOut, pIn, totalSampleCount);
4288        return;
4289    }
4290
4291
4292    /* Slightly more optimal implementation for common formats. */
4293    if (bytesPerSample == 2) {
4294        for (i = 0; i < totalSampleCount; ++i) {
4295           *pOut++ = ((const drwav_int16*)pIn)[i];
4296        }
4297        return;
4298    }
4299    if (bytesPerSample == 3) {
4300        drwav_s24_to_s16(pOut, pIn, totalSampleCount);
4301        return;
4302    }
4303    if (bytesPerSample == 4) {
4304        drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
4305        return;
4306    }
4307
4308
4309    /* Anything more than 64 bits per sample is not supported. */
4310    if (bytesPerSample > 8) {
4311        DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
4312        return;
4313    }
4314
4315
4316    /* Generic, slow converter. */
4317    for (i = 0; i < totalSampleCount; ++i) {
4318        drwav_uint64 sample = 0;
4319        unsigned int shift  = (8 - bytesPerSample) * 8;
4320
4321        unsigned int j;
4322        for (j = 0; j < bytesPerSample; j += 1) {
4323            DRWAV_ASSERT(j < 8);
4324            sample |= (drwav_uint64)(pIn[j]) << shift;
4325            shift  += 8;
4326        }
4327
4328        pIn += j;
4329        *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
4330    }
4331}
4332
4333static void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4334{
4335    if (bytesPerSample == 4) {
4336        drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount);
4337        return;
4338    } else if (bytesPerSample == 8) {
4339        drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount);
4340        return;
4341    } else {
4342        /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
4343        DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
4344        return;
4345    }
4346}
4347
4348static drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4349{
4350    drwav_uint32 bytesPerFrame;
4351    drwav_uint64 totalFramesRead;
4352    drwav_uint8 sampleData[4096];
4353
4354    /* Fast path. */
4355    if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) {
4356        return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
4357    }
4358    
4359    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4360    if (bytesPerFrame == 0) {
4361        return 0;
4362    }
4363
4364    totalFramesRead = 0;
4365    
4366    while (framesToRead > 0) {
4367        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4368        if (framesRead == 0) {
4369            break;
4370        }
4371
4372        drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4373
4374        pBufferOut      += framesRead*pWav->channels;
4375        framesToRead    -= framesRead;
4376        totalFramesRead += framesRead;
4377    }
4378
4379    return totalFramesRead;
4380}
4381
4382static drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4383{
4384    drwav_uint64 totalFramesRead;
4385    drwav_uint8 sampleData[4096];
4386    drwav_uint32 bytesPerFrame;
4387
4388    if (pBufferOut == NULL) {
4389        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4390    }
4391
4392    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4393    if (bytesPerFrame == 0) {
4394        return 0;
4395    }
4396
4397    totalFramesRead = 0;
4398    
4399    while (framesToRead > 0) {
4400        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4401        if (framesRead == 0) {
4402            break;
4403        }
4404
4405        drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4406
4407        pBufferOut      += framesRead*pWav->channels;
4408        framesToRead    -= framesRead;
4409        totalFramesRead += framesRead;
4410    }
4411
4412    return totalFramesRead;
4413}
4414
4415static drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4416{
4417    drwav_uint64 totalFramesRead;
4418    drwav_uint8 sampleData[4096];
4419    drwav_uint32 bytesPerFrame;
4420
4421    if (pBufferOut == NULL) {
4422        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4423    }
4424
4425    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4426    if (bytesPerFrame == 0) {
4427        return 0;
4428    }
4429
4430    totalFramesRead = 0;
4431    
4432    while (framesToRead > 0) {
4433        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4434        if (framesRead == 0) {
4435            break;
4436        }
4437
4438        drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4439
4440        pBufferOut      += framesRead*pWav->channels;
4441        framesToRead    -= framesRead;
4442        totalFramesRead += framesRead;
4443    }
4444
4445    return totalFramesRead;
4446}
4447
4448static drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4449{
4450    drwav_uint64 totalFramesRead;
4451    drwav_uint8 sampleData[4096];
4452    drwav_uint32 bytesPerFrame;
4453
4454    if (pBufferOut == NULL) {
4455        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4456    }
4457
4458    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4459    if (bytesPerFrame == 0) {
4460        return 0;
4461    }
4462
4463    totalFramesRead = 0;
4464
4465    while (framesToRead > 0) {
4466        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4467        if (framesRead == 0) {
4468            break;
4469        }
4470
4471        drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4472
4473        pBufferOut      += framesRead*pWav->channels;
4474        framesToRead    -= framesRead;
4475        totalFramesRead += framesRead;
4476    }
4477
4478    return totalFramesRead;
4479}
4480
4481DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4482{
4483    if (pWav == NULL || framesToRead == 0) {
4484        return 0;
4485    }
4486
4487    if (pBufferOut == NULL) {
4488        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4489    }
4490
4491    /* Don't try to read more samples than can potentially fit in the output buffer. */
4492    if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) {
4493        framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels;
4494    }
4495
4496    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
4497        return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut);
4498    }
4499
4500    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
4501        return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut);
4502    }
4503
4504    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
4505        return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut);
4506    }
4507
4508    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
4509        return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut);
4510    }
4511
4512    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
4513        return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut);
4514    }
4515
4516    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
4517        return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut);
4518    }
4519
4520    return 0;
4521}
4522
4523DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4524{
4525    drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
4526    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
4527        drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
4528    }
4529
4530    return framesRead;
4531}
4532
4533DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4534{
4535    drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
4536    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
4537        drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
4538    }
4539
4540    return framesRead;
4541}
4542
4543
4544DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4545{
4546    int r;
4547    size_t i;
4548    for (i = 0; i < sampleCount; ++i) {
4549        int x = pIn[i];
4550        r = x << 8;
4551        r = r - 32768;
4552        pOut[i] = (short)r;
4553    }
4554}
4555
4556DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4557{
4558    int r;
4559    size_t i;
4560    for (i = 0; i < sampleCount; ++i) {
4561        int x = ((int)(((unsigned int)(((const drwav_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+2])) << 24)) >> 8;
4562        r = x >> 8;
4563        pOut[i] = (short)r;
4564    }
4565}
4566
4567DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
4568{
4569    int r;
4570    size_t i;
4571    for (i = 0; i < sampleCount; ++i) {
4572        int x = pIn[i];
4573        r = x >> 16;
4574        pOut[i] = (short)r;
4575    }
4576}
4577
4578DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
4579{
4580    int r;
4581    size_t i;
4582    for (i = 0; i < sampleCount; ++i) {
4583        float x = pIn[i];
4584        float c;
4585        c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
4586        c = c + 1;
4587        r = (int)(c * 32767.5f);
4588        r = r - 32768;
4589        pOut[i] = (short)r;
4590    }
4591}
4592
4593DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
4594{
4595    int r;
4596    size_t i;
4597    for (i = 0; i < sampleCount; ++i) {
4598        double x = pIn[i];
4599        double c;
4600        c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
4601        c = c + 1;
4602        r = (int)(c * 32767.5);
4603        r = r - 32768;
4604        pOut[i] = (short)r;
4605    }
4606}
4607
4608DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4609{
4610    size_t i;
4611    for (i = 0; i < sampleCount; ++i) {
4612        pOut[i] = drwav__alaw_to_s16(pIn[i]);
4613    }
4614}
4615
4616DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4617{
4618    size_t i;
4619    for (i = 0; i < sampleCount; ++i) {
4620        pOut[i] = drwav__mulaw_to_s16(pIn[i]);
4621    }
4622}
4623
4624
4625
4626static void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
4627{
4628    unsigned int i;
4629
4630    /* Special case for 8-bit sample data because it's treated as unsigned. */
4631    if (bytesPerSample == 1) {
4632        drwav_u8_to_f32(pOut, pIn, sampleCount);
4633        return;
4634    }
4635
4636    /* Slightly more optimal implementation for common formats. */
4637    if (bytesPerSample == 2) {
4638        drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount);
4639        return;
4640    }
4641    if (bytesPerSample == 3) {
4642        drwav_s24_to_f32(pOut, pIn, sampleCount);
4643        return;
4644    }
4645    if (bytesPerSample == 4) {
4646        drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
4647        return;
4648    }
4649
4650
4651    /* Anything more than 64 bits per sample is not supported. */
4652    if (bytesPerSample > 8) {
4653        DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
4654        return;
4655    }
4656
4657
4658    /* Generic, slow converter. */
4659    for (i = 0; i < sampleCount; ++i) {
4660        drwav_uint64 sample = 0;
4661        unsigned int shift  = (8 - bytesPerSample) * 8;
4662
4663        unsigned int j;
4664        for (j = 0; j < bytesPerSample; j += 1) {
4665            DRWAV_ASSERT(j < 8);
4666            sample |= (drwav_uint64)(pIn[j]) << shift;
4667            shift  += 8;
4668        }
4669
4670        pIn += j;
4671        *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
4672    }
4673}
4674
4675static void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
4676{
4677    if (bytesPerSample == 4) {
4678        unsigned int i;
4679        for (i = 0; i < sampleCount; ++i) {
4680            *pOut++ = ((const float*)pIn)[i];
4681        }
4682        return;
4683    } else if (bytesPerSample == 8) {
4684        drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount);
4685        return;
4686    } else {
4687        /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
4688        DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
4689        return;
4690    }
4691}
4692
4693
4694static drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4695{
4696    drwav_uint64 totalFramesRead;
4697    drwav_uint8 sampleData[4096];
4698
4699    drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4700    if (bytesPerFrame == 0) {
4701        return 0;
4702    }
4703
4704    totalFramesRead = 0;
4705
4706    while (framesToRead > 0) {
4707        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4708        if (framesRead == 0) {
4709            break;
4710        }
4711
4712        drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels);
4713
4714        pBufferOut      += framesRead*pWav->channels;
4715        framesToRead    -= framesRead;
4716        totalFramesRead += framesRead;
4717    }
4718
4719    return totalFramesRead;
4720}
4721
4722static drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4723{
4724    /*
4725    We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't
4726    want to duplicate that code.
4727    */
4728    drwav_uint64 totalFramesRead = 0;
4729    drwav_int16 samples16[2048];
4730    while (framesToRead > 0) {
4731        drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
4732        if (framesRead == 0) {
4733            break;
4734        }
4735
4736        drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));   /* <-- Safe cast because we're clamping to 2048. */
4737
4738        pBufferOut      += framesRead*pWav->channels;
4739        framesToRead    -= framesRead;
4740        totalFramesRead += framesRead;
4741    }
4742
4743    return totalFramesRead;
4744}
4745
4746static drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4747{
4748    /*
4749    We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't
4750    want to duplicate that code.
4751    */
4752    drwav_uint64 totalFramesRead = 0;
4753    drwav_int16 samples16[2048];
4754    while (framesToRead > 0) {
4755        drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
4756        if (framesRead == 0) {
4757            break;
4758        }
4759
4760        drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));   /* <-- Safe cast because we're clamping to 2048. */
4761
4762        pBufferOut      += framesRead*pWav->channels;
4763        framesToRead    -= framesRead;
4764        totalFramesRead += framesRead;
4765    }
4766
4767    return totalFramesRead;
4768}
4769
4770static drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4771{
4772    drwav_uint64 totalFramesRead;
4773    drwav_uint8 sampleData[4096];
4774    drwav_uint32 bytesPerFrame;
4775
4776    /* Fast path. */
4777    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) {
4778        return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
4779    }
4780    
4781    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4782    if (bytesPerFrame == 0) {
4783        return 0;
4784    }
4785
4786    totalFramesRead = 0;
4787
4788    while (framesToRead > 0) {
4789        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4790        if (framesRead == 0) {
4791            break;
4792        }
4793
4794        drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4795
4796        pBufferOut      += framesRead*pWav->channels;
4797        framesToRead    -= framesRead;
4798        totalFramesRead += framesRead;
4799    }
4800
4801    return totalFramesRead;
4802}
4803
4804static drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4805{
4806    drwav_uint64 totalFramesRead;
4807    drwav_uint8 sampleData[4096];
4808    drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4809    if (bytesPerFrame == 0) {
4810        return 0;
4811    }
4812
4813    totalFramesRead = 0;
4814
4815    while (framesToRead > 0) {
4816        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4817        if (framesRead == 0) {
4818            break;
4819        }
4820
4821        drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4822
4823        pBufferOut      += framesRead*pWav->channels;
4824        framesToRead    -= framesRead;
4825        totalFramesRead += framesRead;
4826    }
4827
4828    return totalFramesRead;
4829}
4830
4831static drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4832{
4833    drwav_uint64 totalFramesRead;
4834    drwav_uint8 sampleData[4096];
4835
4836    drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4837    if (bytesPerFrame == 0) {
4838        return 0;
4839    }
4840
4841    totalFramesRead = 0;
4842
4843    while (framesToRead > 0) {
4844        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4845        if (framesRead == 0) {
4846            break;
4847        }
4848
4849        drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4850
4851        pBufferOut      += framesRead*pWav->channels;
4852        framesToRead    -= framesRead;
4853        totalFramesRead += framesRead;
4854    }
4855
4856    return totalFramesRead;
4857}
4858
4859DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4860{
4861    if (pWav == NULL || framesToRead == 0) {
4862        return 0;
4863    }
4864
4865    if (pBufferOut == NULL) {
4866        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4867    }
4868
4869    /* Don't try to read more samples than can potentially fit in the output buffer. */
4870    if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) {
4871        framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels;
4872    }
4873
4874    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
4875        return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut);
4876    }
4877
4878    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
4879        return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut);
4880    }
4881
4882    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
4883        return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut);
4884    }
4885
4886    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
4887        return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut);
4888    }
4889
4890    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
4891        return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut);
4892    }
4893
4894    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
4895        return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut);
4896    }
4897
4898    return 0;
4899}
4900
4901DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4902{
4903    drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
4904    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
4905        drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
4906    }
4907
4908    return framesRead;
4909}
4910
4911DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4912{
4913    drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
4914    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
4915        drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
4916    }
4917
4918    return framesRead;
4919}
4920
4921
4922DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4923{
4924    size_t i;
4925
4926    if (pOut == NULL || pIn == NULL) {
4927        return;
4928    }
4929
4930#ifdef DR_WAV_LIBSNDFILE_COMPAT
4931    /*
4932    It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears
4933    libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note
4934    the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated
4935    correctness testing. This is disabled by default.
4936    */
4937    for (i = 0; i < sampleCount; ++i) {
4938        *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
4939    }
4940#else
4941    for (i = 0; i < sampleCount; ++i) {
4942        float x = pIn[i];
4943        x = x * 0.00784313725490196078f;    /* 0..255 to 0..2 */
4944        x = x - 1;                          /* 0..2 to -1..1 */
4945
4946        *pOut++ = x;
4947    }
4948#endif
4949}
4950
4951DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
4952{
4953    size_t i;
4954
4955    if (pOut == NULL || pIn == NULL) {
4956        return;
4957    }
4958
4959    for (i = 0; i < sampleCount; ++i) {
4960        *pOut++ = pIn[i] * 0.000030517578125f;
4961    }
4962}
4963
4964DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4965{
4966    size_t i;
4967
4968    if (pOut == NULL || pIn == NULL) {
4969        return;
4970    }
4971
4972    for (i = 0; i < sampleCount; ++i) {
4973        double x;
4974        drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) <<  8);
4975        drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16);
4976        drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24);
4977
4978        x = (double)((drwav_int32)(a | b | c) >> 8);
4979        *pOut++ = (float)(x * 0.00000011920928955078125);
4980    }
4981}
4982
4983DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
4984{
4985    size_t i;
4986    if (pOut == NULL || pIn == NULL) {
4987        return;
4988    }
4989
4990    for (i = 0; i < sampleCount; ++i) {
4991        *pOut++ = (float)(pIn[i] / 2147483648.0);
4992    }
4993}
4994
4995DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
4996{
4997    size_t i;
4998
4999    if (pOut == NULL || pIn == NULL) {
5000        return;
5001    }
5002
5003    for (i = 0; i < sampleCount; ++i) {
5004        *pOut++ = (float)pIn[i];
5005    }
5006}
5007
5008DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
5009{
5010    size_t i;
5011
5012    if (pOut == NULL || pIn == NULL) {
5013        return;
5014    }
5015
5016    for (i = 0; i < sampleCount; ++i) {
5017        *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
5018    }
5019}
5020
5021DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
5022{
5023    size_t i;
5024
5025    if (pOut == NULL || pIn == NULL) {
5026        return;
5027    }
5028
5029    for (i = 0; i < sampleCount; ++i) {
5030        *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
5031    }
5032}
5033
5034
5035
5036static void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
5037{
5038    unsigned int i;
5039
5040    /* Special case for 8-bit sample data because it's treated as unsigned. */
5041    if (bytesPerSample == 1) {
5042        drwav_u8_to_s32(pOut, pIn, totalSampleCount);
5043        return;
5044    }
5045
5046    /* Slightly more optimal implementation for common formats. */
5047    if (bytesPerSample == 2) {
5048        drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount);
5049        return;
5050    }
5051    if (bytesPerSample == 3) {
5052        drwav_s24_to_s32(pOut, pIn, totalSampleCount);
5053        return;
5054    }
5055    if (bytesPerSample == 4) {
5056        for (i = 0; i < totalSampleCount; ++i) {
5057           *pOut++ = ((const drwav_int32*)pIn)[i];
5058        }
5059        return;
5060    }
5061
5062
5063    /* Anything more than 64 bits per sample is not supported. */
5064    if (bytesPerSample > 8) {
5065        DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
5066        return;
5067    }
5068
5069
5070    /* Generic, slow converter. */
5071    for (i = 0; i < totalSampleCount; ++i) {
5072        drwav_uint64 sample = 0;
5073        unsigned int shift  = (8 - bytesPerSample) * 8;
5074
5075        unsigned int j;
5076        for (j = 0; j < bytesPerSample; j += 1) {
5077            DRWAV_ASSERT(j < 8);
5078            sample |= (drwav_uint64)(pIn[j]) << shift;
5079            shift  += 8;
5080        }
5081
5082        pIn += j;
5083        *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
5084    }
5085}
5086
5087static void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
5088{
5089    if (bytesPerSample == 4) {
5090        drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount);
5091        return;
5092    } else if (bytesPerSample == 8) {
5093        drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount);
5094        return;
5095    } else {
5096        /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
5097        DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
5098        return;
5099    }
5100}
5101
5102
5103static drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5104{
5105    drwav_uint64 totalFramesRead;
5106    drwav_uint8 sampleData[4096];
5107    drwav_uint32 bytesPerFrame;
5108
5109    /* Fast path. */
5110    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) {
5111        return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
5112    }
5113    
5114    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5115    if (bytesPerFrame == 0) {
5116        return 0;
5117    }
5118
5119    totalFramesRead = 0;
5120
5121    while (framesToRead > 0) {
5122        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
5123        if (framesRead == 0) {
5124            break;
5125        }
5126
5127        drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
5128
5129        pBufferOut      += framesRead*pWav->channels;
5130        framesToRead    -= framesRead;
5131        totalFramesRead += framesRead;
5132    }
5133
5134    return totalFramesRead;
5135}
5136
5137static drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5138{
5139    /*
5140    We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't
5141    want to duplicate that code.
5142    */
5143    drwav_uint64 totalFramesRead = 0;
5144    drwav_int16 samples16[2048];
5145    while (framesToRead > 0) {
5146        drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
5147        if (framesRead == 0) {
5148            break;
5149        }
5150
5151        drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));   /* <-- Safe cast because we're clamping to 2048. */
5152
5153        pBufferOut      += framesRead*pWav->channels;
5154        framesToRead    -= framesRead;
5155        totalFramesRead += framesRead;
5156    }
5157
5158    return totalFramesRead;
5159}
5160
5161static drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5162{
5163    /*
5164    We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't
5165    want to duplicate that code.
5166    */
5167    drwav_uint64 totalFramesRead = 0;
5168    drwav_int16 samples16[2048];
5169    while (framesToRead > 0) {
5170        drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
5171        if (framesRead == 0) {
5172            break;
5173        }
5174
5175        drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));   /* <-- Safe cast because we're clamping to 2048. */
5176
5177        pBufferOut      += framesRead*pWav->channels;
5178        framesToRead    -= framesRead;
5179        totalFramesRead += framesRead;
5180    }
5181
5182    return totalFramesRead;
5183}
5184
5185static drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5186{
5187    drwav_uint64 totalFramesRead;
5188    drwav_uint8 sampleData[4096];
5189
5190    drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5191    if (bytesPerFrame == 0) {
5192        return 0;
5193    }
5194
5195    totalFramesRead = 0;
5196
5197    while (framesToRead > 0) {
5198        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
5199        if (framesRead == 0) {
5200            break;
5201        }
5202
5203        drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
5204
5205        pBufferOut      += framesRead*pWav->channels;
5206        framesToRead    -= framesRead;
5207        totalFramesRead += framesRead;
5208    }
5209
5210    return totalFramesRead;
5211}
5212
5213static drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5214{
5215    drwav_uint64 totalFramesRead;
5216    drwav_uint8 sampleData[4096];
5217
5218    drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5219    if (bytesPerFrame == 0) {
5220        return 0;
5221    }
5222
5223    totalFramesRead = 0;
5224
5225    while (framesToRead > 0) {
5226        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
5227        if (framesRead == 0) {
5228            break;
5229        }
5230
5231        drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
5232
5233        pBufferOut      += framesRead*pWav->channels;
5234        framesToRead    -= framesRead;
5235        totalFramesRead += framesRead;
5236    }
5237
5238    return totalFramesRead;
5239}
5240
5241static drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5242{
5243    drwav_uint64 totalFramesRead;
5244    drwav_uint8 sampleData[4096];
5245
5246    drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5247    if (bytesPerFrame == 0) {
5248        return 0;
5249    }
5250
5251    totalFramesRead = 0;
5252
5253    while (framesToRead > 0) {
5254        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
5255        if (framesRead == 0) {
5256            break;
5257        }
5258
5259        drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
5260
5261        pBufferOut      += framesRead*pWav->channels;
5262        framesToRead    -= framesRead;
5263        totalFramesRead += framesRead;
5264    }
5265
5266    return totalFramesRead;
5267}
5268
5269DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5270{
5271    if (pWav == NULL || framesToRead == 0) {
5272        return 0;
5273    }
5274
5275    if (pBufferOut == NULL) {
5276        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
5277    }
5278
5279    /* Don't try to read more samples than can potentially fit in the output buffer. */
5280    if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) {
5281        framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels;
5282    }
5283
5284    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
5285        return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut);
5286    }
5287
5288    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
5289        return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut);
5290    }
5291
5292    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
5293        return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut);
5294    }
5295
5296    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
5297        return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut);
5298    }
5299
5300    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
5301        return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut);
5302    }
5303
5304    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
5305        return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut);
5306    }
5307
5308    return 0;
5309}
5310
5311DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5312{
5313    drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
5314    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
5315        drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
5316    }
5317
5318    return framesRead;
5319}
5320
5321DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5322{
5323    drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
5324    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
5325        drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
5326    }
5327
5328    return framesRead;
5329}
5330
5331
5332DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5333{
5334    size_t i;
5335
5336    if (pOut == NULL || pIn == NULL) {
5337        return;
5338    }
5339
5340    for (i = 0; i < sampleCount; ++i) {
5341        *pOut++ = ((int)pIn[i] - 128) << 24;
5342    }
5343}
5344
5345DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
5346{
5347    size_t i;
5348
5349    if (pOut == NULL || pIn == NULL) {
5350        return;
5351    }
5352
5353    for (i = 0; i < sampleCount; ++i) {
5354        *pOut++ = pIn[i] << 16;
5355    }
5356}
5357
5358DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5359{
5360    size_t i;
5361
5362    if (pOut == NULL || pIn == NULL) {
5363        return;
5364    }
5365
5366    for (i = 0; i < sampleCount; ++i) {
5367        unsigned int s0 = pIn[i*3 + 0];
5368        unsigned int s1 = pIn[i*3 + 1];
5369        unsigned int s2 = pIn[i*3 + 2];
5370
5371        drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
5372        *pOut++ = sample32;
5373    }
5374}
5375
5376DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
5377{
5378    size_t i;
5379
5380    if (pOut == NULL || pIn == NULL) {
5381        return;
5382    }
5383
5384    for (i = 0; i < sampleCount; ++i) {
5385        *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
5386    }
5387}
5388
5389DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
5390{
5391    size_t i;
5392
5393    if (pOut == NULL || pIn == NULL) {
5394        return;
5395    }
5396
5397    for (i = 0; i < sampleCount; ++i) {
5398        *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
5399    }
5400}
5401
5402DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5403{
5404    size_t i;
5405
5406    if (pOut == NULL || pIn == NULL) {
5407        return;
5408    }
5409
5410    for (i = 0; i < sampleCount; ++i) {
5411        *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
5412    }
5413}
5414
5415DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5416{
5417    size_t i;
5418
5419    if (pOut == NULL || pIn == NULL) {
5420        return;
5421    }
5422
5423    for (i= 0; i < sampleCount; ++i) {
5424        *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
5425    }
5426}
5427
5428
5429
5430static drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5431{
5432    drwav_uint64 sampleDataSize;
5433    drwav_int16* pSampleData;
5434    drwav_uint64 framesRead;
5435
5436    DRWAV_ASSERT(pWav != NULL);
5437
5438    sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
5439    if (sampleDataSize > DRWAV_SIZE_MAX) {
5440        drwav_uninit(pWav);
5441        return NULL;    /* File's too big. */
5442    }
5443
5444    pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5445    if (pSampleData == NULL) {
5446        drwav_uninit(pWav);
5447        return NULL;    /* Failed to allocate memory. */
5448    }
5449
5450    framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5451    if (framesRead != pWav->totalPCMFrameCount) {
5452        drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5453        drwav_uninit(pWav);
5454        return NULL;    /* There was an error reading the samples. */
5455    }
5456
5457    drwav_uninit(pWav);
5458
5459    if (sampleRate) {
5460        *sampleRate = pWav->sampleRate;
5461    }
5462    if (channels) {
5463        *channels = pWav->channels;
5464    }
5465    if (totalFrameCount) {
5466        *totalFrameCount = pWav->totalPCMFrameCount;
5467    }
5468
5469    return pSampleData;
5470}
5471
5472static float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5473{
5474    drwav_uint64 sampleDataSize;
5475    float* pSampleData;
5476    drwav_uint64 framesRead;
5477
5478    DRWAV_ASSERT(pWav != NULL);
5479
5480    sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
5481    if (sampleDataSize > DRWAV_SIZE_MAX) {
5482        drwav_uninit(pWav);
5483        return NULL;    /* File's too big. */
5484    }
5485
5486    pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5487    if (pSampleData == NULL) {
5488        drwav_uninit(pWav);
5489        return NULL;    /* Failed to allocate memory. */
5490    }
5491
5492    framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5493    if (framesRead != pWav->totalPCMFrameCount) {
5494        drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5495        drwav_uninit(pWav);
5496        return NULL;    /* There was an error reading the samples. */
5497    }
5498
5499    drwav_uninit(pWav);
5500
5501    if (sampleRate) {
5502        *sampleRate = pWav->sampleRate;
5503    }
5504    if (channels) {
5505        *channels = pWav->channels;
5506    }
5507    if (totalFrameCount) {
5508        *totalFrameCount = pWav->totalPCMFrameCount;
5509    }
5510
5511    return pSampleData;
5512}
5513
5514static drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5515{
5516    drwav_uint64 sampleDataSize;
5517    drwav_int32* pSampleData;
5518    drwav_uint64 framesRead;
5519
5520    DRWAV_ASSERT(pWav != NULL);
5521
5522    sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
5523    if (sampleDataSize > DRWAV_SIZE_MAX) {
5524        drwav_uninit(pWav);
5525        return NULL;    /* File's too big. */
5526    }
5527
5528    pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5529    if (pSampleData == NULL) {
5530        drwav_uninit(pWav);
5531        return NULL;    /* Failed to allocate memory. */
5532    }
5533
5534    framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5535    if (framesRead != pWav->totalPCMFrameCount) {
5536        drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5537        drwav_uninit(pWav);
5538        return NULL;    /* There was an error reading the samples. */
5539    }
5540
5541    drwav_uninit(pWav);
5542
5543    if (sampleRate) {
5544        *sampleRate = pWav->sampleRate;
5545    }
5546    if (channels) {
5547        *channels = pWav->channels;
5548    }
5549    if (totalFrameCount) {
5550        *totalFrameCount = pWav->totalPCMFrameCount;
5551    }
5552
5553    return pSampleData;
5554}
5555
5556
5557
5558DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5559{
5560    drwav wav;
5561
5562    if (channelsOut) {
5563        *channelsOut = 0;
5564    }
5565    if (sampleRateOut) {
5566        *sampleRateOut = 0;
5567    }
5568    if (totalFrameCountOut) {
5569        *totalFrameCountOut = 0;
5570    }
5571
5572    if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5573        return NULL;
5574    }
5575
5576    return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5577}
5578
5579DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5580{
5581    drwav wav;
5582
5583    if (channelsOut) {
5584        *channelsOut = 0;
5585    }
5586    if (sampleRateOut) {
5587        *sampleRateOut = 0;
5588    }
5589    if (totalFrameCountOut) {
5590        *totalFrameCountOut = 0;
5591    }
5592
5593    if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5594        return NULL;
5595    }
5596
5597    return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5598}
5599
5600DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5601{
5602    drwav wav;
5603
5604    if (channelsOut) {
5605        *channelsOut = 0;
5606    }
5607    if (sampleRateOut) {
5608        *sampleRateOut = 0;
5609    }
5610    if (totalFrameCountOut) {
5611        *totalFrameCountOut = 0;
5612    }
5613
5614    if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5615        return NULL;
5616    }
5617
5618    return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5619}
5620
5621#ifndef DR_WAV_NO_STDIO
5622DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5623{
5624    drwav wav;
5625
5626    if (channelsOut) {
5627        *channelsOut = 0;
5628    }
5629    if (sampleRateOut) {
5630        *sampleRateOut = 0;
5631    }
5632    if (totalFrameCountOut) {
5633        *totalFrameCountOut = 0;
5634    }
5635
5636    if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5637        return NULL;
5638    }
5639
5640    return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5641}
5642
5643DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5644{
5645    drwav wav;
5646
5647    if (channelsOut) {
5648        *channelsOut = 0;
5649    }
5650    if (sampleRateOut) {
5651        *sampleRateOut = 0;
5652    }
5653    if (totalFrameCountOut) {
5654        *totalFrameCountOut = 0;
5655    }
5656
5657    if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5658        return NULL;
5659    }
5660
5661    return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5662}
5663
5664DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5665{
5666    drwav wav;
5667
5668    if (channelsOut) {
5669        *channelsOut = 0;
5670    }
5671    if (sampleRateOut) {
5672        *sampleRateOut = 0;
5673    }
5674    if (totalFrameCountOut) {
5675        *totalFrameCountOut = 0;
5676    }
5677
5678    if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5679        return NULL;
5680    }
5681
5682    return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5683}
5684
5685
5686DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5687{
5688    drwav wav;
5689
5690    if (sampleRateOut) {
5691        *sampleRateOut = 0;
5692    }
5693    if (channelsOut) {
5694        *channelsOut = 0;
5695    }
5696    if (totalFrameCountOut) {
5697        *totalFrameCountOut = 0;
5698    }
5699
5700    if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5701        return NULL;
5702    }
5703
5704    return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5705}
5706
5707DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5708{
5709    drwav wav;
5710
5711    if (sampleRateOut) {
5712        *sampleRateOut = 0;
5713    }
5714    if (channelsOut) {
5715        *channelsOut = 0;
5716    }
5717    if (totalFrameCountOut) {
5718        *totalFrameCountOut = 0;
5719    }
5720
5721    if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5722        return NULL;
5723    }
5724
5725    return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5726}
5727
5728DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5729{
5730    drwav wav;
5731
5732    if (sampleRateOut) {
5733        *sampleRateOut = 0;
5734    }
5735    if (channelsOut) {
5736        *channelsOut = 0;
5737    }
5738    if (totalFrameCountOut) {
5739        *totalFrameCountOut = 0;
5740    }
5741
5742    if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5743        return NULL;
5744    }
5745
5746    return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5747}
5748#endif
5749
5750DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5751{
5752    drwav wav;
5753
5754    if (channelsOut) {
5755        *channelsOut = 0;
5756    }
5757    if (sampleRateOut) {
5758        *sampleRateOut = 0;
5759    }
5760    if (totalFrameCountOut) {
5761        *totalFrameCountOut = 0;
5762    }
5763
5764    if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5765        return NULL;
5766    }
5767
5768    return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5769}
5770
5771DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5772{
5773    drwav wav;
5774
5775    if (channelsOut) {
5776        *channelsOut = 0;
5777    }
5778    if (sampleRateOut) {
5779        *sampleRateOut = 0;
5780    }
5781    if (totalFrameCountOut) {
5782        *totalFrameCountOut = 0;
5783    }
5784
5785    if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5786        return NULL;
5787    }
5788
5789    return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5790}
5791
5792DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
5793{
5794    drwav wav;
5795
5796    if (channelsOut) {
5797        *channelsOut = 0;
5798    }
5799    if (sampleRateOut) {
5800        *sampleRateOut = 0;
5801    }
5802    if (totalFrameCountOut) {
5803        *totalFrameCountOut = 0;
5804    }
5805
5806    if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5807        return NULL;
5808    }
5809
5810    return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5811}
5812#endif  /* DR_WAV_NO_CONVERSION_API */
5813
5814
5815DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
5816{
5817    if (pAllocationCallbacks != NULL) {
5818        drwav__free_from_callbacks(p, pAllocationCallbacks);
5819    } else {
5820        drwav__free_default(p, NULL);
5821    }
5822}
5823
5824DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data)
5825{
5826    return drwav__bytes_to_u16(data);
5827}
5828
5829DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data)
5830{
5831    return drwav__bytes_to_s16(data);
5832}
5833
5834DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data)
5835{
5836    return drwav__bytes_to_u32(data);
5837}
5838
5839DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data)
5840{
5841    return drwav__bytes_to_s32(data);
5842}
5843
5844DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data)
5845{
5846    return drwav__bytes_to_u64(data);
5847}
5848
5849DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data)
5850{
5851    return drwav__bytes_to_s64(data);
5852}
5853
5854
5855DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
5856{
5857    return drwav__guid_equal(a, b);
5858}
5859
5860DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
5861{
5862    return drwav__fourcc_equal(a, b);
5863}
5864
5865#endif  /* dr_wav_c */
5866#endif  /* DR_WAV_IMPLEMENTATION */
5867
5868/*
5869RELEASE NOTES - v0.11.0
5870=======================
5871Version 0.11.0 has breaking API changes.
5872
5873Improved Client-Defined Memory Allocation
5874-----------------------------------------
5875The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
5876existing system of DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE are still in place and will be used by default when no custom
5877allocation callbacks are specified.
5878
5879To use the new system, you pass in a pointer to a drwav_allocation_callbacks object to drwav_init() and family, like this:
5880
5881    void* my_malloc(size_t sz, void* pUserData)
5882    {
5883        return malloc(sz);
5884    }
5885    void* my_realloc(void* p, size_t sz, void* pUserData)
5886    {
5887        return realloc(p, sz);
5888    }
5889    void my_free(void* p, void* pUserData)
5890    {
5891        free(p);
5892    }
5893
5894    ...
5895
5896    drwav_allocation_callbacks allocationCallbacks;
5897    allocationCallbacks.pUserData = &myData;
5898    allocationCallbacks.onMalloc  = my_malloc;
5899    allocationCallbacks.onRealloc = my_realloc;
5900    allocationCallbacks.onFree    = my_free;
5901    drwav_init_file(&wav, "my_file.wav", &allocationCallbacks);
5902
5903The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
5904
5905Passing in null for the allocation callbacks object will cause dr_wav to use defaults which is the same as DRWAV_MALLOC,
5906DRWAV_REALLOC and DRWAV_FREE and the equivalent of how it worked in previous versions.
5907
5908Every API that opens a drwav object now takes this extra parameter. These include the following:
5909
5910    drwav_init()
5911    drwav_init_ex()
5912    drwav_init_file()
5913    drwav_init_file_ex()
5914    drwav_init_file_w()
5915    drwav_init_file_w_ex()
5916    drwav_init_memory()
5917    drwav_init_memory_ex()
5918    drwav_init_write()
5919    drwav_init_write_sequential()
5920    drwav_init_write_sequential_pcm_frames()
5921    drwav_init_file_write()
5922    drwav_init_file_write_sequential()
5923    drwav_init_file_write_sequential_pcm_frames()
5924    drwav_init_file_write_w()
5925    drwav_init_file_write_sequential_w()
5926    drwav_init_file_write_sequential_pcm_frames_w()
5927    drwav_init_memory_write()
5928    drwav_init_memory_write_sequential()
5929    drwav_init_memory_write_sequential_pcm_frames()
5930    drwav_open_and_read_pcm_frames_s16()
5931    drwav_open_and_read_pcm_frames_f32()
5932    drwav_open_and_read_pcm_frames_s32()
5933    drwav_open_file_and_read_pcm_frames_s16()
5934    drwav_open_file_and_read_pcm_frames_f32()
5935    drwav_open_file_and_read_pcm_frames_s32()
5936    drwav_open_file_and_read_pcm_frames_s16_w()
5937    drwav_open_file_and_read_pcm_frames_f32_w()
5938    drwav_open_file_and_read_pcm_frames_s32_w()
5939    drwav_open_memory_and_read_pcm_frames_s16()
5940    drwav_open_memory_and_read_pcm_frames_f32()
5941    drwav_open_memory_and_read_pcm_frames_s32()
5942
5943Endian Improvements
5944-------------------
5945Previously, the following APIs returned little-endian audio data. These now return native-endian data. This improves compatibility
5946on big-endian architectures.
5947
5948    drwav_read_pcm_frames()
5949    drwav_read_pcm_frames_s16()
5950    drwav_read_pcm_frames_s32()
5951    drwav_read_pcm_frames_f32()
5952    drwav_open_and_read_pcm_frames_s16()
5953    drwav_open_and_read_pcm_frames_s32()
5954    drwav_open_and_read_pcm_frames_f32()
5955    drwav_open_file_and_read_pcm_frames_s16()
5956    drwav_open_file_and_read_pcm_frames_s32()
5957    drwav_open_file_and_read_pcm_frames_f32()
5958    drwav_open_file_and_read_pcm_frames_s16_w()
5959    drwav_open_file_and_read_pcm_frames_s32_w()
5960    drwav_open_file_and_read_pcm_frames_f32_w()
5961    drwav_open_memory_and_read_pcm_frames_s16()
5962    drwav_open_memory_and_read_pcm_frames_s32()
5963    drwav_open_memory_and_read_pcm_frames_f32()
5964
5965APIs have been added to give you explicit control over whether or not audio data is read or written in big- or little-endian byte
5966order:
5967
5968    drwav_read_pcm_frames_le()
5969    drwav_read_pcm_frames_be()
5970    drwav_read_pcm_frames_s16le()
5971    drwav_read_pcm_frames_s16be()
5972    drwav_read_pcm_frames_f32le()
5973    drwav_read_pcm_frames_f32be()
5974    drwav_read_pcm_frames_s32le()
5975    drwav_read_pcm_frames_s32be()
5976    drwav_write_pcm_frames_le()
5977    drwav_write_pcm_frames_be()
5978
5979Removed APIs
5980------------
5981The following APIs were deprecated in version 0.10.0 and have now been removed:
5982
5983    drwav_open()
5984    drwav_open_ex()
5985    drwav_open_write()
5986    drwav_open_write_sequential()
5987    drwav_open_file()
5988    drwav_open_file_ex()
5989    drwav_open_file_write()
5990    drwav_open_file_write_sequential()
5991    drwav_open_memory()
5992    drwav_open_memory_ex()
5993    drwav_open_memory_write()
5994    drwav_open_memory_write_sequential()
5995    drwav_close()
5996
5997
5998
5999RELEASE NOTES - v0.10.0
6000=======================
6001Version 0.10.0 has breaking API changes. There are no significant bug fixes in this release, so if you are affected you do
6002not need to upgrade.
6003
6004Removed APIs
6005------------
6006The following APIs were deprecated in version 0.9.0 and have been completely removed in version 0.10.0:
6007
6008    drwav_read()
6009    drwav_read_s16()
6010    drwav_read_f32()
6011    drwav_read_s32()
6012    drwav_seek_to_sample()
6013    drwav_write()
6014    drwav_open_and_read_s16()
6015    drwav_open_and_read_f32()
6016    drwav_open_and_read_s32()
6017    drwav_open_file_and_read_s16()
6018    drwav_open_file_and_read_f32()
6019    drwav_open_file_and_read_s32()
6020    drwav_open_memory_and_read_s16()
6021    drwav_open_memory_and_read_f32()
6022    drwav_open_memory_and_read_s32()
6023    drwav::totalSampleCount
6024
6025See release notes for version 0.9.0 at the bottom of this file for replacement APIs.
6026
6027Deprecated APIs
6028---------------
6029The following APIs have been deprecated. There is a confusing and completely arbitrary difference between drwav_init*() and
6030drwav_open*(), where drwav_init*() initializes a pre-allocated drwav object, whereas drwav_open*() will first allocated a
6031drwav object on the heap and then initialize it. drwav_open*() has been deprecated which means you must now use a pre-
6032allocated drwav object with drwav_init*(). If you need the previous functionality, you can just do a malloc() followed by
6033a called to one of the drwav_init*() APIs.
6034
6035    drwav_open()
6036    drwav_open_ex()
6037    drwav_open_write()
6038    drwav_open_write_sequential()
6039    drwav_open_file()
6040    drwav_open_file_ex()
6041    drwav_open_file_write()
6042    drwav_open_file_write_sequential()
6043    drwav_open_memory()
6044    drwav_open_memory_ex()
6045    drwav_open_memory_write()
6046    drwav_open_memory_write_sequential()
6047    drwav_close()
6048
6049These APIs will be removed completely in a future version. The rationale for this change is to remove confusion between the
6050two different ways to initialize a drwav object.
6051*/
6052
6053/*
6054REVISION HISTORY
6055================
6056v0.12.16 - 2020-12-02
6057  - Fix a bug when trying to read more bytes than can fit in a size_t.
6058
6059v0.12.15 - 2020-11-21
6060  - Fix compilation with OpenWatcom.
6061
6062v0.12.14 - 2020-11-13
6063  - Minor code clean up.
6064
6065v0.12.13 - 2020-11-01
6066  - Improve compiler support for older versions of GCC.
6067
6068v0.12.12 - 2020-09-28
6069  - Add support for RF64.
6070  - Fix a bug in writing mode where the size of the RIFF chunk incorrectly includes the header section.
6071
6072v0.12.11 - 2020-09-08
6073  - Fix a compilation error on older compilers.
6074
6075v0.12.10 - 2020-08-24
6076  - Fix a bug when seeking with ADPCM formats.
6077
6078v0.12.9 - 2020-08-02
6079  - Simplify sized types.
6080
6081v0.12.8 - 2020-07-25
6082  - Fix a compilation warning.
6083
6084v0.12.7 - 2020-07-15
6085  - Fix some bugs on big-endian architectures.
6086  - Fix an error in s24 to f32 conversion.
6087
6088v0.12.6 - 2020-06-23
6089  - Change drwav_read_*() to allow NULL to be passed in as the output buffer which is equivalent to a forward seek.
6090  - Fix a buffer overflow when trying to decode invalid IMA-ADPCM files.
6091  - Add include guard for the implementation section.
6092
6093v0.12.5 - 2020-05-27
6094  - Minor documentation fix.
6095
6096v0.12.4 - 2020-05-16
6097  - Replace assert() with DRWAV_ASSERT().
6098  - Add compile-time and run-time version querying.
6099    - DRWAV_VERSION_MINOR
6100    - DRWAV_VERSION_MAJOR
6101    - DRWAV_VERSION_REVISION
6102    - DRWAV_VERSION_STRING
6103    - drwav_version()
6104    - drwav_version_string()
6105
6106v0.12.3 - 2020-04-30
6107  - Fix compilation errors with VC6.
6108
6109v0.12.2 - 2020-04-21
6110  - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file.
6111
6112v0.12.1 - 2020-04-13
6113  - Fix some pedantic warnings.
6114
6115v0.12.0 - 2020-04-04
6116  - API CHANGE: Add container and format parameters to the chunk callback.
6117  - Minor documentation updates.
6118
6119v0.11.5 - 2020-03-07
6120  - Fix compilation error with Visual Studio .NET 2003.
6121
6122v0.11.4 - 2020-01-29
6123  - Fix some static analysis warnings.
6124  - Fix a bug when reading f32 samples from an A-law encoded stream.
6125
6126v0.11.3 - 2020-01-12
6127  - Minor changes to some f32 format conversion routines.
6128  - Minor bug fix for ADPCM conversion when end of file is reached.
6129
6130v0.11.2 - 2019-12-02
6131  - Fix a possible crash when using custom memory allocators without a custom realloc() implementation.
6132  - Fix an integer overflow bug.
6133  - Fix a null pointer dereference bug.
6134  - Add limits to sample rate, channels and bits per sample to tighten up some validation.
6135
6136v0.11.1 - 2019-10-07
6137  - Internal code clean up.
6138
6139v0.11.0 - 2019-10-06
6140  - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
6141    routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
6142    - drwav_init()
6143    - drwav_init_ex()
6144    - drwav_init_file()
6145    - drwav_init_file_ex()
6146    - drwav_init_file_w()
6147    - drwav_init_file_w_ex()
6148    - drwav_init_memory()
6149    - drwav_init_memory_ex()
6150    - drwav_init_write()
6151    - drwav_init_write_sequential()
6152    - drwav_init_write_sequential_pcm_frames()
6153    - drwav_init_file_write()
6154    - drwav_init_file_write_sequential()
6155    - drwav_init_file_write_sequential_pcm_frames()
6156    - drwav_init_file_write_w()
6157    - drwav_init_file_write_sequential_w()
6158    - drwav_init_file_write_sequential_pcm_frames_w()
6159    - drwav_init_memory_write()
6160    - drwav_init_memory_write_sequential()
6161    - drwav_init_memory_write_sequential_pcm_frames()
6162    - drwav_open_and_read_pcm_frames_s16()
6163    - drwav_open_and_read_pcm_frames_f32()
6164    - drwav_open_and_read_pcm_frames_s32()
6165    - drwav_open_file_and_read_pcm_frames_s16()
6166    - drwav_open_file_and_read_pcm_frames_f32()
6167    - drwav_open_file_and_read_pcm_frames_s32()
6168    - drwav_open_file_and_read_pcm_frames_s16_w()
6169    - drwav_open_file_and_read_pcm_frames_f32_w()
6170    - drwav_open_file_and_read_pcm_frames_s32_w()
6171    - drwav_open_memory_and_read_pcm_frames_s16()
6172    - drwav_open_memory_and_read_pcm_frames_f32()
6173    - drwav_open_memory_and_read_pcm_frames_s32()
6174    Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use
6175    DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE.
6176  - Add support for reading and writing PCM frames in an explicit endianness. New APIs:
6177    - drwav_read_pcm_frames_le()
6178    - drwav_read_pcm_frames_be()
6179    - drwav_read_pcm_frames_s16le()
6180    - drwav_read_pcm_frames_s16be()
6181    - drwav_read_pcm_frames_f32le()
6182    - drwav_read_pcm_frames_f32be()
6183    - drwav_read_pcm_frames_s32le()
6184    - drwav_read_pcm_frames_s32be()
6185    - drwav_write_pcm_frames_le()
6186    - drwav_write_pcm_frames_be()
6187  - Remove deprecated APIs.
6188  - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data.
6189    - drwav_read_pcm_frames()
6190    - drwav_read_pcm_frames_s16()
6191    - drwav_read_pcm_frames_s32()
6192    - drwav_read_pcm_frames_f32()
6193    - drwav_open_and_read_pcm_frames_s16()
6194    - drwav_open_and_read_pcm_frames_s32()
6195    - drwav_open_and_read_pcm_frames_f32()
6196    - drwav_open_file_and_read_pcm_frames_s16()
6197    - drwav_open_file_and_read_pcm_frames_s32()
6198    - drwav_open_file_and_read_pcm_frames_f32()
6199    - drwav_open_file_and_read_pcm_frames_s16_w()
6200    - drwav_open_file_and_read_pcm_frames_s32_w()
6201    - drwav_open_file_and_read_pcm_frames_f32_w()
6202    - drwav_open_memory_and_read_pcm_frames_s16()
6203    - drwav_open_memory_and_read_pcm_frames_s32()
6204    - drwav_open_memory_and_read_pcm_frames_f32()
6205
6206v0.10.1 - 2019-08-31
6207  - Correctly handle partial trailing ADPCM blocks.
6208
6209v0.10.0 - 2019-08-04
6210  - Remove deprecated APIs.
6211  - Add wchar_t variants for file loading APIs:
6212      drwav_init_file_w()
6213      drwav_init_file_ex_w()
6214      drwav_init_file_write_w()
6215      drwav_init_file_write_sequential_w()
6216  - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count.
6217  - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode:
6218      drwav_init_write_sequential_pcm_frames()
6219      drwav_init_file_write_sequential_pcm_frames()
6220      drwav_init_file_write_sequential_pcm_frames_w()
6221      drwav_init_memory_write_sequential_pcm_frames()
6222  - Deprecate drwav_open*() and drwav_close():
6223      drwav_open()
6224      drwav_open_ex()
6225      drwav_open_write()
6226      drwav_open_write_sequential()
6227      drwav_open_file()
6228      drwav_open_file_ex()
6229      drwav_open_file_write()
6230      drwav_open_file_write_sequential()
6231      drwav_open_memory()
6232      drwav_open_memory_ex()
6233      drwav_open_memory_write()
6234      drwav_open_memory_write_sequential()
6235      drwav_close()
6236  - Minor documentation updates.
6237
6238v0.9.2 - 2019-05-21
6239  - Fix warnings.
6240
6241v0.9.1 - 2019-05-05
6242  - Add support for C89.
6243  - Change license to choice of public domain or MIT-0.
6244
6245v0.9.0 - 2018-12-16
6246  - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and
6247    will be removed in v0.10.0. Deprecated APIs and their replacements:
6248      drwav_read()                     -> drwav_read_pcm_frames()
6249      drwav_read_s16()                 -> drwav_read_pcm_frames_s16()
6250      drwav_read_f32()                 -> drwav_read_pcm_frames_f32()
6251      drwav_read_s32()                 -> drwav_read_pcm_frames_s32()
6252      drwav_seek_to_sample()           -> drwav_seek_to_pcm_frame()
6253      drwav_write()                    -> drwav_write_pcm_frames()
6254      drwav_open_and_read_s16()        -> drwav_open_and_read_pcm_frames_s16()
6255      drwav_open_and_read_f32()        -> drwav_open_and_read_pcm_frames_f32()
6256      drwav_open_and_read_s32()        -> drwav_open_and_read_pcm_frames_s32()
6257      drwav_open_file_and_read_s16()   -> drwav_open_file_and_read_pcm_frames_s16()
6258      drwav_open_file_and_read_f32()   -> drwav_open_file_and_read_pcm_frames_f32()
6259      drwav_open_file_and_read_s32()   -> drwav_open_file_and_read_pcm_frames_s32()
6260      drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16()
6261      drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32()
6262      drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32()
6263      drwav::totalSampleCount          -> drwav::totalPCMFrameCount
6264  - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*().
6265  - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*().
6266  - Add built-in support for smpl chunks.
6267  - Add support for firing a callback for each chunk in the file at initialization time.
6268    - This is enabled through the drwav_init_ex(), etc. family of APIs.
6269  - Handle invalid FMT chunks more robustly.
6270
6271v0.8.5 - 2018-09-11
6272  - Const correctness.
6273  - Fix a potential stack overflow.
6274
6275v0.8.4 - 2018-08-07
6276  - Improve 64-bit detection.
6277
6278v0.8.3 - 2018-08-05
6279  - Fix C++ build on older versions of GCC.
6280
6281v0.8.2 - 2018-08-02
6282  - Fix some big-endian bugs.
6283
6284v0.8.1 - 2018-06-29
6285  - Add support for sequential writing APIs.
6286  - Disable seeking in write mode.
6287  - Fix bugs with Wave64.
6288  - Fix typos.
6289
6290v0.8 - 2018-04-27
6291  - Bug fix.
6292  - Start using major.minor.revision versioning.
6293
6294v0.7f - 2018-02-05
6295  - Restrict ADPCM formats to a maximum of 2 channels.
6296
6297v0.7e - 2018-02-02
6298  - Fix a crash.
6299
6300v0.7d - 2018-02-01
6301  - Fix a crash.
6302
6303v0.7c - 2018-02-01
6304  - Set drwav.bytesPerSample to 0 for all compressed formats.
6305  - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for
6306    all format conversion reading APIs (*_s16, *_s32, *_f32 APIs).
6307  - Fix some divide-by-zero errors.
6308
6309v0.7b - 2018-01-22
6310  - Fix errors with seeking of compressed formats.
6311  - Fix compilation error when DR_WAV_NO_CONVERSION_API
6312
6313v0.7a - 2017-11-17
6314  - Fix some GCC warnings.
6315
6316v0.7 - 2017-11-04
6317  - Add writing APIs.
6318
6319v0.6 - 2017-08-16
6320  - API CHANGE: Rename dr_* types to drwav_*.
6321  - Add support for custom implementations of malloc(), realloc(), etc.
6322  - Add support for Microsoft ADPCM.
6323  - Add support for IMA ADPCM (DVI, format code 0x11).
6324  - Optimizations to drwav_read_s16().
6325  - Bug fixes.
6326
6327v0.5g - 2017-07-16
6328  - Change underlying type for booleans to unsigned.
6329
6330v0.5f - 2017-04-04
6331  - Fix a minor bug with drwav_open_and_read_s16() and family.
6332
6333v0.5e - 2016-12-29
6334  - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this.
6335  - Minor fixes to documentation.
6336
6337v0.5d - 2016-12-28
6338  - Use drwav_int* and drwav_uint* sized types to improve compiler support.
6339
6340v0.5c - 2016-11-11
6341  - Properly handle JUNK chunks that come before the FMT chunk.
6342
6343v0.5b - 2016-10-23
6344  - A minor change to drwav_bool8 and drwav_bool32 types.
6345
6346v0.5a - 2016-10-11
6347  - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering.
6348  - Improve A-law and mu-law efficiency.
6349
6350v0.5 - 2016-09-29
6351  - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to
6352    keep it consistent with dr_audio and dr_flac.
6353
6354v0.4b - 2016-09-18
6355  - Fixed a typo in documentation.
6356
6357v0.4a - 2016-09-18
6358  - Fixed a typo.
6359  - Change date format to ISO 8601 (YYYY-MM-DD)
6360
6361v0.4 - 2016-07-13
6362  - API CHANGE. Make onSeek consistent with dr_flac.
6363  - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac.
6364  - Added support for Sony Wave64.
6365
6366v0.3a - 2016-05-28
6367  - API CHANGE. Return drwav_bool32 instead of int in onSeek callback.
6368  - Fixed a memory leak.
6369
6370v0.3 - 2016-05-22
6371  - Lots of API changes for consistency.
6372
6373v0.2a - 2016-05-16
6374  - Fixed Linux/GCC build.
6375
6376v0.2 - 2016-05-11
6377  - Added support for reading data as signed 32-bit PCM for consistency with dr_flac.
6378
6379v0.1a - 2016-05-07
6380  - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize.
6381
6382v0.1 - 2016-05-04
6383  - Initial versioned release.
6384*/
6385
6386/*
6387This software is available as a choice of the following licenses. Choose
6388whichever you prefer.
6389
6390===============================================================================
6391ALTERNATIVE 1 - Public Domain (www.unlicense.org)
6392===============================================================================
6393This is free and unencumbered software released into the public domain.
6394
6395Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
6396software, either in source code form or as a compiled binary, for any purpose,
6397commercial or non-commercial, and by any means.
6398
6399In jurisdictions that recognize copyright laws, the author or authors of this
6400software dedicate any and all copyright interest in the software to the public
6401domain. We make this dedication for the benefit of the public at large and to
6402the detriment of our heirs and successors. We intend this dedication to be an
6403overt act of relinquishment in perpetuity of all present and future rights to
6404this software under copyright law.
6405
6406THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6407IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6408FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6409AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
6410ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
6411WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6412
6413For more information, please refer to <http://unlicense.org/>
6414
6415===============================================================================
6416ALTERNATIVE 2 - MIT No Attribution
6417===============================================================================
6418Copyright 2020 David Reid
6419
6420Permission is hereby granted, free of charge, to any person obtaining a copy of
6421this software and associated documentation files (the "Software"), to deal in
6422the Software without restriction, including without limitation the rights to
6423use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
6424of the Software, and to permit persons to whom the Software is furnished to do
6425so.
6426
6427THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6428IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6429FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6430AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6431LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6432OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
6433SOFTWARE.
6434*/