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