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