Logo

index : raylib-jai

---

  • summary
  • about
  • tree
  • log
  • branches
<< path: root/public/raylib-jai.git/html/Raylib/raylib/src/external/dr_wav.h blob: 7a7e02246704ef8c8a9dc2945de842f47a526347 [raw] [clear marker]

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