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

Generated with cgit - Back to sebastiano.tronto.net