Coverage Report

Created: 2026-09-01 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dr_libs/dr_wav.h
Line
Count
Source
1
/*
2
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
3
dr_wav - v0.14.6 - TBD
4
5
David Reid - mackron@gmail.com
6
7
GitHub: https://github.com/mackron/dr_libs
8
*/
9
10
/*
11
Introduction
12
============
13
This is a single file library. To use it, do something like the following in one .c file.
14
15
    ```c
16
    #define DR_WAV_IMPLEMENTATION
17
    #include "dr_wav.h"
18
    ```
19
20
You can then #include this file in other parts of the program as you would with any other header file. Do something like the following to read audio data:
21
22
    ```c
23
    drwav wav;
24
    if (!drwav_init_file(&wav, "my_song.wav", NULL)) {
25
        // Error opening WAV file.
26
    }
27
28
    drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32));
29
    size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
30
31
    ...
32
33
    drwav_uninit(&wav);
34
    ```
35
36
If you just want to quickly open and read the audio data in a single operation you can do something like this:
37
38
    ```c
39
    unsigned int channels;
40
    unsigned int sampleRate;
41
    drwav_uint64 totalPCMFrameCount;
42
    float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount, NULL);
43
    if (pSampleData == NULL) {
44
        // Error opening and reading WAV file.
45
    }
46
47
    ...
48
49
    drwav_free(pSampleData, NULL);
50
    ```
51
52
The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in this case), but you can still output the
53
audio data in its internal format (see notes below for supported formats):
54
55
    ```c
56
    size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
57
    ```
58
59
You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for a particular data format:
60
61
    ```c
62
    size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer);
63
    ```
64
65
dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at `drwav_init_write()`,
66
`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.
67
68
    ```c
69
    drwav_data_format format;
70
    format.container = drwav_container_riff;     // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
71
    format.format = DR_WAVE_FORMAT_PCM;          // <-- Any of the DR_WAVE_FORMAT_* codes.
72
    format.channels = 2;
73
    format.sampleRate = 44100;
74
    format.bitsPerSample = 16;
75
    drwav_init_file_write(&wav, "data/recording.wav", &format, NULL);
76
77
    ...
78
79
    drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples);
80
    ```
81
82
Note that writing to AIFF or RIFX is not supported.
83
84
dr_wav has support for decoding from a number of different encapsulation formats. See below for details.
85
86
87
Build Options
88
=============
89
#define these options before including this file.
90
91
#define DR_WAV_NO_CONVERSION_API
92
  Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`.
93
94
#define DR_WAV_NO_STDIO
95
  Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc.
96
97
#define DR_WAV_NO_WCHAR
98
  Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_WAV_NO_STDIO is also defined.
99
100
101
Supported Encapsulations
102
========================
103
- RIFF (Regular WAV)
104
- RIFX (Big-Endian)
105
- AIFF (Does not currently support ADPCM)
106
- RF64
107
- W64
108
109
Note that AIFF and RIFX do not support write mode, nor do they support reading of metadata.
110
111
112
Supported Encodings
113
===================
114
- Unsigned 8-bit PCM
115
- Signed 12-bit PCM
116
- Signed 16-bit PCM
117
- Signed 24-bit PCM
118
- Signed 32-bit PCM
119
- IEEE 32-bit floating point
120
- IEEE 64-bit floating point
121
- A-law and u-law
122
- Microsoft ADPCM
123
- IMA ADPCM (DVI, format code 0x11)
124
125
8-bit PCM encodings are always assumed to be unsigned. Signed 8-bit encoding can only be read with `drwav_read_raw()`.
126
127
Note that ADPCM is not currently supported with AIFF. Contributions welcome.
128
129
130
Notes
131
=====
132
- Samples are always interleaved.
133
- 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()`
134
  to read and convert audio data to 32-bit floating point, signed 32-bit integer and signed 16-bit integer samples respectively.
135
- dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format.
136
*/
137
138
#ifndef dr_wav_h
139
#define dr_wav_h
140
141
#ifdef __cplusplus
142
extern "C" {
143
#endif
144
145
0
#define DRWAV_STRINGIFY(x)      #x
146
0
#define DRWAV_XSTRINGIFY(x)     DRWAV_STRINGIFY(x)
147
148
0
#define DRWAV_VERSION_MAJOR     0
149
0
#define DRWAV_VERSION_MINOR     14
150
0
#define DRWAV_VERSION_REVISION  6
151
0
#define DRWAV_VERSION_STRING    DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
152
153
#include <stddef.h> /* For size_t. */
154
155
/* Sized Types */
156
typedef   signed char           drwav_int8;
157
typedef unsigned char           drwav_uint8;
158
typedef   signed short          drwav_int16;
159
typedef unsigned short          drwav_uint16;
160
typedef   signed int            drwav_int32;
161
typedef unsigned int            drwav_uint32;
162
#if defined(_MSC_VER) && !defined(__clang__)
163
    typedef   signed __int64    drwav_int64;
164
    typedef unsigned __int64    drwav_uint64;
165
#else
166
    #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
167
        #pragma GCC diagnostic push
168
        #pragma GCC diagnostic ignored "-Wlong-long"
169
        #if defined(__clang__)
170
            #pragma GCC diagnostic ignored "-Wc++11-long-long"
171
        #endif
172
    #endif
173
    typedef   signed long long  drwav_int64;
174
    typedef unsigned long long  drwav_uint64;
175
    #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
176
        #pragma GCC diagnostic pop
177
    #endif
178
#endif
179
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(__powerpc64__)
180
    typedef drwav_uint64        drwav_uintptr;
181
#else
182
    typedef drwav_uint32        drwav_uintptr;
183
#endif
184
typedef drwav_uint8             drwav_bool8;
185
typedef drwav_uint32            drwav_bool32;
186
280k
#define DRWAV_TRUE              1
187
74.7k
#define DRWAV_FALSE             0
188
/* End Sized Types */
189
190
/* Decorations */
191
#if !defined(DRWAV_API)
192
    #if defined(DRWAV_DLL)
193
        #if defined(_WIN32)
194
            #define DRWAV_DLL_IMPORT  __declspec(dllimport)
195
            #define DRWAV_DLL_EXPORT  __declspec(dllexport)
196
            #define DRWAV_DLL_PRIVATE static
197
        #else
198
            #if defined(__GNUC__) && __GNUC__ >= 4
199
                #define DRWAV_DLL_IMPORT  __attribute__((visibility("default")))
200
                #define DRWAV_DLL_EXPORT  __attribute__((visibility("default")))
201
                #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden")))
202
            #else
203
                #define DRWAV_DLL_IMPORT
204
                #define DRWAV_DLL_EXPORT
205
                #define DRWAV_DLL_PRIVATE static
206
            #endif
207
        #endif
208
209
        #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
210
            #define DRWAV_API  DRWAV_DLL_EXPORT
211
        #else
212
            #define DRWAV_API  DRWAV_DLL_IMPORT
213
        #endif
214
        #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE
215
    #else
216
        #define DRWAV_API extern
217
        #define DRWAV_PRIVATE static
218
    #endif
219
#endif
220
/* End Decorations */
221
222
/* Result Codes */
223
typedef drwav_int32 drwav_result;
224
32.8k
#define DRWAV_SUCCESS                        0
225
0
#define DRWAV_ERROR                         -1   /* A generic error. */
226
0
#define DRWAV_INVALID_ARGS                  -2
227
0
#define DRWAV_INVALID_OPERATION             -3
228
0
#define DRWAV_OUT_OF_MEMORY                 -4
229
0
#define DRWAV_OUT_OF_RANGE                  -5
230
0
#define DRWAV_ACCESS_DENIED                 -6
231
0
#define DRWAV_DOES_NOT_EXIST                -7
232
0
#define DRWAV_ALREADY_EXISTS                -8
233
0
#define DRWAV_TOO_MANY_OPEN_FILES           -9
234
34
#define DRWAV_INVALID_FILE                  -10
235
0
#define DRWAV_TOO_BIG                       -11
236
0
#define DRWAV_PATH_TOO_LONG                 -12
237
#define DRWAV_NAME_TOO_LONG                 -13
238
0
#define DRWAV_NOT_DIRECTORY                 -14
239
0
#define DRWAV_IS_DIRECTORY                  -15
240
0
#define DRWAV_DIRECTORY_NOT_EMPTY           -16
241
#define DRWAV_END_OF_FILE                   -17
242
0
#define DRWAV_NO_SPACE                      -18
243
0
#define DRWAV_BUSY                          -19
244
0
#define DRWAV_IO_ERROR                      -20
245
0
#define DRWAV_INTERRUPT                     -21
246
0
#define DRWAV_UNAVAILABLE                   -22
247
0
#define DRWAV_ALREADY_IN_USE                -23
248
0
#define DRWAV_BAD_ADDRESS                   -24
249
0
#define DRWAV_BAD_SEEK                      -25
250
0
#define DRWAV_BAD_PIPE                      -26
251
0
#define DRWAV_DEADLOCK                      -27
252
0
#define DRWAV_TOO_MANY_LINKS                -28
253
0
#define DRWAV_NOT_IMPLEMENTED               -29
254
0
#define DRWAV_NO_MESSAGE                    -30
255
0
#define DRWAV_BAD_MESSAGE                   -31
256
0
#define DRWAV_NO_DATA_AVAILABLE             -32
257
0
#define DRWAV_INVALID_DATA                  -33
258
0
#define DRWAV_TIMEOUT                       -34
259
0
#define DRWAV_NO_NETWORK                    -35
260
0
#define DRWAV_NOT_UNIQUE                    -36
261
0
#define DRWAV_NOT_SOCKET                    -37
262
0
#define DRWAV_NO_ADDRESS                    -38
263
0
#define DRWAV_BAD_PROTOCOL                  -39
264
0
#define DRWAV_PROTOCOL_UNAVAILABLE          -40
265
0
#define DRWAV_PROTOCOL_NOT_SUPPORTED        -41
266
0
#define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42
267
0
#define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED  -43
268
0
#define DRWAV_SOCKET_NOT_SUPPORTED          -44
269
0
#define DRWAV_CONNECTION_RESET              -45
270
0
#define DRWAV_ALREADY_CONNECTED             -46
271
0
#define DRWAV_NOT_CONNECTED                 -47
272
0
#define DRWAV_CONNECTION_REFUSED            -48
273
0
#define DRWAV_NO_HOST                       -49
274
0
#define DRWAV_IN_PROGRESS                   -50
275
0
#define DRWAV_CANCELLED                     -51
276
#define DRWAV_MEMORY_ALREADY_MAPPED         -52
277
117
#define DRWAV_AT_END                        -53
278
/* End Result Codes */
279
280
/* Common data formats. */
281
10.5k
#define DR_WAVE_FORMAT_PCM          0x1
282
31.5k
#define DR_WAVE_FORMAT_ADPCM        0x2
283
6.89k
#define DR_WAVE_FORMAT_IEEE_FLOAT   0x3
284
61.9k
#define DR_WAVE_FORMAT_ALAW         0x6
285
27.4k
#define DR_WAVE_FORMAT_MULAW        0x7
286
#define DR_WAVE_FORMAT_DTS          0x8
287
25.1k
#define DR_WAVE_FORMAT_DVI_ADPCM    0x11
288
2.67k
#define DR_WAVE_FORMAT_EXTENSIBLE   0xFFFE
289
290
/* Flags to pass into drwav_init_ex(), etc. */
291
4.51k
#define DRWAV_SEQUENTIAL            0x00000001
292
4.51k
#define DRWAV_WITH_METADATA         0x00000002
293
294
DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
295
DRWAV_API const char* drwav_version_string(void);
296
297
/* Allocation Callbacks */
298
typedef struct
299
{
300
    void* pUserData;
301
    void* (* onMalloc)(size_t sz, void* pUserData);
302
    void* (* onRealloc)(void* p, size_t sz, void* pUserData);
303
    void  (* onFree)(void* p, void* pUserData);
304
} drwav_allocation_callbacks;
305
/* End Allocation Callbacks */
306
307
typedef enum
308
{
309
    DRWAV_SEEK_SET,
310
    DRWAV_SEEK_CUR,
311
    DRWAV_SEEK_END
312
} drwav_seek_origin;
313
314
typedef enum
315
{
316
    drwav_container_riff,
317
    drwav_container_rifx,
318
    drwav_container_w64,
319
    drwav_container_rf64,
320
    drwav_container_aiff
321
} drwav_container;
322
323
typedef struct
324
{
325
    union
326
    {
327
        drwav_uint8 fourcc[4];
328
        drwav_uint8 guid[16];
329
    } id;
330
331
    /* The size in bytes of the chunk. */
332
    drwav_uint64 sizeInBytes;
333
334
    /*
335
    RIFF = 2 byte alignment.
336
    W64  = 8 byte alignment.
337
    */
338
    unsigned int paddingSize;
339
} drwav_chunk_header;
340
341
typedef struct
342
{
343
    /*
344
    The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
345
    that require support for data formats not natively supported by dr_wav.
346
    */
347
    drwav_uint16 formatTag;
348
349
    /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */
350
    drwav_uint16 channels;
351
352
    /* The sample rate. Usually set to something like 44100. */
353
    drwav_uint32 sampleRate;
354
355
    /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */
356
    drwav_uint32 avgBytesPerSec;
357
358
    /* Block align. This is equal to the number of channels * bytes per sample. */
359
    drwav_uint16 blockAlign;
360
361
    /* Bits per sample. */
362
    drwav_uint16 bitsPerSample;
363
364
    /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */
365
    drwav_uint16 extendedSize;
366
367
    /*
368
    The number of valid bits per sample. When <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample>
369
    is always rounded up to the nearest multiple of 8. This variable contains information about exactly how
370
    many bits are valid per sample. Mainly used for informational purposes.
371
    */
372
    drwav_uint16 validBitsPerSample;
373
374
    /* The channel mask. Not used at the moment. */
375
    drwav_uint32 channelMask;
376
377
    /* The sub-format, exactly as specified by the wave file. */
378
    drwav_uint8 subFormat[16];
379
} drwav_fmt;
380
381
DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
382
383
384
/*
385
Callback for when data is read. Return value is the number of bytes actually read.
386
387
pUserData   [in]  The user data that was passed to drwav_init() and family.
388
pBufferOut  [out] The output buffer.
389
bytesToRead [in]  The number of bytes to read.
390
391
Returns the number of bytes actually read.
392
393
A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until
394
either the entire bytesToRead is filled or you have reached the end of the stream.
395
*/
396
typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
397
398
/*
399
Callback for when data is written. Returns value is the number of bytes actually written.
400
401
pUserData    [in]  The user data that was passed to drwav_init_write() and family.
402
pData        [out] A pointer to the data to write.
403
bytesToWrite [in]  The number of bytes to write.
404
405
Returns the number of bytes actually written.
406
407
If the return value differs from bytesToWrite, it indicates an error.
408
*/
409
typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
410
411
/*
412
Callback for when data needs to be seeked.
413
414
pUserData [in] The user data that was passed to drwav_init() and family.
415
offset    [in] The number of bytes to move, relative to the origin. Will never be negative.
416
origin    [in] The origin of the seek - the current position or the start of the stream.
417
418
Returns whether or not the seek was successful.
419
420
Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either DRWAV_SEEK_SET or
421
DRWAV_SEEK_CUR.
422
*/
423
typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
424
425
/*
426
Callback for when the current position in the stream needs to be retrieved.
427
428
pUserData [in]  The user data that was passed to drwav_init() and family.
429
pCursor   [out] A pointer to a variable to receive the current position in the stream.
430
431
Returns whether or not the operation was successful.
432
*/
433
typedef drwav_bool32 (* drwav_tell_proc)(void* pUserData, drwav_int64* pCursor);
434
435
/*
436
Callback for when drwav_init_ex() finds a chunk.
437
438
pChunkUserData    [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family.
439
onRead            [in] A pointer to the function to call when reading.
440
onSeek            [in] A pointer to the function to call when seeking.
441
pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family.
442
pChunkHeader      [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk.
443
container         [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF.
444
pFMT              [in] A pointer to the object containing the contents of the "fmt" chunk.
445
446
Returns the number of bytes read + seeked.
447
448
To 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
449
be the total number of bytes you have read _plus_ seeked.
450
451
Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should
452
use `id.fourcc`, otherwise you should use `id.guid`.
453
454
The `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
455
`DR_WAVE_FORMAT_*` identifiers.
456
457
The 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.
458
*/
459
typedef 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);
460
461
462
/* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */
463
typedef struct
464
{
465
    const drwav_uint8* data;
466
    size_t dataSize;
467
    size_t currentReadPos;
468
} drwav__memory_stream;
469
470
/* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */
471
typedef struct
472
{
473
    void** ppData;
474
    size_t* pDataSize;
475
    size_t dataSize;
476
    size_t dataCapacity;
477
    size_t currentWritePos;
478
} drwav__memory_stream_write;
479
480
typedef struct
481
{
482
    drwav_container container;  /* RIFF, W64. */
483
    drwav_uint32 format;        /* DR_WAVE_FORMAT_* */
484
    drwav_uint32 channels;
485
    drwav_uint32 sampleRate;
486
    drwav_uint32 bitsPerSample;
487
} drwav_data_format;
488
489
typedef enum
490
{
491
    drwav_metadata_type_none                        = 0,
492
493
    /*
494
    Unknown simply means a chunk that drwav does not handle specifically. You can still ask to
495
    receive these chunks as metadata objects. It is then up to you to interpret the chunk's data.
496
    You can also write unknown metadata to a wav file. Be careful writing unknown chunks if you
497
    have also edited the audio data. The unknown chunks could represent offsets/sizes that no
498
    longer correctly correspond to the audio data.
499
    */
500
    drwav_metadata_type_unknown                     = 1 << 0,
501
502
    /* Only 1 of each of these metadata items are allowed in a wav file. */
503
    drwav_metadata_type_smpl                        = 1 << 1,
504
    drwav_metadata_type_inst                        = 1 << 2,
505
    drwav_metadata_type_cue                         = 1 << 3,
506
    drwav_metadata_type_acid                        = 1 << 4,
507
    drwav_metadata_type_bext                        = 1 << 5,
508
509
    /*
510
    Wav files often have a LIST chunk. This is a chunk that contains a set of subchunks. For this
511
    higher-level metadata API, we don't make a distinction between a regular chunk and a LIST
512
    subchunk. Instead, they are all just 'metadata' items.
513
514
    There can be multiple of these metadata items in a wav file.
515
    */
516
    drwav_metadata_type_list_label                  = 1 << 6,
517
    drwav_metadata_type_list_note                   = 1 << 7,
518
    drwav_metadata_type_list_labelled_cue_region    = 1 << 8,
519
520
    drwav_metadata_type_list_info_software          = 1 << 9,
521
    drwav_metadata_type_list_info_copyright         = 1 << 10,
522
    drwav_metadata_type_list_info_title             = 1 << 11,
523
    drwav_metadata_type_list_info_artist            = 1 << 12,
524
    drwav_metadata_type_list_info_comment           = 1 << 13,
525
    drwav_metadata_type_list_info_date              = 1 << 14,
526
    drwav_metadata_type_list_info_genre             = 1 << 15,
527
    drwav_metadata_type_list_info_album             = 1 << 16,
528
    drwav_metadata_type_list_info_tracknumber       = 1 << 17,
529
    drwav_metadata_type_list_info_location          = 1 << 18,
530
    drwav_metadata_type_list_info_organization      = 1 << 19,
531
    drwav_metadata_type_list_info_keywords          = 1 << 20,
532
    drwav_metadata_type_list_info_medium            = 1 << 21,
533
    drwav_metadata_type_list_info_description       = 1 << 22,
534
535
    /* Other type constants for convenience. */
536
    drwav_metadata_type_list_all_info_strings       = drwav_metadata_type_list_info_software
537
                                                    | drwav_metadata_type_list_info_copyright
538
                                                    | drwav_metadata_type_list_info_title
539
                                                    | drwav_metadata_type_list_info_artist
540
                                                    | drwav_metadata_type_list_info_comment
541
                                                    | drwav_metadata_type_list_info_date
542
                                                    | drwav_metadata_type_list_info_genre
543
                                                    | drwav_metadata_type_list_info_album
544
                                                    | drwav_metadata_type_list_info_tracknumber
545
                                                    | drwav_metadata_type_list_info_location
546
                                                    | drwav_metadata_type_list_info_organization
547
                                                    | drwav_metadata_type_list_info_keywords
548
                                                    | drwav_metadata_type_list_info_medium
549
                                                    | drwav_metadata_type_list_info_description,
550
551
    drwav_metadata_type_list_all_adtl               = drwav_metadata_type_list_label
552
                                                    | drwav_metadata_type_list_note
553
                                                    | drwav_metadata_type_list_labelled_cue_region,
554
555
    drwav_metadata_type_all                         = -2,   /*0xFFFFFFFF & ~drwav_metadata_type_unknown,*/
556
    drwav_metadata_type_all_including_unknown       = -1    /*0xFFFFFFFF,*/
557
} drwav_metadata_type;
558
559
/*
560
Sampler Metadata
561
562
The sampler chunk contains information about how a sound should be played in the context of a whole
563
audio production, and when used in a sampler. See https://en.wikipedia.org/wiki/Sample-based_synthesis.
564
*/
565
typedef enum
566
{
567
    drwav_smpl_loop_type_forward  = 0,
568
    drwav_smpl_loop_type_pingpong = 1,
569
    drwav_smpl_loop_type_backward = 2
570
} drwav_smpl_loop_type;
571
572
typedef struct
573
{
574
    /* The ID of the associated cue point, see drwav_cue and drwav_cue_point. As with all cue point IDs, this can correspond to a label chunk to give this loop a name, see drwav_list_label_or_note. */
575
    drwav_uint32 cuePointId;
576
577
    /* See drwav_smpl_loop_type. */
578
    drwav_uint32 type;
579
580
    /* The offset of the first sample to be played in the loop. */
581
    drwav_uint32 firstSampleOffset;
582
583
    /* The offset into the audio data of the last sample to be played in the loop. */
584
    drwav_uint32 lastSampleOffset;
585
586
    /* A value to represent that playback should occur at a point between samples. This value ranges from 0 to UINT32_MAX. Where a value of 0 means no fraction, and a value of (UINT32_MAX / 2) would mean half a sample. */
587
    drwav_uint32 sampleFraction;
588
589
    /* Number of times to play the loop. 0 means loop infinitely. */
590
    drwav_uint32 playCount;
591
} drwav_smpl_loop;
592
593
typedef struct
594
{
595
    /* IDs for a particular MIDI manufacturer. 0 if not used. */
596
    drwav_uint32 manufacturerId;
597
    drwav_uint32 productId;
598
599
    /* The period of 1 sample in nanoseconds. */
600
    drwav_uint32 samplePeriodNanoseconds;
601
602
    /* The MIDI root note of this file. 0 to 127. */
603
    drwav_uint32 midiUnityNote;
604
605
    /* The fraction of a semitone up from the given MIDI note. This is a value from 0 to UINT32_MAX, where 0 means no change and (UINT32_MAX / 2) is half a semitone (AKA 50 cents). */
606
    drwav_uint32 midiPitchFraction;
607
608
    /* Data relating to SMPTE standards which are used for syncing audio and video. 0 if not used. */
609
    drwav_uint32 smpteFormat;
610
    drwav_uint32 smpteOffset;
611
612
    /* drwav_smpl_loop loops. */
613
    drwav_uint32 sampleLoopCount;
614
615
    /* Optional sampler-specific data. */
616
    drwav_uint32 samplerSpecificDataSizeInBytes;
617
618
    drwav_smpl_loop* pLoops;
619
    drwav_uint8* pSamplerSpecificData;
620
} drwav_smpl;
621
622
/*
623
Instrument Metadata
624
625
The inst metadata contains data about how a sound should be played as part of an instrument. This
626
commonly read by samplers. See https://en.wikipedia.org/wiki/Sample-based_synthesis.
627
*/
628
typedef struct
629
{
630
    drwav_int8 midiUnityNote;   /* The root note of the audio as a MIDI note number. 0 to 127. */
631
    drwav_int8 fineTuneCents;   /* -50 to +50 */
632
    drwav_int8 gainDecibels;    /* -64 to +64 */
633
    drwav_int8 lowNote;         /* 0 to 127 */
634
    drwav_int8 highNote;        /* 0 to 127 */
635
    drwav_int8 lowVelocity;     /* 1 to 127 */
636
    drwav_int8 highVelocity;    /* 1 to 127 */
637
} drwav_inst;
638
639
/*
640
Cue Metadata
641
642
Cue points are markers at specific points in the audio. They often come with an associated piece of
643
drwav_list_label_or_note metadata which contains the text for the marker.
644
*/
645
typedef struct
646
{
647
    /* Unique identification value. */
648
    drwav_uint32 id;
649
650
    /* Set to 0. This is only relevant if there is a 'playlist' chunk - which is not supported by dr_wav. */
651
    drwav_uint32 playOrderPosition;
652
653
    /* Should always be "data". This represents the fourcc value of the chunk that this cue point corresponds to. dr_wav only supports a single data chunk so this should always be "data". */
654
    drwav_uint8 dataChunkId[4];
655
656
    /* Set to 0. This is only relevant if there is a wave list chunk. dr_wav, like lots of readers/writers, do not support this. */
657
    drwav_uint32 chunkStart;
658
659
    /* Set to 0 for uncompressed formats. Else the last byte in compressed wave data where decompression can begin to find the value of the corresponding sample value. */
660
    drwav_uint32 blockStart;
661
662
    /* For uncompressed formats this is the offset of the cue point into the audio data. For compressed formats this is relative to the block specified with blockStart. */
663
    drwav_uint32 sampleOffset;
664
} drwav_cue_point;
665
666
typedef struct
667
{
668
    drwav_uint32 cuePointCount;
669
    drwav_cue_point *pCuePoints;
670
} drwav_cue;
671
672
/*
673
Acid Metadata
674
675
This chunk contains some information about the time signature and the tempo of the audio.
676
*/
677
typedef enum
678
{
679
    drwav_acid_flag_one_shot      = 1,  /* If this is not set, then it is a loop instead of a one-shot. */
680
    drwav_acid_flag_root_note_set = 2,
681
    drwav_acid_flag_stretch       = 4,
682
    drwav_acid_flag_disk_based    = 8,
683
    drwav_acid_flag_acidizer      = 16  /* Not sure what this means. */
684
} drwav_acid_flag;
685
686
typedef struct
687
{
688
    /* A bit-field, see drwav_acid_flag. */
689
    drwav_uint32 flags;
690
691
    /* Valid if flags contains drwav_acid_flag_root_note_set. It represents the MIDI root note the file - a value from 0 to 127. */
692
    drwav_uint16 midiUnityNote;
693
694
    /* Reserved values that should probably be ignored. reserved1 seems to often be 128 and reserved2 is 0. */
695
    drwav_uint16 reserved1;
696
    float reserved2;
697
698
    /* Number of beats. */
699
    drwav_uint32 numBeats;
700
701
    /* The time signature of the audio. */
702
    drwav_uint16 meterDenominator;
703
    drwav_uint16 meterNumerator;
704
705
    /* Beats per minute of the track. Setting a value of 0 suggests that there is no tempo. */
706
    float tempo;
707
} drwav_acid;
708
709
/*
710
Cue Label or Note metadata
711
712
These are 2 different types of metadata, but they have the exact same format. Labels tend to be the
713
more common and represent a short name for a cue point. Notes might be used to represent a longer
714
comment.
715
*/
716
typedef struct
717
{
718
    /* The ID of a cue point that this label or note corresponds to. */
719
    drwav_uint32 cuePointId;
720
721
    /* Size of the string not including any null terminator. */
722
    drwav_uint32 stringLength;
723
724
    /* The string. The *init_with_metadata functions null terminate this for convenience. */
725
    char* pString;
726
} drwav_list_label_or_note;
727
728
/*
729
BEXT metadata, also known as Broadcast Wave Format (BWF)
730
731
This metadata adds some extra description to an audio file. You must check the version field to
732
determine if the UMID or the loudness fields are valid.
733
*/
734
typedef struct
735
{
736
    /*
737
    These top 3 fields, and the umid field are actually defined in the standard as a statically
738
    sized buffers. In order to reduce the size of this struct (and therefore the union in the
739
    metadata struct), we instead store these as pointers.
740
    */
741
    char* pDescription;                 /* Can be NULL or a null-terminated string, must be <= 256 characters. */
742
    char* pOriginatorName;              /* Can be NULL or a null-terminated string, must be <= 32 characters. */
743
    char* pOriginatorReference;         /* Can be NULL or a null-terminated string, must be <= 32 characters. */
744
    char  pOriginationDate[10];         /* ASCII "yyyy:mm:dd". */
745
    char  pOriginationTime[8];          /* ASCII "hh:mm:ss". */
746
    drwav_uint64 timeReference;         /* First sample count since midnight. */
747
    drwav_uint16 version;               /* Version of the BWF, check this to see if the fields below are valid. */
748
749
    /*
750
    Unrestricted ASCII characters containing a collection of strings terminated by CR/LF. Each
751
    string shall contain a description of a coding process applied to the audio data.
752
    */
753
    char* pCodingHistory;
754
    drwav_uint32 codingHistorySize;
755
756
    /* Fields below this point are only valid if the version is 1 or above. */
757
    drwav_uint8* pUMID;                  /* Exactly 64 bytes of SMPTE UMID */
758
759
    /* Fields below this point are only valid if the version is 2 or above. */
760
    drwav_uint16 loudnessValue;         /* Integrated Loudness Value of the file in LUFS (multiplied by 100). */
761
    drwav_uint16 loudnessRange;         /* Loudness Range of the file in LU (multiplied by 100). */
762
    drwav_uint16 maxTruePeakLevel;      /* Maximum True Peak Level of the file expressed as dBTP (multiplied by 100). */
763
    drwav_uint16 maxMomentaryLoudness;  /* Highest value of the Momentary Loudness Level of the file in LUFS (multiplied by 100). */
764
    drwav_uint16 maxShortTermLoudness;  /* Highest value of the Short-Term Loudness Level of the file in LUFS (multiplied by 100). */
765
} drwav_bext;
766
767
/*
768
Info Text Metadata
769
770
There a many different types of information text that can be saved in this format. This is where
771
things like the album name, the artists, the year it was produced, etc are saved. See
772
drwav_metadata_type for the full list of types that dr_wav supports.
773
*/
774
typedef struct
775
{
776
    /* Size of the string not including any null terminator. */
777
    drwav_uint32 stringLength;
778
779
    /* The string. The *init_with_metadata functions null terminate this for convenience. */
780
    char* pString;
781
} drwav_list_info_text;
782
783
/*
784
Labelled Cue Region Metadata
785
786
The labelled cue region metadata is used to associate some region of audio with text. The region
787
starts at a cue point, and extends for the given number of samples.
788
*/
789
typedef struct
790
{
791
    /* The ID of a cue point that this object corresponds to. */
792
    drwav_uint32 cuePointId;
793
794
    /* The number of samples from the cue point forwards that should be considered this region */
795
    drwav_uint32 sampleLength;
796
797
    /* Four characters used to say what the purpose of this region is. */
798
    drwav_uint8 purposeId[4];
799
800
    /* Unsure of the exact meanings of these. It appears to be acceptable to set them all to 0. */
801
    drwav_uint16 country;
802
    drwav_uint16 language;
803
    drwav_uint16 dialect;
804
    drwav_uint16 codePage;
805
806
    /* Size of the string not including any null terminator. */
807
    drwav_uint32 stringLength;
808
809
    /* The string. The *init_with_metadata functions null terminate this for convenience. */
810
    char* pString;
811
} drwav_list_labelled_cue_region;
812
813
/*
814
Unknown Metadata
815
816
This chunk just represents a type of chunk that dr_wav does not understand.
817
818
Unknown metadata has a location attached to it. This is because wav files can have a LIST chunk
819
that contains subchunks. These LIST chunks can be one of two types. An adtl list, or an INFO
820
list. This enum is used to specify the location of a chunk that dr_wav currently doesn't support.
821
*/
822
typedef enum
823
{
824
    drwav_metadata_location_invalid,
825
    drwav_metadata_location_top_level,
826
    drwav_metadata_location_inside_info_list,
827
    drwav_metadata_location_inside_adtl_list
828
} drwav_metadata_location;
829
830
typedef struct
831
{
832
    drwav_uint8 id[4];
833
    drwav_metadata_location chunkLocation;
834
    drwav_uint32 dataSizeInBytes;
835
    drwav_uint8* pData;
836
} drwav_unknown_metadata;
837
838
/*
839
Metadata is saved as a union of all the supported types.
840
*/
841
typedef struct
842
{
843
    /* Determines which item in the union is valid. */
844
    drwav_metadata_type type;
845
846
    union
847
    {
848
        drwav_cue cue;
849
        drwav_smpl smpl;
850
        drwav_acid acid;
851
        drwav_inst inst;
852
        drwav_bext bext;
853
        drwav_list_label_or_note labelOrNote;   /* List label or list note. */
854
        drwav_list_labelled_cue_region labelledCueRegion;
855
        drwav_list_info_text infoText;          /* Any of the list info types. */
856
        drwav_unknown_metadata unknown;
857
    } data;
858
} drwav_metadata;
859
860
typedef struct
861
{
862
    /* A pointer to the function to call when more data is needed. */
863
    drwav_read_proc onRead;
864
865
    /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */
866
    drwav_write_proc onWrite;
867
868
    /* A pointer to the function to call when the wav file needs to be seeked. */
869
    drwav_seek_proc onSeek;
870
871
    /* A pointer to the function to call when the position of the stream needs to be retrieved. */
872
    drwav_tell_proc onTell;
873
874
    /* The user data to pass to callbacks. */
875
    void* pUserData;
876
877
    /* Allocation callbacks. */
878
    drwav_allocation_callbacks allocationCallbacks;
879
880
881
    /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */
882
    drwav_container container;
883
884
885
    /* Structure containing format information exactly as specified by the wav file. */
886
    drwav_fmt fmt;
887
888
    /* The sample rate. Will be set to something like 44100. */
889
    drwav_uint32 sampleRate;
890
891
    /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */
892
    drwav_uint16 channels;
893
894
    /* The bits per sample. Will be set to something like 16, 24, etc. */
895
    drwav_uint16 bitsPerSample;
896
897
    /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */
898
    drwav_uint16 translatedFormatTag;
899
900
    /* The total number of PCM frames making up the audio data. */
901
    drwav_uint64 totalPCMFrameCount;
902
903
904
    /* The size in bytes of the data chunk. */
905
    drwav_uint64 dataChunkDataSize;
906
907
    /* The position in the stream of the first data byte of the data chunk. This is used for seeking. */
908
    drwav_uint64 dataChunkDataPos;
909
910
    /* The number of bytes remaining in the data chunk. */
911
    drwav_uint64 bytesRemaining;
912
913
    /* The current read position in PCM frames. */
914
    drwav_uint64 readCursorInPCMFrames;
915
916
917
    /*
918
    Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always
919
    set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation.
920
    */
921
    drwav_uint64 dataChunkDataSizeTargetWrite;
922
923
    /* Keeps track of whether or not the wav writer was initialized in sequential mode. */
924
    drwav_bool32 isSequentialWrite;
925
926
927
    /* A array of metadata. This is valid after the *init_with_metadata call returns. It will be valid until drwav_uninit() is called. You can take ownership of this data with drwav_take_ownership_of_metadata(). */
928
    drwav_metadata* pMetadata;
929
    drwav_uint32 metadataCount;
930
931
932
    /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */
933
    drwav__memory_stream memoryStream;
934
    drwav__memory_stream_write memoryStreamWrite;
935
936
937
    /* Microsoft ADPCM specific data. */
938
    struct
939
    {
940
        drwav_uint32 bytesRemainingInBlock;
941
        drwav_uint16 predictor[2];
942
        drwav_int32  delta[2];
943
        drwav_int32  cachedFrames[4];  /* Samples are stored in this cache during decoding. */
944
        drwav_uint32 cachedFrameCount;
945
        drwav_int32  prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */
946
    } msadpcm;
947
948
    /* IMA ADPCM specific data. */
949
    struct
950
    {
951
        drwav_uint32 bytesRemainingInBlock;
952
        drwav_int32  predictor[2];
953
        drwav_int32  stepIndex[2];
954
        drwav_int32  cachedFrames[16]; /* Samples are stored in this cache during decoding. */
955
        drwav_uint32 cachedFrameCount;
956
    } ima;
957
958
    /* AIFF specific data. */
959
    struct
960
    {
961
        drwav_bool8 isLE;   /* Will be set to true if the audio data is little-endian encoded. */
962
        drwav_bool8 isUnsigned; /* Only used for 8-bit samples. When set to true, will be treated as unsigned. */
963
    } aiff;
964
} drwav;
965
966
967
/*
968
Initializes a pre-allocated drwav object for reading.
969
970
pWav                         [out]          A pointer to the drwav object being initialized.
971
onRead                       [in]           The function to call when data needs to be read from the client.
972
onSeek                       [in]           The function to call when the read position of the client data needs to move.
973
onChunk                      [in, optional] The function to call when a chunk is enumerated at initialized time.
974
pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
975
pChunkUserData               [in, optional] A pointer to application defined data that will be passed to onChunk.
976
flags                        [in, optional] A set of flags for controlling how things are loaded.
977
978
Returns true if successful; false otherwise.
979
980
Close the loader with drwav_uninit().
981
982
This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory()
983
to open the stream from a file or from a block of memory respectively.
984
985
Possible values for flags:
986
  DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function
987
                    to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored.
988
989
drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);".
990
991
The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt
992
after the function returns.
993
994
See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
995
*/
996
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
997
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, drwav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
998
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
999
1000
/*
1001
Initializes a pre-allocated drwav object for writing.
1002
1003
onWrite               [in]           The function to call when data needs to be written.
1004
onSeek                [in]           The function to call when the write position needs to move.
1005
pUserData             [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek.
1006
metadata, numMetadata [in, optional] An array of metadata objects that should be written to the file. The array is not edited. You are responsible for this metadata memory and it must maintain valid until drwav_uninit() is called.
1007
1008
Returns true if successful; false otherwise.
1009
1010
Close the writer with drwav_uninit().
1011
1012
This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write()
1013
to open the stream from a file or from a block of memory respectively.
1014
1015
If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform
1016
a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek.
1017
1018
See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit()
1019
*/
1020
DRWAV_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);
1021
DRWAV_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);
1022
DRWAV_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);
1023
DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount);
1024
1025
/*
1026
Utility function to determine the target size of the entire data to be written (including all headers and chunks).
1027
1028
Returns the target size in bytes.
1029
1030
The metadata argument can be NULL meaning no metadata exists.
1031
1032
Useful if the application needs to know the size to allocate.
1033
1034
Only writing to the RIFF chunk and one data chunk is currently supported.
1035
1036
See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write()
1037
*/
1038
DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount);
1039
1040
/*
1041
Take ownership of the metadata objects that were allocated via one of the init_with_metadata() function calls. The init_with_metdata functions perform a single heap allocation for this metadata.
1042
1043
Useful if you want the data to persist beyond the lifetime of the drwav object.
1044
1045
You must free the data returned from this function using drwav_free().
1046
*/
1047
DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav);
1048
1049
/*
1050
Uninitializes the given drwav object.
1051
1052
Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()).
1053
*/
1054
DRWAV_API drwav_result drwav_uninit(drwav* pWav);
1055
1056
1057
/*
1058
Reads raw audio data.
1059
1060
This is the lowest level function for reading audio data. It simply reads the given number of
1061
bytes of the raw internal sample data.
1062
1063
Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for
1064
reading sample data in a consistent format.
1065
1066
pBufferOut can be NULL in which case a seek will be performed.
1067
1068
Returns the number of bytes actually read.
1069
*/
1070
DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
1071
1072
/*
1073
Reads up to the specified number of PCM frames from the WAV file.
1074
1075
The output data will be in the file's internal format, converted to native-endian byte order. Use
1076
drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format.
1077
1078
If the return value is less than <framesToRead> it means the end of the file has been reached or
1079
you have requested more PCM frames than can possibly fit in the output buffer.
1080
1081
This function will only work when sample data is of a fixed size and uncompressed. If you are
1082
using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32().
1083
1084
pBufferOut can be NULL in which case a seek will be performed.
1085
*/
1086
DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1087
DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1088
DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1089
1090
/*
1091
Seeks to the given PCM frame.
1092
1093
Returns true if successful; false otherwise.
1094
*/
1095
DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
1096
1097
/*
1098
Retrieves the current read position in pcm frames.
1099
*/
1100
DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor);
1101
1102
/*
1103
Retrieves the length of the file.
1104
*/
1105
DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength);
1106
1107
1108
/*
1109
Writes raw audio data.
1110
1111
Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error.
1112
*/
1113
DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
1114
1115
/*
1116
Writes PCM frames.
1117
1118
Returns the number of PCM frames written.
1119
1120
Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to
1121
little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion.
1122
*/
1123
DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1124
DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1125
DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1126
1127
/* Conversion Utilities */
1128
#ifndef DR_WAV_NO_CONVERSION_API
1129
1130
/*
1131
Reads a chunk of audio data and converts it to signed 16-bit PCM samples.
1132
1133
pBufferOut can be NULL in which case a seek will be performed.
1134
1135
Returns the number of PCM frames actually read.
1136
1137
If the return value is less than <framesToRead> it means the end of the file has been reached.
1138
*/
1139
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1140
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1141
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1142
1143
/* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */
1144
DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1145
1146
/* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */
1147
DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1148
1149
/* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */
1150
DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
1151
1152
/* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */
1153
DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
1154
1155
/* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */
1156
DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
1157
1158
/* Low-level function for converting A-law samples to signed 16-bit PCM samples. */
1159
DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1160
1161
/* Low-level function for converting u-law samples to signed 16-bit PCM samples. */
1162
DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1163
1164
1165
/*
1166
Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples.
1167
1168
pBufferOut can be NULL in which case a seek will be performed.
1169
1170
Returns the number of PCM frames actually read.
1171
1172
If the return value is less than <framesToRead> it means the end of the file has been reached.
1173
*/
1174
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1175
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1176
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1177
1178
/* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */
1179
DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1180
1181
/* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */
1182
DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
1183
1184
/* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */
1185
DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1186
1187
/* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */
1188
DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
1189
1190
/* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */
1191
DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
1192
1193
/* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */
1194
DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1195
1196
/* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */
1197
DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1198
1199
1200
/*
1201
Reads a chunk of audio data and converts it to signed 32-bit PCM samples.
1202
1203
pBufferOut can be NULL in which case a seek will be performed.
1204
1205
Returns the number of PCM frames actually read.
1206
1207
If the return value is less than <framesToRead> it means the end of the file has been reached.
1208
*/
1209
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1210
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1211
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1212
1213
/* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */
1214
DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1215
1216
/* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */
1217
DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
1218
1219
/* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */
1220
DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1221
1222
/* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */
1223
DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
1224
1225
/* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */
1226
DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
1227
1228
/* Low-level function for converting A-law samples to signed 32-bit PCM samples. */
1229
DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1230
1231
/* Low-level function for converting u-law samples to signed 32-bit PCM samples. */
1232
DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1233
1234
#endif  /* DR_WAV_NO_CONVERSION_API */
1235
1236
1237
/* High-Level Convenience Helpers */
1238
1239
#ifndef DR_WAV_NO_STDIO
1240
/*
1241
Helper for initializing a wave file for reading using stdio.
1242
1243
This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
1244
objects because the operating system may restrict the number of file handles an application can have open at
1245
any given time.
1246
*/
1247
DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
1248
DRWAV_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);
1249
DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
1250
DRWAV_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);
1251
DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1252
DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1253
1254
1255
/*
1256
Helper for initializing a wave file for writing using stdio.
1257
1258
This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
1259
objects because the operating system may restrict the number of file handles an application can have open at
1260
any given time.
1261
*/
1262
DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
1263
DRWAV_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);
1264
DRWAV_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);
1265
DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
1266
DRWAV_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);
1267
DRWAV_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);
1268
#endif  /* DR_WAV_NO_STDIO */
1269
1270
/*
1271
Helper for initializing a loader from a pre-allocated memory buffer.
1272
1273
This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
1274
the lifetime of the drwav object.
1275
1276
The buffer should contain the contents of the entire wave file, not just the sample data.
1277
*/
1278
DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
1279
DRWAV_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);
1280
DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void* data, size_t dataSize, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1281
1282
/*
1283
Helper for initializing a writer which outputs data to a memory buffer.
1284
1285
dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
1286
1287
The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid
1288
until after drwav_uninit() has been called.
1289
*/
1290
DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
1291
DRWAV_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);
1292
DRWAV_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);
1293
1294
1295
#ifndef DR_WAV_NO_CONVERSION_API
1296
/*
1297
Opens and reads an entire wav file in a single operation.
1298
1299
The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1300
*/
1301
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1302
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1303
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1304
#ifndef DR_WAV_NO_STDIO
1305
/*
1306
Opens and decodes an entire wav file in a single operation.
1307
1308
The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1309
*/
1310
DRWAV_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);
1311
DRWAV_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);
1312
DRWAV_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);
1313
DRWAV_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);
1314
DRWAV_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);
1315
DRWAV_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);
1316
#endif
1317
/*
1318
Opens and decodes an entire wav file from a block of memory in a single operation.
1319
1320
The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1321
*/
1322
DRWAV_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);
1323
DRWAV_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);
1324
DRWAV_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);
1325
#endif
1326
1327
/* Frees data that was allocated internally by dr_wav. */
1328
DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
1329
1330
/* Converts bytes from a wav stream to a sized type of native endian. */
1331
DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data);
1332
DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data);
1333
DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data);
1334
DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data);
1335
DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data);
1336
DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data);
1337
DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data);
1338
1339
/* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */
1340
DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
1341
1342
/* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */
1343
DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
1344
1345
#ifdef __cplusplus
1346
}
1347
#endif
1348
#endif  /* dr_wav_h */
1349
1350
1351
/************************************************************************************************************************************************************
1352
 ************************************************************************************************************************************************************
1353
1354
 IMPLEMENTATION
1355
1356
 ************************************************************************************************************************************************************
1357
 ************************************************************************************************************************************************************/
1358
#if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
1359
#ifndef dr_wav_c
1360
#define dr_wav_c
1361
1362
#ifdef __MRC__
1363
/* MrC currently doesn't compile dr_wav correctly with any optimizations enabled. */
1364
#pragma options opt off
1365
#endif
1366
1367
#include <stdlib.h>
1368
#include <string.h>
1369
#include <limits.h> /* For INT_MAX */
1370
1371
#ifndef DR_WAV_NO_STDIO
1372
#include <stdio.h>
1373
#ifndef DR_WAV_NO_WCHAR
1374
#include <wchar.h>
1375
#endif
1376
#endif
1377
1378
/* Standard library stuff. */
1379
#ifndef DRWAV_ASSERT
1380
#include <assert.h>
1381
12.6M
#define DRWAV_ASSERT(expression)           assert(expression)
1382
#endif
1383
#ifndef DRWAV_MALLOC
1384
0
#define DRWAV_MALLOC(sz)                   malloc((sz))
1385
#endif
1386
#ifndef DRWAV_REALLOC
1387
0
#define DRWAV_REALLOC(p, sz)               realloc((p), (sz))
1388
#endif
1389
#ifndef DRWAV_FREE
1390
0
#define DRWAV_FREE(p)                      free((p))
1391
#endif
1392
#ifndef DRWAV_COPY_MEMORY
1393
3.79M
#define DRWAV_COPY_MEMORY(dst, src, sz)    memcpy((dst), (src), (sz))
1394
#endif
1395
#ifndef DRWAV_ZERO_MEMORY
1396
16.7k
#define DRWAV_ZERO_MEMORY(p, sz)           memset((p), 0, (sz))
1397
#endif
1398
#ifndef DRWAV_ZERO_OBJECT
1399
4.51k
#define DRWAV_ZERO_OBJECT(p)               DRWAV_ZERO_MEMORY((p), sizeof(*p))
1400
#endif
1401
1402
30.5M
#define drwav_countof(x)                   (sizeof(x) / sizeof(x[0]))
1403
#define drwav_align(x, a)                  ((((x) + (a) - 1) / (a)) * (a))
1404
8.43k
#define drwav_min(a, b)                    (((a) < (b)) ? (a) : (b))
1405
49.5M
#define drwav_max(a, b)                    (((a) > (b)) ? (a) : (b))
1406
24.7M
#define drwav_clamp(x, lo, hi)             (drwav_max((lo), drwav_min((hi), (x))))
1407
0
#define drwav_offset_ptr(p, offset)        (((drwav_uint8*)(p)) + (offset))
1408
1409
#define DRWAV_MAX_SIMD_VECTOR_SIZE         32
1410
1411
/* Architecture Detection */
1412
#if defined(__x86_64__) || (defined(_M_X64) && !defined(_M_ARM64EC))
1413
    #define DRWAV_X64
1414
#elif defined(__i386) || defined(_M_IX86)
1415
    #define DRWAV_X86
1416
#elif defined(__arm__) || defined(_M_ARM)
1417
    #define DRWAV_ARM
1418
#endif
1419
/* End Architecture Detection */
1420
1421
/* Inline */
1422
#ifdef _MSC_VER
1423
    #define DRWAV_INLINE __forceinline
1424
#elif defined(__GNUC__)
1425
    /*
1426
    I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
1427
    the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
1428
    case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
1429
    command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
1430
    I am using "__inline__" only when we're compiling in strict ANSI mode.
1431
    */
1432
    #if defined(__STRICT_ANSI__)
1433
        #define DRWAV_GNUC_INLINE_HINT __inline__
1434
    #else
1435
        #define DRWAV_GNUC_INLINE_HINT inline
1436
    #endif
1437
1438
    #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__)
1439
        #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT __attribute__((always_inline))
1440
    #else
1441
        #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT
1442
    #endif
1443
#elif defined(__WATCOMC__)
1444
    #define DRWAV_INLINE __inline
1445
#else
1446
    #define DRWAV_INLINE
1447
#endif
1448
/* End Inline */
1449
1450
/* SIZE_MAX */
1451
#if defined(SIZE_MAX)
1452
16.4k
    #define DRWAV_SIZE_MAX  SIZE_MAX
1453
#else
1454
    #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
1455
        #define DRWAV_SIZE_MAX  ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
1456
    #else
1457
        #define DRWAV_SIZE_MAX  0xFFFFFFFF
1458
    #endif
1459
#endif
1460
/* End SIZE_MAX */
1461
1462
/* Weird bit manipulation is for C89 compatibility (no direct support for 64-bit integers). */
1463
30
#define DRWAV_INT64_MIN ((drwav_int64) ((drwav_uint64)0x80000000 << 32))
1464
119
#define DRWAV_INT64_MAX ((drwav_int64)(((drwav_uint64)0x7FFFFFFF << 32) | 0xFFFFFFFF))
1465
1466
#if defined(_MSC_VER) && _MSC_VER >= 1400
1467
    #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1468
    #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1469
    #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1470
#elif defined(__clang__)
1471
    #if defined(__has_builtin)
1472
        #if __has_builtin(__builtin_bswap16)
1473
            #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1474
        #endif
1475
        #if __has_builtin(__builtin_bswap32)
1476
            #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1477
        #endif
1478
        #if __has_builtin(__builtin_bswap64)
1479
            #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1480
        #endif
1481
    #endif
1482
#elif defined(__GNUC__)
1483
    #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
1484
        #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1485
        #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1486
    #endif
1487
    #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
1488
        #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1489
    #endif
1490
#endif
1491
1492
DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision)
1493
0
{
1494
0
    if (pMajor) {
1495
0
        *pMajor = DRWAV_VERSION_MAJOR;
1496
0
    }
1497
1498
0
    if (pMinor) {
1499
0
        *pMinor = DRWAV_VERSION_MINOR;
1500
0
    }
1501
1502
0
    if (pRevision) {
1503
0
        *pRevision = DRWAV_VERSION_REVISION;
1504
0
    }
1505
0
}
1506
1507
DRWAV_API const char* drwav_version_string(void)
1508
0
{
1509
0
    return DRWAV_VERSION_STRING;
1510
0
}
1511
1512
/*
1513
These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are
1514
you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation.
1515
*/
1516
#ifndef DRWAV_MAX_SAMPLE_RATE
1517
2.33k
#define DRWAV_MAX_SAMPLE_RATE       384000
1518
#endif
1519
#ifndef DRWAV_MAX_CHANNELS
1520
2.28k
#define DRWAV_MAX_CHANNELS          256
1521
#endif
1522
#ifndef DRWAV_MAX_BITS_PER_SAMPLE
1523
2.25k
#define DRWAV_MAX_BITS_PER_SAMPLE   64
1524
#endif
1525
1526
static 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 */
1527
static 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 */
1528
/*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 */
1529
static 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 */
1530
static 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 */
1531
static 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 */
1532
/*static 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 */
1533
1534
1535
static DRWAV_INLINE int drwav__is_little_endian(void)
1536
226k
{
1537
226k
#if defined(DRWAV_X86) || defined(DRWAV_X64)
1538
226k
    return DRWAV_TRUE;
1539
#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
1540
    return DRWAV_TRUE;
1541
#else
1542
    int n = 1;
1543
    return (*(char*)&n) == 1;
1544
#endif
1545
226k
}
1546
1547
1548
static DRWAV_INLINE void drwav_bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid)
1549
4
{
1550
4
    int i;
1551
68
    for (i = 0; i < 16; ++i) {
1552
64
        guid[i] = data[i];
1553
64
    }
1554
4
}
1555
1556
1557
static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n)
1558
3.08k
{
1559
3.08k
#ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC
1560
    #if defined(_MSC_VER)
1561
        return _byteswap_ushort(n);
1562
    #elif defined(__GNUC__) || defined(__clang__)
1563
        return __builtin_bswap16(n);
1564
    #else
1565
        #error "This compiler does not support the byte swap intrinsic."
1566
    #endif
1567
#else
1568
    return ((n & 0xFF00) >> 8) |
1569
           ((n & 0x00FF) << 8);
1570
#endif
1571
3.08k
}
1572
1573
static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n)
1574
480k
{
1575
480k
#ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC
1576
    #if defined(_MSC_VER)
1577
        return _byteswap_ulong(n);
1578
    #elif defined(__GNUC__) || defined(__clang__)
1579
        #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. */
1580
            /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
1581
            drwav_uint32 r;
1582
            __asm__ __volatile__ (
1583
            #if defined(DRWAV_64BIT)
1584
                "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! */
1585
            #else
1586
                "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
1587
            #endif
1588
            );
1589
            return r;
1590
        #else
1591
480k
            return __builtin_bswap32(n);
1592
480k
        #endif
1593
    #else
1594
        #error "This compiler does not support the byte swap intrinsic."
1595
    #endif
1596
#else
1597
    return ((n & 0xFF000000) >> 24) |
1598
           ((n & 0x00FF0000) >>  8) |
1599
           ((n & 0x0000FF00) <<  8) |
1600
           ((n & 0x000000FF) << 24);
1601
#endif
1602
480k
}
1603
1604
static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
1605
244k
{
1606
244k
#ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC
1607
    #if defined(_MSC_VER)
1608
        return _byteswap_uint64(n);
1609
    #elif defined(__GNUC__) || defined(__clang__)
1610
        return __builtin_bswap64(n);
1611
    #else
1612
        #error "This compiler does not support the byte swap intrinsic."
1613
    #endif
1614
#else
1615
    /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
1616
    return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) |
1617
           ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) |
1618
           ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) |
1619
           ((n & ((drwav_uint64)0x000000FF << 32)) >>  8) |
1620
           ((n & ((drwav_uint64)0xFF000000      )) <<  8) |
1621
           ((n & ((drwav_uint64)0x00FF0000      )) << 24) |
1622
           ((n & ((drwav_uint64)0x0000FF00      )) << 40) |
1623
           ((n & ((drwav_uint64)0x000000FF      )) << 56);
1624
#endif
1625
244k
}
1626
1627
1628
static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
1629
3.08k
{
1630
3.08k
    return (drwav_int16)drwav__bswap16((drwav_uint16)n);
1631
3.08k
}
1632
1633
static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount)
1634
8
{
1635
8
    drwav_uint64 iSample;
1636
3.08k
    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1637
3.08k
        pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]);
1638
3.08k
    }
1639
8
}
1640
1641
1642
static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p)
1643
259k
{
1644
259k
    drwav_uint8 t;
1645
259k
    t = p[0];
1646
259k
    p[0] = p[2];
1647
259k
    p[2] = t;
1648
259k
}
1649
1650
static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount)
1651
317
{
1652
317
    drwav_uint64 iSample;
1653
259k
    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1654
259k
        drwav_uint8* pSample = pSamples + (iSample*3);
1655
259k
        drwav__bswap_s24(pSample);
1656
259k
    }
1657
317
}
1658
1659
1660
static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n)
1661
480k
{
1662
480k
    return (drwav_int32)drwav__bswap32((drwav_uint32)n);
1663
480k
}
1664
1665
static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount)
1666
552
{
1667
552
    drwav_uint64 iSample;
1668
481k
    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1669
480k
        pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]);
1670
480k
    }
1671
552
}
1672
1673
1674
static DRWAV_INLINE drwav_int64 drwav__bswap_s64(drwav_int64 n)
1675
244k
{
1676
244k
    return (drwav_int64)drwav__bswap64((drwav_uint64)n);
1677
244k
}
1678
1679
static DRWAV_INLINE void drwav__bswap_samples_s64(drwav_int64* pSamples, drwav_uint64 sampleCount)
1680
539
{
1681
539
    drwav_uint64 iSample;
1682
245k
    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1683
244k
        pSamples[iSample] = drwav__bswap_s64(pSamples[iSample]);
1684
244k
    }
1685
539
}
1686
1687
1688
static DRWAV_INLINE float drwav__bswap_f32(float n)
1689
0
{
1690
0
    union {
1691
0
        drwav_uint32 i;
1692
0
        float f;
1693
0
    } x;
1694
0
    x.f = n;
1695
0
    x.i = drwav__bswap32(x.i);
1696
1697
0
    return x.f;
1698
0
}
1699
1700
static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount)
1701
0
{
1702
0
    drwav_uint64 iSample;
1703
0
    for (iSample = 0; iSample < sampleCount; iSample += 1) {
1704
0
        pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]);
1705
0
    }
1706
0
}
1707
1708
1709
static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1710
2.10k
{
1711
2.10k
    switch (bytesPerSample)
1712
2.10k
    {
1713
670
        case 1:
1714
670
        {
1715
            /* No-op. */
1716
670
        } break;
1717
8
        case 2:
1718
8
        {
1719
8
            drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1720
8
        } break;
1721
317
        case 3:
1722
317
        {
1723
317
            drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount);
1724
317
        } break;
1725
552
        case 4:
1726
552
        {
1727
552
            drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount);
1728
552
        } break;
1729
539
        case 8:
1730
539
        {
1731
539
            drwav__bswap_samples_s64((drwav_int64*)pSamples, sampleCount);
1732
539
        } break;
1733
20
        default:
1734
20
        {
1735
20
            drwav_uint64 iSample;
1736
1737
7.44k
            for (iSample = 0; iSample < sampleCount; iSample += 1) {
1738
7.42k
                drwav_uint8* pSample = (drwav_uint8*)pSamples + (iSample * bytesPerSample);
1739
7.42k
                drwav_uint32 iByte;
1740
1741
22.2k
                for (iByte = 0; iByte < bytesPerSample / 2; iByte += 1) {
1742
14.8k
                    drwav_uint8 temp = pSample[iByte];
1743
14.8k
                    pSample[iByte] = pSample[bytesPerSample - iByte - 1];
1744
14.8k
                    pSample[bytesPerSample - iByte - 1] = temp;
1745
14.8k
                }
1746
7.42k
            }
1747
20
        } break;
1748
2.10k
    }
1749
2.10k
}
1750
1751
1752
1753
DRWAV_PRIVATE DRWAV_INLINE drwav_bool32 drwav_is_container_be(drwav_container container)
1754
47.8k
{
1755
47.8k
    if (container == drwav_container_rifx || container == drwav_container_aiff) {
1756
15.8k
        return DRWAV_TRUE;
1757
32.0k
    } else {
1758
32.0k
        return DRWAV_FALSE;
1759
32.0k
    }
1760
47.8k
}
1761
1762
1763
DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_le(const drwav_uint8* data)
1764
10.4k
{
1765
10.4k
    return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8);
1766
10.4k
}
1767
1768
DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_be(const drwav_uint8* data)
1769
3.75k
{
1770
3.75k
    return ((drwav_uint16)data[1] << 0) | ((drwav_uint16)data[0] << 8);
1771
3.75k
}
1772
1773
DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_ex(const drwav_uint8* data, drwav_container container)
1774
14.2k
{
1775
14.2k
    if (drwav_is_container_be(container)) {
1776
3.75k
        return drwav_bytes_to_u16_be(data);
1777
10.4k
    } else {
1778
10.4k
        return drwav_bytes_to_u16_le(data);
1779
10.4k
    }
1780
14.2k
}
1781
1782
1783
DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_le(const drwav_uint8* data)
1784
15.9k
{
1785
15.9k
    return ((drwav_uint32)data[0] << 0) | ((drwav_uint32)data[1] << 8) | ((drwav_uint32)data[2] << 16) | ((drwav_uint32)data[3] << 24);
1786
15.9k
}
1787
1788
DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_be(const drwav_uint8* data)
1789
11.3k
{
1790
11.3k
    return ((drwav_uint32)data[3] << 0) | ((drwav_uint32)data[2] << 8) | ((drwav_uint32)data[1] << 16) | ((drwav_uint32)data[0] << 24);
1791
11.3k
}
1792
1793
DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_ex(const drwav_uint8* data, drwav_container container)
1794
25.0k
{
1795
25.0k
    if (drwav_is_container_be(container)) {
1796
9.95k
        return drwav_bytes_to_u32_be(data);
1797
15.1k
    } else {
1798
15.1k
        return drwav_bytes_to_u32_le(data);
1799
15.1k
    }
1800
25.0k
}
1801
1802
1803
1804
DRWAV_PRIVATE drwav_int64 drwav_aiff_extented_to_s64(const drwav_uint8* data)
1805
1.25k
{
1806
1.25k
    drwav_uint32 exponent = ((drwav_uint32)data[0] << 8) | data[1];
1807
1.25k
    drwav_uint64 hi = ((drwav_uint64)data[2] << 24) | ((drwav_uint64)data[3] << 16) | ((drwav_uint64)data[4] <<  8) | ((drwav_uint64)data[5] <<  0);
1808
1.25k
    drwav_uint64 lo = ((drwav_uint64)data[6] << 24) | ((drwav_uint64)data[7] << 16) | ((drwav_uint64)data[8] <<  8) | ((drwav_uint64)data[9] <<  0);
1809
1.25k
    drwav_uint64 significand = (hi << 32) | lo;
1810
1.25k
    int sign = exponent >> 15;
1811
1812
    /* Remove sign bit. */
1813
1.25k
    exponent &= 0x7FFF;
1814
1815
    /* Special cases. */
1816
1.25k
    if (exponent == 0 && significand == 0) {
1817
144
        return 0;
1818
1.11k
    } else if (exponent == 0x7FFF) {
1819
1
        return sign ? DRWAV_INT64_MIN : DRWAV_INT64_MAX;    /* Infinite. */
1820
1
    }
1821
1822
1.11k
    exponent -= 16383;
1823
1824
1.11k
    if (exponent > 63) {
1825
148
        return sign ? DRWAV_INT64_MIN : DRWAV_INT64_MAX;    /* Too big for a 64-bit integer. */
1826
963
    } else if (exponent < 1) {
1827
55
        return 0;  /* Number is less than 1, so rounds down to 0. */
1828
55
    }
1829
1830
908
    significand >>= (63 - exponent);
1831
1832
908
    if (sign) {
1833
104
        return -(drwav_int64)significand;
1834
804
    } else {
1835
804
        return  (drwav_int64)significand;
1836
804
    }
1837
908
}
1838
1839
1840
DRWAV_PRIVATE void* drwav__malloc_default(size_t sz, void* pUserData)
1841
0
{
1842
0
    (void)pUserData;
1843
0
    return DRWAV_MALLOC(sz);
1844
0
}
1845
1846
DRWAV_PRIVATE void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
1847
0
{
1848
0
    (void)pUserData;
1849
0
    return DRWAV_REALLOC(p, sz);
1850
0
}
1851
1852
DRWAV_PRIVATE void drwav__free_default(void* p, void* pUserData)
1853
0
{
1854
0
    (void)pUserData;
1855
0
    DRWAV_FREE(p);
1856
0
}
1857
1858
1859
DRWAV_PRIVATE void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
1860
0
{
1861
0
    if (pAllocationCallbacks == NULL) {
1862
0
        return NULL;
1863
0
    }
1864
1865
0
    if (pAllocationCallbacks->onMalloc != NULL) {
1866
0
        return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
1867
0
    }
1868
1869
    /* Try using realloc(). */
1870
0
    if (pAllocationCallbacks->onRealloc != NULL) {
1871
0
        return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
1872
0
    }
1873
1874
0
    return NULL;
1875
0
}
1876
1877
DRWAV_PRIVATE void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
1878
0
{
1879
0
    if (pAllocationCallbacks == NULL) {
1880
0
        return NULL;
1881
0
    }
1882
1883
0
    if (pAllocationCallbacks->onRealloc != NULL) {
1884
0
        return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
1885
0
    }
1886
1887
    /* Try emulating realloc() in terms of malloc()/free(). */
1888
0
    if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
1889
0
        void* p2;
1890
1891
0
        p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
1892
0
        if (p2 == NULL) {
1893
0
            return NULL;
1894
0
        }
1895
1896
0
        if (p != NULL) {
1897
0
            DRWAV_COPY_MEMORY(p2, p, szOld);
1898
0
            pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1899
0
        }
1900
1901
0
        return p2;
1902
0
    }
1903
1904
0
    return NULL;
1905
0
}
1906
1907
DRWAV_PRIVATE void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
1908
2.20k
{
1909
2.20k
    if (p == NULL || pAllocationCallbacks == NULL) {
1910
2.20k
        return;
1911
2.20k
    }
1912
1913
0
    if (pAllocationCallbacks->onFree != NULL) {
1914
0
        pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1915
0
    }
1916
0
}
1917
1918
1919
DRWAV_PRIVATE drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
1920
4.51k
{
1921
4.51k
    if (pAllocationCallbacks != NULL) {
1922
        /* Copy. */
1923
0
        return *pAllocationCallbacks;
1924
4.51k
    } else {
1925
        /* Defaults. */
1926
4.51k
        drwav_allocation_callbacks allocationCallbacks;
1927
4.51k
        allocationCallbacks.pUserData = NULL;
1928
4.51k
        allocationCallbacks.onMalloc  = drwav__malloc_default;
1929
4.51k
        allocationCallbacks.onRealloc = drwav__realloc_default;
1930
4.51k
        allocationCallbacks.onFree    = drwav__free_default;
1931
4.51k
        return allocationCallbacks;
1932
4.51k
    }
1933
4.51k
}
1934
1935
1936
static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
1937
10.7k
{
1938
10.7k
    return
1939
10.7k
        formatTag == DR_WAVE_FORMAT_ADPCM ||
1940
9.94k
        formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
1941
10.7k
}
1942
1943
DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
1944
15.3k
{
1945
15.3k
    return (unsigned int)(chunkSize % 2);
1946
15.3k
}
1947
1948
DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
1949
0
{
1950
0
    return (unsigned int)(chunkSize % 8);
1951
0
}
1952
1953
DRWAV_PRIVATE unsigned int drwav_calculate_padding_size(drwav_container container, drwav_uint64 chunkSize)
1954
0
{
1955
0
    if (container == drwav_container_riff || container == drwav_container_rf64) {
1956
0
        return drwav__chunk_padding_size_riff(chunkSize);
1957
0
    } else {
1958
0
        return drwav__chunk_padding_size_w64(chunkSize);
1959
0
    }
1960
0
}
1961
1962
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1963
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1964
DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
1965
1966
DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
1967
15.4k
{
1968
15.4k
    if (container == drwav_container_riff || container == drwav_container_rifx || container == drwav_container_rf64 || container == drwav_container_aiff) {
1969
15.4k
        drwav_uint8 sizeInBytes[4];
1970
1971
15.4k
        if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
1972
117
            return DRWAV_AT_END;
1973
117
        }
1974
1975
15.3k
        if (onRead(pUserData, sizeInBytes, 4) != 4) {
1976
34
            return DRWAV_INVALID_FILE;
1977
34
        }
1978
1979
15.3k
        pHeaderOut->sizeInBytes = drwav_bytes_to_u32_ex(sizeInBytes, container);
1980
15.3k
        pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes);
1981
1982
15.3k
        *pRunningBytesReadOut += 8;
1983
15.3k
    } else if (container == drwav_container_w64) {
1984
0
        drwav_uint8 sizeInBytes[8];
1985
1986
0
        if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
1987
0
            return DRWAV_AT_END;
1988
0
        }
1989
1990
0
        if (onRead(pUserData, sizeInBytes, 8) != 8) {
1991
0
            return DRWAV_INVALID_FILE;
1992
0
        }
1993
1994
0
        pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes);
1995
1996
        /* Subtract 24 from the size because with w64 the reported chunk size includes the size of the header itself. */
1997
0
        if (pHeaderOut->sizeInBytes >= 24) {
1998
0
            pHeaderOut->sizeInBytes -= 24;
1999
0
        } else {
2000
0
            return DRWAV_INVALID_FILE;
2001
0
        }
2002
2003
0
        pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
2004
0
        *pRunningBytesReadOut += 24;
2005
0
    } else {
2006
0
        return DRWAV_INVALID_FILE;
2007
0
    }
2008
2009
15.3k
    return DRWAV_SUCCESS;
2010
15.4k
}
2011
2012
DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
2013
10.1k
{
2014
10.1k
    drwav_uint64 bytesRemainingToSeek = offset;
2015
13.8k
    while (bytesRemainingToSeek > 0) {
2016
4.47k
        if (bytesRemainingToSeek > 0x7FFFFFFF) {
2017
213
            if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_CUR)) {
2018
213
                return DRWAV_FALSE;
2019
213
            }
2020
0
            bytesRemainingToSeek -= 0x7FFFFFFF;
2021
4.26k
        } else {
2022
4.26k
            if (!onSeek(pUserData, (int)bytesRemainingToSeek, DRWAV_SEEK_CUR)) {
2023
541
                return DRWAV_FALSE;
2024
541
            }
2025
3.72k
            bytesRemainingToSeek = 0;
2026
3.72k
        }
2027
4.47k
    }
2028
2029
9.41k
    return DRWAV_TRUE;
2030
10.1k
}
2031
2032
DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
2033
4.43k
{
2034
4.43k
    if (offset <= 0x7FFFFFFF) {
2035
4.42k
        return onSeek(pUserData, (int)offset, DRWAV_SEEK_SET);
2036
4.42k
    }
2037
2038
    /* Larger than 32-bit seek. */
2039
8
    if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_SET)) {
2040
8
        return DRWAV_FALSE;
2041
8
    }
2042
0
    offset -= 0x7FFFFFFF;
2043
2044
0
    for (;;) {
2045
0
        if (offset <= 0x7FFFFFFF) {
2046
0
            return onSeek(pUserData, (int)offset, DRWAV_SEEK_CUR);
2047
0
        }
2048
2049
0
        if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_CUR)) {
2050
0
            return DRWAV_FALSE;
2051
0
        }
2052
0
        offset -= 0x7FFFFFFF;
2053
0
    }
2054
2055
    /* Should never get here. */
2056
    /*return DRWAV_TRUE; */
2057
0
}
2058
2059
2060
2061
DRWAV_PRIVATE size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
2062
17.5k
{
2063
17.5k
    size_t bytesRead;
2064
2065
17.5k
    DRWAV_ASSERT(onRead != NULL);
2066
17.5k
    DRWAV_ASSERT(pCursor != NULL);
2067
2068
17.5k
    bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
2069
17.5k
    *pCursor += bytesRead;
2070
17.5k
    return bytesRead;
2071
17.5k
}
2072
2073
#if 0
2074
DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
2075
{
2076
    DRWAV_ASSERT(onSeek != NULL);
2077
    DRWAV_ASSERT(pCursor != NULL);
2078
2079
    if (!onSeek(pUserData, offset, origin)) {
2080
        return DRWAV_FALSE;
2081
    }
2082
2083
    if (origin == DRWAV_SEEK_SET) {
2084
        *pCursor = offset;
2085
    } else {
2086
        *pCursor += offset;
2087
    }
2088
2089
    return DRWAV_TRUE;
2090
}
2091
#endif
2092
2093
2094
0
#define DRWAV_SMPL_BYTES                    36
2095
0
#define DRWAV_SMPL_LOOP_BYTES               24
2096
0
#define DRWAV_INST_BYTES                    7
2097
0
#define DRWAV_ACID_BYTES                    24
2098
0
#define DRWAV_CUE_BYTES                     4
2099
0
#define DRWAV_BEXT_BYTES                    602
2100
0
#define DRWAV_BEXT_DESCRIPTION_BYTES        256
2101
0
#define DRWAV_BEXT_ORIGINATOR_NAME_BYTES    32
2102
0
#define DRWAV_BEXT_ORIGINATOR_REF_BYTES     32
2103
#define DRWAV_BEXT_RESERVED_BYTES           180
2104
0
#define DRWAV_BEXT_UMID_BYTES               64
2105
0
#define DRWAV_CUE_POINT_BYTES               24
2106
0
#define DRWAV_LIST_LABEL_OR_NOTE_BYTES      4
2107
0
#define DRWAV_LIST_LABELLED_TEXT_BYTES      20
2108
2109
0
#define DRWAV_METADATA_ALIGNMENT            8
2110
2111
typedef enum
2112
{
2113
    drwav__metadata_parser_stage_count,
2114
    drwav__metadata_parser_stage_read
2115
} drwav__metadata_parser_stage;
2116
2117
typedef struct
2118
{
2119
    drwav_read_proc onRead;
2120
    drwav_seek_proc onSeek;
2121
    void *pReadSeekUserData;
2122
    drwav__metadata_parser_stage stage;
2123
    drwav_metadata *pMetadata;
2124
    drwav_uint32 metadataCount;
2125
    drwav_uint8 *pData;
2126
    drwav_uint8 *pDataCursor;
2127
    drwav_uint64 metadataCursor;
2128
    drwav_uint64 extraCapacity;
2129
} drwav__metadata_parser;
2130
2131
DRWAV_PRIVATE size_t drwav__metadata_memory_capacity(drwav__metadata_parser* pParser)
2132
0
{
2133
0
    drwav_uint64 cap = sizeof(drwav_metadata) * (drwav_uint64)pParser->metadataCount + pParser->extraCapacity;
2134
0
    if (cap > DRWAV_SIZE_MAX) {
2135
0
        return 0;   /* Too big. */
2136
0
    }
2137
2138
0
    return (size_t)cap; /* Safe cast thanks to the check above. */
2139
0
}
2140
2141
DRWAV_PRIVATE drwav_uint8* drwav__metadata_get_memory(drwav__metadata_parser* pParser, size_t size, size_t align)
2142
0
{
2143
0
    drwav_uint8* pResult;
2144
2145
0
    if (align) {
2146
0
        drwav_uintptr modulo = (drwav_uintptr)pParser->pDataCursor % align;
2147
0
        if (modulo != 0) {
2148
0
            pParser->pDataCursor += align - modulo;
2149
0
        }
2150
0
    }
2151
2152
0
    pResult = pParser->pDataCursor;
2153
2154
    /*
2155
    Getting to the point where this function is called means there should always be memory
2156
    available. Out of memory checks should have been done at an earlier stage.
2157
    */
2158
0
    DRWAV_ASSERT((pResult + size) <= (pParser->pData + drwav__metadata_memory_capacity(pParser)));
2159
2160
0
    pParser->pDataCursor += size;
2161
0
    return pResult;
2162
0
}
2163
2164
DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metadata_parser* pParser, size_t bytes, size_t align)
2165
0
{
2166
0
    size_t extra = bytes + (align ? (align - 1) : 0);
2167
0
    pParser->extraCapacity += extra;
2168
0
}
2169
2170
DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks)
2171
0
{
2172
0
    if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) {
2173
0
        pAllocationCallbacks->onFree(pParser->pData, pAllocationCallbacks->pUserData);
2174
2175
0
        pParser->pData = (drwav_uint8*)pAllocationCallbacks->onMalloc(drwav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData);
2176
0
        pParser->pDataCursor = pParser->pData;
2177
2178
0
        if (pParser->pData == NULL) {
2179
0
            return DRWAV_OUT_OF_MEMORY;
2180
0
        }
2181
2182
        /*
2183
        We don't need to worry about specifying an alignment here because malloc always returns something
2184
        of suitable alignment. This also means pParser->pMetadata is all that we need to store in order
2185
        for us to free when we are done.
2186
        */
2187
0
        pParser->pMetadata = (drwav_metadata*)drwav__metadata_get_memory(pParser, sizeof(drwav_metadata) * pParser->metadataCount, 1);
2188
0
        pParser->metadataCursor = 0;
2189
0
    }
2190
2191
0
    return DRWAV_SUCCESS;
2192
0
}
2193
2194
DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
2195
0
{
2196
0
    if (pCursor != NULL) {
2197
0
        return drwav__on_read(pParser->onRead, pParser->pReadSeekUserData, pBufferOut, bytesToRead, pCursor);
2198
0
    } else {
2199
0
        return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead);
2200
0
    }
2201
0
}
2202
2203
DRWAV_PRIVATE drwav_bool32 drwav__metadata_validate_smpl_chunk(const drwav_chunk_header* pChunkHeader, drwav_uint32 loopCount, drwav_uint32 samplerSpecificDataSizeInBytes, drwav_uint64* pTrailingDataSizeInBytes)
2204
0
{
2205
0
    drwav_uint64 remainingDataSizeInBytes;
2206
2207
0
    DRWAV_ASSERT(pChunkHeader != NULL);
2208
2209
0
    if (pChunkHeader->sizeInBytes < DRWAV_SMPL_BYTES) {
2210
0
        return DRWAV_FALSE;
2211
0
    }
2212
2213
0
    remainingDataSizeInBytes = pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES;
2214
0
    if ((drwav_uint64)loopCount > remainingDataSizeInBytes / DRWAV_SMPL_LOOP_BYTES) {
2215
0
        return DRWAV_FALSE;
2216
0
    }
2217
2218
0
    remainingDataSizeInBytes -= (drwav_uint64)loopCount * DRWAV_SMPL_LOOP_BYTES;
2219
0
    if ((drwav_uint64)samplerSpecificDataSizeInBytes > remainingDataSizeInBytes) {
2220
0
        return DRWAV_FALSE;
2221
0
    }
2222
2223
0
    if (pTrailingDataSizeInBytes != NULL) {
2224
0
        *pTrailingDataSizeInBytes = remainingDataSizeInBytes - samplerSpecificDataSizeInBytes;
2225
0
    }
2226
2227
0
    return DRWAV_TRUE;
2228
0
}
2229
2230
DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata)
2231
0
{
2232
0
    drwav_uint8 smplHeaderData[DRWAV_SMPL_BYTES];
2233
0
    drwav_uint64 totalBytesRead = 0;
2234
0
    size_t bytesJustRead;
2235
2236
0
    if (pMetadata == NULL) {
2237
0
        return 0;
2238
0
    }
2239
2240
0
    bytesJustRead = drwav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead);
2241
2242
0
    DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2243
0
    DRWAV_ASSERT(pChunkHeader != NULL);
2244
2245
0
    if (pMetadata != NULL && bytesJustRead == sizeof(smplHeaderData)) {
2246
0
        drwav_uint32 iSampleLoop;
2247
0
        drwav_uint32 loopCount;
2248
0
        drwav_uint32 samplerSpecificDataSizeInBytes;
2249
0
        drwav_uint64 trailingDataSizeInBytes;
2250
2251
        /*
2252
        When we calculated the amount of memory required for the "smpl" chunk we excluded the chunk entirely
2253
        if its loop or sampler-specific data exceeded the chunk size. When this happens, the second stage will
2254
        still hit this path but the `pMetadata` will either point at the end of the allocation or at another
2255
        chunk. We need to repeat the validation before dereferencing the pMetadata object.
2256
        */
2257
0
        loopCount = drwav_bytes_to_u32(smplHeaderData + 28);
2258
0
        samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(smplHeaderData + 32);
2259
0
        if (!drwav__metadata_validate_smpl_chunk(pChunkHeader, loopCount, samplerSpecificDataSizeInBytes, &trailingDataSizeInBytes)) {
2260
0
            return totalBytesRead;
2261
0
        }
2262
2263
0
        pMetadata->type                                     = drwav_metadata_type_smpl;
2264
0
        pMetadata->data.smpl.manufacturerId                 = drwav_bytes_to_u32(smplHeaderData + 0);
2265
0
        pMetadata->data.smpl.productId                      = drwav_bytes_to_u32(smplHeaderData + 4);
2266
0
        pMetadata->data.smpl.samplePeriodNanoseconds        = drwav_bytes_to_u32(smplHeaderData + 8);
2267
0
        pMetadata->data.smpl.midiUnityNote                  = drwav_bytes_to_u32(smplHeaderData + 12);
2268
0
        pMetadata->data.smpl.midiPitchFraction              = drwav_bytes_to_u32(smplHeaderData + 16);
2269
0
        pMetadata->data.smpl.smpteFormat                    = drwav_bytes_to_u32(smplHeaderData + 20);
2270
0
        pMetadata->data.smpl.smpteOffset                    = drwav_bytes_to_u32(smplHeaderData + 24);
2271
0
        pMetadata->data.smpl.sampleLoopCount                = loopCount;
2272
0
        pMetadata->data.smpl.samplerSpecificDataSizeInBytes = samplerSpecificDataSizeInBytes;
2273
2274
0
        pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT);
2275
2276
0
        for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) {
2277
0
            drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES];
2278
0
            bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead);
2279
2280
0
            if (bytesJustRead == sizeof(smplLoopData)) {
2281
0
                pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId        = drwav_bytes_to_u32(smplLoopData + 0);
2282
0
                pMetadata->data.smpl.pLoops[iSampleLoop].type              = drwav_bytes_to_u32(smplLoopData + 4);
2283
0
                pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleOffset = drwav_bytes_to_u32(smplLoopData + 8);
2284
0
                pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleOffset  = drwav_bytes_to_u32(smplLoopData + 12);
2285
0
                pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction    = drwav_bytes_to_u32(smplLoopData + 16);
2286
0
                pMetadata->data.smpl.pLoops[iSampleLoop].playCount         = drwav_bytes_to_u32(smplLoopData + 20);
2287
0
            } else {
2288
0
                return totalBytesRead;
2289
0
            }
2290
0
        }
2291
2292
0
        if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) {
2293
0
            pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1);
2294
0
            DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL);
2295
2296
0
            bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead);
2297
0
            if (bytesJustRead != pMetadata->data.smpl.samplerSpecificDataSizeInBytes) {
2298
0
                return totalBytesRead;
2299
0
            }
2300
0
        }
2301
2302
0
        if (trailingDataSizeInBytes > 0) {
2303
0
            if (!drwav__seek_forward(pParser->onSeek, trailingDataSizeInBytes, pParser->pReadSeekUserData)) {
2304
0
                return totalBytesRead;
2305
0
            }
2306
0
            totalBytesRead += trailingDataSizeInBytes;
2307
0
        }
2308
0
    }
2309
2310
0
    return totalBytesRead;
2311
0
}
2312
2313
DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata)
2314
0
{
2315
0
    drwav_uint8 cueHeaderSectionData[DRWAV_CUE_BYTES];
2316
0
    drwav_uint64 totalBytesRead = 0;
2317
0
    size_t bytesJustRead;
2318
2319
0
    if (pMetadata == NULL) {
2320
0
        return 0;
2321
0
    }
2322
2323
0
    bytesJustRead = drwav__metadata_parser_read(pParser, cueHeaderSectionData, sizeof(cueHeaderSectionData), &totalBytesRead);
2324
2325
0
    DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2326
2327
0
    if (bytesJustRead == sizeof(cueHeaderSectionData)) {
2328
0
        pMetadata->type                   = drwav_metadata_type_cue;
2329
0
        pMetadata->data.cue.cuePointCount = drwav_bytes_to_u32(cueHeaderSectionData);
2330
2331
        /*
2332
        We need to validate the cue point count against the size of the chunk so we don't read
2333
        beyond the chunk.
2334
        */
2335
0
        if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES) {
2336
0
            pMetadata->data.cue.pCuePoints    = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT);
2337
0
            DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL);
2338
2339
0
            if (pMetadata->data.cue.cuePointCount > 0) {
2340
0
                drwav_uint32 iCuePoint;
2341
2342
0
                for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) {
2343
0
                    drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES];
2344
0
                    bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead);
2345
2346
0
                    if (bytesJustRead == sizeof(cuePointData)) {
2347
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].id                = drwav_bytes_to_u32(cuePointData + 0);
2348
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4);
2349
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0]    = cuePointData[8];
2350
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1]    = cuePointData[9];
2351
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2]    = cuePointData[10];
2352
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3]    = cuePointData[11];
2353
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart        = drwav_bytes_to_u32(cuePointData + 12);
2354
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].blockStart        = drwav_bytes_to_u32(cuePointData + 16);
2355
0
                        pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset      = drwav_bytes_to_u32(cuePointData + 20);
2356
0
                    } else {
2357
0
                        break;
2358
0
                    }
2359
0
                }
2360
0
            }
2361
0
        }
2362
0
    }
2363
2364
0
    return totalBytesRead;
2365
0
}
2366
2367
DRWAV_PRIVATE drwav_uint64 drwav__read_inst_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
2368
0
{
2369
0
    drwav_uint8 instData[DRWAV_INST_BYTES];
2370
0
    drwav_uint64 bytesRead;
2371
2372
0
    if (pMetadata == NULL) {
2373
0
        return 0;
2374
0
    }
2375
2376
0
    bytesRead = drwav__metadata_parser_read(pParser, instData, sizeof(instData), NULL);
2377
2378
0
    DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2379
2380
0
    if (bytesRead == sizeof(instData)) {
2381
0
        pMetadata->type                    = drwav_metadata_type_inst;
2382
0
        pMetadata->data.inst.midiUnityNote = (drwav_int8)instData[0];
2383
0
        pMetadata->data.inst.fineTuneCents = (drwav_int8)instData[1];
2384
0
        pMetadata->data.inst.gainDecibels  = (drwav_int8)instData[2];
2385
0
        pMetadata->data.inst.lowNote       = (drwav_int8)instData[3];
2386
0
        pMetadata->data.inst.highNote      = (drwav_int8)instData[4];
2387
0
        pMetadata->data.inst.lowVelocity   = (drwav_int8)instData[5];
2388
0
        pMetadata->data.inst.highVelocity  = (drwav_int8)instData[6];
2389
0
    }
2390
2391
0
    return bytesRead;
2392
0
}
2393
2394
DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
2395
0
{
2396
0
    drwav_uint8 acidData[DRWAV_ACID_BYTES];
2397
0
    drwav_uint64 bytesRead;
2398
2399
0
    if (pMetadata == NULL) {
2400
0
        return 0;
2401
0
    }
2402
2403
0
    bytesRead = drwav__metadata_parser_read(pParser, acidData, sizeof(acidData), NULL);
2404
2405
0
    DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2406
2407
0
    if (bytesRead == sizeof(acidData)) {
2408
0
        pMetadata->type                       = drwav_metadata_type_acid;
2409
0
        pMetadata->data.acid.flags            = drwav_bytes_to_u32(acidData + 0);
2410
0
        pMetadata->data.acid.midiUnityNote    = drwav_bytes_to_u16(acidData + 4);
2411
0
        pMetadata->data.acid.reserved1        = drwav_bytes_to_u16(acidData + 6);
2412
0
        pMetadata->data.acid.reserved2        = drwav_bytes_to_f32(acidData + 8);
2413
0
        pMetadata->data.acid.numBeats         = drwav_bytes_to_u32(acidData + 12);
2414
0
        pMetadata->data.acid.meterDenominator = drwav_bytes_to_u16(acidData + 16);
2415
0
        pMetadata->data.acid.meterNumerator   = drwav_bytes_to_u16(acidData + 18);
2416
0
        pMetadata->data.acid.tempo            = drwav_bytes_to_f32(acidData + 20);
2417
0
    }
2418
2419
0
    return bytesRead;
2420
0
}
2421
2422
DRWAV_PRIVATE size_t drwav__strlen(const char* str)
2423
0
{
2424
0
    size_t result = 0;
2425
2426
0
    while (*str++) {
2427
0
        result += 1;
2428
0
    }
2429
2430
0
    return result;
2431
0
}
2432
2433
DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead)
2434
0
{
2435
0
    size_t result = 0;
2436
2437
0
    while (*str++ && result < maxToRead) {
2438
0
        result += 1;
2439
0
    }
2440
2441
0
    return result;
2442
0
}
2443
2444
DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, const char* str, size_t maxToRead)
2445
0
{
2446
0
    size_t len = drwav__strlen_clamped(str, maxToRead);
2447
2448
0
    if (len) {
2449
0
        char* result = (char*)drwav__metadata_get_memory(pParser, len + 1, 1);
2450
0
        DRWAV_ASSERT(result != NULL);
2451
2452
0
        DRWAV_COPY_MEMORY(result, str, len);
2453
0
        result[len] = '\0';
2454
2455
0
        return result;
2456
0
    } else {
2457
0
        return NULL;
2458
0
    }
2459
0
}
2460
2461
typedef struct
2462
{
2463
    const void* pBuffer;
2464
    size_t sizeInBytes;
2465
    size_t cursor;
2466
} drwav_buffer_reader;
2467
2468
DRWAV_PRIVATE drwav_result drwav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, drwav_buffer_reader* pReader)
2469
0
{
2470
0
    DRWAV_ASSERT(pBuffer != NULL);
2471
0
    DRWAV_ASSERT(pReader != NULL);
2472
2473
0
    DRWAV_ZERO_OBJECT(pReader);
2474
2475
0
    pReader->pBuffer     = pBuffer;
2476
0
    pReader->sizeInBytes = sizeInBytes;
2477
0
    pReader->cursor      = 0;
2478
2479
0
    return DRWAV_SUCCESS;
2480
0
}
2481
2482
DRWAV_PRIVATE const void* drwav_buffer_reader_ptr(const drwav_buffer_reader* pReader)
2483
0
{
2484
0
    DRWAV_ASSERT(pReader != NULL);
2485
2486
0
    return drwav_offset_ptr(pReader->pBuffer, pReader->cursor);
2487
0
}
2488
2489
DRWAV_PRIVATE drwav_result drwav_buffer_reader_seek(drwav_buffer_reader* pReader, size_t bytesToSeek)
2490
0
{
2491
0
    DRWAV_ASSERT(pReader != NULL);
2492
2493
0
    if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) {
2494
0
        return DRWAV_BAD_SEEK;  /* Seeking too far forward. */
2495
0
    }
2496
2497
0
    pReader->cursor += bytesToSeek;
2498
2499
0
    return DRWAV_SUCCESS;
2500
0
}
2501
2502
DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead)
2503
0
{
2504
0
    drwav_result result = DRWAV_SUCCESS;
2505
0
    size_t bytesRemaining;
2506
2507
0
    DRWAV_ASSERT(pReader != NULL);
2508
2509
0
    if (pBytesRead != NULL) {
2510
0
        *pBytesRead = 0;
2511
0
    }
2512
2513
0
    bytesRemaining = (pReader->sizeInBytes - pReader->cursor);
2514
0
    if (bytesToRead > bytesRemaining) {
2515
0
        bytesToRead = bytesRemaining;
2516
0
    }
2517
2518
0
    if (pDst == NULL) {
2519
        /* Seek. */
2520
0
        result = drwav_buffer_reader_seek(pReader, bytesToRead);
2521
0
    } else {
2522
        /* Read. */
2523
0
        DRWAV_COPY_MEMORY(pDst, drwav_buffer_reader_ptr(pReader), bytesToRead);
2524
0
        pReader->cursor += bytesToRead;
2525
0
    }
2526
2527
0
    DRWAV_ASSERT(pReader->cursor <= pReader->sizeInBytes);
2528
2529
0
    if (result == DRWAV_SUCCESS) {
2530
0
        if (pBytesRead != NULL) {
2531
0
            *pBytesRead = bytesToRead;
2532
0
        }
2533
0
    }
2534
2535
0
    return DRWAV_SUCCESS;
2536
0
}
2537
2538
DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u16(drwav_buffer_reader* pReader, drwav_uint16* pDst)
2539
0
{
2540
0
    drwav_result result;
2541
0
    size_t bytesRead;
2542
0
    drwav_uint8 data[2];
2543
2544
0
    DRWAV_ASSERT(pReader != NULL);
2545
0
    DRWAV_ASSERT(pDst != NULL);
2546
2547
0
    *pDst = 0;  /* Safety. */
2548
2549
0
    result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead);
2550
0
    if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) {
2551
0
        return result;
2552
0
    }
2553
2554
0
    *pDst = drwav_bytes_to_u16(data);
2555
2556
0
    return DRWAV_SUCCESS;
2557
0
}
2558
2559
DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u32(drwav_buffer_reader* pReader, drwav_uint32* pDst)
2560
0
{
2561
0
    drwav_result result;
2562
0
    size_t bytesRead;
2563
0
    drwav_uint8 data[4];
2564
2565
0
    DRWAV_ASSERT(pReader != NULL);
2566
0
    DRWAV_ASSERT(pDst != NULL);
2567
2568
0
    *pDst = 0;  /* Safety. */
2569
2570
0
    result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead);
2571
0
    if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) {
2572
0
        return result;
2573
0
    }
2574
2575
0
    *pDst = drwav_bytes_to_u32(data);
2576
2577
0
    return DRWAV_SUCCESS;
2578
0
}
2579
2580
2581
2582
DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize)
2583
0
{
2584
0
    drwav_uint8 bextData[DRWAV_BEXT_BYTES];
2585
0
    size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL);
2586
2587
0
    DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2588
2589
0
    if (bytesRead == sizeof(bextData)) {
2590
0
        drwav_buffer_reader reader;
2591
0
        drwav_uint32 timeReferenceLow;
2592
0
        drwav_uint32 timeReferenceHigh;
2593
0
        size_t extraBytes;
2594
2595
0
        pMetadata->type = drwav_metadata_type_bext;
2596
2597
0
        if (drwav_buffer_reader_init(bextData, bytesRead, &reader) == DRWAV_SUCCESS) {
2598
0
            pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_DESCRIPTION_BYTES);
2599
0
            drwav_buffer_reader_seek(&reader, DRWAV_BEXT_DESCRIPTION_BYTES);
2600
2601
0
            pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
2602
0
            drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
2603
2604
0
            pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_REF_BYTES);
2605
0
            drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_REF_BYTES);
2606
2607
0
            drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL);
2608
0
            drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL);
2609
2610
0
            drwav_buffer_reader_read_u32(&reader, &timeReferenceLow);
2611
0
            drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh);
2612
0
            pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow;
2613
2614
0
            drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version);
2615
2616
0
            pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1);
2617
0
            drwav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES, NULL);
2618
2619
0
            drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue);
2620
0
            drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange);
2621
0
            drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel);
2622
0
            drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness);
2623
0
            drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness);
2624
2625
0
            DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES));
2626
2627
0
            extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES);
2628
0
            if (extraBytes > 0) {
2629
0
                pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1);
2630
0
                DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL);
2631
2632
0
                pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL);
2633
0
                pMetadata->data.bext.pCodingHistory[pMetadata->data.bext.codingHistorySize] = '\0'; /* <-- Explicit null terminator in case of a badly formed file. */
2634
                
2635
0
                bytesRead += pMetadata->data.bext.codingHistorySize;
2636
0
            } else {
2637
0
                pMetadata->data.bext.pCodingHistory    = NULL;
2638
0
                pMetadata->data.bext.codingHistorySize = 0;
2639
0
            }
2640
0
        }
2641
0
    }
2642
2643
0
    return bytesRead;
2644
0
}
2645
2646
DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize, drwav_metadata_type type)
2647
0
{
2648
0
    drwav_uint8 cueIDBuffer[DRWAV_LIST_LABEL_OR_NOTE_BYTES];
2649
0
    drwav_uint64 totalBytesRead = 0;
2650
0
    size_t bytesJustRead = drwav__metadata_parser_read(pParser, cueIDBuffer, sizeof(cueIDBuffer), &totalBytesRead);
2651
2652
0
    DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2653
2654
0
    if (bytesJustRead == sizeof(cueIDBuffer)) {
2655
0
        drwav_uint32 sizeIncludingNullTerminator;
2656
2657
0
        pMetadata->type = type;
2658
0
        pMetadata->data.labelOrNote.cuePointId = drwav_bytes_to_u32(cueIDBuffer);
2659
2660
0
        sizeIncludingNullTerminator = (drwav_uint32)chunkSize - DRWAV_LIST_LABEL_OR_NOTE_BYTES;
2661
0
        if (sizeIncludingNullTerminator > 0) {
2662
0
            pMetadata->data.labelOrNote.stringLength = sizeIncludingNullTerminator - 1;
2663
0
            pMetadata->data.labelOrNote.pString      = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1);
2664
0
            DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL);
2665
2666
0
            drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead);
2667
0
        } else {
2668
0
            pMetadata->data.labelOrNote.stringLength = 0;
2669
0
            pMetadata->data.labelOrNote.pString      = NULL;
2670
0
        }
2671
0
    }
2672
2673
0
    return totalBytesRead;
2674
0
}
2675
2676
DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize)
2677
0
{
2678
0
    drwav_uint8 buffer[DRWAV_LIST_LABELLED_TEXT_BYTES];
2679
0
    drwav_uint64 totalBytesRead = 0;
2680
0
    size_t bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &totalBytesRead);
2681
2682
0
    DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2683
2684
0
    if (bytesJustRead == sizeof(buffer)) {
2685
0
        drwav_uint32 sizeIncludingNullTerminator;
2686
2687
0
        pMetadata->type                                = drwav_metadata_type_list_labelled_cue_region;
2688
0
        pMetadata->data.labelledCueRegion.cuePointId   = drwav_bytes_to_u32(buffer + 0);
2689
0
        pMetadata->data.labelledCueRegion.sampleLength = drwav_bytes_to_u32(buffer + 4);
2690
0
        pMetadata->data.labelledCueRegion.purposeId[0] = buffer[8];
2691
0
        pMetadata->data.labelledCueRegion.purposeId[1] = buffer[9];
2692
0
        pMetadata->data.labelledCueRegion.purposeId[2] = buffer[10];
2693
0
        pMetadata->data.labelledCueRegion.purposeId[3] = buffer[11];
2694
0
        pMetadata->data.labelledCueRegion.country      = drwav_bytes_to_u16(buffer + 12);
2695
0
        pMetadata->data.labelledCueRegion.language     = drwav_bytes_to_u16(buffer + 14);
2696
0
        pMetadata->data.labelledCueRegion.dialect      = drwav_bytes_to_u16(buffer + 16);
2697
0
        pMetadata->data.labelledCueRegion.codePage     = drwav_bytes_to_u16(buffer + 18);
2698
2699
0
        sizeIncludingNullTerminator = (drwav_uint32)chunkSize - DRWAV_LIST_LABELLED_TEXT_BYTES;
2700
0
        if (sizeIncludingNullTerminator > 0) {
2701
0
            pMetadata->data.labelledCueRegion.stringLength = sizeIncludingNullTerminator - 1;
2702
0
            pMetadata->data.labelledCueRegion.pString      = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1);
2703
0
            DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL);
2704
2705
0
            drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead);
2706
0
        } else {
2707
0
            pMetadata->data.labelledCueRegion.stringLength = 0;
2708
0
            pMetadata->data.labelledCueRegion.pString      = NULL;
2709
0
        }
2710
0
    }
2711
2712
0
    return totalBytesRead;
2713
0
}
2714
2715
DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_info_text_chunk(drwav__metadata_parser* pParser, drwav_uint64 chunkSize, drwav_metadata_type type)
2716
0
{
2717
0
    drwav_uint64 bytesRead = 0;
2718
0
    drwav_uint32 stringSizeWithNullTerminator = (drwav_uint32)chunkSize;
2719
2720
0
    if (pParser->stage == drwav__metadata_parser_stage_count) {
2721
0
        pParser->metadataCount += 1;
2722
0
        drwav__metadata_request_extra_memory_for_stage_2(pParser, stringSizeWithNullTerminator, 1);
2723
0
    } else {
2724
0
        drwav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor];
2725
0
        pMetadata->type = type;
2726
0
        if (stringSizeWithNullTerminator > 0) {
2727
0
            pMetadata->data.infoText.stringLength = stringSizeWithNullTerminator - 1;
2728
0
            pMetadata->data.infoText.pString = (char*)drwav__metadata_get_memory(pParser, stringSizeWithNullTerminator, 1);
2729
0
            DRWAV_ASSERT(pMetadata->data.infoText.pString != NULL);
2730
2731
0
            bytesRead = drwav__metadata_parser_read(pParser, pMetadata->data.infoText.pString, (size_t)stringSizeWithNullTerminator, NULL);
2732
0
            if (bytesRead == chunkSize) {
2733
0
                pParser->metadataCursor += 1;
2734
0
            } else {
2735
                /* Failed to parse. */
2736
0
            }
2737
0
        } else {
2738
0
            pMetadata->data.infoText.stringLength = 0;
2739
0
            pMetadata->data.infoText.pString      = NULL;
2740
0
            pParser->metadataCursor += 1;
2741
0
        }
2742
0
    }
2743
2744
0
    return bytesRead;
2745
0
}
2746
2747
DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata_parser* pParser, const drwav_uint8* pChunkId, drwav_uint64 chunkSize, drwav_metadata_location location)
2748
0
{
2749
0
    drwav_uint64 bytesRead = 0;
2750
2751
0
    if (location == drwav_metadata_location_invalid) {
2752
0
        return 0;
2753
0
    }
2754
2755
0
    if (drwav_fourcc_equal(pChunkId, "data") || drwav_fourcc_equal(pChunkId, "fmt ") || drwav_fourcc_equal(pChunkId, "fact")) {
2756
0
        return 0;
2757
0
    }
2758
2759
0
    if (pParser->stage == drwav__metadata_parser_stage_count) {
2760
0
        pParser->metadataCount += 1;
2761
0
        drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)chunkSize, 1);
2762
0
    } else {
2763
0
        drwav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor];
2764
0
        pMetadata->type                         = drwav_metadata_type_unknown;
2765
0
        pMetadata->data.unknown.chunkLocation   = location;
2766
0
        pMetadata->data.unknown.id[0]           = pChunkId[0];
2767
0
        pMetadata->data.unknown.id[1]           = pChunkId[1];
2768
0
        pMetadata->data.unknown.id[2]           = pChunkId[2];
2769
0
        pMetadata->data.unknown.id[3]           = pChunkId[3];
2770
0
        pMetadata->data.unknown.dataSizeInBytes = (drwav_uint32)chunkSize;
2771
0
        pMetadata->data.unknown.pData           = (drwav_uint8 *)drwav__metadata_get_memory(pParser, (size_t)chunkSize, 1);
2772
0
        DRWAV_ASSERT(pMetadata->data.unknown.pData != NULL);
2773
2774
0
        bytesRead = drwav__metadata_parser_read(pParser, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes, NULL);
2775
0
        if (bytesRead == pMetadata->data.unknown.dataSizeInBytes) {
2776
0
            pParser->metadataCursor += 1;
2777
0
        } else {
2778
            /* Failed to read. */
2779
0
        }
2780
0
    }
2781
2782
0
    return bytesRead;
2783
0
}
2784
2785
DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_metadata_type allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID)
2786
0
{
2787
0
    return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID);
2788
0
}
2789
2790
DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata_type allowedMetadataTypes)
2791
0
{
2792
0
    const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc;
2793
0
    drwav_uint64 bytesRead = 0;
2794
2795
0
    if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_smpl, "smpl")) {
2796
0
        if (pChunkHeader->sizeInBytes >= DRWAV_SMPL_BYTES) {
2797
0
            if (pParser->stage == drwav__metadata_parser_stage_count) {
2798
0
                drwav_uint8 buffer[4];
2799
0
                size_t bytesJustRead;
2800
2801
0
                if (!pParser->onSeek(pParser->pReadSeekUserData, 28, DRWAV_SEEK_CUR)) {
2802
0
                    return bytesRead;
2803
0
                }
2804
0
                bytesRead += 28;
2805
2806
0
                bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
2807
0
                if (bytesJustRead == sizeof(buffer)) {
2808
0
                    drwav_uint32 loopCount = drwav_bytes_to_u32(buffer);
2809
2810
0
                    bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
2811
0
                    if (bytesJustRead == sizeof(buffer)) {
2812
0
                        drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer);
2813
2814
0
                        if (drwav__metadata_validate_smpl_chunk(pChunkHeader, loopCount, samplerSpecificDataSizeInBytes, NULL)) {
2815
0
                            pParser->metadataCount += 1;
2816
0
                            drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT);
2817
0
                            drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1);
2818
0
                        } else {
2819
                            /* Incorrectly formed chunk. Loop or sampler-specific data exceeds the size of the chunk. */
2820
0
                        }
2821
0
                    }
2822
0
                }
2823
0
            } else {
2824
0
                bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]);
2825
0
                if (bytesRead == pChunkHeader->sizeInBytes) {
2826
0
                    pParser->metadataCursor += 1;
2827
0
                } else {
2828
                    /* Failed to parse. */
2829
0
                }
2830
0
            }
2831
0
        } else {
2832
            /* Incorrectly formed chunk. */
2833
0
        }
2834
0
    } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_inst, "inst")) {
2835
0
        if (pChunkHeader->sizeInBytes == DRWAV_INST_BYTES) {
2836
0
            if (pParser->stage == drwav__metadata_parser_stage_count) {
2837
0
                pParser->metadataCount += 1;
2838
0
            } else {
2839
0
                bytesRead = drwav__read_inst_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]);
2840
0
                if (bytesRead == pChunkHeader->sizeInBytes) {
2841
0
                    pParser->metadataCursor += 1;
2842
0
                } else {
2843
                    /* Failed to parse. */
2844
0
                }
2845
0
            }
2846
0
        } else {
2847
            /* Incorrectly formed chunk. */
2848
0
        }
2849
0
    } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_acid, "acid")) {
2850
0
        if (pChunkHeader->sizeInBytes == DRWAV_ACID_BYTES) {
2851
0
            if (pParser->stage == drwav__metadata_parser_stage_count) {
2852
0
                pParser->metadataCount += 1;
2853
0
            } else {
2854
0
                bytesRead = drwav__read_acid_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]);
2855
0
                if (bytesRead == pChunkHeader->sizeInBytes) {
2856
0
                    pParser->metadataCursor += 1;
2857
0
                } else {
2858
                    /* Failed to parse. */
2859
0
                }
2860
0
            }
2861
0
        } else {
2862
            /* Incorrectly formed chunk. */
2863
0
        }
2864
0
    } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_cue, "cue ")) {
2865
0
        if (pChunkHeader->sizeInBytes >= DRWAV_CUE_BYTES) {
2866
0
            if (pParser->stage == drwav__metadata_parser_stage_count) {
2867
0
                size_t cueCount;
2868
2869
0
                pParser->metadataCount += 1;
2870
0
                cueCount = (size_t)(pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES;
2871
0
                drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_cue_point) * cueCount, DRWAV_METADATA_ALIGNMENT);
2872
0
            } else {
2873
0
                bytesRead = drwav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]);
2874
0
                if (bytesRead == pChunkHeader->sizeInBytes) {
2875
0
                    pParser->metadataCursor += 1;
2876
0
                } else {
2877
                    /* Failed to parse. */
2878
0
                }
2879
0
            }
2880
0
        } else {
2881
            /* Incorrectly formed chunk. */
2882
0
        }
2883
0
    } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_bext, "bext")) {
2884
0
        if (pChunkHeader->sizeInBytes >= DRWAV_BEXT_BYTES) {
2885
0
            if (pParser->stage == drwav__metadata_parser_stage_count) {
2886
                /* The description field is the largest one in a bext chunk, so that is the max size of this temporary buffer. */
2887
0
                char buffer[DRWAV_BEXT_DESCRIPTION_BYTES + 1];
2888
0
                size_t allocSizeNeeded = DRWAV_BEXT_UMID_BYTES; /* We know we will need SMPTE umid size. */
2889
0
                size_t bytesJustRead;
2890
2891
0
                buffer[DRWAV_BEXT_DESCRIPTION_BYTES] = '\0';
2892
0
                bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_DESCRIPTION_BYTES, &bytesRead);
2893
0
                if (bytesJustRead != DRWAV_BEXT_DESCRIPTION_BYTES) {
2894
0
                    return bytesRead;
2895
0
                }
2896
0
                allocSizeNeeded += drwav__strlen(buffer) + 1;
2897
2898
0
                buffer[DRWAV_BEXT_ORIGINATOR_NAME_BYTES] = '\0';
2899
0
                bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_NAME_BYTES, &bytesRead);
2900
0
                if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_NAME_BYTES) {
2901
0
                    return bytesRead;
2902
0
                }
2903
0
                allocSizeNeeded += drwav__strlen(buffer) + 1;
2904
2905
0
                buffer[DRWAV_BEXT_ORIGINATOR_REF_BYTES] = '\0';
2906
0
                bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_REF_BYTES, &bytesRead);
2907
0
                if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_REF_BYTES) {
2908
0
                    return bytesRead;
2909
0
                }
2910
0
                allocSizeNeeded += drwav__strlen(buffer) + 1;
2911
2912
                /* Coding history. */
2913
0
                allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES + 1;
2914
2915
0
                drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
2916
2917
0
                pParser->metadataCount += 1;
2918
0
            } else {
2919
0
                bytesRead = drwav__read_bext_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], pChunkHeader->sizeInBytes);
2920
0
                if (bytesRead == pChunkHeader->sizeInBytes) {
2921
0
                    pParser->metadataCursor += 1;
2922
0
                } else {
2923
                    /* Failed to parse. */
2924
0
                }
2925
0
            }
2926
0
        } else {
2927
            /* Incorrectly formed chunk. */
2928
0
        }
2929
0
    } else if (drwav_fourcc_equal(pChunkID, "LIST") || drwav_fourcc_equal(pChunkID, "list")) {
2930
0
        drwav_metadata_location listType = drwav_metadata_location_invalid;
2931
0
        while (bytesRead < pChunkHeader->sizeInBytes) {
2932
0
            drwav_uint8 subchunkId[4];
2933
0
            drwav_uint8 subchunkSizeBuffer[4];
2934
0
            drwav_uint64 subchunkDataSize;
2935
0
            drwav_uint64 subchunkBytesRead = 0;
2936
0
            drwav_uint64 bytesJustRead = drwav__metadata_parser_read(pParser, subchunkId, sizeof(subchunkId), &bytesRead);
2937
0
            if (bytesJustRead != sizeof(subchunkId)) {
2938
0
                break;
2939
0
            }
2940
2941
            /*
2942
            The first thing in a list chunk should be "adtl" or "INFO".
2943
2944
              - adtl means this list is a Associated Data List Chunk and will contain labels, notes
2945
                or labelled cue regions.
2946
              - INFO means this list is an Info List Chunk containing info text chunks such as IPRD
2947
                which would specifies the album of this wav file.
2948
2949
            No data follows the adtl or INFO id so we just make note of what type this list is and
2950
            continue.
2951
            */
2952
0
            if (drwav_fourcc_equal(subchunkId, "adtl")) {
2953
0
                listType = drwav_metadata_location_inside_adtl_list;
2954
0
                continue;
2955
0
            } else if (drwav_fourcc_equal(subchunkId, "INFO")) {
2956
0
                listType = drwav_metadata_location_inside_info_list;
2957
0
                continue;
2958
0
            }
2959
2960
0
            bytesJustRead = drwav__metadata_parser_read(pParser, subchunkSizeBuffer, sizeof(subchunkSizeBuffer), &bytesRead);
2961
0
            if (bytesJustRead != sizeof(subchunkSizeBuffer)) {
2962
0
                break;
2963
0
            }
2964
0
            subchunkDataSize = drwav_bytes_to_u32(subchunkSizeBuffer);
2965
2966
0
            if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_label, "labl") || drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_note, "note")) {
2967
0
                if (subchunkDataSize >= DRWAV_LIST_LABEL_OR_NOTE_BYTES) {
2968
0
                    drwav_uint64 stringSizeWithNullTerm = subchunkDataSize - DRWAV_LIST_LABEL_OR_NOTE_BYTES;
2969
0
                    if (pParser->stage == drwav__metadata_parser_stage_count) {
2970
0
                        pParser->metadataCount += 1;
2971
0
                        drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerm, 1);
2972
0
                    } else {
2973
0
                        subchunkBytesRead = drwav__read_list_label_or_note_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize, drwav_fourcc_equal(subchunkId, "labl") ? drwav_metadata_type_list_label : drwav_metadata_type_list_note);
2974
0
                        if (subchunkBytesRead == subchunkDataSize) {
2975
0
                            pParser->metadataCursor += 1;
2976
0
                        } else {
2977
                            /* Failed to parse. */
2978
0
                        }
2979
0
                    }
2980
0
                } else {
2981
                    /* Incorrectly formed chunk. */
2982
0
                }
2983
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_labelled_cue_region, "ltxt")) {
2984
0
                if (subchunkDataSize >= DRWAV_LIST_LABELLED_TEXT_BYTES) {
2985
0
                    drwav_uint64 stringSizeWithNullTerminator = subchunkDataSize - DRWAV_LIST_LABELLED_TEXT_BYTES;
2986
0
                    if (pParser->stage == drwav__metadata_parser_stage_count) {
2987
0
                        pParser->metadataCount += 1;
2988
0
                        drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerminator, 1);
2989
0
                    } else {
2990
0
                        subchunkBytesRead = drwav__read_list_labelled_cue_region_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize);
2991
0
                        if (subchunkBytesRead == subchunkDataSize) {
2992
0
                            pParser->metadataCursor += 1;
2993
0
                        } else {
2994
                            /* Failed to parse. */
2995
0
                        }
2996
0
                    }
2997
0
                } else {
2998
                    /* Incorrectly formed chunk. */
2999
0
                }
3000
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_software, "ISFT")) {
3001
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_software);
3002
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_copyright, "ICOP")) {
3003
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_copyright);
3004
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_title, "INAM")) {
3005
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_title);
3006
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_artist, "IART")) {
3007
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_artist);
3008
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_comment, "ICMT")) {
3009
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_comment);
3010
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_date, "ICRD")) {
3011
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_date);
3012
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_genre, "IGNR")) {
3013
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_genre);
3014
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_album, "IPRD")) {
3015
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_album);
3016
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) {
3017
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_tracknumber);
3018
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_location, "IARL")) {
3019
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_location);
3020
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_organization, "ICMS")) {
3021
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_organization);
3022
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_keywords, "IKEY")) {
3023
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_keywords);
3024
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_medium, "IMED")) {
3025
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_medium);
3026
0
            } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_description, "ISBJ")) {
3027
0
                subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_description);
3028
0
            } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
3029
0
                subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType);
3030
0
            }
3031
3032
0
            bytesRead += subchunkBytesRead;
3033
0
            DRWAV_ASSERT(subchunkBytesRead <= subchunkDataSize);
3034
3035
0
            if (subchunkBytesRead < subchunkDataSize) {
3036
0
                drwav_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead;
3037
3038
0
                if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, DRWAV_SEEK_CUR)) {
3039
0
                    break;
3040
0
                }
3041
0
                bytesRead += bytesToSeek;
3042
0
            }
3043
3044
0
            if ((subchunkDataSize % 2) == 1) {
3045
0
                if (!pParser->onSeek(pParser->pReadSeekUserData, 1, DRWAV_SEEK_CUR)) {
3046
0
                    break;
3047
0
                }
3048
0
                bytesRead += 1;
3049
0
            }
3050
0
        }
3051
0
    } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
3052
0
        bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level);
3053
0
    }
3054
3055
0
    return bytesRead;
3056
0
}
3057
3058
3059
DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
3060
27.2k
{
3061
27.2k
    drwav_uint32 bytesPerFrame;
3062
3063
    /*
3064
    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
3065
    is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align.
3066
    */
3067
27.2k
    if ((pWav->bitsPerSample & 0x7) == 0) {
3068
        /* Bits per sample is a multiple of 8. */
3069
19.6k
        bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3;
3070
19.6k
    } else {
3071
7.60k
        bytesPerFrame = pWav->fmt.blockAlign;
3072
7.60k
    }
3073
3074
    /* Validation for known formats. a-law and mu-law should be 1 byte per channel. If it's not, it's not decodable. */
3075
27.2k
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
3076
11.6k
        if (bytesPerFrame != pWav->fmt.channels) {
3077
56
            return 0;   /* Invalid file. */
3078
56
        }
3079
11.6k
    }
3080
3081
27.1k
    return bytesPerFrame;
3082
27.2k
}
3083
3084
DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
3085
0
{
3086
0
    if (pFMT == NULL) {
3087
0
        return 0;
3088
0
    }
3089
3090
0
    if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) {
3091
0
        return pFMT->formatTag;
3092
0
    } else {
3093
0
        return drwav_bytes_to_u16(pFMT->subFormat);    /* Only the first two bytes are required. */
3094
0
    }
3095
0
}
3096
3097
DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pReadSeekTellUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
3098
4.51k
{
3099
4.51k
    if (pWav == NULL || onRead == NULL || onSeek == NULL) { /* <-- onTell is optional. */
3100
0
        return DRWAV_FALSE;
3101
0
    }
3102
3103
4.51k
    DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
3104
4.51k
    pWav->onRead    = onRead;
3105
4.51k
    pWav->onSeek    = onSeek;
3106
4.51k
    pWav->onTell    = onTell;
3107
4.51k
    pWav->pUserData = pReadSeekTellUserData;
3108
4.51k
    pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
3109
3110
4.51k
    if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
3111
0
        return DRWAV_FALSE;    /* Invalid allocation callbacks. */
3112
0
    }
3113
3114
4.51k
    return DRWAV_TRUE;
3115
4.51k
}
3116
3117
DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
3118
4.51k
{
3119
    /* This function assumes drwav_preinit() has been called beforehand. */
3120
4.51k
    drwav_result result;
3121
4.51k
    drwav_uint64 cursor;    /* <-- Keeps track of the byte position so we can seek to specific locations. */
3122
4.51k
    drwav_bool32 sequential;
3123
4.51k
    drwav_uint8 riff[4];
3124
4.51k
    drwav_fmt fmt;
3125
4.51k
    unsigned short translatedFormatTag;
3126
4.51k
    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. */
3127
4.51k
    drwav_uint64 sampleCountFromFactChunk = 0;  /* Same as dataChunkSize - make sure this is the only place this is initialized to 0. */
3128
4.51k
    drwav_uint64 metadataStartPos;
3129
4.51k
    drwav__metadata_parser metadataParser;
3130
4.51k
    drwav_bool8 isProcessingMetadata = DRWAV_FALSE;
3131
4.51k
    drwav_bool8 foundChunk_fmt  = DRWAV_FALSE;
3132
4.51k
    drwav_bool8 foundChunk_data = DRWAV_FALSE;
3133
4.51k
    drwav_bool8 isAIFCFormType = DRWAV_FALSE;   /* Only used with AIFF. */
3134
4.51k
    drwav_uint64 aiffFrameCount = 0;
3135
4.51k
    drwav_int64 fileSize;
3136
4.51k
    drwav_bool32 hasKnownFileSize = DRWAV_FALSE;
3137
3138
4.51k
    cursor = 0;
3139
4.51k
    sequential = (flags & DRWAV_SEQUENTIAL) != 0;
3140
3141
    /*
3142
    Whether or not we are processing metadata controls how we load. We can load more efficiently when
3143
    metadata is not being processed. Seqential mode cannot support metadata because it involves seeking
3144
    backwards.
3145
    */
3146
4.51k
    isProcessingMetadata = !sequential && ((flags & DRWAV_WITH_METADATA) != 0);
3147
3148
    /*
3149
    When processing metadata we'll be doing some memory allocations here against untrusted data. We'll do
3150
    a basic validation check that they don't exceed the size of the file.
3151
    */
3152
4.51k
    if (isProcessingMetadata && pWav->onTell != NULL && pWav->onSeek != NULL) {
3153
0
        if (pWav->onSeek(pWav->pUserData, 0, DRWAV_SEEK_END)) {
3154
0
            if (pWav->onTell(pWav->pUserData, &fileSize)) {
3155
0
                hasKnownFileSize = DRWAV_TRUE;
3156
0
            }
3157
3158
0
            pWav->onSeek(pWav->pUserData, 0, DRWAV_SEEK_SET);
3159
0
        }
3160
0
    }
3161
3162
4.51k
    DRWAV_ZERO_OBJECT(&fmt);
3163
3164
    /* The first 4 bytes should be the RIFF identifier. */
3165
4.51k
    if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) {
3166
3
        return DRWAV_FALSE;
3167
3
    }
3168
3169
    /*
3170
    The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for
3171
    w64 it will start with "riff".
3172
    */
3173
4.51k
    if (drwav_fourcc_equal(riff, "RIFF")) {
3174
1.93k
        pWav->container = drwav_container_riff;
3175
2.57k
    } else if (drwav_fourcc_equal(riff, "RIFX")) {
3176
175
        pWav->container = drwav_container_rifx;
3177
2.40k
    } else if (drwav_fourcc_equal(riff, "riff")) {
3178
129
        int i;
3179
129
        drwav_uint8 riff2[12];
3180
3181
129
        pWav->container = drwav_container_w64;
3182
3183
        /* Check the rest of the GUID for validity. */
3184
129
        if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) {
3185
8
            return DRWAV_FALSE;
3186
8
        }
3187
3188
1.45k
        for (i = 0; i < 12; ++i) {
3189
1.35k
            if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
3190
13
                return DRWAV_FALSE;
3191
13
            }
3192
1.35k
        }
3193
2.27k
    } else if (drwav_fourcc_equal(riff, "RF64")) {
3194
773
        pWav->container = drwav_container_rf64;
3195
1.49k
    } else if (drwav_fourcc_equal(riff, "FORM")) {
3196
1.35k
        pWav->container = drwav_container_aiff;
3197
1.35k
    } else {
3198
146
        return DRWAV_FALSE;   /* Unknown or unsupported container. */
3199
146
    }
3200
3201
3202
4.34k
    if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) {
3203
2.88k
        drwav_uint8 chunkSizeBytes[4];
3204
2.88k
        drwav_uint8 wave[4];
3205
3206
2.88k
        if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
3207
5
            return DRWAV_FALSE;
3208
5
        }
3209
3210
2.87k
        if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) {
3211
2.10k
            if (drwav_bytes_to_u32_ex(chunkSizeBytes, pWav->container) < 36) {
3212
                /*
3213
                I've had a report of a WAV file failing to load when the size of the WAVE chunk is not encoded
3214
                and is instead just set to 0. I'm going to relax the validation here to allow these files to
3215
                load. Considering the chunk size isn't actually used this should be safe. With this change my
3216
                test suite still passes.
3217
                */
3218
                /*return DRWAV_FALSE;*/    /* Chunk size should always be at least 36 bytes. */
3219
268
            }
3220
2.10k
        } else if (pWav->container == drwav_container_rf64) {
3221
772
            if (drwav_bytes_to_u32_le(chunkSizeBytes) != 0xFFFFFFFF) {
3222
54
                return DRWAV_FALSE;    /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */
3223
54
            }
3224
772
        } else {
3225
0
            return DRWAV_FALSE; /* Should never hit this. */
3226
0
        }
3227
3228
2.82k
        if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
3229
5
            return DRWAV_FALSE;
3230
5
        }
3231
3232
2.82k
        if (!drwav_fourcc_equal(wave, "WAVE")) {
3233
46
            return DRWAV_FALSE;    /* Expecting "WAVE". */
3234
46
        }
3235
2.82k
    } else if (pWav->container == drwav_container_w64) {
3236
108
        drwav_uint8 chunkSizeBytes[8];
3237
108
        drwav_uint8 wave[16];
3238
3239
108
        if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
3240
3
            return DRWAV_FALSE;
3241
3
        }
3242
3243
105
        if (drwav_bytes_to_u64(chunkSizeBytes) < 80) {
3244
5
            return DRWAV_FALSE;
3245
5
        }
3246
3247
100
        if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
3248
70
            return DRWAV_FALSE;
3249
70
        }
3250
3251
30
        if (!drwav_guid_equal(wave, drwavGUID_W64_WAVE)) {
3252
30
            return DRWAV_FALSE;
3253
30
        }
3254
1.35k
    } else if (pWav->container == drwav_container_aiff) {
3255
1.35k
        drwav_uint8 chunkSizeBytes[4];
3256
1.35k
        drwav_uint8 aiff[4];
3257
3258
1.35k
        if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
3259
3
            return DRWAV_FALSE;
3260
3
        }
3261
3262
1.35k
        if (drwav_bytes_to_u32_be(chunkSizeBytes) < 18) {
3263
4
            return DRWAV_FALSE;
3264
4
        }
3265
3266
1.34k
        if (drwav__on_read(pWav->onRead, pWav->pUserData, aiff, sizeof(aiff), &cursor) != sizeof(aiff)) {
3267
49
            return DRWAV_FALSE;
3268
49
        }
3269
3270
1.29k
        if (drwav_fourcc_equal(aiff, "AIFF")) {
3271
592
            isAIFCFormType = DRWAV_FALSE;
3272
705
        } else if (drwav_fourcc_equal(aiff, "AIFC")) {
3273
649
            isAIFCFormType = DRWAV_TRUE;
3274
649
        } else {
3275
56
            return DRWAV_FALSE; /* Expecting "AIFF" or "AIFC". */
3276
56
        }
3277
1.29k
    } else {
3278
0
        return DRWAV_FALSE;
3279
0
    }
3280
3281
3282
    /* For RF64, the "ds64" chunk must come next, before the "fmt " chunk. */
3283
4.01k
    if (pWav->container == drwav_container_rf64) {
3284
716
        drwav_uint8 sizeBytes[8];
3285
716
        drwav_uint64 bytesRemainingInChunk;
3286
716
        drwav_chunk_header header;
3287
716
        result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
3288
716
        if (result != DRWAV_SUCCESS) {
3289
4
            return DRWAV_FALSE;
3290
4
        }
3291
3292
712
        if (!drwav_fourcc_equal(header.id.fourcc, "ds64")) {
3293
46
            return DRWAV_FALSE; /* Expecting "ds64". */
3294
46
        }
3295
3296
666
        bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
3297
3298
        /* We don't care about the size of the RIFF chunk - skip it. */
3299
666
        if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
3300
2
            return DRWAV_FALSE;
3301
2
        }
3302
664
        bytesRemainingInChunk -= 8;
3303
664
        cursor += 8;
3304
3305
3306
        /* Next 8 bytes is the size of the "data" chunk. */
3307
664
        if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
3308
5
            return DRWAV_FALSE;
3309
5
        }
3310
659
        bytesRemainingInChunk -= 8;
3311
659
        dataChunkSize = drwav_bytes_to_u64(sizeBytes);
3312
3313
3314
        /* Next 8 bytes is the same count which we would usually derived from the FACT chunk if it was available. */
3315
659
        if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
3316
5
            return DRWAV_FALSE;
3317
5
        }
3318
654
        bytesRemainingInChunk -= 8;
3319
654
        sampleCountFromFactChunk = drwav_bytes_to_u64(sizeBytes);
3320
3321
3322
        /* Skip over everything else. */
3323
654
        if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
3324
20
            return DRWAV_FALSE;
3325
20
        }
3326
634
        cursor += bytesRemainingInChunk;
3327
634
    }
3328
3329
3330
3.93k
    metadataStartPos = cursor;
3331
3332
    /* Don't allow processing of metadata with untested containers. */
3333
3.93k
    if (pWav->container != drwav_container_riff && pWav->container != drwav_container_rf64) {
3334
1.40k
        isProcessingMetadata = DRWAV_FALSE;
3335
1.40k
    }
3336
3337
3.93k
    DRWAV_ZERO_MEMORY(&metadataParser, sizeof(metadataParser));
3338
3.93k
    if (isProcessingMetadata) {
3339
0
        metadataParser.onRead = pWav->onRead;
3340
0
        metadataParser.onSeek = pWav->onSeek;
3341
0
        metadataParser.pReadSeekUserData = pWav->pUserData;
3342
0
        metadataParser.stage  = drwav__metadata_parser_stage_count;
3343
0
    }
3344
3345
3346
    /*
3347
    From here on out, chunks might be in any order. In order to robustly handle metadata we'll need
3348
    to loop through every chunk and handle them as we find them. In sequential mode we need to get
3349
    out of the loop as soon as we find the data chunk because we won't be able to seek back.
3350
    */
3351
14.7k
    for (;;) {  /* For each chunk... */
3352
14.7k
        drwav_chunk_header header;
3353
14.7k
        drwav_uint64 chunkSize;
3354
3355
14.7k
        result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
3356
14.7k
        if (result != DRWAV_SUCCESS) {
3357
147
            break;
3358
147
        }
3359
3360
14.6k
        chunkSize = header.sizeInBytes;
3361
3362
3363
        /*
3364
        Always tell the caller about this chunk. We cannot do this in sequential mode because the
3365
        callback is allowed to read from the file, in which case we'll need to rewind.
3366
        */
3367
14.6k
        if (!sequential && onChunk != NULL) {
3368
0
            drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt);
3369
3370
            /*
3371
            dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before
3372
            we called the callback.
3373
            */
3374
0
            if (callbackBytesRead > 0) {
3375
0
                if (drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == DRWAV_FALSE) {
3376
0
                    return DRWAV_FALSE;
3377
0
                }
3378
0
            }
3379
0
        }
3380
3381
3382
        /* Explicitly handle known chunks first. */
3383
3384
        /* "fmt " */
3385
14.6k
        if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "fmt ")) ||
3386
11.7k
            ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
3387
2.86k
            drwav_uint8 fmtData[16];
3388
3389
2.86k
            if (header.sizeInBytes < sizeof(fmtData)) {
3390
5
                return DRWAV_FALSE; /* Invalid fmt chunk. */
3391
5
            }
3392
3393
2.86k
            foundChunk_fmt = DRWAV_TRUE;
3394
3395
2.86k
            if (pWav->onRead(pWav->pUserData, fmtData, sizeof(fmtData)) != sizeof(fmtData)) {
3396
36
                return DRWAV_FALSE;
3397
36
            }
3398
2.82k
            cursor += sizeof(fmtData);
3399
3400
2.82k
            fmt.formatTag      = drwav_bytes_to_u16_ex(fmtData + 0,  pWav->container);
3401
2.82k
            fmt.channels       = drwav_bytes_to_u16_ex(fmtData + 2,  pWav->container);
3402
2.82k
            fmt.sampleRate     = drwav_bytes_to_u32_ex(fmtData + 4,  pWav->container);
3403
2.82k
            fmt.avgBytesPerSec = drwav_bytes_to_u32_ex(fmtData + 8,  pWav->container);
3404
2.82k
            fmt.blockAlign     = drwav_bytes_to_u16_ex(fmtData + 12, pWav->container);
3405
2.82k
            fmt.bitsPerSample  = drwav_bytes_to_u16_ex(fmtData + 14, pWav->container);
3406
3407
2.82k
            fmt.extendedSize       = 0;
3408
2.82k
            fmt.validBitsPerSample = 0;
3409
2.82k
            fmt.channelMask        = 0;
3410
2.82k
            DRWAV_ZERO_MEMORY(fmt.subFormat, sizeof(fmt.subFormat));
3411
3412
2.82k
            if (header.sizeInBytes > 16) {
3413
440
                drwav_uint8 fmt_cbSize[2];
3414
440
                int bytesReadSoFar = 0;
3415
440
                drwav_uint64 leftoverBytes;
3416
3417
440
                if (pWav->onRead(pWav->pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
3418
34
                    return DRWAV_FALSE;    /* Expecting more data. */
3419
34
                }
3420
406
                cursor += sizeof(fmt_cbSize);
3421
3422
406
                bytesReadSoFar = 18;
3423
3424
406
                fmt.extendedSize = drwav_bytes_to_u16_ex(fmt_cbSize, pWav->container);
3425
406
                if (fmt.extendedSize > 0) {
3426
                    /* Simple validation. */
3427
226
                    if (fmt.formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
3428
25
                        if (fmt.extendedSize != 22) {
3429
16
                            return DRWAV_FALSE;
3430
16
                        }
3431
25
                    }
3432
3433
210
                    if (fmt.formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
3434
9
                        drwav_uint8 fmtext[22];
3435
3436
9
                        if (pWav->onRead(pWav->pUserData, fmtext, fmt.extendedSize) != fmt.extendedSize) {
3437
5
                            return DRWAV_FALSE;    /* Expecting more data. */
3438
5
                        }
3439
3440
4
                        fmt.validBitsPerSample = drwav_bytes_to_u16_ex(fmtext + 0, pWav->container);
3441
4
                        fmt.channelMask        = drwav_bytes_to_u32_ex(fmtext + 2, pWav->container);
3442
4
                        drwav_bytes_to_guid(fmtext + 6, fmt.subFormat);
3443
201
                    } else {
3444
201
                        if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, DRWAV_SEEK_CUR) == DRWAV_FALSE) {
3445
34
                            return DRWAV_FALSE;
3446
34
                        }
3447
201
                    }
3448
171
                    cursor += fmt.extendedSize;
3449
3450
171
                    bytesReadSoFar += fmt.extendedSize;
3451
171
                }
3452
3453
                /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */
3454
351
                leftoverBytes = header.sizeInBytes - bytesReadSoFar;
3455
351
                if (leftoverBytes > 0x7FFFFFFF) {
3456
23
                    return DRWAV_FALSE;
3457
23
                }
3458
3459
328
                if (pWav->onSeek(pWav->pUserData, (int)leftoverBytes, DRWAV_SEEK_CUR) == DRWAV_FALSE) {
3460
51
                    return DRWAV_FALSE;
3461
51
                }
3462
3463
277
                cursor += leftoverBytes;
3464
277
            }
3465
3466
2.66k
            if (header.paddingSize > 0) {
3467
235
                if (drwav__seek_forward(pWav->onSeek, header.paddingSize, pWav->pUserData) == DRWAV_FALSE) {
3468
1
                    break;
3469
1
                }
3470
234
                cursor += header.paddingSize;
3471
234
            }
3472
3473
            /* Go to the next chunk. Don't include this chunk in metadata. */
3474
2.66k
            continue;
3475
2.66k
        }
3476
3477
        /* "data" */
3478
11.7k
        if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "data")) ||
3479
9.60k
            ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA))) {
3480
2.13k
            foundChunk_data = DRWAV_TRUE;
3481
3482
2.13k
            pWav->dataChunkDataPos  = cursor;
3483
3484
2.13k
            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. */
3485
1.53k
                dataChunkSize = chunkSize;
3486
1.53k
            }
3487
3488
            /* If we're running in sequential mode, or we're not reading metadata, we have enough now that we can get out of the loop. */
3489
2.13k
            if (sequential || !isProcessingMetadata) {
3490
2.13k
                break;      /* No need to keep reading beyond the data chunk. */
3491
2.13k
            } else {
3492
0
                chunkSize += header.paddingSize;    /* <-- Make sure we seek past the padding. */
3493
0
                if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
3494
0
                    break;
3495
0
                }
3496
0
                cursor += chunkSize;
3497
3498
0
                continue;   /* There may be some more metadata to read. */
3499
0
            }
3500
2.13k
        }
3501
3502
        /* "fact". This is optional. Can use this to get the sample count which is useful for compressed formats. For RF64 we retrieved the sample count from the ds64 chunk earlier. */
3503
9.60k
        if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "fact")) ||
3504
8.41k
            ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_FACT))) {
3505
1.19k
            if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) {
3506
932
                drwav_uint8 sampleCount[4];
3507
3508
932
                if (chunkSize < 4) {
3509
4
                    return DRWAV_FALSE;
3510
4
                }
3511
3512
928
                if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) {
3513
31
                    return DRWAV_FALSE;
3514
31
                }
3515
3516
897
                chunkSize -= 4;
3517
3518
                /*
3519
                The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this
3520
                for Microsoft ADPCM formats.
3521
                */
3522
897
                if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3523
0
                    sampleCountFromFactChunk = drwav_bytes_to_u32_ex(sampleCount, pWav->container);
3524
897
                } else {
3525
897
                    sampleCountFromFactChunk = 0;
3526
897
                }
3527
897
            } else if (pWav->container == drwav_container_w64) {
3528
0
                if (chunkSize < 8) {
3529
0
                    return DRWAV_FALSE;
3530
0
                }
3531
3532
0
                if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
3533
0
                    return DRWAV_FALSE;
3534
0
                }
3535
3536
0
                chunkSize -= 8;
3537
264
            } else if (pWav->container == drwav_container_rf64) {
3538
                /* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */
3539
264
            }
3540
3541
            /* Seek to the next chunk in preparation for the next iteration. */
3542
1.16k
            chunkSize += header.paddingSize;    /* <-- Make sure we seek past the padding. */
3543
1.16k
            if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
3544
61
                break;
3545
61
            }
3546
1.10k
            cursor += chunkSize;
3547
3548
1.10k
            continue;
3549
1.16k
        }
3550
3551
3552
        /* "COMM". AIFF/AIFC only. */
3553
8.41k
        if (pWav->container == drwav_container_aiff && drwav_fourcc_equal(header.id.fourcc, "COMM")) {
3554
1.33k
            drwav_uint8 commData[24];
3555
1.33k
            drwav_uint32 commDataBytesToRead;
3556
1.33k
            drwav_uint16 channels;
3557
1.33k
            drwav_uint32 frameCount;
3558
1.33k
            drwav_uint16 sampleSizeInBits;
3559
1.33k
            drwav_int64  sampleRate;
3560
1.33k
            drwav_uint16 compressionFormat;
3561
3562
1.33k
            foundChunk_fmt = DRWAV_TRUE;
3563
3564
1.33k
            if (isAIFCFormType) {
3565
826
                commDataBytesToRead = 24;
3566
826
                if (header.sizeInBytes < commDataBytesToRead) {
3567
7
                    return DRWAV_FALSE; /* Invalid COMM chunk. */
3568
7
                }
3569
826
            } else {
3570
510
                commDataBytesToRead = 18;
3571
510
                if (header.sizeInBytes != commDataBytesToRead) {
3572
29
                    return DRWAV_FALSE; /* INVALID COMM chunk. */
3573
29
                }
3574
510
            }
3575
3576
1.30k
            if (drwav__on_read(pWav->onRead, pWav->pUserData, commData, commDataBytesToRead, &cursor) != commDataBytesToRead) {
3577
44
                return DRWAV_FALSE;
3578
44
            }
3579
3580
3581
1.25k
            channels         = drwav_bytes_to_u16_ex     (commData + 0, pWav->container);
3582
1.25k
            frameCount       = drwav_bytes_to_u32_ex     (commData + 2, pWav->container);
3583
1.25k
            sampleSizeInBits = drwav_bytes_to_u16_ex     (commData + 6, pWav->container);
3584
1.25k
            sampleRate       = drwav_aiff_extented_to_s64(commData + 8);
3585
3586
1.25k
            if (sampleRate < 0 || sampleRate > 0xFFFFFFFF) {
3587
266
                return DRWAV_FALSE; /* Invalid sample rate. */
3588
266
            }
3589
3590
990
            if (isAIFCFormType) {
3591
706
                const drwav_uint8* type = commData + 18;
3592
3593
706
                if (drwav_fourcc_equal(type, "NONE")) {
3594
1
                    compressionFormat = DR_WAVE_FORMAT_PCM; /* PCM, big-endian. */
3595
705
                } else if (drwav_fourcc_equal(type, "raw ")) {
3596
14
                    compressionFormat = DR_WAVE_FORMAT_PCM;
3597
3598
                    /* In my testing, it looks like when the "raw " compression type is used, 8-bit samples should be considered unsigned. */
3599
14
                    if (sampleSizeInBits == 8) {
3600
1
                        pWav->aiff.isUnsigned = DRWAV_TRUE;
3601
1
                    }
3602
691
                } else if (drwav_fourcc_equal(type, "sowt")) {
3603
1
                    compressionFormat = DR_WAVE_FORMAT_PCM; /* PCM, little-endian. */
3604
1
                    pWav->aiff.isLE = DRWAV_TRUE;
3605
690
                } else if (drwav_fourcc_equal(type, "fl32") || drwav_fourcc_equal(type, "fl64") || drwav_fourcc_equal(type, "FL32") || drwav_fourcc_equal(type, "FL64")) {
3606
142
                    compressionFormat = DR_WAVE_FORMAT_IEEE_FLOAT;
3607
548
                } else if (drwav_fourcc_equal(type, "alaw") || drwav_fourcc_equal(type, "ALAW")) {
3608
119
                    compressionFormat = DR_WAVE_FORMAT_ALAW;
3609
429
                } else if (drwav_fourcc_equal(type, "ulaw") || drwav_fourcc_equal(type, "ULAW")) {
3610
104
                    compressionFormat = DR_WAVE_FORMAT_MULAW;
3611
325
                } else if (drwav_fourcc_equal(type, "ima4")) {
3612
1
                    compressionFormat = DR_WAVE_FORMAT_DVI_ADPCM;
3613
1
                    sampleSizeInBits  = 4;
3614
3615
                    /*
3616
                    I haven't been able to figure out how to get correct decoding for IMA ADPCM. Until this is figured out
3617
                    we'll need to abort when we encounter such an encoding. Advice welcome!
3618
                    */
3619
1
                    (void)compressionFormat;
3620
1
                    (void)sampleSizeInBits;
3621
3622
1
                    return DRWAV_FALSE;
3623
324
                } else {
3624
324
                    return DRWAV_FALSE; /* Unknown or unsupported compression format. Need to abort. */
3625
324
                }
3626
706
            } else {
3627
284
                compressionFormat = DR_WAVE_FORMAT_PCM; /* It's a standard AIFF form which is always compressed. */
3628
284
            }
3629
3630
            /* With AIFF we want to use the explicitly defined frame count rather than deriving it from the size of the chunk. */
3631
665
            aiffFrameCount = frameCount;
3632
3633
            /* We should now have enough information to fill out our fmt structure. */
3634
665
            fmt.formatTag      = compressionFormat;
3635
665
            fmt.channels       = channels;
3636
665
            fmt.sampleRate     = (drwav_uint32)sampleRate;
3637
665
            fmt.bitsPerSample  = (sampleSizeInBits + 7) & ~7;   /* In AIFF, samples are padded to 8-bit boundaries. We need to round up our bits per sample here. */
3638
665
            fmt.blockAlign     = (drwav_uint16)((drwav_uint32)fmt.channels * fmt.bitsPerSample / 8);
3639
665
            fmt.avgBytesPerSec = fmt.blockAlign * fmt.sampleRate;
3640
3641
            /*
3642
            Weird one. I've seen some alaw and ulaw encoded files that for some reason set the bits per sample to 16 when
3643
            it should be 8. To get this working I need to explicitly check for this and change it.
3644
            */
3645
665
            if (compressionFormat == DR_WAVE_FORMAT_ALAW || compressionFormat == DR_WAVE_FORMAT_MULAW) {
3646
223
                if (fmt.bitsPerSample > 8) {
3647
174
                    fmt.bitsPerSample = 8;
3648
174
                    fmt.blockAlign = fmt.channels;
3649
174
                }
3650
223
            }
3651
3652
            /* If the form type is AIFC there will be some additional data in the chunk. We need to seek past it. */
3653
665
            if (isAIFCFormType) {
3654
381
                if (drwav__seek_forward(pWav->onSeek, (chunkSize - commDataBytesToRead), pWav->pUserData) == DRWAV_FALSE) {
3655
49
                    return DRWAV_FALSE;
3656
49
                }
3657
332
                cursor += (chunkSize - commDataBytesToRead);
3658
332
            }
3659
3660
            /* Don't fall through or else we'll end up treating this chunk as metadata which is incorrect. */
3661
616
            continue;
3662
665
        }
3663
3664
3665
        /* "SSND". AIFF/AIFC only. This is the AIFF equivalent of the "data" chunk. */
3666
7.07k
        if (pWav->container == drwav_container_aiff && drwav_fourcc_equal(header.id.fourcc, "SSND")) {
3667
751
            drwav_uint8 offsetAndBlockSizeData[8];
3668
751
            drwav_uint32 offset;
3669
3670
751
            foundChunk_data = DRWAV_TRUE;
3671
3672
751
            if (drwav__on_read(pWav->onRead, pWav->pUserData, offsetAndBlockSizeData, sizeof(offsetAndBlockSizeData), &cursor) != sizeof(offsetAndBlockSizeData)) {
3673
6
                return DRWAV_FALSE;
3674
6
            }
3675
3676
            /* The position of the audio data starts at an offset. */
3677
745
            offset = drwav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container);
3678
745
            pWav->dataChunkDataPos = cursor + offset;
3679
3680
            /* The data chunk size needs to be reduced by the offset or else seeking will break. */
3681
745
            dataChunkSize = chunkSize;
3682
745
            if (dataChunkSize  > offset) {
3683
316
                dataChunkSize -= offset;
3684
429
            } else {
3685
429
                dataChunkSize = 0;
3686
429
            }
3687
3688
745
            if (sequential) {
3689
0
                if (foundChunk_fmt) {   /* <-- Name is misleading, but will be set to true if the COMM chunk has been parsed. */
3690
                    /*
3691
                    Getting here means we're opening in sequential mode and we've found the SSND (data) and COMM (fmt) chunks. We need
3692
                    to get out of the loop here or else we'll end up going past the data chunk and will have no way of getting back to
3693
                    it since we're not allowed to seek backwards.
3694
3695
                    One subtle detail here is that there is an offset with the SSND chunk. We need to make sure we seek past this offset
3696
                    so we're left sitting on the first byte of actual audio data.
3697
                    */
3698
0
                    if (drwav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == DRWAV_FALSE) {
3699
0
                        return DRWAV_FALSE;
3700
0
                    }
3701
0
                    cursor += offset;
3702
3703
0
                    break;
3704
0
                } else {
3705
                    /*
3706
                    Getting here means the COMM chunk was not found. In sequential mode, if we haven't yet found the COMM chunk
3707
                    we'll need to abort because we can't be doing a backwards seek back to the SSND chunk in order to read the
3708
                    data. For this reason, this configuration of AIFF files are not supported with sequential mode.
3709
                    */
3710
0
                    return DRWAV_FALSE;
3711
0
                }
3712
745
            } else {
3713
745
                chunkSize += header.paddingSize;                /* <-- Make sure we seek past the padding. */
3714
745
                chunkSize -= sizeof(offsetAndBlockSizeData);    /* <-- This was read earlier. */
3715
3716
745
                if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
3717
275
                    break;
3718
275
                }
3719
470
                cursor += chunkSize;
3720
3721
470
                continue;   /* There may be some more metadata to read. */
3722
745
            }
3723
745
        }
3724
3725
3726
        /* Getting here means it's not a chunk that we care about internally, but might need to be handled as metadata by the caller. */
3727
6.32k
        if (isProcessingMetadata) {
3728
0
            if (hasKnownFileSize && header.sizeInBytes > (drwav_uint64)fileSize) {
3729
0
                return DRWAV_FALSE;
3730
0
            }
3731
3732
0
            drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown);
3733
3734
            /* Go back to the start of the chunk so we can normalize the position of the cursor. */
3735
0
            if (drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == DRWAV_FALSE) {
3736
0
                break;  /* Failed to seek. Can't reliable read the remaining chunks. Get out. */
3737
0
            }
3738
0
        }
3739
3740
3741
        /* Make sure we skip past the content of this chunk before we go to the next one. */
3742
6.32k
        chunkSize += header.paddingSize;    /* <-- Make sure we seek past the padding. */
3743
6.32k
        if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
3744
346
            break;
3745
346
        }
3746
5.97k
        cursor += chunkSize;
3747
5.97k
    }
3748
3749
    /* There's some mandatory chunks that must exist. If they were not found in the iteration above we must abort. */
3750
2.96k
    if (!foundChunk_fmt || !foundChunk_data) {
3751
633
        return DRWAV_FALSE;
3752
633
    }
3753
3754
    /* Basic validation. */
3755
2.33k
    if ((fmt.sampleRate    == 0 || fmt.sampleRate    > DRWAV_MAX_SAMPLE_RATE    ) ||
3756
2.28k
        (fmt.channels      == 0 || fmt.channels      > DRWAV_MAX_CHANNELS       ) ||
3757
2.27k
        (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) ||
3758
2.24k
        fmt.blockAlign == 0) {
3759
101
        return DRWAV_FALSE; /* Probably an invalid WAV file. */
3760
101
    }
3761
3762
    /* Translate the internal format. */
3763
2.23k
    translatedFormatTag = fmt.formatTag;
3764
2.23k
    if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
3765
4
        translatedFormatTag = drwav_bytes_to_u16_ex(fmt.subFormat + 0, pWav->container);
3766
4
    }
3767
3768
    /* 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. */
3769
2.23k
    if (!sequential) {
3770
2.23k
        if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) {
3771
32
            return DRWAV_FALSE;
3772
32
        }
3773
2.20k
        cursor = pWav->dataChunkDataPos;
3774
2.20k
    }
3775
3776
3777
    /*
3778
    At this point we should have done the initial parsing of each of our chunks, but we now need to
3779
    do a second pass to extract the actual contents of the metadata (the first pass just calculated
3780
    the length of the memory allocation).
3781
3782
    We only do this if we've actually got metadata to parse.
3783
    */
3784
2.20k
    if (isProcessingMetadata && metadataParser.metadataCount > 0) {
3785
0
        if (drwav__seek_from_start(pWav->onSeek, metadataStartPos, pWav->pUserData) == DRWAV_FALSE) {
3786
0
            return DRWAV_FALSE;
3787
0
        }
3788
3789
0
        result = drwav__metadata_alloc(&metadataParser, &pWav->allocationCallbacks);
3790
0
        if (result != DRWAV_SUCCESS) {
3791
0
            return DRWAV_FALSE;
3792
0
        }
3793
3794
0
        metadataParser.stage = drwav__metadata_parser_stage_read;
3795
3796
0
        for (;;) {
3797
0
            drwav_chunk_header header;
3798
0
            drwav_uint64 metadataBytesRead;
3799
3800
0
            result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
3801
0
            if (result != DRWAV_SUCCESS) {
3802
0
                break;
3803
0
            }
3804
3805
0
            metadataBytesRead = drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown);
3806
3807
0
            if (metadataParser.metadataCursor == metadataParser.metadataCount) {
3808
0
                break;
3809
0
            }
3810
3811
            /* Move to the end of the chunk so we can keep iterating. */
3812
0
            if (drwav__seek_forward(pWav->onSeek, (header.sizeInBytes + header.paddingSize) - metadataBytesRead, pWav->pUserData) == DRWAV_FALSE) {
3813
0
                drwav_free(metadataParser.pMetadata, &pWav->allocationCallbacks);
3814
0
                return DRWAV_FALSE;
3815
0
            }
3816
0
        }
3817
3818
        /* Getting here means we're finished parsing the metadata. */
3819
0
        pWav->pMetadata     = metadataParser.pMetadata;
3820
0
        pWav->metadataCount = metadataParser.metadataCount;
3821
0
    }
3822
3823
    /*
3824
    It's possible for the size reported in the data chunk to be greater than that of the file. We
3825
    need to do a validation check here to make sure we don't exceed the file size. To skip this
3826
    check, set the onTell callback to NULL.
3827
    */
3828
2.20k
    if (pWav->onTell != NULL && pWav->onSeek != NULL) {
3829
2.20k
        if (pWav->onSeek(pWav->pUserData, 0, DRWAV_SEEK_END) == DRWAV_TRUE) {
3830
2.20k
            drwav_int64 fileSize;
3831
2.20k
            if (pWav->onTell(pWav->pUserData, &fileSize)) {
3832
2.20k
                if (dataChunkSize + pWav->dataChunkDataPos > (drwav_uint64)fileSize) {
3833
2.01k
                    dataChunkSize = (drwav_uint64)fileSize - pWav->dataChunkDataPos;
3834
2.01k
                }
3835
2.20k
            }
3836
2.20k
        } else {
3837
            /*
3838
            Failed to seek to the end of the file. It might not be supported by the backend so in
3839
            this case we cannot perform the validation check.
3840
            */
3841
0
        }
3842
2.20k
    }
3843
3844
    /*
3845
    I've seen a WAV file in the wild where a RIFF-ecapsulated file has the size of it's "RIFF" and
3846
    "data" chunks set to 0xFFFFFFFF when the file is definitely not that big. In this case we're
3847
    going to have to calculate the size by reading and discarding bytes, and then seeking back. We
3848
    cannot do this in sequential mode. We just assume that the rest of the file is audio data.
3849
    */
3850
2.20k
    if (dataChunkSize == 0xFFFFFFFF && (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) && pWav->isSequentialWrite == DRWAV_FALSE) {
3851
0
        dataChunkSize = 0;
3852
3853
0
        for (;;) {
3854
0
            drwav_uint8 temp[4096];
3855
0
            size_t bytesRead = pWav->onRead(pWav->pUserData, temp, sizeof(temp));
3856
0
            dataChunkSize += bytesRead;
3857
3858
0
            if (bytesRead < sizeof(temp)) {
3859
0
                break;
3860
0
            }
3861
0
        }
3862
0
    }
3863
3864
    /* At this point we want to be sitting on the first byte of the raw audio data. */
3865
2.20k
    if (drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData) == DRWAV_FALSE) {
3866
0
        drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3867
0
        return DRWAV_FALSE;
3868
0
    }
3869
3870
3871
2.20k
    pWav->fmt                 = fmt;
3872
2.20k
    pWav->sampleRate          = fmt.sampleRate;
3873
2.20k
    pWav->channels            = fmt.channels;
3874
2.20k
    pWav->bitsPerSample       = fmt.bitsPerSample;
3875
2.20k
    pWav->translatedFormatTag = translatedFormatTag;
3876
3877
    /*
3878
    I've had a report where files would start glitching after seeking. The reason for this is the data
3879
    chunk is not a clean multiple of the PCM frame size in bytes. Where this becomes a problem is when
3880
    seeking, because the number of bytes remaining in the data chunk is used to calculate the current
3881
    byte position. If this byte position is not aligned to the number of bytes in a PCM frame, it will
3882
    result in the seek not being cleanly positioned at the start of the PCM frame thereby resulting in
3883
    all decoded frames after that being corrupted.
3884
3885
    To address this, we need to round the data chunk size down to the nearest multiple of the frame size.
3886
    */
3887
2.20k
    if (!drwav__is_compressed_format_tag(translatedFormatTag)) {
3888
961
        drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
3889
961
        if (bytesPerFrame > 0) {
3890
933
            dataChunkSize -= (dataChunkSize % bytesPerFrame);
3891
933
        }
3892
961
    }
3893
3894
2.20k
    pWav->bytesRemaining      = dataChunkSize;
3895
2.20k
    pWav->dataChunkDataSize   = dataChunkSize;
3896
3897
2.20k
    if (sampleCountFromFactChunk != 0) {
3898
487
        pWav->totalPCMFrameCount = sampleCountFromFactChunk;
3899
1.71k
    } else if (aiffFrameCount != 0) {
3900
148
        pWav->totalPCMFrameCount = aiffFrameCount;
3901
1.56k
    } else {
3902
1.56k
        drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
3903
1.56k
        if (bytesPerFrame == 0) {
3904
26
            drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3905
26
            return DRWAV_FALSE; /* Invalid file. */
3906
26
        }
3907
3908
1.54k
        pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame;
3909
3910
1.54k
        if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3911
582
            drwav_uint64 totalBlockHeaderSizeInBytes;
3912
582
            drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3913
3914
            /* Make sure any trailing partial block is accounted for. */
3915
582
            if ((blockCount * fmt.blockAlign) < dataChunkSize) {
3916
541
                blockCount += 1;
3917
541
            }
3918
3919
            /* 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. */
3920
582
            totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
3921
582
            if (totalBlockHeaderSizeInBytes >= dataChunkSize) {  /* <-- We'll be subtracting totalBlockHeaderSizeInBytes from dataChunkSize next so it must be validated. */
3922
49
                drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3923
49
                return DRWAV_FALSE; /* Invalid file. */
3924
49
            }
3925
3926
533
            pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
3927
533
        }
3928
1.49k
        if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3929
334
            drwav_uint64 totalBlockHeaderSizeInBytes;
3930
334
            drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3931
3932
            /* Make sure any trailing partial block is accounted for. */
3933
334
            if ((blockCount * fmt.blockAlign) < dataChunkSize) {
3934
304
                blockCount += 1;
3935
304
            }
3936
3937
            /* 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. */
3938
334
            totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
3939
334
            if (totalBlockHeaderSizeInBytes >= dataChunkSize) {  /* <-- We'll be subtracting totalBlockHeaderSizeInBytes from dataChunkSize next so it must be validated. */
3940
50
                drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3941
50
                return DRWAV_FALSE; /* Invalid file. */
3942
50
            }
3943
3944
284
            pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
3945
3946
            /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */
3947
284
            pWav->totalPCMFrameCount += blockCount;
3948
284
        }
3949
1.49k
    }
3950
3951
    /* Some formats only support a certain number of channels. */
3952
2.07k
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3953
1.14k
        if (pWav->channels > 2) {
3954
50
            drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3955
50
            return DRWAV_FALSE;
3956
50
        }
3957
1.14k
    }
3958
3959
    /* The number of bytes per frame must be known. If not, it's an invalid file and not decodable. */
3960
2.02k
    if (drwav_get_bytes_per_pcm_frame(pWav) == 0) {
3961
2
        drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3962
2
        return DRWAV_FALSE;
3963
2
    }
3964
3965
#ifdef DR_WAV_LIBSNDFILE_COMPAT
3966
    /*
3967
    I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website),
3968
    it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count
3969
    from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct
3970
    way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should
3971
    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
3972
    correctness tests against libsndfile, and is disabled by default.
3973
    */
3974
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3975
        drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3976
        pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels;  /* x2 because two samples per byte. */
3977
    }
3978
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3979
        drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3980
        pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
3981
    }
3982
#endif
3983
3984
2.02k
    return DRWAV_TRUE;
3985
2.02k
}
3986
3987
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
3988
0
{
3989
0
    return drwav_init_ex(pWav, onRead, onSeek, onTell, NULL, pUserData, NULL, 0, pAllocationCallbacks);
3990
0
}
3991
3992
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, drwav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
3993
0
{
3994
0
    if (!drwav_preinit(pWav, onRead, onSeek, onTell, pReadSeekTellUserData, pAllocationCallbacks)) {
3995
0
        return DRWAV_FALSE;
3996
0
    }
3997
3998
0
    return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
3999
0
}
4000
4001
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
4002
0
{
4003
0
    if (!drwav_preinit(pWav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
4004
0
        return DRWAV_FALSE;
4005
0
    }
4006
4007
0
    return drwav_init__internal(pWav, NULL, NULL, flags | DRWAV_WITH_METADATA);
4008
0
}
4009
4010
DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav)
4011
0
{
4012
0
    drwav_metadata *result = pWav->pMetadata;
4013
4014
0
    pWav->pMetadata     = NULL;
4015
0
    pWav->metadataCount = 0;
4016
4017
0
    return result;
4018
0
}
4019
4020
4021
DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
4022
0
{
4023
0
    DRWAV_ASSERT(pWav          != NULL);
4024
0
    DRWAV_ASSERT(pWav->onWrite != NULL);
4025
4026
    /* Generic write. Assumes no byte reordering required. */
4027
0
    return pWav->onWrite(pWav->pUserData, pData, dataSize);
4028
0
}
4029
4030
DRWAV_PRIVATE size_t drwav__write_byte(drwav* pWav, drwav_uint8 byte)
4031
0
{
4032
0
    DRWAV_ASSERT(pWav          != NULL);
4033
0
    DRWAV_ASSERT(pWav->onWrite != NULL);
4034
4035
0
    return pWav->onWrite(pWav->pUserData, &byte, 1);
4036
0
}
4037
4038
DRWAV_PRIVATE size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value)
4039
0
{
4040
0
    DRWAV_ASSERT(pWav          != NULL);
4041
0
    DRWAV_ASSERT(pWav->onWrite != NULL);
4042
4043
0
    if (!drwav__is_little_endian()) {
4044
0
        value = drwav__bswap16(value);
4045
0
    }
4046
4047
0
    return drwav__write(pWav, &value, 2);
4048
0
}
4049
4050
DRWAV_PRIVATE size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value)
4051
0
{
4052
0
    DRWAV_ASSERT(pWav          != NULL);
4053
0
    DRWAV_ASSERT(pWav->onWrite != NULL);
4054
4055
0
    if (!drwav__is_little_endian()) {
4056
0
        value = drwav__bswap32(value);
4057
0
    }
4058
4059
0
    return drwav__write(pWav, &value, 4);
4060
0
}
4061
4062
DRWAV_PRIVATE size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value)
4063
0
{
4064
0
    DRWAV_ASSERT(pWav          != NULL);
4065
0
    DRWAV_ASSERT(pWav->onWrite != NULL);
4066
4067
0
    if (!drwav__is_little_endian()) {
4068
0
        value = drwav__bswap64(value);
4069
0
    }
4070
4071
0
    return drwav__write(pWav, &value, 8);
4072
0
}
4073
4074
DRWAV_PRIVATE size_t drwav__write_f32ne_to_le(drwav* pWav, float value)
4075
0
{
4076
0
    union {
4077
0
       drwav_uint32 u32;
4078
0
       float f32;
4079
0
    } u;
4080
4081
0
    DRWAV_ASSERT(pWav          != NULL);
4082
0
    DRWAV_ASSERT(pWav->onWrite != NULL);
4083
4084
0
    u.f32 = value;
4085
4086
0
    if (!drwav__is_little_endian()) {
4087
0
        u.u32 = drwav__bswap32(u.u32);
4088
0
    }
4089
4090
0
    return drwav__write(pWav, &u.u32, 4);
4091
0
}
4092
4093
DRWAV_PRIVATE size_t drwav__write_or_count(drwav* pWav, const void* pData, size_t dataSize)
4094
0
{
4095
0
    if (pWav == NULL) {
4096
0
        return dataSize;
4097
0
    }
4098
4099
0
    return drwav__write(pWav, pData, dataSize);
4100
0
}
4101
4102
DRWAV_PRIVATE size_t drwav__write_or_count_byte(drwav* pWav, drwav_uint8 byte)
4103
0
{
4104
0
    if (pWav == NULL) {
4105
0
        return 1;
4106
0
    }
4107
4108
0
    return drwav__write_byte(pWav, byte);
4109
0
}
4110
4111
DRWAV_PRIVATE size_t drwav__write_or_count_u16ne_to_le(drwav* pWav, drwav_uint16 value)
4112
0
{
4113
0
    if (pWav == NULL) {
4114
0
        return 2;
4115
0
    }
4116
4117
0
    return drwav__write_u16ne_to_le(pWav, value);
4118
0
}
4119
4120
DRWAV_PRIVATE size_t drwav__write_or_count_u32ne_to_le(drwav* pWav, drwav_uint32 value)
4121
0
{
4122
0
    if (pWav == NULL) {
4123
0
        return 4;
4124
0
    }
4125
4126
0
    return drwav__write_u32ne_to_le(pWav, value);
4127
0
}
4128
4129
#if 0   /* Unused for now. */
4130
DRWAV_PRIVATE size_t drwav__write_or_count_u64ne_to_le(drwav* pWav, drwav_uint64 value)
4131
{
4132
    if (pWav == NULL) {
4133
        return 8;
4134
    }
4135
4136
    return drwav__write_u64ne_to_le(pWav, value);
4137
}
4138
#endif
4139
4140
DRWAV_PRIVATE size_t drwav__write_or_count_f32ne_to_le(drwav* pWav, float value)
4141
0
{
4142
0
    if (pWav == NULL) {
4143
0
        return 4;
4144
0
    }
4145
4146
0
    return drwav__write_f32ne_to_le(pWav, value);
4147
0
}
4148
4149
DRWAV_PRIVATE size_t drwav__write_or_count_string_to_fixed_size_buf(drwav* pWav, char* str, size_t bufFixedSize)
4150
0
{
4151
0
    size_t len;
4152
4153
0
    if (pWav == NULL) {
4154
0
        return bufFixedSize;
4155
0
    }
4156
4157
0
    len = drwav__strlen_clamped(str, bufFixedSize);
4158
0
    drwav__write_or_count(pWav, str, len);
4159
4160
0
    if (len < bufFixedSize) {
4161
0
        size_t i;
4162
0
        for (i = 0; i < bufFixedSize - len; ++i) {
4163
0
            drwav__write_byte(pWav, 0);
4164
0
        }
4165
0
    }
4166
4167
0
    return bufFixedSize;
4168
0
}
4169
4170
4171
/* pWav can be NULL meaning just count the bytes that would be written. */
4172
DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* pMetadatas, drwav_uint32 metadataCount)
4173
0
{
4174
0
    size_t bytesWritten = 0;
4175
0
    drwav_bool32 hasListAdtl = DRWAV_FALSE;
4176
0
    drwav_bool32 hasListInfo = DRWAV_FALSE;
4177
0
    drwav_uint32 iMetadata;
4178
4179
0
    if (pMetadatas == NULL || metadataCount == 0) {
4180
0
        return 0;
4181
0
    }
4182
4183
0
    for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4184
0
        drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4185
0
        drwav_uint32 chunkSize = 0;
4186
4187
0
        if ((pMetadata->type & drwav_metadata_type_list_all_info_strings) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list)) {
4188
0
            hasListInfo = DRWAV_TRUE;
4189
0
        }
4190
4191
0
        if ((pMetadata->type & drwav_metadata_type_list_all_adtl) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list)) {
4192
0
            hasListAdtl = DRWAV_TRUE;
4193
0
        }
4194
4195
0
        switch (pMetadata->type) {
4196
0
            case drwav_metadata_type_smpl:
4197
0
            {
4198
0
                drwav_uint32 iLoop;
4199
4200
0
                chunkSize = DRWAV_SMPL_BYTES + DRWAV_SMPL_LOOP_BYTES * pMetadata->data.smpl.sampleLoopCount + pMetadata->data.smpl.samplerSpecificDataSizeInBytes;
4201
4202
0
                bytesWritten += drwav__write_or_count(pWav, "smpl", 4);
4203
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4204
4205
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.manufacturerId);
4206
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.productId);
4207
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplePeriodNanoseconds);
4208
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiUnityNote);
4209
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiPitchFraction);
4210
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteFormat);
4211
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteOffset);
4212
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.sampleLoopCount);
4213
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplerSpecificDataSizeInBytes);
4214
4215
0
                for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) {
4216
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId);
4217
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type);
4218
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleOffset);
4219
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleOffset);
4220
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction);
4221
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount);
4222
0
                }
4223
4224
0
                if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) {
4225
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes);
4226
0
                }
4227
0
            } break;
4228
4229
0
            case drwav_metadata_type_inst:
4230
0
            {
4231
0
                chunkSize = DRWAV_INST_BYTES;
4232
4233
0
                bytesWritten += drwav__write_or_count(pWav, "inst", 4);
4234
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4235
0
                bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.midiUnityNote, 1);
4236
0
                bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.fineTuneCents, 1);
4237
0
                bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.gainDecibels, 1);
4238
0
                bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.lowNote, 1);
4239
0
                bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.highNote, 1);
4240
0
                bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.lowVelocity, 1);
4241
0
                bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.highVelocity, 1);
4242
0
            } break;
4243
4244
0
            case drwav_metadata_type_cue:
4245
0
            {
4246
0
                drwav_uint32 iCuePoint;
4247
4248
0
                chunkSize = DRWAV_CUE_BYTES + DRWAV_CUE_POINT_BYTES * pMetadata->data.cue.cuePointCount;
4249
4250
0
                bytesWritten += drwav__write_or_count(pWav, "cue ", 4);
4251
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4252
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.cuePointCount);
4253
0
                for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) {
4254
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].id);
4255
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition);
4256
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4);
4257
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart);
4258
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart);
4259
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset);
4260
0
                }
4261
0
            } break;
4262
4263
0
            case drwav_metadata_type_acid:
4264
0
            {
4265
0
                chunkSize = DRWAV_ACID_BYTES;
4266
4267
0
                bytesWritten += drwav__write_or_count(pWav, "acid", 4);
4268
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4269
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.flags);
4270
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.midiUnityNote);
4271
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.reserved1);
4272
0
                bytesWritten += drwav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.reserved2);
4273
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.numBeats);
4274
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterDenominator);
4275
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterNumerator);
4276
0
                bytesWritten += drwav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.tempo);
4277
0
            } break;
4278
4279
0
            case drwav_metadata_type_bext:
4280
0
            {
4281
0
                char reservedBuf[DRWAV_BEXT_RESERVED_BYTES];
4282
0
                drwav_uint32 timeReferenceLow;
4283
0
                drwav_uint32 timeReferenceHigh;
4284
4285
0
                chunkSize = DRWAV_BEXT_BYTES + pMetadata->data.bext.codingHistorySize;
4286
4287
0
                bytesWritten += drwav__write_or_count(pWav, "bext", 4);
4288
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4289
4290
0
                bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pDescription, DRWAV_BEXT_DESCRIPTION_BYTES);
4291
0
                bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorName, DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
4292
0
                bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorReference, DRWAV_BEXT_ORIGINATOR_REF_BYTES);
4293
0
                bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate));
4294
0
                bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime));
4295
4296
0
                timeReferenceLow  = (drwav_uint32)(pMetadata->data.bext.timeReference & 0xFFFFFFFF);
4297
0
                timeReferenceHigh = (drwav_uint32)(pMetadata->data.bext.timeReference >> 32);
4298
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, timeReferenceLow);
4299
0
                bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, timeReferenceHigh);
4300
4301
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.version);
4302
0
                bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES);
4303
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessValue);
4304
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessRange);
4305
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxTruePeakLevel);
4306
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxMomentaryLoudness);
4307
0
                bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxShortTermLoudness);
4308
4309
0
                DRWAV_ZERO_MEMORY(reservedBuf, sizeof(reservedBuf));
4310
0
                bytesWritten += drwav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf));
4311
4312
0
                if (pMetadata->data.bext.codingHistorySize > 0) {
4313
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pCodingHistory, pMetadata->data.bext.codingHistorySize);
4314
0
                }
4315
0
            } break;
4316
4317
0
            case drwav_metadata_type_unknown:
4318
0
            {
4319
0
                if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_top_level) {
4320
0
                    chunkSize = pMetadata->data.unknown.dataSizeInBytes;
4321
4322
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
4323
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4324
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes);
4325
0
                }
4326
0
            } break;
4327
4328
0
            default: break;
4329
0
        }
4330
0
        if ((chunkSize % 2) != 0) {
4331
0
            bytesWritten += drwav__write_or_count_byte(pWav, 0);
4332
0
        }
4333
0
    }
4334
4335
0
    if (hasListInfo) {
4336
0
        drwav_uint32 chunkSize = 4; /* Start with 4 bytes for "INFO". */
4337
0
        for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4338
0
            drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4339
4340
0
            if ((pMetadata->type & drwav_metadata_type_list_all_info_strings)) {
4341
0
                chunkSize += 8; /* For id and string size. */
4342
0
                chunkSize += pMetadata->data.infoText.stringLength + 1; /* Include null terminator. */
4343
0
            } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) {
4344
0
                chunkSize += 8; /* For id string size. */
4345
0
                chunkSize += pMetadata->data.unknown.dataSizeInBytes;
4346
0
            }
4347
4348
0
            if ((chunkSize % 2) != 0) {
4349
0
                chunkSize += 1;
4350
0
            }
4351
0
        }
4352
4353
0
        bytesWritten += drwav__write_or_count(pWav, "LIST", 4);
4354
0
        bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4355
0
        bytesWritten += drwav__write_or_count(pWav, "INFO", 4);
4356
4357
0
        for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4358
0
            drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4359
0
            drwav_uint32 subchunkSize = 0;
4360
4361
0
            if (pMetadata->type & drwav_metadata_type_list_all_info_strings) {
4362
0
                const char* pID = NULL;
4363
4364
0
                switch (pMetadata->type) {
4365
0
                    case drwav_metadata_type_list_info_software:     pID = "ISFT"; break;
4366
0
                    case drwav_metadata_type_list_info_copyright:    pID = "ICOP"; break;
4367
0
                    case drwav_metadata_type_list_info_title:        pID = "INAM"; break;
4368
0
                    case drwav_metadata_type_list_info_artist:       pID = "IART"; break;
4369
0
                    case drwav_metadata_type_list_info_comment:      pID = "ICMT"; break;
4370
0
                    case drwav_metadata_type_list_info_date:         pID = "ICRD"; break;
4371
0
                    case drwav_metadata_type_list_info_genre:        pID = "IGNR"; break;
4372
0
                    case drwav_metadata_type_list_info_album:        pID = "IPRD"; break;
4373
0
                    case drwav_metadata_type_list_info_tracknumber:  pID = "ITRK"; break;
4374
0
                    case drwav_metadata_type_list_info_location:     pID = "IARL"; break;
4375
0
                    case drwav_metadata_type_list_info_organization: pID = "ICMS"; break;
4376
0
                    case drwav_metadata_type_list_info_keywords:     pID = "IKEY"; break;
4377
0
                    case drwav_metadata_type_list_info_medium:       pID = "IMED"; break;
4378
0
                    case drwav_metadata_type_list_info_description:  pID = "ISBJ"; break;
4379
0
                    default: break;
4380
0
                }
4381
4382
0
                DRWAV_ASSERT(pID != NULL);
4383
4384
0
                if (pMetadata->data.infoText.stringLength) {
4385
0
                    subchunkSize = pMetadata->data.infoText.stringLength + 1;
4386
0
                    bytesWritten += drwav__write_or_count(pWav, pID, 4);
4387
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
4388
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.infoText.pString, pMetadata->data.infoText.stringLength);
4389
0
                    bytesWritten += drwav__write_or_count_byte(pWav, '\0');
4390
0
                }
4391
0
            } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) {
4392
0
                if (pMetadata->data.unknown.dataSizeInBytes) {
4393
0
                    subchunkSize = pMetadata->data.unknown.dataSizeInBytes;
4394
4395
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
4396
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.unknown.dataSizeInBytes);
4397
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize);
4398
0
                }
4399
0
            }
4400
4401
0
            if ((subchunkSize % 2) != 0) {
4402
0
                bytesWritten += drwav__write_or_count_byte(pWav, 0);
4403
0
            }
4404
0
        }
4405
0
    }
4406
4407
0
    if (hasListAdtl) {
4408
0
        drwav_uint32 chunkSize = 4; /* start with 4 bytes for "adtl" */
4409
4410
0
        for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4411
0
            drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4412
4413
0
            switch (pMetadata->type)
4414
0
            {
4415
0
                case drwav_metadata_type_list_label:
4416
0
                case drwav_metadata_type_list_note:
4417
0
                {
4418
0
                    chunkSize += 8; /* for id and chunk size */
4419
0
                    chunkSize += DRWAV_LIST_LABEL_OR_NOTE_BYTES;
4420
4421
0
                    if (pMetadata->data.labelOrNote.stringLength > 0) {
4422
0
                        chunkSize += pMetadata->data.labelOrNote.stringLength + 1;
4423
0
                    }
4424
0
                } break;
4425
4426
0
                case drwav_metadata_type_list_labelled_cue_region:
4427
0
                {
4428
0
                    chunkSize += 8; /* for id and chunk size */
4429
0
                    chunkSize += DRWAV_LIST_LABELLED_TEXT_BYTES;
4430
4431
0
                    if (pMetadata->data.labelledCueRegion.stringLength > 0) {
4432
0
                        chunkSize += pMetadata->data.labelledCueRegion.stringLength + 1;
4433
0
                    }
4434
0
                } break;
4435
4436
0
                case drwav_metadata_type_unknown:
4437
0
                {
4438
0
                    if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) {
4439
0
                        chunkSize += 8; /* for id and chunk size */
4440
0
                        chunkSize += pMetadata->data.unknown.dataSizeInBytes;
4441
0
                    }
4442
0
                } break;
4443
4444
0
                default: break;
4445
0
            }
4446
4447
0
            if ((chunkSize % 2) != 0) {
4448
0
                chunkSize += 1;
4449
0
            }
4450
0
        }
4451
4452
0
        bytesWritten += drwav__write_or_count(pWav, "LIST", 4);
4453
0
        bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4454
0
        bytesWritten += drwav__write_or_count(pWav, "adtl", 4);
4455
4456
0
        for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4457
0
            drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4458
0
            drwav_uint32 subchunkSize = 0;
4459
4460
0
            switch (pMetadata->type)
4461
0
            {
4462
0
                case drwav_metadata_type_list_label:
4463
0
                case drwav_metadata_type_list_note:
4464
0
                {
4465
0
                    if (pMetadata->data.labelOrNote.stringLength > 0) {
4466
0
                        const char *pID = NULL;
4467
4468
0
                        if (pMetadata->type == drwav_metadata_type_list_label) {
4469
0
                            pID = "labl";
4470
0
                        }
4471
0
                        else if (pMetadata->type == drwav_metadata_type_list_note) {
4472
0
                            pID = "note";
4473
0
                        }
4474
4475
0
                        DRWAV_ASSERT(pID != NULL);
4476
0
                        DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL);
4477
4478
0
                        subchunkSize = DRWAV_LIST_LABEL_OR_NOTE_BYTES;
4479
4480
0
                        bytesWritten += drwav__write_or_count(pWav, pID, 4);
4481
0
                        subchunkSize += pMetadata->data.labelOrNote.stringLength + 1;
4482
0
                        bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
4483
4484
0
                        bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelOrNote.cuePointId);
4485
0
                        bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelOrNote.pString, pMetadata->data.labelOrNote.stringLength);
4486
0
                        bytesWritten += drwav__write_or_count_byte(pWav, '\0');
4487
0
                    }
4488
0
                } break;
4489
4490
0
                case drwav_metadata_type_list_labelled_cue_region:
4491
0
                {
4492
0
                    subchunkSize = DRWAV_LIST_LABELLED_TEXT_BYTES;
4493
4494
0
                    bytesWritten += drwav__write_or_count(pWav, "ltxt", 4);
4495
0
                    if (pMetadata->data.labelledCueRegion.stringLength > 0) {
4496
0
                        subchunkSize += pMetadata->data.labelledCueRegion.stringLength + 1;
4497
0
                    }
4498
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
4499
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.cuePointId);
4500
0
                    bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.sampleLength);
4501
0
                    bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.purposeId, 4);
4502
0
                    bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.country);
4503
0
                    bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.language);
4504
0
                    bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.dialect);
4505
0
                    bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.codePage);
4506
4507
0
                    if (pMetadata->data.labelledCueRegion.stringLength > 0) {
4508
0
                        DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL);
4509
4510
0
                        bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.pString, pMetadata->data.labelledCueRegion.stringLength);
4511
0
                        bytesWritten += drwav__write_or_count_byte(pWav, '\0');
4512
0
                    }
4513
0
                } break;
4514
4515
0
                case drwav_metadata_type_unknown:
4516
0
                {
4517
0
                    if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) {
4518
0
                        subchunkSize = pMetadata->data.unknown.dataSizeInBytes;
4519
4520
0
                        DRWAV_ASSERT(pMetadata->data.unknown.pData != NULL);
4521
0
                        bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
4522
0
                        bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
4523
0
                        bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize);
4524
0
                    }
4525
0
                } break;
4526
4527
0
                default: break;
4528
0
            }
4529
4530
0
            if ((subchunkSize % 2) != 0) {
4531
0
                bytesWritten += drwav__write_or_count_byte(pWav, 0);
4532
0
            }
4533
0
        }
4534
0
    }
4535
4536
0
    DRWAV_ASSERT((bytesWritten % 2) == 0);
4537
4538
0
    return bytesWritten;
4539
0
}
4540
4541
DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
4542
0
{
4543
0
    drwav_uint64 chunkSize = 4 + 24 + (drwav_uint64)drwav__write_or_count_metadata(NULL, pMetadata, metadataCount) + 8 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. 8 = "data" + u32 data size. */
4544
0
    if (chunkSize > 0xFFFFFFFFUL) {
4545
0
        chunkSize = 0xFFFFFFFFUL;
4546
0
    }
4547
4548
0
    return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */
4549
0
}
4550
4551
DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
4552
0
{
4553
0
    if (dataChunkSize <= 0xFFFFFFFFUL) {
4554
0
        return (drwav_uint32)dataChunkSize;
4555
0
    } else {
4556
0
        return 0xFFFFFFFFUL;
4557
0
    }
4558
0
}
4559
4560
DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
4561
0
{
4562
0
    drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
4563
4564
0
    return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize;   /* +24 because W64 includes the size of the GUID and size fields. */
4565
0
}
4566
4567
DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
4568
0
{
4569
0
    return 24 + dataChunkSize;        /* +24 because W64 includes the size of the GUID and size fields. */
4570
0
}
4571
4572
DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize, drwav_metadata *metadata, drwav_uint32 numMetadata)
4573
0
{
4574
0
    drwav_uint64 chunkSize = 4 + 36 + 24 + (drwav_uint64)drwav__write_or_count_metadata(NULL, metadata, numMetadata) + 8 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. 8 = "data" + u32 data size. */
4575
0
    if (chunkSize > 0xFFFFFFFFUL) {
4576
0
        chunkSize = 0xFFFFFFFFUL;
4577
0
    }
4578
4579
0
    return chunkSize;
4580
0
}
4581
4582
DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
4583
0
{
4584
0
    return dataChunkSize;
4585
0
}
4586
4587
4588
4589
DRWAV_PRIVATE 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)
4590
0
{
4591
0
    if (pWav == NULL || onWrite == NULL) {
4592
0
        return DRWAV_FALSE;
4593
0
    }
4594
4595
0
    if (!isSequential && onSeek == NULL) {
4596
0
        return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */
4597
0
    }
4598
4599
    /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */
4600
0
    if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
4601
0
        return DRWAV_FALSE;
4602
0
    }
4603
0
    if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
4604
0
        return DRWAV_FALSE;
4605
0
    }
4606
4607
0
    DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
4608
0
    pWav->onWrite   = onWrite;
4609
0
    pWav->onSeek    = onSeek;
4610
0
    pWav->pUserData = pUserData;
4611
0
    pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
4612
4613
0
    if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
4614
0
        return DRWAV_FALSE;    /* Invalid allocation callbacks. */
4615
0
    }
4616
4617
0
    pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
4618
0
    pWav->fmt.channels = (drwav_uint16)pFormat->channels;
4619
0
    pWav->fmt.sampleRate = pFormat->sampleRate;
4620
0
    pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8);
4621
0
    pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8);
4622
0
    pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
4623
0
    pWav->fmt.extendedSize = 0;
4624
0
    pWav->isSequentialWrite = isSequential;
4625
4626
0
    return DRWAV_TRUE;
4627
0
}
4628
4629
4630
DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
4631
0
{
4632
    /* The function assumes drwav_preinit_write() was called beforehand. */
4633
4634
0
    size_t runningPos = 0;
4635
0
    drwav_uint64 initialDataChunkSize = 0;
4636
0
    drwav_uint64 chunkSizeFMT;
4637
4638
    /*
4639
    The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In
4640
    sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non-
4641
    sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek.
4642
    */
4643
0
    if (pWav->isSequentialWrite) {
4644
0
        initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
4645
4646
        /*
4647
        The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64
4648
        so for the sake of simplicity I'm not doing any validation for that.
4649
        */
4650
0
        if (pFormat->container == drwav_container_riff) {
4651
0
            if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
4652
0
                return DRWAV_FALSE; /* Not enough room to store every sample. */
4653
0
            }
4654
0
        }
4655
0
    }
4656
4657
0
    pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
4658
4659
4660
    /* "RIFF" chunk. */
4661
0
    if (pFormat->container == drwav_container_riff) {
4662
0
        drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize;   /* +36 = "WAVE" + [sizeof "fmt " chunk] + [data chunk header] */
4663
0
        runningPos += drwav__write(pWav, "RIFF", 4);
4664
0
        runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
4665
0
        runningPos += drwav__write(pWav, "WAVE", 4);
4666
0
    } else if (pFormat->container == drwav_container_w64) {
4667
0
        drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize;            /* +24 because W64 includes the size of the GUID and size fields. */
4668
0
        runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
4669
0
        runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
4670
0
        runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
4671
0
    } else if (pFormat->container == drwav_container_rf64) {
4672
0
        runningPos += drwav__write(pWav, "RF64", 4);
4673
0
        runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);               /* Always 0xFFFFFFFF for RF64. Set to a proper value in the "ds64" chunk. */
4674
0
        runningPos += drwav__write(pWav, "WAVE", 4);
4675
0
    } else {
4676
0
        return DRWAV_FALSE; /* Container not supported for writing. */
4677
0
    }
4678
4679
4680
    /* "ds64" chunk (RF64 only). */
4681
0
    if (pFormat->container == drwav_container_rf64) {
4682
0
        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. */
4683
0
        drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize;    /* +8 for the ds64 header. */
4684
4685
0
        runningPos += drwav__write(pWav, "ds64", 4);
4686
0
        runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize);     /* Size of ds64. */
4687
0
        runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize);     /* Size of RIFF. Set to true value at the end. */
4688
0
        runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize);     /* Size of DATA. Set to true value at the end. */
4689
0
        runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount);         /* Sample count. */
4690
0
        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". */
4691
0
    }
4692
4693
4694
    /* "fmt " chunk. */
4695
0
    if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
4696
0
        chunkSizeFMT = 16;
4697
0
        runningPos += drwav__write(pWav, "fmt ", 4);
4698
0
        runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
4699
0
    } else if (pFormat->container == drwav_container_w64) {
4700
0
        chunkSizeFMT = 40;
4701
0
        runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
4702
0
        runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
4703
0
    }
4704
4705
0
    runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag);
4706
0
    runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels);
4707
0
    runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate);
4708
0
    runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec);
4709
0
    runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign);
4710
0
    runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample);
4711
4712
    /* TODO: is a 'fact' chunk required for DR_WAVE_FORMAT_IEEE_FLOAT? */
4713
4714
0
    if (!pWav->isSequentialWrite && pWav->pMetadata != NULL && pWav->metadataCount > 0 && (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64)) {
4715
0
        runningPos += drwav__write_or_count_metadata(pWav, pWav->pMetadata, pWav->metadataCount);
4716
0
    }
4717
4718
0
    pWav->dataChunkDataPos = runningPos;
4719
4720
    /* "data" chunk. */
4721
0
    if (pFormat->container == drwav_container_riff) {
4722
0
        drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
4723
0
        runningPos += drwav__write(pWav, "data", 4);
4724
0
        runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
4725
0
    } else if (pFormat->container == drwav_container_w64) {
4726
0
        drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize;     /* +24 because W64 includes the size of the GUID and size fields. */
4727
0
        runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
4728
0
        runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
4729
0
    } else if (pFormat->container == drwav_container_rf64) {
4730
0
        runningPos += drwav__write(pWav, "data", 4);
4731
0
        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. */
4732
0
    }
4733
4734
    /* Set some properties for the client's convenience. */
4735
0
    pWav->container = pFormat->container;
4736
0
    pWav->channels = (drwav_uint16)pFormat->channels;
4737
0
    pWav->sampleRate = pFormat->sampleRate;
4738
0
    pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
4739
0
    pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
4740
0
    pWav->dataChunkDataPos = runningPos;
4741
4742
0
    return DRWAV_TRUE;
4743
0
}
4744
4745
4746
DRWAV_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)
4747
0
{
4748
0
    if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
4749
0
        return DRWAV_FALSE;
4750
0
    }
4751
4752
0
    return drwav_init_write__internal(pWav, pFormat, 0);               /* DRWAV_FALSE = Not Sequential */
4753
0
}
4754
4755
DRWAV_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)
4756
0
{
4757
0
    if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
4758
0
        return DRWAV_FALSE;
4759
0
    }
4760
4761
0
    return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */
4762
0
}
4763
4764
DRWAV_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)
4765
0
{
4766
0
    if (pFormat == NULL) {
4767
0
        return DRWAV_FALSE;
4768
0
    }
4769
4770
0
    return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
4771
0
}
4772
4773
DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
4774
0
{
4775
0
    if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
4776
0
        return DRWAV_FALSE;
4777
0
    }
4778
4779
0
    pWav->pMetadata     = pMetadata;
4780
0
    pWav->metadataCount = metadataCount;
4781
4782
0
    return drwav_init_write__internal(pWav, pFormat, 0);
4783
0
}
4784
4785
4786
DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
4787
0
{
4788
    /* Casting totalFrameCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */
4789
0
    drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalFrameCount * pFormat->channels * pFormat->bitsPerSample/8.0);
4790
0
    drwav_uint64 riffChunkSizeBytes;
4791
0
    drwav_uint64 fileSizeBytes = 0;
4792
4793
0
    if (pFormat->container == drwav_container_riff) {
4794
0
        riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes, pMetadata, metadataCount);
4795
0
        fileSizeBytes = (8 + riffChunkSizeBytes);   /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
4796
0
    } else if (pFormat->container == drwav_container_w64) {
4797
0
        riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
4798
0
        fileSizeBytes = riffChunkSizeBytes;
4799
0
    } else if (pFormat->container == drwav_container_rf64) {
4800
0
        riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes, pMetadata, metadataCount);
4801
0
        fileSizeBytes = (8 + riffChunkSizeBytes);   /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
4802
0
    }
4803
4804
0
    return fileSizeBytes;
4805
0
}
4806
4807
4808
#ifndef DR_WAV_NO_STDIO
4809
4810
/* Errno */
4811
/* 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. */
4812
#include <errno.h>
4813
DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e)
4814
0
{
4815
0
    switch (e)
4816
0
    {
4817
0
        case 0: return DRWAV_SUCCESS;
4818
0
    #ifdef EPERM
4819
0
        case EPERM: return DRWAV_INVALID_OPERATION;
4820
0
    #endif
4821
0
    #ifdef ENOENT
4822
0
        case ENOENT: return DRWAV_DOES_NOT_EXIST;
4823
0
    #endif
4824
0
    #ifdef ESRCH
4825
0
        case ESRCH: return DRWAV_DOES_NOT_EXIST;
4826
0
    #endif
4827
0
    #ifdef EINTR
4828
0
        case EINTR: return DRWAV_INTERRUPT;
4829
0
    #endif
4830
0
    #ifdef EIO
4831
0
        case EIO: return DRWAV_IO_ERROR;
4832
0
    #endif
4833
0
    #ifdef ENXIO
4834
0
        case ENXIO: return DRWAV_DOES_NOT_EXIST;
4835
0
    #endif
4836
0
    #ifdef E2BIG
4837
0
        case E2BIG: return DRWAV_INVALID_ARGS;
4838
0
    #endif
4839
0
    #ifdef ENOEXEC
4840
0
        case ENOEXEC: return DRWAV_INVALID_FILE;
4841
0
    #endif
4842
0
    #ifdef EBADF
4843
0
        case EBADF: return DRWAV_INVALID_FILE;
4844
0
    #endif
4845
0
    #ifdef ECHILD
4846
0
        case ECHILD: return DRWAV_ERROR;
4847
0
    #endif
4848
0
    #ifdef EAGAIN
4849
0
        case EAGAIN: return DRWAV_UNAVAILABLE;
4850
0
    #endif
4851
0
    #ifdef ENOMEM
4852
0
        case ENOMEM: return DRWAV_OUT_OF_MEMORY;
4853
0
    #endif
4854
0
    #ifdef EACCES
4855
0
        case EACCES: return DRWAV_ACCESS_DENIED;
4856
0
    #endif
4857
0
    #ifdef EFAULT
4858
0
        case EFAULT: return DRWAV_BAD_ADDRESS;
4859
0
    #endif
4860
0
    #ifdef ENOTBLK
4861
0
        case ENOTBLK: return DRWAV_ERROR;
4862
0
    #endif
4863
0
    #ifdef EBUSY
4864
0
        case EBUSY: return DRWAV_BUSY;
4865
0
    #endif
4866
0
    #ifdef EEXIST
4867
0
        case EEXIST: return DRWAV_ALREADY_EXISTS;
4868
0
    #endif
4869
0
    #ifdef EXDEV
4870
0
        case EXDEV: return DRWAV_ERROR;
4871
0
    #endif
4872
0
    #ifdef ENODEV
4873
0
        case ENODEV: return DRWAV_DOES_NOT_EXIST;
4874
0
    #endif
4875
0
    #ifdef ENOTDIR
4876
0
        case ENOTDIR: return DRWAV_NOT_DIRECTORY;
4877
0
    #endif
4878
0
    #ifdef EISDIR
4879
0
        case EISDIR: return DRWAV_IS_DIRECTORY;
4880
0
    #endif
4881
0
    #ifdef EINVAL
4882
0
        case EINVAL: return DRWAV_INVALID_ARGS;
4883
0
    #endif
4884
0
    #ifdef ENFILE
4885
0
        case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES;
4886
0
    #endif
4887
0
    #ifdef EMFILE
4888
0
        case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES;
4889
0
    #endif
4890
0
    #ifdef ENOTTY
4891
0
        case ENOTTY: return DRWAV_INVALID_OPERATION;
4892
0
    #endif
4893
0
    #ifdef ETXTBSY
4894
0
        case ETXTBSY: return DRWAV_BUSY;
4895
0
    #endif
4896
0
    #ifdef EFBIG
4897
0
        case EFBIG: return DRWAV_TOO_BIG;
4898
0
    #endif
4899
0
    #ifdef ENOSPC
4900
0
        case ENOSPC: return DRWAV_NO_SPACE;
4901
0
    #endif
4902
0
    #ifdef ESPIPE
4903
0
        case ESPIPE: return DRWAV_BAD_SEEK;
4904
0
    #endif
4905
0
    #ifdef EROFS
4906
0
        case EROFS: return DRWAV_ACCESS_DENIED;
4907
0
    #endif
4908
0
    #ifdef EMLINK
4909
0
        case EMLINK: return DRWAV_TOO_MANY_LINKS;
4910
0
    #endif
4911
0
    #ifdef EPIPE
4912
0
        case EPIPE: return DRWAV_BAD_PIPE;
4913
0
    #endif
4914
0
    #ifdef EDOM
4915
0
        case EDOM: return DRWAV_OUT_OF_RANGE;
4916
0
    #endif
4917
0
    #ifdef ERANGE
4918
0
        case ERANGE: return DRWAV_OUT_OF_RANGE;
4919
0
    #endif
4920
0
    #ifdef EDEADLK
4921
0
        case EDEADLK: return DRWAV_DEADLOCK;
4922
0
    #endif
4923
0
    #ifdef ENAMETOOLONG
4924
0
        case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG;
4925
0
    #endif
4926
0
    #ifdef ENOLCK
4927
0
        case ENOLCK: return DRWAV_ERROR;
4928
0
    #endif
4929
0
    #ifdef ENOSYS
4930
0
        case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
4931
0
    #endif
4932
    #if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST   /* In AIX, ENOTEMPTY and EEXIST use the same value. */
4933
0
        case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
4934
0
    #endif
4935
0
    #ifdef ELOOP
4936
0
        case ELOOP: return DRWAV_TOO_MANY_LINKS;
4937
0
    #endif
4938
0
    #ifdef ENOMSG
4939
0
        case ENOMSG: return DRWAV_NO_MESSAGE;
4940
0
    #endif
4941
0
    #ifdef EIDRM
4942
0
        case EIDRM: return DRWAV_ERROR;
4943
0
    #endif
4944
0
    #ifdef ECHRNG
4945
0
        case ECHRNG: return DRWAV_ERROR;
4946
0
    #endif
4947
0
    #ifdef EL2NSYNC
4948
0
        case EL2NSYNC: return DRWAV_ERROR;
4949
0
    #endif
4950
0
    #ifdef EL3HLT
4951
0
        case EL3HLT: return DRWAV_ERROR;
4952
0
    #endif
4953
0
    #ifdef EL3RST
4954
0
        case EL3RST: return DRWAV_ERROR;
4955
0
    #endif
4956
0
    #ifdef ELNRNG
4957
0
        case ELNRNG: return DRWAV_OUT_OF_RANGE;
4958
0
    #endif
4959
0
    #ifdef EUNATCH
4960
0
        case EUNATCH: return DRWAV_ERROR;
4961
0
    #endif
4962
0
    #ifdef ENOCSI
4963
0
        case ENOCSI: return DRWAV_ERROR;
4964
0
    #endif
4965
0
    #ifdef EL2HLT
4966
0
        case EL2HLT: return DRWAV_ERROR;
4967
0
    #endif
4968
0
    #ifdef EBADE
4969
0
        case EBADE: return DRWAV_ERROR;
4970
0
    #endif
4971
0
    #ifdef EBADR
4972
0
        case EBADR: return DRWAV_ERROR;
4973
0
    #endif
4974
0
    #ifdef EXFULL
4975
0
        case EXFULL: return DRWAV_ERROR;
4976
0
    #endif
4977
0
    #ifdef ENOANO
4978
0
        case ENOANO: return DRWAV_ERROR;
4979
0
    #endif
4980
0
    #ifdef EBADRQC
4981
0
        case EBADRQC: return DRWAV_ERROR;
4982
0
    #endif
4983
0
    #ifdef EBADSLT
4984
0
        case EBADSLT: return DRWAV_ERROR;
4985
0
    #endif
4986
0
    #ifdef EBFONT
4987
0
        case EBFONT: return DRWAV_INVALID_FILE;
4988
0
    #endif
4989
0
    #ifdef ENOSTR
4990
0
        case ENOSTR: return DRWAV_ERROR;
4991
0
    #endif
4992
0
    #ifdef ENODATA
4993
0
        case ENODATA: return DRWAV_NO_DATA_AVAILABLE;
4994
0
    #endif
4995
0
    #ifdef ETIME
4996
0
        case ETIME: return DRWAV_TIMEOUT;
4997
0
    #endif
4998
0
    #ifdef ENOSR
4999
0
        case ENOSR: return DRWAV_NO_DATA_AVAILABLE;
5000
0
    #endif
5001
0
    #ifdef ENONET
5002
0
        case ENONET: return DRWAV_NO_NETWORK;
5003
0
    #endif
5004
0
    #ifdef ENOPKG
5005
0
        case ENOPKG: return DRWAV_ERROR;
5006
0
    #endif
5007
0
    #ifdef EREMOTE
5008
0
        case EREMOTE: return DRWAV_ERROR;
5009
0
    #endif
5010
0
    #ifdef ENOLINK
5011
0
        case ENOLINK: return DRWAV_ERROR;
5012
0
    #endif
5013
0
    #ifdef EADV
5014
0
        case EADV: return DRWAV_ERROR;
5015
0
    #endif
5016
0
    #ifdef ESRMNT
5017
0
        case ESRMNT: return DRWAV_ERROR;
5018
0
    #endif
5019
0
    #ifdef ECOMM
5020
0
        case ECOMM: return DRWAV_ERROR;
5021
0
    #endif
5022
0
    #ifdef EPROTO
5023
0
        case EPROTO: return DRWAV_ERROR;
5024
0
    #endif
5025
0
    #ifdef EMULTIHOP
5026
0
        case EMULTIHOP: return DRWAV_ERROR;
5027
0
    #endif
5028
0
    #ifdef EDOTDOT
5029
0
        case EDOTDOT: return DRWAV_ERROR;
5030
0
    #endif
5031
0
    #ifdef EBADMSG
5032
0
        case EBADMSG: return DRWAV_BAD_MESSAGE;
5033
0
    #endif
5034
0
    #ifdef EOVERFLOW
5035
0
        case EOVERFLOW: return DRWAV_TOO_BIG;
5036
0
    #endif
5037
0
    #ifdef ENOTUNIQ
5038
0
        case ENOTUNIQ: return DRWAV_NOT_UNIQUE;
5039
0
    #endif
5040
0
    #ifdef EBADFD
5041
0
        case EBADFD: return DRWAV_ERROR;
5042
0
    #endif
5043
0
    #ifdef EREMCHG
5044
0
        case EREMCHG: return DRWAV_ERROR;
5045
0
    #endif
5046
0
    #ifdef ELIBACC
5047
0
        case ELIBACC: return DRWAV_ACCESS_DENIED;
5048
0
    #endif
5049
0
    #ifdef ELIBBAD
5050
0
        case ELIBBAD: return DRWAV_INVALID_FILE;
5051
0
    #endif
5052
0
    #ifdef ELIBSCN
5053
0
        case ELIBSCN: return DRWAV_INVALID_FILE;
5054
0
    #endif
5055
0
    #ifdef ELIBMAX
5056
0
        case ELIBMAX: return DRWAV_ERROR;
5057
0
    #endif
5058
0
    #ifdef ELIBEXEC
5059
0
        case ELIBEXEC: return DRWAV_ERROR;
5060
0
    #endif
5061
0
    #ifdef EILSEQ
5062
0
        case EILSEQ: return DRWAV_INVALID_DATA;
5063
0
    #endif
5064
0
    #ifdef ERESTART
5065
0
        case ERESTART: return DRWAV_ERROR;
5066
0
    #endif
5067
0
    #ifdef ESTRPIPE
5068
0
        case ESTRPIPE: return DRWAV_ERROR;
5069
0
    #endif
5070
0
    #ifdef EUSERS
5071
0
        case EUSERS: return DRWAV_ERROR;
5072
0
    #endif
5073
0
    #ifdef ENOTSOCK
5074
0
        case ENOTSOCK: return DRWAV_NOT_SOCKET;
5075
0
    #endif
5076
0
    #ifdef EDESTADDRREQ
5077
0
        case EDESTADDRREQ: return DRWAV_NO_ADDRESS;
5078
0
    #endif
5079
0
    #ifdef EMSGSIZE
5080
0
        case EMSGSIZE: return DRWAV_TOO_BIG;
5081
0
    #endif
5082
0
    #ifdef EPROTOTYPE
5083
0
        case EPROTOTYPE: return DRWAV_BAD_PROTOCOL;
5084
0
    #endif
5085
0
    #ifdef ENOPROTOOPT
5086
0
        case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE;
5087
0
    #endif
5088
0
    #ifdef EPROTONOSUPPORT
5089
0
        case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED;
5090
0
    #endif
5091
0
    #ifdef ESOCKTNOSUPPORT
5092
0
        case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED;
5093
0
    #endif
5094
0
    #ifdef EOPNOTSUPP
5095
0
        case EOPNOTSUPP: return DRWAV_INVALID_OPERATION;
5096
0
    #endif
5097
0
    #ifdef EPFNOSUPPORT
5098
0
        case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED;
5099
0
    #endif
5100
0
    #ifdef EAFNOSUPPORT
5101
0
        case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED;
5102
0
    #endif
5103
0
    #ifdef EADDRINUSE
5104
0
        case EADDRINUSE: return DRWAV_ALREADY_IN_USE;
5105
0
    #endif
5106
0
    #ifdef EADDRNOTAVAIL
5107
0
        case EADDRNOTAVAIL: return DRWAV_ERROR;
5108
0
    #endif
5109
0
    #ifdef ENETDOWN
5110
0
        case ENETDOWN: return DRWAV_NO_NETWORK;
5111
0
    #endif
5112
0
    #ifdef ENETUNREACH
5113
0
        case ENETUNREACH: return DRWAV_NO_NETWORK;
5114
0
    #endif
5115
0
    #ifdef ENETRESET
5116
0
        case ENETRESET: return DRWAV_NO_NETWORK;
5117
0
    #endif
5118
0
    #ifdef ECONNABORTED
5119
0
        case ECONNABORTED: return DRWAV_NO_NETWORK;
5120
0
    #endif
5121
0
    #ifdef ECONNRESET
5122
0
        case ECONNRESET: return DRWAV_CONNECTION_RESET;
5123
0
    #endif
5124
0
    #ifdef ENOBUFS
5125
0
        case ENOBUFS: return DRWAV_NO_SPACE;
5126
0
    #endif
5127
0
    #ifdef EISCONN
5128
0
        case EISCONN: return DRWAV_ALREADY_CONNECTED;
5129
0
    #endif
5130
0
    #ifdef ENOTCONN
5131
0
        case ENOTCONN: return DRWAV_NOT_CONNECTED;
5132
0
    #endif
5133
0
    #ifdef ESHUTDOWN
5134
0
        case ESHUTDOWN: return DRWAV_ERROR;
5135
0
    #endif
5136
0
    #ifdef ETOOMANYREFS
5137
0
        case ETOOMANYREFS: return DRWAV_ERROR;
5138
0
    #endif
5139
0
    #ifdef ETIMEDOUT
5140
0
        case ETIMEDOUT: return DRWAV_TIMEOUT;
5141
0
    #endif
5142
0
    #ifdef ECONNREFUSED
5143
0
        case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED;
5144
0
    #endif
5145
0
    #ifdef EHOSTDOWN
5146
0
        case EHOSTDOWN: return DRWAV_NO_HOST;
5147
0
    #endif
5148
0
    #ifdef EHOSTUNREACH
5149
0
        case EHOSTUNREACH: return DRWAV_NO_HOST;
5150
0
    #endif
5151
0
    #ifdef EALREADY
5152
0
        case EALREADY: return DRWAV_IN_PROGRESS;
5153
0
    #endif
5154
0
    #ifdef EINPROGRESS
5155
0
        case EINPROGRESS: return DRWAV_IN_PROGRESS;
5156
0
    #endif
5157
0
    #ifdef ESTALE
5158
0
        case ESTALE: return DRWAV_INVALID_FILE;
5159
0
    #endif
5160
0
    #ifdef EUCLEAN
5161
0
        case EUCLEAN: return DRWAV_ERROR;
5162
0
    #endif
5163
0
    #ifdef ENOTNAM
5164
0
        case ENOTNAM: return DRWAV_ERROR;
5165
0
    #endif
5166
0
    #ifdef ENAVAIL
5167
0
        case ENAVAIL: return DRWAV_ERROR;
5168
0
    #endif
5169
0
    #ifdef EISNAM
5170
0
        case EISNAM: return DRWAV_ERROR;
5171
0
    #endif
5172
0
    #ifdef EREMOTEIO
5173
0
        case EREMOTEIO: return DRWAV_IO_ERROR;
5174
0
    #endif
5175
0
    #ifdef EDQUOT
5176
0
        case EDQUOT: return DRWAV_NO_SPACE;
5177
0
    #endif
5178
0
    #ifdef ENOMEDIUM
5179
0
        case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST;
5180
0
    #endif
5181
0
    #ifdef EMEDIUMTYPE
5182
0
        case EMEDIUMTYPE: return DRWAV_ERROR;
5183
0
    #endif
5184
0
    #ifdef ECANCELED
5185
0
        case ECANCELED: return DRWAV_CANCELLED;
5186
0
    #endif
5187
0
    #ifdef ENOKEY
5188
0
        case ENOKEY: return DRWAV_ERROR;
5189
0
    #endif
5190
0
    #ifdef EKEYEXPIRED
5191
0
        case EKEYEXPIRED: return DRWAV_ERROR;
5192
0
    #endif
5193
0
    #ifdef EKEYREVOKED
5194
0
        case EKEYREVOKED: return DRWAV_ERROR;
5195
0
    #endif
5196
0
    #ifdef EKEYREJECTED
5197
0
        case EKEYREJECTED: return DRWAV_ERROR;
5198
0
    #endif
5199
0
    #ifdef EOWNERDEAD
5200
0
        case EOWNERDEAD: return DRWAV_ERROR;
5201
0
    #endif
5202
0
    #ifdef ENOTRECOVERABLE
5203
0
        case ENOTRECOVERABLE: return DRWAV_ERROR;
5204
0
    #endif
5205
0
    #ifdef ERFKILL
5206
0
        case ERFKILL: return DRWAV_ERROR;
5207
0
    #endif
5208
0
    #ifdef EHWPOISON
5209
0
        case EHWPOISON: return DRWAV_ERROR;
5210
0
    #endif
5211
0
        default: return DRWAV_ERROR;
5212
0
    }
5213
0
}
5214
/* End Errno */
5215
5216
/* fopen */
5217
DRWAV_PRIVATE drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
5218
0
{
5219
#if defined(_MSC_VER) && _MSC_VER >= 1400
5220
    errno_t err;
5221
#endif
5222
5223
0
    if (ppFile != NULL) {
5224
0
        *ppFile = NULL;  /* Safety. */
5225
0
    }
5226
5227
0
    if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
5228
0
        return DRWAV_INVALID_ARGS;
5229
0
    }
5230
5231
#if defined(_MSC_VER) && _MSC_VER >= 1400
5232
    err = fopen_s(ppFile, pFilePath, pOpenMode);
5233
    if (err != 0) {
5234
        return drwav_result_from_errno(err);
5235
    }
5236
#else
5237
#if defined(_WIN32) || defined(__APPLE__)
5238
    *ppFile = fopen(pFilePath, pOpenMode);
5239
#else
5240
    #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
5241
        *ppFile = fopen64(pFilePath, pOpenMode);
5242
    #else
5243
0
        *ppFile = fopen(pFilePath, pOpenMode);
5244
0
    #endif
5245
0
#endif
5246
0
    if (*ppFile == NULL) {
5247
0
        drwav_result result = drwav_result_from_errno(errno);
5248
0
        if (result == DRWAV_SUCCESS) {
5249
0
            result = DRWAV_ERROR;   /* Just a safety check to make sure we never ever return success when pFile == NULL. */
5250
0
        }
5251
5252
0
        return result;
5253
0
    }
5254
0
#endif
5255
5256
0
    return DRWAV_SUCCESS;
5257
0
}
5258
5259
/*
5260
_wfopen() isn't always available in all compilation environments.
5261
5262
    * Windows only.
5263
    * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
5264
    * MinGW-64 (both 32- and 64-bit) seems to support it.
5265
    * MinGW wraps it in !defined(__STRICT_ANSI__).
5266
    * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
5267
5268
This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
5269
fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
5270
*/
5271
#if defined(_WIN32)
5272
    #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
5273
        #define DRWAV_HAS_WFOPEN
5274
    #endif
5275
#endif
5276
5277
#ifndef DR_WAV_NO_WCHAR
5278
DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
5279
0
{
5280
0
    if (ppFile != NULL) {
5281
0
        *ppFile = NULL;  /* Safety. */
5282
0
    }
5283
5284
0
    if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
5285
0
        return DRWAV_INVALID_ARGS;
5286
0
    }
5287
5288
#if defined(DRWAV_HAS_WFOPEN)
5289
    {
5290
        /* Use _wfopen() on Windows. */
5291
    #if defined(_MSC_VER) && _MSC_VER >= 1400
5292
        errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
5293
        if (err != 0) {
5294
            return drwav_result_from_errno(err);
5295
        }
5296
    #else
5297
        *ppFile = _wfopen(pFilePath, pOpenMode);
5298
        if (*ppFile == NULL) {
5299
            return drwav_result_from_errno(errno);
5300
        }
5301
    #endif
5302
        (void)pAllocationCallbacks;
5303
    }
5304
#else
5305
  /*
5306
    Use fopen() on anything other than Windows. Requires a conversion. This is annoying because
5307
  fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note
5308
  that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
5309
    maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler
5310
  error I'll look into improving compatibility.
5311
    */
5312
5313
  /*
5314
  Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just
5315
  need to abort with an error. If you encounter a compiler lacking such support, add it to this list
5316
  and submit a bug report and it'll be added to the library upstream.
5317
  */
5318
  #if defined(__DJGPP__)
5319
  {
5320
    /* Nothing to do here. This will fall through to the error check below. */
5321
  }
5322
  #else
5323
0
    {
5324
0
        mbstate_t mbs;
5325
0
        size_t lenMB;
5326
0
        const wchar_t* pFilePathTemp = pFilePath;
5327
0
        char* pFilePathMB = NULL;
5328
0
        char pOpenModeMB[32] = {0};
5329
5330
        /* Get the length first. */
5331
0
        DRWAV_ZERO_OBJECT(&mbs);
5332
0
        lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
5333
0
        if (lenMB == (size_t)-1) {
5334
0
            return drwav_result_from_errno(errno);
5335
0
        }
5336
5337
0
        pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
5338
0
        if (pFilePathMB == NULL) {
5339
0
            return DRWAV_OUT_OF_MEMORY;
5340
0
        }
5341
5342
0
        pFilePathTemp = pFilePath;
5343
0
        DRWAV_ZERO_OBJECT(&mbs);
5344
0
        wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
5345
5346
        /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
5347
0
        {
5348
0
            size_t i = 0;
5349
0
            for (;;) {
5350
0
                if (pOpenMode[i] == 0) {
5351
0
                    pOpenModeMB[i] = '\0';
5352
0
                    break;
5353
0
                }
5354
5355
0
                pOpenModeMB[i] = (char)pOpenMode[i];
5356
0
                i += 1;
5357
0
            }
5358
0
        }
5359
5360
0
        *ppFile = fopen(pFilePathMB, pOpenModeMB);
5361
5362
0
        drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
5363
0
    }
5364
0
  #endif
5365
5366
0
    if (*ppFile == NULL) {
5367
0
        return DRWAV_ERROR;
5368
0
    }
5369
0
#endif
5370
5371
0
    return DRWAV_SUCCESS;
5372
0
}
5373
#endif
5374
/* End fopen */
5375
5376
5377
DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
5378
0
{
5379
0
    return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
5380
0
}
5381
5382
DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
5383
0
{
5384
0
    return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
5385
0
}
5386
5387
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
5388
0
{
5389
0
    int whence = SEEK_SET;
5390
0
    if (origin == DRWAV_SEEK_CUR) {
5391
0
        whence = SEEK_CUR;
5392
0
    } else if (origin == DRWAV_SEEK_END) {
5393
0
        whence = SEEK_END;
5394
0
    }
5395
5396
0
    return fseek((FILE*)pUserData, offset, whence) == 0;
5397
0
}
5398
5399
DRWAV_PRIVATE drwav_bool32 drwav__on_tell_stdio(void* pUserData, drwav_int64* pCursor)
5400
0
{
5401
0
    FILE* pFileStdio = (FILE*)pUserData;
5402
0
    drwav_int64 result;
5403
5404
    /* These were all validated at a higher level. */
5405
0
    DRWAV_ASSERT(pFileStdio != NULL);
5406
0
    DRWAV_ASSERT(pCursor    != NULL);
5407
5408
#if defined(_WIN32) && !defined(NXDK)
5409
    #if defined(_MSC_VER) && _MSC_VER > 1200
5410
        result = _ftelli64(pFileStdio);
5411
    #else
5412
        result = ftell(pFileStdio);
5413
    #endif
5414
#else
5415
0
    result = ftell(pFileStdio);
5416
0
#endif
5417
5418
0
    *pCursor = result;
5419
5420
0
    return DRWAV_TRUE;
5421
0
}
5422
5423
DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
5424
0
{
5425
0
    return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
5426
0
}
5427
5428
5429
DRWAV_PRIVATE 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)
5430
0
{
5431
0
    drwav_bool32 result;
5432
5433
0
    result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, drwav__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
5434
0
    if (result != DRWAV_TRUE) {
5435
0
        fclose(pFile);
5436
0
        return result;
5437
0
    }
5438
5439
0
    result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
5440
0
    if (result != DRWAV_TRUE) {
5441
0
        fclose(pFile);
5442
0
        return result;
5443
0
    }
5444
5445
0
    return DRWAV_TRUE;
5446
0
}
5447
5448
DRWAV_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)
5449
0
{
5450
0
    FILE* pFile;
5451
0
    if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
5452
0
        return DRWAV_FALSE;
5453
0
    }
5454
5455
    /* This takes ownership of the FILE* object. */
5456
0
    return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
5457
0
}
5458
5459
#ifndef DR_WAV_NO_WCHAR
5460
DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
5461
0
{
5462
0
    return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
5463
0
}
5464
5465
DRWAV_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)
5466
0
{
5467
0
    FILE* pFile;
5468
0
    if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
5469
0
        return DRWAV_FALSE;
5470
0
    }
5471
5472
    /* This takes ownership of the FILE* object. */
5473
0
    return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
5474
0
}
5475
#endif
5476
5477
DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5478
0
{
5479
0
    FILE* pFile;
5480
0
    if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
5481
0
        return DRWAV_FALSE;
5482
0
    }
5483
5484
    /* This takes ownership of the FILE* object. */
5485
0
    return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags | DRWAV_WITH_METADATA, pAllocationCallbacks);
5486
0
}
5487
5488
#ifndef DR_WAV_NO_WCHAR
5489
DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5490
0
{
5491
0
    FILE* pFile;
5492
0
    if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
5493
0
        return DRWAV_FALSE;
5494
0
    }
5495
5496
    /* This takes ownership of the FILE* object. */
5497
0
    return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags | DRWAV_WITH_METADATA, pAllocationCallbacks);
5498
0
}
5499
#endif
5500
5501
5502
DRWAV_PRIVATE 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)
5503
0
{
5504
0
    drwav_bool32 result;
5505
5506
0
    result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
5507
0
    if (result != DRWAV_TRUE) {
5508
0
        fclose(pFile);
5509
0
        return result;
5510
0
    }
5511
5512
0
    result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
5513
0
    if (result != DRWAV_TRUE) {
5514
0
        fclose(pFile);
5515
0
        return result;
5516
0
    }
5517
5518
0
    return DRWAV_TRUE;
5519
0
}
5520
5521
DRWAV_PRIVATE 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)
5522
0
{
5523
0
    FILE* pFile;
5524
0
    if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
5525
0
        return DRWAV_FALSE;
5526
0
    }
5527
5528
    /* This takes ownership of the FILE* object. */
5529
0
    return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
5530
0
}
5531
5532
#ifndef DR_WAV_NO_WCHAR
5533
DRWAV_PRIVATE 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)
5534
0
{
5535
0
    FILE* pFile;
5536
0
    if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
5537
0
        return DRWAV_FALSE;
5538
0
    }
5539
5540
    /* This takes ownership of the FILE* object. */
5541
0
    return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
5542
0
}
5543
#endif
5544
5545
DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
5546
0
{
5547
0
    return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
5548
0
}
5549
5550
DRWAV_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)
5551
0
{
5552
0
    return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
5553
0
}
5554
5555
DRWAV_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)
5556
0
{
5557
0
    if (pFormat == NULL) {
5558
0
        return DRWAV_FALSE;
5559
0
    }
5560
5561
0
    return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
5562
0
}
5563
5564
#ifndef DR_WAV_NO_WCHAR
5565
DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
5566
0
{
5567
0
    return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
5568
0
}
5569
5570
DRWAV_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)
5571
0
{
5572
0
    return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
5573
0
}
5574
5575
DRWAV_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)
5576
0
{
5577
0
    if (pFormat == NULL) {
5578
0
        return DRWAV_FALSE;
5579
0
    }
5580
5581
0
    return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
5582
0
}
5583
#endif
5584
#endif  /* DR_WAV_NO_STDIO */
5585
5586
5587
DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
5588
3.79M
{
5589
3.79M
    drwav* pWav = (drwav*)pUserData;
5590
3.79M
    size_t bytesRemaining;
5591
5592
3.79M
    DRWAV_ASSERT(pWav != NULL);
5593
3.79M
    DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
5594
5595
3.79M
    bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
5596
3.79M
    if (bytesToRead > bytesRemaining) {
5597
1.48k
        bytesToRead = bytesRemaining;
5598
1.48k
    }
5599
5600
3.79M
    if (bytesToRead > 0) {
5601
3.79M
        DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
5602
3.79M
        pWav->memoryStream.currentReadPos += bytesToRead;
5603
3.79M
    }
5604
5605
3.79M
    return bytesToRead;
5606
3.79M
}
5607
5608
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
5609
11.6k
{
5610
11.6k
    drwav* pWav = (drwav*)pUserData;
5611
11.6k
    drwav_int64 newCursor;
5612
5613
11.6k
    DRWAV_ASSERT(pWav != NULL);
5614
5615
11.6k
    if (origin == DRWAV_SEEK_SET) {
5616
4.43k
        newCursor = 0;
5617
7.23k
    } else if (origin == DRWAV_SEEK_CUR) {
5618
5.03k
        newCursor = (drwav_int64)pWav->memoryStream.currentReadPos;
5619
5.03k
    } else if (origin == DRWAV_SEEK_END) {
5620
2.20k
        newCursor = (drwav_int64)pWav->memoryStream.dataSize;
5621
2.20k
    } else {
5622
0
        DRWAV_ASSERT(!"Invalid seek origin");
5623
0
        return DRWAV_FALSE;
5624
0
    }
5625
5626
11.6k
    newCursor += offset;
5627
5628
11.6k
    if (newCursor < 0) {
5629
0
        return DRWAV_FALSE;  /* Trying to seek prior to the start of the buffer. */
5630
0
    }
5631
11.6k
    if ((size_t)newCursor > pWav->memoryStream.dataSize) {
5632
890
        return DRWAV_FALSE;  /* Trying to seek beyond the end of the buffer. */
5633
890
    }
5634
5635
10.7k
    pWav->memoryStream.currentReadPos = (size_t)newCursor;
5636
5637
10.7k
    return DRWAV_TRUE;
5638
11.6k
}
5639
5640
DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
5641
0
{
5642
0
    drwav* pWav = (drwav*)pUserData;
5643
0
    size_t bytesRemaining;
5644
5645
0
    DRWAV_ASSERT(pWav != NULL);
5646
0
    DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
5647
5648
0
    bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos;
5649
0
    if (bytesRemaining < bytesToWrite) {
5650
        /* Need to reallocate. */
5651
0
        void* pNewData;
5652
0
        size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2;
5653
5654
        /* If doubling wasn't enough, just make it the minimum required size to write the data. */
5655
0
        if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) {
5656
0
            newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite;
5657
0
        }
5658
5659
0
        pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
5660
0
        if (pNewData == NULL) {
5661
0
            return 0;
5662
0
        }
5663
5664
0
        *pWav->memoryStreamWrite.ppData = pNewData;
5665
0
        pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
5666
0
    }
5667
5668
0
    DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
5669
5670
0
    pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
5671
0
    if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
5672
0
        pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
5673
0
    }
5674
5675
0
    *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
5676
5677
0
    return bytesToWrite;
5678
0
}
5679
5680
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
5681
0
{
5682
0
    drwav* pWav = (drwav*)pUserData;
5683
0
    drwav_int64 newCursor;
5684
5685
0
    DRWAV_ASSERT(pWav != NULL);
5686
5687
0
    if (origin == DRWAV_SEEK_SET) {
5688
0
        newCursor = 0;
5689
0
    } else if (origin == DRWAV_SEEK_CUR) {
5690
0
        newCursor = (drwav_int64)pWav->memoryStreamWrite.currentWritePos;
5691
0
    } else if (origin == DRWAV_SEEK_END) {
5692
0
        newCursor = (drwav_int64)pWav->memoryStreamWrite.dataSize;
5693
0
    } else {
5694
0
        DRWAV_ASSERT(!"Invalid seek origin");
5695
0
        return DRWAV_FALSE;
5696
0
    }
5697
5698
0
    newCursor += offset;
5699
5700
0
    if (newCursor < 0) {
5701
0
        return DRWAV_FALSE;  /* Trying to seek prior to the start of the buffer. */
5702
0
    }
5703
0
    if ((size_t)newCursor > pWav->memoryStreamWrite.dataSize) {
5704
0
        return DRWAV_FALSE;  /* Trying to seek beyond the end of the buffer. */
5705
0
    }
5706
5707
0
    pWav->memoryStreamWrite.currentWritePos = (size_t)newCursor;
5708
5709
0
    return DRWAV_TRUE;
5710
0
}
5711
5712
DRWAV_PRIVATE drwav_bool32 drwav__on_tell_memory(void* pUserData, drwav_int64* pCursor)
5713
2.20k
{
5714
2.20k
    drwav* pWav = (drwav*)pUserData;
5715
5716
2.20k
    DRWAV_ASSERT(pWav != NULL);
5717
2.20k
    DRWAV_ASSERT(pCursor != NULL);
5718
5719
2.20k
    *pCursor = (drwav_int64)pWav->memoryStream.currentReadPos;
5720
2.20k
    return DRWAV_TRUE;
5721
2.20k
}
5722
5723
DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
5724
4.51k
{
5725
4.51k
    return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
5726
4.51k
}
5727
5728
DRWAV_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)
5729
4.51k
{
5730
4.51k
    if (data == NULL || dataSize == 0) {
5731
0
        return DRWAV_FALSE;
5732
0
    }
5733
5734
4.51k
    if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, drwav__on_tell_memory, pWav, pAllocationCallbacks)) {
5735
0
        return DRWAV_FALSE;
5736
0
    }
5737
5738
4.51k
    pWav->memoryStream.data = (const drwav_uint8*)data;
5739
4.51k
    pWav->memoryStream.dataSize = dataSize;
5740
4.51k
    pWav->memoryStream.currentReadPos = 0;
5741
5742
4.51k
    return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
5743
4.51k
}
5744
5745
DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void* data, size_t dataSize, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5746
0
{
5747
0
    if (data == NULL || dataSize == 0) {
5748
0
        return DRWAV_FALSE;
5749
0
    }
5750
5751
0
    if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, drwav__on_tell_memory, pWav, pAllocationCallbacks)) {
5752
0
        return DRWAV_FALSE;
5753
0
    }
5754
5755
0
    pWav->memoryStream.data = (const drwav_uint8*)data;
5756
0
    pWav->memoryStream.dataSize = dataSize;
5757
0
    pWav->memoryStream.currentReadPos = 0;
5758
5759
0
    return drwav_init__internal(pWav, NULL, NULL, flags | DRWAV_WITH_METADATA);
5760
0
}
5761
5762
5763
DRWAV_PRIVATE 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)
5764
0
{
5765
0
    if (ppData == NULL || pDataSize == NULL) {
5766
0
        return DRWAV_FALSE;
5767
0
    }
5768
5769
0
    *ppData = NULL; /* Important because we're using realloc()! */
5770
0
    *pDataSize = 0;
5771
5772
0
    if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
5773
0
        return DRWAV_FALSE;
5774
0
    }
5775
5776
0
    pWav->memoryStreamWrite.ppData = ppData;
5777
0
    pWav->memoryStreamWrite.pDataSize = pDataSize;
5778
0
    pWav->memoryStreamWrite.dataSize = 0;
5779
0
    pWav->memoryStreamWrite.dataCapacity = 0;
5780
0
    pWav->memoryStreamWrite.currentWritePos = 0;
5781
5782
0
    return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
5783
0
}
5784
5785
DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
5786
0
{
5787
0
    return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
5788
0
}
5789
5790
DRWAV_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)
5791
0
{
5792
0
    return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
5793
0
}
5794
5795
DRWAV_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)
5796
0
{
5797
0
    if (pFormat == NULL) {
5798
0
        return DRWAV_FALSE;
5799
0
    }
5800
5801
0
    return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
5802
0
}
5803
5804
DRWAV_PRIVATE drwav_uint32 drwav_write_padding(drwav* pWav)
5805
0
{
5806
    /* Do not adjust pWav->dataChunkDataSize - this should not include the padding. */
5807
0
    drwav_uint32 paddingSize = drwav_calculate_padding_size(pWav->container, pWav->dataChunkDataSize);
5808
5809
0
    if (paddingSize > 0) {
5810
0
        drwav_uint64 paddingData = 0;
5811
0
        drwav__write(pWav, &paddingData, paddingSize);  /* Byte order does not matter for this. */
5812
0
    }
5813
5814
0
    return paddingSize;
5815
0
}
5816
5817
DRWAV_PRIVATE void drwav_write_chunk_sizes(drwav* pWav)
5818
0
{
5819
    /*
5820
    When using sequential mode, these will have been filled in at initialization time. We only need
5821
    to do this when using non-sequential mode.
5822
    */
5823
0
    if (pWav->onSeek != NULL && !pWav->isSequentialWrite) {
5824
0
        if (pWav->container == drwav_container_riff) {
5825
            /* The "RIFF" chunk size. */
5826
0
            if (pWav->onSeek(pWav->pUserData, 4, DRWAV_SEEK_SET)) {
5827
0
                drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
5828
0
                drwav__write_u32ne_to_le(pWav, riffChunkSize);
5829
0
            }
5830
5831
            /* The "data" chunk size. */
5832
0
            if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, DRWAV_SEEK_SET)) {
5833
0
                drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
5834
0
                drwav__write_u32ne_to_le(pWav, dataChunkSize);
5835
0
            }
5836
0
        } else if (pWav->container == drwav_container_w64) {
5837
            /* The "RIFF" chunk size. */
5838
0
            if (pWav->onSeek(pWav->pUserData, 16, DRWAV_SEEK_SET)) {
5839
0
                drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
5840
0
                drwav__write_u64ne_to_le(pWav, riffChunkSize);
5841
0
            }
5842
5843
            /* The "data" chunk size. */
5844
0
            if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, DRWAV_SEEK_SET)) {
5845
0
                drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
5846
0
                drwav__write_u64ne_to_le(pWav, dataChunkSize);
5847
0
            }
5848
0
        } else if (pWav->container == drwav_container_rf64) {
5849
            /* We only need to update the ds64 chunk. The "RIFF" and "data" chunks always have their sizes set to 0xFFFFFFFF for RF64. */
5850
0
            int ds64BodyPos = 12 + 8;
5851
5852
            /* The "RIFF" chunk size. */
5853
0
            if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, DRWAV_SEEK_SET)) {
5854
0
                drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
5855
0
                drwav__write_u64ne_to_le(pWav, riffChunkSize);
5856
0
            }
5857
5858
            /* The "data" chunk size. */
5859
0
            if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, DRWAV_SEEK_SET)) {
5860
0
                drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
5861
0
                drwav__write_u64ne_to_le(pWav, dataChunkSize);
5862
0
            }
5863
0
        }
5864
0
    }
5865
0
}
5866
5867
DRWAV_API drwav_result drwav_uninit(drwav* pWav)
5868
2.02k
{
5869
2.02k
    drwav_result result = DRWAV_SUCCESS;
5870
5871
2.02k
    if (pWav == NULL) {
5872
0
        return DRWAV_INVALID_ARGS;
5873
0
    }
5874
5875
2.02k
    if (pWav->onWrite != NULL) {
5876
0
        if (pWav->isSequentialWrite) {
5877
            /*
5878
            Padding will not have been written in `drwav_write_*()` in sequential mode so we'll want to
5879
            do it explicitly here.
5880
            */
5881
0
            drwav_write_padding(pWav);
5882
5883
            /* Validation for sequential mode. */
5884
0
            if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
5885
0
                result = DRWAV_INVALID_FILE;
5886
0
            }
5887
0
        }
5888
2.02k
    } else {
5889
2.02k
        drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
5890
2.02k
    }
5891
5892
2.02k
#ifndef DR_WAV_NO_STDIO
5893
    /*
5894
    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()
5895
    was used by looking at the onRead and onSeek callbacks.
5896
    */
5897
2.02k
    if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
5898
0
        fclose((FILE*)pWav->pUserData);
5899
0
    }
5900
2.02k
#endif
5901
5902
2.02k
    return result;
5903
2.02k
}
5904
5905
5906
5907
DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
5908
7.99k
{
5909
7.99k
    size_t bytesRead;
5910
7.99k
    drwav_uint32 bytesPerFrame;
5911
5912
7.99k
    if (pWav == NULL || bytesToRead == 0) {
5913
0
        return 0;   /* Invalid args. */
5914
0
    }
5915
5916
7.99k
    if (bytesToRead > pWav->bytesRemaining) {
5917
410
        bytesToRead = (size_t)pWav->bytesRemaining;
5918
410
    }
5919
5920
7.99k
    if (bytesToRead == 0) {
5921
238
        return 0;   /* At end. */
5922
238
    }
5923
5924
7.75k
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5925
7.75k
    if (bytesPerFrame == 0) {
5926
0
        return 0;   /* Could not determine the bytes per frame. */
5927
0
    }
5928
5929
7.75k
    if (pBufferOut != NULL) {
5930
7.75k
        bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
5931
7.75k
    } else {
5932
        /* We need to seek. If we fail, we need to read-and-discard to make sure we get a good byte count. */
5933
0
        bytesRead = 0;
5934
0
        while (bytesRead < bytesToRead) {
5935
0
            size_t bytesToSeek = (bytesToRead - bytesRead);
5936
0
            if (bytesToSeek > 0x7FFFFFFF) {
5937
0
                bytesToSeek = 0x7FFFFFFF;
5938
0
            }
5939
5940
0
            if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, DRWAV_SEEK_CUR) == DRWAV_FALSE) {
5941
0
                break;
5942
0
            }
5943
5944
0
            bytesRead += bytesToSeek;
5945
0
        }
5946
5947
        /* When we get here we may need to read-and-discard some data. */
5948
0
        while (bytesRead < bytesToRead) {
5949
0
            drwav_uint8 buffer[4096];
5950
0
            size_t bytesSeeked;
5951
0
            size_t bytesToSeek = (bytesToRead - bytesRead);
5952
0
            if (bytesToSeek > sizeof(buffer)) {
5953
0
                bytesToSeek = sizeof(buffer);
5954
0
            }
5955
5956
0
            bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek);
5957
0
            bytesRead += bytesSeeked;
5958
5959
0
            if (bytesSeeked < bytesToSeek) {
5960
0
                break;  /* Reached the end. */
5961
0
            }
5962
0
        }
5963
0
    }
5964
5965
7.75k
    pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame;
5966
5967
7.75k
    pWav->bytesRemaining -= bytesRead;
5968
7.75k
    return bytesRead;
5969
7.75k
}
5970
5971
5972
5973
DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
5974
8.54k
{
5975
8.54k
    drwav_uint32 bytesPerFrame;
5976
8.54k
    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. */
5977
8.54k
    drwav_uint64 framesRemainingInFile;
5978
5979
8.54k
    if (pWav == NULL || framesToRead == 0) {
5980
43
        return 0;
5981
43
    }
5982
5983
    /* Cannot use this function for compressed formats. */
5984
8.50k
    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
5985
0
        return 0;
5986
0
    }
5987
5988
8.50k
    framesRemainingInFile = pWav->totalPCMFrameCount - pWav->readCursorInPCMFrames;
5989
8.50k
    if (framesToRead > framesRemainingInFile) {
5990
1.01k
        framesToRead = framesRemainingInFile;
5991
1.01k
    }
5992
5993
8.50k
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5994
8.50k
    if (bytesPerFrame == 0) {
5995
0
        return 0;
5996
0
    }
5997
5998
    /* Don't try to read more samples than can potentially fit in the output buffer. */
5999
8.50k
    bytesToRead = framesToRead * bytesPerFrame;
6000
8.50k
    if (bytesToRead > DRWAV_SIZE_MAX) {
6001
0
        bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame; /* Round the number of bytes to read to a clean frame boundary. */
6002
0
    }
6003
6004
    /*
6005
    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
6006
    *could* be a time where it evaluates to 0 due to overflowing.
6007
    */
6008
8.50k
    if (bytesToRead == 0) {
6009
512
        return 0;
6010
512
    }
6011
6012
7.99k
    return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame;
6013
8.50k
}
6014
6015
DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
6016
2.10k
{
6017
2.10k
    drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
6018
6019
2.10k
    if (pBufferOut != NULL) {
6020
2.10k
        drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6021
2.10k
        if (bytesPerFrame == 0) {
6022
0
            return 0;   /* Could not get the bytes per frame which means bytes per sample cannot be determined and we don't know how to byte swap. */
6023
0
        }
6024
6025
2.10k
        drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels);
6026
2.10k
    }
6027
6028
2.10k
    return framesRead;
6029
2.10k
}
6030
6031
DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
6032
8.54k
{
6033
8.54k
    drwav_uint64 framesRead = 0;
6034
6035
8.54k
    if (drwav_is_container_be(pWav->container)) {
6036
        /*
6037
        Special case for AIFF. AIFF is a big-endian encoded format, but it supports a format that is
6038
        PCM in little-endian encoding. In this case, we fall through this branch and treate it as
6039
        little-endian.
6040
        */
6041
2.10k
        if (pWav->container != drwav_container_aiff || pWav->aiff.isLE == DRWAV_FALSE) {
6042
2.10k
            if (drwav__is_little_endian()) {
6043
2.10k
                framesRead = drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
6044
2.10k
            } else {
6045
0
                framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
6046
0
            }
6047
6048
2.10k
            goto post_process;
6049
2.10k
        }
6050
2.10k
    }
6051
6052
    /* Getting here means the data should be considered little-endian. */
6053
6.44k
    if (drwav__is_little_endian()) {
6054
6.44k
        framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
6055
6.44k
    } else {
6056
0
        framesRead = drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
6057
0
    }
6058
6059
    /*
6060
    Here is where we check if we need to do a signed/unsigned conversion for AIFF. The reason we need to do this
6061
    is because dr_wav always assumes an 8-bit sample is unsigned, whereas AIFF can have signed 8-bit formats.
6062
    */
6063
8.54k
    post_process:
6064
8.54k
    {
6065
8.54k
        if (pWav->container == drwav_container_aiff && pWav->bitsPerSample == 8 && pWav->aiff.isUnsigned == DRWAV_FALSE) {
6066
670
            if (pBufferOut != NULL) {
6067
670
                drwav_uint64 iSample;
6068
6069
2.41M
                for (iSample = 0; iSample < framesRead * pWav->channels; iSample += 1) {
6070
2.41M
                    ((drwav_uint8*)pBufferOut)[iSample] += 128;
6071
2.41M
                }
6072
670
            }
6073
670
        }
6074
8.54k
    }
6075
6076
8.54k
    return framesRead;
6077
6.44k
}
6078
6079
6080
6081
DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
6082
0
{
6083
0
    if (pWav->onWrite != NULL) {
6084
0
        return DRWAV_FALSE; /* No seeking in write mode. */
6085
0
    }
6086
6087
0
    if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, DRWAV_SEEK_SET)) {
6088
0
        return DRWAV_FALSE;
6089
0
    }
6090
6091
0
    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
6092
        /* Cached data needs to be cleared for compressed formats. */
6093
0
        if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
6094
0
            DRWAV_ZERO_OBJECT(&pWav->msadpcm);
6095
0
        } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
6096
0
            DRWAV_ZERO_OBJECT(&pWav->ima);
6097
0
        } else {
6098
0
            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. */
6099
0
        }
6100
0
    }
6101
6102
0
    pWav->readCursorInPCMFrames = 0;
6103
0
    pWav->bytesRemaining = pWav->dataChunkDataSize;
6104
6105
0
    return DRWAV_TRUE;
6106
0
}
6107
6108
DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex)
6109
0
{
6110
    /* Seeking should be compatible with wave files > 2GB. */
6111
6112
0
    if (pWav == NULL || pWav->onSeek == NULL) {
6113
0
        return DRWAV_FALSE;
6114
0
    }
6115
6116
    /* No seeking in write mode. */
6117
0
    if (pWav->onWrite != NULL) {
6118
0
        return DRWAV_FALSE;
6119
0
    }
6120
6121
    /* If there are no samples, just return DRWAV_TRUE without doing anything. */
6122
0
    if (pWav->totalPCMFrameCount == 0) {
6123
0
        return DRWAV_TRUE;
6124
0
    }
6125
6126
    /* Make sure the sample is clamped. */
6127
0
    if (targetFrameIndex > pWav->totalPCMFrameCount) {
6128
0
        targetFrameIndex = pWav->totalPCMFrameCount;
6129
0
    }
6130
6131
    /*
6132
    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
6133
    to seek back to the start.
6134
    */
6135
0
    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
6136
        /* TODO: This can be optimized. */
6137
6138
        /*
6139
        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,
6140
        we first need to seek back to the start and then just do the same thing as a forward seek.
6141
        */
6142
0
        if (targetFrameIndex < pWav->readCursorInPCMFrames) {
6143
0
            if (!drwav_seek_to_first_pcm_frame(pWav)) {
6144
0
                return DRWAV_FALSE;
6145
0
            }
6146
0
        }
6147
6148
0
        if (targetFrameIndex > pWav->readCursorInPCMFrames) {
6149
0
            drwav_uint64 offsetInFrames = targetFrameIndex - pWav->readCursorInPCMFrames;
6150
6151
0
            drwav_int16 devnull[2048];
6152
0
            while (offsetInFrames > 0) {
6153
0
                drwav_uint64 framesRead = 0;
6154
0
                drwav_uint64 framesToRead = offsetInFrames;
6155
0
                if (framesToRead > drwav_countof(devnull)/pWav->channels) {
6156
0
                    framesToRead = drwav_countof(devnull)/pWav->channels;
6157
0
                }
6158
6159
0
                if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
6160
0
                    framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull);
6161
0
                } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
6162
0
                    framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull);
6163
0
                } else {
6164
0
                    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. */
6165
0
                }
6166
6167
0
                if (framesRead != framesToRead) {
6168
0
                    return DRWAV_FALSE;
6169
0
                }
6170
6171
0
                offsetInFrames -= framesRead;
6172
0
            }
6173
0
        }
6174
0
    } else {
6175
0
        drwav_uint64 totalSizeInBytes;
6176
0
        drwav_uint64 currentBytePos;
6177
0
        drwav_uint64 targetBytePos;
6178
0
        drwav_uint64 offset;
6179
0
        drwav_uint32 bytesPerFrame;
6180
6181
0
        bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6182
0
        if (bytesPerFrame == 0) {
6183
0
            return DRWAV_FALSE; /* Not able to calculate offset. */
6184
0
        }
6185
6186
0
        totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame;
6187
        /*DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);*/
6188
6189
0
        currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
6190
0
        targetBytePos  = targetFrameIndex * bytesPerFrame;
6191
6192
0
        if (currentBytePos < targetBytePos) {
6193
            /* Offset forwards. */
6194
0
            offset = (targetBytePos - currentBytePos);
6195
0
        } else {
6196
            /* Offset backwards. */
6197
0
            if (!drwav_seek_to_first_pcm_frame(pWav)) {
6198
0
                return DRWAV_FALSE;
6199
0
            }
6200
0
            offset = targetBytePos;
6201
0
        }
6202
6203
0
        while (offset > 0) {
6204
0
            int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
6205
0
            if (!pWav->onSeek(pWav->pUserData, offset32, DRWAV_SEEK_CUR)) {
6206
0
                return DRWAV_FALSE;
6207
0
            }
6208
6209
0
            pWav->readCursorInPCMFrames += offset32 / bytesPerFrame;
6210
0
            pWav->bytesRemaining        -= offset32;
6211
0
            offset                      -= offset32;
6212
0
        }
6213
0
    }
6214
6215
0
    return DRWAV_TRUE;
6216
0
}
6217
6218
DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor)
6219
0
{
6220
0
    if (pCursor == NULL) {
6221
0
        return DRWAV_INVALID_ARGS;
6222
0
    }
6223
6224
0
    *pCursor = 0;   /* Safety. */
6225
6226
0
    if (pWav == NULL) {
6227
0
        return DRWAV_INVALID_ARGS;
6228
0
    }
6229
6230
0
    *pCursor = pWav->readCursorInPCMFrames;
6231
6232
0
    return DRWAV_SUCCESS;
6233
0
}
6234
6235
DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength)
6236
0
{
6237
0
    if (pLength == NULL) {
6238
0
        return DRWAV_INVALID_ARGS;
6239
0
    }
6240
6241
0
    *pLength = 0;   /* Safety. */
6242
6243
0
    if (pWav == NULL) {
6244
0
        return DRWAV_INVALID_ARGS;
6245
0
    }
6246
6247
0
    *pLength = pWav->totalPCMFrameCount;
6248
6249
0
    return DRWAV_SUCCESS;
6250
0
}
6251
6252
6253
DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
6254
0
{
6255
0
    size_t bytesWritten;
6256
6257
0
    if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
6258
0
        return 0;
6259
0
    }
6260
6261
0
    bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
6262
0
    pWav->dataChunkDataSize += bytesWritten;
6263
6264
0
    if (!pWav->isSequentialWrite) {
6265
0
        drwav_uint32 padding;
6266
6267
        /* Padding. */
6268
0
        padding = drwav_write_padding(pWav);
6269
6270
        /* Chunk sizes. */
6271
0
        drwav_write_chunk_sizes(pWav);
6272
6273
        /* Now seek back to just before the padding in preparation for the next writes. */
6274
0
        if (pWav->onSeek != NULL) {
6275
0
            pWav->onSeek(pWav->pUserData, -(int)padding, DRWAV_SEEK_END);   /* Safe cast. */
6276
0
        }
6277
0
    }
6278
6279
0
    return bytesWritten;
6280
0
}
6281
6282
DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
6283
0
{
6284
0
    drwav_uint64 bytesToWrite;
6285
0
    drwav_uint64 bytesWritten;
6286
0
    const drwav_uint8* pRunningData;
6287
6288
0
    if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
6289
0
        return 0;
6290
0
    }
6291
6292
0
    bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
6293
0
    if (bytesToWrite > DRWAV_SIZE_MAX) {
6294
0
        return 0;
6295
0
    }
6296
6297
0
    bytesWritten = 0;
6298
0
    pRunningData = (const drwav_uint8*)pData;
6299
6300
0
    while (bytesToWrite > 0) {
6301
0
        size_t bytesJustWritten;
6302
0
        drwav_uint64 bytesToWriteThisIteration;
6303
6304
0
        bytesToWriteThisIteration = bytesToWrite;
6305
0
        DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX);  /* <-- This is checked above. */
6306
6307
0
        bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData);
6308
0
        if (bytesJustWritten == 0) {
6309
0
            break;
6310
0
        }
6311
6312
0
        bytesToWrite -= bytesJustWritten;
6313
0
        bytesWritten += bytesJustWritten;
6314
0
        pRunningData += bytesJustWritten;
6315
0
    }
6316
6317
0
    return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
6318
0
}
6319
6320
DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
6321
0
{
6322
0
    drwav_uint64 bytesToWrite;
6323
0
    drwav_uint64 bytesWritten;
6324
0
    drwav_uint32 bytesPerSample;
6325
0
    const drwav_uint8* pRunningData;
6326
6327
0
    if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
6328
0
        return 0;
6329
0
    }
6330
6331
0
    bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
6332
0
    if (bytesToWrite > DRWAV_SIZE_MAX) {
6333
0
        return 0;
6334
0
    }
6335
6336
0
    bytesWritten = 0;
6337
0
    pRunningData = (const drwav_uint8*)pData;
6338
6339
0
    bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels;
6340
0
    if (bytesPerSample == 0) {
6341
0
        return 0;   /* Cannot determine bytes per sample, or bytes per sample is less than one byte. */
6342
0
    }
6343
6344
0
    while (bytesToWrite > 0) {
6345
0
        drwav_uint8 temp[4096];
6346
0
        drwav_uint32 sampleCount;
6347
0
        size_t bytesJustWritten;
6348
0
        drwav_uint64 bytesToWriteThisIteration;
6349
6350
0
        bytesToWriteThisIteration = bytesToWrite;
6351
0
        DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX);  /* <-- This is checked above. */
6352
6353
        /*
6354
        WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need
6355
        to use an intermediary buffer for the conversion.
6356
        */
6357
0
        sampleCount = sizeof(temp)/bytesPerSample;
6358
6359
0
        if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) {
6360
0
            bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample;
6361
0
        }
6362
6363
0
        DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration);
6364
0
        drwav__bswap_samples(temp, sampleCount, bytesPerSample);
6365
6366
0
        bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp);
6367
0
        if (bytesJustWritten == 0) {
6368
0
            break;
6369
0
        }
6370
6371
0
        bytesToWrite -= bytesJustWritten;
6372
0
        bytesWritten += bytesJustWritten;
6373
0
        pRunningData += bytesJustWritten;
6374
0
    }
6375
6376
0
    return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
6377
0
}
6378
6379
DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
6380
0
{
6381
0
    if (drwav__is_little_endian()) {
6382
0
        return drwav_write_pcm_frames_le(pWav, framesToWrite, pData);
6383
0
    } else {
6384
0
        return drwav_write_pcm_frames_be(pWav, framesToWrite, pData);
6385
0
    }
6386
0
}
6387
6388
6389
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6390
1.85k
{
6391
1.85k
    drwav_uint64 totalFramesRead = 0;
6392
6393
1.85k
    static const drwav_int32 adaptationTable[] = {
6394
1.85k
        230, 230, 230, 230, 307, 409, 512, 614,
6395
1.85k
        768, 614, 512, 409, 307, 230, 230, 230
6396
1.85k
    };
6397
1.85k
    static const drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460,  392 };
6398
1.85k
    static const drwav_int32 coeff2Table[] = { 0,  -256, 0, 64,  0,  -208, -232 };
6399
6400
1.85k
    DRWAV_ASSERT(pWav != NULL);
6401
1.85k
    DRWAV_ASSERT(framesToRead > 0);
6402
6403
    /* TODO: Lots of room for optimization here. */
6404
6405
2.91M
    while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
6406
2.91M
        DRWAV_ASSERT(framesToRead > 0); /* This loop iteration will never get hit with framesToRead == 0 because it's asserted at the top, and we check for 0 inside the loop just below. */
6407
6408
        /* If there are no cached frames we need to load a new block. */
6409
2.91M
        if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) {
6410
1.81k
            if (pWav->channels == 1) {
6411
                /* Mono. */
6412
601
                drwav_uint8 header[7];
6413
601
                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
6414
55
                    return totalFramesRead;
6415
55
                }
6416
546
                pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
6417
6418
546
                pWav->msadpcm.predictor[0]     = header[0];
6419
546
                pWav->msadpcm.delta[0]         = drwav_bytes_to_s16(header + 1);
6420
546
                pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 3);
6421
546
                pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 5);
6422
546
                pWav->msadpcm.cachedFrames[2]  = pWav->msadpcm.prevFrames[0][0];
6423
546
                pWav->msadpcm.cachedFrames[3]  = pWav->msadpcm.prevFrames[0][1];
6424
546
                pWav->msadpcm.cachedFrameCount = 2;
6425
6426
                /* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */
6427
546
                if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
6428
15
                    return totalFramesRead; /* Invalid file. */
6429
15
                }
6430
1.21k
            } else {
6431
                /* Stereo. */
6432
1.21k
                drwav_uint8 header[14];
6433
1.21k
                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
6434
11
                    return totalFramesRead;
6435
11
                }
6436
1.19k
                pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
6437
6438
1.19k
                pWav->msadpcm.predictor[0] = header[0];
6439
1.19k
                pWav->msadpcm.predictor[1] = header[1];
6440
1.19k
                pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 2);
6441
1.19k
                pWav->msadpcm.delta[1] = drwav_bytes_to_s16(header + 4);
6442
1.19k
                pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 6);
6443
1.19k
                pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav_bytes_to_s16(header + 8);
6444
1.19k
                pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 10);
6445
1.19k
                pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav_bytes_to_s16(header + 12);
6446
6447
1.19k
                pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0];
6448
1.19k
                pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0];
6449
1.19k
                pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
6450
1.19k
                pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
6451
1.19k
                pWav->msadpcm.cachedFrameCount = 2;
6452
6453
                /* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */
6454
1.19k
                if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table) ||
6455
1.18k
                    pWav->msadpcm.predictor[1] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
6456
19
                    return totalFramesRead; /* Invalid file. */
6457
19
                }
6458
1.19k
            }
6459
1.81k
        }
6460
6461
        /* Output anything that's cached. */
6462
7.80M
        while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
6463
4.88M
            if (pBufferOut != NULL) {
6464
4.88M
                drwav_uint32 iSample = 0;
6465
10.7M
                for (iSample = 0; iSample < pWav->channels; iSample += 1) {
6466
5.83M
                    pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample];
6467
5.83M
                }
6468
6469
4.88M
                pBufferOut += pWav->channels;
6470
4.88M
            }
6471
6472
4.88M
            framesToRead    -= 1;
6473
4.88M
            totalFramesRead += 1;
6474
4.88M
            pWav->readCursorInPCMFrames += 1;
6475
4.88M
            pWav->msadpcm.cachedFrameCount -= 1;
6476
4.88M
        }
6477
6478
2.91M
        if (framesToRead == 0) {
6479
1.16k
            break;
6480
1.16k
        }
6481
6482
6483
        /*
6484
        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
6485
        loop iteration which will trigger the loading of a new block.
6486
        */
6487
2.91M
        if (pWav->msadpcm.cachedFrameCount == 0) {
6488
2.91M
            if (pWav->msadpcm.bytesRemainingInBlock == 0) {
6489
1.13k
                continue;
6490
2.91M
            } else {
6491
2.91M
                drwav_uint8 nibbles;
6492
2.91M
                drwav_int32 nibble0;
6493
2.91M
                drwav_int32 nibble1;
6494
6495
2.91M
                if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
6496
560
                    return totalFramesRead;
6497
560
                }
6498
2.91M
                pWav->msadpcm.bytesRemainingInBlock -= 1;
6499
6500
                /* TODO: Optimize away these if statements. */
6501
2.91M
                nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; }
6502
2.91M
                nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; }
6503
6504
2.91M
                if (pWav->channels == 1) {
6505
                    /* Mono. */
6506
1.96M
                    drwav_int32 newSample0;
6507
1.96M
                    drwav_int32 newSample1;
6508
6509
                    /* The predictor is read from the file and then indexed into a table. Check that it's in bounds. */
6510
1.96M
                    if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
6511
0
                        return totalFramesRead;
6512
0
                    }
6513
6514
1.96M
                    newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
6515
1.96M
                    newSample0 += nibble0 * pWav->msadpcm.delta[0];
6516
1.96M
                    newSample0  = drwav_clamp(newSample0, -32768, 32767);
6517
6518
1.96M
                    pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
6519
 
6520
1.96M
                    pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
6521
1.96M
                    pWav->msadpcm.prevFrames[0][1] = newSample0;
6522
6523
6524
1.96M
                    newSample1  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
6525
1.96M
                    newSample1 += nibble1 * pWav->msadpcm.delta[0];
6526
1.96M
                    newSample1  = drwav_clamp(newSample1, -32768, 32767);
6527
6528
1.96M
                    pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
6529
6530
1.96M
                    pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
6531
1.96M
                    pWav->msadpcm.prevFrames[0][1] = newSample1;
6532
6533
1.96M
                    pWav->msadpcm.cachedFrames[2] = newSample0;
6534
1.96M
                    pWav->msadpcm.cachedFrames[3] = newSample1;
6535
1.96M
                    pWav->msadpcm.cachedFrameCount = 2;
6536
1.96M
                } else {
6537
                    /* Stereo. */
6538
945k
                    drwav_int32 newSample0;
6539
945k
                    drwav_int32 newSample1;
6540
6541
                    /* Left. */
6542
945k
                    if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[0] >= drwav_countof(coeff2Table)) {
6543
0
                        return totalFramesRead; /* Out of bounds. Invalid file. */
6544
0
                    }
6545
6546
945k
                    newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
6547
945k
                    newSample0 += nibble0 * pWav->msadpcm.delta[0];
6548
945k
                    newSample0  = drwav_clamp(newSample0, -32768, 32767);
6549
6550
945k
                    pWav->msadpcm.delta[0] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8, 16, 0x7FFFFFFF);
6551
6552
945k
                    pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
6553
945k
                    pWav->msadpcm.prevFrames[0][1] = newSample0;
6554
6555
6556
                    /* Right. */
6557
945k
                    if (pWav->msadpcm.predictor[1] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
6558
0
                        return totalFramesRead; /* Out of bounds. Invalid file. */
6559
0
                    }
6560
6561
945k
                    newSample1  = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
6562
945k
                    newSample1 += nibble1 * pWav->msadpcm.delta[1];
6563
945k
                    newSample1  = drwav_clamp(newSample1, -32768, 32767);
6564
6565
945k
                    pWav->msadpcm.delta[1] = (drwav_int32)drwav_clamp(((drwav_int64)adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8, 16, 0x7FFFFFFF);
6566
6567
945k
                    pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
6568
945k
                    pWav->msadpcm.prevFrames[1][1] = newSample1;
6569
6570
945k
                    pWav->msadpcm.cachedFrames[2] = newSample0;
6571
945k
                    pWav->msadpcm.cachedFrames[3] = newSample1;
6572
945k
                    pWav->msadpcm.cachedFrameCount = 1;
6573
945k
                }
6574
2.91M
            }
6575
2.91M
        }
6576
2.91M
    }
6577
6578
1.19k
    return totalFramesRead;
6579
1.85k
}
6580
6581
6582
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6583
1.60k
{
6584
1.60k
    drwav_uint64 totalFramesRead = 0;
6585
1.60k
    drwav_uint32 iChannel;
6586
6587
1.60k
    static const drwav_int32 indexTable[16] = {
6588
1.60k
        -1, -1, -1, -1, 2, 4, 6, 8,
6589
1.60k
        -1, -1, -1, -1, 2, 4, 6, 8
6590
1.60k
    };
6591
6592
1.60k
    static const drwav_int32 stepTable[89] = {
6593
1.60k
        7,     8,     9,     10,    11,    12,    13,    14,    16,    17,
6594
1.60k
        19,    21,    23,    25,    28,    31,    34,    37,    41,    45,
6595
1.60k
        50,    55,    60,    66,    73,    80,    88,    97,    107,   118,
6596
1.60k
        130,   143,   157,   173,   190,   209,   230,   253,   279,   307,
6597
1.60k
        337,   371,   408,   449,   494,   544,   598,   658,   724,   796,
6598
1.60k
        876,   963,   1060,  1166,  1282,  1411,  1552,  1707,  1878,  2066,
6599
1.60k
        2272,  2499,  2749,  3024,  3327,  3660,  4026,  4428,  4871,  5358,
6600
1.60k
        5894,  6484,  7132,  7845,  8630,  9493,  10442, 11487, 12635, 13899,
6601
1.60k
        15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
6602
1.60k
    };
6603
6604
1.60k
    DRWAV_ASSERT(pWav != NULL);
6605
1.60k
    DRWAV_ASSERT(framesToRead > 0);
6606
6607
    /* TODO: Lots of room for optimization here. */
6608
6609
629k
    while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
6610
629k
        DRWAV_ASSERT(framesToRead > 0); /* This loop iteration will never get hit with framesToRead == 0 because it's asserted at the top, and we check for 0 inside the loop just below. */
6611
6612
        /* If there are no cached samples we need to load a new block. */
6613
629k
        if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) {
6614
2.50k
            if (pWav->channels == 1) {
6615
                /* Mono. */
6616
1.27k
                drwav_uint8 header[4];
6617
1.27k
                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
6618
22
                    return totalFramesRead;
6619
22
                }
6620
1.25k
                pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
6621
6622
1.25k
                if (header[2] >= drwav_countof(stepTable)) {
6623
13
                    pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, DRWAV_SEEK_CUR);
6624
13
                    pWav->ima.bytesRemainingInBlock = 0;
6625
13
                    return totalFramesRead; /* Invalid data. */
6626
13
                }
6627
6628
1.23k
                pWav->ima.predictor[0] = (drwav_int16)drwav_bytes_to_u16(header + 0);
6629
1.23k
                pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1);    /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */
6630
1.23k
                pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0];
6631
1.23k
                pWav->ima.cachedFrameCount = 1;
6632
1.23k
            } else {
6633
                /* Stereo. */
6634
1.22k
                drwav_uint8 header[8];
6635
1.22k
                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
6636
29
                    return totalFramesRead;
6637
29
                }
6638
1.19k
                pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
6639
6640
1.19k
                if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
6641
16
                    pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, DRWAV_SEEK_CUR);
6642
16
                    pWav->ima.bytesRemainingInBlock = 0;
6643
16
                    return totalFramesRead; /* Invalid data. */
6644
16
                }
6645
6646
1.18k
                pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0);
6647
1.18k
                pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1);    /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */
6648
1.18k
                pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4);
6649
1.18k
                pWav->ima.stepIndex[1] = drwav_clamp(header[6], 0, (drwav_int32)drwav_countof(stepTable)-1);    /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */
6650
6651
1.18k
                pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0];
6652
1.18k
                pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1];
6653
1.18k
                pWav->ima.cachedFrameCount = 1;
6654
1.18k
            }
6655
2.50k
        }
6656
6657
        /* Output anything that's cached. */
6658
5.63M
        while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
6659
5.00M
            if (pBufferOut != NULL) {
6660
5.00M
                drwav_uint32 iSample;
6661
11.5M
                for (iSample = 0; iSample < pWav->channels; iSample += 1) {
6662
6.55M
                    pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample];
6663
6.55M
                }
6664
5.00M
                pBufferOut += pWav->channels;
6665
5.00M
            }
6666
6667
5.00M
            framesToRead    -= 1;
6668
5.00M
            totalFramesRead += 1;
6669
5.00M
            pWav->readCursorInPCMFrames += 1;
6670
5.00M
            pWav->ima.cachedFrameCount -= 1;
6671
5.00M
        }
6672
6673
629k
        if (framesToRead == 0) {
6674
1.20k
            break;
6675
1.20k
        }
6676
6677
        /*
6678
        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
6679
        loop iteration which will trigger the loading of a new block.
6680
        */
6681
627k
        if (pWav->ima.cachedFrameCount == 0) {
6682
627k
            if (pWav->ima.bytesRemainingInBlock == 0) {
6683
2.10k
                continue;
6684
625k
            } else {
6685
                /*
6686
                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
6687
                left channel, 4 bytes for the right channel.
6688
                */
6689
625k
                pWav->ima.cachedFrameCount = 8;
6690
1.44M
                for (iChannel = 0; iChannel < pWav->channels; ++iChannel) {
6691
818k
                    drwav_uint32 iByte;
6692
818k
                    drwav_uint8 nibbles[4];
6693
818k
                    if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) {
6694
268
                        pWav->ima.cachedFrameCount = 0;
6695
268
                        return totalFramesRead;
6696
268
                    }
6697
818k
                    pWav->ima.bytesRemainingInBlock -= 4;
6698
6699
4.09M
                    for (iByte = 0; iByte < 4; ++iByte) {
6700
3.27M
                        drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
6701
3.27M
                        drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
6702
6703
3.27M
                        drwav_int32 step      = stepTable[pWav->ima.stepIndex[iChannel]];
6704
3.27M
                        drwav_int32 predictor = pWav->ima.predictor[iChannel];
6705
6706
3.27M
                        drwav_int32      diff  = step >> 3;
6707
3.27M
                        if (nibble0 & 1) diff += step >> 2;
6708
3.27M
                        if (nibble0 & 2) diff += step >> 1;
6709
3.27M
                        if (nibble0 & 4) diff += step;
6710
3.27M
                        if (nibble0 & 8) diff  = -diff;
6711
6712
3.27M
                        predictor = drwav_clamp(predictor + diff, -32768, 32767);
6713
3.27M
                        pWav->ima.predictor[iChannel] = predictor;
6714
3.27M
                        pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1);
6715
3.27M
                        pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor;
6716
6717
6718
3.27M
                        step      = stepTable[pWav->ima.stepIndex[iChannel]];
6719
3.27M
                        predictor = pWav->ima.predictor[iChannel];
6720
6721
3.27M
                                         diff  = step >> 3;
6722
3.27M
                        if (nibble1 & 1) diff += step >> 2;
6723
3.27M
                        if (nibble1 & 2) diff += step >> 1;
6724
3.27M
                        if (nibble1 & 4) diff += step;
6725
3.27M
                        if (nibble1 & 8) diff  = -diff;
6726
6727
3.27M
                        predictor = drwav_clamp(predictor + diff, -32768, 32767);
6728
3.27M
                        pWav->ima.predictor[iChannel] = predictor;
6729
3.27M
                        pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1);
6730
3.27M
                        pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor;
6731
3.27M
                    }
6732
818k
                }
6733
625k
            }
6734
627k
        }
6735
627k
    }
6736
6737
1.25k
    return totalFramesRead;
6738
1.60k
}
6739
6740
6741
#ifndef DR_WAV_NO_CONVERSION_API
6742
static const unsigned short g_drwavAlawTable[256] = {
6743
    0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
6744
    0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
6745
    0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
6746
    0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
6747
    0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
6748
    0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
6749
    0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
6750
    0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
6751
    0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
6752
    0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
6753
    0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
6754
    0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
6755
    0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
6756
    0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
6757
    0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
6758
    0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
6759
};
6760
6761
static const unsigned short g_drwavMulawTable[256] = {
6762
    0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
6763
    0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
6764
    0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
6765
    0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
6766
    0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
6767
    0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
6768
    0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
6769
    0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
6770
    0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
6771
    0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
6772
    0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
6773
    0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
6774
    0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
6775
    0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
6776
    0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
6777
    0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
6778
};
6779
6780
static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
6781
5.93M
{
6782
5.93M
    return (short)g_drwavAlawTable[sampleIn];
6783
5.93M
}
6784
6785
static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
6786
7.57M
{
6787
7.57M
    return (short)g_drwavMulawTable[sampleIn];
6788
7.57M
}
6789
6790
6791
6792
DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
6793
2.56k
{
6794
2.56k
    size_t i;
6795
6796
    /* Special case for 8-bit sample data because it's treated as unsigned. */
6797
2.56k
    if (bytesPerSample == 1) {
6798
790
        drwav_u8_to_s16(pOut, pIn, totalSampleCount);
6799
790
        return;
6800
790
    }
6801
6802
6803
    /* Slightly more optimal implementation for common formats. */
6804
1.77k
    if (bytesPerSample == 2) {
6805
53.3k
        for (i = 0; i < totalSampleCount; ++i) {
6806
53.3k
           *pOut++ = ((const drwav_int16*)pIn)[i];
6807
53.3k
        }
6808
39
        return;
6809
39
    }
6810
1.74k
    if (bytesPerSample == 3) {
6811
436
        drwav_s24_to_s16(pOut, pIn, totalSampleCount);
6812
436
        return;
6813
436
    }
6814
1.30k
    if (bytesPerSample == 4) {
6815
666
        drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
6816
666
        return;
6817
666
    }
6818
6819
6820
    /* Anything more than 64 bits per sample is not supported. */
6821
638
    if (bytesPerSample > 8) {
6822
221
        DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
6823
221
        return;
6824
221
    }
6825
6826
6827
    /* Generic, slow converter. */
6828
217k
    for (i = 0; i < totalSampleCount; ++i) {
6829
217k
        drwav_uint64 sample = 0;
6830
217k
        unsigned int shift  = (8 - bytesPerSample) * 8;
6831
6832
217k
        unsigned int j;
6833
1.65M
        for (j = 0; j < bytesPerSample; j += 1) {
6834
1.44M
            DRWAV_ASSERT(j < 8);
6835
1.44M
            sample |= (drwav_uint64)(pIn[j]) << shift;
6836
1.44M
            shift  += 8;
6837
1.44M
        }
6838
6839
217k
        if (!drwav__is_little_endian()) {
6840
0
            sample = drwav__bswap64(sample);
6841
0
        }
6842
6843
217k
        pIn += j;
6844
217k
        *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
6845
217k
    }
6846
417
}
6847
6848
DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
6849
1.36k
{
6850
1.36k
    if (bytesPerSample == 4) {
6851
229
        drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount);
6852
229
        return;
6853
1.13k
    } else if (bytesPerSample == 8) {
6854
403
        drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount);
6855
403
        return;
6856
734
    } else {
6857
        /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
6858
734
        DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
6859
734
        return;
6860
734
    }
6861
1.36k
}
6862
6863
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6864
1.16k
{
6865
1.16k
    drwav_uint64 totalFramesRead;
6866
1.16k
    drwav_uint8 sampleData[4096] = {0};
6867
1.16k
    drwav_uint32 bytesPerFrame;
6868
1.16k
    drwav_uint32 bytesPerSample;
6869
1.16k
    drwav_uint64 samplesRead;
6870
6871
    /* Fast path. */
6872
1.16k
    if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) {
6873
108
        return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
6874
108
    }
6875
6876
1.05k
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6877
1.05k
    if (bytesPerFrame == 0) {
6878
0
        return 0;
6879
0
    }
6880
6881
1.05k
    bytesPerSample = bytesPerFrame / pWav->channels;
6882
1.05k
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
6883
11
        return 0;   /* Only byte-aligned formats are supported. */
6884
11
    }
6885
6886
1.04k
    totalFramesRead = 0;
6887
6888
3.61k
    while (framesToRead > 0) {
6889
2.89k
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
6890
2.89k
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
6891
2.89k
        if (framesRead == 0) {
6892
326
            break;
6893
326
        }
6894
6895
2.56k
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
6896
6897
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
6898
2.56k
        samplesRead = framesRead * pWav->channels;
6899
2.56k
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
6900
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
6901
0
            break;
6902
0
        }
6903
6904
2.56k
        drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
6905
6906
2.56k
        pBufferOut      += samplesRead;
6907
2.56k
        framesToRead    -= framesRead;
6908
2.56k
        totalFramesRead += framesRead;
6909
2.56k
    }
6910
6911
1.04k
    return totalFramesRead;
6912
1.04k
}
6913
6914
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6915
691
{
6916
691
    drwav_uint64 totalFramesRead;
6917
691
    drwav_uint8 sampleData[4096] = {0};
6918
691
    drwav_uint32 bytesPerFrame;
6919
691
    drwav_uint32 bytesPerSample;
6920
691
    drwav_uint64 samplesRead;
6921
6922
691
    if (pBufferOut == NULL) {
6923
0
        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6924
0
    }
6925
6926
691
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6927
691
    if (bytesPerFrame == 0) {
6928
0
        return 0;
6929
0
    }
6930
6931
691
    bytesPerSample = bytesPerFrame / pWav->channels;
6932
691
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
6933
17
        return 0;   /* Only byte-aligned formats are supported. */
6934
17
    }
6935
6936
674
    totalFramesRead = 0;
6937
6938
2.04k
    while (framesToRead > 0) {
6939
1.58k
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
6940
1.58k
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
6941
1.58k
        if (framesRead == 0) {
6942
214
            break;
6943
214
        }
6944
6945
1.36k
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
6946
6947
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
6948
1.36k
        samplesRead = framesRead * pWav->channels;
6949
1.36k
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
6950
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
6951
0
            break;
6952
0
        }
6953
6954
1.36k
        drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);    /* Safe cast. */
6955
6956
1.36k
        pBufferOut      += samplesRead;
6957
1.36k
        framesToRead    -= framesRead;
6958
1.36k
        totalFramesRead += framesRead;
6959
1.36k
    }
6960
6961
674
    return totalFramesRead;
6962
674
}
6963
6964
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6965
1.14k
{
6966
1.14k
    drwav_uint64 totalFramesRead;
6967
1.14k
    drwav_uint8 sampleData[4096] = {0};
6968
1.14k
    drwav_uint32 bytesPerFrame;
6969
1.14k
    drwav_uint32 bytesPerSample;
6970
1.14k
    drwav_uint64 samplesRead;
6971
6972
1.14k
    if (pBufferOut == NULL) {
6973
0
        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6974
0
    }
6975
6976
1.14k
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6977
1.14k
    if (bytesPerFrame == 0) {
6978
0
        return 0;
6979
0
    }
6980
6981
1.14k
    bytesPerSample = bytesPerFrame / pWav->channels;
6982
1.14k
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
6983
0
        return 0;   /* Only byte-aligned formats are supported. */
6984
0
    }
6985
6986
1.14k
    totalFramesRead = 0;
6987
6988
2.78k
    while (framesToRead > 0) {
6989
1.74k
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
6990
1.74k
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
6991
1.74k
        if (framesRead == 0) {
6992
112
            break;
6993
112
        }
6994
6995
1.63k
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
6996
6997
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
6998
1.63k
        samplesRead = framesRead * pWav->channels;
6999
1.63k
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7000
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7001
0
            break;
7002
0
        }
7003
7004
1.63k
        drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead);
7005
7006
        /*
7007
        For some reason libsndfile seems to be returning samples of the opposite sign for a-law, but only
7008
        with AIFF files. For WAV files it seems to be the same as dr_wav. This is resulting in dr_wav's
7009
        automated tests failing. I'm not sure which is correct, but will assume dr_wav. If we're enforcing
7010
        libsndfile compatibility we'll swap the signs here.
7011
        */
7012
        #ifdef DR_WAV_LIBSNDFILE_COMPAT
7013
        {
7014
            if (pWav->container == drwav_container_aiff) {
7015
                drwav_uint64 iSample;
7016
                for (iSample = 0; iSample < samplesRead; iSample += 1) {
7017
                    pBufferOut[iSample] = -pBufferOut[iSample];
7018
                }
7019
            }
7020
        }
7021
        #endif
7022
7023
1.63k
        pBufferOut      += samplesRead;
7024
1.63k
        framesToRead    -= framesRead;
7025
1.63k
        totalFramesRead += framesRead;
7026
1.63k
    }
7027
7028
1.14k
    return totalFramesRead;
7029
1.14k
}
7030
7031
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
7032
1.39k
{
7033
1.39k
    drwav_uint64 totalFramesRead;
7034
1.39k
    drwav_uint8 sampleData[4096] = {0};
7035
1.39k
    drwav_uint32 bytesPerFrame;
7036
1.39k
    drwav_uint32 bytesPerSample;
7037
1.39k
    drwav_uint64 samplesRead;
7038
7039
1.39k
    if (pBufferOut == NULL) {
7040
0
        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
7041
0
    }
7042
7043
1.39k
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7044
1.39k
    if (bytesPerFrame == 0) {
7045
0
        return 0;
7046
0
    }
7047
7048
1.39k
    bytesPerSample = bytesPerFrame / pWav->channels;
7049
1.39k
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7050
0
        return 0;   /* Only byte-aligned formats are supported. */
7051
0
    }
7052
7053
1.39k
    totalFramesRead = 0;
7054
7055
3.45k
    while (framesToRead > 0) {
7056
2.21k
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7057
2.21k
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7058
2.21k
        if (framesRead == 0) {
7059
158
            break;
7060
158
        }
7061
7062
2.06k
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7063
7064
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7065
2.06k
        samplesRead = framesRead * pWav->channels;
7066
2.06k
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7067
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7068
0
            break;
7069
0
        }
7070
7071
2.06k
        drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead);
7072
7073
        /*
7074
        Just like with alaw, for some reason the signs between libsndfile and dr_wav are opposite. We just need to
7075
        swap the sign if we're compiling with libsndfile compatiblity so our automated tests don't fail.
7076
        */
7077
        #ifdef DR_WAV_LIBSNDFILE_COMPAT
7078
        {
7079
            if (pWav->container == drwav_container_aiff) {
7080
                drwav_uint64 iSample;
7081
                for (iSample = 0; iSample < samplesRead; iSample += 1) {
7082
                    pBufferOut[iSample] = -pBufferOut[iSample];
7083
                }
7084
            }
7085
        }
7086
        #endif
7087
7088
2.06k
        pBufferOut      += samplesRead;
7089
2.06k
        framesToRead    -= framesRead;
7090
2.06k
        totalFramesRead += framesRead;
7091
2.06k
    }
7092
7093
1.39k
    return totalFramesRead;
7094
1.39k
}
7095
7096
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
7097
7.91k
{
7098
7.91k
    if (pWav == NULL || framesToRead == 0) {
7099
0
        return 0;
7100
0
    }
7101
7102
7.91k
    if (pBufferOut == NULL) {
7103
0
        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
7104
0
    }
7105
7106
    /* Don't try to read more samples than can potentially fit in the output buffer. */
7107
7.91k
    if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) {
7108
0
        framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels;
7109
0
    }
7110
7111
7.91k
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
7112
1.16k
        return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut);
7113
1.16k
    }
7114
7115
6.74k
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
7116
691
        return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut);
7117
691
    }
7118
7119
6.05k
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
7120
1.14k
        return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut);
7121
1.14k
    }
7122
7123
4.90k
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
7124
1.39k
        return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut);
7125
1.39k
    }
7126
7127
3.51k
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
7128
1.85k
        return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut);
7129
1.85k
    }
7130
7131
1.65k
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
7132
1.60k
        return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut);
7133
1.60k
    }
7134
7135
46
    return 0;
7136
1.65k
}
7137
7138
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
7139
0
{
7140
0
    drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
7141
0
    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
7142
0
        drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
7143
0
    }
7144
7145
0
    return framesRead;
7146
0
}
7147
7148
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
7149
0
{
7150
0
    drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
7151
0
    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
7152
0
        drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
7153
0
    }
7154
7155
0
    return framesRead;
7156
0
}
7157
7158
7159
DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
7160
790
{
7161
790
    int r;
7162
790
    size_t i;
7163
2.96M
    for (i = 0; i < sampleCount; ++i) {
7164
2.96M
        int x = pIn[i];
7165
2.96M
        r = x << 8;
7166
2.96M
        r = r - 32768;
7167
2.96M
        pOut[i] = (short)r;
7168
2.96M
    }
7169
790
}
7170
7171
DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
7172
436
{
7173
436
    int r;
7174
436
    size_t i;
7175
399k
    for (i = 0; i < sampleCount; ++i) {
7176
399k
        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;
7177
399k
        r = x >> 8;
7178
399k
        pOut[i] = (short)r;
7179
399k
    }
7180
436
}
7181
7182
DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
7183
666
{
7184
666
    int r;
7185
666
    size_t i;
7186
629k
    for (i = 0; i < sampleCount; ++i) {
7187
628k
        int x = pIn[i];
7188
628k
        r = x >> 16;
7189
628k
        pOut[i] = (short)r;
7190
628k
    }
7191
666
}
7192
7193
DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
7194
229
{
7195
229
    size_t i;
7196
193k
    for (i = 0; i < sampleCount; ++i) {
7197
193k
        float x = pIn[i];
7198
193k
        if (x != x) {
7199
1.13k
            pOut[i] = 0;    /* NaN */
7200
192k
        } else if (x <= -1) {
7201
12.1k
            pOut[i] = (-32767 - 1);
7202
179k
        } else if (x >= 1) {
7203
18.0k
            pOut[i] = 32767;
7204
161k
        } else {
7205
161k
            pOut[i] = (drwav_int16)(x * 32768.0f);
7206
161k
        }
7207
193k
    }
7208
229
}
7209
7210
DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
7211
403
{
7212
403
    size_t i;
7213
183k
    for (i = 0; i < sampleCount; ++i) {
7214
182k
        double x = pIn[i];
7215
182k
        if (x != x) {
7216
4.87k
            pOut[i] = 0;    /* NaN */
7217
177k
        } else if (x <= -1) {
7218
31.4k
            pOut[i] = (-32767 - 1);
7219
146k
        } else if (x >= 1) {
7220
46.0k
            pOut[i] = 32767;
7221
100k
        } else {
7222
100k
            pOut[i] = (drwav_int16)(x * 32768.0);
7223
100k
        }
7224
182k
    }
7225
403
}
7226
7227
DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
7228
1.63k
{
7229
1.63k
    size_t i;
7230
5.93M
    for (i = 0; i < sampleCount; ++i) {
7231
5.93M
        pOut[i] = drwav__alaw_to_s16(pIn[i]);
7232
5.93M
    }
7233
1.63k
}
7234
7235
DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
7236
2.06k
{
7237
2.06k
    size_t i;
7238
7.57M
    for (i = 0; i < sampleCount; ++i) {
7239
7.57M
        pOut[i] = drwav__mulaw_to_s16(pIn[i]);
7240
7.57M
    }
7241
2.06k
}
7242
7243
7244
DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
7245
0
{
7246
0
    unsigned int i;
7247
7248
    /* Special case for 8-bit sample data because it's treated as unsigned. */
7249
0
    if (bytesPerSample == 1) {
7250
0
        drwav_u8_to_f32(pOut, pIn, sampleCount);
7251
0
        return;
7252
0
    }
7253
7254
    /* Slightly more optimal implementation for common formats. */
7255
0
    if (bytesPerSample == 2) {
7256
0
        drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount);
7257
0
        return;
7258
0
    }
7259
0
    if (bytesPerSample == 3) {
7260
0
        drwav_s24_to_f32(pOut, pIn, sampleCount);
7261
0
        return;
7262
0
    }
7263
0
    if (bytesPerSample == 4) {
7264
0
        drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
7265
0
        return;
7266
0
    }
7267
7268
7269
    /* Anything more than 64 bits per sample is not supported. */
7270
0
    if (bytesPerSample > 8) {
7271
0
        DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
7272
0
        return;
7273
0
    }
7274
7275
7276
    /* Generic, slow converter. */
7277
0
    for (i = 0; i < sampleCount; ++i) {
7278
0
        drwav_uint64 sample = 0;
7279
0
        unsigned int shift  = (8 - bytesPerSample) * 8;
7280
7281
0
        unsigned int j;
7282
0
        for (j = 0; j < bytesPerSample; j += 1) {
7283
0
            DRWAV_ASSERT(j < 8);
7284
0
            sample |= (drwav_uint64)(pIn[j]) << shift;
7285
0
            shift  += 8;
7286
0
        }
7287
7288
0
        if (!drwav__is_little_endian()) {
7289
0
            sample = drwav__bswap64(sample);
7290
0
        }
7291
7292
0
        pIn += j;
7293
0
        *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
7294
0
    }
7295
0
}
7296
7297
DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
7298
0
{
7299
0
    if (bytesPerSample == 4) {
7300
0
        unsigned int i;
7301
0
        for (i = 0; i < sampleCount; ++i) {
7302
0
            *pOut++ = ((const float*)pIn)[i];
7303
0
        }
7304
0
        return;
7305
0
    } else if (bytesPerSample == 8) {
7306
0
        drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount);
7307
0
        return;
7308
0
    } else {
7309
        /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
7310
0
        DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
7311
0
        return;
7312
0
    }
7313
0
}
7314
7315
7316
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7317
0
{
7318
0
    drwav_uint64 totalFramesRead;
7319
0
    drwav_uint8 sampleData[4096] = {0};
7320
0
    drwav_uint32 bytesPerFrame;
7321
0
    drwav_uint32 bytesPerSample;
7322
0
    drwav_uint64 samplesRead;
7323
7324
0
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7325
0
    if (bytesPerFrame == 0) {
7326
0
        return 0;
7327
0
    }
7328
7329
0
    bytesPerSample = bytesPerFrame / pWav->channels;
7330
0
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7331
0
        return 0;   /* Only byte-aligned formats are supported. */
7332
0
    }
7333
7334
0
    totalFramesRead = 0;
7335
7336
0
    while (framesToRead > 0) {
7337
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7338
0
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7339
0
        if (framesRead == 0) {
7340
0
            break;
7341
0
        }
7342
7343
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7344
7345
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7346
0
        samplesRead = framesRead * pWav->channels;
7347
0
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7348
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7349
0
            break;
7350
0
        }
7351
7352
0
        drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
7353
7354
0
        pBufferOut      += samplesRead;
7355
0
        framesToRead    -= framesRead;
7356
0
        totalFramesRead += framesRead;
7357
0
    }
7358
7359
0
    return totalFramesRead;
7360
0
}
7361
7362
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7363
0
{
7364
    /*
7365
    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
7366
    want to duplicate that code.
7367
    */
7368
0
    drwav_uint64 totalFramesRead;
7369
0
    drwav_int16 samples16[2048];
7370
7371
0
    totalFramesRead = 0;
7372
7373
0
    while (framesToRead > 0) {
7374
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels);
7375
0
        drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16);
7376
0
        if (framesRead == 0) {
7377
0
            break;
7378
0
        }
7379
7380
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7381
7382
0
        drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));   /* <-- Safe cast because we're clamping to 2048. */
7383
7384
0
        pBufferOut      += framesRead*pWav->channels;
7385
0
        framesToRead    -= framesRead;
7386
0
        totalFramesRead += framesRead;
7387
0
    }
7388
7389
0
    return totalFramesRead;
7390
0
}
7391
7392
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7393
0
{
7394
0
    drwav_uint64 totalFramesRead;
7395
0
    drwav_uint8 sampleData[4096] = {0};
7396
0
    drwav_uint32 bytesPerFrame;
7397
0
    drwav_uint32 bytesPerSample;
7398
0
    drwav_uint64 samplesRead;
7399
7400
    /* Fast path. */
7401
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) {
7402
0
        return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
7403
0
    }
7404
7405
0
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7406
0
    if (bytesPerFrame == 0) {
7407
0
        return 0;
7408
0
    }
7409
7410
0
    bytesPerSample = bytesPerFrame / pWav->channels;
7411
0
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7412
0
        return 0;   /* Only byte-aligned formats are supported. */
7413
0
    }
7414
7415
0
    totalFramesRead = 0;
7416
7417
0
    while (framesToRead > 0) {
7418
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7419
0
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7420
0
        if (framesRead == 0) {
7421
0
            break;
7422
0
        }
7423
7424
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7425
7426
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7427
0
        samplesRead = framesRead * pWav->channels;
7428
0
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7429
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7430
0
            break;
7431
0
        }
7432
7433
0
        drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
7434
7435
0
        pBufferOut      += samplesRead;
7436
0
        framesToRead    -= framesRead;
7437
0
        totalFramesRead += framesRead;
7438
0
    }
7439
7440
0
    return totalFramesRead;
7441
0
}
7442
7443
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7444
0
{
7445
0
    drwav_uint64 totalFramesRead;
7446
0
    drwav_uint8 sampleData[4096] = {0};
7447
0
    drwav_uint32 bytesPerFrame;
7448
0
    drwav_uint32 bytesPerSample;
7449
0
    drwav_uint64 samplesRead;
7450
7451
0
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7452
0
    if (bytesPerFrame == 0) {
7453
0
        return 0;
7454
0
    }
7455
7456
0
    bytesPerSample = bytesPerFrame / pWav->channels;
7457
0
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7458
0
        return 0;   /* Only byte-aligned formats are supported. */
7459
0
    }
7460
7461
0
    totalFramesRead = 0;
7462
7463
0
    while (framesToRead > 0) {
7464
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7465
0
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7466
0
        if (framesRead == 0) {
7467
0
            break;
7468
0
        }
7469
7470
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7471
7472
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7473
0
        samplesRead = framesRead * pWav->channels;
7474
0
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7475
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7476
0
            break;
7477
0
        }
7478
7479
0
        drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
7480
7481
        #ifdef DR_WAV_LIBSNDFILE_COMPAT
7482
        {
7483
            if (pWav->container == drwav_container_aiff) {
7484
                drwav_uint64 iSample;
7485
                for (iSample = 0; iSample < samplesRead; iSample += 1) {
7486
                    pBufferOut[iSample] = -pBufferOut[iSample];
7487
                }
7488
            }
7489
        }
7490
        #endif
7491
7492
0
        pBufferOut      += samplesRead;
7493
0
        framesToRead    -= framesRead;
7494
0
        totalFramesRead += framesRead;
7495
0
    }
7496
7497
0
    return totalFramesRead;
7498
0
}
7499
7500
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7501
0
{
7502
0
    drwav_uint64 totalFramesRead;
7503
0
    drwav_uint8 sampleData[4096] = {0};
7504
0
    drwav_uint32 bytesPerFrame;
7505
0
    drwav_uint32 bytesPerSample;
7506
0
    drwav_uint64 samplesRead;
7507
7508
0
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7509
0
    if (bytesPerFrame == 0) {
7510
0
        return 0;
7511
0
    }
7512
7513
0
    bytesPerSample = bytesPerFrame / pWav->channels;
7514
0
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7515
0
        return 0;   /* Only byte-aligned formats are supported. */
7516
0
    }
7517
7518
0
    totalFramesRead = 0;
7519
7520
0
    while (framesToRead > 0) {
7521
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7522
0
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7523
0
        if (framesRead == 0) {
7524
0
            break;
7525
0
        }
7526
7527
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7528
7529
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7530
0
        samplesRead = framesRead * pWav->channels;
7531
0
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7532
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7533
0
            break;
7534
0
        }
7535
7536
0
        drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
7537
7538
        #ifdef DR_WAV_LIBSNDFILE_COMPAT
7539
        {
7540
            if (pWav->container == drwav_container_aiff) {
7541
                drwav_uint64 iSample;
7542
                for (iSample = 0; iSample < samplesRead; iSample += 1) {
7543
                    pBufferOut[iSample] = -pBufferOut[iSample];
7544
                }
7545
            }
7546
        }
7547
        #endif
7548
7549
0
        pBufferOut      += samplesRead;
7550
0
        framesToRead    -= framesRead;
7551
0
        totalFramesRead += framesRead;
7552
0
    }
7553
7554
0
    return totalFramesRead;
7555
0
}
7556
7557
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7558
0
{
7559
0
    if (pWav == NULL || framesToRead == 0) {
7560
0
        return 0;
7561
0
    }
7562
7563
0
    if (pBufferOut == NULL) {
7564
0
        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
7565
0
    }
7566
7567
    /* Don't try to read more samples than can potentially fit in the output buffer. */
7568
0
    if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) {
7569
0
        framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels;
7570
0
    }
7571
7572
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
7573
0
        return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut);
7574
0
    }
7575
7576
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
7577
0
        return drwav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut);
7578
0
    }
7579
7580
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
7581
0
        return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut);
7582
0
    }
7583
7584
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
7585
0
        return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut);
7586
0
    }
7587
7588
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
7589
0
        return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut);
7590
0
    }
7591
7592
0
    return 0;
7593
0
}
7594
7595
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7596
0
{
7597
0
    drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
7598
0
    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
7599
0
        drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
7600
0
    }
7601
7602
0
    return framesRead;
7603
0
}
7604
7605
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7606
0
{
7607
0
    drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
7608
0
    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
7609
0
        drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
7610
0
    }
7611
7612
0
    return framesRead;
7613
0
}
7614
7615
7616
DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
7617
0
{
7618
0
    size_t i;
7619
7620
0
    if (pOut == NULL || pIn == NULL) {
7621
0
        return;
7622
0
    }
7623
7624
#ifdef DR_WAV_LIBSNDFILE_COMPAT
7625
    /*
7626
    It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears
7627
    libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note
7628
    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
7629
    correctness testing. This is disabled by default.
7630
    */
7631
    for (i = 0; i < sampleCount; ++i) {
7632
        *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
7633
    }
7634
#else
7635
0
    for (i = 0; i < sampleCount; ++i) {
7636
0
        float x = pIn[i];
7637
0
        x = x * 0.00784313725490196078f;    /* 0..255 to 0..2 */
7638
0
        x = x - 1;                          /* 0..2 to -1..1 */
7639
7640
0
        *pOut++ = x;
7641
0
    }
7642
0
#endif
7643
0
}
7644
7645
DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
7646
0
{
7647
0
    size_t i;
7648
7649
0
    if (pOut == NULL || pIn == NULL) {
7650
0
        return;
7651
0
    }
7652
7653
0
    for (i = 0; i < sampleCount; ++i) {
7654
0
        *pOut++ = pIn[i] * 0.000030517578125f;
7655
0
    }
7656
0
}
7657
7658
DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
7659
0
{
7660
0
    size_t i;
7661
7662
0
    if (pOut == NULL || pIn == NULL) {
7663
0
        return;
7664
0
    }
7665
7666
0
    for (i = 0; i < sampleCount; ++i) {
7667
0
        double x;
7668
0
        drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) <<  8);
7669
0
        drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16);
7670
0
        drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24);
7671
7672
0
        x = (double)((drwav_int32)(a | b | c) >> 8);
7673
0
        *pOut++ = (float)(x * 0.00000011920928955078125);
7674
0
    }
7675
0
}
7676
7677
DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
7678
0
{
7679
0
    size_t i;
7680
0
    if (pOut == NULL || pIn == NULL) {
7681
0
        return;
7682
0
    }
7683
7684
0
    for (i = 0; i < sampleCount; ++i) {
7685
0
        *pOut++ = (float)(pIn[i] / 2147483648.0);
7686
0
    }
7687
0
}
7688
7689
DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
7690
0
{
7691
0
    size_t i;
7692
7693
0
    if (pOut == NULL || pIn == NULL) {
7694
0
        return;
7695
0
    }
7696
7697
0
    for (i = 0; i < sampleCount; ++i) {
7698
0
        *pOut++ = (float)pIn[i];
7699
0
    }
7700
0
}
7701
7702
DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
7703
0
{
7704
0
    size_t i;
7705
7706
0
    if (pOut == NULL || pIn == NULL) {
7707
0
        return;
7708
0
    }
7709
7710
0
    for (i = 0; i < sampleCount; ++i) {
7711
0
        *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
7712
0
    }
7713
0
}
7714
7715
DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
7716
0
{
7717
0
    size_t i;
7718
7719
0
    if (pOut == NULL || pIn == NULL) {
7720
0
        return;
7721
0
    }
7722
7723
0
    for (i = 0; i < sampleCount; ++i) {
7724
0
        *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
7725
0
    }
7726
0
}
7727
7728
7729
7730
DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
7731
0
{
7732
0
    unsigned int i;
7733
7734
    /* Special case for 8-bit sample data because it's treated as unsigned. */
7735
0
    if (bytesPerSample == 1) {
7736
0
        drwav_u8_to_s32(pOut, pIn, totalSampleCount);
7737
0
        return;
7738
0
    }
7739
7740
    /* Slightly more optimal implementation for common formats. */
7741
0
    if (bytesPerSample == 2) {
7742
0
        drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount);
7743
0
        return;
7744
0
    }
7745
0
    if (bytesPerSample == 3) {
7746
0
        drwav_s24_to_s32(pOut, pIn, totalSampleCount);
7747
0
        return;
7748
0
    }
7749
0
    if (bytesPerSample == 4) {
7750
0
        for (i = 0; i < totalSampleCount; ++i) {
7751
0
           *pOut++ = ((const drwav_int32*)pIn)[i];
7752
0
        }
7753
0
        return;
7754
0
    }
7755
7756
7757
    /* Anything more than 64 bits per sample is not supported. */
7758
0
    if (bytesPerSample > 8) {
7759
0
        DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
7760
0
        return;
7761
0
    }
7762
7763
7764
    /* Generic, slow converter. */
7765
0
    for (i = 0; i < totalSampleCount; ++i) {
7766
0
        drwav_uint64 sample = 0;
7767
0
        unsigned int shift  = (8 - bytesPerSample) * 8;
7768
7769
0
        unsigned int j;
7770
0
        for (j = 0; j < bytesPerSample; j += 1) {
7771
0
            DRWAV_ASSERT(j < 8);
7772
0
            sample |= (drwav_uint64)(pIn[j]) << shift;
7773
0
            shift  += 8;
7774
0
        }
7775
7776
0
        if (!drwav__is_little_endian()) {
7777
0
            sample = drwav__bswap64(sample);
7778
0
        }
7779
7780
0
        pIn += j;
7781
0
        *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
7782
0
    }
7783
0
}
7784
7785
DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
7786
0
{
7787
0
    if (bytesPerSample == 4) {
7788
0
        drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount);
7789
0
        return;
7790
0
    } else if (bytesPerSample == 8) {
7791
0
        drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount);
7792
0
        return;
7793
0
    } else {
7794
        /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
7795
0
        DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
7796
0
        return;
7797
0
    }
7798
0
}
7799
7800
7801
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7802
0
{
7803
0
    drwav_uint64 totalFramesRead;
7804
0
    drwav_uint8 sampleData[4096] = {0};
7805
0
    drwav_uint32 bytesPerFrame;
7806
0
    drwav_uint32 bytesPerSample;
7807
0
    drwav_uint64 samplesRead;
7808
7809
    /* Fast path. */
7810
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) {
7811
0
        return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
7812
0
    }
7813
7814
0
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7815
0
    if (bytesPerFrame == 0) {
7816
0
        return 0;
7817
0
    }
7818
7819
0
    bytesPerSample = bytesPerFrame / pWav->channels;
7820
0
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7821
0
        return 0;   /* Only byte-aligned formats are supported. */
7822
0
    }
7823
7824
0
    totalFramesRead = 0;
7825
7826
0
    while (framesToRead > 0) {
7827
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7828
0
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7829
0
        if (framesRead == 0) {
7830
0
            break;
7831
0
        }
7832
7833
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7834
7835
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7836
0
        samplesRead = framesRead * pWav->channels;
7837
0
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7838
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7839
0
            break;
7840
0
        }
7841
7842
0
        drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
7843
7844
0
        pBufferOut      += samplesRead;
7845
0
        framesToRead    -= framesRead;
7846
0
        totalFramesRead += framesRead;
7847
0
    }
7848
7849
0
    return totalFramesRead;
7850
0
}
7851
7852
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7853
0
{
7854
    /*
7855
    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
7856
    want to duplicate that code.
7857
    */
7858
0
    drwav_uint64 totalFramesRead = 0;
7859
0
    drwav_int16 samples16[2048];
7860
7861
0
    while (framesToRead > 0) {
7862
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels);
7863
0
        drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16);
7864
0
        if (framesRead == 0) {
7865
0
            break;
7866
0
        }
7867
7868
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7869
7870
0
        drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));   /* <-- Safe cast because we're clamping to 2048. */
7871
7872
0
        pBufferOut      += framesRead*pWav->channels;
7873
0
        framesToRead    -= framesRead;
7874
0
        totalFramesRead += framesRead;
7875
0
    }
7876
7877
0
    return totalFramesRead;
7878
0
}
7879
7880
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7881
0
{
7882
0
    drwav_uint64 totalFramesRead;
7883
0
    drwav_uint8 sampleData[4096] = {0};
7884
0
    drwav_uint32 bytesPerFrame;
7885
0
    drwav_uint32 bytesPerSample;
7886
0
    drwav_uint64 samplesRead;
7887
7888
0
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7889
0
    if (bytesPerFrame == 0) {
7890
0
        return 0;
7891
0
    }
7892
7893
0
    bytesPerSample = bytesPerFrame / pWav->channels;
7894
0
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7895
0
        return 0;   /* Only byte-aligned formats are supported. */
7896
0
    }
7897
7898
0
    totalFramesRead = 0;
7899
7900
0
    while (framesToRead > 0) {
7901
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7902
0
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7903
0
        if (framesRead == 0) {
7904
0
            break;
7905
0
        }
7906
7907
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7908
7909
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7910
0
        samplesRead = framesRead * pWav->channels;
7911
0
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7912
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7913
0
            break;
7914
0
        }
7915
7916
0
        drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
7917
7918
0
        pBufferOut      += samplesRead;
7919
0
        framesToRead    -= framesRead;
7920
0
        totalFramesRead += framesRead;
7921
0
    }
7922
7923
0
    return totalFramesRead;
7924
0
}
7925
7926
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7927
0
{
7928
0
    drwav_uint64 totalFramesRead;
7929
0
    drwav_uint8 sampleData[4096] = {0};
7930
0
    drwav_uint32 bytesPerFrame;
7931
0
    drwav_uint32 bytesPerSample;
7932
0
    drwav_uint64 samplesRead;
7933
7934
0
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7935
0
    if (bytesPerFrame == 0) {
7936
0
        return 0;
7937
0
    }
7938
7939
0
    bytesPerSample = bytesPerFrame / pWav->channels;
7940
0
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7941
0
        return 0;   /* Only byte-aligned formats are supported. */
7942
0
    }
7943
7944
0
    totalFramesRead = 0;
7945
7946
0
    while (framesToRead > 0) {
7947
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7948
0
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7949
0
        if (framesRead == 0) {
7950
0
            break;
7951
0
        }
7952
7953
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7954
7955
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7956
0
        samplesRead = framesRead * pWav->channels;
7957
0
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7958
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
7959
0
            break;
7960
0
        }
7961
7962
0
        drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
7963
7964
        #ifdef DR_WAV_LIBSNDFILE_COMPAT
7965
        {
7966
            if (pWav->container == drwav_container_aiff) {
7967
                drwav_uint64 iSample;
7968
                for (iSample = 0; iSample < samplesRead; iSample += 1) {
7969
                    pBufferOut[iSample] = -pBufferOut[iSample];
7970
                }
7971
            }
7972
        }
7973
        #endif
7974
7975
0
        pBufferOut      += samplesRead;
7976
0
        framesToRead    -= framesRead;
7977
0
        totalFramesRead += framesRead;
7978
0
    }
7979
7980
0
    return totalFramesRead;
7981
0
}
7982
7983
DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7984
0
{
7985
0
    drwav_uint64 totalFramesRead;
7986
0
    drwav_uint8 sampleData[4096] = {0};
7987
0
    drwav_uint32 bytesPerFrame;
7988
0
    drwav_uint32 bytesPerSample;
7989
0
    drwav_uint64 samplesRead;
7990
7991
0
    bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7992
0
    if (bytesPerFrame == 0) {
7993
0
        return 0;
7994
0
    }
7995
7996
0
    bytesPerSample = bytesPerFrame / pWav->channels;
7997
0
    if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7998
0
        return 0;   /* Only byte-aligned formats are supported. */
7999
0
    }
8000
8001
0
    totalFramesRead = 0;
8002
8003
0
    while (framesToRead > 0) {
8004
0
        drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
8005
0
        drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
8006
0
        if (framesRead == 0) {
8007
0
            break;
8008
0
        }
8009
8010
0
        DRWAV_ASSERT(framesRead <= framesToReadThisIteration);   /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
8011
8012
        /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
8013
0
        samplesRead = framesRead * pWav->channels;
8014
0
        if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
8015
0
            DRWAV_ASSERT(DRWAV_FALSE);  /* This should never happen with a valid file. */
8016
0
            break;
8017
0
        }
8018
8019
0
        drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
8020
8021
        #ifdef DR_WAV_LIBSNDFILE_COMPAT
8022
        {
8023
            if (pWav->container == drwav_container_aiff) {
8024
                drwav_uint64 iSample;
8025
                for (iSample = 0; iSample < samplesRead; iSample += 1) {
8026
                    pBufferOut[iSample] = -pBufferOut[iSample];
8027
                }
8028
            }
8029
        }
8030
        #endif
8031
8032
0
        pBufferOut      += samplesRead;
8033
0
        framesToRead    -= framesRead;
8034
0
        totalFramesRead += framesRead;
8035
0
    }
8036
8037
0
    return totalFramesRead;
8038
0
}
8039
8040
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
8041
0
{
8042
0
    if (pWav == NULL || framesToRead == 0) {
8043
0
        return 0;
8044
0
    }
8045
8046
0
    if (pBufferOut == NULL) {
8047
0
        return drwav_read_pcm_frames(pWav, framesToRead, NULL);
8048
0
    }
8049
8050
    /* Don't try to read more samples than can potentially fit in the output buffer. */
8051
0
    if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) {
8052
0
        framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels;
8053
0
    }
8054
8055
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
8056
0
        return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut);
8057
0
    }
8058
8059
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
8060
0
        return drwav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut);
8061
0
    }
8062
8063
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
8064
0
        return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut);
8065
0
    }
8066
8067
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
8068
0
        return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut);
8069
0
    }
8070
8071
0
    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
8072
0
        return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut);
8073
0
    }
8074
8075
0
    return 0;
8076
0
}
8077
8078
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
8079
0
{
8080
0
    drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
8081
0
    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
8082
0
        drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
8083
0
    }
8084
8085
0
    return framesRead;
8086
0
}
8087
8088
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
8089
0
{
8090
0
    drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
8091
0
    if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
8092
0
        drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
8093
0
    }
8094
8095
0
    return framesRead;
8096
0
}
8097
8098
8099
DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
8100
0
{
8101
0
    size_t i;
8102
8103
0
    if (pOut == NULL || pIn == NULL) {
8104
0
        return;
8105
0
    }
8106
8107
0
    for (i = 0; i < sampleCount; ++i) {
8108
0
        *pOut++ = ((int)pIn[i] - 128) * 16777216;
8109
0
    }
8110
0
}
8111
8112
DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
8113
0
{
8114
0
    size_t i;
8115
8116
0
    if (pOut == NULL || pIn == NULL) {
8117
0
        return;
8118
0
    }
8119
8120
0
    for (i = 0; i < sampleCount; ++i) {
8121
0
        *pOut++ = (drwav_int32)pIn[i] * 65536;
8122
0
    }
8123
0
}
8124
8125
DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
8126
0
{
8127
0
    size_t i;
8128
8129
0
    if (pOut == NULL || pIn == NULL) {
8130
0
        return;
8131
0
    }
8132
8133
0
    for (i = 0; i < sampleCount; ++i) {
8134
0
        unsigned int s0 = pIn[i*3 + 0];
8135
0
        unsigned int s1 = pIn[i*3 + 1];
8136
0
        unsigned int s2 = pIn[i*3 + 2];
8137
8138
0
        drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
8139
0
        *pOut++ = sample32;
8140
0
    }
8141
0
}
8142
8143
DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
8144
0
{
8145
0
    size_t i;
8146
0
    for (i = 0; i < sampleCount; ++i) {
8147
0
        float x = pIn[i];
8148
0
        if (x != x) {
8149
0
            pOut[i] = 0;    /* NaN */
8150
0
        } else if (x <= -1) {
8151
0
            pOut[i] = (-2147483647 - 1);
8152
0
        } else if (x >= 1) {
8153
0
            pOut[i] = 2147483647;
8154
0
        } else {
8155
0
            pOut[i] = (drwav_int32)(x * 2147483648.0f);
8156
0
        }
8157
0
    }
8158
0
}
8159
8160
DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
8161
0
{
8162
0
    size_t i;
8163
0
    for (i = 0; i < sampleCount; ++i) {
8164
0
        double x = pIn[i];
8165
0
        if (x != x) {
8166
0
            pOut[i] = 0;    /* NaN */
8167
0
        } else if (x <= -1) {
8168
0
            pOut[i] = (-2147483647 - 1);
8169
0
        } else if (x >= 1) {
8170
0
            pOut[i] = 2147483647;
8171
0
        } else {
8172
0
            pOut[i] = (drwav_int32)(x * 2147483648.0);
8173
0
        }
8174
0
    }
8175
0
}
8176
8177
DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
8178
0
{
8179
0
    size_t i;
8180
8181
0
    if (pOut == NULL || pIn == NULL) {
8182
0
        return;
8183
0
    }
8184
8185
0
    for (i = 0; i < sampleCount; ++i) {
8186
0
        *pOut++ = (drwav_int32)drwav__alaw_to_s16(pIn[i]) * 65536;
8187
0
    }
8188
0
}
8189
8190
DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
8191
0
{
8192
0
    size_t i;
8193
8194
0
    if (pOut == NULL || pIn == NULL) {
8195
0
        return;
8196
0
    }
8197
8198
0
    for (i= 0; i < sampleCount; ++i) {
8199
0
        *pOut++ = (drwav_int32)drwav__mulaw_to_s16(pIn[i]) * 65536;
8200
0
    }
8201
0
}
8202
8203
8204
8205
DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
8206
0
{
8207
0
    drwav_uint64 sampleDataSize;
8208
0
    drwav_int16* pSampleData;
8209
0
    drwav_uint64 framesRead;
8210
8211
0
    DRWAV_ASSERT(pWav != NULL);
8212
8213
    /* Check for overflow before multiplication. */
8214
0
    if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(drwav_int16)) {
8215
0
        drwav_uninit(pWav);
8216
0
        return NULL;    /* Overflow or invalid channels. */
8217
0
    }
8218
8219
0
    sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
8220
0
    if (sampleDataSize > DRWAV_SIZE_MAX) {
8221
0
        drwav_uninit(pWav);
8222
0
        return NULL;    /* File's too big. */
8223
0
    }
8224
8225
0
    pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
8226
0
    if (pSampleData == NULL) {
8227
0
        drwav_uninit(pWav);
8228
0
        return NULL;    /* Failed to allocate memory. */
8229
0
    }
8230
8231
0
    framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
8232
0
    if (framesRead != pWav->totalPCMFrameCount) {
8233
0
        drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
8234
0
        drwav_uninit(pWav);
8235
0
        return NULL;    /* There was an error reading the samples. */
8236
0
    }
8237
8238
0
    drwav_uninit(pWav);
8239
8240
0
    if (sampleRate) {
8241
0
        *sampleRate = pWav->sampleRate;
8242
0
    }
8243
0
    if (channels) {
8244
0
        *channels = pWav->channels;
8245
0
    }
8246
0
    if (totalFrameCount) {
8247
0
        *totalFrameCount = pWav->totalPCMFrameCount;
8248
0
    }
8249
8250
0
    return pSampleData;
8251
0
}
8252
8253
DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
8254
0
{
8255
0
    drwav_uint64 sampleDataSize;
8256
0
    float* pSampleData;
8257
0
    drwav_uint64 framesRead;
8258
8259
0
    DRWAV_ASSERT(pWav != NULL);
8260
8261
    /* Check for overflow before multiplication. */
8262
0
    if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(float)) {
8263
0
        drwav_uninit(pWav);
8264
0
        return NULL;    /* Overflow or invalid channels. */
8265
0
    }
8266
8267
0
    sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
8268
0
    if (sampleDataSize > DRWAV_SIZE_MAX) {
8269
0
        drwav_uninit(pWav);
8270
0
        return NULL;    /* File's too big. */
8271
0
    }
8272
8273
0
    pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
8274
0
    if (pSampleData == NULL) {
8275
0
        drwav_uninit(pWav);
8276
0
        return NULL;    /* Failed to allocate memory. */
8277
0
    }
8278
8279
0
    framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
8280
0
    if (framesRead != pWav->totalPCMFrameCount) {
8281
0
        drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
8282
0
        drwav_uninit(pWav);
8283
0
        return NULL;    /* There was an error reading the samples. */
8284
0
    }
8285
8286
0
    drwav_uninit(pWav);
8287
8288
0
    if (sampleRate) {
8289
0
        *sampleRate = pWav->sampleRate;
8290
0
    }
8291
0
    if (channels) {
8292
0
        *channels = pWav->channels;
8293
0
    }
8294
0
    if (totalFrameCount) {
8295
0
        *totalFrameCount = pWav->totalPCMFrameCount;
8296
0
    }
8297
8298
0
    return pSampleData;
8299
0
}
8300
8301
DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
8302
0
{
8303
0
    drwav_uint64 sampleDataSize;
8304
0
    drwav_int32* pSampleData;
8305
0
    drwav_uint64 framesRead;
8306
8307
0
    DRWAV_ASSERT(pWav != NULL);
8308
8309
    /* Check for overflow before multiplication. */
8310
0
    if (pWav->channels == 0 || pWav->totalPCMFrameCount > DRWAV_SIZE_MAX / pWav->channels / sizeof(drwav_int32)) {
8311
0
        drwav_uninit(pWav);
8312
0
        return NULL;    /* Overflow or invalid channels. */
8313
0
    }
8314
8315
0
    sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
8316
0
    if (sampleDataSize > DRWAV_SIZE_MAX) {
8317
0
        drwav_uninit(pWav);
8318
0
        return NULL;    /* File's too big. */
8319
0
    }
8320
8321
0
    pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
8322
0
    if (pSampleData == NULL) {
8323
0
        drwav_uninit(pWav);
8324
0
        return NULL;    /* Failed to allocate memory. */
8325
0
    }
8326
8327
0
    framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
8328
0
    if (framesRead != pWav->totalPCMFrameCount) {
8329
0
        drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
8330
0
        drwav_uninit(pWav);
8331
0
        return NULL;    /* There was an error reading the samples. */
8332
0
    }
8333
8334
0
    drwav_uninit(pWav);
8335
8336
0
    if (sampleRate) {
8337
0
        *sampleRate = pWav->sampleRate;
8338
0
    }
8339
0
    if (channels) {
8340
0
        *channels = pWav->channels;
8341
0
    }
8342
0
    if (totalFrameCount) {
8343
0
        *totalFrameCount = pWav->totalPCMFrameCount;
8344
0
    }
8345
8346
0
    return pSampleData;
8347
0
}
8348
8349
8350
8351
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8352
0
{
8353
0
    drwav wav;
8354
8355
0
    if (channelsOut) {
8356
0
        *channelsOut = 0;
8357
0
    }
8358
0
    if (sampleRateOut) {
8359
0
        *sampleRateOut = 0;
8360
0
    }
8361
0
    if (totalFrameCountOut) {
8362
0
        *totalFrameCountOut = 0;
8363
0
    }
8364
8365
0
    if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
8366
0
        return NULL;
8367
0
    }
8368
8369
0
    return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8370
0
}
8371
8372
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8373
0
{
8374
0
    drwav wav;
8375
8376
0
    if (channelsOut) {
8377
0
        *channelsOut = 0;
8378
0
    }
8379
0
    if (sampleRateOut) {
8380
0
        *sampleRateOut = 0;
8381
0
    }
8382
0
    if (totalFrameCountOut) {
8383
0
        *totalFrameCountOut = 0;
8384
0
    }
8385
8386
0
    if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
8387
0
        return NULL;
8388
0
    }
8389
8390
0
    return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8391
0
}
8392
8393
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8394
0
{
8395
0
    drwav wav;
8396
8397
0
    if (channelsOut) {
8398
0
        *channelsOut = 0;
8399
0
    }
8400
0
    if (sampleRateOut) {
8401
0
        *sampleRateOut = 0;
8402
0
    }
8403
0
    if (totalFrameCountOut) {
8404
0
        *totalFrameCountOut = 0;
8405
0
    }
8406
8407
0
    if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
8408
0
        return NULL;
8409
0
    }
8410
8411
0
    return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8412
0
}
8413
8414
#ifndef DR_WAV_NO_STDIO
8415
DRWAV_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)
8416
0
{
8417
0
    drwav wav;
8418
8419
0
    if (channelsOut) {
8420
0
        *channelsOut = 0;
8421
0
    }
8422
0
    if (sampleRateOut) {
8423
0
        *sampleRateOut = 0;
8424
0
    }
8425
0
    if (totalFrameCountOut) {
8426
0
        *totalFrameCountOut = 0;
8427
0
    }
8428
8429
0
    if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
8430
0
        return NULL;
8431
0
    }
8432
8433
0
    return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8434
0
}
8435
8436
DRWAV_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)
8437
0
{
8438
0
    drwav wav;
8439
8440
0
    if (channelsOut) {
8441
0
        *channelsOut = 0;
8442
0
    }
8443
0
    if (sampleRateOut) {
8444
0
        *sampleRateOut = 0;
8445
0
    }
8446
0
    if (totalFrameCountOut) {
8447
0
        *totalFrameCountOut = 0;
8448
0
    }
8449
8450
0
    if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
8451
0
        return NULL;
8452
0
    }
8453
8454
0
    return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8455
0
}
8456
8457
DRWAV_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)
8458
0
{
8459
0
    drwav wav;
8460
8461
0
    if (channelsOut) {
8462
0
        *channelsOut = 0;
8463
0
    }
8464
0
    if (sampleRateOut) {
8465
0
        *sampleRateOut = 0;
8466
0
    }
8467
0
    if (totalFrameCountOut) {
8468
0
        *totalFrameCountOut = 0;
8469
0
    }
8470
8471
0
    if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
8472
0
        return NULL;
8473
0
    }
8474
8475
0
    return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8476
0
}
8477
8478
8479
#ifndef DR_WAV_NO_WCHAR
8480
DRWAV_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)
8481
0
{
8482
0
    drwav wav;
8483
8484
0
    if (sampleRateOut) {
8485
0
        *sampleRateOut = 0;
8486
0
    }
8487
0
    if (channelsOut) {
8488
0
        *channelsOut = 0;
8489
0
    }
8490
0
    if (totalFrameCountOut) {
8491
0
        *totalFrameCountOut = 0;
8492
0
    }
8493
8494
0
    if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
8495
0
        return NULL;
8496
0
    }
8497
8498
0
    return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8499
0
}
8500
8501
DRWAV_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)
8502
0
{
8503
0
    drwav wav;
8504
8505
0
    if (sampleRateOut) {
8506
0
        *sampleRateOut = 0;
8507
0
    }
8508
0
    if (channelsOut) {
8509
0
        *channelsOut = 0;
8510
0
    }
8511
0
    if (totalFrameCountOut) {
8512
0
        *totalFrameCountOut = 0;
8513
0
    }
8514
8515
0
    if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
8516
0
        return NULL;
8517
0
    }
8518
8519
0
    return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8520
0
}
8521
8522
DRWAV_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)
8523
0
{
8524
0
    drwav wav;
8525
8526
0
    if (sampleRateOut) {
8527
0
        *sampleRateOut = 0;
8528
0
    }
8529
0
    if (channelsOut) {
8530
0
        *channelsOut = 0;
8531
0
    }
8532
0
    if (totalFrameCountOut) {
8533
0
        *totalFrameCountOut = 0;
8534
0
    }
8535
8536
0
    if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
8537
0
        return NULL;
8538
0
    }
8539
8540
0
    return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8541
0
}
8542
#endif /* DR_WAV_NO_WCHAR */
8543
#endif /* DR_WAV_NO_STDIO */
8544
8545
DRWAV_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)
8546
0
{
8547
0
    drwav wav;
8548
8549
0
    if (channelsOut) {
8550
0
        *channelsOut = 0;
8551
0
    }
8552
0
    if (sampleRateOut) {
8553
0
        *sampleRateOut = 0;
8554
0
    }
8555
0
    if (totalFrameCountOut) {
8556
0
        *totalFrameCountOut = 0;
8557
0
    }
8558
8559
0
    if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
8560
0
        return NULL;
8561
0
    }
8562
8563
0
    return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8564
0
}
8565
8566
DRWAV_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)
8567
0
{
8568
0
    drwav wav;
8569
8570
0
    if (channelsOut) {
8571
0
        *channelsOut = 0;
8572
0
    }
8573
0
    if (sampleRateOut) {
8574
0
        *sampleRateOut = 0;
8575
0
    }
8576
0
    if (totalFrameCountOut) {
8577
0
        *totalFrameCountOut = 0;
8578
0
    }
8579
8580
0
    if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
8581
0
        return NULL;
8582
0
    }
8583
8584
0
    return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8585
0
}
8586
8587
DRWAV_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)
8588
0
{
8589
0
    drwav wav;
8590
8591
0
    if (channelsOut) {
8592
0
        *channelsOut = 0;
8593
0
    }
8594
0
    if (sampleRateOut) {
8595
0
        *sampleRateOut = 0;
8596
0
    }
8597
0
    if (totalFrameCountOut) {
8598
0
        *totalFrameCountOut = 0;
8599
0
    }
8600
8601
0
    if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
8602
0
        return NULL;
8603
0
    }
8604
8605
0
    return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8606
0
}
8607
#endif  /* DR_WAV_NO_CONVERSION_API */
8608
8609
8610
DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
8611
2.20k
{
8612
2.20k
    if (pAllocationCallbacks != NULL) {
8613
2.20k
        drwav__free_from_callbacks(p, pAllocationCallbacks);
8614
2.20k
    } else {
8615
0
        drwav__free_default(p, NULL);
8616
0
    }
8617
2.20k
}
8618
8619
DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data)
8620
12.4k
{
8621
12.4k
    return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8);
8622
12.4k
}
8623
8624
DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data)
8625
11.1k
{
8626
11.1k
    return (drwav_int16)drwav_bytes_to_u16(data);
8627
11.1k
}
8628
8629
DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data)
8630
0
{
8631
0
    return drwav_bytes_to_u32_le(data);
8632
0
}
8633
8634
DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data)
8635
0
{
8636
0
    union {
8637
0
        drwav_uint32 u32;
8638
0
        float f32;
8639
0
    } value;
8640
8641
0
    value.u32 = drwav_bytes_to_u32(data);
8642
0
    return value.f32;
8643
0
}
8644
8645
DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data)
8646
0
{
8647
0
    return (drwav_int32)drwav_bytes_to_u32(data);
8648
0
}
8649
8650
DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data)
8651
1.41k
{
8652
1.41k
    return
8653
1.41k
        ((drwav_uint64)data[0] <<  0) | ((drwav_uint64)data[1] <<  8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
8654
1.41k
        ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
8655
1.41k
}
8656
8657
DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data)
8658
0
{
8659
0
    return (drwav_int64)drwav_bytes_to_u64(data);
8660
0
}
8661
8662
8663
DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
8664
30
{
8665
30
    int i;
8666
31
    for (i = 0; i < 16; i += 1) {
8667
31
        if (a[i] != b[i]) {
8668
30
            return DRWAV_FALSE;
8669
30
        }
8670
31
    }
8671
8672
0
    return DRWAV_TRUE;
8673
30
}
8674
8675
DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
8676
54.9k
{
8677
54.9k
    return
8678
54.9k
        a[0] == b[0] &&
8679
25.3k
        a[1] == b[1] &&
8680
20.3k
        a[2] == b[2] &&
8681
18.9k
        a[3] == b[3];
8682
54.9k
}
8683
8684
#ifdef __MRC__
8685
/* Undo the pragma at the beginning of this file. */
8686
#pragma options opt reset
8687
#endif
8688
8689
#endif  /* dr_wav_c */
8690
#endif  /* DR_WAV_IMPLEMENTATION */
8691
8692
/*
8693
REVISION HISTORY
8694
================
8695
v0.14.6 - TBD
8696
  - Encoders will now write out header information each write so that a valid file is still produced when an explicit `drwav_uninit()` is not called.
8697
  - Fix an error when loading files with a malformed "bext" chunk.
8698
  - Fix an error when loading files with a malformed "fmt" chunk.
8699
  - Fix an error when loading files with a malformed "fact" chunk.
8700
  - Fix an error when loading files with a malformed "smpl" chunk.
8701
  - Fix an underflow error with badly formed ADPCM encoded files.
8702
  - Fix an underflow error with badly formed W64 files.
8703
  - Fix an error when converting from >32 bit samples to s16/f32/s32 on big-endian architectures.
8704
  - Fix an error with conversion from u8, 16, alaw and mulaw to s32.
8705
  - Fix an error with AIFF files with an unusual bit depth.
8706
  - Fix some NaN conversion errors when converting from floating point to s16 and s32.
8707
  - Add some bound checking when processing metadata chunks.
8708
8709
v0.14.5 - 2026-03-03
8710
  - Fix a crash when loading files with a malformed "smpl" chunk.
8711
  - Fix a signed overflow bug with the MS-ADPCM decoder.
8712
8713
v0.14.4 - 2026-01-17
8714
  - Fix some compilation warnings.
8715
8716
v0.14.3 - 2025-12-14
8717
  - Fix a possible out-of-bounds read when reading from MS-ADPCM encoded files.
8718
  - Fix a possible integer overflow error.
8719
8720
v0.14.2 - 2025-12-02
8721
  - Fix a compilation warning.
8722
8723
v0.14.1 - 2025-09-10
8724
  - Fix an error with the NXDK build.
8725
8726
v0.14.0 - 2025-07-23
8727
  - API CHANGE: Seek origin enums have been renamed to the following:
8728
    - drwav_seek_origin_start   -> DRWAV_SEEK_SET
8729
    - drwav_seek_origin_current -> DRWAV_SEEK_CUR
8730
    - DRWAV_SEEK_END (new)
8731
  - API CHANGE: A new seek origin has been added to allow seeking from the end of the file. If you implement your own `onSeek` callback, you must now handle `DRWAV_SEEK_END`. If you only use `*_init_file()` or `*_init_memory()`, you need not change anything.
8732
  - API CHANGE: An `onTell` callback has been added to the following functions:
8733
    - drwav_init()
8734
    - drwav_init_ex()
8735
    - drwav_init_with_metadata()
8736
    - drwav_open_and_read_pcm_frames_s16()
8737
    - drwav_open_and_read_pcm_frames_f32()
8738
    - drwav_open_and_read_pcm_frames_s32()
8739
  - API CHANGE: The `firstSampleByteOffset`, `lastSampleByteOffset` and `sampleByteOffset` members of `drwav_cue_point` have been renamed to `firstSampleOffset`, `lastSampleOffset` and `sampleOffset`, respectively.
8740
  - Fix a static analysis warning.
8741
  - Fix compilation for AIX OS.
8742
8743
v0.13.17 - 2024-12-17
8744
  - Fix a possible crash when reading from MS-ADPCM encoded files.
8745
  - Improve detection of ARM64EC
8746
8747
v0.13.16 - 2024-02-27
8748
  - Fix a Wdouble-promotion warning.
8749
8750
v0.13.15 - 2024-01-23
8751
  - Relax some unnecessary validation that prevented some files from loading.
8752
8753
v0.13.14 - 2023-12-02
8754
  - Fix a warning about an unused variable.
8755
8756
v0.13.13 - 2023-11-02
8757
  - Fix a warning when compiling with Clang.
8758
8759
v0.13.12 - 2023-08-07
8760
  - Fix a possible crash in drwav_read_pcm_frames().
8761
8762
v0.13.11 - 2023-07-07
8763
  - AIFF compatibility improvements.
8764
8765
v0.13.10 - 2023-05-29
8766
  - Fix a bug where drwav_init_with_metadata() does not decode any frames after initializtion.
8767
8768
v0.13.9 - 2023-05-22
8769
  - Add support for AIFF decoding (writing and metadata not supported).
8770
  - Add support for RIFX decoding (writing and metadata not supported).
8771
  - Fix a bug where metadata is not processed if it's located before the "fmt " chunk.
8772
  - Add a workaround for a type of malformed WAV file where the size of the "RIFF" and "data" chunks
8773
    are incorrectly set to 0xFFFFFFFF.
8774
8775
v0.13.8 - 2023-03-25
8776
  - Fix a possible null pointer dereference.
8777
  - Fix a crash when loading files with badly formed metadata.
8778
8779
v0.13.7 - 2022-09-17
8780
  - Fix compilation with DJGPP.
8781
  - Add support for disabling wchar_t with DR_WAV_NO_WCHAR.
8782
8783
v0.13.6 - 2022-04-10
8784
  - Fix compilation error on older versions of GCC.
8785
  - Remove some dependencies on the standard library.
8786
8787
v0.13.5 - 2022-01-26
8788
  - Fix an error when seeking to the end of the file.
8789
8790
v0.13.4 - 2021-12-08
8791
  - Fix some static analysis warnings.
8792
8793
v0.13.3 - 2021-11-24
8794
  - Fix an incorrect assertion when trying to endian swap 1-byte sample formats. This is now a no-op
8795
    rather than a failed assertion.
8796
  - Fix a bug with parsing of the bext chunk.
8797
  - Fix some static analysis warnings.
8798
8799
v0.13.2 - 2021-10-02
8800
  - Fix a possible buffer overflow when reading from compressed formats.
8801
8802
v0.13.1 - 2021-07-31
8803
  - Fix platform detection for ARM64.
8804
8805
v0.13.0 - 2021-07-01
8806
  - Improve support for reading and writing metadata. Use the `_with_metadata()` APIs to initialize
8807
    a WAV decoder and store the metadata within the `drwav` object. Use the `pMetadata` and
8808
    `metadataCount` members of the `drwav` object to read the data. The old way of handling metadata
8809
    via a callback is still usable and valid.
8810
  - API CHANGE: drwav_target_write_size_bytes() now takes extra parameters for calculating the
8811
    required write size when writing metadata.
8812
  - Add drwav_get_cursor_in_pcm_frames()
8813
  - Add drwav_get_length_in_pcm_frames()
8814
  - Fix a bug where drwav_read_raw() can call the read callback with a byte count of zero.
8815
8816
v0.12.20 - 2021-06-11
8817
  - Fix some undefined behavior.
8818
8819
v0.12.19 - 2021-02-21
8820
  - Fix a warning due to referencing _MSC_VER when it is undefined.
8821
  - Minor improvements to the management of some internal state concerning the data chunk cursor.
8822
8823
v0.12.18 - 2021-01-31
8824
  - Clean up some static analysis warnings.
8825
8826
v0.12.17 - 2021-01-17
8827
  - Minor fix to sample code in documentation.
8828
  - Correctly qualify a private API as private rather than public.
8829
  - Code cleanup.
8830
8831
v0.12.16 - 2020-12-02
8832
  - Fix a bug when trying to read more bytes than can fit in a size_t.
8833
8834
v0.12.15 - 2020-11-21
8835
  - Fix compilation with OpenWatcom.
8836
8837
v0.12.14 - 2020-11-13
8838
  - Minor code clean up.
8839
8840
v0.12.13 - 2020-11-01
8841
  - Improve compiler support for older versions of GCC.
8842
8843
v0.12.12 - 2020-09-28
8844
  - Add support for RF64.
8845
  - Fix a bug in writing mode where the size of the RIFF chunk incorrectly includes the header section.
8846
8847
v0.12.11 - 2020-09-08
8848
  - Fix a compilation error on older compilers.
8849
8850
v0.12.10 - 2020-08-24
8851
  - Fix a bug when seeking with ADPCM formats.
8852
8853
v0.12.9 - 2020-08-02
8854
  - Simplify sized types.
8855
8856
v0.12.8 - 2020-07-25
8857
  - Fix a compilation warning.
8858
8859
v0.12.7 - 2020-07-15
8860
  - Fix some bugs on big-endian architectures.
8861
  - Fix an error in s24 to f32 conversion.
8862
8863
v0.12.6 - 2020-06-23
8864
  - Change drwav_read_*() to allow NULL to be passed in as the output buffer which is equivalent to a forward seek.
8865
  - Fix a buffer overflow when trying to decode invalid IMA-ADPCM files.
8866
  - Add include guard for the implementation section.
8867
8868
v0.12.5 - 2020-05-27
8869
  - Minor documentation fix.
8870
8871
v0.12.4 - 2020-05-16
8872
  - Replace assert() with DRWAV_ASSERT().
8873
  - Add compile-time and run-time version querying.
8874
    - DRWAV_VERSION_MINOR
8875
    - DRWAV_VERSION_MAJOR
8876
    - DRWAV_VERSION_REVISION
8877
    - DRWAV_VERSION_STRING
8878
    - drwav_version()
8879
    - drwav_version_string()
8880
8881
v0.12.3 - 2020-04-30
8882
  - Fix compilation errors with VC6.
8883
8884
v0.12.2 - 2020-04-21
8885
  - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file.
8886
8887
v0.12.1 - 2020-04-13
8888
  - Fix some pedantic warnings.
8889
8890
v0.12.0 - 2020-04-04
8891
  - API CHANGE: Add container and format parameters to the chunk callback.
8892
  - Minor documentation updates.
8893
8894
v0.11.5 - 2020-03-07
8895
  - Fix compilation error with Visual Studio .NET 2003.
8896
8897
v0.11.4 - 2020-01-29
8898
  - Fix some static analysis warnings.
8899
  - Fix a bug when reading f32 samples from an A-law encoded stream.
8900
8901
v0.11.3 - 2020-01-12
8902
  - Minor changes to some f32 format conversion routines.
8903
  - Minor bug fix for ADPCM conversion when end of file is reached.
8904
8905
v0.11.2 - 2019-12-02
8906
  - Fix a possible crash when using custom memory allocators without a custom realloc() implementation.
8907
  - Fix an integer overflow bug.
8908
  - Fix a null pointer dereference bug.
8909
  - Add limits to sample rate, channels and bits per sample to tighten up some validation.
8910
8911
v0.11.1 - 2019-10-07
8912
  - Internal code clean up.
8913
8914
v0.11.0 - 2019-10-06
8915
  - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
8916
    routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
8917
    - drwav_init()
8918
    - drwav_init_ex()
8919
    - drwav_init_file()
8920
    - drwav_init_file_ex()
8921
    - drwav_init_file_w()
8922
    - drwav_init_file_w_ex()
8923
    - drwav_init_memory()
8924
    - drwav_init_memory_ex()
8925
    - drwav_init_write()
8926
    - drwav_init_write_sequential()
8927
    - drwav_init_write_sequential_pcm_frames()
8928
    - drwav_init_file_write()
8929
    - drwav_init_file_write_sequential()
8930
    - drwav_init_file_write_sequential_pcm_frames()
8931
    - drwav_init_file_write_w()
8932
    - drwav_init_file_write_sequential_w()
8933
    - drwav_init_file_write_sequential_pcm_frames_w()
8934
    - drwav_init_memory_write()
8935
    - drwav_init_memory_write_sequential()
8936
    - drwav_init_memory_write_sequential_pcm_frames()
8937
    - drwav_open_and_read_pcm_frames_s16()
8938
    - drwav_open_and_read_pcm_frames_f32()
8939
    - drwav_open_and_read_pcm_frames_s32()
8940
    - drwav_open_file_and_read_pcm_frames_s16()
8941
    - drwav_open_file_and_read_pcm_frames_f32()
8942
    - drwav_open_file_and_read_pcm_frames_s32()
8943
    - drwav_open_file_and_read_pcm_frames_s16_w()
8944
    - drwav_open_file_and_read_pcm_frames_f32_w()
8945
    - drwav_open_file_and_read_pcm_frames_s32_w()
8946
    - drwav_open_memory_and_read_pcm_frames_s16()
8947
    - drwav_open_memory_and_read_pcm_frames_f32()
8948
    - drwav_open_memory_and_read_pcm_frames_s32()
8949
    Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use
8950
    DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE.
8951
  - Add support for reading and writing PCM frames in an explicit endianness. New APIs:
8952
    - drwav_read_pcm_frames_le()
8953
    - drwav_read_pcm_frames_be()
8954
    - drwav_read_pcm_frames_s16le()
8955
    - drwav_read_pcm_frames_s16be()
8956
    - drwav_read_pcm_frames_f32le()
8957
    - drwav_read_pcm_frames_f32be()
8958
    - drwav_read_pcm_frames_s32le()
8959
    - drwav_read_pcm_frames_s32be()
8960
    - drwav_write_pcm_frames_le()
8961
    - drwav_write_pcm_frames_be()
8962
  - Remove deprecated APIs.
8963
  - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data.
8964
    - drwav_read_pcm_frames()
8965
    - drwav_read_pcm_frames_s16()
8966
    - drwav_read_pcm_frames_s32()
8967
    - drwav_read_pcm_frames_f32()
8968
    - drwav_open_and_read_pcm_frames_s16()
8969
    - drwav_open_and_read_pcm_frames_s32()
8970
    - drwav_open_and_read_pcm_frames_f32()
8971
    - drwav_open_file_and_read_pcm_frames_s16()
8972
    - drwav_open_file_and_read_pcm_frames_s32()
8973
    - drwav_open_file_and_read_pcm_frames_f32()
8974
    - drwav_open_file_and_read_pcm_frames_s16_w()
8975
    - drwav_open_file_and_read_pcm_frames_s32_w()
8976
    - drwav_open_file_and_read_pcm_frames_f32_w()
8977
    - drwav_open_memory_and_read_pcm_frames_s16()
8978
    - drwav_open_memory_and_read_pcm_frames_s32()
8979
    - drwav_open_memory_and_read_pcm_frames_f32()
8980
8981
v0.10.1 - 2019-08-31
8982
  - Correctly handle partial trailing ADPCM blocks.
8983
8984
v0.10.0 - 2019-08-04
8985
  - Remove deprecated APIs.
8986
  - Add wchar_t variants for file loading APIs:
8987
      drwav_init_file_w()
8988
      drwav_init_file_ex_w()
8989
      drwav_init_file_write_w()
8990
      drwav_init_file_write_sequential_w()
8991
  - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count.
8992
  - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode:
8993
      drwav_init_write_sequential_pcm_frames()
8994
      drwav_init_file_write_sequential_pcm_frames()
8995
      drwav_init_file_write_sequential_pcm_frames_w()
8996
      drwav_init_memory_write_sequential_pcm_frames()
8997
  - Deprecate drwav_open*() and drwav_close():
8998
      drwav_open()
8999
      drwav_open_ex()
9000
      drwav_open_write()
9001
      drwav_open_write_sequential()
9002
      drwav_open_file()
9003
      drwav_open_file_ex()
9004
      drwav_open_file_write()
9005
      drwav_open_file_write_sequential()
9006
      drwav_open_memory()
9007
      drwav_open_memory_ex()
9008
      drwav_open_memory_write()
9009
      drwav_open_memory_write_sequential()
9010
      drwav_close()
9011
  - Minor documentation updates.
9012
9013
v0.9.2 - 2019-05-21
9014
  - Fix warnings.
9015
9016
v0.9.1 - 2019-05-05
9017
  - Add support for C89.
9018
  - Change license to choice of public domain or MIT-0.
9019
9020
v0.9.0 - 2018-12-16
9021
  - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and
9022
    will be removed in v0.10.0. Deprecated APIs and their replacements:
9023
      drwav_read()                     -> drwav_read_pcm_frames()
9024
      drwav_read_s16()                 -> drwav_read_pcm_frames_s16()
9025
      drwav_read_f32()                 -> drwav_read_pcm_frames_f32()
9026
      drwav_read_s32()                 -> drwav_read_pcm_frames_s32()
9027
      drwav_seek_to_sample()           -> drwav_seek_to_pcm_frame()
9028
      drwav_write()                    -> drwav_write_pcm_frames()
9029
      drwav_open_and_read_s16()        -> drwav_open_and_read_pcm_frames_s16()
9030
      drwav_open_and_read_f32()        -> drwav_open_and_read_pcm_frames_f32()
9031
      drwav_open_and_read_s32()        -> drwav_open_and_read_pcm_frames_s32()
9032
      drwav_open_file_and_read_s16()   -> drwav_open_file_and_read_pcm_frames_s16()
9033
      drwav_open_file_and_read_f32()   -> drwav_open_file_and_read_pcm_frames_f32()
9034
      drwav_open_file_and_read_s32()   -> drwav_open_file_and_read_pcm_frames_s32()
9035
      drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16()
9036
      drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32()
9037
      drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32()
9038
      drwav::totalSampleCount          -> drwav::totalPCMFrameCount
9039
  - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*().
9040
  - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*().
9041
  - Add built-in support for smpl chunks.
9042
  - Add support for firing a callback for each chunk in the file at initialization time.
9043
    - This is enabled through the drwav_init_ex(), etc. family of APIs.
9044
  - Handle invalid FMT chunks more robustly.
9045
9046
v0.8.5 - 2018-09-11
9047
  - Const correctness.
9048
  - Fix a potential stack overflow.
9049
9050
v0.8.4 - 2018-08-07
9051
  - Improve 64-bit detection.
9052
9053
v0.8.3 - 2018-08-05
9054
  - Fix C++ build on older versions of GCC.
9055
9056
v0.8.2 - 2018-08-02
9057
  - Fix some big-endian bugs.
9058
9059
v0.8.1 - 2018-06-29
9060
  - Add support for sequential writing APIs.
9061
  - Disable seeking in write mode.
9062
  - Fix bugs with Wave64.
9063
  - Fix typos.
9064
9065
v0.8 - 2018-04-27
9066
  - Bug fix.
9067
  - Start using major.minor.revision versioning.
9068
9069
v0.7f - 2018-02-05
9070
  - Restrict ADPCM formats to a maximum of 2 channels.
9071
9072
v0.7e - 2018-02-02
9073
  - Fix a crash.
9074
9075
v0.7d - 2018-02-01
9076
  - Fix a crash.
9077
9078
v0.7c - 2018-02-01
9079
  - Set drwav.bytesPerSample to 0 for all compressed formats.
9080
  - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for
9081
    all format conversion reading APIs (*_s16, *_s32, *_f32 APIs).
9082
  - Fix some divide-by-zero errors.
9083
9084
v0.7b - 2018-01-22
9085
  - Fix errors with seeking of compressed formats.
9086
  - Fix compilation error when DR_WAV_NO_CONVERSION_API
9087
9088
v0.7a - 2017-11-17
9089
  - Fix some GCC warnings.
9090
9091
v0.7 - 2017-11-04
9092
  - Add writing APIs.
9093
9094
v0.6 - 2017-08-16
9095
  - API CHANGE: Rename dr_* types to drwav_*.
9096
  - Add support for custom implementations of malloc(), realloc(), etc.
9097
  - Add support for Microsoft ADPCM.
9098
  - Add support for IMA ADPCM (DVI, format code 0x11).
9099
  - Optimizations to drwav_read_s16().
9100
  - Bug fixes.
9101
9102
v0.5g - 2017-07-16
9103
  - Change underlying type for booleans to unsigned.
9104
9105
v0.5f - 2017-04-04
9106
  - Fix a minor bug with drwav_open_and_read_s16() and family.
9107
9108
v0.5e - 2016-12-29
9109
  - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this.
9110
  - Minor fixes to documentation.
9111
9112
v0.5d - 2016-12-28
9113
  - Use drwav_int* and drwav_uint* sized types to improve compiler support.
9114
9115
v0.5c - 2016-11-11
9116
  - Properly handle JUNK chunks that come before the FMT chunk.
9117
9118
v0.5b - 2016-10-23
9119
  - A minor change to drwav_bool8 and drwav_bool32 types.
9120
9121
v0.5a - 2016-10-11
9122
  - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering.
9123
  - Improve A-law and mu-law efficiency.
9124
9125
v0.5 - 2016-09-29
9126
  - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to
9127
    keep it consistent with dr_audio and dr_flac.
9128
9129
v0.4b - 2016-09-18
9130
  - Fixed a typo in documentation.
9131
9132
v0.4a - 2016-09-18
9133
  - Fixed a typo.
9134
  - Change date format to ISO 8601 (YYYY-MM-DD)
9135
9136
v0.4 - 2016-07-13
9137
  - API CHANGE. Make onSeek consistent with dr_flac.
9138
  - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac.
9139
  - Added support for Sony Wave64.
9140
9141
v0.3a - 2016-05-28
9142
  - API CHANGE. Return drwav_bool32 instead of int in onSeek callback.
9143
  - Fixed a memory leak.
9144
9145
v0.3 - 2016-05-22
9146
  - Lots of API changes for consistency.
9147
9148
v0.2a - 2016-05-16
9149
  - Fixed Linux/GCC build.
9150
9151
v0.2 - 2016-05-11
9152
  - Added support for reading data as signed 32-bit PCM for consistency with dr_flac.
9153
9154
v0.1a - 2016-05-07
9155
  - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize.
9156
9157
v0.1 - 2016-05-04
9158
  - Initial versioned release.
9159
*/
9160
9161
/*
9162
This software is available as a choice of the following licenses. Choose
9163
whichever you prefer.
9164
9165
===============================================================================
9166
ALTERNATIVE 1 - Public Domain (www.unlicense.org)
9167
===============================================================================
9168
This is free and unencumbered software released into the public domain.
9169
9170
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
9171
software, either in source code form or as a compiled binary, for any purpose,
9172
commercial or non-commercial, and by any means.
9173
9174
In jurisdictions that recognize copyright laws, the author or authors of this
9175
software dedicate any and all copyright interest in the software to the public
9176
domain. We make this dedication for the benefit of the public at large and to
9177
the detriment of our heirs and successors. We intend this dedication to be an
9178
overt act of relinquishment in perpetuity of all present and future rights to
9179
this software under copyright law.
9180
9181
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9182
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9183
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
9184
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
9185
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
9186
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9187
9188
For more information, please refer to <http://unlicense.org/>
9189
9190
===============================================================================
9191
ALTERNATIVE 2 - MIT No Attribution
9192
===============================================================================
9193
Copyright 2023 David Reid
9194
9195
Permission is hereby granted, free of charge, to any person obtaining a copy of
9196
this software and associated documentation files (the "Software"), to deal in
9197
the Software without restriction, including without limitation the rights to
9198
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9199
of the Software, and to permit persons to whom the Software is furnished to do
9200
so.
9201
9202
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9203
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9204
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
9205
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9206
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9207
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
9208
SOFTWARE.
9209
*/