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