Cleanup
[carla.git] / source / modules / ysfx / thirdparty / dr_libs / dr_wav.h
blobfed528fb78c7771337919ea2ce5657864265d238
1 /*
2 WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
3 dr_wav - v0.13.2 - 2021-10-02
5 David Reid - mackron@gmail.com
7 GitHub: https://github.com/mackron/dr_libs
8 */
11 Introduction
12 ============
13 This is a single file library. To use it, do something like the following in one .c file.
15 ```c
16 #define DR_WAV_IMPLEMENTATION
17 #include "dr_wav.h"
18 ```
20 You can then #include this file in other parts of the program as you would with any other header file. Do something like the following to read audio data:
22 ```c
23 drwav wav;
24 if (!drwav_init_file(&wav, "my_song.wav", NULL)) {
25 // Error opening WAV file.
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);
31 ...
33 drwav_uninit(&wav);
34 ```
36 If you just want to quickly open and read the audio data in a single operation you can do something like this:
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.
47 ...
49 drwav_free(pSampleData, NULL);
50 ```
52 The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in this case), but you can still output the
53 audio data in its internal format (see notes below for supported formats):
55 ```c
56 size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
57 ```
59 You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for a particular data format:
61 ```c
62 size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer);
63 ```
65 dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at `drwav_init_write()`,
66 `drwav_init_file_write()`, etc. Use `drwav_write_pcm_frames()` to write samples, or `drwav_write_raw()` to write raw data in the "data" chunk.
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);
77 ...
79 drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples);
80 ```
82 dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work without any manual intervention.
85 Build Options
86 =============
87 #define these options before including this file.
89 #define DR_WAV_NO_CONVERSION_API
90 Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`.
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.
97 Notes
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.
116 #ifndef dr_wav_h
117 #define dr_wav_h
119 #ifdef __cplusplus
120 extern "C" {
121 #endif
123 #define DRWAV_STRINGIFY(x) #x
124 #define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
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)
131 #include <stddef.h> /* For size_t. */
133 /* Sized types. */
134 typedef signed char drwav_int8;
135 typedef unsigned char drwav_uint8;
136 typedef signed short drwav_int16;
137 typedef unsigned short drwav_uint16;
138 typedef signed int drwav_int32;
139 typedef 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__)
158 typedef drwav_uint64 drwav_uintptr;
159 #else
160 typedef drwav_uint32 drwav_uintptr;
161 #endif
162 typedef drwav_uint8 drwav_bool8;
163 typedef drwav_uint32 drwav_bool32;
164 #define DRWAV_TRUE 1
165 #define DRWAV_FALSE 0
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
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
197 typedef drwav_int32 drwav_result;
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
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
262 /* Flags to pass into drwav_init_ex(), etc. */
263 #define DRWAV_SEQUENTIAL 0x00000001
265 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
266 DRWAV_API const char* drwav_version_string(void);
268 typedef enum
270 drwav_seek_origin_start,
271 drwav_seek_origin_current
272 } drwav_seek_origin;
274 typedef enum
276 drwav_container_riff,
277 drwav_container_w64,
278 drwav_container_rf64
279 } drwav_container;
281 typedef struct
283 union
285 drwav_uint8 fourcc[4];
286 drwav_uint8 guid[16];
287 } id;
289 /* The size in bytes of the chunk. */
290 drwav_uint64 sizeInBytes;
293 RIFF = 2 byte alignment.
294 W64 = 8 byte alignment.
296 unsigned int paddingSize;
297 } drwav_chunk_header;
299 typedef struct
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.
305 drwav_uint16 formatTag;
307 /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */
308 drwav_uint16 channels;
310 /* The sample rate. Usually set to something like 44100. */
311 drwav_uint32 sampleRate;
313 /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */
314 drwav_uint32 avgBytesPerSec;
316 /* Block align. This is equal to the number of channels * bytes per sample. */
317 drwav_uint16 blockAlign;
319 /* Bits per sample. */
320 drwav_uint16 bitsPerSample;
322 /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */
323 drwav_uint16 extendedSize;
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.
330 drwav_uint16 validBitsPerSample;
332 /* The channel mask. Not used at the moment. */
333 drwav_uint32 channelMask;
335 /* The sub-format, exactly as specified by the wave file. */
336 drwav_uint8 subFormat[16];
337 } drwav_fmt;
339 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
343 Callback for when data is read. Return value is the number of bytes actually read.
345 pUserData [in] The user data that was passed to drwav_init() and family.
346 pBufferOut [out] The output buffer.
347 bytesToRead [in] The number of bytes to read.
349 Returns the number of bytes actually read.
351 A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until
352 either the entire bytesToRead is filled or you have reached the end of the stream.
354 typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
357 Callback for when data is written. Returns value is the number of bytes actually written.
359 pUserData [in] The user data that was passed to drwav_init_write() and family.
360 pData [out] A pointer to the data to write.
361 bytesToWrite [in] The number of bytes to write.
363 Returns the number of bytes actually written.
365 If the return value differs from bytesToWrite, it indicates an error.
367 typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
370 Callback for when data needs to be seeked.
372 pUserData [in] The user data that was passed to drwav_init() and family.
373 offset [in] The number of bytes to move, relative to the origin. Will never be negative.
374 origin [in] The origin of the seek - the current position or the start of the stream.
376 Returns whether or not the seek was successful.
378 Whether 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
379 drwav_seek_origin_current.
381 typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
384 Callback for when drwav_init_ex() finds a chunk.
386 pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family.
387 onRead [in] A pointer to the function to call when reading.
388 onSeek [in] A pointer to the function to call when seeking.
389 pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family.
390 pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk.
391 container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF.
392 pFMT [in] A pointer to the object containing the contents of the "fmt" chunk.
394 Returns the number of bytes read + seeked.
396 To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same for seeking with onSeek(). The return value must
397 be the total number of bytes you have read _plus_ seeked.
399 Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should
400 use `id.fourcc`, otherwise you should use `id.guid`.
402 The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the
403 `DR_WAVE_FORMAT_*` identifiers.
405 The read pointer will be sitting on the first byte after the chunk's header. You must not attempt to read beyond the boundary of the chunk.
407 typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT);
409 typedef struct
411 void* pUserData;
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);
415 } drwav_allocation_callbacks;
417 /* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */
418 typedef struct
420 const drwav_uint8* data;
421 size_t dataSize;
422 size_t currentReadPos;
423 } drwav__memory_stream;
425 /* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */
426 typedef struct
428 void** ppData;
429 size_t* pDataSize;
430 size_t dataSize;
431 size_t dataCapacity;
432 size_t currentWritePos;
433 } drwav__memory_stream_write;
435 typedef struct
437 drwav_container container; /* RIFF, W64. */
438 drwav_uint32 format; /* DR_WAVE_FORMAT_* */
439 drwav_uint32 channels;
440 drwav_uint32 sampleRate;
441 drwav_uint32 bitsPerSample;
442 } drwav_data_format;
444 typedef enum
446 drwav_metadata_type_none = 0,
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.
455 drwav_metadata_type_unknown = 1 << 0,
457 /* Only 1 of each of these metadata items are allowed in a wav file. */
458 drwav_metadata_type_smpl = 1 << 1,
459 drwav_metadata_type_inst = 1 << 2,
460 drwav_metadata_type_cue = 1 << 3,
461 drwav_metadata_type_acid = 1 << 4,
462 drwav_metadata_type_bext = 1 << 5,
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.
469 There can be multiple of these metadata items in a wav file.
471 drwav_metadata_type_list_label = 1 << 6,
472 drwav_metadata_type_list_note = 1 << 7,
473 drwav_metadata_type_list_labelled_cue_region = 1 << 8,
475 drwav_metadata_type_list_info_software = 1 << 9,
476 drwav_metadata_type_list_info_copyright = 1 << 10,
477 drwav_metadata_type_list_info_title = 1 << 11,
478 drwav_metadata_type_list_info_artist = 1 << 12,
479 drwav_metadata_type_list_info_comment = 1 << 13,
480 drwav_metadata_type_list_info_date = 1 << 14,
481 drwav_metadata_type_list_info_genre = 1 << 15,
482 drwav_metadata_type_list_info_album = 1 << 16,
483 drwav_metadata_type_list_info_tracknumber = 1 << 17,
485 /* Other type constants for convenience. */
486 drwav_metadata_type_list_all_info_strings = drwav_metadata_type_list_info_software
487 | drwav_metadata_type_list_info_copyright
488 | drwav_metadata_type_list_info_title
489 | drwav_metadata_type_list_info_artist
490 | drwav_metadata_type_list_info_comment
491 | drwav_metadata_type_list_info_date
492 | drwav_metadata_type_list_info_genre
493 | drwav_metadata_type_list_info_album
494 | drwav_metadata_type_list_info_tracknumber,
496 drwav_metadata_type_list_all_adtl = drwav_metadata_type_list_label
497 | drwav_metadata_type_list_note
498 | drwav_metadata_type_list_labelled_cue_region,
500 drwav_metadata_type_all = -2, /*0xFFFFFFFF & ~drwav_metadata_type_unknown,*/
501 drwav_metadata_type_all_including_unknown = -1 /*0xFFFFFFFF,*/
502 } drwav_metadata_type;
505 Sampler Metadata
507 The sampler chunk contains information about how a sound should be played in the context of a whole
508 audio production, and when used in a sampler. See https://en.wikipedia.org/wiki/Sample-based_synthesis.
510 typedef enum
512 drwav_smpl_loop_type_forward = 0,
513 drwav_smpl_loop_type_pingpong = 1,
514 drwav_smpl_loop_type_backward = 2
515 } drwav_smpl_loop_type;
517 typedef struct
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. */
520 drwav_uint32 cuePointId;
522 /* See drwav_smpl_loop_type. */
523 drwav_uint32 type;
525 /* The byte offset of the first sample to be played in the loop. */
526 drwav_uint32 firstSampleByteOffset;
528 /* The byte offset into the audio data of the last sample to be played in the loop. */
529 drwav_uint32 lastSampleByteOffset;
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. */
532 drwav_uint32 sampleFraction;
534 /* Number of times to play the loop. 0 means loop infinitely. */
535 drwav_uint32 playCount;
536 } drwav_smpl_loop;
538 typedef struct
540 /* IDs for a particular MIDI manufacturer. 0 if not used. */
541 drwav_uint32 manufacturerId;
542 drwav_uint32 productId;
544 /* The period of 1 sample in nanoseconds. */
545 drwav_uint32 samplePeriodNanoseconds;
547 /* The MIDI root note of this file. 0 to 127. */
548 drwav_uint32 midiUnityNote;
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). */
551 drwav_uint32 midiPitchFraction;
553 /* Data relating to SMPTE standards which are used for syncing audio and video. 0 if not used. */
554 drwav_uint32 smpteFormat;
555 drwav_uint32 smpteOffset;
557 /* drwav_smpl_loop loops. */
558 drwav_uint32 sampleLoopCount;
560 /* Optional sampler-specific data. */
561 drwav_uint32 samplerSpecificDataSizeInBytes;
563 drwav_smpl_loop* pLoops;
564 drwav_uint8* pSamplerSpecificData;
565 } drwav_smpl;
568 Instrument Metadata
570 The inst metadata contains data about how a sound should be played as part of an instrument. This
571 commonly read by samplers. See https://en.wikipedia.org/wiki/Sample-based_synthesis.
573 typedef struct
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;
585 Cue Metadata
587 Cue points are markers at specific points in the audio. They often come with an associated piece of
588 drwav_list_label_or_note metadata which contains the text for the marker.
590 typedef struct
592 /* Unique identification value. */
593 drwav_uint32 id;
595 /* Set to 0. This is only relevant if there is a 'playlist' chunk - which is not supported by dr_wav. */
596 drwav_uint32 playOrderPosition;
598 /* Should always be "data". This represents the fourcc value of the chunk that this cue point corresponds to. dr_wav only supports a single data chunk so this should always be "data". */
599 drwav_uint8 dataChunkId[4];
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. */
602 drwav_uint32 chunkStart;
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. */
605 drwav_uint32 blockStart;
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. */
608 drwav_uint32 sampleByteOffset;
609 } drwav_cue_point;
611 typedef struct
613 drwav_uint32 cuePointCount;
614 drwav_cue_point *pCuePoints;
615 } drwav_cue;
618 Acid Metadata
620 This chunk contains some information about the time signature and the tempo of the audio.
622 typedef enum
624 drwav_acid_flag_one_shot = 1, /* If this is not set, then it is a loop instead of a one-shot. */
625 drwav_acid_flag_root_note_set = 2,
626 drwav_acid_flag_stretch = 4,
627 drwav_acid_flag_disk_based = 8,
628 drwav_acid_flag_acidizer = 16 /* Not sure what this means. */
629 } drwav_acid_flag;
631 typedef struct
633 /* A bit-field, see drwav_acid_flag. */
634 drwav_uint32 flags;
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. */
637 drwav_uint16 midiUnityNote;
639 /* Reserved values that should probably be ignored. reserved1 seems to often be 128 and reserved2 is 0. */
640 drwav_uint16 reserved1;
641 float reserved2;
643 /* Number of beats. */
644 drwav_uint32 numBeats;
646 /* The time signature of the audio. */
647 drwav_uint16 meterDenominator;
648 drwav_uint16 meterNumerator;
650 /* Beats per minute of the track. Setting a value of 0 suggests that there is no tempo. */
651 float tempo;
652 } drwav_acid;
655 Cue Label or Note metadata
657 These are 2 different types of metadata, but they have the exact same format. Labels tend to be the
658 more common and represent a short name for a cue point. Notes might be used to represent a longer
659 comment.
661 typedef struct
663 /* The ID of a cue point that this label or note corresponds to. */
664 drwav_uint32 cuePointId;
666 /* Size of the string not including any null terminator. */
667 drwav_uint32 stringLength;
669 /* The string. The *init_with_metadata functions null terminate this for convenience. */
670 char* pString;
671 } drwav_list_label_or_note;
674 BEXT metadata, also known as Broadcast Wave Format (BWF)
676 This metadata adds some extra description to an audio file. You must check the version field to
677 determine if the UMID or the loudness fields are valid.
679 typedef struct
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.
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. */
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.
698 char* pCodingHistory;
699 drwav_uint32 codingHistorySize;
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 */
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;
713 Info Text Metadata
715 There a many different types of information text that can be saved in this format. This is where
716 things like the album name, the artists, the year it was produced, etc are saved. See
717 drwav_metadata_type for the full list of types that dr_wav supports.
719 typedef struct
721 /* Size of the string not including any null terminator. */
722 drwav_uint32 stringLength;
724 /* The string. The *init_with_metadata functions null terminate this for convenience. */
725 char* pString;
726 } drwav_list_info_text;
729 Labelled Cue Region Metadata
731 The labelled cue region metadata is used to associate some region of audio with text. The region
732 starts at a cue point, and extends for the given number of samples.
734 typedef struct
736 /* The ID of a cue point that this object corresponds to. */
737 drwav_uint32 cuePointId;
739 /* The number of samples from the cue point forwards that should be considered this region */
740 drwav_uint32 sampleLength;
742 /* Four characters used to say what the purpose of this region is. */
743 drwav_uint8 purposeId[4];
745 /* Unsure of the exact meanings of these. It appears to be acceptable to set them all to 0. */
746 drwav_uint16 country;
747 drwav_uint16 language;
748 drwav_uint16 dialect;
749 drwav_uint16 codePage;
751 /* Size of the string not including any null terminator. */
752 drwav_uint32 stringLength;
754 /* The string. The *init_with_metadata functions null terminate this for convenience. */
755 char* pString;
756 } drwav_list_labelled_cue_region;
759 Unknown Metadata
761 This chunk just represents a type of chunk that dr_wav does not understand.
763 Unknown metadata has a location attached to it. This is because wav files can have a LIST chunk
764 that contains subchunks. These LIST chunks can be one of two types. An adtl list, or an INFO
765 list. This enum is used to specify the location of a chunk that dr_wav currently doesn't support.
767 typedef enum
769 drwav_metadata_location_invalid,
770 drwav_metadata_location_top_level,
771 drwav_metadata_location_inside_info_list,
772 drwav_metadata_location_inside_adtl_list
773 } drwav_metadata_location;
775 typedef struct
777 drwav_uint8 id[4];
778 drwav_metadata_location chunkLocation;
779 drwav_uint32 dataSizeInBytes;
780 drwav_uint8* pData;
781 } drwav_unknown_metadata;
784 Metadata is saved as a union of all the supported types.
786 typedef struct
788 /* Determines which item in the union is valid. */
789 drwav_metadata_type type;
791 union
793 drwav_cue cue;
794 drwav_smpl smpl;
795 drwav_acid acid;
796 drwav_inst inst;
797 drwav_bext bext;
798 drwav_list_label_or_note labelOrNote; /* List label or list note. */
799 drwav_list_labelled_cue_region labelledCueRegion;
800 drwav_list_info_text infoText; /* Any of the list info types. */
801 drwav_unknown_metadata unknown;
802 } data;
803 } drwav_metadata;
805 typedef struct
807 /* A pointer to the function to call when more data is needed. */
808 drwav_read_proc onRead;
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. */
811 drwav_write_proc onWrite;
813 /* A pointer to the function to call when the wav file needs to be seeked. */
814 drwav_seek_proc onSeek;
816 /* The user data to pass to callbacks. */
817 void* pUserData;
819 /* Allocation callbacks. */
820 drwav_allocation_callbacks allocationCallbacks;
823 /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */
824 drwav_container container;
827 /* Structure containing format information exactly as specified by the wav file. */
828 drwav_fmt fmt;
830 /* The sample rate. Will be set to something like 44100. */
831 drwav_uint32 sampleRate;
833 /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */
834 drwav_uint16 channels;
836 /* The bits per sample. Will be set to something like 16, 24, etc. */
837 drwav_uint16 bitsPerSample;
839 /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */
840 drwav_uint16 translatedFormatTag;
842 /* The total number of PCM frames making up the audio data. */
843 drwav_uint64 totalPCMFrameCount;
846 /* The size in bytes of the data chunk. */
847 drwav_uint64 dataChunkDataSize;
849 /* The position in the stream of the first data byte of the data chunk. This is used for seeking. */
850 drwav_uint64 dataChunkDataPos;
852 /* The number of bytes remaining in the data chunk. */
853 drwav_uint64 bytesRemaining;
855 /* The current read position in PCM frames. */
856 drwav_uint64 readCursorInPCMFrames;
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.
863 drwav_uint64 dataChunkDataSizeTargetWrite;
865 /* Keeps track of whether or not the wav writer was initialized in sequential mode. */
866 drwav_bool32 isSequentialWrite;
869 /* A bit-field of drwav_metadata_type values, only bits set in this variable are parsed and saved */
870 drwav_metadata_type allowedMetadataTypes;
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(). */
873 drwav_metadata* pMetadata;
874 drwav_uint32 metadataCount;
877 /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */
878 drwav__memory_stream memoryStream;
879 drwav__memory_stream_write memoryStreamWrite;
882 /* Microsoft ADPCM specific data. */
883 struct
885 drwav_uint32 bytesRemainingInBlock;
886 drwav_uint16 predictor[2];
887 drwav_int32 delta[2];
888 drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */
889 drwav_uint32 cachedFrameCount;
890 drwav_int32 prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */
891 } msadpcm;
893 /* IMA ADPCM specific data. */
894 struct
896 drwav_uint32 bytesRemainingInBlock;
897 drwav_int32 predictor[2];
898 drwav_int32 stepIndex[2];
899 drwav_int32 cachedFrames[16]; /* Samples are stored in this cache during decoding. */
900 drwav_uint32 cachedFrameCount;
901 } ima;
902 } drwav;
906 Initializes a pre-allocated drwav object for reading.
908 pWav [out] A pointer to the drwav object being initialized.
909 onRead [in] The function to call when data needs to be read from the client.
910 onSeek [in] The function to call when the read position of the client data needs to move.
911 onChunk [in, optional] The function to call when a chunk is enumerated at initialized time.
912 pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
913 pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk.
914 flags [in, optional] A set of flags for controlling how things are loaded.
916 Returns true if successful; false otherwise.
918 Close the loader with drwav_uninit().
920 This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory()
921 to open the stream from a file or from a block of memory respectively.
923 Possible 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.
927 drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);".
929 The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt
930 after the function returns.
932 See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
934 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
935 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);
936 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);
939 Initializes a pre-allocated drwav object for writing.
941 onWrite [in] The function to call when data needs to be written.
942 onSeek [in] The function to call when the write position needs to move.
943 pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek.
944 metadata, numMetadata [in, optional] An array of metadata objects that should be written to the file. The array is not edited. You are responsible for this metadata memory and it must maintain valid until drwav_uninit() is called.
946 Returns true if successful; false otherwise.
948 Close the writer with drwav_uninit().
950 This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write()
951 to open the stream from a file or from a block of memory respectively.
953 If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform
954 a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek.
956 See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit()
958 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);
959 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);
960 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);
961 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);
964 Utility function to determine the target size of the entire data to be written (including all headers and chunks).
966 Returns the target size in bytes.
968 The metadata argument can be NULL meaning no metadata exists.
970 Useful if the application needs to know the size to allocate.
972 Only writing to the RIFF chunk and one data chunk is currently supported.
974 See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write()
976 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount);
979 Take ownership of the metadata objects that were allocated via one of the init_with_metadata() function calls. The init_with_metdata functions perform a single heap allocation for this metadata.
981 Useful if you want the data to persist beyond the lifetime of the drwav object.
983 You must free the data returned from this function using drwav_free().
985 DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav);
988 Uninitializes the given drwav object.
990 Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()).
992 DRWAV_API drwav_result drwav_uninit(drwav* pWav);
996 Reads raw audio data.
998 This is the lowest level function for reading audio data. It simply reads the given number of
999 bytes of the raw internal sample data.
1001 Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for
1002 reading sample data in a consistent format.
1004 pBufferOut can be NULL in which case a seek will be performed.
1006 Returns the number of bytes actually read.
1008 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
1011 Reads up to the specified number of PCM frames from the WAV file.
1013 The output data will be in the file's internal format, converted to native-endian byte order. Use
1014 drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format.
1016 If the return value is less than <framesToRead> it means the end of the file has been reached or
1017 you have requested more PCM frames than can possibly fit in the output buffer.
1019 This function will only work when sample data is of a fixed size and uncompressed. If you are
1020 using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32().
1022 pBufferOut can be NULL in which case a seek will be performed.
1024 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1025 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1026 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1029 Seeks to the given PCM frame.
1031 Returns true if successful; false otherwise.
1033 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
1036 Retrieves the current read position in pcm frames.
1038 DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor);
1041 Retrieves the length of the file.
1043 DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength);
1047 Writes raw audio data.
1049 Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error.
1051 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
1054 Writes PCM frames.
1056 Returns the number of PCM frames written.
1058 Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to
1059 little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion.
1061 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1062 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1063 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1065 /* Conversion Utilities */
1066 #ifndef DR_WAV_NO_CONVERSION_API
1069 Reads a chunk of audio data and converts it to signed 16-bit PCM samples.
1071 pBufferOut can be NULL in which case a seek will be performed.
1073 Returns the number of PCM frames actually read.
1075 If the return value is less than <framesToRead> it means the end of the file has been reached.
1077 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1078 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1079 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1081 /* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */
1082 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1084 /* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */
1085 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1087 /* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */
1088 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
1090 /* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */
1091 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
1093 /* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */
1094 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
1096 /* Low-level function for converting A-law samples to signed 16-bit PCM samples. */
1097 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1099 /* Low-level function for converting u-law samples to signed 16-bit PCM samples. */
1100 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1104 Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples.
1106 pBufferOut can be NULL in which case a seek will be performed.
1108 Returns the number of PCM frames actually read.
1110 If the return value is less than <framesToRead> it means the end of the file has been reached.
1112 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1113 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1114 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1116 /* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */
1117 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1119 /* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */
1120 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
1122 /* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */
1123 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1125 /* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */
1126 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
1128 /* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */
1129 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
1131 /* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */
1132 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1134 /* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */
1135 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1139 Reads a chunk of audio data and converts it to signed 32-bit PCM samples.
1141 pBufferOut can be NULL in which case a seek will be performed.
1143 Returns the number of PCM frames actually read.
1145 If the return value is less than <framesToRead> it means the end of the file has been reached.
1147 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1148 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1149 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1151 /* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */
1152 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1154 /* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */
1155 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
1157 /* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */
1158 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1160 /* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */
1161 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
1163 /* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */
1164 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
1166 /* Low-level function for converting A-law samples to signed 32-bit PCM samples. */
1167 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1169 /* Low-level function for converting u-law samples to signed 32-bit PCM samples. */
1170 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1172 #endif /* DR_WAV_NO_CONVERSION_API */
1175 /* High-Level Convenience Helpers */
1177 #ifndef DR_WAV_NO_STDIO
1179 Helper for initializing a wave file for reading using stdio.
1181 This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
1182 objects because the operating system may restrict the number of file handles an application can have open at
1183 any given time.
1185 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
1186 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);
1187 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
1188 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);
1189 DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1190 DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1194 Helper for initializing a wave file for writing using stdio.
1196 This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
1197 objects because the operating system may restrict the number of file handles an application can have open at
1198 any given time.
1200 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
1201 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);
1202 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);
1203 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);
1204 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);
1205 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);
1206 #endif /* DR_WAV_NO_STDIO */
1209 Helper for initializing a loader from a pre-allocated memory buffer.
1211 This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
1212 the lifetime of the drwav object.
1214 The buffer should contain the contents of the entire wave file, not just the sample data.
1216 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
1217 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);
1218 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);
1221 Helper for initializing a writer which outputs data to a memory buffer.
1223 dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
1225 The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid
1226 until after drwav_uninit() has been called.
1228 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);
1229 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);
1230 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);
1233 #ifndef DR_WAV_NO_CONVERSION_API
1235 Opens and reads an entire wav file in a single operation.
1237 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1239 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);
1240 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);
1241 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);
1242 #ifndef DR_WAV_NO_STDIO
1244 Opens and decodes an entire wav file in a single operation.
1246 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1248 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);
1249 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);
1250 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);
1251 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);
1252 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);
1253 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);
1254 #endif
1256 Opens and decodes an entire wav file from a block of memory in a single operation.
1258 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1260 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);
1261 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);
1262 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);
1263 #endif
1265 /* Frees data that was allocated internally by dr_wav. */
1266 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
1268 /* Converts bytes from a wav stream to a sized type of native endian. */
1269 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data);
1270 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data);
1271 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data);
1272 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data);
1273 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data);
1274 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data);
1275 DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data);
1277 /* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */
1278 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
1280 /* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */
1281 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
1283 #ifdef __cplusplus
1285 #endif
1286 #endif /* dr_wav_h */
1289 /************************************************************************************************************************************************************
1290 ************************************************************************************************************************************************************
1292 IMPLEMENTATION
1294 ************************************************************************************************************************************************************
1295 ************************************************************************************************************************************************************/
1296 #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
1297 #ifndef dr_wav_c
1298 #define dr_wav_c
1300 #include <stdlib.h>
1301 #include <string.h> /* For memcpy(), memset() */
1302 #include <limits.h> /* For INT_MAX */
1304 #ifndef DR_WAV_NO_STDIO
1305 #include <stdio.h>
1306 #include <wchar.h>
1307 #endif
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
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))))
1339 #define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */
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
1350 #ifdef _MSC_VER
1351 #define DRWAV_INLINE __forceinline
1352 #elif defined(__GNUC__)
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.
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
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
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
1407 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision)
1409 if (pMajor) {
1410 *pMajor = DRWAV_VERSION_MAJOR;
1413 if (pMinor) {
1414 *pMinor = DRWAV_VERSION_MINOR;
1417 if (pRevision) {
1418 *pRevision = DRWAV_VERSION_REVISION;
1422 DRWAV_API const char* drwav_version_string(void)
1424 return DRWAV_VERSION_STRING;
1428 These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are
1429 you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation.
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
1441 static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; /* 66666972-912E-11CF-A5D6-28DB04C10000 */
1442 static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
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 */
1444 static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
1445 static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 74636166-ACF3-11D3-8CD1-00C04F8EDB8A */
1446 static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
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 */
1450 static DRWAV_INLINE int drwav__is_little_endian(void)
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
1463 static DRWAV_INLINE void drwav_bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid)
1465 int i;
1466 for (i = 0; i < 16; ++i) {
1467 guid[i] = data[i];
1472 static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n)
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
1488 static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n)
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(). */
1496 drwav_uint32 r;
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
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
1519 static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
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
1543 static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
1545 return (drwav_int16)drwav__bswap16((drwav_uint16)n);
1548 static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount)
1550 drwav_uint64 iSample;
1551 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1552 pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]);
1557 static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p)
1559 drwav_uint8 t;
1560 t = p[0];
1561 p[0] = p[2];
1562 p[2] = t;
1565 static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount)
1567 drwav_uint64 iSample;
1568 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1569 drwav_uint8* pSample = pSamples + (iSample*3);
1570 drwav__bswap_s24(pSample);
1575 static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n)
1577 return (drwav_int32)drwav__bswap32((drwav_uint32)n);
1580 static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount)
1582 drwav_uint64 iSample;
1583 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1584 pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]);
1589 static DRWAV_INLINE float drwav__bswap_f32(float n)
1591 union {
1592 drwav_uint32 i;
1593 float f;
1594 } x;
1595 x.f = n;
1596 x.i = drwav__bswap32(x.i);
1598 return x.f;
1601 static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount)
1603 drwav_uint64 iSample;
1604 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1605 pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]);
1610 static DRWAV_INLINE double drwav__bswap_f64(double n)
1612 union {
1613 drwav_uint64 i;
1614 double f;
1615 } x;
1616 x.f = n;
1617 x.i = drwav__bswap64(x.i);
1619 return x.f;
1622 static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount)
1624 drwav_uint64 iSample;
1625 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1626 pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]);
1631 static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1633 /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */
1634 switch (bytesPerSample)
1636 case 2: /* s16, s12 (loosely packed) */
1638 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1639 } break;
1640 case 3: /* s24 */
1642 drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount);
1643 } break;
1644 case 4: /* s32 */
1646 drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount);
1647 } break;
1648 default:
1650 /* Unsupported format. */
1651 DRWAV_ASSERT(DRWAV_FALSE);
1652 } break;
1656 static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1658 switch (bytesPerSample)
1660 #if 0 /* Contributions welcome for f16 support. */
1661 case 2: /* f16 */
1663 drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount);
1664 } break;
1665 #endif
1666 case 4: /* f32 */
1668 drwav__bswap_samples_f32((float*)pSamples, sampleCount);
1669 } break;
1670 case 8: /* f64 */
1672 drwav__bswap_samples_f64((double*)pSamples, sampleCount);
1673 } break;
1674 default:
1676 /* Unsupported format. */
1677 DRWAV_ASSERT(DRWAV_FALSE);
1678 } break;
1682 static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format)
1684 switch (format)
1686 case DR_WAVE_FORMAT_PCM:
1688 drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample);
1689 } break;
1691 case DR_WAVE_FORMAT_IEEE_FLOAT:
1693 drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample);
1694 } break;
1696 case DR_WAVE_FORMAT_ALAW:
1697 case DR_WAVE_FORMAT_MULAW:
1699 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1700 } break;
1702 case DR_WAVE_FORMAT_ADPCM:
1703 case DR_WAVE_FORMAT_DVI_ADPCM:
1704 default:
1706 /* Unsupported format. */
1707 DRWAV_ASSERT(DRWAV_FALSE);
1708 } break;
1713 DRWAV_PRIVATE void* drwav__malloc_default(size_t sz, void* pUserData)
1715 (void)pUserData;
1716 return DRWAV_MALLOC(sz);
1719 DRWAV_PRIVATE void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
1721 (void)pUserData;
1722 return DRWAV_REALLOC(p, sz);
1725 DRWAV_PRIVATE void drwav__free_default(void* p, void* pUserData)
1727 (void)pUserData;
1728 DRWAV_FREE(p);
1732 DRWAV_PRIVATE void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
1734 if (pAllocationCallbacks == NULL) {
1735 return NULL;
1738 if (pAllocationCallbacks->onMalloc != NULL) {
1739 return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
1742 /* Try using realloc(). */
1743 if (pAllocationCallbacks->onRealloc != NULL) {
1744 return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
1747 return NULL;
1750 DRWAV_PRIVATE void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
1752 if (pAllocationCallbacks == NULL) {
1753 return NULL;
1756 if (pAllocationCallbacks->onRealloc != NULL) {
1757 return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
1760 /* Try emulating realloc() in terms of malloc()/free(). */
1761 if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
1762 void* p2;
1764 p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
1765 if (p2 == NULL) {
1766 return NULL;
1769 if (p != NULL) {
1770 DRWAV_COPY_MEMORY(p2, p, szOld);
1771 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1774 return p2;
1777 return NULL;
1780 DRWAV_PRIVATE void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
1782 if (p == NULL || pAllocationCallbacks == NULL) {
1783 return;
1786 if (pAllocationCallbacks->onFree != NULL) {
1787 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1792 DRWAV_PRIVATE drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
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;
1809 static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
1811 return
1812 formatTag == DR_WAVE_FORMAT_ADPCM ||
1813 formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
1816 DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
1818 return (unsigned int)(chunkSize % 2);
1821 DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
1823 return (unsigned int)(chunkSize % 8);
1826 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1827 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1828 DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
1830 DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
1832 if (container == drwav_container_riff || container == drwav_container_rf64) {
1833 drwav_uint8 sizeInBytes[4];
1835 if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
1836 return DRWAV_AT_END;
1839 if (onRead(pUserData, sizeInBytes, 4) != 4) {
1840 return DRWAV_INVALID_FILE;
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];
1849 if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
1850 return DRWAV_AT_END;
1853 if (onRead(pUserData, sizeInBytes, 8) != 8) {
1854 return DRWAV_INVALID_FILE;
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;
1862 return DRWAV_SUCCESS;
1865 DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
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;
1873 bytesRemainingToSeek -= 0x7FFFFFFF;
1874 } else {
1875 if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
1876 return DRWAV_FALSE;
1878 bytesRemainingToSeek = 0;
1882 return DRWAV_TRUE;
1885 DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1887 if (offset <= 0x7FFFFFFF) {
1888 return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
1891 /* Larger than 32-bit seek. */
1892 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
1893 return DRWAV_FALSE;
1895 offset -= 0x7FFFFFFF;
1897 for (;;) {
1898 if (offset <= 0x7FFFFFFF) {
1899 return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
1902 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1903 return DRWAV_FALSE;
1905 offset -= 0x7FFFFFFF;
1908 /* Should never get here. */
1909 /*return DRWAV_TRUE; */
1913 DRWAV_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)
1915 drwav_chunk_header header;
1916 drwav_uint8 fmt[16];
1918 if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
1919 return DRWAV_FALSE;
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;
1928 *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize;
1930 /* Try the next header. */
1931 if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
1932 return DRWAV_FALSE;
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;
1942 } else {
1943 if (!drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
1944 return DRWAV_FALSE;
1949 if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
1950 return DRWAV_FALSE;
1952 *pRunningBytesReadOut += sizeof(fmt);
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);
1961 fmtOut->extendedSize = 0;
1962 fmtOut->validBitsPerSample = 0;
1963 fmtOut->channelMask = 0;
1964 memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
1966 if (header.sizeInBytes > 16) {
1967 drwav_uint8 fmt_cbSize[2];
1968 int bytesReadSoFar = 0;
1970 if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
1971 return DRWAV_FALSE; /* Expecting more data. */
1973 *pRunningBytesReadOut += sizeof(fmt_cbSize);
1975 bytesReadSoFar = 18;
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;
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. */
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;
2000 *pRunningBytesReadOut += fmtOut->extendedSize;
2002 bytesReadSoFar += fmtOut->extendedSize;
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;
2009 *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
2012 if (header.paddingSize > 0) {
2013 if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
2014 return DRWAV_FALSE;
2016 *pRunningBytesReadOut += header.paddingSize;
2019 return DRWAV_TRUE;
2023 DRWAV_PRIVATE size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
2025 size_t bytesRead;
2027 DRWAV_ASSERT(onRead != NULL);
2028 DRWAV_ASSERT(pCursor != NULL);
2030 bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
2031 *pCursor += bytesRead;
2032 return bytesRead;
2035 #if 0
2036 DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
2038 DRWAV_ASSERT(onSeek != NULL);
2039 DRWAV_ASSERT(pCursor != NULL);
2041 if (!onSeek(pUserData, offset, origin)) {
2042 return DRWAV_FALSE;
2045 if (origin == drwav_seek_origin_start) {
2046 *pCursor = offset;
2047 } else {
2048 *pCursor += offset;
2051 return DRWAV_TRUE;
2053 #endif
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
2071 #define DRWAV_METADATA_ALIGNMENT 8
2073 typedef enum
2075 drwav__metadata_parser_stage_count,
2076 drwav__metadata_parser_stage_read
2077 } drwav__metadata_parser_stage;
2079 typedef struct
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;
2093 DRWAV_PRIVATE size_t drwav__metadata_memory_capacity(drwav__metadata_parser* pParser)
2095 drwav_uint64 cap = sizeof(drwav_metadata) * (drwav_uint64)pParser->metadataCount + pParser->extraCapacity;
2096 if (cap > DRWAV_SIZE_MAX) {
2097 return 0; /* Too big. */
2100 return (size_t)cap; /* Safe cast thanks to the check above. */
2103 DRWAV_PRIVATE drwav_uint8* drwav__metadata_get_memory(drwav__metadata_parser* pParser, size_t size, size_t align)
2105 drwav_uint8* pResult;
2107 if (align) {
2108 drwav_uintptr modulo = (drwav_uintptr)pParser->pDataCursor % align;
2109 if (modulo != 0) {
2110 pParser->pDataCursor += align - modulo;
2114 pResult = pParser->pDataCursor;
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.
2120 DRWAV_ASSERT((pResult + size) <= (pParser->pData + drwav__metadata_memory_capacity(pParser)));
2122 pParser->pDataCursor += size;
2123 return pResult;
2126 DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metadata_parser* pParser, size_t bytes, size_t align)
2128 size_t extra = bytes + (align ? (align - 1) : 0);
2129 pParser->extraCapacity += extra;
2132 DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks)
2134 if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) {
2135 free(pParser->pData);
2137 pParser->pData = (drwav_uint8*)pAllocationCallbacks->onMalloc(drwav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData);
2138 pParser->pDataCursor = pParser->pData;
2140 if (pParser->pData == NULL) {
2141 return DRWAV_OUT_OF_MEMORY;
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.
2149 pParser->pMetadata = (drwav_metadata*)drwav__metadata_get_memory(pParser, sizeof(drwav_metadata) * pParser->metadataCount, 1);
2150 pParser->metadataCursor = 0;
2153 return DRWAV_SUCCESS;
2156 DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
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);
2165 DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
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);
2171 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2173 if (bytesJustRead == sizeof(smplHeaderData)) {
2174 drwav_uint32 iSampleLoop;
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);
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);
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;
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);
2208 bytesJustRead = drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead);
2212 return totalBytesRead;
2215 DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
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);
2221 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
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);
2229 if (pMetadata->data.cue.cuePointCount > 0) {
2230 drwav_uint32 iCuePoint;
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);
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;
2253 return totalBytesRead;
2256 DRWAV_PRIVATE drwav_uint64 drwav__read_inst_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
2258 drwav_uint8 instData[DRWAV_INST_BYTES];
2259 drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, instData, sizeof(instData), NULL);
2261 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
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];
2274 return bytesRead;
2277 DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
2279 drwav_uint8 acidData[DRWAV_ACID_BYTES];
2280 drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, acidData, sizeof(acidData), NULL);
2282 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
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);
2296 return bytesRead;
2299 DRWAV_PRIVATE size_t drwav__strlen_clamped(char* str, size_t maxToRead)
2301 size_t result = 0;
2303 while (*str++ && result < maxToRead) {
2304 result += 1;
2307 return result;
2310 DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, char* str, size_t maxToRead)
2312 size_t len = drwav__strlen_clamped(str, maxToRead);
2314 if (len) {
2315 char* result = (char*)drwav__metadata_get_memory(pParser, len + 1, 1);
2316 DRWAV_ASSERT(result != NULL);
2318 memcpy(result, str, len);
2319 result[len] = '\0';
2321 return result;
2322 } else {
2323 return NULL;
2327 DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize)
2329 drwav_uint8 bextData[DRWAV_BEXT_BYTES];
2330 drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL);
2332 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2334 if (bytesRead == sizeof(bextData)) {
2335 drwav_uint8* pReadPointer;
2336 drwav_uint32 timeReferenceLow;
2337 drwav_uint32 timeReferenceHigh;
2338 size_t extraBytes;
2340 pMetadata->type = drwav_metadata_type_bext;
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;
2346 pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
2347 pReadPointer += DRWAV_BEXT_ORIGINATOR_NAME_BYTES;
2349 pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (char*)(pReadPointer), DRWAV_BEXT_ORIGINATOR_REF_BYTES);
2350 pReadPointer += DRWAV_BEXT_ORIGINATOR_REF_BYTES;
2352 memcpy(pReadPointer, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate));
2353 pReadPointer += sizeof(pMetadata->data.bext.pOriginationDate);
2355 memcpy(pReadPointer, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime));
2356 pReadPointer += sizeof(pMetadata->data.bext.pOriginationTime);
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;
2364 pMetadata->data.bext.version = drwav_bytes_to_u16(pReadPointer);
2365 pReadPointer += sizeof(drwav_uint16);
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;
2371 pMetadata->data.bext.loudnessValue = drwav_bytes_to_u16(pReadPointer);
2372 pReadPointer += sizeof(drwav_uint16);
2374 pMetadata->data.bext.loudnessRange = drwav_bytes_to_u16(pReadPointer);
2375 pReadPointer += sizeof(drwav_uint16);
2377 pMetadata->data.bext.maxTruePeakLevel = drwav_bytes_to_u16(pReadPointer);
2378 pReadPointer += sizeof(drwav_uint16);
2380 pMetadata->data.bext.maxMomentaryLoudness = drwav_bytes_to_u16(pReadPointer);
2381 pReadPointer += sizeof(drwav_uint16);
2383 pMetadata->data.bext.maxShortTermLoudness = drwav_bytes_to_u16(pReadPointer);
2384 pReadPointer += sizeof(drwav_uint16);
2386 DRWAV_ASSERT((pReadPointer + DRWAV_BEXT_RESERVED_BYTES) == (bextData + DRWAV_BEXT_BYTES));
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);
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;
2401 return bytesRead;
2404 DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize, drwav_metadata_type type)
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);
2410 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2412 if (bytesJustRead == sizeof(cueIDBuffer)) {
2413 drwav_uint32 sizeIncludingNullTerminator;
2415 pMetadata->type = type;
2416 pMetadata->data.labelOrNote.cuePointId = drwav_bytes_to_u32(cueIDBuffer);
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);
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;
2431 return totalBytesRead;
2434 DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize)
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);
2440 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2442 if (bytesJustRead == sizeof(buffer)) {
2443 drwav_uint32 sizeIncludingNullTerminator;
2445 pMetadata->type = drwav_metadata_type_list_labelled_cue_region;
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);
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);
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;
2470 return totalBytesRead;
2473 DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_info_text_chunk(drwav__metadata_parser* pParser, drwav_uint64 chunkSize, drwav_metadata_type type)
2475 drwav_uint64 bytesRead = 0;
2476 drwav_uint32 stringSizeWithNullTerminator = (drwav_uint32)chunkSize;
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);
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. */
2495 } else {
2496 pMetadata->data.infoText.stringLength = 0;
2497 pMetadata->data.infoText.pString = NULL;
2498 pParser->metadataCursor += 1;
2502 return bytesRead;
2505 DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata_parser* pParser, const drwav_uint8* pChunkId, drwav_uint64 chunkSize, drwav_metadata_location location)
2507 drwav_uint64 bytesRead = 0;
2509 if (location == drwav_metadata_location_invalid) {
2510 return 0;
2513 if (drwav_fourcc_equal(pChunkId, "data") || drwav_fourcc_equal(pChunkId, "fmt") || drwav_fourcc_equal(pChunkId, "fact")) {
2514 return 0;
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);
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. */
2540 return bytesRead;
2543 DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_uint64 allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID)
2545 return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID);
2548 DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_uint64 allowedMetadataTypes)
2550 const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc;
2551 drwav_uint64 bytesRead = 0;
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) {
2556 drwav_uint8 buffer[4];
2557 size_t bytesJustRead;
2559 if (!pParser->onSeek(pParser->pReadSeekUserData, 28, drwav_seek_origin_current)) {
2560 return bytesRead;
2562 bytesRead += 28;
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);
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);
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);
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. */
2585 } else {
2586 /* Incorrectly formed chunk. */
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. */
2600 } else {
2601 /* Incorrectly formed chunk. */
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. */
2615 } else {
2616 /* Incorrectly formed chunk. */
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;
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. */
2634 } else {
2635 /* Incorrectly formed chunk. */
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;
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;
2650 allocSizeNeeded += strlen(buffer) + 1;
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;
2657 allocSizeNeeded += strlen(buffer) + 1;
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;
2664 allocSizeNeeded += strlen(buffer) + 1;
2665 allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES; /* Coding history. */
2667 drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
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. */
2678 } else {
2679 /* Incorrectly formed chunk. */
2681 } else if (drwav_fourcc_equal(pChunkID, "LIST") || drwav_fourcc_equal(pChunkID, "list")) {
2682 drwav_metadata_location listType = drwav_metadata_location_invalid;
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;
2694 The first thing in a list chunk should be "adtl" or "INFO".
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.
2701 No data follows the adtl or INFO id so we just make note of what type this list is and
2702 continue.
2704 if (drwav_fourcc_equal(subchunkId, "adtl")) {
2705 listType = drwav_metadata_location_inside_adtl_list;
2706 continue;
2707 } else if (drwav_fourcc_equal(subchunkId, "INFO")) {
2708 listType = drwav_metadata_location_inside_info_list;
2709 continue;
2712 bytesJustRead = drwav__metadata_parser_read(pParser, subchunkSizeBuffer, sizeof(subchunkSizeBuffer), &bytesRead);
2713 if (bytesJustRead != sizeof(subchunkSizeBuffer)) {
2714 break;
2716 subchunkDataSize = drwav_bytes_to_u32(subchunkSizeBuffer);
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. */
2732 } else {
2733 /* Incorrectly formed chunk. */
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. */
2749 } else {
2750 /* Incorrectly formed chunk. */
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);
2774 bytesRead += subchunkBytesRead;
2775 DRWAV_ASSERT(subchunkBytesRead <= subchunkDataSize);
2777 if (subchunkBytesRead < subchunkDataSize) {
2778 drwav_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead;
2780 if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, drwav_seek_origin_current)) {
2781 break;
2783 bytesRead += bytesToSeek;
2786 if ((subchunkDataSize % 2) == 1) {
2787 if (!pParser->onSeek(pParser->pReadSeekUserData, 1, drwav_seek_origin_current)) {
2788 break;
2790 bytesRead += 1;
2793 } else if (allowedMetadataTypes & drwav_metadata_type_unknown) {
2794 bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level);
2797 return bytesRead;
2801 DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
2803 drwav_uint32 bytesPerFrame;
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.
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;
2816 /* Validation for known formats. a-law and mu-law should be 1 byte per channel. If it's not, it's not decodable. */
2817 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
2818 if (bytesPerFrame != pWav->fmt.channels) {
2819 return 0; /* Invalid file. */
2823 return bytesPerFrame;
2826 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
2828 if (pFMT == NULL) {
2829 return 0;
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. */
2839 DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2841 if (pWav == NULL || onRead == NULL || onSeek == NULL) {
2842 return DRWAV_FALSE;
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);
2851 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
2852 return DRWAV_FALSE; /* Invalid allocation callbacks. */
2855 return DRWAV_TRUE;
2858 DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
2860 /* This function assumes drwav_preinit() has been called beforehand. */
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;
2873 cursor = 0;
2874 sequential = (flags & DRWAV_SEQUENTIAL) != 0;
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;
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".
2885 if (drwav_fourcc_equal(riff, "RIFF")) {
2886 pWav->container = drwav_container_riff;
2887 } else if (drwav_fourcc_equal(riff, "riff")) {
2888 int i;
2889 drwav_uint8 riff2[12];
2891 pWav->container = drwav_container_w64;
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;
2898 for (i = 0; i < 12; ++i) {
2899 if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
2900 return DRWAV_FALSE;
2903 } else if (drwav_fourcc_equal(riff, "RF64")) {
2904 pWav->container = drwav_container_rf64;
2905 } else {
2906 return DRWAV_FALSE; /* Unknown or unsupported container. */
2910 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
2911 drwav_uint8 chunkSizeBytes[4];
2912 drwav_uint8 wave[4];
2914 /* RIFF/WAVE */
2915 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
2916 return DRWAV_FALSE;
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. */
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. */
2929 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
2930 return DRWAV_FALSE;
2933 if (!drwav_fourcc_equal(wave, "WAVE")) {
2934 return DRWAV_FALSE; /* Expecting "WAVE". */
2936 } else {
2937 drwav_uint8 chunkSizeBytes[8];
2938 drwav_uint8 wave[16];
2940 /* W64 */
2941 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
2942 return DRWAV_FALSE;
2945 if (drwav_bytes_to_u64(chunkSizeBytes) < 80) {
2946 return DRWAV_FALSE;
2949 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
2950 return DRWAV_FALSE;
2953 if (!drwav_guid_equal(wave, drwavGUID_W64_WAVE)) {
2954 return DRWAV_FALSE;
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;
2969 if (!drwav_fourcc_equal(header.id.fourcc, "ds64")) {
2970 return DRWAV_FALSE; /* Expecting "ds64". */
2973 bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
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;
2979 bytesRemainingInChunk -= 8;
2980 cursor += 8;
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;
2987 bytesRemainingInChunk -= 8;
2988 dataChunkSize = drwav_bytes_to_u64(sizeBytes);
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;
2995 bytesRemainingInChunk -= 8;
2996 sampleCountFromFactChunk = drwav_bytes_to_u64(sizeBytes);
2999 /* Skip over everything else. */
3000 if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
3001 return DRWAV_FALSE;
3003 cursor += bytesRemainingInChunk;
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. */
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. */
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);
3027 memset(&metadataParser, 0, sizeof(metadataParser));
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;
3033 metadataParser.onRead = pWav->onRead;
3034 metadataParser.onSeek = pWav->onSeek;
3035 metadataParser.pReadSeekUserData = pWav->pUserData;
3036 metadataParser.stage = drwav__metadata_parser_stage_count;
3038 for (;;) {
3039 drwav_result result;
3040 drwav_uint64 bytesRead;
3041 drwav_uint64 remainingBytes;
3042 drwav_chunk_header header;
3044 result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursorForMetadata, &header);
3045 if (result != DRWAV_SUCCESS) {
3046 break;
3049 bytesRead = drwav__metadata_process_chunk(&metadataParser, &header, pWav->allowedMetadataTypes);
3050 DRWAV_ASSERT(bytesRead <= header.sizeInBytes);
3052 remainingBytes = header.sizeInBytes - bytesRead + header.paddingSize;
3053 if (!drwav__seek_forward(pWav->onSeek, remainingBytes, pWav->pUserData)) {
3054 break;
3056 cursorForMetadata += remainingBytes;
3059 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
3060 return DRWAV_FALSE;
3063 drwav__metadata_alloc(&metadataParser, &pWav->allocationCallbacks);
3064 metadataParser.stage = drwav__metadata_parser_stage_read;
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
3072 In order to correctly report each chunk back to the client we will need to keep looping until the end of the file.
3074 foundDataChunk = DRWAV_FALSE;
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. */
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);
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.
3096 if (callbackBytesRead > 0) {
3097 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
3098 return DRWAV_FALSE;
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);
3106 if (bytesRead > 0) {
3107 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
3108 return DRWAV_FALSE;
3114 if (!foundDataChunk) {
3115 pWav->dataChunkDataPos = cursor;
3118 chunkSize = header.sizeInBytes;
3119 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
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;
3126 } else {
3127 if (drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
3128 foundDataChunk = DRWAV_TRUE;
3129 dataChunkSize = chunkSize;
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.
3137 if (foundDataChunk && sequential) {
3138 break;
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;
3148 chunkSize -= 4;
3150 if (!foundDataChunk) {
3151 pWav->dataChunkDataPos = cursor;
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.
3158 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3159 sampleCountFromFactChunk = sampleCount;
3160 } else {
3161 sampleCountFromFactChunk = 0;
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;
3169 chunkSize -= 8;
3171 if (!foundDataChunk) {
3172 pWav->dataChunkDataPos = cursor;
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. */
3179 /* Make sure we seek past the padding. */
3180 chunkSize += header.paddingSize;
3181 if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) {
3182 break;
3184 cursor += chunkSize;
3186 if (!foundDataChunk) {
3187 pWav->dataChunkDataPos = cursor;
3191 pWav->pMetadata = metadataParser.pMetadata;
3192 pWav->metadataCount = metadataParser.metadataCount;
3194 /* If we haven't found a data chunk, return an error. */
3195 if (!foundDataChunk) {
3196 return DRWAV_FALSE;
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;
3204 cursor = pWav->dataChunkDataPos;
3208 /* At this point we should be sitting on the first byte of the raw audio data. */
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;
3218 if (sampleCountFromFactChunk != 0) {
3219 pWav->totalPCMFrameCount = sampleCountFromFactChunk;
3220 } else {
3221 pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav);
3223 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3224 drwav_uint64 totalBlockHeaderSizeInBytes;
3225 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3227 /* Make sure any trailing partial block is accounted for. */
3228 if ((blockCount * fmt.blockAlign) < dataChunkSize) {
3229 blockCount += 1;
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;
3236 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3237 drwav_uint64 totalBlockHeaderSizeInBytes;
3238 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3240 /* Make sure any trailing partial block is accounted for. */
3241 if ((blockCount * fmt.blockAlign) < dataChunkSize) {
3242 blockCount += 1;
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;
3249 /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */
3250 pWav->totalPCMFrameCount += blockCount;
3254 /* Some formats only support a certain number of channels. */
3255 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3256 if (pWav->channels > 2) {
3257 return DRWAV_FALSE;
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;
3266 #ifdef DR_WAV_LIBSNDFILE_COMPAT
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.
3275 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
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. */
3279 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3280 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3281 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
3283 #endif
3285 return DRWAV_TRUE;
3288 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
3290 return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
3293 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)
3295 if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
3296 return DRWAV_FALSE;
3299 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
3302 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)
3304 if (!drwav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
3305 return DRWAV_FALSE;
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);
3312 DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav)
3314 drwav_metadata *result = pWav->pMetadata;
3316 pWav->pMetadata = NULL;
3317 pWav->metadataCount = 0;
3319 return result;
3323 DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
3325 DRWAV_ASSERT(pWav != NULL);
3326 DRWAV_ASSERT(pWav->onWrite != NULL);
3328 /* Generic write. Assumes no byte reordering required. */
3329 return pWav->onWrite(pWav->pUserData, pData, dataSize);
3332 DRWAV_PRIVATE size_t drwav__write_byte(drwav* pWav, drwav_uint8 byte)
3334 DRWAV_ASSERT(pWav != NULL);
3335 DRWAV_ASSERT(pWav->onWrite != NULL);
3337 return pWav->onWrite(pWav->pUserData, &byte, 1);
3340 DRWAV_PRIVATE size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value)
3342 DRWAV_ASSERT(pWav != NULL);
3343 DRWAV_ASSERT(pWav->onWrite != NULL);
3345 if (!drwav__is_little_endian()) {
3346 value = drwav__bswap16(value);
3349 return drwav__write(pWav, &value, 2);
3352 DRWAV_PRIVATE size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value)
3354 DRWAV_ASSERT(pWav != NULL);
3355 DRWAV_ASSERT(pWav->onWrite != NULL);
3357 if (!drwav__is_little_endian()) {
3358 value = drwav__bswap32(value);
3361 return drwav__write(pWav, &value, 4);
3364 DRWAV_PRIVATE size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value)
3366 DRWAV_ASSERT(pWav != NULL);
3367 DRWAV_ASSERT(pWav->onWrite != NULL);
3369 if (!drwav__is_little_endian()) {
3370 value = drwav__bswap64(value);
3373 return drwav__write(pWav, &value, 8);
3376 DRWAV_PRIVATE size_t drwav__write_f32ne_to_le(drwav* pWav, float value)
3378 union {
3379 drwav_uint32 u32;
3380 float f32;
3381 } u;
3383 DRWAV_ASSERT(pWav != NULL);
3384 DRWAV_ASSERT(pWav->onWrite != NULL);
3386 u.f32 = value;
3388 if (!drwav__is_little_endian()) {
3389 u.u32 = drwav__bswap32(u.u32);
3392 return drwav__write(pWav, &u.u32, 4);
3395 DRWAV_PRIVATE size_t drwav__write_or_count(drwav* pWav, const void* pData, size_t dataSize)
3397 if (pWav == NULL) {
3398 return dataSize;
3401 return drwav__write(pWav, pData, dataSize);
3404 DRWAV_PRIVATE size_t drwav__write_or_count_byte(drwav* pWav, drwav_uint8 byte)
3406 if (pWav == NULL) {
3407 return 1;
3410 return drwav__write_byte(pWav, byte);
3413 DRWAV_PRIVATE size_t drwav__write_or_count_u16ne_to_le(drwav* pWav, drwav_uint16 value)
3415 if (pWav == NULL) {
3416 return 2;
3419 return drwav__write_u16ne_to_le(pWav, value);
3422 DRWAV_PRIVATE size_t drwav__write_or_count_u32ne_to_le(drwav* pWav, drwav_uint32 value)
3424 if (pWav == NULL) {
3425 return 4;
3428 return drwav__write_u32ne_to_le(pWav, value);
3431 #if 0 /* Unused for now. */
3432 DRWAV_PRIVATE size_t drwav__write_or_count_u64ne_to_le(drwav* pWav, drwav_uint64 value)
3434 if (pWav == NULL) {
3435 return 8;
3438 return drwav__write_u64ne_to_le(pWav, value);
3440 #endif
3442 DRWAV_PRIVATE size_t drwav__write_or_count_f32ne_to_le(drwav* pWav, float value)
3444 if (pWav == NULL) {
3445 return 4;
3448 return drwav__write_f32ne_to_le(pWav, value);
3451 DRWAV_PRIVATE size_t drwav__write_or_count_string_to_fixed_size_buf(drwav* pWav, char* str, size_t bufFixedSize)
3453 size_t len;
3455 if (pWav == NULL) {
3456 return bufFixedSize;
3459 len = drwav__strlen_clamped(str, bufFixedSize);
3460 drwav__write_or_count(pWav, str, len);
3462 if (len < bufFixedSize) {
3463 size_t i;
3464 for (i = 0; i < bufFixedSize - len; ++i) {
3465 drwav__write_byte(pWav, 0);
3469 return bufFixedSize;
3473 /* pWav can be NULL meaning just count the bytes that would be written. */
3474 DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* pMetadatas, drwav_uint32 metadataCount)
3476 size_t bytesWritten = 0;
3477 drwav_bool32 hasListAdtl = DRWAV_FALSE;
3478 drwav_bool32 hasListInfo = DRWAV_FALSE;
3479 drwav_uint32 iMetadata;
3481 if (pMetadatas == NULL || metadataCount == 0) {
3482 return 0;
3485 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
3486 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
3487 drwav_uint32 chunkSize = 0;
3489 if ((pMetadata->type & drwav_metadata_type_list_all_info_strings) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list)) {
3490 hasListInfo = DRWAV_TRUE;
3493 if ((pMetadata->type & drwav_metadata_type_list_all_adtl) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list)) {
3494 hasListAdtl = DRWAV_TRUE;
3497 switch (pMetadata->type) {
3498 case drwav_metadata_type_smpl:
3500 drwav_uint32 iLoop;
3502 chunkSize = DRWAV_SMPL_BYTES + DRWAV_SMPL_LOOP_BYTES * pMetadata->data.smpl.sampleLoopCount + pMetadata->data.smpl.samplerSpecificDataSizeInBytes;
3504 bytesWritten += drwav__write_or_count(pWav, "smpl", 4);
3505 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
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);
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);
3526 if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) {
3527 bytesWritten += drwav__write(pWav, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes);
3529 } break;
3531 case drwav_metadata_type_inst:
3533 chunkSize = DRWAV_INST_BYTES;
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;
3546 case drwav_metadata_type_cue:
3548 drwav_uint32 iCuePoint;
3550 chunkSize = DRWAV_CUE_BYTES + DRWAV_CUE_POINT_BYTES * pMetadata->data.cue.cuePointCount;
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);
3563 } break;
3565 case drwav_metadata_type_acid:
3567 chunkSize = DRWAV_ACID_BYTES;
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;
3581 case drwav_metadata_type_bext:
3583 char reservedBuf[DRWAV_BEXT_RESERVED_BYTES];
3584 drwav_uint32 timeReferenceLow;
3585 drwav_uint32 timeReferenceHigh;
3587 chunkSize = DRWAV_BEXT_BYTES + pMetadata->data.bext.codingHistorySize;
3589 bytesWritten += drwav__write_or_count(pWav, "bext", 4);
3590 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
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));
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);
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);
3611 memset(reservedBuf, 0, sizeof(reservedBuf));
3612 bytesWritten += drwav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf));
3614 if (pMetadata->data.bext.codingHistorySize > 0) {
3615 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pCodingHistory, pMetadata->data.bext.codingHistorySize);
3617 } break;
3619 case drwav_metadata_type_unknown:
3621 if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_top_level) {
3622 chunkSize = pMetadata->data.unknown.dataSizeInBytes;
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);
3628 } break;
3630 default: break;
3632 if ((chunkSize % 2) != 0) {
3633 bytesWritten += drwav__write_or_count_byte(pWav, 0);
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];
3642 if ((pMetadata->type & drwav_metadata_type_list_all_info_strings)) {
3643 chunkSize += 8; /* For id and string size. */
3644 chunkSize += pMetadata->data.infoText.stringLength + 1; /* Include null terminator. */
3645 } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) {
3646 chunkSize += 8; /* For id string size. */
3647 chunkSize += pMetadata->data.unknown.dataSizeInBytes;
3650 if ((chunkSize % 2) != 0) {
3651 chunkSize += 1;
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);
3659 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
3660 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
3661 drwav_uint32 subchunkSize = 0;
3663 if (pMetadata->type & drwav_metadata_type_list_all_info_strings) {
3664 const char* pID = NULL;
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;
3679 DRWAV_ASSERT(pID != NULL);
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');
3688 } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) {
3689 if (pMetadata->data.unknown.dataSizeInBytes) {
3690 subchunkSize = pMetadata->data.unknown.dataSizeInBytes;
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);
3698 if ((subchunkSize % 2) != 0) {
3699 bytesWritten += drwav__write_or_count_byte(pWav, 0);
3704 if (hasListAdtl) {
3705 drwav_uint32 chunkSize = 4; /* start with 4 bytes for "adtl" */
3707 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
3708 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
3710 switch (pMetadata->type)
3712 case drwav_metadata_type_list_label:
3713 case drwav_metadata_type_list_note:
3715 chunkSize += 8; /* for id and chunk size */
3716 chunkSize += DRWAV_LIST_LABEL_OR_NOTE_BYTES;
3718 if (pMetadata->data.labelOrNote.stringLength > 0) {
3719 chunkSize += pMetadata->data.labelOrNote.stringLength + 1;
3721 } break;
3723 case drwav_metadata_type_list_labelled_cue_region:
3725 chunkSize += 8; /* for id and chunk size */
3726 chunkSize += DRWAV_LIST_LABELLED_TEXT_BYTES;
3728 if (pMetadata->data.labelledCueRegion.stringLength > 0) {
3729 chunkSize += pMetadata->data.labelledCueRegion.stringLength + 1;
3731 } break;
3733 case drwav_metadata_type_unknown:
3735 if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) {
3736 chunkSize += 8; /* for id and chunk size */
3737 chunkSize += pMetadata->data.unknown.dataSizeInBytes;
3739 } break;
3741 default: break;
3744 if ((chunkSize % 2) != 0) {
3745 chunkSize += 1;
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);
3753 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
3754 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
3755 drwav_uint32 subchunkSize = 0;
3757 switch (pMetadata->type)
3759 case drwav_metadata_type_list_label:
3760 case drwav_metadata_type_list_note:
3762 if (pMetadata->data.labelOrNote.stringLength > 0) {
3763 const char *pID = NULL;
3765 if (pMetadata->type == drwav_metadata_type_list_label) {
3766 pID = "labl";
3768 else if (pMetadata->type == drwav_metadata_type_list_note) {
3769 pID = "note";
3772 DRWAV_ASSERT(pID != NULL);
3773 DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL);
3775 subchunkSize = DRWAV_LIST_LABEL_OR_NOTE_BYTES;
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);
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');
3785 } break;
3787 case drwav_metadata_type_list_labelled_cue_region:
3789 subchunkSize = DRWAV_LIST_LABELLED_TEXT_BYTES;
3791 bytesWritten += drwav__write_or_count(pWav, "ltxt", 4);
3792 if (pMetadata->data.labelledCueRegion.stringLength > 0) {
3793 subchunkSize += pMetadata->data.labelledCueRegion.stringLength + 1;
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);
3804 if (pMetadata->data.labelledCueRegion.stringLength > 0) {
3805 DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL);
3807 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.pString, pMetadata->data.labelledCueRegion.stringLength);
3808 bytesWritten += drwav__write_or_count_byte(pWav, '\0');
3810 } break;
3812 case drwav_metadata_type_unknown:
3814 if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) {
3815 subchunkSize = pMetadata->data.unknown.dataSizeInBytes;
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);
3822 } break;
3824 default: break;
3827 if ((subchunkSize % 2) != 0) {
3828 bytesWritten += drwav__write_or_count_byte(pWav, 0);
3833 DRWAV_ASSERT((bytesWritten % 2) == 0);
3835 return bytesWritten;
3838 DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
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;
3845 return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */
3848 DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
3850 if (dataChunkSize <= 0xFFFFFFFFUL) {
3851 return (drwav_uint32)dataChunkSize;
3852 } else {
3853 return 0xFFFFFFFFUL;
3857 DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
3859 drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
3861 return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */
3864 DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
3866 return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
3869 DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize, drwav_metadata *metadata, drwav_uint32 numMetadata)
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;
3876 return chunkSize;
3879 DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
3881 return dataChunkSize;
3886 DRWAV_PRIVATE drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
3888 if (pWav == NULL || onWrite == NULL) {
3889 return DRWAV_FALSE;
3892 if (!isSequential && onSeek == NULL) {
3893 return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */
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;
3900 if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
3901 return DRWAV_FALSE;
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);
3910 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
3911 return DRWAV_FALSE; /* Invalid allocation callbacks. */
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;
3923 return DRWAV_TRUE;
3927 DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
3929 /* The function assumes drwav_preinit_write() was called beforehand. */
3931 size_t runningPos = 0;
3932 drwav_uint64 initialDataChunkSize = 0;
3933 drwav_uint64 chunkSizeFMT;
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.
3940 if (pWav->isSequentialWrite) {
3941 initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
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.
3947 if (pFormat->container == drwav_container_riff) {
3948 if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
3949 return DRWAV_FALSE; /* Not enough room to store every sample. */
3954 pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
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);
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. */
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". */
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);
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);
4007 /* TODO: is a 'fact' chunk required for DR_WAVE_FORMAT_IEEE_FLOAT? */
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);
4013 pWav->dataChunkDataPos = runningPos;
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. */
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;
4037 return DRWAV_TRUE;
4041 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)
4043 if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
4044 return DRWAV_FALSE;
4047 return drwav_init_write__internal(pWav, pFormat, 0); /* DRWAV_FALSE = Not Sequential */
4050 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)
4052 if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
4053 return DRWAV_FALSE;
4056 return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */
4059 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)
4061 if (pFormat == NULL) {
4062 return DRWAV_FALSE;
4065 return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
4068 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)
4070 if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
4071 return DRWAV_FALSE;
4074 pWav->pMetadata = pMetadata;
4075 pWav->metadataCount = metadataCount;
4077 return drwav_init_write__internal(pWav, pFormat, 0);
4081 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
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;
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. */
4099 return fileSizeBytes;
4103 #ifndef DR_WAV_NO_STDIO
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>
4107 DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e)
4109 switch (e)
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;
4509 DRWAV_PRIVATE drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
4511 #if defined(_MSC_VER) && _MSC_VER >= 1400
4512 errno_t err;
4513 #endif
4515 if (ppFile != NULL) {
4516 *ppFile = NULL; /* Safety. */
4519 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
4520 return DRWAV_INVALID_ARGS;
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);
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. */
4544 return result;
4546 #endif
4548 return DRWAV_SUCCESS;
4552 _wfopen() isn't always available in all compilation environments.
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).
4560 This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
4561 fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
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
4569 DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
4571 if (ppFile != NULL) {
4572 *ppFile = NULL; /* Safety. */
4575 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
4576 return DRWAV_INVALID_ARGS;
4579 #if defined(DRWAV_HAS_WFOPEN)
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);
4587 #else
4588 *ppFile = _wfopen(pFilePath, pOpenMode);
4589 if (*ppFile == NULL) {
4590 return drwav_result_from_errno(errno);
4592 #endif
4593 (void)pAllocationCallbacks;
4595 #else
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.
4602 mbstate_t mbs;
4603 size_t lenMB;
4604 const wchar_t* pFilePathTemp = pFilePath;
4605 char* pFilePathMB = NULL;
4606 char pOpenModeMB[32] = {0};
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);
4615 pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
4616 if (pFilePathMB == NULL) {
4617 return DRWAV_OUT_OF_MEMORY;
4620 pFilePathTemp = pFilePath;
4621 DRWAV_ZERO_OBJECT(&mbs);
4622 wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
4624 /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
4626 size_t i = 0;
4627 for (;;) {
4628 if (pOpenMode[i] == 0) {
4629 pOpenModeMB[i] = '\0';
4630 break;
4633 pOpenModeMB[i] = (char)pOpenMode[i];
4634 i += 1;
4638 *ppFile = fopen(pFilePathMB, pOpenModeMB);
4640 drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
4643 if (*ppFile == NULL) {
4644 return DRWAV_ERROR;
4646 #endif
4648 return DRWAV_SUCCESS;
4652 DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
4654 return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
4657 DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
4659 return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
4662 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
4664 return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
4667 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
4669 return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
4673 DRWAV_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)
4675 drwav_bool32 result;
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;
4683 pWav->allowedMetadataTypes = allowedMetadataTypes;
4685 result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
4686 if (result != DRWAV_TRUE) {
4687 fclose(pFile);
4688 return result;
4691 return DRWAV_TRUE;
4694 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)
4696 FILE* pFile;
4697 if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
4698 return DRWAV_FALSE;
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);
4705 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
4707 return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
4710 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)
4712 FILE* pFile;
4713 if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
4714 return DRWAV_FALSE;
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);
4721 DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
4723 FILE* pFile;
4724 if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
4725 return DRWAV_FALSE;
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);
4732 DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
4734 FILE* pFile;
4735 if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
4736 return DRWAV_FALSE;
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);
4744 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
4746 drwav_bool32 result;
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;
4754 result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
4755 if (result != DRWAV_TRUE) {
4756 fclose(pFile);
4757 return result;
4760 return DRWAV_TRUE;
4763 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
4765 FILE* pFile;
4766 if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
4767 return DRWAV_FALSE;
4770 /* This takes ownership of the FILE* object. */
4771 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
4774 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
4776 FILE* pFile;
4777 if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
4778 return DRWAV_FALSE;
4781 /* This takes ownership of the FILE* object. */
4782 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
4785 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
4787 return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
4790 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)
4792 return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
4795 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)
4797 if (pFormat == NULL) {
4798 return DRWAV_FALSE;
4801 return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
4804 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)
4806 return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
4809 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)
4811 return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
4814 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)
4816 if (pFormat == NULL) {
4817 return DRWAV_FALSE;
4820 return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
4822 #endif /* DR_WAV_NO_STDIO */
4825 DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
4827 drwav* pWav = (drwav*)pUserData;
4828 size_t bytesRemaining;
4830 DRWAV_ASSERT(pWav != NULL);
4831 DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
4833 bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
4834 if (bytesToRead > bytesRemaining) {
4835 bytesToRead = bytesRemaining;
4838 if (bytesToRead > 0) {
4839 DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
4840 pWav->memoryStream.currentReadPos += bytesToRead;
4843 return bytesToRead;
4846 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
4848 drwav* pWav = (drwav*)pUserData;
4849 DRWAV_ASSERT(pWav != NULL);
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. */
4856 } else {
4857 if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
4858 return DRWAV_FALSE; /* Trying to seek too far backwards. */
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. */
4872 return DRWAV_TRUE;
4875 DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
4877 drwav* pWav = (drwav*)pUserData;
4878 size_t bytesRemaining;
4880 DRWAV_ASSERT(pWav != NULL);
4881 DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
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;
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;
4894 pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
4895 if (pNewData == NULL) {
4896 return 0;
4899 *pWav->memoryStreamWrite.ppData = pNewData;
4900 pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
4903 DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
4905 pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
4906 if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
4907 pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
4910 *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
4912 return bytesToWrite;
4915 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
4917 drwav* pWav = (drwav*)pUserData;
4918 DRWAV_ASSERT(pWav != NULL);
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. */
4925 } else {
4926 if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
4927 offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */
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. */
4941 return DRWAV_TRUE;
4944 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
4946 return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
4949 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)
4951 if (data == NULL || dataSize == 0) {
4952 return DRWAV_FALSE;
4955 if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
4956 return DRWAV_FALSE;
4959 pWav->memoryStream.data = (const drwav_uint8*)data;
4960 pWav->memoryStream.dataSize = dataSize;
4961 pWav->memoryStream.currentReadPos = 0;
4963 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
4966 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)
4968 if (data == NULL || dataSize == 0) {
4969 return DRWAV_FALSE;
4972 if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
4973 return DRWAV_FALSE;
4976 pWav->memoryStream.data = (const drwav_uint8*)data;
4977 pWav->memoryStream.dataSize = dataSize;
4978 pWav->memoryStream.currentReadPos = 0;
4980 pWav->allowedMetadataTypes = drwav_metadata_type_all_including_unknown;
4982 return drwav_init__internal(pWav, NULL, NULL, flags);
4986 DRWAV_PRIVATE drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
4988 if (ppData == NULL || pDataSize == NULL) {
4989 return DRWAV_FALSE;
4992 *ppData = NULL; /* Important because we're using realloc()! */
4993 *pDataSize = 0;
4995 if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
4996 return DRWAV_FALSE;
4999 pWav->memoryStreamWrite.ppData = ppData;
5000 pWav->memoryStreamWrite.pDataSize = pDataSize;
5001 pWav->memoryStreamWrite.dataSize = 0;
5002 pWav->memoryStreamWrite.dataCapacity = 0;
5003 pWav->memoryStreamWrite.currentWritePos = 0;
5005 return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
5008 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)
5010 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
5013 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)
5015 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
5018 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)
5020 if (pFormat == NULL) {
5021 return DRWAV_FALSE;
5024 return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
5029 DRWAV_API drwav_result drwav_uninit(drwav* pWav)
5031 drwav_result result = DRWAV_SUCCESS;
5033 if (pWav == NULL) {
5034 return DRWAV_INVALID_ARGS;
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.
5042 if (pWav->onWrite != NULL) {
5043 drwav_uint32 paddingSize = 0;
5045 /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */
5046 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
5047 paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
5048 } else {
5049 paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
5052 if (paddingSize > 0) {
5053 drwav_uint64 paddingData = 0;
5054 drwav__write(pWav, &paddingData, paddingSize); /* Byte order does not matter for this. */
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.
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);
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);
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);
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);
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;
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);
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);
5104 /* Validation for sequential mode. */
5105 if (pWav->isSequentialWrite) {
5106 if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
5107 result = DRWAV_INVALID_FILE;
5110 } else {
5111 if (pWav->pMetadata != NULL) {
5112 pWav->allocationCallbacks.onFree(pWav->pMetadata, pWav->allocationCallbacks.pUserData);
5116 #ifndef DR_WAV_NO_STDIO
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.
5121 if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
5122 fclose((FILE*)pWav->pUserData);
5124 #endif
5126 return result;
5131 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
5133 size_t bytesRead;
5135 if (pWav == NULL || bytesToRead == 0) {
5136 return 0; /* Invalid args. */
5139 if (bytesToRead > pWav->bytesRemaining) {
5140 bytesToRead = (size_t)pWav->bytesRemaining;
5143 if (bytesToRead == 0) {
5144 return 0; /* At end. */
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;
5158 if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) {
5159 break;
5162 bytesRead += bytesToSeek;
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);
5174 bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek);
5175 bytesRead += bytesSeeked;
5177 if (bytesSeeked < bytesToSeek) {
5178 break; /* Reached the end. */
5183 pWav->readCursorInPCMFrames += bytesRead / drwav_get_bytes_per_pcm_frame(pWav);
5185 pWav->bytesRemaining -= bytesRead;
5186 return bytesRead;
5191 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
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. */
5196 if (pWav == NULL || framesToRead == 0) {
5197 return 0;
5200 /* Cannot use this function for compressed formats. */
5201 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
5202 return 0;
5205 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5206 if (bytesPerFrame == 0) {
5207 return 0;
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. */
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.
5220 if (bytesToRead == 0) {
5221 return 0;
5224 return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame;
5227 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
5229 drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
5231 if (pBufferOut != NULL) {
5232 drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag);
5235 return framesRead;
5238 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
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);
5249 DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
5251 if (pWav->onWrite != NULL) {
5252 return DRWAV_FALSE; /* No seeking in write mode. */
5255 if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
5256 return DRWAV_FALSE;
5259 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
5260 /* Cached data needs to be cleared for compressed formats. */
5261 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
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. */
5270 pWav->readCursorInPCMFrames = 0;
5271 pWav->bytesRemaining = pWav->dataChunkDataSize;
5273 return DRWAV_TRUE;
5276 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex)
5278 /* Seeking should be compatible with wave files > 2GB. */
5280 if (pWav == NULL || pWav->onSeek == NULL) {
5281 return DRWAV_FALSE;
5284 /* No seeking in write mode. */
5285 if (pWav->onWrite != NULL) {
5286 return DRWAV_FALSE;
5289 /* If there are no samples, just return DRWAV_TRUE without doing anything. */
5290 if (pWav->totalPCMFrameCount == 0) {
5291 return DRWAV_TRUE;
5294 /* Make sure the sample is clamped. */
5295 if (targetFrameIndex >= pWav->totalPCMFrameCount) {
5296 targetFrameIndex = pWav->totalPCMFrameCount - 1;
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.
5303 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
5304 /* TODO: This can be optimized. */
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.
5310 if (targetFrameIndex < pWav->readCursorInPCMFrames) {
5311 if (!drwav_seek_to_first_pcm_frame(pWav)) {
5312 return DRWAV_FALSE;
5316 if (targetFrameIndex > pWav->readCursorInPCMFrames) {
5317 drwav_uint64 offsetInFrames = targetFrameIndex - pWav->readCursorInPCMFrames;
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;
5327 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
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. */
5335 if (framesRead != framesToRead) {
5336 return DRWAV_FALSE;
5339 offsetInFrames -= framesRead;
5342 } else {
5343 drwav_uint64 totalSizeInBytes;
5344 drwav_uint64 currentBytePos;
5345 drwav_uint64 targetBytePos;
5346 drwav_uint64 offset;
5348 totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav);
5349 DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);
5351 currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
5352 targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav);
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;
5362 offset = targetBytePos;
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;
5371 pWav->readCursorInPCMFrames += offset32 / drwav_get_bytes_per_pcm_frame(pWav);
5372 pWav->bytesRemaining -= offset32;
5373 offset -= offset32;
5377 return DRWAV_TRUE;
5380 DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor)
5382 if (pCursor == NULL) {
5383 return DRWAV_INVALID_ARGS;
5386 *pCursor = 0; /* Safety. */
5388 if (pWav == NULL) {
5389 return DRWAV_INVALID_ARGS;
5392 *pCursor = pWav->readCursorInPCMFrames;
5394 return DRWAV_SUCCESS;
5397 DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength)
5399 if (pLength == NULL) {
5400 return DRWAV_INVALID_ARGS;
5403 *pLength = 0; /* Safety. */
5405 if (pWav == NULL) {
5406 return DRWAV_INVALID_ARGS;
5409 *pLength = pWav->totalPCMFrameCount;
5411 return DRWAV_SUCCESS;
5415 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
5417 size_t bytesWritten;
5419 if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
5420 return 0;
5423 bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
5424 pWav->dataChunkDataSize += bytesWritten;
5426 return bytesWritten;
5429 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
5431 drwav_uint64 bytesToWrite;
5432 drwav_uint64 bytesWritten;
5433 const drwav_uint8* pRunningData;
5435 if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
5436 return 0;
5439 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
5440 if (bytesToWrite > DRWAV_SIZE_MAX) {
5441 return 0;
5444 bytesWritten = 0;
5445 pRunningData = (const drwav_uint8*)pData;
5447 while (bytesToWrite > 0) {
5448 size_t bytesJustWritten;
5449 drwav_uint64 bytesToWriteThisIteration;
5451 bytesToWriteThisIteration = bytesToWrite;
5452 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */
5454 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData);
5455 if (bytesJustWritten == 0) {
5456 break;
5459 bytesToWrite -= bytesJustWritten;
5460 bytesWritten += bytesJustWritten;
5461 pRunningData += bytesJustWritten;
5464 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
5467 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
5469 drwav_uint64 bytesToWrite;
5470 drwav_uint64 bytesWritten;
5471 drwav_uint32 bytesPerSample;
5472 const drwav_uint8* pRunningData;
5474 if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
5475 return 0;
5478 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
5479 if (bytesToWrite > DRWAV_SIZE_MAX) {
5480 return 0;
5483 bytesWritten = 0;
5484 pRunningData = (const drwav_uint8*)pData;
5486 bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels;
5488 while (bytesToWrite > 0) {
5489 drwav_uint8 temp[4096];
5490 drwav_uint32 sampleCount;
5491 size_t bytesJustWritten;
5492 drwav_uint64 bytesToWriteThisIteration;
5494 bytesToWriteThisIteration = bytesToWrite;
5495 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */
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.
5501 sampleCount = sizeof(temp)/bytesPerSample;
5503 if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) {
5504 bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample;
5507 DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration);
5508 drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag);
5510 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp);
5511 if (bytesJustWritten == 0) {
5512 break;
5515 bytesToWrite -= bytesJustWritten;
5516 bytesWritten += bytesJustWritten;
5517 pRunningData += bytesJustWritten;
5520 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
5523 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
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);
5533 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
5535 drwav_uint64 totalFramesRead = 0;
5537 DRWAV_ASSERT(pWav != NULL);
5538 DRWAV_ASSERT(framesToRead > 0);
5540 /* TODO: Lots of room for optimization here. */
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. */
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;
5553 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
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;
5568 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
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);
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;
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];
5595 pBufferOut += pWav->channels;
5598 framesToRead -= 1;
5599 totalFramesRead += 1;
5600 pWav->readCursorInPCMFrames += 1;
5601 pWav->msadpcm.cachedFrameCount -= 1;
5604 if (framesToRead == 0) {
5605 break;
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.
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
5621 static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
5622 static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
5624 drwav_uint8 nibbles;
5625 drwav_int32 nibble0;
5626 drwav_int32 nibble1;
5628 if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
5629 return totalFramesRead;
5631 pWav->msadpcm.bytesRemainingInBlock -= 1;
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; }
5637 if (pWav->channels == 1) {
5638 /* Mono. */
5639 drwav_int32 newSample0;
5640 drwav_int32 newSample1;
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);
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;
5651 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
5652 pWav->msadpcm.prevFrames[0][1] = newSample0;
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);
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;
5664 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
5665 pWav->msadpcm.prevFrames[0][1] = newSample1;
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;
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);
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;
5686 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
5687 pWav->msadpcm.prevFrames[0][1] = newSample0;
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);
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;
5700 pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
5701 pWav->msadpcm.prevFrames[1][1] = newSample1;
5703 pWav->msadpcm.cachedFrames[2] = newSample0;
5704 pWav->msadpcm.cachedFrames[3] = newSample1;
5705 pWav->msadpcm.cachedFrameCount = 1;
5711 return totalFramesRead;
5715 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
5717 drwav_uint64 totalFramesRead = 0;
5718 drwav_uint32 iChannel;
5720 static drwav_int32 indexTable[16] = {
5721 -1, -1, -1, -1, 2, 4, 6, 8,
5722 -1, -1, -1, -1, 2, 4, 6, 8
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
5737 DRWAV_ASSERT(pWav != NULL);
5738 DRWAV_ASSERT(framesToRead > 0);
5740 /* TODO: Lots of room for optimization here. */
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. */
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;
5753 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
5755 if (header[2] >= drwav_countof(stepTable)) {
5756 pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
5757 pWav->ima.bytesRemainingInBlock = 0;
5758 return totalFramesRead; /* Invalid data. */
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;
5771 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
5773 if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
5774 pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
5775 pWav->ima.bytesRemainingInBlock = 0;
5776 return totalFramesRead; /* Invalid data. */
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];
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;
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];
5797 pBufferOut += pWav->channels;
5800 framesToRead -= 1;
5801 totalFramesRead += 1;
5802 pWav->readCursorInPCMFrames += 1;
5803 pWav->ima.cachedFrameCount -= 1;
5806 if (framesToRead == 0) {
5807 break;
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.
5814 if (pWav->ima.cachedFrameCount == 0) {
5815 if (pWav->ima.bytesRemainingInBlock == 0) {
5816 continue;
5817 } else {
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.
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;
5830 pWav->ima.bytesRemainingInBlock -= 4;
5832 for (iByte = 0; iByte < 4; ++iByte) {
5833 drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
5834 drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
5836 drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]];
5837 drwav_int32 predictor = pWav->ima.predictor[iChannel];
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;
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;
5851 step = stepTable[pWav->ima.stepIndex[iChannel]];
5852 predictor = pWav->ima.predictor[iChannel];
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;
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;
5870 return totalFramesRead;
5874 #ifndef DR_WAV_NO_CONVERSION_API
5875 static 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
5894 static 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
5913 static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
5915 return (short)g_drwavAlawTable[sampleIn];
5918 static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
5920 return (short)g_drwavMulawTable[sampleIn];
5925 DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
5927 unsigned int i;
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;
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];
5941 return;
5943 if (bytesPerSample == 3) {
5944 drwav_s24_to_s16(pOut, pIn, totalSampleCount);
5945 return;
5947 if (bytesPerSample == 4) {
5948 drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
5949 return;
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;
5960 /* Generic, slow converter. */
5961 for (i = 0; i < totalSampleCount; ++i) {
5962 drwav_uint64 sample = 0;
5963 unsigned int shift = (8 - bytesPerSample) * 8;
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;
5972 pIn += j;
5973 *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
5977 DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
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;
5992 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
5994 drwav_uint64 totalFramesRead;
5995 drwav_uint8 sampleData[4096];
5996 drwav_uint32 bytesPerFrame;
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);
6003 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6004 if (bytesPerFrame == 0) {
6005 return 0;
6008 totalFramesRead = 0;
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;
6016 drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
6018 pBufferOut += framesRead*pWav->channels;
6019 framesToRead -= framesRead;
6020 totalFramesRead += framesRead;
6023 return totalFramesRead;
6026 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6028 drwav_uint64 totalFramesRead;
6029 drwav_uint8 sampleData[4096];
6030 drwav_uint32 bytesPerFrame;
6032 if (pBufferOut == NULL) {
6033 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6036 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6037 if (bytesPerFrame == 0) {
6038 return 0;
6041 totalFramesRead = 0;
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;
6049 drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
6051 pBufferOut += framesRead*pWav->channels;
6052 framesToRead -= framesRead;
6053 totalFramesRead += framesRead;
6056 return totalFramesRead;
6059 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6061 drwav_uint64 totalFramesRead;
6062 drwav_uint8 sampleData[4096];
6063 drwav_uint32 bytesPerFrame;
6065 if (pBufferOut == NULL) {
6066 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6069 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6070 if (bytesPerFrame == 0) {
6071 return 0;
6074 totalFramesRead = 0;
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;
6082 drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
6084 pBufferOut += framesRead*pWav->channels;
6085 framesToRead -= framesRead;
6086 totalFramesRead += framesRead;
6089 return totalFramesRead;
6092 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6094 drwav_uint64 totalFramesRead;
6095 drwav_uint8 sampleData[4096];
6096 drwav_uint32 bytesPerFrame;
6098 if (pBufferOut == NULL) {
6099 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6102 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6103 if (bytesPerFrame == 0) {
6104 return 0;
6107 totalFramesRead = 0;
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;
6115 drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
6117 pBufferOut += framesRead*pWav->channels;
6118 framesToRead -= framesRead;
6119 totalFramesRead += framesRead;
6122 return totalFramesRead;
6125 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6127 if (pWav == NULL || framesToRead == 0) {
6128 return 0;
6131 if (pBufferOut == NULL) {
6132 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
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;
6140 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
6141 return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut);
6144 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
6145 return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut);
6148 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
6149 return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut);
6152 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
6153 return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut);
6156 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
6157 return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut);
6160 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
6161 return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut);
6164 return 0;
6167 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
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);
6174 return framesRead;
6177 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
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);
6184 return framesRead;
6188 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
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;
6200 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
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;
6211 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
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;
6222 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
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;
6237 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
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;
6252 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
6254 size_t i;
6255 for (i = 0; i < sampleCount; ++i) {
6256 pOut[i] = drwav__alaw_to_s16(pIn[i]);
6260 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
6262 size_t i;
6263 for (i = 0; i < sampleCount; ++i) {
6264 pOut[i] = drwav__mulaw_to_s16(pIn[i]);
6270 DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
6272 unsigned int i;
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;
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;
6285 if (bytesPerSample == 3) {
6286 drwav_s24_to_f32(pOut, pIn, sampleCount);
6287 return;
6289 if (bytesPerSample == 4) {
6290 drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
6291 return;
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;
6302 /* Generic, slow converter. */
6303 for (i = 0; i < sampleCount; ++i) {
6304 drwav_uint64 sample = 0;
6305 unsigned int shift = (8 - bytesPerSample) * 8;
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;
6314 pIn += j;
6315 *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
6319 DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
6321 if (bytesPerSample == 4) {
6322 unsigned int i;
6323 for (i = 0; i < sampleCount; ++i) {
6324 *pOut++ = ((const float*)pIn)[i];
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;
6338 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
6340 drwav_uint64 totalFramesRead;
6341 drwav_uint8 sampleData[4096];
6342 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6344 if (bytesPerFrame == 0) {
6345 return 0;
6348 totalFramesRead = 0;
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;
6356 drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels);
6358 pBufferOut += framesRead*pWav->channels;
6359 framesToRead -= framesRead;
6360 totalFramesRead += framesRead;
6363 return totalFramesRead;
6366 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
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.
6372 drwav_uint64 totalFramesRead = 0;
6373 drwav_int16 samples16[2048];
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;
6381 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
6383 pBufferOut += framesRead*pWav->channels;
6384 framesToRead -= framesRead;
6385 totalFramesRead += framesRead;
6388 return totalFramesRead;
6391 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
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.
6397 drwav_uint64 totalFramesRead = 0;
6398 drwav_int16 samples16[2048];
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;
6406 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
6408 pBufferOut += framesRead*pWav->channels;
6409 framesToRead -= framesRead;
6410 totalFramesRead += framesRead;
6413 return totalFramesRead;
6416 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
6418 drwav_uint64 totalFramesRead;
6419 drwav_uint8 sampleData[4096];
6420 drwav_uint32 bytesPerFrame;
6422 /* Fast path. */
6423 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) {
6424 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
6427 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6428 if (bytesPerFrame == 0) {
6429 return 0;
6432 totalFramesRead = 0;
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;
6440 drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
6442 pBufferOut += framesRead*pWav->channels;
6443 framesToRead -= framesRead;
6444 totalFramesRead += framesRead;
6447 return totalFramesRead;
6450 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
6452 drwav_uint64 totalFramesRead;
6453 drwav_uint8 sampleData[4096];
6454 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6456 if (bytesPerFrame == 0) {
6457 return 0;
6460 totalFramesRead = 0;
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;
6468 drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
6470 pBufferOut += framesRead*pWav->channels;
6471 framesToRead -= framesRead;
6472 totalFramesRead += framesRead;
6475 return totalFramesRead;
6478 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
6480 drwav_uint64 totalFramesRead;
6481 drwav_uint8 sampleData[4096];
6482 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6484 if (bytesPerFrame == 0) {
6485 return 0;
6488 totalFramesRead = 0;
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;
6496 drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
6498 pBufferOut += framesRead*pWav->channels;
6499 framesToRead -= framesRead;
6500 totalFramesRead += framesRead;
6503 return totalFramesRead;
6506 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
6508 if (pWav == NULL || framesToRead == 0) {
6509 return 0;
6512 if (pBufferOut == NULL) {
6513 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
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;
6521 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
6522 return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut);
6525 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
6526 return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut);
6529 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
6530 return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut);
6533 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
6534 return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut);
6537 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
6538 return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut);
6541 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
6542 return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut);
6545 return 0;
6548 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
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);
6555 return framesRead;
6558 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
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);
6565 return framesRead;
6569 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
6571 size_t i;
6573 if (pOut == NULL || pIn == NULL) {
6574 return;
6577 #ifdef DR_WAV_LIBSNDFILE_COMPAT
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.
6584 for (i = 0; i < sampleCount; ++i) {
6585 *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
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 */
6593 *pOut++ = x;
6595 #endif
6598 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
6600 size_t i;
6602 if (pOut == NULL || pIn == NULL) {
6603 return;
6606 for (i = 0; i < sampleCount; ++i) {
6607 *pOut++ = pIn[i] * 0.000030517578125f;
6611 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
6613 size_t i;
6615 if (pOut == NULL || pIn == NULL) {
6616 return;
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);
6625 x = (double)((drwav_int32)(a | b | c) >> 8);
6626 *pOut++ = (float)(x * 0.00000011920928955078125);
6630 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
6632 size_t i;
6633 if (pOut == NULL || pIn == NULL) {
6634 return;
6637 for (i = 0; i < sampleCount; ++i) {
6638 *pOut++ = (float)(pIn[i] / 2147483648.0);
6642 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
6644 size_t i;
6646 if (pOut == NULL || pIn == NULL) {
6647 return;
6650 for (i = 0; i < sampleCount; ++i) {
6651 *pOut++ = (float)pIn[i];
6655 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
6657 size_t i;
6659 if (pOut == NULL || pIn == NULL) {
6660 return;
6663 for (i = 0; i < sampleCount; ++i) {
6664 *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
6668 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
6670 size_t i;
6672 if (pOut == NULL || pIn == NULL) {
6673 return;
6676 for (i = 0; i < sampleCount; ++i) {
6677 *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
6683 DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
6685 unsigned int i;
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;
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;
6698 if (bytesPerSample == 3) {
6699 drwav_s24_to_s32(pOut, pIn, totalSampleCount);
6700 return;
6702 if (bytesPerSample == 4) {
6703 for (i = 0; i < totalSampleCount; ++i) {
6704 *pOut++ = ((const drwav_int32*)pIn)[i];
6706 return;
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;
6717 /* Generic, slow converter. */
6718 for (i = 0; i < totalSampleCount; ++i) {
6719 drwav_uint64 sample = 0;
6720 unsigned int shift = (8 - bytesPerSample) * 8;
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;
6729 pIn += j;
6730 *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
6734 DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
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;
6750 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
6752 drwav_uint64 totalFramesRead;
6753 drwav_uint8 sampleData[4096];
6754 drwav_uint32 bytesPerFrame;
6756 /* Fast path. */
6757 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) {
6758 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
6761 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6762 if (bytesPerFrame == 0) {
6763 return 0;
6766 totalFramesRead = 0;
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;
6774 drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
6776 pBufferOut += framesRead*pWav->channels;
6777 framesToRead -= framesRead;
6778 totalFramesRead += framesRead;
6781 return totalFramesRead;
6784 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
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.
6790 drwav_uint64 totalFramesRead = 0;
6791 drwav_int16 samples16[2048];
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;
6799 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
6801 pBufferOut += framesRead*pWav->channels;
6802 framesToRead -= framesRead;
6803 totalFramesRead += framesRead;
6806 return totalFramesRead;
6809 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
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.
6815 drwav_uint64 totalFramesRead = 0;
6816 drwav_int16 samples16[2048];
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;
6824 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
6826 pBufferOut += framesRead*pWav->channels;
6827 framesToRead -= framesRead;
6828 totalFramesRead += framesRead;
6831 return totalFramesRead;
6834 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
6836 drwav_uint64 totalFramesRead;
6837 drwav_uint8 sampleData[4096];
6838 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6840 if (bytesPerFrame == 0) {
6841 return 0;
6844 totalFramesRead = 0;
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;
6852 drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
6854 pBufferOut += framesRead*pWav->channels;
6855 framesToRead -= framesRead;
6856 totalFramesRead += framesRead;
6859 return totalFramesRead;
6862 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
6864 drwav_uint64 totalFramesRead;
6865 drwav_uint8 sampleData[4096];
6866 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6868 if (bytesPerFrame == 0) {
6869 return 0;
6872 totalFramesRead = 0;
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;
6880 drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
6882 pBufferOut += framesRead*pWav->channels;
6883 framesToRead -= framesRead;
6884 totalFramesRead += framesRead;
6887 return totalFramesRead;
6890 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
6892 drwav_uint64 totalFramesRead;
6893 drwav_uint8 sampleData[4096];
6894 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6896 if (bytesPerFrame == 0) {
6897 return 0;
6900 totalFramesRead = 0;
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;
6908 drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
6910 pBufferOut += framesRead*pWav->channels;
6911 framesToRead -= framesRead;
6912 totalFramesRead += framesRead;
6915 return totalFramesRead;
6918 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
6920 if (pWav == NULL || framesToRead == 0) {
6921 return 0;
6924 if (pBufferOut == NULL) {
6925 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
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;
6933 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
6934 return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut);
6937 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
6938 return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut);
6941 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
6942 return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut);
6945 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
6946 return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut);
6949 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
6950 return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut);
6953 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
6954 return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut);
6957 return 0;
6960 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
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);
6967 return framesRead;
6970 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
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);
6977 return framesRead;
6981 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
6983 size_t i;
6985 if (pOut == NULL || pIn == NULL) {
6986 return;
6989 for (i = 0; i < sampleCount; ++i) {
6990 *pOut++ = ((int)pIn[i] - 128) << 24;
6994 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
6996 size_t i;
6998 if (pOut == NULL || pIn == NULL) {
6999 return;
7002 for (i = 0; i < sampleCount; ++i) {
7003 *pOut++ = pIn[i] << 16;
7007 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
7009 size_t i;
7011 if (pOut == NULL || pIn == NULL) {
7012 return;
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];
7020 drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
7021 *pOut++ = sample32;
7025 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
7027 size_t i;
7029 if (pOut == NULL || pIn == NULL) {
7030 return;
7033 for (i = 0; i < sampleCount; ++i) {
7034 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
7038 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
7040 size_t i;
7042 if (pOut == NULL || pIn == NULL) {
7043 return;
7046 for (i = 0; i < sampleCount; ++i) {
7047 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
7051 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
7053 size_t i;
7055 if (pOut == NULL || pIn == NULL) {
7056 return;
7059 for (i = 0; i < sampleCount; ++i) {
7060 *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
7064 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
7066 size_t i;
7068 if (pOut == NULL || pIn == NULL) {
7069 return;
7072 for (i= 0; i < sampleCount; ++i) {
7073 *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
7079 DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
7081 drwav_uint64 sampleDataSize;
7082 drwav_int16* pSampleData;
7083 drwav_uint64 framesRead;
7085 DRWAV_ASSERT(pWav != NULL);
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. */
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. */
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. */
7106 drwav_uninit(pWav);
7108 if (sampleRate) {
7109 *sampleRate = pWav->sampleRate;
7111 if (channels) {
7112 *channels = pWav->channels;
7114 if (totalFrameCount) {
7115 *totalFrameCount = pWav->totalPCMFrameCount;
7118 return pSampleData;
7121 DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
7123 drwav_uint64 sampleDataSize;
7124 float* pSampleData;
7125 drwav_uint64 framesRead;
7127 DRWAV_ASSERT(pWav != NULL);
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. */
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. */
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. */
7148 drwav_uninit(pWav);
7150 if (sampleRate) {
7151 *sampleRate = pWav->sampleRate;
7153 if (channels) {
7154 *channels = pWav->channels;
7156 if (totalFrameCount) {
7157 *totalFrameCount = pWav->totalPCMFrameCount;
7160 return pSampleData;
7163 DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
7165 drwav_uint64 sampleDataSize;
7166 drwav_int32* pSampleData;
7167 drwav_uint64 framesRead;
7169 DRWAV_ASSERT(pWav != NULL);
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. */
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. */
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. */
7190 drwav_uninit(pWav);
7192 if (sampleRate) {
7193 *sampleRate = pWav->sampleRate;
7195 if (channels) {
7196 *channels = pWav->channels;
7198 if (totalFrameCount) {
7199 *totalFrameCount = pWav->totalPCMFrameCount;
7202 return pSampleData;
7207 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)
7209 drwav wav;
7211 if (channelsOut) {
7212 *channelsOut = 0;
7214 if (sampleRateOut) {
7215 *sampleRateOut = 0;
7217 if (totalFrameCountOut) {
7218 *totalFrameCountOut = 0;
7221 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
7222 return NULL;
7225 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7228 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)
7230 drwav wav;
7232 if (channelsOut) {
7233 *channelsOut = 0;
7235 if (sampleRateOut) {
7236 *sampleRateOut = 0;
7238 if (totalFrameCountOut) {
7239 *totalFrameCountOut = 0;
7242 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
7243 return NULL;
7246 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7249 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)
7251 drwav wav;
7253 if (channelsOut) {
7254 *channelsOut = 0;
7256 if (sampleRateOut) {
7257 *sampleRateOut = 0;
7259 if (totalFrameCountOut) {
7260 *totalFrameCountOut = 0;
7263 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
7264 return NULL;
7267 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7270 #ifndef DR_WAV_NO_STDIO
7271 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)
7273 drwav wav;
7275 if (channelsOut) {
7276 *channelsOut = 0;
7278 if (sampleRateOut) {
7279 *sampleRateOut = 0;
7281 if (totalFrameCountOut) {
7282 *totalFrameCountOut = 0;
7285 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
7286 return NULL;
7289 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7292 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)
7294 drwav wav;
7296 if (channelsOut) {
7297 *channelsOut = 0;
7299 if (sampleRateOut) {
7300 *sampleRateOut = 0;
7302 if (totalFrameCountOut) {
7303 *totalFrameCountOut = 0;
7306 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
7307 return NULL;
7310 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7313 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)
7315 drwav wav;
7317 if (channelsOut) {
7318 *channelsOut = 0;
7320 if (sampleRateOut) {
7321 *sampleRateOut = 0;
7323 if (totalFrameCountOut) {
7324 *totalFrameCountOut = 0;
7327 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
7328 return NULL;
7331 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7335 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)
7337 drwav wav;
7339 if (sampleRateOut) {
7340 *sampleRateOut = 0;
7342 if (channelsOut) {
7343 *channelsOut = 0;
7345 if (totalFrameCountOut) {
7346 *totalFrameCountOut = 0;
7349 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
7350 return NULL;
7353 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7356 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)
7358 drwav wav;
7360 if (sampleRateOut) {
7361 *sampleRateOut = 0;
7363 if (channelsOut) {
7364 *channelsOut = 0;
7366 if (totalFrameCountOut) {
7367 *totalFrameCountOut = 0;
7370 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
7371 return NULL;
7374 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7377 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)
7379 drwav wav;
7381 if (sampleRateOut) {
7382 *sampleRateOut = 0;
7384 if (channelsOut) {
7385 *channelsOut = 0;
7387 if (totalFrameCountOut) {
7388 *totalFrameCountOut = 0;
7391 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
7392 return NULL;
7395 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7397 #endif
7399 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)
7401 drwav wav;
7403 if (channelsOut) {
7404 *channelsOut = 0;
7406 if (sampleRateOut) {
7407 *sampleRateOut = 0;
7409 if (totalFrameCountOut) {
7410 *totalFrameCountOut = 0;
7413 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
7414 return NULL;
7417 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7420 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)
7422 drwav wav;
7424 if (channelsOut) {
7425 *channelsOut = 0;
7427 if (sampleRateOut) {
7428 *sampleRateOut = 0;
7430 if (totalFrameCountOut) {
7431 *totalFrameCountOut = 0;
7434 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
7435 return NULL;
7438 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7441 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)
7443 drwav wav;
7445 if (channelsOut) {
7446 *channelsOut = 0;
7448 if (sampleRateOut) {
7449 *sampleRateOut = 0;
7451 if (totalFrameCountOut) {
7452 *totalFrameCountOut = 0;
7455 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
7456 return NULL;
7459 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
7461 #endif /* DR_WAV_NO_CONVERSION_API */
7464 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
7466 if (pAllocationCallbacks != NULL) {
7467 drwav__free_from_callbacks(p, pAllocationCallbacks);
7468 } else {
7469 drwav__free_default(p, NULL);
7473 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data)
7475 return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8);
7478 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data)
7480 return (drwav_int16)drwav_bytes_to_u16(data);
7483 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data)
7485 return ((drwav_uint32)data[0] << 0) | ((drwav_uint32)data[1] << 8) | ((drwav_uint32)data[2] << 16) | ((drwav_uint32)data[3] << 24);
7488 DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data)
7490 union {
7491 drwav_uint32 u32;
7492 float f32;
7493 } value;
7495 value.u32 = drwav_bytes_to_u32(data);
7496 return value.f32;
7499 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data)
7501 return (drwav_int32)drwav_bytes_to_u32(data);
7504 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data)
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);
7511 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data)
7513 return (drwav_int64)drwav_bytes_to_u64(data);
7517 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
7519 int i;
7520 for (i = 0; i < 16; i += 1) {
7521 if (a[i] != b[i]) {
7522 return DRWAV_FALSE;
7526 return DRWAV_TRUE;
7529 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
7531 return
7532 a[0] == b[0] &&
7533 a[1] == b[1] &&
7534 a[2] == b[2] &&
7535 a[3] == b[3];
7538 #endif /* dr_wav_c */
7539 #endif /* DR_WAV_IMPLEMENTATION */
7542 REVISION HISTORY
7543 ================
7544 v0.13.2 - 2021-10-02
7545 - Fix a possible buffer overflow when reading from compressed formats.
7547 v0.13.1 - 2021-07-31
7548 - Fix platform detection for ARM64.
7550 v0.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.
7561 v0.12.20 - 2021-06-11
7562 - Fix some undefined behavior.
7564 v0.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.
7568 v0.12.18 - 2021-01-31
7569 - Clean up some static analysis warnings.
7571 v0.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.
7576 v0.12.16 - 2020-12-02
7577 - Fix a bug when trying to read more bytes than can fit in a size_t.
7579 v0.12.15 - 2020-11-21
7580 - Fix compilation with OpenWatcom.
7582 v0.12.14 - 2020-11-13
7583 - Minor code clean up.
7585 v0.12.13 - 2020-11-01
7586 - Improve compiler support for older versions of GCC.
7588 v0.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.
7592 v0.12.11 - 2020-09-08
7593 - Fix a compilation error on older compilers.
7595 v0.12.10 - 2020-08-24
7596 - Fix a bug when seeking with ADPCM formats.
7598 v0.12.9 - 2020-08-02
7599 - Simplify sized types.
7601 v0.12.8 - 2020-07-25
7602 - Fix a compilation warning.
7604 v0.12.7 - 2020-07-15
7605 - Fix some bugs on big-endian architectures.
7606 - Fix an error in s24 to f32 conversion.
7608 v0.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.
7613 v0.12.5 - 2020-05-27
7614 - Minor documentation fix.
7616 v0.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()
7626 v0.12.3 - 2020-04-30
7627 - Fix compilation errors with VC6.
7629 v0.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.
7632 v0.12.1 - 2020-04-13
7633 - Fix some pedantic warnings.
7635 v0.12.0 - 2020-04-04
7636 - API CHANGE: Add container and format parameters to the chunk callback.
7637 - Minor documentation updates.
7639 v0.11.5 - 2020-03-07
7640 - Fix compilation error with Visual Studio .NET 2003.
7642 v0.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.
7646 v0.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.
7650 v0.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.
7656 v0.11.1 - 2019-10-07
7657 - Internal code clean up.
7659 v0.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()
7726 v0.10.1 - 2019-08-31
7727 - Correctly handle partial trailing ADPCM blocks.
7729 v0.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.
7758 v0.9.2 - 2019-05-21
7759 - Fix warnings.
7761 v0.9.1 - 2019-05-05
7762 - Add support for C89.
7763 - Change license to choice of public domain or MIT-0.
7765 v0.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.
7791 v0.8.5 - 2018-09-11
7792 - Const correctness.
7793 - Fix a potential stack overflow.
7795 v0.8.4 - 2018-08-07
7796 - Improve 64-bit detection.
7798 v0.8.3 - 2018-08-05
7799 - Fix C++ build on older versions of GCC.
7801 v0.8.2 - 2018-08-02
7802 - Fix some big-endian bugs.
7804 v0.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.
7810 v0.8 - 2018-04-27
7811 - Bug fix.
7812 - Start using major.minor.revision versioning.
7814 v0.7f - 2018-02-05
7815 - Restrict ADPCM formats to a maximum of 2 channels.
7817 v0.7e - 2018-02-02
7818 - Fix a crash.
7820 v0.7d - 2018-02-01
7821 - Fix a crash.
7823 v0.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.
7829 v0.7b - 2018-01-22
7830 - Fix errors with seeking of compressed formats.
7831 - Fix compilation error when DR_WAV_NO_CONVERSION_API
7833 v0.7a - 2017-11-17
7834 - Fix some GCC warnings.
7836 v0.7 - 2017-11-04
7837 - Add writing APIs.
7839 v0.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.
7847 v0.5g - 2017-07-16
7848 - Change underlying type for booleans to unsigned.
7850 v0.5f - 2017-04-04
7851 - Fix a minor bug with drwav_open_and_read_s16() and family.
7853 v0.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.
7857 v0.5d - 2016-12-28
7858 - Use drwav_int* and drwav_uint* sized types to improve compiler support.
7860 v0.5c - 2016-11-11
7861 - Properly handle JUNK chunks that come before the FMT chunk.
7863 v0.5b - 2016-10-23
7864 - A minor change to drwav_bool8 and drwav_bool32 types.
7866 v0.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.
7870 v0.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.
7874 v0.4b - 2016-09-18
7875 - Fixed a typo in documentation.
7877 v0.4a - 2016-09-18
7878 - Fixed a typo.
7879 - Change date format to ISO 8601 (YYYY-MM-DD)
7881 v0.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.
7886 v0.3a - 2016-05-28
7887 - API CHANGE. Return drwav_bool32 instead of int in onSeek callback.
7888 - Fixed a memory leak.
7890 v0.3 - 2016-05-22
7891 - Lots of API changes for consistency.
7893 v0.2a - 2016-05-16
7894 - Fixed Linux/GCC build.
7896 v0.2 - 2016-05-11
7897 - Added support for reading data as signed 32-bit PCM for consistency with dr_flac.
7899 v0.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.
7902 v0.1 - 2016-05-04
7903 - Initial versioned release.
7907 This software is available as a choice of the following licenses. Choose
7908 whichever you prefer.
7910 ===============================================================================
7911 ALTERNATIVE 1 - Public Domain (www.unlicense.org)
7912 ===============================================================================
7913 This is free and unencumbered software released into the public domain.
7915 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
7916 software, either in source code form or as a compiled binary, for any purpose,
7917 commercial or non-commercial, and by any means.
7919 In jurisdictions that recognize copyright laws, the author or authors of this
7920 software dedicate any and all copyright interest in the software to the public
7921 domain. We make this dedication for the benefit of the public at large and to
7922 the detriment of our heirs and successors. We intend this dedication to be an
7923 overt act of relinquishment in perpetuity of all present and future rights to
7924 this software under copyright law.
7926 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7927 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7928 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7929 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
7930 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
7931 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7933 For more information, please refer to <http://unlicense.org/>
7935 ===============================================================================
7936 ALTERNATIVE 2 - MIT No Attribution
7937 ===============================================================================
7938 Copyright 2020 David Reid
7940 Permission is hereby granted, free of charge, to any person obtaining a copy of
7941 this software and associated documentation files (the "Software"), to deal in
7942 the Software without restriction, including without limitation the rights to
7943 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7944 of the Software, and to permit persons to whom the Software is furnished to do
7947 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7948 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7949 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7950 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7951 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7952 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
7953 SOFTWARE.