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

source code of qtmultimedia/src/3rdparty/dr_libs/dr_wav.h