GCC Code Coverage Report


Directory: ./
File: submodules/raylib/src/external/dr_wav.h
Date: 2023-09-29 04:53:15
Exec Total Coverage
Lines: 0 2089 0.0%
Branches: 0 1935 0.0%

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