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.12.2 - 2020-04-21
4
5 David Reid - mackron@gmail.com
6
7 GitHub: https://github.com/mackron/dr_libs
8 */
9
10 /*
11 RELEASE NOTES - VERSION 0.12
12 ============================
13 Version 0.12 includes breaking changes to custom chunk handling.
14
15
16 Changes to Chunk Callback
17 -------------------------
18 dr_wav supports the ability to fire a callback when a chunk is encounted (except for WAVE and FMT chunks). The callback has been update to include both the
19 container (RIFF or Wave64) and the FMT chunk which contains information about the format of the data in the wave file.
20
21 Previously, there was no direct way to determine the container, and therefore no way discriminate against the different IDs in the chunk header (RIFF and
22 Wave64 containers encode chunk ID's differently). The `container` parameter can be used to know which ID to use.
23
24 Sometimes it can be useful to know the data format at the time the chunk callback is fired. A pointer to a `drwav_fmt` object is now passed into the chunk
25 callback which will give you information about the data format. To determine the sample format, use `drwav_fmt_get_format()`. This will return one of the
26 `DR_WAVE_FORMAT_*` tokens.
27 */
28
29 /*
30 Introduction
31 ============
32 This is a single file library. To use it, do something like the following in one .c file.
33
34 ```c
35 #define DR_WAV_IMPLEMENTATION
36 #include "dr_wav.h"
37 ```
38
39 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:
40
41 ```c
42 drwav wav;
43 if (!drwav_init_file(&wav, "my_song.wav", NULL)) {
44 // Error opening WAV file.
45 }
46
47 drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32));
48 size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
49
50 ...
51
52 drwav_uninit(&wav);
53 ```
54
55 If you just want to quickly open and read the audio data in a single operation you can do something like this:
56
57 ```c
58 unsigned int channels;
59 unsigned int sampleRate;
60 drwav_uint64 totalPCMFrameCount;
61 float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount, NULL);
62 if (pSampleData == NULL) {
63 // Error opening and reading WAV file.
64 }
65
66 ...
67
68 drwav_free(pSampleData);
69 ```
70
71 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
72 audio data in its internal format (see notes below for supported formats):
73
74 ```c
75 size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
76 ```
77
78 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:
79
80 ```c
81 size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer);
82 ```
83
84 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()`,
85 `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.
86
87 ```c
88 drwav_data_format format;
89 format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
90 format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes.
91 format.channels = 2;
92 format.sampleRate = 44100;
93 format.bitsPerSample = 16;
94 drwav_init_file_write(&wav, "data/recording.wav", &format, NULL);
95
96 ...
97
98 drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples);
99 ```
100
101 dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work without any manual intervention.
102
103
104 Build Options
105 =============
106 #define these options before including this file.
107
108 #define DR_WAV_NO_CONVERSION_API
109 Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`.
110
111 #define DR_WAV_NO_STDIO
112 Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc.
113
114
115
116 Notes
117 =====
118 - Samples are always interleaved.
119 - 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()`
120 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
121 formats include the following:
122 - Unsigned 8-bit PCM
123 - Signed 12-bit PCM
124 - Signed 16-bit PCM
125 - Signed 24-bit PCM
126 - Signed 32-bit PCM
127 - IEEE 32-bit floating point
128 - IEEE 64-bit floating point
129 - A-law and u-law
130 - Microsoft ADPCM
131 - IMA ADPCM (DVI, format code 0x11)
132 - dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format.
133 */
134
135 #ifndef dr_wav_h
136 #define dr_wav_h
137
138 #ifdef __cplusplus
139 extern "C" {
140 #endif
141
142 #include <stddef.h> /* For size_t. */
143
144 /* Sized types. Prefer built-in types. Fall back to stdint. */
145 #ifdef _MSC_VER
146 #if defined(__clang__)
147 #pragma GCC diagnostic push
148 #pragma GCC diagnostic ignored "-Wlanguage-extension-token"
149 #pragma GCC diagnostic ignored "-Wlong-long"
150 #pragma GCC diagnostic ignored "-Wc++11-long-long"
151 #endif
152 typedef signed __int8 drwav_int8;
153 typedef unsigned __int8 drwav_uint8;
154 typedef signed __int16 drwav_int16;
155 typedef unsigned __int16 drwav_uint16;
156 typedef signed __int32 drwav_int32;
157 typedef unsigned __int32 drwav_uint32;
158 typedef signed __int64 drwav_int64;
159 typedef unsigned __int64 drwav_uint64;
160 #if defined(__clang__)
161 #pragma GCC diagnostic pop
162 #endif
163 #else
164 #include <stdint.h>
165 typedef int8_t drwav_int8;
166 typedef uint8_t drwav_uint8;
167 typedef int16_t drwav_int16;
168 typedef uint16_t drwav_uint16;
169 typedef int32_t drwav_int32;
170 typedef uint32_t drwav_uint32;
171 typedef int64_t drwav_int64;
172 typedef uint64_t drwav_uint64;
173 #endif
174 typedef drwav_uint8 drwav_bool8;
175 typedef drwav_uint32 drwav_bool32;
176 #define DRWAV_TRUE 1
177 #define DRWAV_FALSE 0
178
179 #if !defined(DRWAV_API)
180 #if defined(DRWAV_DLL)
181 #if defined(_WIN32)
182 #define DRWAV_DLL_IMPORT __declspec(dllimport)
183 #define DRWAV_DLL_EXPORT __declspec(dllexport)
184 #define DRWAV_DLL_PRIVATE static
185 #else
186 #if defined(__GNUC__) && __GNUC__ >= 4
187 #define DRWAV_DLL_IMPORT __attribute__((visibility("default")))
188 #define DRWAV_DLL_EXPORT __attribute__((visibility("default")))
189 #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden")))
190 #else
191 #define DRWAV_DLL_IMPORT
192 #define DRWAV_DLL_EXPORT
193 #define DRWAV_DLL_PRIVATE static
194 #endif
195 #endif
196
197 #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
198 #define DRWAV_API DRWAV_DLL_EXPORT
199 #else
200 #define DRWAV_API DRWAV_DLL_IMPORT
201 #endif
202 #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE
203 #else
204 #define DRWAV_API extern
205 #define DRWAV_PRIVATE static
206 #endif
207 #endif
208
209 typedef drwav_int32 drwav_result;
210 #define DRWAV_SUCCESS 0
211 #define DRWAV_ERROR -1 /* A generic error. */
212 #define DRWAV_INVALID_ARGS -2
213 #define DRWAV_INVALID_OPERATION -3
214 #define DRWAV_OUT_OF_MEMORY -4
215 #define DRWAV_OUT_OF_RANGE -5
216 #define DRWAV_ACCESS_DENIED -6
217 #define DRWAV_DOES_NOT_EXIST -7
218 #define DRWAV_ALREADY_EXISTS -8
219 #define DRWAV_TOO_MANY_OPEN_FILES -9
220 #define DRWAV_INVALID_FILE -10
221 #define DRWAV_TOO_BIG -11
222 #define DRWAV_PATH_TOO_LONG -12
223 #define DRWAV_NAME_TOO_LONG -13
224 #define DRWAV_NOT_DIRECTORY -14
225 #define DRWAV_IS_DIRECTORY -15
226 #define DRWAV_DIRECTORY_NOT_EMPTY -16
227 #define DRWAV_END_OF_FILE -17
228 #define DRWAV_NO_SPACE -18
229 #define DRWAV_BUSY -19
230 #define DRWAV_IO_ERROR -20
231 #define DRWAV_INTERRUPT -21
232 #define DRWAV_UNAVAILABLE -22
233 #define DRWAV_ALREADY_IN_USE -23
234 #define DRWAV_BAD_ADDRESS -24
235 #define DRWAV_BAD_SEEK -25
236 #define DRWAV_BAD_PIPE -26
237 #define DRWAV_DEADLOCK -27
238 #define DRWAV_TOO_MANY_LINKS -28
239 #define DRWAV_NOT_IMPLEMENTED -29
240 #define DRWAV_NO_MESSAGE -30
241 #define DRWAV_BAD_MESSAGE -31
242 #define DRWAV_NO_DATA_AVAILABLE -32
243 #define DRWAV_INVALID_DATA -33
244 #define DRWAV_TIMEOUT -34
245 #define DRWAV_NO_NETWORK -35
246 #define DRWAV_NOT_UNIQUE -36
247 #define DRWAV_NOT_SOCKET -37
248 #define DRWAV_NO_ADDRESS -38
249 #define DRWAV_BAD_PROTOCOL -39
250 #define DRWAV_PROTOCOL_UNAVAILABLE -40
251 #define DRWAV_PROTOCOL_NOT_SUPPORTED -41
252 #define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42
253 #define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED -43
254 #define DRWAV_SOCKET_NOT_SUPPORTED -44
255 #define DRWAV_CONNECTION_RESET -45
256 #define DRWAV_ALREADY_CONNECTED -46
257 #define DRWAV_NOT_CONNECTED -47
258 #define DRWAV_CONNECTION_REFUSED -48
259 #define DRWAV_NO_HOST -49
260 #define DRWAV_IN_PROGRESS -50
261 #define DRWAV_CANCELLED -51
262 #define DRWAV_MEMORY_ALREADY_MAPPED -52
263 #define DRWAV_AT_END -53
264
265 /* Common data formats. */
266 #define DR_WAVE_FORMAT_PCM 0x1
267 #define DR_WAVE_FORMAT_ADPCM 0x2
268 #define DR_WAVE_FORMAT_IEEE_FLOAT 0x3
269 #define DR_WAVE_FORMAT_ALAW 0x6
270 #define DR_WAVE_FORMAT_MULAW 0x7
271 #define DR_WAVE_FORMAT_DVI_ADPCM 0x11
272 #define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE
273
274 /* Constants. */
275 #ifndef DRWAV_MAX_SMPL_LOOPS
276 #define DRWAV_MAX_SMPL_LOOPS 1
277 #endif
278
279 /* Flags to pass into drwav_init_ex(), etc. */
280 #define DRWAV_SEQUENTIAL 0x00000001
281
282 typedef enum
283 {
284 drwav_seek_origin_start,
285 drwav_seek_origin_current
286 } drwav_seek_origin;
287
288 typedef enum
289 {
290 drwav_container_riff,
291 drwav_container_w64
292 } drwav_container;
293
294 typedef struct
295 {
296 union
297 {
298 drwav_uint8 fourcc[4];
299 drwav_uint8 guid[16];
300 } id;
301
302 /* The size in bytes of the chunk. */
303 drwav_uint64 sizeInBytes;
304
305 /*
306 RIFF = 2 byte alignment.
307 W64 = 8 byte alignment.
308 */
309 unsigned int paddingSize;
310 } drwav_chunk_header;
311
312 typedef struct
313 {
314 /*
315 The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
316 that require support for data formats not natively supported by dr_wav.
317 */
318 drwav_uint16 formatTag;
319
320 /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */
321 drwav_uint16 channels;
322
323 /* The sample rate. Usually set to something like 44100. */
324 drwav_uint32 sampleRate;
325
326 /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */
327 drwav_uint32 avgBytesPerSec;
328
329 /* Block align. This is equal to the number of channels * bytes per sample. */
330 drwav_uint16 blockAlign;
331
332 /* Bits per sample. */
333 drwav_uint16 bitsPerSample;
334
335 /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */
336 drwav_uint16 extendedSize;
337
338 /*
339 The number of valid bits per sample. When <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample>
340 is always rounded up to the nearest multiple of 8. This variable contains information about exactly how
341 many bits are valid per sample. Mainly used for informational purposes.
342 */
343 drwav_uint16 validBitsPerSample;
344
345 /* The channel mask. Not used at the moment. */
346 drwav_uint32 channelMask;
347
348 /* The sub-format, exactly as specified by the wave file. */
349 drwav_uint8 subFormat[16];
350 } drwav_fmt;
351
352 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
353
354
355 /*
356 Callback for when data is read. Return value is the number of bytes actually read.
357
358 pUserData [in] The user data that was passed to drwav_init() and family.
359 pBufferOut [out] The output buffer.
360 bytesToRead [in] The number of bytes to read.
361
362 Returns the number of bytes actually read.
363
364 A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until
365 either the entire bytesToRead is filled or you have reached the end of the stream.
366 */
367 typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
368
369 /*
370 Callback for when data is written. Returns value is the number of bytes actually written.
371
372 pUserData [in] The user data that was passed to drwav_init_write() and family.
373 pData [out] A pointer to the data to write.
374 bytesToWrite [in] The number of bytes to write.
375
376 Returns the number of bytes actually written.
377
378 If the return value differs from bytesToWrite, it indicates an error.
379 */
380 typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
381
382 /*
383 Callback for when data needs to be seeked.
384
385 pUserData [in] The user data that was passed to drwav_init() and family.
386 offset [in] The number of bytes to move, relative to the origin. Will never be negative.
387 origin [in] The origin of the seek - the current position or the start of the stream.
388
389 Returns whether or not the seek was successful.
390
391 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
392 drwav_seek_origin_current.
393 */
394 typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
395
396 /*
397 Callback for when drwav_init_ex() finds a chunk.
398
399 pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family.
400 onRead [in] A pointer to the function to call when reading.
401 onSeek [in] A pointer to the function to call when seeking.
402 pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family.
403 pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk.
404 container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF.
405 pFMT [in] A pointer to the object containing the contents of the "fmt" chunk.
406
407 Returns the number of bytes read + seeked.
408
409 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
410 be the total number of bytes you have read _plus_ seeked.
411
412 Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` you should use `id.fourcc`,
413 otherwise you should use `id.guid`.
414
415 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
416 `DR_WAVE_FORMAT_*` identifiers.
417
418 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.
419 */
420 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);
421
422 typedef struct
423 {
424 void* pUserData;
425 void* (* onMalloc)(size_t sz, void* pUserData);
426 void* (* onRealloc)(void* p, size_t sz, void* pUserData);
427 void (* onFree)(void* p, void* pUserData);
428 } drwav_allocation_callbacks;
429
430 /* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */
431 typedef struct
432 {
433 const drwav_uint8* data;
434 size_t dataSize;
435 size_t currentReadPos;
436 } drwav__memory_stream;
437
438 /* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */
439 typedef struct
440 {
441 void** ppData;
442 size_t* pDataSize;
443 size_t dataSize;
444 size_t dataCapacity;
445 size_t currentWritePos;
446 } drwav__memory_stream_write;
447
448 typedef struct
449 {
450 drwav_container container; /* RIFF, W64. */
451 drwav_uint32 format; /* DR_WAVE_FORMAT_* */
452 drwav_uint32 channels;
453 drwav_uint32 sampleRate;
454 drwav_uint32 bitsPerSample;
455 } drwav_data_format;
456
457
458 /* See the following for details on the 'smpl' chunk: https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl */
459 typedef struct
460 {
461 drwav_uint32 cuePointId;
462 drwav_uint32 type;
463 drwav_uint32 start;
464 drwav_uint32 end;
465 drwav_uint32 fraction;
466 drwav_uint32 playCount;
467 } drwav_smpl_loop;
468
469 typedef struct
470 {
471 drwav_uint32 manufacturer;
472 drwav_uint32 product;
473 drwav_uint32 samplePeriod;
474 drwav_uint32 midiUnityNotes;
475 drwav_uint32 midiPitchFraction;
476 drwav_uint32 smpteFormat;
477 drwav_uint32 smpteOffset;
478 drwav_uint32 numSampleLoops;
479 drwav_uint32 samplerData;
480 drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS];
481 } drwav_smpl;
482
483 typedef struct
484 {
485 /* A pointer to the function to call when more data is needed. */
486 drwav_read_proc onRead;
487
488 /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */
489 drwav_write_proc onWrite;
490
491 /* A pointer to the function to call when the wav file needs to be seeked. */
492 drwav_seek_proc onSeek;
493
494 /* The user data to pass to callbacks. */
495 void* pUserData;
496
497 /* Allocation callbacks. */
498 drwav_allocation_callbacks allocationCallbacks;
499
500
501 /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */
502 drwav_container container;
503
504
505 /* Structure containing format information exactly as specified by the wav file. */
506 drwav_fmt fmt;
507
508 /* The sample rate. Will be set to something like 44100. */
509 drwav_uint32 sampleRate;
510
511 /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */
512 drwav_uint16 channels;
513
514 /* The bits per sample. Will be set to something like 16, 24, etc. */
515 drwav_uint16 bitsPerSample;
516
517 /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */
518 drwav_uint16 translatedFormatTag;
519
520 /* The total number of PCM frames making up the audio data. */
521 drwav_uint64 totalPCMFrameCount;
522
523
524 /* The size in bytes of the data chunk. */
525 drwav_uint64 dataChunkDataSize;
526
527 /* The position in the stream of the first byte of the data chunk. This is used for seeking. */
528 drwav_uint64 dataChunkDataPos;
529
530 /* The number of bytes remaining in the data chunk. */
531 drwav_uint64 bytesRemaining;
532
533
534 /*
535 Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always
536 set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation.
537 */
538 drwav_uint64 dataChunkDataSizeTargetWrite;
539
540 /* Keeps track of whether or not the wav writer was initialized in sequential mode. */
541 drwav_bool32 isSequentialWrite;
542
543
544 /* smpl chunk. */
545 drwav_smpl smpl;
546
547
548 /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */
549 drwav__memory_stream memoryStream;
550 drwav__memory_stream_write memoryStreamWrite;
551
552 /* Generic data for compressed formats. This data is shared across all block-compressed formats. */
553 struct
554 {
555 drwav_uint64 iCurrentPCMFrame; /* The index of the next PCM frame that will be read by drwav_read_*(). This is used with "totalPCMFrameCount" to ensure we don't read excess samples at the end of the last block. */
556 } compressed;
557
558 /* Microsoft ADPCM specific data. */
559 struct
560 {
561 drwav_uint32 bytesRemainingInBlock;
562 drwav_uint16 predictor[2];
563 drwav_int32 delta[2];
564 drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */
565 drwav_uint32 cachedFrameCount;
566 drwav_int32 prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */
567 } msadpcm;
568
569 /* IMA ADPCM specific data. */
570 struct
571 {
572 drwav_uint32 bytesRemainingInBlock;
573 drwav_int32 predictor[2];
574 drwav_int32 stepIndex[2];
575 drwav_int32 cachedFrames[16]; /* Samples are stored in this cache during decoding. */
576 drwav_uint32 cachedFrameCount;
577 } ima;
578 } drwav;
579
580
581 /*
582 Initializes a pre-allocated drwav object for reading.
583
584 pWav [out] A pointer to the drwav object being initialized.
585 onRead [in] The function to call when data needs to be read from the client.
586 onSeek [in] The function to call when the read position of the client data needs to move.
587 onChunk [in, optional] The function to call when a chunk is enumerated at initialized time.
588 pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
589 pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk.
590 flags [in, optional] A set of flags for controlling how things are loaded.
591
592 Returns true if successful; false otherwise.
593
594 Close the loader with drwav_uninit().
595
596 This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory()
597 to open the stream from a file or from a block of memory respectively.
598
599 Possible values for flags:
600 DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function
601 to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored.
602
603 drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);".
604
605 The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt
606 after the function returns.
607
608 See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
609 */
610 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
611 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);
612
613 /*
614 Initializes a pre-allocated drwav object for writing.
615
616 onWrite [in] The function to call when data needs to be written.
617 onSeek [in] The function to call when the write position needs to move.
618 pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek.
619
620 Returns true if successful; false otherwise.
621
622 Close the writer with drwav_uninit().
623
624 This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write()
625 to open the stream from a file or from a block of memory respectively.
626
627 If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform
628 a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek.
629
630 See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit()
631 */
632 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);
633 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);
634 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);
635
636 /*
637 Utility function to determine the target size of the entire data to be written (including all headers and chunks).
638
639 Returns the target size in bytes.
640
641 Useful if the application needs to know the size to allocate.
642
643 Only writing to the RIFF chunk and one data chunk is currently supported.
644
645 See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write()
646 */
647 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
648
649 /*
650 Uninitializes the given drwav object.
651
652 Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()).
653 */
654 DRWAV_API drwav_result drwav_uninit(drwav* pWav);
655
656
657 /*
658 Reads raw audio data.
659
660 This is the lowest level function for reading audio data. It simply reads the given number of
661 bytes of the raw internal sample data.
662
663 Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for
664 reading sample data in a consistent format.
665
666 Returns the number of bytes actually read.
667 */
668 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
669
670 /*
671 Reads up to the specified number of PCM frames from the WAV file.
672
673 The output data will be in the file's internal format, converted to native-endian byte order. Use
674 drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format.
675
676 If the return value is less than <framesToRead> it means the end of the file has been reached or
677 you have requested more PCM frames than can possibly fit in the output buffer.
678
679 This function will only work when sample data is of a fixed size and uncompressed. If you are
680 using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32().
681 */
682 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
683 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
684 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
685
686 /*
687 Seeks to the given PCM frame.
688
689 Returns true if successful; false otherwise.
690 */
691 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
692
693
694 /*
695 Writes raw audio data.
696
697 Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error.
698 */
699 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
700
701 /*
702 Writes PCM frames.
703
704 Returns the number of PCM frames written.
705
706 Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to
707 little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion.
708 */
709 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
710 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
711 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
712
713
714 /* Conversion Utilities */
715 #ifndef DR_WAV_NO_CONVERSION_API
716
717 /*
718 Reads a chunk of audio data and converts it to signed 16-bit PCM samples.
719
720 Returns the number of PCM frames actually read.
721
722 If the return value is less than <framesToRead> it means the end of the file has been reached.
723 */
724 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
725 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
726 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
727
728 /* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */
729 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
730
731 /* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */
732 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
733
734 /* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */
735 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
736
737 /* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */
738 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
739
740 /* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */
741 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
742
743 /* Low-level function for converting A-law samples to signed 16-bit PCM samples. */
744 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
745
746 /* Low-level function for converting u-law samples to signed 16-bit PCM samples. */
747 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
748
749
750 /*
751 Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples.
752
753 Returns the number of PCM frames actually read.
754
755 If the return value is less than <framesToRead> it means the end of the file has been reached.
756 */
757 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
758 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
759 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
760
761 /* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */
762 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
763
764 /* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */
765 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
766
767 /* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */
768 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
769
770 /* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */
771 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
772
773 /* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */
774 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
775
776 /* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */
777 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
778
779 /* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */
780 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
781
782
783 /*
784 Reads a chunk of audio data and converts it to signed 32-bit PCM samples.
785
786 Returns the number of PCM frames actually read.
787
788 If the return value is less than <framesToRead> it means the end of the file has been reached.
789 */
790 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
791 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
792 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
793
794 /* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */
795 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
796
797 /* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */
798 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
799
800 /* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */
801 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
802
803 /* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */
804 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
805
806 /* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */
807 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
808
809 /* Low-level function for converting A-law samples to signed 32-bit PCM samples. */
810 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
811
812 /* Low-level function for converting u-law samples to signed 32-bit PCM samples. */
813 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
814
815 #endif /* DR_WAV_NO_CONVERSION_API */
816
817
818 /* High-Level Convenience Helpers */
819
820 #ifndef DR_WAV_NO_STDIO
821 /*
822 Helper for initializing a wave file for reading using stdio.
823
824 This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
825 objects because the operating system may restrict the number of file handles an application can have open at
826 any given time.
827 */
828 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
829 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);
830 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
831 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);
832
833 /*
834 Helper for initializing a wave file for writing using stdio.
835
836 This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
837 objects because the operating system may restrict the number of file handles an application can have open at
838 any given time.
839 */
840 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
841 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);
842 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);
843 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);
844 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);
845 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);
846 #endif /* DR_WAV_NO_STDIO */
847
848 /*
849 Helper for initializing a loader from a pre-allocated memory buffer.
850
851 This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
852 the lifetime of the drwav object.
853
854 The buffer should contain the contents of the entire wave file, not just the sample data.
855 */
856 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
857 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);
858
859 /*
860 Helper for initializing a writer which outputs data to a memory buffer.
861
862 dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
863
864 The buffer will remain allocated even after drwav_uninit() is called. Indeed, the buffer should not be
865 considered valid until after drwav_uninit() has been called anyway.
866 */
867 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);
868 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);
869 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);
870
871
872 #ifndef DR_WAV_NO_CONVERSION_API
873 /*
874 Opens and reads an entire wav file in a single operation.
875
876 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
877 */
878 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);
879 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);
880 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);
881 #ifndef DR_WAV_NO_STDIO
882 /*
883 Opens and decodes an entire wav file in a single operation.
884
885 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
886 */
887 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);
888 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);
889 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);
890 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);
891 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);
892 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);
893 #endif
894 /*
895 Opens and decodes an entire wav file from a block of memory in a single operation.
896
897 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
898 */
899 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);
900 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);
901 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);
902 #endif
903
904 /* Frees data that was allocated internally by dr_wav. */
905 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
906
907 /* Converts bytes from a wav stream to a sized type of native endian. */
908 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const unsigned char* data);
909 DRWAV_API drwav_int16 drwav_bytes_to_s16(const unsigned char* data);
910 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const unsigned char* data);
911 DRWAV_API drwav_int32 drwav_bytes_to_s32(const unsigned char* data);
912 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const unsigned char* data);
913 DRWAV_API drwav_int64 drwav_bytes_to_s64(const unsigned char* data);
914
915 /* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */
916 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
917
918 /* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */
919 DRWAV_API drwav_bool32 drwav_fourcc_equal(const unsigned char* a, const char* b);
920
921 #ifdef __cplusplus
922 }
923 #endif
924 #endif /* dr_wav_h */
925
926
927 /************************************************************************************************************************************************************
928 ************************************************************************************************************************************************************
929
930 IMPLEMENTATION
931
932 ************************************************************************************************************************************************************
933 ************************************************************************************************************************************************************/
934 #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
935 #include <stdlib.h>
936 #include <string.h> /* For memcpy(), memset() */
937 #include <limits.h> /* For INT_MAX */
938
939 #ifndef DR_WAV_NO_STDIO
940 #include <stdio.h>
941 #include <wchar.h>
942 #endif
943
944 /* Standard library stuff. */
945 #ifndef DRWAV_ASSERT
946 #include <assert.h>
947 #define DRWAV_ASSERT(expression) assert(expression)
948 #endif
949 #ifndef DRWAV_MALLOC
950 #define DRWAV_MALLOC(sz) malloc((sz))
951 #endif
952 #ifndef DRWAV_REALLOC
953 #define DRWAV_REALLOC(p, sz) realloc((p), (sz))
954 #endif
955 #ifndef DRWAV_FREE
956 #define DRWAV_FREE(p) free((p))
957 #endif
958 #ifndef DRWAV_COPY_MEMORY
959 #define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
960 #endif
961 #ifndef DRWAV_ZERO_MEMORY
962 #define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
963 #endif
964 #ifndef DRWAV_ZERO_OBJECT
965 #define DRWAV_ZERO_OBJECT(p) DRWAV_ZERO_MEMORY((p), sizeof(*p))
966 #endif
967
968 #define drwav_countof(x) (sizeof(x) / sizeof(x[0]))
969 #define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a))
970 #define drwav_min(a, b) (((a) < (b)) ? (a) : (b))
971 #define drwav_max(a, b) (((a) > (b)) ? (a) : (b))
972 #define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x))))
973
974 #define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */
975
976 /* CPU architecture. */
977 #if defined(__x86_64__) || defined(_M_X64)
978 #define DRWAV_X64
979 #elif defined(__i386) || defined(_M_IX86)
980 #define DRWAV_X86
981 #elif defined(__arm__) || defined(_M_ARM)
982 #define DRWAV_ARM
983 #endif
984
985 #ifdef _MSC_VER
986 #define DRWAV_INLINE __forceinline
987 #elif defined(__GNUC__)
988 /*
989 I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
990 the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
991 case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
992 command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
993 I am using "__inline__" only when we're compiling in strict ANSI mode.
994 */
995 #if defined(__STRICT_ANSI__)
996 #define DRWAV_INLINE __inline__ __attribute__((always_inline))
997 #else
998 #define DRWAV_INLINE inline __attribute__((always_inline))
999 #endif
1000 #else
1001 #define DRWAV_INLINE
1002 #endif
1003
1004 #if defined(SIZE_MAX)
1005 #define DRWAV_SIZE_MAX SIZE_MAX
1006 #else
1007 #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
1008 #define DRWAV_SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
1009 #else
1010 #define DRWAV_SIZE_MAX 0xFFFFFFFF
1011 #endif
1012 #endif
1013
1014 #if defined(_MSC_VER) && _MSC_VER >= 1400
1015 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1016 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1017 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1018 #elif defined(__clang__)
1019 #if defined(__has_builtin)
1020 #if __has_builtin(__builtin_bswap16)
1021 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1022 #endif
1023 #if __has_builtin(__builtin_bswap32)
1024 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1025 #endif
1026 #if __has_builtin(__builtin_bswap64)
1027 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1028 #endif
1029 #endif
1030 #elif defined(__GNUC__)
1031 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
1032 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1033 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1034 #endif
1035 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
1036 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1037 #endif
1038 #endif
1039
1040 /*
1041 These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are
1042 you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation.
1043 */
1044 #ifndef DRWAV_MAX_SAMPLE_RATE
1045 #define DRWAV_MAX_SAMPLE_RATE 384000
1046 #endif
1047 #ifndef DRWAV_MAX_CHANNELS
1048 #define DRWAV_MAX_CHANNELS 256
1049 #endif
1050 #ifndef DRWAV_MAX_BITS_PER_SAMPLE
1051 #define DRWAV_MAX_BITS_PER_SAMPLE 64
1052 #endif
1053
1054 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 */
1055 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 */
1056 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 */
1057 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 */
1058 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 */
1059 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 */
1060 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 */
1061
drwav__guid_equal(const drwav_uint8 a[16],const drwav_uint8 b[16])1062 static DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
1063 {
1064 int i;
1065 for (i = 0; i < 16; i += 1) {
1066 if (a[i] != b[i]) {
1067 return DRWAV_FALSE;
1068 }
1069 }
1070
1071 return DRWAV_TRUE;
1072 }
1073
drwav__fourcc_equal(const unsigned char * a,const char * b)1074 static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const unsigned char* a, const char* b)
1075 {
1076 return
1077 a[0] == b[0] &&
1078 a[1] == b[1] &&
1079 a[2] == b[2] &&
1080 a[3] == b[3];
1081 }
1082
1083
1084
drwav__is_little_endian(void)1085 static DRWAV_INLINE int drwav__is_little_endian(void)
1086 {
1087 #if defined(DRWAV_X86) || defined(DRWAV_X64)
1088 return DRWAV_TRUE;
1089 #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
1090 return DRWAV_TRUE;
1091 #else
1092 int n = 1;
1093 return (*(char*)&n) == 1;
1094 #endif
1095 }
1096
drwav__bytes_to_u16(const unsigned char * data)1097 static DRWAV_INLINE drwav_uint16 drwav__bytes_to_u16(const unsigned char* data)
1098 {
1099 return (data[0] << 0) | (data[1] << 8);
1100 }
1101
drwav__bytes_to_s16(const unsigned char * data)1102 static DRWAV_INLINE drwav_int16 drwav__bytes_to_s16(const unsigned char* data)
1103 {
1104 return (short)drwav__bytes_to_u16(data);
1105 }
1106
drwav__bytes_to_u32(const unsigned char * data)1107 static DRWAV_INLINE drwav_uint32 drwav__bytes_to_u32(const unsigned char* data)
1108 {
1109 return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
1110 }
1111
drwav__bytes_to_s32(const unsigned char * data)1112 static DRWAV_INLINE drwav_int32 drwav__bytes_to_s32(const unsigned char* data)
1113 {
1114 return (drwav_int32)drwav__bytes_to_u32(data);
1115 }
1116
drwav__bytes_to_u64(const unsigned char * data)1117 static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const unsigned char* data)
1118 {
1119 return
1120 ((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
1121 ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
1122 }
1123
drwav__bytes_to_s64(const unsigned char * data)1124 static DRWAV_INLINE drwav_int64 drwav__bytes_to_s64(const unsigned char* data)
1125 {
1126 return (drwav_int64)drwav__bytes_to_u64(data);
1127 }
1128
drwav__bytes_to_guid(const unsigned char * data,drwav_uint8 * guid)1129 static DRWAV_INLINE void drwav__bytes_to_guid(const unsigned char* data, drwav_uint8* guid)
1130 {
1131 int i;
1132 for (i = 0; i < 16; ++i) {
1133 guid[i] = data[i];
1134 }
1135 }
1136
1137
drwav__bswap16(drwav_uint16 n)1138 static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n)
1139 {
1140 #ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC
1141 #if defined(_MSC_VER)
1142 return _byteswap_ushort(n);
1143 #elif defined(__GNUC__) || defined(__clang__)
1144 return __builtin_bswap16(n);
1145 #else
1146 #error "This compiler does not support the byte swap intrinsic."
1147 #endif
1148 #else
1149 return ((n & 0xFF00) >> 8) |
1150 ((n & 0x00FF) << 8);
1151 #endif
1152 }
1153
drwav__bswap32(drwav_uint32 n)1154 static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n)
1155 {
1156 #ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC
1157 #if defined(_MSC_VER)
1158 return _byteswap_ulong(n);
1159 #elif defined(__GNUC__) || defined(__clang__)
1160 #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. */
1161 /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
1162 drwav_uint32 r;
1163 __asm__ __volatile__ (
1164 #if defined(DRWAV_64BIT)
1165 "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! */
1166 #else
1167 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
1168 #endif
1169 );
1170 return r;
1171 #else
1172 return __builtin_bswap32(n);
1173 #endif
1174 #else
1175 #error "This compiler does not support the byte swap intrinsic."
1176 #endif
1177 #else
1178 return ((n & 0xFF000000) >> 24) |
1179 ((n & 0x00FF0000) >> 8) |
1180 ((n & 0x0000FF00) << 8) |
1181 ((n & 0x000000FF) << 24);
1182 #endif
1183 }
1184
drwav__bswap64(drwav_uint64 n)1185 static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
1186 {
1187 #ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC
1188 #if defined(_MSC_VER)
1189 return _byteswap_uint64(n);
1190 #elif defined(__GNUC__) || defined(__clang__)
1191 return __builtin_bswap64(n);
1192 #else
1193 #error "This compiler does not support the byte swap intrinsic."
1194 #endif
1195 #else
1196 return ((n & (drwav_uint64)0xFF00000000000000) >> 56) |
1197 ((n & (drwav_uint64)0x00FF000000000000) >> 40) |
1198 ((n & (drwav_uint64)0x0000FF0000000000) >> 24) |
1199 ((n & (drwav_uint64)0x000000FF00000000) >> 8) |
1200 ((n & (drwav_uint64)0x00000000FF000000) << 8) |
1201 ((n & (drwav_uint64)0x0000000000FF0000) << 24) |
1202 ((n & (drwav_uint64)0x000000000000FF00) << 40) |
1203 ((n & (drwav_uint64)0x00000000000000FF) << 56);
1204 #endif
1205 }
1206
1207
drwav__bswap_s16(drwav_int16 n)1208 static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
1209 {
1210 return (drwav_int16)drwav__bswap16((drwav_uint16)n);
1211 }
1212
drwav__bswap_samples_s16(drwav_int16 * pSamples,drwav_uint64 sampleCount)1213 static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount)
1214 {
1215 drwav_uint64 iSample;
1216 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1217 pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]);
1218 }
1219 }
1220
1221
drwav__bswap_s24(drwav_uint8 * p)1222 static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p)
1223 {
1224 drwav_uint8 t;
1225 t = p[0];
1226 p[0] = p[2];
1227 p[2] = t;
1228 }
1229
drwav__bswap_samples_s24(drwav_uint8 * pSamples,drwav_uint64 sampleCount)1230 static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount)
1231 {
1232 drwav_uint64 iSample;
1233 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1234 drwav_uint8* pSample = pSamples + (iSample*3);
1235 drwav__bswap_s24(pSample);
1236 }
1237 }
1238
1239
drwav__bswap_s32(drwav_int32 n)1240 static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n)
1241 {
1242 return (drwav_int32)drwav__bswap32((drwav_uint32)n);
1243 }
1244
drwav__bswap_samples_s32(drwav_int32 * pSamples,drwav_uint64 sampleCount)1245 static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount)
1246 {
1247 drwav_uint64 iSample;
1248 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1249 pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]);
1250 }
1251 }
1252
1253
drwav__bswap_f32(float n)1254 static DRWAV_INLINE float drwav__bswap_f32(float n)
1255 {
1256 union {
1257 drwav_uint32 i;
1258 float f;
1259 } x;
1260 x.f = n;
1261 x.i = drwav__bswap32(x.i);
1262
1263 return x.f;
1264 }
1265
drwav__bswap_samples_f32(float * pSamples,drwav_uint64 sampleCount)1266 static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount)
1267 {
1268 drwav_uint64 iSample;
1269 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1270 pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]);
1271 }
1272 }
1273
1274
drwav__bswap_f64(double n)1275 static DRWAV_INLINE double drwav__bswap_f64(double n)
1276 {
1277 union {
1278 drwav_uint64 i;
1279 double f;
1280 } x;
1281 x.f = n;
1282 x.i = drwav__bswap64(x.i);
1283
1284 return x.f;
1285 }
1286
drwav__bswap_samples_f64(double * pSamples,drwav_uint64 sampleCount)1287 static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount)
1288 {
1289 drwav_uint64 iSample;
1290 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1291 pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]);
1292 }
1293 }
1294
1295
drwav__bswap_samples_pcm(void * pSamples,drwav_uint64 sampleCount,drwav_uint32 bytesPerSample)1296 static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1297 {
1298 /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */
1299 switch (bytesPerSample)
1300 {
1301 case 2: /* s16, s12 (loosely packed) */
1302 {
1303 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1304 } break;
1305 case 3: /* s24 */
1306 {
1307 drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount);
1308 } break;
1309 case 4: /* s32 */
1310 {
1311 drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount);
1312 } break;
1313 default:
1314 {
1315 /* Unsupported format. */
1316 DRWAV_ASSERT(DRWAV_FALSE);
1317 } break;
1318 }
1319 }
1320
drwav__bswap_samples_ieee(void * pSamples,drwav_uint64 sampleCount,drwav_uint32 bytesPerSample)1321 static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1322 {
1323 switch (bytesPerSample)
1324 {
1325 #if 0 /* Contributions welcome for f16 support. */
1326 case 2: /* f16 */
1327 {
1328 drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount);
1329 } break;
1330 #endif
1331 case 4: /* f32 */
1332 {
1333 drwav__bswap_samples_f32((float*)pSamples, sampleCount);
1334 } break;
1335 case 8: /* f64 */
1336 {
1337 drwav__bswap_samples_f64((double*)pSamples, sampleCount);
1338 } break;
1339 default:
1340 {
1341 /* Unsupported format. */
1342 DRWAV_ASSERT(DRWAV_FALSE);
1343 } break;
1344 }
1345 }
1346
drwav__bswap_samples(void * pSamples,drwav_uint64 sampleCount,drwav_uint32 bytesPerSample,drwav_uint16 format)1347 static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format)
1348 {
1349 switch (format)
1350 {
1351 case DR_WAVE_FORMAT_PCM:
1352 {
1353 drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample);
1354 } break;
1355
1356 case DR_WAVE_FORMAT_IEEE_FLOAT:
1357 {
1358 drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample);
1359 } break;
1360
1361 case DR_WAVE_FORMAT_ALAW:
1362 case DR_WAVE_FORMAT_MULAW:
1363 {
1364 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1365 } break;
1366
1367 case DR_WAVE_FORMAT_ADPCM:
1368 case DR_WAVE_FORMAT_DVI_ADPCM:
1369 default:
1370 {
1371 /* Unsupported format. */
1372 DRWAV_ASSERT(DRWAV_FALSE);
1373 } break;
1374 }
1375 }
1376
1377
drwav__malloc_default(size_t sz,void * pUserData)1378 static void* drwav__malloc_default(size_t sz, void* pUserData)
1379 {
1380 (void)pUserData;
1381 return DRWAV_MALLOC(sz);
1382 }
1383
drwav__realloc_default(void * p,size_t sz,void * pUserData)1384 static void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
1385 {
1386 (void)pUserData;
1387 return DRWAV_REALLOC(p, sz);
1388 }
1389
drwav__free_default(void * p,void * pUserData)1390 static void drwav__free_default(void* p, void* pUserData)
1391 {
1392 (void)pUserData;
1393 DRWAV_FREE(p);
1394 }
1395
1396
drwav__malloc_from_callbacks(size_t sz,const drwav_allocation_callbacks * pAllocationCallbacks)1397 static void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
1398 {
1399 if (pAllocationCallbacks == NULL) {
1400 return NULL;
1401 }
1402
1403 if (pAllocationCallbacks->onMalloc != NULL) {
1404 return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
1405 }
1406
1407 /* Try using realloc(). */
1408 if (pAllocationCallbacks->onRealloc != NULL) {
1409 return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
1410 }
1411
1412 return NULL;
1413 }
1414
drwav__realloc_from_callbacks(void * p,size_t szNew,size_t szOld,const drwav_allocation_callbacks * pAllocationCallbacks)1415 static void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
1416 {
1417 if (pAllocationCallbacks == NULL) {
1418 return NULL;
1419 }
1420
1421 if (pAllocationCallbacks->onRealloc != NULL) {
1422 return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
1423 }
1424
1425 /* Try emulating realloc() in terms of malloc()/free(). */
1426 if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
1427 void* p2;
1428
1429 p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
1430 if (p2 == NULL) {
1431 return NULL;
1432 }
1433
1434 if (p != NULL) {
1435 DRWAV_COPY_MEMORY(p2, p, szOld);
1436 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1437 }
1438
1439 return p2;
1440 }
1441
1442 return NULL;
1443 }
1444
drwav__free_from_callbacks(void * p,const drwav_allocation_callbacks * pAllocationCallbacks)1445 static void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
1446 {
1447 if (p == NULL || pAllocationCallbacks == NULL) {
1448 return;
1449 }
1450
1451 if (pAllocationCallbacks->onFree != NULL) {
1452 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1453 }
1454 }
1455
1456
drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks * pAllocationCallbacks)1457 static drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
1458 {
1459 if (pAllocationCallbacks != NULL) {
1460 /* Copy. */
1461 return *pAllocationCallbacks;
1462 } else {
1463 /* Defaults. */
1464 drwav_allocation_callbacks allocationCallbacks;
1465 allocationCallbacks.pUserData = NULL;
1466 allocationCallbacks.onMalloc = drwav__malloc_default;
1467 allocationCallbacks.onRealloc = drwav__realloc_default;
1468 allocationCallbacks.onFree = drwav__free_default;
1469 return allocationCallbacks;
1470 }
1471 }
1472
1473
drwav__is_compressed_format_tag(drwav_uint16 formatTag)1474 static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
1475 {
1476 return
1477 formatTag == DR_WAVE_FORMAT_ADPCM ||
1478 formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
1479 }
1480
drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)1481 static unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
1482 {
1483 return (unsigned int)(chunkSize % 2);
1484 }
1485
drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)1486 static unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
1487 {
1488 return (unsigned int)(chunkSize % 8);
1489 }
1490
1491 static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1492 static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1493 static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
1494
drwav__read_chunk_header(drwav_read_proc onRead,void * pUserData,drwav_container container,drwav_uint64 * pRunningBytesReadOut,drwav_chunk_header * pHeaderOut)1495 static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
1496 {
1497 if (container == drwav_container_riff) {
1498 unsigned char sizeInBytes[4];
1499
1500 if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
1501 return DRWAV_AT_END;
1502 }
1503
1504 if (onRead(pUserData, sizeInBytes, 4) != 4) {
1505 return DRWAV_INVALID_FILE;
1506 }
1507
1508 pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes);
1509 pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes);
1510 *pRunningBytesReadOut += 8;
1511 } else {
1512 unsigned char sizeInBytes[8];
1513
1514 if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
1515 return DRWAV_AT_END;
1516 }
1517
1518 if (onRead(pUserData, sizeInBytes, 8) != 8) {
1519 return DRWAV_INVALID_FILE;
1520 }
1521
1522 pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */
1523 pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
1524 *pRunningBytesReadOut += 24;
1525 }
1526
1527 return DRWAV_SUCCESS;
1528 }
1529
drwav__seek_forward(drwav_seek_proc onSeek,drwav_uint64 offset,void * pUserData)1530 static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1531 {
1532 drwav_uint64 bytesRemainingToSeek = offset;
1533 while (bytesRemainingToSeek > 0) {
1534 if (bytesRemainingToSeek > 0x7FFFFFFF) {
1535 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1536 return DRWAV_FALSE;
1537 }
1538 bytesRemainingToSeek -= 0x7FFFFFFF;
1539 } else {
1540 if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
1541 return DRWAV_FALSE;
1542 }
1543 bytesRemainingToSeek = 0;
1544 }
1545 }
1546
1547 return DRWAV_TRUE;
1548 }
1549
drwav__seek_from_start(drwav_seek_proc onSeek,drwav_uint64 offset,void * pUserData)1550 static drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1551 {
1552 if (offset <= 0x7FFFFFFF) {
1553 return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
1554 }
1555
1556 /* Larger than 32-bit seek. */
1557 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
1558 return DRWAV_FALSE;
1559 }
1560 offset -= 0x7FFFFFFF;
1561
1562 for (;;) {
1563 if (offset <= 0x7FFFFFFF) {
1564 return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
1565 }
1566
1567 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1568 return DRWAV_FALSE;
1569 }
1570 offset -= 0x7FFFFFFF;
1571 }
1572
1573 /* Should never get here. */
1574 /*return DRWAV_TRUE; */
1575 }
1576
1577
drwav__read_fmt(drwav_read_proc onRead,drwav_seek_proc onSeek,void * pUserData,drwav_container container,drwav_uint64 * pRunningBytesReadOut,drwav_fmt * fmtOut)1578 static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut)
1579 {
1580 drwav_chunk_header header;
1581 unsigned char fmt[16];
1582
1583 if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
1584 return DRWAV_FALSE;
1585 }
1586
1587
1588 /* Skip non-fmt chunks. */
1589 while ((container == drwav_container_riff && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
1590 if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
1591 return DRWAV_FALSE;
1592 }
1593 *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize;
1594
1595 /* Try the next header. */
1596 if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
1597 return DRWAV_FALSE;
1598 }
1599 }
1600
1601
1602 /* Validation. */
1603 if (container == drwav_container_riff) {
1604 if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) {
1605 return DRWAV_FALSE;
1606 }
1607 } else {
1608 if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
1609 return DRWAV_FALSE;
1610 }
1611 }
1612
1613
1614 if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
1615 return DRWAV_FALSE;
1616 }
1617 *pRunningBytesReadOut += sizeof(fmt);
1618
1619 fmtOut->formatTag = drwav__bytes_to_u16(fmt + 0);
1620 fmtOut->channels = drwav__bytes_to_u16(fmt + 2);
1621 fmtOut->sampleRate = drwav__bytes_to_u32(fmt + 4);
1622 fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8);
1623 fmtOut->blockAlign = drwav__bytes_to_u16(fmt + 12);
1624 fmtOut->bitsPerSample = drwav__bytes_to_u16(fmt + 14);
1625
1626 fmtOut->extendedSize = 0;
1627 fmtOut->validBitsPerSample = 0;
1628 fmtOut->channelMask = 0;
1629 memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
1630
1631 if (header.sizeInBytes > 16) {
1632 unsigned char fmt_cbSize[2];
1633 int bytesReadSoFar = 0;
1634
1635 if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
1636 return DRWAV_FALSE; /* Expecting more data. */
1637 }
1638 *pRunningBytesReadOut += sizeof(fmt_cbSize);
1639
1640 bytesReadSoFar = 18;
1641
1642 fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize);
1643 if (fmtOut->extendedSize > 0) {
1644 /* Simple validation. */
1645 if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1646 if (fmtOut->extendedSize != 22) {
1647 return DRWAV_FALSE;
1648 }
1649 }
1650
1651 if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1652 unsigned char fmtext[22];
1653 if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) {
1654 return DRWAV_FALSE; /* Expecting more data. */
1655 }
1656
1657 fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0);
1658 fmtOut->channelMask = drwav__bytes_to_u32(fmtext + 2);
1659 drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat);
1660 } else {
1661 if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) {
1662 return DRWAV_FALSE;
1663 }
1664 }
1665 *pRunningBytesReadOut += fmtOut->extendedSize;
1666
1667 bytesReadSoFar += fmtOut->extendedSize;
1668 }
1669
1670 /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */
1671 if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) {
1672 return DRWAV_FALSE;
1673 }
1674 *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
1675 }
1676
1677 if (header.paddingSize > 0) {
1678 if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
1679 return DRWAV_FALSE;
1680 }
1681 *pRunningBytesReadOut += header.paddingSize;
1682 }
1683
1684 return DRWAV_TRUE;
1685 }
1686
1687
drwav__on_read(drwav_read_proc onRead,void * pUserData,void * pBufferOut,size_t bytesToRead,drwav_uint64 * pCursor)1688 static size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
1689 {
1690 size_t bytesRead;
1691
1692 DRWAV_ASSERT(onRead != NULL);
1693 DRWAV_ASSERT(pCursor != NULL);
1694
1695 bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
1696 *pCursor += bytesRead;
1697 return bytesRead;
1698 }
1699
1700 #if 0
1701 static drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
1702 {
1703 DRWAV_ASSERT(onSeek != NULL);
1704 DRWAV_ASSERT(pCursor != NULL);
1705
1706 if (!onSeek(pUserData, offset, origin)) {
1707 return DRWAV_FALSE;
1708 }
1709
1710 if (origin == drwav_seek_origin_start) {
1711 *pCursor = offset;
1712 } else {
1713 *pCursor += offset;
1714 }
1715
1716 return DRWAV_TRUE;
1717 }
1718 #endif
1719
1720
1721
drwav_get_bytes_per_pcm_frame(drwav * pWav)1722 static drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
1723 {
1724 /*
1725 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
1726 is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align.
1727 */
1728 if ((pWav->bitsPerSample & 0x7) == 0) {
1729 /* Bits per sample is a multiple of 8. */
1730 return (pWav->bitsPerSample * pWav->fmt.channels) >> 3;
1731 } else {
1732 return pWav->fmt.blockAlign;
1733 }
1734 }
1735
drwav_fmt_get_format(const drwav_fmt * pFMT)1736 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
1737 {
1738 if (pFMT == NULL) {
1739 return 0;
1740 }
1741
1742 if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) {
1743 return pFMT->formatTag;
1744 } else {
1745 return drwav__bytes_to_u16(pFMT->subFormat); /* Only the first two bytes are required. */
1746 }
1747 }
1748
drwav_preinit(drwav * pWav,drwav_read_proc onRead,drwav_seek_proc onSeek,void * pReadSeekUserData,const drwav_allocation_callbacks * pAllocationCallbacks)1749 static drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
1750 {
1751 if (pWav == NULL || onRead == NULL || onSeek == NULL) {
1752 return DRWAV_FALSE;
1753 }
1754
1755 DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
1756 pWav->onRead = onRead;
1757 pWav->onSeek = onSeek;
1758 pWav->pUserData = pReadSeekUserData;
1759 pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
1760
1761 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
1762 return DRWAV_FALSE; /* Invalid allocation callbacks. */
1763 }
1764
1765 return DRWAV_TRUE;
1766 }
1767
drwav_init__internal(drwav * pWav,drwav_chunk_proc onChunk,void * pChunkUserData,drwav_uint32 flags)1768 static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
1769 {
1770 /* This function assumes drwav_preinit() has been called beforehand. */
1771
1772 drwav_uint64 cursor; /* <-- Keeps track of the byte position so we can seek to specific locations. */
1773 drwav_bool32 sequential;
1774 unsigned char riff[4];
1775 drwav_fmt fmt;
1776 unsigned short translatedFormatTag;
1777 drwav_uint64 sampleCountFromFactChunk;
1778 drwav_bool32 foundDataChunk;
1779 drwav_uint64 dataChunkSize;
1780 drwav_uint64 chunkSize;
1781
1782 cursor = 0;
1783 sequential = (flags & DRWAV_SEQUENTIAL) != 0;
1784
1785 /* The first 4 bytes should be the RIFF identifier. */
1786 if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) {
1787 return DRWAV_FALSE;
1788 }
1789
1790 /*
1791 The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for
1792 w64 it will start with "riff".
1793 */
1794 if (drwav__fourcc_equal(riff, "RIFF")) {
1795 pWav->container = drwav_container_riff;
1796 } else if (drwav__fourcc_equal(riff, "riff")) {
1797 int i;
1798 drwav_uint8 riff2[12];
1799
1800 pWav->container = drwav_container_w64;
1801
1802 /* Check the rest of the GUID for validity. */
1803 if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) {
1804 return DRWAV_FALSE;
1805 }
1806
1807 for (i = 0; i < 12; ++i) {
1808 if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
1809 return DRWAV_FALSE;
1810 }
1811 }
1812 } else {
1813 return DRWAV_FALSE; /* Unknown or unsupported container. */
1814 }
1815
1816
1817 if (pWav->container == drwav_container_riff) {
1818 unsigned char chunkSizeBytes[4];
1819 unsigned char wave[4];
1820
1821 /* RIFF/WAVE */
1822 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
1823 return DRWAV_FALSE;
1824 }
1825
1826 if (drwav__bytes_to_u32(chunkSizeBytes) < 36) {
1827 return DRWAV_FALSE; /* Chunk size should always be at least 36 bytes. */
1828 }
1829
1830 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
1831 return DRWAV_FALSE;
1832 }
1833
1834 if (!drwav__fourcc_equal(wave, "WAVE")) {
1835 return DRWAV_FALSE; /* Expecting "WAVE". */
1836 }
1837 } else {
1838 unsigned char chunkSizeBytes[8];
1839 drwav_uint8 wave[16];
1840
1841 /* W64 */
1842 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
1843 return DRWAV_FALSE;
1844 }
1845
1846 if (drwav__bytes_to_u64(chunkSizeBytes) < 80) {
1847 return DRWAV_FALSE;
1848 }
1849
1850 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
1851 return DRWAV_FALSE;
1852 }
1853
1854 if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) {
1855 return DRWAV_FALSE;
1856 }
1857 }
1858
1859
1860 /* The next bytes should be the "fmt " chunk. */
1861 if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) {
1862 return DRWAV_FALSE; /* Failed to read the "fmt " chunk. */
1863 }
1864
1865 /* Basic validation. */
1866 if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE) ||
1867 (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS) ||
1868 (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) ||
1869 fmt.blockAlign == 0) {
1870 return DRWAV_FALSE; /* Probably an invalid WAV file. */
1871 }
1872
1873
1874 /* Translate the internal format. */
1875 translatedFormatTag = fmt.formatTag;
1876 if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1877 translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0);
1878 }
1879
1880
1881
1882 sampleCountFromFactChunk = 0;
1883
1884 /*
1885 We need to enumerate over each chunk for two reasons:
1886 1) The "data" chunk may not be the next one
1887 2) We may want to report each chunk back to the client
1888
1889 In order to correctly report each chunk back to the client we will need to keep looping until the end of the file.
1890 */
1891 foundDataChunk = DRWAV_FALSE;
1892 dataChunkSize = 0;
1893
1894 /* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */
1895 for (;;)
1896 {
1897 drwav_chunk_header header;
1898 drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
1899 if (result != DRWAV_SUCCESS) {
1900 if (!foundDataChunk) {
1901 return DRWAV_FALSE;
1902 } else {
1903 break; /* Probably at the end of the file. Get out of the loop. */
1904 }
1905 }
1906
1907 /* Tell the client about this chunk. */
1908 if (!sequential && onChunk != NULL) {
1909 drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt);
1910
1911 /*
1912 dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before
1913 we called the callback.
1914 */
1915 if (callbackBytesRead > 0) {
1916 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
1917 return DRWAV_FALSE;
1918 }
1919 }
1920 }
1921
1922
1923 if (!foundDataChunk) {
1924 pWav->dataChunkDataPos = cursor;
1925 }
1926
1927 chunkSize = header.sizeInBytes;
1928 if (pWav->container == drwav_container_riff) {
1929 if (drwav__fourcc_equal(header.id.fourcc, "data")) {
1930 foundDataChunk = DRWAV_TRUE;
1931 dataChunkSize = chunkSize;
1932 }
1933 } else {
1934 if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
1935 foundDataChunk = DRWAV_TRUE;
1936 dataChunkSize = chunkSize;
1937 }
1938 }
1939
1940 /*
1941 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
1942 this is that we would otherwise require a backwards seek which sequential mode forbids.
1943 */
1944 if (foundDataChunk && sequential) {
1945 break;
1946 }
1947
1948 /* Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. */
1949 if (pWav->container == drwav_container_riff) {
1950 if (drwav__fourcc_equal(header.id.fourcc, "fact")) {
1951 drwav_uint32 sampleCount;
1952 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) {
1953 return DRWAV_FALSE;
1954 }
1955 chunkSize -= 4;
1956
1957 if (!foundDataChunk) {
1958 pWav->dataChunkDataPos = cursor;
1959 }
1960
1961 /*
1962 The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this
1963 for Microsoft ADPCM formats.
1964 */
1965 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
1966 sampleCountFromFactChunk = sampleCount;
1967 } else {
1968 sampleCountFromFactChunk = 0;
1969 }
1970 }
1971 } else {
1972 if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
1973 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
1974 return DRWAV_FALSE;
1975 }
1976 chunkSize -= 8;
1977
1978 if (!foundDataChunk) {
1979 pWav->dataChunkDataPos = cursor;
1980 }
1981 }
1982 }
1983
1984 /* "smpl" chunk. */
1985 if (pWav->container == drwav_container_riff) {
1986 if (drwav__fourcc_equal(header.id.fourcc, "smpl")) {
1987 unsigned char smplHeaderData[36]; /* 36 = size of the smpl header section, not including the loop data. */
1988 if (chunkSize >= sizeof(smplHeaderData)) {
1989 drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor);
1990 chunkSize -= bytesJustRead;
1991
1992 if (bytesJustRead == sizeof(smplHeaderData)) {
1993 drwav_uint32 iLoop;
1994
1995 pWav->smpl.manufacturer = drwav__bytes_to_u32(smplHeaderData+0);
1996 pWav->smpl.product = drwav__bytes_to_u32(smplHeaderData+4);
1997 pWav->smpl.samplePeriod = drwav__bytes_to_u32(smplHeaderData+8);
1998 pWav->smpl.midiUnityNotes = drwav__bytes_to_u32(smplHeaderData+12);
1999 pWav->smpl.midiPitchFraction = drwav__bytes_to_u32(smplHeaderData+16);
2000 pWav->smpl.smpteFormat = drwav__bytes_to_u32(smplHeaderData+20);
2001 pWav->smpl.smpteOffset = drwav__bytes_to_u32(smplHeaderData+24);
2002 pWav->smpl.numSampleLoops = drwav__bytes_to_u32(smplHeaderData+28);
2003 pWav->smpl.samplerData = drwav__bytes_to_u32(smplHeaderData+32);
2004
2005 for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) {
2006 unsigned char smplLoopData[24]; /* 24 = size of a loop section in the smpl chunk. */
2007 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor);
2008 chunkSize -= bytesJustRead;
2009
2010 if (bytesJustRead == sizeof(smplLoopData)) {
2011 pWav->smpl.loops[iLoop].cuePointId = drwav__bytes_to_u32(smplLoopData+0);
2012 pWav->smpl.loops[iLoop].type = drwav__bytes_to_u32(smplLoopData+4);
2013 pWav->smpl.loops[iLoop].start = drwav__bytes_to_u32(smplLoopData+8);
2014 pWav->smpl.loops[iLoop].end = drwav__bytes_to_u32(smplLoopData+12);
2015 pWav->smpl.loops[iLoop].fraction = drwav__bytes_to_u32(smplLoopData+16);
2016 pWav->smpl.loops[iLoop].playCount = drwav__bytes_to_u32(smplLoopData+20);
2017 } else {
2018 break; /* Break from the smpl loop for loop. */
2019 }
2020 }
2021 }
2022 } else {
2023 /* Looks like invalid data. Ignore the chunk. */
2024 }
2025 }
2026 } else {
2027 if (drwav__guid_equal(header.id.guid, drwavGUID_W64_SMPL)) {
2028 /*
2029 This path will be hit when a W64 WAV file contains a smpl chunk. I don't have a sample file to test this path, so a contribution
2030 is welcome to add support for this.
2031 */
2032 }
2033 }
2034
2035 /* Make sure we seek past the padding. */
2036 chunkSize += header.paddingSize;
2037 if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) {
2038 break;
2039 }
2040 cursor += chunkSize;
2041
2042 if (!foundDataChunk) {
2043 pWav->dataChunkDataPos = cursor;
2044 }
2045 }
2046
2047 /* If we haven't found a data chunk, return an error. */
2048 if (!foundDataChunk) {
2049 return DRWAV_FALSE;
2050 }
2051
2052 /* 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. */
2053 if (!sequential) {
2054 if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) {
2055 return DRWAV_FALSE;
2056 }
2057 cursor = pWav->dataChunkDataPos;
2058 }
2059
2060
2061 /* At this point we should be sitting on the first byte of the raw audio data. */
2062
2063 pWav->fmt = fmt;
2064 pWav->sampleRate = fmt.sampleRate;
2065 pWav->channels = fmt.channels;
2066 pWav->bitsPerSample = fmt.bitsPerSample;
2067 pWav->bytesRemaining = dataChunkSize;
2068 pWav->translatedFormatTag = translatedFormatTag;
2069 pWav->dataChunkDataSize = dataChunkSize;
2070
2071 if (sampleCountFromFactChunk != 0) {
2072 pWav->totalPCMFrameCount = sampleCountFromFactChunk;
2073 } else {
2074 pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav);
2075
2076 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
2077 drwav_uint64 totalBlockHeaderSizeInBytes;
2078 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2079
2080 /* Make sure any trailing partial block is accounted for. */
2081 if ((blockCount * fmt.blockAlign) < dataChunkSize) {
2082 blockCount += 1;
2083 }
2084
2085 /* 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. */
2086 totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
2087 pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
2088 }
2089 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2090 drwav_uint64 totalBlockHeaderSizeInBytes;
2091 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2092
2093 /* Make sure any trailing partial block is accounted for. */
2094 if ((blockCount * fmt.blockAlign) < dataChunkSize) {
2095 blockCount += 1;
2096 }
2097
2098 /* 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. */
2099 totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
2100 pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
2101
2102 /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */
2103 pWav->totalPCMFrameCount += blockCount;
2104 }
2105 }
2106
2107 /* Some formats only support a certain number of channels. */
2108 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2109 if (pWav->channels > 2) {
2110 return DRWAV_FALSE;
2111 }
2112 }
2113
2114 #ifdef DR_WAV_LIBSNDFILE_COMPAT
2115 /*
2116 I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website),
2117 it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count
2118 from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct
2119 way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should
2120 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
2121 correctness tests against libsndfile, and is disabled by default.
2122 */
2123 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
2124 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2125 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */
2126 }
2127 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2128 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2129 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
2130 }
2131 #endif
2132
2133 return DRWAV_TRUE;
2134 }
2135
drwav_init(drwav * pWav,drwav_read_proc onRead,drwav_seek_proc onSeek,void * pUserData,const drwav_allocation_callbacks * pAllocationCallbacks)2136 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2137 {
2138 return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
2139 }
2140
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)2141 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)
2142 {
2143 if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
2144 return DRWAV_FALSE;
2145 }
2146
2147 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
2148 }
2149
2150
drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize)2151 static drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize)
2152 {
2153 drwav_uint32 dataSubchunkPaddingSize = drwav__chunk_padding_size_riff(dataChunkSize);
2154
2155 if (dataChunkSize <= (0xFFFFFFFFUL - 36 - dataSubchunkPaddingSize)) {
2156 return 36 + (drwav_uint32)(dataChunkSize + dataSubchunkPaddingSize);
2157 } else {
2158 return 0xFFFFFFFF;
2159 }
2160 }
2161
drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)2162 static drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
2163 {
2164 if (dataChunkSize <= 0xFFFFFFFFUL) {
2165 return (drwav_uint32)dataChunkSize;
2166 } else {
2167 return 0xFFFFFFFFUL;
2168 }
2169 }
2170
drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)2171 static drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
2172 {
2173 drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
2174
2175 return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */
2176 }
2177
drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)2178 static drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
2179 {
2180 return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
2181 }
2182
2183
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)2184 static 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)
2185 {
2186 if (pWav == NULL || onWrite == NULL) {
2187 return DRWAV_FALSE;
2188 }
2189
2190 if (!isSequential && onSeek == NULL) {
2191 return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */
2192 }
2193
2194 /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */
2195 if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
2196 return DRWAV_FALSE;
2197 }
2198 if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
2199 return DRWAV_FALSE;
2200 }
2201
2202 DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
2203 pWav->onWrite = onWrite;
2204 pWav->onSeek = onSeek;
2205 pWav->pUserData = pUserData;
2206 pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
2207
2208 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
2209 return DRWAV_FALSE; /* Invalid allocation callbacks. */
2210 }
2211
2212 pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
2213 pWav->fmt.channels = (drwav_uint16)pFormat->channels;
2214 pWav->fmt.sampleRate = pFormat->sampleRate;
2215 pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8);
2216 pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8);
2217 pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
2218 pWav->fmt.extendedSize = 0;
2219 pWav->isSequentialWrite = isSequential;
2220
2221 return DRWAV_TRUE;
2222 }
2223
drwav_init_write__internal(drwav * pWav,const drwav_data_format * pFormat,drwav_uint64 totalSampleCount)2224 static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
2225 {
2226 /* The function assumes drwav_preinit_write() was called beforehand. */
2227
2228 size_t runningPos = 0;
2229 drwav_uint64 initialDataChunkSize = 0;
2230 drwav_uint64 chunkSizeFMT;
2231
2232 /*
2233 The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In
2234 sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non-
2235 sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek.
2236 */
2237 if (pWav->isSequentialWrite) {
2238 initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
2239
2240 /*
2241 The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64
2242 so for the sake of simplicity I'm not doing any validation for that.
2243 */
2244 if (pFormat->container == drwav_container_riff) {
2245 if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
2246 return DRWAV_FALSE; /* Not enough room to store every sample. */
2247 }
2248 }
2249 }
2250
2251 pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
2252
2253
2254 /* "RIFF" chunk. */
2255 if (pFormat->container == drwav_container_riff) {
2256 drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize; /* +36 = "RIFF"+[RIFF Chunk Size]+"WAVE" + [sizeof "fmt " chunk] */
2257 runningPos += pWav->onWrite(pWav->pUserData, "RIFF", 4);
2258 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeRIFF, 4);
2259 runningPos += pWav->onWrite(pWav->pUserData, "WAVE", 4);
2260 } else {
2261 drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
2262 runningPos += pWav->onWrite(pWav->pUserData, drwavGUID_W64_RIFF, 16);
2263 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeRIFF, 8);
2264 runningPos += pWav->onWrite(pWav->pUserData, drwavGUID_W64_WAVE, 16);
2265 }
2266
2267 /* "fmt " chunk. */
2268 if (pFormat->container == drwav_container_riff) {
2269 chunkSizeFMT = 16;
2270 runningPos += pWav->onWrite(pWav->pUserData, "fmt ", 4);
2271 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeFMT, 4);
2272 } else {
2273 chunkSizeFMT = 40;
2274 runningPos += pWav->onWrite(pWav->pUserData, drwavGUID_W64_FMT, 16);
2275 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeFMT, 8);
2276 }
2277
2278 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.formatTag, 2);
2279 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.channels, 2);
2280 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.sampleRate, 4);
2281 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.avgBytesPerSec, 4);
2282 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.blockAlign, 2);
2283 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.bitsPerSample, 2);
2284
2285 pWav->dataChunkDataPos = runningPos;
2286
2287 /* "data" chunk. */
2288 if (pFormat->container == drwav_container_riff) {
2289 drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
2290 runningPos += pWav->onWrite(pWav->pUserData, "data", 4);
2291 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeDATA, 4);
2292 } else {
2293 drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
2294 runningPos += pWav->onWrite(pWav->pUserData, drwavGUID_W64_DATA, 16);
2295 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeDATA, 8);
2296 }
2297
2298
2299 /* Simple validation. */
2300 if (pFormat->container == drwav_container_riff) {
2301 if (runningPos != 20 + chunkSizeFMT + 8) {
2302 return DRWAV_FALSE;
2303 }
2304 } else {
2305 if (runningPos != 40 + chunkSizeFMT + 24) {
2306 return DRWAV_FALSE;
2307 }
2308 }
2309
2310
2311 /* Set some properties for the client's convenience. */
2312 pWav->container = pFormat->container;
2313 pWav->channels = (drwav_uint16)pFormat->channels;
2314 pWav->sampleRate = pFormat->sampleRate;
2315 pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
2316 pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
2317
2318 return DRWAV_TRUE;
2319 }
2320
2321
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)2322 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)
2323 {
2324 if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
2325 return DRWAV_FALSE;
2326 }
2327
2328 return drwav_init_write__internal(pWav, pFormat, 0); /* DRWAV_FALSE = Not Sequential */
2329 }
2330
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)2331 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)
2332 {
2333 if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
2334 return DRWAV_FALSE;
2335 }
2336
2337 return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */
2338 }
2339
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)2340 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)
2341 {
2342 if (pFormat == NULL) {
2343 return DRWAV_FALSE;
2344 }
2345
2346 return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
2347 }
2348
drwav_target_write_size_bytes(const drwav_data_format * pFormat,drwav_uint64 totalSampleCount)2349 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
2350 {
2351 drwav_uint64 targetDataSizeBytes = (drwav_uint64)(totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0);
2352 drwav_uint64 riffChunkSizeBytes;
2353 drwav_uint64 fileSizeBytes;
2354
2355 if (pFormat->container == drwav_container_riff) {
2356 riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes);
2357 fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
2358 } else {
2359 riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
2360 fileSizeBytes = riffChunkSizeBytes;
2361 }
2362
2363 return fileSizeBytes;
2364 }
2365
2366
2367 #ifndef DR_WAV_NO_STDIO
2368
2369 /* 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. */
2370 #include <errno.h>
drwav_result_from_errno(int e)2371 static drwav_result drwav_result_from_errno(int e)
2372 {
2373 switch (e)
2374 {
2375 case 0: return DRWAV_SUCCESS;
2376 #ifdef EPERM
2377 case EPERM: return DRWAV_INVALID_OPERATION;
2378 #endif
2379 #ifdef ENOENT
2380 case ENOENT: return DRWAV_DOES_NOT_EXIST;
2381 #endif
2382 #ifdef ESRCH
2383 case ESRCH: return DRWAV_DOES_NOT_EXIST;
2384 #endif
2385 #ifdef EINTR
2386 case EINTR: return DRWAV_INTERRUPT;
2387 #endif
2388 #ifdef EIO
2389 case EIO: return DRWAV_IO_ERROR;
2390 #endif
2391 #ifdef ENXIO
2392 case ENXIO: return DRWAV_DOES_NOT_EXIST;
2393 #endif
2394 #ifdef E2BIG
2395 case E2BIG: return DRWAV_INVALID_ARGS;
2396 #endif
2397 #ifdef ENOEXEC
2398 case ENOEXEC: return DRWAV_INVALID_FILE;
2399 #endif
2400 #ifdef EBADF
2401 case EBADF: return DRWAV_INVALID_FILE;
2402 #endif
2403 #ifdef ECHILD
2404 case ECHILD: return DRWAV_ERROR;
2405 #endif
2406 #ifdef EAGAIN
2407 case EAGAIN: return DRWAV_UNAVAILABLE;
2408 #endif
2409 #ifdef ENOMEM
2410 case ENOMEM: return DRWAV_OUT_OF_MEMORY;
2411 #endif
2412 #ifdef EACCES
2413 case EACCES: return DRWAV_ACCESS_DENIED;
2414 #endif
2415 #ifdef EFAULT
2416 case EFAULT: return DRWAV_BAD_ADDRESS;
2417 #endif
2418 #ifdef ENOTBLK
2419 case ENOTBLK: return DRWAV_ERROR;
2420 #endif
2421 #ifdef EBUSY
2422 case EBUSY: return DRWAV_BUSY;
2423 #endif
2424 #ifdef EEXIST
2425 case EEXIST: return DRWAV_ALREADY_EXISTS;
2426 #endif
2427 #ifdef EXDEV
2428 case EXDEV: return DRWAV_ERROR;
2429 #endif
2430 #ifdef ENODEV
2431 case ENODEV: return DRWAV_DOES_NOT_EXIST;
2432 #endif
2433 #ifdef ENOTDIR
2434 case ENOTDIR: return DRWAV_NOT_DIRECTORY;
2435 #endif
2436 #ifdef EISDIR
2437 case EISDIR: return DRWAV_IS_DIRECTORY;
2438 #endif
2439 #ifdef EINVAL
2440 case EINVAL: return DRWAV_INVALID_ARGS;
2441 #endif
2442 #ifdef ENFILE
2443 case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES;
2444 #endif
2445 #ifdef EMFILE
2446 case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES;
2447 #endif
2448 #ifdef ENOTTY
2449 case ENOTTY: return DRWAV_INVALID_OPERATION;
2450 #endif
2451 #ifdef ETXTBSY
2452 case ETXTBSY: return DRWAV_BUSY;
2453 #endif
2454 #ifdef EFBIG
2455 case EFBIG: return DRWAV_TOO_BIG;
2456 #endif
2457 #ifdef ENOSPC
2458 case ENOSPC: return DRWAV_NO_SPACE;
2459 #endif
2460 #ifdef ESPIPE
2461 case ESPIPE: return DRWAV_BAD_SEEK;
2462 #endif
2463 #ifdef EROFS
2464 case EROFS: return DRWAV_ACCESS_DENIED;
2465 #endif
2466 #ifdef EMLINK
2467 case EMLINK: return DRWAV_TOO_MANY_LINKS;
2468 #endif
2469 #ifdef EPIPE
2470 case EPIPE: return DRWAV_BAD_PIPE;
2471 #endif
2472 #ifdef EDOM
2473 case EDOM: return DRWAV_OUT_OF_RANGE;
2474 #endif
2475 #ifdef ERANGE
2476 case ERANGE: return DRWAV_OUT_OF_RANGE;
2477 #endif
2478 #ifdef EDEADLK
2479 case EDEADLK: return DRWAV_DEADLOCK;
2480 #endif
2481 #ifdef ENAMETOOLONG
2482 case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG;
2483 #endif
2484 #ifdef ENOLCK
2485 case ENOLCK: return DRWAV_ERROR;
2486 #endif
2487 #ifdef ENOSYS
2488 case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
2489 #endif
2490 #ifdef ENOTEMPTY
2491 case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
2492 #endif
2493 #ifdef ELOOP
2494 case ELOOP: return DRWAV_TOO_MANY_LINKS;
2495 #endif
2496 #ifdef ENOMSG
2497 case ENOMSG: return DRWAV_NO_MESSAGE;
2498 #endif
2499 #ifdef EIDRM
2500 case EIDRM: return DRWAV_ERROR;
2501 #endif
2502 #ifdef ECHRNG
2503 case ECHRNG: return DRWAV_ERROR;
2504 #endif
2505 #ifdef EL2NSYNC
2506 case EL2NSYNC: return DRWAV_ERROR;
2507 #endif
2508 #ifdef EL3HLT
2509 case EL3HLT: return DRWAV_ERROR;
2510 #endif
2511 #ifdef EL3RST
2512 case EL3RST: return DRWAV_ERROR;
2513 #endif
2514 #ifdef ELNRNG
2515 case ELNRNG: return DRWAV_OUT_OF_RANGE;
2516 #endif
2517 #ifdef EUNATCH
2518 case EUNATCH: return DRWAV_ERROR;
2519 #endif
2520 #ifdef ENOCSI
2521 case ENOCSI: return DRWAV_ERROR;
2522 #endif
2523 #ifdef EL2HLT
2524 case EL2HLT: return DRWAV_ERROR;
2525 #endif
2526 #ifdef EBADE
2527 case EBADE: return DRWAV_ERROR;
2528 #endif
2529 #ifdef EBADR
2530 case EBADR: return DRWAV_ERROR;
2531 #endif
2532 #ifdef EXFULL
2533 case EXFULL: return DRWAV_ERROR;
2534 #endif
2535 #ifdef ENOANO
2536 case ENOANO: return DRWAV_ERROR;
2537 #endif
2538 #ifdef EBADRQC
2539 case EBADRQC: return DRWAV_ERROR;
2540 #endif
2541 #ifdef EBADSLT
2542 case EBADSLT: return DRWAV_ERROR;
2543 #endif
2544 #ifdef EBFONT
2545 case EBFONT: return DRWAV_INVALID_FILE;
2546 #endif
2547 #ifdef ENOSTR
2548 case ENOSTR: return DRWAV_ERROR;
2549 #endif
2550 #ifdef ENODATA
2551 case ENODATA: return DRWAV_NO_DATA_AVAILABLE;
2552 #endif
2553 #ifdef ETIME
2554 case ETIME: return DRWAV_TIMEOUT;
2555 #endif
2556 #ifdef ENOSR
2557 case ENOSR: return DRWAV_NO_DATA_AVAILABLE;
2558 #endif
2559 #ifdef ENONET
2560 case ENONET: return DRWAV_NO_NETWORK;
2561 #endif
2562 #ifdef ENOPKG
2563 case ENOPKG: return DRWAV_ERROR;
2564 #endif
2565 #ifdef EREMOTE
2566 case EREMOTE: return DRWAV_ERROR;
2567 #endif
2568 #ifdef ENOLINK
2569 case ENOLINK: return DRWAV_ERROR;
2570 #endif
2571 #ifdef EADV
2572 case EADV: return DRWAV_ERROR;
2573 #endif
2574 #ifdef ESRMNT
2575 case ESRMNT: return DRWAV_ERROR;
2576 #endif
2577 #ifdef ECOMM
2578 case ECOMM: return DRWAV_ERROR;
2579 #endif
2580 #ifdef EPROTO
2581 case EPROTO: return DRWAV_ERROR;
2582 #endif
2583 #ifdef EMULTIHOP
2584 case EMULTIHOP: return DRWAV_ERROR;
2585 #endif
2586 #ifdef EDOTDOT
2587 case EDOTDOT: return DRWAV_ERROR;
2588 #endif
2589 #ifdef EBADMSG
2590 case EBADMSG: return DRWAV_BAD_MESSAGE;
2591 #endif
2592 #ifdef EOVERFLOW
2593 case EOVERFLOW: return DRWAV_TOO_BIG;
2594 #endif
2595 #ifdef ENOTUNIQ
2596 case ENOTUNIQ: return DRWAV_NOT_UNIQUE;
2597 #endif
2598 #ifdef EBADFD
2599 case EBADFD: return DRWAV_ERROR;
2600 #endif
2601 #ifdef EREMCHG
2602 case EREMCHG: return DRWAV_ERROR;
2603 #endif
2604 #ifdef ELIBACC
2605 case ELIBACC: return DRWAV_ACCESS_DENIED;
2606 #endif
2607 #ifdef ELIBBAD
2608 case ELIBBAD: return DRWAV_INVALID_FILE;
2609 #endif
2610 #ifdef ELIBSCN
2611 case ELIBSCN: return DRWAV_INVALID_FILE;
2612 #endif
2613 #ifdef ELIBMAX
2614 case ELIBMAX: return DRWAV_ERROR;
2615 #endif
2616 #ifdef ELIBEXEC
2617 case ELIBEXEC: return DRWAV_ERROR;
2618 #endif
2619 #ifdef EILSEQ
2620 case EILSEQ: return DRWAV_INVALID_DATA;
2621 #endif
2622 #ifdef ERESTART
2623 case ERESTART: return DRWAV_ERROR;
2624 #endif
2625 #ifdef ESTRPIPE
2626 case ESTRPIPE: return DRWAV_ERROR;
2627 #endif
2628 #ifdef EUSERS
2629 case EUSERS: return DRWAV_ERROR;
2630 #endif
2631 #ifdef ENOTSOCK
2632 case ENOTSOCK: return DRWAV_NOT_SOCKET;
2633 #endif
2634 #ifdef EDESTADDRREQ
2635 case EDESTADDRREQ: return DRWAV_NO_ADDRESS;
2636 #endif
2637 #ifdef EMSGSIZE
2638 case EMSGSIZE: return DRWAV_TOO_BIG;
2639 #endif
2640 #ifdef EPROTOTYPE
2641 case EPROTOTYPE: return DRWAV_BAD_PROTOCOL;
2642 #endif
2643 #ifdef ENOPROTOOPT
2644 case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE;
2645 #endif
2646 #ifdef EPROTONOSUPPORT
2647 case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED;
2648 #endif
2649 #ifdef ESOCKTNOSUPPORT
2650 case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED;
2651 #endif
2652 #ifdef EOPNOTSUPP
2653 case EOPNOTSUPP: return DRWAV_INVALID_OPERATION;
2654 #endif
2655 #ifdef EPFNOSUPPORT
2656 case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED;
2657 #endif
2658 #ifdef EAFNOSUPPORT
2659 case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED;
2660 #endif
2661 #ifdef EADDRINUSE
2662 case EADDRINUSE: return DRWAV_ALREADY_IN_USE;
2663 #endif
2664 #ifdef EADDRNOTAVAIL
2665 case EADDRNOTAVAIL: return DRWAV_ERROR;
2666 #endif
2667 #ifdef ENETDOWN
2668 case ENETDOWN: return DRWAV_NO_NETWORK;
2669 #endif
2670 #ifdef ENETUNREACH
2671 case ENETUNREACH: return DRWAV_NO_NETWORK;
2672 #endif
2673 #ifdef ENETRESET
2674 case ENETRESET: return DRWAV_NO_NETWORK;
2675 #endif
2676 #ifdef ECONNABORTED
2677 case ECONNABORTED: return DRWAV_NO_NETWORK;
2678 #endif
2679 #ifdef ECONNRESET
2680 case ECONNRESET: return DRWAV_CONNECTION_RESET;
2681 #endif
2682 #ifdef ENOBUFS
2683 case ENOBUFS: return DRWAV_NO_SPACE;
2684 #endif
2685 #ifdef EISCONN
2686 case EISCONN: return DRWAV_ALREADY_CONNECTED;
2687 #endif
2688 #ifdef ENOTCONN
2689 case ENOTCONN: return DRWAV_NOT_CONNECTED;
2690 #endif
2691 #ifdef ESHUTDOWN
2692 case ESHUTDOWN: return DRWAV_ERROR;
2693 #endif
2694 #ifdef ETOOMANYREFS
2695 case ETOOMANYREFS: return DRWAV_ERROR;
2696 #endif
2697 #ifdef ETIMEDOUT
2698 case ETIMEDOUT: return DRWAV_TIMEOUT;
2699 #endif
2700 #ifdef ECONNREFUSED
2701 case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED;
2702 #endif
2703 #ifdef EHOSTDOWN
2704 case EHOSTDOWN: return DRWAV_NO_HOST;
2705 #endif
2706 #ifdef EHOSTUNREACH
2707 case EHOSTUNREACH: return DRWAV_NO_HOST;
2708 #endif
2709 #ifdef EALREADY
2710 case EALREADY: return DRWAV_IN_PROGRESS;
2711 #endif
2712 #ifdef EINPROGRESS
2713 case EINPROGRESS: return DRWAV_IN_PROGRESS;
2714 #endif
2715 #ifdef ESTALE
2716 case ESTALE: return DRWAV_INVALID_FILE;
2717 #endif
2718 #ifdef EUCLEAN
2719 case EUCLEAN: return DRWAV_ERROR;
2720 #endif
2721 #ifdef ENOTNAM
2722 case ENOTNAM: return DRWAV_ERROR;
2723 #endif
2724 #ifdef ENAVAIL
2725 case ENAVAIL: return DRWAV_ERROR;
2726 #endif
2727 #ifdef EISNAM
2728 case EISNAM: return DRWAV_ERROR;
2729 #endif
2730 #ifdef EREMOTEIO
2731 case EREMOTEIO: return DRWAV_IO_ERROR;
2732 #endif
2733 #ifdef EDQUOT
2734 case EDQUOT: return DRWAV_NO_SPACE;
2735 #endif
2736 #ifdef ENOMEDIUM
2737 case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST;
2738 #endif
2739 #ifdef EMEDIUMTYPE
2740 case EMEDIUMTYPE: return DRWAV_ERROR;
2741 #endif
2742 #ifdef ECANCELED
2743 case ECANCELED: return DRWAV_CANCELLED;
2744 #endif
2745 #ifdef ENOKEY
2746 case ENOKEY: return DRWAV_ERROR;
2747 #endif
2748 #ifdef EKEYEXPIRED
2749 case EKEYEXPIRED: return DRWAV_ERROR;
2750 #endif
2751 #ifdef EKEYREVOKED
2752 case EKEYREVOKED: return DRWAV_ERROR;
2753 #endif
2754 #ifdef EKEYREJECTED
2755 case EKEYREJECTED: return DRWAV_ERROR;
2756 #endif
2757 #ifdef EOWNERDEAD
2758 case EOWNERDEAD: return DRWAV_ERROR;
2759 #endif
2760 #ifdef ENOTRECOVERABLE
2761 case ENOTRECOVERABLE: return DRWAV_ERROR;
2762 #endif
2763 #ifdef ERFKILL
2764 case ERFKILL: return DRWAV_ERROR;
2765 #endif
2766 #ifdef EHWPOISON
2767 case EHWPOISON: return DRWAV_ERROR;
2768 #endif
2769 default: return DRWAV_ERROR;
2770 }
2771 }
2772
drwav_fopen(FILE ** ppFile,const char * pFilePath,const char * pOpenMode)2773 static drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
2774 {
2775 #if _MSC_VER && _MSC_VER >= 1400
2776 errno_t err;
2777 #endif
2778
2779 if (ppFile != NULL) {
2780 *ppFile = NULL; /* Safety. */
2781 }
2782
2783 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
2784 return DRWAV_INVALID_ARGS;
2785 }
2786
2787 #if _MSC_VER && _MSC_VER >= 1400
2788 err = fopen_s(ppFile, pFilePath, pOpenMode);
2789 if (err != 0) {
2790 return drwav_result_from_errno(err);
2791 }
2792 #else
2793 #if defined(_WIN32) || defined(__APPLE__)
2794 *ppFile = fopen(pFilePath, pOpenMode);
2795 #else
2796 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
2797 *ppFile = fopen64(pFilePath, pOpenMode);
2798 #else
2799 *ppFile = fopen(pFilePath, pOpenMode);
2800 #endif
2801 #endif
2802 if (*ppFile == NULL) {
2803 drwav_result result = drwav_result_from_errno(errno);
2804 if (result == DRWAV_SUCCESS) {
2805 result = DRWAV_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */
2806 }
2807
2808 return result;
2809 }
2810 #endif
2811
2812 return DRWAV_SUCCESS;
2813 }
2814
2815 /*
2816 _wfopen() isn't always available in all compilation environments.
2817
2818 * Windows only.
2819 * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
2820 * MinGW-64 (both 32- and 64-bit) seems to support it.
2821 * MinGW wraps it in !defined(__STRICT_ANSI__).
2822
2823 This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
2824 fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
2825 */
2826 #if defined(_WIN32)
2827 #if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__)
2828 #define DRWAV_HAS_WFOPEN
2829 #endif
2830 #endif
2831
drwav_wfopen(FILE ** ppFile,const wchar_t * pFilePath,const wchar_t * pOpenMode,const drwav_allocation_callbacks * pAllocationCallbacks)2832 static drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
2833 {
2834 if (ppFile != NULL) {
2835 *ppFile = NULL; /* Safety. */
2836 }
2837
2838 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
2839 return DRWAV_INVALID_ARGS;
2840 }
2841
2842 #if defined(DRWAV_HAS_WFOPEN)
2843 {
2844 /* Use _wfopen() on Windows. */
2845 #if defined(_MSC_VER) && _MSC_VER >= 1400
2846 errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
2847 if (err != 0) {
2848 return drwav_result_from_errno(err);
2849 }
2850 #else
2851 *ppFile = _wfopen(pFilePath, pOpenMode);
2852 if (*ppFile == NULL) {
2853 return drwav_result_from_errno(errno);
2854 }
2855 #endif
2856 (void)pAllocationCallbacks;
2857 }
2858 #else
2859 /*
2860 Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
2861 think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
2862 maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
2863 */
2864 {
2865 mbstate_t mbs;
2866 size_t lenMB;
2867 const wchar_t* pFilePathTemp = pFilePath;
2868 char* pFilePathMB = NULL;
2869 char pOpenModeMB[32] = {0};
2870
2871 /* Get the length first. */
2872 DRWAV_ZERO_OBJECT(&mbs);
2873 lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
2874 if (lenMB == (size_t)-1) {
2875 return drwav_result_from_errno(errno);
2876 }
2877
2878 pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
2879 if (pFilePathMB == NULL) {
2880 return DRWAV_OUT_OF_MEMORY;
2881 }
2882
2883 pFilePathTemp = pFilePath;
2884 DRWAV_ZERO_OBJECT(&mbs);
2885 wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
2886
2887 /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
2888 {
2889 size_t i = 0;
2890 for (;;) {
2891 if (pOpenMode[i] == 0) {
2892 pOpenModeMB[i] = '\0';
2893 break;
2894 }
2895
2896 pOpenModeMB[i] = (char)pOpenMode[i];
2897 i += 1;
2898 }
2899 }
2900
2901 *ppFile = fopen(pFilePathMB, pOpenModeMB);
2902
2903 drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
2904 }
2905
2906 if (*ppFile == NULL) {
2907 return DRWAV_ERROR;
2908 }
2909 #endif
2910
2911 return DRWAV_SUCCESS;
2912 }
2913
2914
drwav__on_read_stdio(void * pUserData,void * pBufferOut,size_t bytesToRead)2915 static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
2916 {
2917 return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
2918 }
2919
drwav__on_write_stdio(void * pUserData,const void * pData,size_t bytesToWrite)2920 static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
2921 {
2922 return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
2923 }
2924
drwav__on_seek_stdio(void * pUserData,int offset,drwav_seek_origin origin)2925 static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
2926 {
2927 return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
2928 }
2929
drwav_init_file(drwav * pWav,const char * filename,const drwav_allocation_callbacks * pAllocationCallbacks)2930 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
2931 {
2932 return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
2933 }
2934
2935
drwav_init_file__internal_FILE(drwav * pWav,FILE * pFile,drwav_chunk_proc onChunk,void * pChunkUserData,drwav_uint32 flags,const drwav_allocation_callbacks * pAllocationCallbacks)2936 static drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
2937 {
2938 drwav_bool32 result;
2939
2940 result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
2941 if (result != DRWAV_TRUE) {
2942 fclose(pFile);
2943 return result;
2944 }
2945
2946 result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
2947 if (result != DRWAV_TRUE) {
2948 fclose(pFile);
2949 return result;
2950 }
2951
2952 return DRWAV_TRUE;
2953 }
2954
drwav_init_file_ex(drwav * pWav,const char * filename,drwav_chunk_proc onChunk,void * pChunkUserData,drwav_uint32 flags,const drwav_allocation_callbacks * pAllocationCallbacks)2955 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)
2956 {
2957 FILE* pFile;
2958 if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
2959 return DRWAV_FALSE;
2960 }
2961
2962 /* This takes ownership of the FILE* object. */
2963 return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
2964 }
2965
drwav_init_file_w(drwav * pWav,const wchar_t * filename,const drwav_allocation_callbacks * pAllocationCallbacks)2966 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
2967 {
2968 return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
2969 }
2970
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)2971 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)
2972 {
2973 FILE* pFile;
2974 if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
2975 return DRWAV_FALSE;
2976 }
2977
2978 /* This takes ownership of the FILE* object. */
2979 return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
2980 }
2981
2982
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)2983 static 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)
2984 {
2985 drwav_bool32 result;
2986
2987 result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
2988 if (result != DRWAV_TRUE) {
2989 fclose(pFile);
2990 return result;
2991 }
2992
2993 result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
2994 if (result != DRWAV_TRUE) {
2995 fclose(pFile);
2996 return result;
2997 }
2998
2999 return DRWAV_TRUE;
3000 }
3001
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)3002 static 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)
3003 {
3004 FILE* pFile;
3005 if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
3006 return DRWAV_FALSE;
3007 }
3008
3009 /* This takes ownership of the FILE* object. */
3010 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
3011 }
3012
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)3013 static 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)
3014 {
3015 FILE* pFile;
3016 if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
3017 return DRWAV_FALSE;
3018 }
3019
3020 /* This takes ownership of the FILE* object. */
3021 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
3022 }
3023
drwav_init_file_write(drwav * pWav,const char * filename,const drwav_data_format * pFormat,const drwav_allocation_callbacks * pAllocationCallbacks)3024 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
3025 {
3026 return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3027 }
3028
drwav_init_file_write_sequential(drwav * pWav,const char * filename,const drwav_data_format * pFormat,drwav_uint64 totalSampleCount,const drwav_allocation_callbacks * pAllocationCallbacks)3029 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)
3030 {
3031 return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3032 }
3033
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)3034 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)
3035 {
3036 if (pFormat == NULL) {
3037 return DRWAV_FALSE;
3038 }
3039
3040 return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3041 }
3042
drwav_init_file_write_w(drwav * pWav,const wchar_t * filename,const drwav_data_format * pFormat,const drwav_allocation_callbacks * pAllocationCallbacks)3043 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)
3044 {
3045 return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3046 }
3047
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)3048 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)
3049 {
3050 return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3051 }
3052
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)3053 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)
3054 {
3055 if (pFormat == NULL) {
3056 return DRWAV_FALSE;
3057 }
3058
3059 return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3060 }
3061 #endif /* DR_WAV_NO_STDIO */
3062
3063
drwav__on_read_memory(void * pUserData,void * pBufferOut,size_t bytesToRead)3064 static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
3065 {
3066 drwav* pWav = (drwav*)pUserData;
3067 size_t bytesRemaining;
3068
3069 DRWAV_ASSERT(pWav != NULL);
3070 DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
3071
3072 bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
3073 if (bytesToRead > bytesRemaining) {
3074 bytesToRead = bytesRemaining;
3075 }
3076
3077 if (bytesToRead > 0) {
3078 DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
3079 pWav->memoryStream.currentReadPos += bytesToRead;
3080 }
3081
3082 return bytesToRead;
3083 }
3084
drwav__on_seek_memory(void * pUserData,int offset,drwav_seek_origin origin)3085 static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
3086 {
3087 drwav* pWav = (drwav*)pUserData;
3088 DRWAV_ASSERT(pWav != NULL);
3089
3090 if (origin == drwav_seek_origin_current) {
3091 if (offset > 0) {
3092 if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
3093 return DRWAV_FALSE; /* Trying to seek too far forward. */
3094 }
3095 } else {
3096 if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
3097 return DRWAV_FALSE; /* Trying to seek too far backwards. */
3098 }
3099 }
3100
3101 /* This will never underflow thanks to the clamps above. */
3102 pWav->memoryStream.currentReadPos += offset;
3103 } else {
3104 if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
3105 pWav->memoryStream.currentReadPos = offset;
3106 } else {
3107 return DRWAV_FALSE; /* Trying to seek too far forward. */
3108 }
3109 }
3110
3111 return DRWAV_TRUE;
3112 }
3113
drwav__on_write_memory(void * pUserData,const void * pDataIn,size_t bytesToWrite)3114 static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
3115 {
3116 drwav* pWav = (drwav*)pUserData;
3117 size_t bytesRemaining;
3118
3119 DRWAV_ASSERT(pWav != NULL);
3120 DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
3121
3122 bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos;
3123 if (bytesRemaining < bytesToWrite) {
3124 /* Need to reallocate. */
3125 void* pNewData;
3126 size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2;
3127
3128 /* If doubling wasn't enough, just make it the minimum required size to write the data. */
3129 if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) {
3130 newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite;
3131 }
3132
3133 pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
3134 if (pNewData == NULL) {
3135 return 0;
3136 }
3137
3138 *pWav->memoryStreamWrite.ppData = pNewData;
3139 pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
3140 }
3141
3142 DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
3143
3144 pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
3145 if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
3146 pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
3147 }
3148
3149 *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
3150
3151 return bytesToWrite;
3152 }
3153
drwav__on_seek_memory_write(void * pUserData,int offset,drwav_seek_origin origin)3154 static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
3155 {
3156 drwav* pWav = (drwav*)pUserData;
3157 DRWAV_ASSERT(pWav != NULL);
3158
3159 if (origin == drwav_seek_origin_current) {
3160 if (offset > 0) {
3161 if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
3162 offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); /* Trying to seek too far forward. */
3163 }
3164 } else {
3165 if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
3166 offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */
3167 }
3168 }
3169
3170 /* This will never underflow thanks to the clamps above. */
3171 pWav->memoryStreamWrite.currentWritePos += offset;
3172 } else {
3173 if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
3174 pWav->memoryStreamWrite.currentWritePos = offset;
3175 } else {
3176 pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */
3177 }
3178 }
3179
3180 return DRWAV_TRUE;
3181 }
3182
drwav_init_memory(drwav * pWav,const void * data,size_t dataSize,const drwav_allocation_callbacks * pAllocationCallbacks)3183 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
3184 {
3185 return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
3186 }
3187
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)3188 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)
3189 {
3190 if (data == NULL || dataSize == 0) {
3191 return DRWAV_FALSE;
3192 }
3193
3194 if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
3195 return DRWAV_FALSE;
3196 }
3197
3198 pWav->memoryStream.data = (const unsigned char*)data;
3199 pWav->memoryStream.dataSize = dataSize;
3200 pWav->memoryStream.currentReadPos = 0;
3201
3202 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
3203 }
3204
3205
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)3206 static 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)
3207 {
3208 if (ppData == NULL || pDataSize == NULL) {
3209 return DRWAV_FALSE;
3210 }
3211
3212 *ppData = NULL; /* Important because we're using realloc()! */
3213 *pDataSize = 0;
3214
3215 if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
3216 return DRWAV_FALSE;
3217 }
3218
3219 pWav->memoryStreamWrite.ppData = ppData;
3220 pWav->memoryStreamWrite.pDataSize = pDataSize;
3221 pWav->memoryStreamWrite.dataSize = 0;
3222 pWav->memoryStreamWrite.dataCapacity = 0;
3223 pWav->memoryStreamWrite.currentWritePos = 0;
3224
3225 return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
3226 }
3227
drwav_init_memory_write(drwav * pWav,void ** ppData,size_t * pDataSize,const drwav_data_format * pFormat,const drwav_allocation_callbacks * pAllocationCallbacks)3228 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)
3229 {
3230 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3231 }
3232
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)3233 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)
3234 {
3235 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3236 }
3237
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)3238 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)
3239 {
3240 if (pFormat == NULL) {
3241 return DRWAV_FALSE;
3242 }
3243
3244 return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3245 }
3246
3247
3248
drwav_uninit(drwav * pWav)3249 DRWAV_API drwav_result drwav_uninit(drwav* pWav)
3250 {
3251 drwav_result result = DRWAV_SUCCESS;
3252
3253 if (pWav == NULL) {
3254 return DRWAV_INVALID_ARGS;
3255 }
3256
3257 /*
3258 If the drwav object was opened in write mode we'll need to finalize a few things:
3259 - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers.
3260 - Set the size of the "data" chunk.
3261 */
3262 if (pWav->onWrite != NULL) {
3263 drwav_uint32 paddingSize = 0;
3264
3265 /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */
3266 if (pWav->container == drwav_container_riff) {
3267 paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
3268 } else {
3269 paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
3270 }
3271
3272 if (paddingSize > 0) {
3273 drwav_uint64 paddingData = 0;
3274 pWav->onWrite(pWav->pUserData, &paddingData, paddingSize);
3275 }
3276
3277 /*
3278 Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need
3279 to do this when using non-sequential mode.
3280 */
3281 if (pWav->onSeek && !pWav->isSequentialWrite) {
3282 if (pWav->container == drwav_container_riff) {
3283 /* The "RIFF" chunk size. */
3284 if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
3285 drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize);
3286 pWav->onWrite(pWav->pUserData, &riffChunkSize, 4);
3287 }
3288
3289 /* the "data" chunk size. */
3290 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) {
3291 drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
3292 pWav->onWrite(pWav->pUserData, &dataChunkSize, 4);
3293 }
3294 } else {
3295 /* The "RIFF" chunk size. */
3296 if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
3297 drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
3298 pWav->onWrite(pWav->pUserData, &riffChunkSize, 8);
3299 }
3300
3301 /* The "data" chunk size. */
3302 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) {
3303 drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
3304 pWav->onWrite(pWav->pUserData, &dataChunkSize, 8);
3305 }
3306 }
3307 }
3308
3309 /* Validation for sequential mode. */
3310 if (pWav->isSequentialWrite) {
3311 if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
3312 result = DRWAV_INVALID_FILE;
3313 }
3314 }
3315 }
3316
3317 #ifndef DR_WAV_NO_STDIO
3318 /*
3319 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()
3320 was used by looking at the onRead and onSeek callbacks.
3321 */
3322 if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
3323 fclose((FILE*)pWav->pUserData);
3324 }
3325 #endif
3326
3327 return result;
3328 }
3329
3330
3331
drwav_read_raw(drwav * pWav,size_t bytesToRead,void * pBufferOut)3332 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
3333 {
3334 size_t bytesRead;
3335
3336 if (pWav == NULL || bytesToRead == 0 || pBufferOut == NULL) {
3337 return 0;
3338 }
3339
3340 if (bytesToRead > pWav->bytesRemaining) {
3341 bytesToRead = (size_t)pWav->bytesRemaining;
3342 }
3343
3344 bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
3345
3346 pWav->bytesRemaining -= bytesRead;
3347 return bytesRead;
3348 }
3349
3350
3351
drwav_read_pcm_frames_le(drwav * pWav,drwav_uint64 framesToRead,void * pBufferOut)3352 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3353 {
3354 drwav_uint32 bytesPerFrame;
3355
3356 if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) {
3357 return 0;
3358 }
3359
3360 /* Cannot use this function for compressed formats. */
3361 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3362 return 0;
3363 }
3364
3365 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
3366 if (bytesPerFrame == 0) {
3367 return 0;
3368 }
3369
3370 /* Don't try to read more samples than can potentially fit in the output buffer. */
3371 if (framesToRead * bytesPerFrame > DRWAV_SIZE_MAX) {
3372 framesToRead = DRWAV_SIZE_MAX / bytesPerFrame;
3373 }
3374
3375 return drwav_read_raw(pWav, (size_t)(framesToRead * bytesPerFrame), pBufferOut) / bytesPerFrame;
3376 }
3377
drwav_read_pcm_frames_be(drwav * pWav,drwav_uint64 framesToRead,void * pBufferOut)3378 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3379 {
3380 drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
3381 drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag);
3382
3383 return framesRead;
3384 }
3385
drwav_read_pcm_frames(drwav * pWav,drwav_uint64 framesToRead,void * pBufferOut)3386 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3387 {
3388 if (drwav__is_little_endian()) {
3389 return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
3390 } else {
3391 return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
3392 }
3393 }
3394
3395
3396
drwav_seek_to_first_pcm_frame(drwav * pWav)3397 DRWAV_API drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
3398 {
3399 if (pWav->onWrite != NULL) {
3400 return DRWAV_FALSE; /* No seeking in write mode. */
3401 }
3402
3403 if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
3404 return DRWAV_FALSE;
3405 }
3406
3407 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3408 pWav->compressed.iCurrentPCMFrame = 0;
3409 }
3410
3411 pWav->bytesRemaining = pWav->dataChunkDataSize;
3412 return DRWAV_TRUE;
3413 }
3414
drwav_seek_to_pcm_frame(drwav * pWav,drwav_uint64 targetFrameIndex)3415 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex)
3416 {
3417 /* Seeking should be compatible with wave files > 2GB. */
3418
3419 if (pWav == NULL || pWav->onSeek == NULL) {
3420 return DRWAV_FALSE;
3421 }
3422
3423 /* No seeking in write mode. */
3424 if (pWav->onWrite != NULL) {
3425 return DRWAV_FALSE;
3426 }
3427
3428 /* If there are no samples, just return DRWAV_TRUE without doing anything. */
3429 if (pWav->totalPCMFrameCount == 0) {
3430 return DRWAV_TRUE;
3431 }
3432
3433 /* Make sure the sample is clamped. */
3434 if (targetFrameIndex >= pWav->totalPCMFrameCount) {
3435 targetFrameIndex = pWav->totalPCMFrameCount - 1;
3436 }
3437
3438 /*
3439 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
3440 to seek back to the start.
3441 */
3442 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3443 /* TODO: This can be optimized. */
3444
3445 /*
3446 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,
3447 we first need to seek back to the start and then just do the same thing as a forward seek.
3448 */
3449 if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) {
3450 if (!drwav_seek_to_first_pcm_frame(pWav)) {
3451 return DRWAV_FALSE;
3452 }
3453 }
3454
3455 if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) {
3456 drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame;
3457
3458 drwav_int16 devnull[2048];
3459 while (offsetInFrames > 0) {
3460 drwav_uint64 framesRead = 0;
3461 drwav_uint64 framesToRead = offsetInFrames;
3462 if (framesToRead > drwav_countof(devnull)/pWav->channels) {
3463 framesToRead = drwav_countof(devnull)/pWav->channels;
3464 }
3465
3466 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3467 framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull);
3468 } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3469 framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull);
3470 } else {
3471 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. */
3472 }
3473
3474 if (framesRead != framesToRead) {
3475 return DRWAV_FALSE;
3476 }
3477
3478 offsetInFrames -= framesRead;
3479 }
3480 }
3481 } else {
3482 drwav_uint64 totalSizeInBytes;
3483 drwav_uint64 currentBytePos;
3484 drwav_uint64 targetBytePos;
3485 drwav_uint64 offset;
3486
3487 totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav);
3488 DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);
3489
3490 currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
3491 targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav);
3492
3493 if (currentBytePos < targetBytePos) {
3494 /* Offset forwards. */
3495 offset = (targetBytePos - currentBytePos);
3496 } else {
3497 /* Offset backwards. */
3498 if (!drwav_seek_to_first_pcm_frame(pWav)) {
3499 return DRWAV_FALSE;
3500 }
3501 offset = targetBytePos;
3502 }
3503
3504 while (offset > 0) {
3505 int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
3506 if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
3507 return DRWAV_FALSE;
3508 }
3509
3510 pWav->bytesRemaining -= offset32;
3511 offset -= offset32;
3512 }
3513 }
3514
3515 return DRWAV_TRUE;
3516 }
3517
3518
drwav_write_raw(drwav * pWav,size_t bytesToWrite,const void * pData)3519 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
3520 {
3521 size_t bytesWritten;
3522
3523 if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
3524 return 0;
3525 }
3526
3527 bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
3528 pWav->dataChunkDataSize += bytesWritten;
3529
3530 return bytesWritten;
3531 }
3532
3533
drwav_write_pcm_frames_le(drwav * pWav,drwav_uint64 framesToWrite,const void * pData)3534 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3535 {
3536 drwav_uint64 bytesToWrite;
3537 drwav_uint64 bytesWritten;
3538 const drwav_uint8* pRunningData;
3539
3540 if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
3541 return 0;
3542 }
3543
3544 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
3545 if (bytesToWrite > DRWAV_SIZE_MAX) {
3546 return 0;
3547 }
3548
3549 bytesWritten = 0;
3550 pRunningData = (const drwav_uint8*)pData;
3551
3552 while (bytesToWrite > 0) {
3553 size_t bytesJustWritten;
3554 drwav_uint64 bytesToWriteThisIteration;
3555
3556 bytesToWriteThisIteration = bytesToWrite;
3557 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */
3558
3559 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData);
3560 if (bytesJustWritten == 0) {
3561 break;
3562 }
3563
3564 bytesToWrite -= bytesJustWritten;
3565 bytesWritten += bytesJustWritten;
3566 pRunningData += bytesJustWritten;
3567 }
3568
3569 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
3570 }
3571
drwav_write_pcm_frames_be(drwav * pWav,drwav_uint64 framesToWrite,const void * pData)3572 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3573 {
3574 drwav_uint64 bytesToWrite;
3575 drwav_uint64 bytesWritten;
3576 drwav_uint32 bytesPerSample;
3577 const drwav_uint8* pRunningData;
3578
3579 if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
3580 return 0;
3581 }
3582
3583 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
3584 if (bytesToWrite > DRWAV_SIZE_MAX) {
3585 return 0;
3586 }
3587
3588 bytesWritten = 0;
3589 pRunningData = (const drwav_uint8*)pData;
3590
3591 bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels;
3592
3593 while (bytesToWrite > 0) {
3594 drwav_uint8 temp[4096];
3595 drwav_uint32 sampleCount;
3596 size_t bytesJustWritten;
3597 drwav_uint64 bytesToWriteThisIteration;
3598
3599 bytesToWriteThisIteration = bytesToWrite;
3600 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */
3601
3602 /*
3603 WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need
3604 to use an intermediary buffer for the conversion.
3605 */
3606 sampleCount = sizeof(temp)/bytesPerSample;
3607
3608 if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) {
3609 bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample;
3610 }
3611
3612 DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration);
3613 drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag);
3614
3615 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp);
3616 if (bytesJustWritten == 0) {
3617 break;
3618 }
3619
3620 bytesToWrite -= bytesJustWritten;
3621 bytesWritten += bytesJustWritten;
3622 pRunningData += bytesJustWritten;
3623 }
3624
3625 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
3626 }
3627
drwav_write_pcm_frames(drwav * pWav,drwav_uint64 framesToWrite,const void * pData)3628 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3629 {
3630 if (drwav__is_little_endian()) {
3631 return drwav_write_pcm_frames_le(pWav, framesToWrite, pData);
3632 } else {
3633 return drwav_write_pcm_frames_be(pWav, framesToWrite, pData);
3634 }
3635 }
3636
3637
drwav_read_pcm_frames_s16__msadpcm(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)3638 static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
3639 {
3640 drwav_uint64 totalFramesRead = 0;
3641
3642 DRWAV_ASSERT(pWav != NULL);
3643 DRWAV_ASSERT(framesToRead > 0);
3644 DRWAV_ASSERT(pBufferOut != NULL);
3645
3646 /* TODO: Lots of room for optimization here. */
3647
3648 while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
3649 /* If there are no cached frames we need to load a new block. */
3650 if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) {
3651 if (pWav->channels == 1) {
3652 /* Mono. */
3653 drwav_uint8 header[7];
3654 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
3655 return totalFramesRead;
3656 }
3657 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
3658
3659 pWav->msadpcm.predictor[0] = header[0];
3660 pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 1);
3661 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 3);
3662 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 5);
3663 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0];
3664 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1];
3665 pWav->msadpcm.cachedFrameCount = 2;
3666 } else {
3667 /* Stereo. */
3668 drwav_uint8 header[14];
3669 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
3670 return totalFramesRead;
3671 }
3672 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
3673
3674 pWav->msadpcm.predictor[0] = header[0];
3675 pWav->msadpcm.predictor[1] = header[1];
3676 pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 2);
3677 pWav->msadpcm.delta[1] = drwav__bytes_to_s16(header + 4);
3678 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 6);
3679 pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav__bytes_to_s16(header + 8);
3680 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 10);
3681 pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav__bytes_to_s16(header + 12);
3682
3683 pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0];
3684 pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0];
3685 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
3686 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
3687 pWav->msadpcm.cachedFrameCount = 2;
3688 }
3689 }
3690
3691 /* Output anything that's cached. */
3692 while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
3693 drwav_uint32 iSample = 0;
3694 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
3695 pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample];
3696 }
3697
3698 pBufferOut += pWav->channels;
3699 framesToRead -= 1;
3700 totalFramesRead += 1;
3701 pWav->compressed.iCurrentPCMFrame += 1;
3702 pWav->msadpcm.cachedFrameCount -= 1;
3703 }
3704
3705 if (framesToRead == 0) {
3706 return totalFramesRead;
3707 }
3708
3709
3710 /*
3711 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
3712 loop iteration which will trigger the loading of a new block.
3713 */
3714 if (pWav->msadpcm.cachedFrameCount == 0) {
3715 if (pWav->msadpcm.bytesRemainingInBlock == 0) {
3716 continue;
3717 } else {
3718 static drwav_int32 adaptationTable[] = {
3719 230, 230, 230, 230, 307, 409, 512, 614,
3720 768, 614, 512, 409, 307, 230, 230, 230
3721 };
3722 static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
3723 static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
3724
3725 drwav_uint8 nibbles;
3726 drwav_int32 nibble0;
3727 drwav_int32 nibble1;
3728
3729 if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
3730 return totalFramesRead;
3731 }
3732 pWav->msadpcm.bytesRemainingInBlock -= 1;
3733
3734 /* TODO: Optimize away these if statements. */
3735 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; }
3736 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; }
3737
3738 if (pWav->channels == 1) {
3739 /* Mono. */
3740 drwav_int32 newSample0;
3741 drwav_int32 newSample1;
3742
3743 newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
3744 newSample0 += nibble0 * pWav->msadpcm.delta[0];
3745 newSample0 = drwav_clamp(newSample0, -32768, 32767);
3746
3747 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
3748 if (pWav->msadpcm.delta[0] < 16) {
3749 pWav->msadpcm.delta[0] = 16;
3750 }
3751
3752 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
3753 pWav->msadpcm.prevFrames[0][1] = newSample0;
3754
3755
3756 newSample1 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
3757 newSample1 += nibble1 * pWav->msadpcm.delta[0];
3758 newSample1 = drwav_clamp(newSample1, -32768, 32767);
3759
3760 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
3761 if (pWav->msadpcm.delta[0] < 16) {
3762 pWav->msadpcm.delta[0] = 16;
3763 }
3764
3765 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
3766 pWav->msadpcm.prevFrames[0][1] = newSample1;
3767
3768
3769 pWav->msadpcm.cachedFrames[2] = newSample0;
3770 pWav->msadpcm.cachedFrames[3] = newSample1;
3771 pWav->msadpcm.cachedFrameCount = 2;
3772 } else {
3773 /* Stereo. */
3774 drwav_int32 newSample0;
3775 drwav_int32 newSample1;
3776
3777 /* Left. */
3778 newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
3779 newSample0 += nibble0 * pWav->msadpcm.delta[0];
3780 newSample0 = drwav_clamp(newSample0, -32768, 32767);
3781
3782 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
3783 if (pWav->msadpcm.delta[0] < 16) {
3784 pWav->msadpcm.delta[0] = 16;
3785 }
3786
3787 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
3788 pWav->msadpcm.prevFrames[0][1] = newSample0;
3789
3790
3791 /* Right. */
3792 newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
3793 newSample1 += nibble1 * pWav->msadpcm.delta[1];
3794 newSample1 = drwav_clamp(newSample1, -32768, 32767);
3795
3796 pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
3797 if (pWav->msadpcm.delta[1] < 16) {
3798 pWav->msadpcm.delta[1] = 16;
3799 }
3800
3801 pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
3802 pWav->msadpcm.prevFrames[1][1] = newSample1;
3803
3804 pWav->msadpcm.cachedFrames[2] = newSample0;
3805 pWav->msadpcm.cachedFrames[3] = newSample1;
3806 pWav->msadpcm.cachedFrameCount = 1;
3807 }
3808 }
3809 }
3810 }
3811
3812 return totalFramesRead;
3813 }
3814
3815
drwav_read_pcm_frames_s16__ima(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)3816 static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
3817 {
3818 drwav_uint64 totalFramesRead = 0;
3819
3820 DRWAV_ASSERT(pWav != NULL);
3821 DRWAV_ASSERT(framesToRead > 0);
3822 DRWAV_ASSERT(pBufferOut != NULL);
3823
3824 /* TODO: Lots of room for optimization here. */
3825
3826 while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
3827 /* If there are no cached samples we need to load a new block. */
3828 if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) {
3829 if (pWav->channels == 1) {
3830 /* Mono. */
3831 drwav_uint8 header[4];
3832 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
3833 return totalFramesRead;
3834 }
3835 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
3836
3837 pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0);
3838 pWav->ima.stepIndex[0] = header[2];
3839 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0];
3840 pWav->ima.cachedFrameCount = 1;
3841 } else {
3842 /* Stereo. */
3843 drwav_uint8 header[8];
3844 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
3845 return totalFramesRead;
3846 }
3847 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
3848
3849 pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0);
3850 pWav->ima.stepIndex[0] = header[2];
3851 pWav->ima.predictor[1] = drwav__bytes_to_s16(header + 4);
3852 pWav->ima.stepIndex[1] = header[6];
3853
3854 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0];
3855 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1];
3856 pWav->ima.cachedFrameCount = 1;
3857 }
3858 }
3859
3860 /* Output anything that's cached. */
3861 while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
3862 drwav_uint32 iSample;
3863 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
3864 pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample];
3865 }
3866
3867 pBufferOut += pWav->channels;
3868 framesToRead -= 1;
3869 totalFramesRead += 1;
3870 pWav->compressed.iCurrentPCMFrame += 1;
3871 pWav->ima.cachedFrameCount -= 1;
3872 }
3873
3874 if (framesToRead == 0) {
3875 return totalFramesRead;
3876 }
3877
3878 /*
3879 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
3880 loop iteration which will trigger the loading of a new block.
3881 */
3882 if (pWav->ima.cachedFrameCount == 0) {
3883 if (pWav->ima.bytesRemainingInBlock == 0) {
3884 continue;
3885 } else {
3886 static drwav_int32 indexTable[16] = {
3887 -1, -1, -1, -1, 2, 4, 6, 8,
3888 -1, -1, -1, -1, 2, 4, 6, 8
3889 };
3890
3891 static drwav_int32 stepTable[89] = {
3892 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
3893 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
3894 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
3895 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
3896 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
3897 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
3898 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
3899 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
3900 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
3901 };
3902
3903 drwav_uint32 iChannel;
3904
3905 /*
3906 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
3907 left channel, 4 bytes for the right channel.
3908 */
3909 pWav->ima.cachedFrameCount = 8;
3910 for (iChannel = 0; iChannel < pWav->channels; ++iChannel) {
3911 drwav_uint32 iByte;
3912 drwav_uint8 nibbles[4];
3913 if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) {
3914 pWav->ima.cachedFrameCount = 0;
3915 return totalFramesRead;
3916 }
3917 pWav->ima.bytesRemainingInBlock -= 4;
3918
3919 for (iByte = 0; iByte < 4; ++iByte) {
3920 drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
3921 drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
3922
3923 drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]];
3924 drwav_int32 predictor = pWav->ima.predictor[iChannel];
3925
3926 drwav_int32 diff = step >> 3;
3927 if (nibble0 & 1) diff += step >> 2;
3928 if (nibble0 & 2) diff += step >> 1;
3929 if (nibble0 & 4) diff += step;
3930 if (nibble0 & 8) diff = -diff;
3931
3932 predictor = drwav_clamp(predictor + diff, -32768, 32767);
3933 pWav->ima.predictor[iChannel] = predictor;
3934 pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1);
3935 pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor;
3936
3937
3938 step = stepTable[pWav->ima.stepIndex[iChannel]];
3939 predictor = pWav->ima.predictor[iChannel];
3940
3941 diff = step >> 3;
3942 if (nibble1 & 1) diff += step >> 2;
3943 if (nibble1 & 2) diff += step >> 1;
3944 if (nibble1 & 4) diff += step;
3945 if (nibble1 & 8) diff = -diff;
3946
3947 predictor = drwav_clamp(predictor + diff, -32768, 32767);
3948 pWav->ima.predictor[iChannel] = predictor;
3949 pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1);
3950 pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor;
3951 }
3952 }
3953 }
3954 }
3955 }
3956
3957 return totalFramesRead;
3958 }
3959
3960
3961 #ifndef DR_WAV_NO_CONVERSION_API
3962 static unsigned short g_drwavAlawTable[256] = {
3963 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
3964 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
3965 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
3966 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
3967 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
3968 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
3969 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
3970 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
3971 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
3972 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
3973 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
3974 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
3975 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
3976 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
3977 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
3978 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
3979 };
3980
3981 static unsigned short g_drwavMulawTable[256] = {
3982 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
3983 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
3984 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
3985 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
3986 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
3987 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
3988 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
3989 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
3990 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
3991 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
3992 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
3993 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
3994 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
3995 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
3996 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
3997 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
3998 };
3999
drwav__alaw_to_s16(drwav_uint8 sampleIn)4000 static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
4001 {
4002 return (short)g_drwavAlawTable[sampleIn];
4003 }
4004
drwav__mulaw_to_s16(drwav_uint8 sampleIn)4005 static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
4006 {
4007 return (short)g_drwavMulawTable[sampleIn];
4008 }
4009
4010
4011
drwav__pcm_to_s16(drwav_int16 * pOut,const unsigned char * pIn,size_t totalSampleCount,unsigned int bytesPerSample)4012 static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4013 {
4014 unsigned int i;
4015
4016 /* Special case for 8-bit sample data because it's treated as unsigned. */
4017 if (bytesPerSample == 1) {
4018 drwav_u8_to_s16(pOut, pIn, totalSampleCount);
4019 return;
4020 }
4021
4022
4023 /* Slightly more optimal implementation for common formats. */
4024 if (bytesPerSample == 2) {
4025 for (i = 0; i < totalSampleCount; ++i) {
4026 *pOut++ = ((const drwav_int16*)pIn)[i];
4027 }
4028 return;
4029 }
4030 if (bytesPerSample == 3) {
4031 drwav_s24_to_s16(pOut, pIn, totalSampleCount);
4032 return;
4033 }
4034 if (bytesPerSample == 4) {
4035 drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
4036 return;
4037 }
4038
4039
4040 /* Anything more than 64 bits per sample is not supported. */
4041 if (bytesPerSample > 8) {
4042 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
4043 return;
4044 }
4045
4046
4047 /* Generic, slow converter. */
4048 for (i = 0; i < totalSampleCount; ++i) {
4049 drwav_uint64 sample = 0;
4050 unsigned int shift = (8 - bytesPerSample) * 8;
4051
4052 unsigned int j;
4053 for (j = 0; j < bytesPerSample; j += 1) {
4054 DRWAV_ASSERT(j < 8);
4055 sample |= (drwav_uint64)(pIn[j]) << shift;
4056 shift += 8;
4057 }
4058
4059 pIn += j;
4060 *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
4061 }
4062 }
4063
drwav__ieee_to_s16(drwav_int16 * pOut,const unsigned char * pIn,size_t totalSampleCount,unsigned int bytesPerSample)4064 static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4065 {
4066 if (bytesPerSample == 4) {
4067 drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount);
4068 return;
4069 } else if (bytesPerSample == 8) {
4070 drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount);
4071 return;
4072 } else {
4073 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
4074 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
4075 return;
4076 }
4077 }
4078
drwav_read_pcm_frames_s16__pcm(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)4079 static drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4080 {
4081 drwav_uint32 bytesPerFrame;
4082 drwav_uint64 totalFramesRead;
4083 unsigned char sampleData[4096];
4084
4085 /* Fast path. */
4086 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) {
4087 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
4088 }
4089
4090 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4091 if (bytesPerFrame == 0) {
4092 return 0;
4093 }
4094
4095 totalFramesRead = 0;
4096
4097 while (framesToRead > 0) {
4098 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4099 if (framesRead == 0) {
4100 break;
4101 }
4102
4103 drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4104
4105 pBufferOut += framesRead*pWav->channels;
4106 framesToRead -= framesRead;
4107 totalFramesRead += framesRead;
4108 }
4109
4110 return totalFramesRead;
4111 }
4112
drwav_read_pcm_frames_s16__ieee(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)4113 static drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4114 {
4115 drwav_uint64 totalFramesRead;
4116 unsigned char sampleData[4096];
4117
4118 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4119 if (bytesPerFrame == 0) {
4120 return 0;
4121 }
4122
4123 totalFramesRead = 0;
4124
4125 while (framesToRead > 0) {
4126 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4127 if (framesRead == 0) {
4128 break;
4129 }
4130
4131 drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4132
4133 pBufferOut += framesRead*pWav->channels;
4134 framesToRead -= framesRead;
4135 totalFramesRead += framesRead;
4136 }
4137
4138 return totalFramesRead;
4139 }
4140
drwav_read_pcm_frames_s16__alaw(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)4141 static drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4142 {
4143 drwav_uint64 totalFramesRead;
4144 unsigned char sampleData[4096];
4145
4146 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4147 if (bytesPerFrame == 0) {
4148 return 0;
4149 }
4150
4151 totalFramesRead = 0;
4152
4153 while (framesToRead > 0) {
4154 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4155 if (framesRead == 0) {
4156 break;
4157 }
4158
4159 drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4160
4161 pBufferOut += framesRead*pWav->channels;
4162 framesToRead -= framesRead;
4163 totalFramesRead += framesRead;
4164 }
4165
4166 return totalFramesRead;
4167 }
4168
drwav_read_pcm_frames_s16__mulaw(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)4169 static drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4170 {
4171 drwav_uint64 totalFramesRead;
4172 unsigned char sampleData[4096];
4173
4174 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4175 if (bytesPerFrame == 0) {
4176 return 0;
4177 }
4178
4179 totalFramesRead = 0;
4180
4181 while (framesToRead > 0) {
4182 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4183 if (framesRead == 0) {
4184 break;
4185 }
4186
4187 drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4188
4189 pBufferOut += framesRead*pWav->channels;
4190 framesToRead -= framesRead;
4191 totalFramesRead += framesRead;
4192 }
4193
4194 return totalFramesRead;
4195 }
4196
drwav_read_pcm_frames_s16(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)4197 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4198 {
4199 if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) {
4200 return 0;
4201 }
4202
4203 /* Don't try to read more samples than can potentially fit in the output buffer. */
4204 if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) {
4205 framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels;
4206 }
4207
4208 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
4209 return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut);
4210 }
4211
4212 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
4213 return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut);
4214 }
4215
4216 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
4217 return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut);
4218 }
4219
4220 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
4221 return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut);
4222 }
4223
4224 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
4225 return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut);
4226 }
4227
4228 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
4229 return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut);
4230 }
4231
4232 return 0;
4233 }
4234
drwav_read_pcm_frames_s16le(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)4235 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4236 {
4237 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
4238 if (!drwav__is_little_endian()) {
4239 drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
4240 }
4241
4242 return framesRead;
4243 }
4244
drwav_read_pcm_frames_s16be(drwav * pWav,drwav_uint64 framesToRead,drwav_int16 * pBufferOut)4245 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4246 {
4247 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
4248 if (drwav__is_little_endian()) {
4249 drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
4250 }
4251
4252 return framesRead;
4253 }
4254
4255
drwav_u8_to_s16(drwav_int16 * pOut,const drwav_uint8 * pIn,size_t sampleCount)4256 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4257 {
4258 int r;
4259 size_t i;
4260 for (i = 0; i < sampleCount; ++i) {
4261 int x = pIn[i];
4262 r = x << 8;
4263 r = r - 32768;
4264 pOut[i] = (short)r;
4265 }
4266 }
4267
drwav_s24_to_s16(drwav_int16 * pOut,const drwav_uint8 * pIn,size_t sampleCount)4268 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4269 {
4270 int r;
4271 size_t i;
4272 for (i = 0; i < sampleCount; ++i) {
4273 int x = ((int)(((unsigned int)(((const unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const unsigned char*)pIn)[i*3+2])) << 24)) >> 8;
4274 r = x >> 8;
4275 pOut[i] = (short)r;
4276 }
4277 }
4278
drwav_s32_to_s16(drwav_int16 * pOut,const drwav_int32 * pIn,size_t sampleCount)4279 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
4280 {
4281 int r;
4282 size_t i;
4283 for (i = 0; i < sampleCount; ++i) {
4284 int x = pIn[i];
4285 r = x >> 16;
4286 pOut[i] = (short)r;
4287 }
4288 }
4289
drwav_f32_to_s16(drwav_int16 * pOut,const float * pIn,size_t sampleCount)4290 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
4291 {
4292 int r;
4293 size_t i;
4294 for (i = 0; i < sampleCount; ++i) {
4295 float x = pIn[i];
4296 float c;
4297 c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
4298 c = c + 1;
4299 r = (int)(c * 32767.5f);
4300 r = r - 32768;
4301 pOut[i] = (short)r;
4302 }
4303 }
4304
drwav_f64_to_s16(drwav_int16 * pOut,const double * pIn,size_t sampleCount)4305 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
4306 {
4307 int r;
4308 size_t i;
4309 for (i = 0; i < sampleCount; ++i) {
4310 double x = pIn[i];
4311 double c;
4312 c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
4313 c = c + 1;
4314 r = (int)(c * 32767.5);
4315 r = r - 32768;
4316 pOut[i] = (short)r;
4317 }
4318 }
4319
drwav_alaw_to_s16(drwav_int16 * pOut,const drwav_uint8 * pIn,size_t sampleCount)4320 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4321 {
4322 size_t i;
4323 for (i = 0; i < sampleCount; ++i) {
4324 pOut[i] = drwav__alaw_to_s16(pIn[i]);
4325 }
4326 }
4327
drwav_mulaw_to_s16(drwav_int16 * pOut,const drwav_uint8 * pIn,size_t sampleCount)4328 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4329 {
4330 size_t i;
4331 for (i = 0; i < sampleCount; ++i) {
4332 pOut[i] = drwav__mulaw_to_s16(pIn[i]);
4333 }
4334 }
4335
4336
4337
drwav__pcm_to_f32(float * pOut,const unsigned char * pIn,size_t sampleCount,unsigned int bytesPerSample)4338 static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned int bytesPerSample)
4339 {
4340 unsigned int i;
4341
4342 /* Special case for 8-bit sample data because it's treated as unsigned. */
4343 if (bytesPerSample == 1) {
4344 drwav_u8_to_f32(pOut, pIn, sampleCount);
4345 return;
4346 }
4347
4348 /* Slightly more optimal implementation for common formats. */
4349 if (bytesPerSample == 2) {
4350 drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount);
4351 return;
4352 }
4353 if (bytesPerSample == 3) {
4354 drwav_s24_to_f32(pOut, pIn, sampleCount);
4355 return;
4356 }
4357 if (bytesPerSample == 4) {
4358 drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
4359 return;
4360 }
4361
4362
4363 /* Anything more than 64 bits per sample is not supported. */
4364 if (bytesPerSample > 8) {
4365 DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
4366 return;
4367 }
4368
4369
4370 /* Generic, slow converter. */
4371 for (i = 0; i < sampleCount; ++i) {
4372 drwav_uint64 sample = 0;
4373 unsigned int shift = (8 - bytesPerSample) * 8;
4374
4375 unsigned int j;
4376 for (j = 0; j < bytesPerSample; j += 1) {
4377 DRWAV_ASSERT(j < 8);
4378 sample |= (drwav_uint64)(pIn[j]) << shift;
4379 shift += 8;
4380 }
4381
4382 pIn += j;
4383 *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
4384 }
4385 }
4386
drwav__ieee_to_f32(float * pOut,const unsigned char * pIn,size_t sampleCount,unsigned int bytesPerSample)4387 static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned int bytesPerSample)
4388 {
4389 if (bytesPerSample == 4) {
4390 unsigned int i;
4391 for (i = 0; i < sampleCount; ++i) {
4392 *pOut++ = ((const float*)pIn)[i];
4393 }
4394 return;
4395 } else if (bytesPerSample == 8) {
4396 drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount);
4397 return;
4398 } else {
4399 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
4400 DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
4401 return;
4402 }
4403 }
4404
4405
drwav_read_pcm_frames_f32__pcm(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4406 static drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4407 {
4408 drwav_uint64 totalFramesRead;
4409 unsigned char sampleData[4096];
4410
4411 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4412 if (bytesPerFrame == 0) {
4413 return 0;
4414 }
4415
4416 totalFramesRead = 0;
4417
4418 while (framesToRead > 0) {
4419 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4420 if (framesRead == 0) {
4421 break;
4422 }
4423
4424 drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels);
4425
4426 pBufferOut += framesRead*pWav->channels;
4427 framesToRead -= framesRead;
4428 totalFramesRead += framesRead;
4429 }
4430
4431 return totalFramesRead;
4432 }
4433
drwav_read_pcm_frames_f32__msadpcm(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4434 static drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4435 {
4436 /*
4437 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
4438 want to duplicate that code.
4439 */
4440 drwav_uint64 totalFramesRead = 0;
4441 drwav_int16 samples16[2048];
4442 while (framesToRead > 0) {
4443 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
4444 if (framesRead == 0) {
4445 break;
4446 }
4447
4448 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
4449
4450 pBufferOut += framesRead*pWav->channels;
4451 framesToRead -= framesRead;
4452 totalFramesRead += framesRead;
4453 }
4454
4455 return totalFramesRead;
4456 }
4457
drwav_read_pcm_frames_f32__ima(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4458 static drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4459 {
4460 /*
4461 We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't
4462 want to duplicate that code.
4463 */
4464 drwav_uint64 totalFramesRead = 0;
4465 drwav_int16 samples16[2048];
4466 while (framesToRead > 0) {
4467 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
4468 if (framesRead == 0) {
4469 break;
4470 }
4471
4472 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
4473
4474 pBufferOut += framesRead*pWav->channels;
4475 framesToRead -= framesRead;
4476 totalFramesRead += framesRead;
4477 }
4478
4479 return totalFramesRead;
4480 }
4481
drwav_read_pcm_frames_f32__ieee(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4482 static drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4483 {
4484 drwav_uint64 totalFramesRead;
4485 unsigned char sampleData[4096];
4486 drwav_uint32 bytesPerFrame;
4487
4488 /* Fast path. */
4489 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) {
4490 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
4491 }
4492
4493 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4494 if (bytesPerFrame == 0) {
4495 return 0;
4496 }
4497
4498 totalFramesRead = 0;
4499
4500 while (framesToRead > 0) {
4501 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4502 if (framesRead == 0) {
4503 break;
4504 }
4505
4506 drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4507
4508 pBufferOut += framesRead*pWav->channels;
4509 framesToRead -= framesRead;
4510 totalFramesRead += framesRead;
4511 }
4512
4513 return totalFramesRead;
4514 }
4515
drwav_read_pcm_frames_f32__alaw(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4516 static drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4517 {
4518 drwav_uint64 totalFramesRead;
4519 unsigned char sampleData[4096];
4520 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4521 if (bytesPerFrame == 0) {
4522 return 0;
4523 }
4524
4525 totalFramesRead = 0;
4526
4527 while (framesToRead > 0) {
4528 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4529 if (framesRead == 0) {
4530 break;
4531 }
4532
4533 drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4534
4535 pBufferOut += framesRead*pWav->channels;
4536 framesToRead -= framesRead;
4537 totalFramesRead += framesRead;
4538 }
4539
4540 return totalFramesRead;
4541 }
4542
drwav_read_pcm_frames_f32__mulaw(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4543 static drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4544 {
4545 drwav_uint64 totalFramesRead;
4546 unsigned char sampleData[4096];
4547
4548 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4549 if (bytesPerFrame == 0) {
4550 return 0;
4551 }
4552
4553 totalFramesRead = 0;
4554
4555 while (framesToRead > 0) {
4556 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4557 if (framesRead == 0) {
4558 break;
4559 }
4560
4561 drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4562
4563 pBufferOut += framesRead*pWav->channels;
4564 framesToRead -= framesRead;
4565 totalFramesRead += framesRead;
4566 }
4567
4568 return totalFramesRead;
4569 }
4570
drwav_read_pcm_frames_f32(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4571 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4572 {
4573 if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) {
4574 return 0;
4575 }
4576
4577 /* Don't try to read more samples than can potentially fit in the output buffer. */
4578 if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) {
4579 framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels;
4580 }
4581
4582 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
4583 return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut);
4584 }
4585
4586 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
4587 return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut);
4588 }
4589
4590 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
4591 return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut);
4592 }
4593
4594 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
4595 return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut);
4596 }
4597
4598 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
4599 return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut);
4600 }
4601
4602 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
4603 return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut);
4604 }
4605
4606 return 0;
4607 }
4608
drwav_read_pcm_frames_f32le(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4609 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4610 {
4611 drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
4612 if (!drwav__is_little_endian()) {
4613 drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
4614 }
4615
4616 return framesRead;
4617 }
4618
drwav_read_pcm_frames_f32be(drwav * pWav,drwav_uint64 framesToRead,float * pBufferOut)4619 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4620 {
4621 drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
4622 if (drwav__is_little_endian()) {
4623 drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
4624 }
4625
4626 return framesRead;
4627 }
4628
4629
drwav_u8_to_f32(float * pOut,const drwav_uint8 * pIn,size_t sampleCount)4630 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4631 {
4632 size_t i;
4633
4634 if (pOut == NULL || pIn == NULL) {
4635 return;
4636 }
4637
4638 #ifdef DR_WAV_LIBSNDFILE_COMPAT
4639 /*
4640 It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears
4641 libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note
4642 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
4643 correctness testing. This is disabled by default.
4644 */
4645 for (i = 0; i < sampleCount; ++i) {
4646 *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
4647 }
4648 #else
4649 for (i = 0; i < sampleCount; ++i) {
4650 float x = pIn[i];
4651 x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */
4652 x = x - 1; /* 0..2 to -1..1 */
4653
4654 *pOut++ = x;
4655 }
4656 #endif
4657 }
4658
drwav_s16_to_f32(float * pOut,const drwav_int16 * pIn,size_t sampleCount)4659 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
4660 {
4661 size_t i;
4662
4663 if (pOut == NULL || pIn == NULL) {
4664 return;
4665 }
4666
4667 for (i = 0; i < sampleCount; ++i) {
4668 *pOut++ = pIn[i] * 0.000030517578125f;
4669 }
4670 }
4671
drwav_s24_to_f32(float * pOut,const drwav_uint8 * pIn,size_t sampleCount)4672 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4673 {
4674 size_t i;
4675
4676 if (pOut == NULL || pIn == NULL) {
4677 return;
4678 }
4679
4680 for (i = 0; i < sampleCount; ++i) {
4681 double x = (double)(((drwav_int32)(((drwav_uint32)(pIn[i*3+0]) << 8) | ((drwav_uint32)(pIn[i*3+1]) << 16) | ((drwav_uint32)(pIn[i*3+2])) << 24)) >> 8);
4682 *pOut++ = (float)(x * 0.00000011920928955078125);
4683 }
4684 }
4685
drwav_s32_to_f32(float * pOut,const drwav_int32 * pIn,size_t sampleCount)4686 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
4687 {
4688 size_t i;
4689 if (pOut == NULL || pIn == NULL) {
4690 return;
4691 }
4692
4693 for (i = 0; i < sampleCount; ++i) {
4694 *pOut++ = (float)(pIn[i] / 2147483648.0);
4695 }
4696 }
4697
drwav_f64_to_f32(float * pOut,const double * pIn,size_t sampleCount)4698 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
4699 {
4700 size_t i;
4701
4702 if (pOut == NULL || pIn == NULL) {
4703 return;
4704 }
4705
4706 for (i = 0; i < sampleCount; ++i) {
4707 *pOut++ = (float)pIn[i];
4708 }
4709 }
4710
drwav_alaw_to_f32(float * pOut,const drwav_uint8 * pIn,size_t sampleCount)4711 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4712 {
4713 size_t i;
4714
4715 if (pOut == NULL || pIn == NULL) {
4716 return;
4717 }
4718
4719 for (i = 0; i < sampleCount; ++i) {
4720 *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
4721 }
4722 }
4723
drwav_mulaw_to_f32(float * pOut,const drwav_uint8 * pIn,size_t sampleCount)4724 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4725 {
4726 size_t i;
4727
4728 if (pOut == NULL || pIn == NULL) {
4729 return;
4730 }
4731
4732 for (i = 0; i < sampleCount; ++i) {
4733 *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
4734 }
4735 }
4736
4737
4738
drwav__pcm_to_s32(drwav_int32 * pOut,const unsigned char * pIn,size_t totalSampleCount,unsigned int bytesPerSample)4739 static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4740 {
4741 unsigned int i;
4742
4743 /* Special case for 8-bit sample data because it's treated as unsigned. */
4744 if (bytesPerSample == 1) {
4745 drwav_u8_to_s32(pOut, pIn, totalSampleCount);
4746 return;
4747 }
4748
4749 /* Slightly more optimal implementation for common formats. */
4750 if (bytesPerSample == 2) {
4751 drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount);
4752 return;
4753 }
4754 if (bytesPerSample == 3) {
4755 drwav_s24_to_s32(pOut, pIn, totalSampleCount);
4756 return;
4757 }
4758 if (bytesPerSample == 4) {
4759 for (i = 0; i < totalSampleCount; ++i) {
4760 *pOut++ = ((const drwav_int32*)pIn)[i];
4761 }
4762 return;
4763 }
4764
4765
4766 /* Anything more than 64 bits per sample is not supported. */
4767 if (bytesPerSample > 8) {
4768 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
4769 return;
4770 }
4771
4772
4773 /* Generic, slow converter. */
4774 for (i = 0; i < totalSampleCount; ++i) {
4775 drwav_uint64 sample = 0;
4776 unsigned int shift = (8 - bytesPerSample) * 8;
4777
4778 unsigned int j;
4779 for (j = 0; j < bytesPerSample; j += 1) {
4780 DRWAV_ASSERT(j < 8);
4781 sample |= (drwav_uint64)(pIn[j]) << shift;
4782 shift += 8;
4783 }
4784
4785 pIn += j;
4786 *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
4787 }
4788 }
4789
drwav__ieee_to_s32(drwav_int32 * pOut,const unsigned char * pIn,size_t totalSampleCount,unsigned int bytesPerSample)4790 static void drwav__ieee_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4791 {
4792 if (bytesPerSample == 4) {
4793 drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount);
4794 return;
4795 } else if (bytesPerSample == 8) {
4796 drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount);
4797 return;
4798 } else {
4799 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
4800 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
4801 return;
4802 }
4803 }
4804
4805
drwav_read_pcm_frames_s32__pcm(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)4806 static drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
4807 {
4808 drwav_uint64 totalFramesRead;
4809 unsigned char sampleData[4096];
4810 drwav_uint32 bytesPerFrame;
4811
4812 /* Fast path. */
4813 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) {
4814 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
4815 }
4816
4817 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4818 if (bytesPerFrame == 0) {
4819 return 0;
4820 }
4821
4822 totalFramesRead = 0;
4823
4824 while (framesToRead > 0) {
4825 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4826 if (framesRead == 0) {
4827 break;
4828 }
4829
4830 drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4831
4832 pBufferOut += framesRead*pWav->channels;
4833 framesToRead -= framesRead;
4834 totalFramesRead += framesRead;
4835 }
4836
4837 return totalFramesRead;
4838 }
4839
drwav_read_pcm_frames_s32__msadpcm(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)4840 static drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
4841 {
4842 /*
4843 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
4844 want to duplicate that code.
4845 */
4846 drwav_uint64 totalFramesRead = 0;
4847 drwav_int16 samples16[2048];
4848 while (framesToRead > 0) {
4849 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
4850 if (framesRead == 0) {
4851 break;
4852 }
4853
4854 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
4855
4856 pBufferOut += framesRead*pWav->channels;
4857 framesToRead -= framesRead;
4858 totalFramesRead += framesRead;
4859 }
4860
4861 return totalFramesRead;
4862 }
4863
drwav_read_pcm_frames_s32__ima(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)4864 static drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
4865 {
4866 /*
4867 We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't
4868 want to duplicate that code.
4869 */
4870 drwav_uint64 totalFramesRead = 0;
4871 drwav_int16 samples16[2048];
4872 while (framesToRead > 0) {
4873 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
4874 if (framesRead == 0) {
4875 break;
4876 }
4877
4878 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
4879
4880 pBufferOut += framesRead*pWav->channels;
4881 framesToRead -= framesRead;
4882 totalFramesRead += framesRead;
4883 }
4884
4885 return totalFramesRead;
4886 }
4887
drwav_read_pcm_frames_s32__ieee(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)4888 static drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
4889 {
4890 drwav_uint64 totalFramesRead;
4891 unsigned char sampleData[4096];
4892
4893 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4894 if (bytesPerFrame == 0) {
4895 return 0;
4896 }
4897
4898 totalFramesRead = 0;
4899
4900 while (framesToRead > 0) {
4901 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4902 if (framesRead == 0) {
4903 break;
4904 }
4905
4906 drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4907
4908 pBufferOut += framesRead*pWav->channels;
4909 framesToRead -= framesRead;
4910 totalFramesRead += framesRead;
4911 }
4912
4913 return totalFramesRead;
4914 }
4915
drwav_read_pcm_frames_s32__alaw(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)4916 static drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
4917 {
4918 drwav_uint64 totalFramesRead;
4919 unsigned char sampleData[4096];
4920
4921 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4922 if (bytesPerFrame == 0) {
4923 return 0;
4924 }
4925
4926 totalFramesRead = 0;
4927
4928 while (framesToRead > 0) {
4929 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4930 if (framesRead == 0) {
4931 break;
4932 }
4933
4934 drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4935
4936 pBufferOut += framesRead*pWav->channels;
4937 framesToRead -= framesRead;
4938 totalFramesRead += framesRead;
4939 }
4940
4941 return totalFramesRead;
4942 }
4943
drwav_read_pcm_frames_s32__mulaw(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)4944 static drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
4945 {
4946 drwav_uint64 totalFramesRead;
4947 unsigned char sampleData[4096];
4948
4949 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4950 if (bytesPerFrame == 0) {
4951 return 0;
4952 }
4953
4954 totalFramesRead = 0;
4955
4956 while (framesToRead > 0) {
4957 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4958 if (framesRead == 0) {
4959 break;
4960 }
4961
4962 drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4963
4964 pBufferOut += framesRead*pWav->channels;
4965 framesToRead -= framesRead;
4966 totalFramesRead += framesRead;
4967 }
4968
4969 return totalFramesRead;
4970 }
4971
drwav_read_pcm_frames_s32(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)4972 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
4973 {
4974 if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) {
4975 return 0;
4976 }
4977
4978 /* Don't try to read more samples than can potentially fit in the output buffer. */
4979 if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) {
4980 framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels;
4981 }
4982
4983
4984 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
4985 return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut);
4986 }
4987
4988 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
4989 return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut);
4990 }
4991
4992 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
4993 return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut);
4994 }
4995
4996 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
4997 return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut);
4998 }
4999
5000 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
5001 return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut);
5002 }
5003
5004 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
5005 return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut);
5006 }
5007
5008 return 0;
5009 }
5010
drwav_read_pcm_frames_s32le(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)5011 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5012 {
5013 drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
5014 if (!drwav__is_little_endian()) {
5015 drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
5016 }
5017
5018 return framesRead;
5019 }
5020
drwav_read_pcm_frames_s32be(drwav * pWav,drwav_uint64 framesToRead,drwav_int32 * pBufferOut)5021 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5022 {
5023 drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
5024 if (drwav__is_little_endian()) {
5025 drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
5026 }
5027
5028 return framesRead;
5029 }
5030
5031
drwav_u8_to_s32(drwav_int32 * pOut,const drwav_uint8 * pIn,size_t sampleCount)5032 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5033 {
5034 size_t i;
5035
5036 if (pOut == NULL || pIn == NULL) {
5037 return;
5038 }
5039
5040 for (i = 0; i < sampleCount; ++i) {
5041 *pOut++ = ((int)pIn[i] - 128) << 24;
5042 }
5043 }
5044
drwav_s16_to_s32(drwav_int32 * pOut,const drwav_int16 * pIn,size_t sampleCount)5045 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
5046 {
5047 size_t i;
5048
5049 if (pOut == NULL || pIn == NULL) {
5050 return;
5051 }
5052
5053 for (i = 0; i < sampleCount; ++i) {
5054 *pOut++ = pIn[i] << 16;
5055 }
5056 }
5057
drwav_s24_to_s32(drwav_int32 * pOut,const drwav_uint8 * pIn,size_t sampleCount)5058 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5059 {
5060 size_t i;
5061
5062 if (pOut == NULL || pIn == NULL) {
5063 return;
5064 }
5065
5066 for (i = 0; i < sampleCount; ++i) {
5067 unsigned int s0 = pIn[i*3 + 0];
5068 unsigned int s1 = pIn[i*3 + 1];
5069 unsigned int s2 = pIn[i*3 + 2];
5070
5071 drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
5072 *pOut++ = sample32;
5073 }
5074 }
5075
drwav_f32_to_s32(drwav_int32 * pOut,const float * pIn,size_t sampleCount)5076 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
5077 {
5078 size_t i;
5079
5080 if (pOut == NULL || pIn == NULL) {
5081 return;
5082 }
5083
5084 for (i = 0; i < sampleCount; ++i) {
5085 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
5086 }
5087 }
5088
drwav_f64_to_s32(drwav_int32 * pOut,const double * pIn,size_t sampleCount)5089 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
5090 {
5091 size_t i;
5092
5093 if (pOut == NULL || pIn == NULL) {
5094 return;
5095 }
5096
5097 for (i = 0; i < sampleCount; ++i) {
5098 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
5099 }
5100 }
5101
drwav_alaw_to_s32(drwav_int32 * pOut,const drwav_uint8 * pIn,size_t sampleCount)5102 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5103 {
5104 size_t i;
5105
5106 if (pOut == NULL || pIn == NULL) {
5107 return;
5108 }
5109
5110 for (i = 0; i < sampleCount; ++i) {
5111 *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
5112 }
5113 }
5114
drwav_mulaw_to_s32(drwav_int32 * pOut,const drwav_uint8 * pIn,size_t sampleCount)5115 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5116 {
5117 size_t i;
5118
5119 if (pOut == NULL || pIn == NULL) {
5120 return;
5121 }
5122
5123 for (i= 0; i < sampleCount; ++i) {
5124 *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
5125 }
5126 }
5127
5128
5129
drwav__read_pcm_frames_and_close_s16(drwav * pWav,unsigned int * channels,unsigned int * sampleRate,drwav_uint64 * totalFrameCount)5130 static drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5131 {
5132 drwav_uint64 sampleDataSize;
5133 drwav_int16* pSampleData;
5134 drwav_uint64 framesRead;
5135
5136 DRWAV_ASSERT(pWav != NULL);
5137
5138 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
5139 if (sampleDataSize > DRWAV_SIZE_MAX) {
5140 drwav_uninit(pWav);
5141 return NULL; /* File's too big. */
5142 }
5143
5144 pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5145 if (pSampleData == NULL) {
5146 drwav_uninit(pWav);
5147 return NULL; /* Failed to allocate memory. */
5148 }
5149
5150 framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5151 if (framesRead != pWav->totalPCMFrameCount) {
5152 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5153 drwav_uninit(pWav);
5154 return NULL; /* There was an error reading the samples. */
5155 }
5156
5157 drwav_uninit(pWav);
5158
5159 if (sampleRate) {
5160 *sampleRate = pWav->sampleRate;
5161 }
5162 if (channels) {
5163 *channels = pWav->channels;
5164 }
5165 if (totalFrameCount) {
5166 *totalFrameCount = pWav->totalPCMFrameCount;
5167 }
5168
5169 return pSampleData;
5170 }
5171
drwav__read_pcm_frames_and_close_f32(drwav * pWav,unsigned int * channels,unsigned int * sampleRate,drwav_uint64 * totalFrameCount)5172 static float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5173 {
5174 drwav_uint64 sampleDataSize;
5175 float* pSampleData;
5176 drwav_uint64 framesRead;
5177
5178 DRWAV_ASSERT(pWav != NULL);
5179
5180 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
5181 if (sampleDataSize > DRWAV_SIZE_MAX) {
5182 drwav_uninit(pWav);
5183 return NULL; /* File's too big. */
5184 }
5185
5186 pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5187 if (pSampleData == NULL) {
5188 drwav_uninit(pWav);
5189 return NULL; /* Failed to allocate memory. */
5190 }
5191
5192 framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5193 if (framesRead != pWav->totalPCMFrameCount) {
5194 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5195 drwav_uninit(pWav);
5196 return NULL; /* There was an error reading the samples. */
5197 }
5198
5199 drwav_uninit(pWav);
5200
5201 if (sampleRate) {
5202 *sampleRate = pWav->sampleRate;
5203 }
5204 if (channels) {
5205 *channels = pWav->channels;
5206 }
5207 if (totalFrameCount) {
5208 *totalFrameCount = pWav->totalPCMFrameCount;
5209 }
5210
5211 return pSampleData;
5212 }
5213
drwav__read_pcm_frames_and_close_s32(drwav * pWav,unsigned int * channels,unsigned int * sampleRate,drwav_uint64 * totalFrameCount)5214 static drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5215 {
5216 drwav_uint64 sampleDataSize;
5217 drwav_int32* pSampleData;
5218 drwav_uint64 framesRead;
5219
5220 DRWAV_ASSERT(pWav != NULL);
5221
5222 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
5223 if (sampleDataSize > DRWAV_SIZE_MAX) {
5224 drwav_uninit(pWav);
5225 return NULL; /* File's too big. */
5226 }
5227
5228 pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5229 if (pSampleData == NULL) {
5230 drwav_uninit(pWav);
5231 return NULL; /* Failed to allocate memory. */
5232 }
5233
5234 framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5235 if (framesRead != pWav->totalPCMFrameCount) {
5236 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5237 drwav_uninit(pWav);
5238 return NULL; /* There was an error reading the samples. */
5239 }
5240
5241 drwav_uninit(pWav);
5242
5243 if (sampleRate) {
5244 *sampleRate = pWav->sampleRate;
5245 }
5246 if (channels) {
5247 *channels = pWav->channels;
5248 }
5249 if (totalFrameCount) {
5250 *totalFrameCount = pWav->totalPCMFrameCount;
5251 }
5252
5253 return pSampleData;
5254 }
5255
5256
5257
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)5258 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)
5259 {
5260 drwav wav;
5261
5262 if (channelsOut) {
5263 *channelsOut = 0;
5264 }
5265 if (sampleRateOut) {
5266 *sampleRateOut = 0;
5267 }
5268 if (totalFrameCountOut) {
5269 *totalFrameCountOut = 0;
5270 }
5271
5272 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5273 return NULL;
5274 }
5275
5276 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5277 }
5278
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)5279 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)
5280 {
5281 drwav wav;
5282
5283 if (channelsOut) {
5284 *channelsOut = 0;
5285 }
5286 if (sampleRateOut) {
5287 *sampleRateOut = 0;
5288 }
5289 if (totalFrameCountOut) {
5290 *totalFrameCountOut = 0;
5291 }
5292
5293 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5294 return NULL;
5295 }
5296
5297 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5298 }
5299
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)5300 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)
5301 {
5302 drwav wav;
5303
5304 if (channelsOut) {
5305 *channelsOut = 0;
5306 }
5307 if (sampleRateOut) {
5308 *sampleRateOut = 0;
5309 }
5310 if (totalFrameCountOut) {
5311 *totalFrameCountOut = 0;
5312 }
5313
5314 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5315 return NULL;
5316 }
5317
5318 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5319 }
5320
5321 #ifndef DR_WAV_NO_STDIO
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)5322 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)
5323 {
5324 drwav wav;
5325
5326 if (channelsOut) {
5327 *channelsOut = 0;
5328 }
5329 if (sampleRateOut) {
5330 *sampleRateOut = 0;
5331 }
5332 if (totalFrameCountOut) {
5333 *totalFrameCountOut = 0;
5334 }
5335
5336 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5337 return NULL;
5338 }
5339
5340 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5341 }
5342
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)5343 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)
5344 {
5345 drwav wav;
5346
5347 if (channelsOut) {
5348 *channelsOut = 0;
5349 }
5350 if (sampleRateOut) {
5351 *sampleRateOut = 0;
5352 }
5353 if (totalFrameCountOut) {
5354 *totalFrameCountOut = 0;
5355 }
5356
5357 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5358 return NULL;
5359 }
5360
5361 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5362 }
5363
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)5364 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)
5365 {
5366 drwav wav;
5367
5368 if (channelsOut) {
5369 *channelsOut = 0;
5370 }
5371 if (sampleRateOut) {
5372 *sampleRateOut = 0;
5373 }
5374 if (totalFrameCountOut) {
5375 *totalFrameCountOut = 0;
5376 }
5377
5378 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5379 return NULL;
5380 }
5381
5382 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5383 }
5384
5385
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)5386 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)
5387 {
5388 drwav wav;
5389
5390 if (sampleRateOut) {
5391 *sampleRateOut = 0;
5392 }
5393 if (channelsOut) {
5394 *channelsOut = 0;
5395 }
5396 if (totalFrameCountOut) {
5397 *totalFrameCountOut = 0;
5398 }
5399
5400 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5401 return NULL;
5402 }
5403
5404 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5405 }
5406
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)5407 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)
5408 {
5409 drwav wav;
5410
5411 if (sampleRateOut) {
5412 *sampleRateOut = 0;
5413 }
5414 if (channelsOut) {
5415 *channelsOut = 0;
5416 }
5417 if (totalFrameCountOut) {
5418 *totalFrameCountOut = 0;
5419 }
5420
5421 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5422 return NULL;
5423 }
5424
5425 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5426 }
5427
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)5428 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)
5429 {
5430 drwav wav;
5431
5432 if (sampleRateOut) {
5433 *sampleRateOut = 0;
5434 }
5435 if (channelsOut) {
5436 *channelsOut = 0;
5437 }
5438 if (totalFrameCountOut) {
5439 *totalFrameCountOut = 0;
5440 }
5441
5442 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5443 return NULL;
5444 }
5445
5446 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5447 }
5448 #endif
5449
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)5450 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)
5451 {
5452 drwav wav;
5453
5454 if (channelsOut) {
5455 *channelsOut = 0;
5456 }
5457 if (sampleRateOut) {
5458 *sampleRateOut = 0;
5459 }
5460 if (totalFrameCountOut) {
5461 *totalFrameCountOut = 0;
5462 }
5463
5464 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5465 return NULL;
5466 }
5467
5468 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5469 }
5470
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)5471 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)
5472 {
5473 drwav wav;
5474
5475 if (channelsOut) {
5476 *channelsOut = 0;
5477 }
5478 if (sampleRateOut) {
5479 *sampleRateOut = 0;
5480 }
5481 if (totalFrameCountOut) {
5482 *totalFrameCountOut = 0;
5483 }
5484
5485 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5486 return NULL;
5487 }
5488
5489 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5490 }
5491
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)5492 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)
5493 {
5494 drwav wav;
5495
5496 if (channelsOut) {
5497 *channelsOut = 0;
5498 }
5499 if (sampleRateOut) {
5500 *sampleRateOut = 0;
5501 }
5502 if (totalFrameCountOut) {
5503 *totalFrameCountOut = 0;
5504 }
5505
5506 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5507 return NULL;
5508 }
5509
5510 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5511 }
5512 #endif /* DR_WAV_NO_CONVERSION_API */
5513
5514
drwav_free(void * p,const drwav_allocation_callbacks * pAllocationCallbacks)5515 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
5516 {
5517 if (pAllocationCallbacks != NULL) {
5518 drwav__free_from_callbacks(p, pAllocationCallbacks);
5519 } else {
5520 drwav__free_default(p, NULL);
5521 }
5522 }
5523
drwav_bytes_to_u16(const unsigned char * data)5524 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const unsigned char* data)
5525 {
5526 return drwav__bytes_to_u16(data);
5527 }
5528
drwav_bytes_to_s16(const unsigned char * data)5529 DRWAV_API drwav_int16 drwav_bytes_to_s16(const unsigned char* data)
5530 {
5531 return drwav__bytes_to_s16(data);
5532 }
5533
drwav_bytes_to_u32(const unsigned char * data)5534 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const unsigned char* data)
5535 {
5536 return drwav__bytes_to_u32(data);
5537 }
5538
drwav_bytes_to_s32(const unsigned char * data)5539 DRWAV_API drwav_int32 drwav_bytes_to_s32(const unsigned char* data)
5540 {
5541 return drwav__bytes_to_s32(data);
5542 }
5543
drwav_bytes_to_u64(const unsigned char * data)5544 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const unsigned char* data)
5545 {
5546 return drwav__bytes_to_u64(data);
5547 }
5548
drwav_bytes_to_s64(const unsigned char * data)5549 DRWAV_API drwav_int64 drwav_bytes_to_s64(const unsigned char* data)
5550 {
5551 return drwav__bytes_to_s64(data);
5552 }
5553
5554
drwav_guid_equal(const drwav_uint8 a[16],const drwav_uint8 b[16])5555 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
5556 {
5557 return drwav__guid_equal(a, b);
5558 }
5559
drwav_fourcc_equal(const unsigned char * a,const char * b)5560 DRWAV_API drwav_bool32 drwav_fourcc_equal(const unsigned char* a, const char* b)
5561 {
5562 return drwav__fourcc_equal(a, b);
5563 }
5564
5565 #endif /* DR_WAV_IMPLEMENTATION */
5566
5567 /*
5568 RELEASE NOTES - v0.11.0
5569 =======================
5570 Version 0.11.0 has breaking API changes.
5571
5572 Improved Client-Defined Memory Allocation
5573 -----------------------------------------
5574 The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
5575 existing system of DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE are still in place and will be used by default when no custom
5576 allocation callbacks are specified.
5577
5578 To use the new system, you pass in a pointer to a drwav_allocation_callbacks object to drwav_init() and family, like this:
5579
5580 void* my_malloc(size_t sz, void* pUserData)
5581 {
5582 return malloc(sz);
5583 }
5584 void* my_realloc(void* p, size_t sz, void* pUserData)
5585 {
5586 return realloc(p, sz);
5587 }
5588 void my_free(void* p, void* pUserData)
5589 {
5590 free(p);
5591 }
5592
5593 ...
5594
5595 drwav_allocation_callbacks allocationCallbacks;
5596 allocationCallbacks.pUserData = &myData;
5597 allocationCallbacks.onMalloc = my_malloc;
5598 allocationCallbacks.onRealloc = my_realloc;
5599 allocationCallbacks.onFree = my_free;
5600 drwav_init_file(&wav, "my_file.wav", &allocationCallbacks);
5601
5602 The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
5603
5604 Passing in null for the allocation callbacks object will cause dr_wav to use defaults which is the same as DRWAV_MALLOC,
5605 DRWAV_REALLOC and DRWAV_FREE and the equivalent of how it worked in previous versions.
5606
5607 Every API that opens a drwav object now takes this extra parameter. These include the following:
5608
5609 drwav_init()
5610 drwav_init_ex()
5611 drwav_init_file()
5612 drwav_init_file_ex()
5613 drwav_init_file_w()
5614 drwav_init_file_w_ex()
5615 drwav_init_memory()
5616 drwav_init_memory_ex()
5617 drwav_init_write()
5618 drwav_init_write_sequential()
5619 drwav_init_write_sequential_pcm_frames()
5620 drwav_init_file_write()
5621 drwav_init_file_write_sequential()
5622 drwav_init_file_write_sequential_pcm_frames()
5623 drwav_init_file_write_w()
5624 drwav_init_file_write_sequential_w()
5625 drwav_init_file_write_sequential_pcm_frames_w()
5626 drwav_init_memory_write()
5627 drwav_init_memory_write_sequential()
5628 drwav_init_memory_write_sequential_pcm_frames()
5629 drwav_open_and_read_pcm_frames_s16()
5630 drwav_open_and_read_pcm_frames_f32()
5631 drwav_open_and_read_pcm_frames_s32()
5632 drwav_open_file_and_read_pcm_frames_s16()
5633 drwav_open_file_and_read_pcm_frames_f32()
5634 drwav_open_file_and_read_pcm_frames_s32()
5635 drwav_open_file_and_read_pcm_frames_s16_w()
5636 drwav_open_file_and_read_pcm_frames_f32_w()
5637 drwav_open_file_and_read_pcm_frames_s32_w()
5638 drwav_open_memory_and_read_pcm_frames_s16()
5639 drwav_open_memory_and_read_pcm_frames_f32()
5640 drwav_open_memory_and_read_pcm_frames_s32()
5641
5642 Endian Improvements
5643 -------------------
5644 Previously, the following APIs returned little-endian audio data. These now return native-endian data. This improves compatibility
5645 on big-endian architectures.
5646
5647 drwav_read_pcm_frames()
5648 drwav_read_pcm_frames_s16()
5649 drwav_read_pcm_frames_s32()
5650 drwav_read_pcm_frames_f32()
5651 drwav_open_and_read_pcm_frames_s16()
5652 drwav_open_and_read_pcm_frames_s32()
5653 drwav_open_and_read_pcm_frames_f32()
5654 drwav_open_file_and_read_pcm_frames_s16()
5655 drwav_open_file_and_read_pcm_frames_s32()
5656 drwav_open_file_and_read_pcm_frames_f32()
5657 drwav_open_file_and_read_pcm_frames_s16_w()
5658 drwav_open_file_and_read_pcm_frames_s32_w()
5659 drwav_open_file_and_read_pcm_frames_f32_w()
5660 drwav_open_memory_and_read_pcm_frames_s16()
5661 drwav_open_memory_and_read_pcm_frames_s32()
5662 drwav_open_memory_and_read_pcm_frames_f32()
5663
5664 APIs have been added to give you explicit control over whether or not audio data is read or written in big- or little-endian byte
5665 order:
5666
5667 drwav_read_pcm_frames_le()
5668 drwav_read_pcm_frames_be()
5669 drwav_read_pcm_frames_s16le()
5670 drwav_read_pcm_frames_s16be()
5671 drwav_read_pcm_frames_f32le()
5672 drwav_read_pcm_frames_f32be()
5673 drwav_read_pcm_frames_s32le()
5674 drwav_read_pcm_frames_s32be()
5675 drwav_write_pcm_frames_le()
5676 drwav_write_pcm_frames_be()
5677
5678 Removed APIs
5679 ------------
5680 The following APIs were deprecated in version 0.10.0 and have now been removed:
5681
5682 drwav_open()
5683 drwav_open_ex()
5684 drwav_open_write()
5685 drwav_open_write_sequential()
5686 drwav_open_file()
5687 drwav_open_file_ex()
5688 drwav_open_file_write()
5689 drwav_open_file_write_sequential()
5690 drwav_open_memory()
5691 drwav_open_memory_ex()
5692 drwav_open_memory_write()
5693 drwav_open_memory_write_sequential()
5694 drwav_close()
5695
5696
5697
5698 RELEASE NOTES - v0.10.0
5699 =======================
5700 Version 0.10.0 has breaking API changes. There are no significant bug fixes in this release, so if you are affected you do
5701 not need to upgrade.
5702
5703 Removed APIs
5704 ------------
5705 The following APIs were deprecated in version 0.9.0 and have been completely removed in version 0.10.0:
5706
5707 drwav_read()
5708 drwav_read_s16()
5709 drwav_read_f32()
5710 drwav_read_s32()
5711 drwav_seek_to_sample()
5712 drwav_write()
5713 drwav_open_and_read_s16()
5714 drwav_open_and_read_f32()
5715 drwav_open_and_read_s32()
5716 drwav_open_file_and_read_s16()
5717 drwav_open_file_and_read_f32()
5718 drwav_open_file_and_read_s32()
5719 drwav_open_memory_and_read_s16()
5720 drwav_open_memory_and_read_f32()
5721 drwav_open_memory_and_read_s32()
5722 drwav::totalSampleCount
5723
5724 See release notes for version 0.9.0 at the bottom of this file for replacement APIs.
5725
5726 Deprecated APIs
5727 ---------------
5728 The following APIs have been deprecated. There is a confusing and completely arbitrary difference between drwav_init*() and
5729 drwav_open*(), where drwav_init*() initializes a pre-allocated drwav object, whereas drwav_open*() will first allocated a
5730 drwav object on the heap and then initialize it. drwav_open*() has been deprecated which means you must now use a pre-
5731 allocated drwav object with drwav_init*(). If you need the previous functionality, you can just do a malloc() followed by
5732 a called to one of the drwav_init*() APIs.
5733
5734 drwav_open()
5735 drwav_open_ex()
5736 drwav_open_write()
5737 drwav_open_write_sequential()
5738 drwav_open_file()
5739 drwav_open_file_ex()
5740 drwav_open_file_write()
5741 drwav_open_file_write_sequential()
5742 drwav_open_memory()
5743 drwav_open_memory_ex()
5744 drwav_open_memory_write()
5745 drwav_open_memory_write_sequential()
5746 drwav_close()
5747
5748 These APIs will be removed completely in a future version. The rationale for this change is to remove confusion between the
5749 two different ways to initialize a drwav object.
5750 */
5751
5752 /*
5753 REVISION HISTORY
5754 ================
5755 v0.12.2 - 2020-04-21
5756 - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file.
5757
5758 v0.12.1 - 2020-04-13
5759 - Fix some pedantic warnings.
5760
5761 v0.12.0 - 2020-04-04
5762 - API CHANGE: Add container and format parameters to the chunk callback.
5763 - Minor documentation updates.
5764
5765 v0.11.5 - 2020-03-07
5766 - Fix compilation error with Visual Studio .NET 2003.
5767
5768 v0.11.4 - 2020-01-29
5769 - Fix some static analysis warnings.
5770 - Fix a bug when reading f32 samples from an A-law encoded stream.
5771
5772 v0.11.3 - 2020-01-12
5773 - Minor changes to some f32 format conversion routines.
5774 - Minor bug fix for ADPCM conversion when end of file is reached.
5775
5776 v0.11.2 - 2019-12-02
5777 - Fix a possible crash when using custom memory allocators without a custom realloc() implementation.
5778 - Fix an integer overflow bug.
5779 - Fix a null pointer dereference bug.
5780 - Add limits to sample rate, channels and bits per sample to tighten up some validation.
5781
5782 v0.11.1 - 2019-10-07
5783 - Internal code clean up.
5784
5785 v0.11.0 - 2019-10-06
5786 - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
5787 routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
5788 - drwav_init()
5789 - drwav_init_ex()
5790 - drwav_init_file()
5791 - drwav_init_file_ex()
5792 - drwav_init_file_w()
5793 - drwav_init_file_w_ex()
5794 - drwav_init_memory()
5795 - drwav_init_memory_ex()
5796 - drwav_init_write()
5797 - drwav_init_write_sequential()
5798 - drwav_init_write_sequential_pcm_frames()
5799 - drwav_init_file_write()
5800 - drwav_init_file_write_sequential()
5801 - drwav_init_file_write_sequential_pcm_frames()
5802 - drwav_init_file_write_w()
5803 - drwav_init_file_write_sequential_w()
5804 - drwav_init_file_write_sequential_pcm_frames_w()
5805 - drwav_init_memory_write()
5806 - drwav_init_memory_write_sequential()
5807 - drwav_init_memory_write_sequential_pcm_frames()
5808 - drwav_open_and_read_pcm_frames_s16()
5809 - drwav_open_and_read_pcm_frames_f32()
5810 - drwav_open_and_read_pcm_frames_s32()
5811 - drwav_open_file_and_read_pcm_frames_s16()
5812 - drwav_open_file_and_read_pcm_frames_f32()
5813 - drwav_open_file_and_read_pcm_frames_s32()
5814 - drwav_open_file_and_read_pcm_frames_s16_w()
5815 - drwav_open_file_and_read_pcm_frames_f32_w()
5816 - drwav_open_file_and_read_pcm_frames_s32_w()
5817 - drwav_open_memory_and_read_pcm_frames_s16()
5818 - drwav_open_memory_and_read_pcm_frames_f32()
5819 - drwav_open_memory_and_read_pcm_frames_s32()
5820 Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use
5821 DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE.
5822 - Add support for reading and writing PCM frames in an explicit endianness. New APIs:
5823 - drwav_read_pcm_frames_le()
5824 - drwav_read_pcm_frames_be()
5825 - drwav_read_pcm_frames_s16le()
5826 - drwav_read_pcm_frames_s16be()
5827 - drwav_read_pcm_frames_f32le()
5828 - drwav_read_pcm_frames_f32be()
5829 - drwav_read_pcm_frames_s32le()
5830 - drwav_read_pcm_frames_s32be()
5831 - drwav_write_pcm_frames_le()
5832 - drwav_write_pcm_frames_be()
5833 - Remove deprecated APIs.
5834 - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data.
5835 - drwav_read_pcm_frames()
5836 - drwav_read_pcm_frames_s16()
5837 - drwav_read_pcm_frames_s32()
5838 - drwav_read_pcm_frames_f32()
5839 - drwav_open_and_read_pcm_frames_s16()
5840 - drwav_open_and_read_pcm_frames_s32()
5841 - drwav_open_and_read_pcm_frames_f32()
5842 - drwav_open_file_and_read_pcm_frames_s16()
5843 - drwav_open_file_and_read_pcm_frames_s32()
5844 - drwav_open_file_and_read_pcm_frames_f32()
5845 - drwav_open_file_and_read_pcm_frames_s16_w()
5846 - drwav_open_file_and_read_pcm_frames_s32_w()
5847 - drwav_open_file_and_read_pcm_frames_f32_w()
5848 - drwav_open_memory_and_read_pcm_frames_s16()
5849 - drwav_open_memory_and_read_pcm_frames_s32()
5850 - drwav_open_memory_and_read_pcm_frames_f32()
5851
5852 v0.10.1 - 2019-08-31
5853 - Correctly handle partial trailing ADPCM blocks.
5854
5855 v0.10.0 - 2019-08-04
5856 - Remove deprecated APIs.
5857 - Add wchar_t variants for file loading APIs:
5858 drwav_init_file_w()
5859 drwav_init_file_ex_w()
5860 drwav_init_file_write_w()
5861 drwav_init_file_write_sequential_w()
5862 - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count.
5863 - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode:
5864 drwav_init_write_sequential_pcm_frames()
5865 drwav_init_file_write_sequential_pcm_frames()
5866 drwav_init_file_write_sequential_pcm_frames_w()
5867 drwav_init_memory_write_sequential_pcm_frames()
5868 - Deprecate drwav_open*() and drwav_close():
5869 drwav_open()
5870 drwav_open_ex()
5871 drwav_open_write()
5872 drwav_open_write_sequential()
5873 drwav_open_file()
5874 drwav_open_file_ex()
5875 drwav_open_file_write()
5876 drwav_open_file_write_sequential()
5877 drwav_open_memory()
5878 drwav_open_memory_ex()
5879 drwav_open_memory_write()
5880 drwav_open_memory_write_sequential()
5881 drwav_close()
5882 - Minor documentation updates.
5883
5884 v0.9.2 - 2019-05-21
5885 - Fix warnings.
5886
5887 v0.9.1 - 2019-05-05
5888 - Add support for C89.
5889 - Change license to choice of public domain or MIT-0.
5890
5891 v0.9.0 - 2018-12-16
5892 - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and
5893 will be removed in v0.10.0. Deprecated APIs and their replacements:
5894 drwav_read() -> drwav_read_pcm_frames()
5895 drwav_read_s16() -> drwav_read_pcm_frames_s16()
5896 drwav_read_f32() -> drwav_read_pcm_frames_f32()
5897 drwav_read_s32() -> drwav_read_pcm_frames_s32()
5898 drwav_seek_to_sample() -> drwav_seek_to_pcm_frame()
5899 drwav_write() -> drwav_write_pcm_frames()
5900 drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16()
5901 drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32()
5902 drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32()
5903 drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16()
5904 drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32()
5905 drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32()
5906 drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16()
5907 drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32()
5908 drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32()
5909 drwav::totalSampleCount -> drwav::totalPCMFrameCount
5910 - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*().
5911 - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*().
5912 - Add built-in support for smpl chunks.
5913 - Add support for firing a callback for each chunk in the file at initialization time.
5914 - This is enabled through the drwav_init_ex(), etc. family of APIs.
5915 - Handle invalid FMT chunks more robustly.
5916
5917 v0.8.5 - 2018-09-11
5918 - Const correctness.
5919 - Fix a potential stack overflow.
5920
5921 v0.8.4 - 2018-08-07
5922 - Improve 64-bit detection.
5923
5924 v0.8.3 - 2018-08-05
5925 - Fix C++ build on older versions of GCC.
5926
5927 v0.8.2 - 2018-08-02
5928 - Fix some big-endian bugs.
5929
5930 v0.8.1 - 2018-06-29
5931 - Add support for sequential writing APIs.
5932 - Disable seeking in write mode.
5933 - Fix bugs with Wave64.
5934 - Fix typos.
5935
5936 v0.8 - 2018-04-27
5937 - Bug fix.
5938 - Start using major.minor.revision versioning.
5939
5940 v0.7f - 2018-02-05
5941 - Restrict ADPCM formats to a maximum of 2 channels.
5942
5943 v0.7e - 2018-02-02
5944 - Fix a crash.
5945
5946 v0.7d - 2018-02-01
5947 - Fix a crash.
5948
5949 v0.7c - 2018-02-01
5950 - Set drwav.bytesPerSample to 0 for all compressed formats.
5951 - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for
5952 all format conversion reading APIs (*_s16, *_s32, *_f32 APIs).
5953 - Fix some divide-by-zero errors.
5954
5955 v0.7b - 2018-01-22
5956 - Fix errors with seeking of compressed formats.
5957 - Fix compilation error when DR_WAV_NO_CONVERSION_API
5958
5959 v0.7a - 2017-11-17
5960 - Fix some GCC warnings.
5961
5962 v0.7 - 2017-11-04
5963 - Add writing APIs.
5964
5965 v0.6 - 2017-08-16
5966 - API CHANGE: Rename dr_* types to drwav_*.
5967 - Add support for custom implementations of malloc(), realloc(), etc.
5968 - Add support for Microsoft ADPCM.
5969 - Add support for IMA ADPCM (DVI, format code 0x11).
5970 - Optimizations to drwav_read_s16().
5971 - Bug fixes.
5972
5973 v0.5g - 2017-07-16
5974 - Change underlying type for booleans to unsigned.
5975
5976 v0.5f - 2017-04-04
5977 - Fix a minor bug with drwav_open_and_read_s16() and family.
5978
5979 v0.5e - 2016-12-29
5980 - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this.
5981 - Minor fixes to documentation.
5982
5983 v0.5d - 2016-12-28
5984 - Use drwav_int* and drwav_uint* sized types to improve compiler support.
5985
5986 v0.5c - 2016-11-11
5987 - Properly handle JUNK chunks that come before the FMT chunk.
5988
5989 v0.5b - 2016-10-23
5990 - A minor change to drwav_bool8 and drwav_bool32 types.
5991
5992 v0.5a - 2016-10-11
5993 - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering.
5994 - Improve A-law and mu-law efficiency.
5995
5996 v0.5 - 2016-09-29
5997 - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to
5998 keep it consistent with dr_audio and dr_flac.
5999
6000 v0.4b - 2016-09-18
6001 - Fixed a typo in documentation.
6002
6003 v0.4a - 2016-09-18
6004 - Fixed a typo.
6005 - Change date format to ISO 8601 (YYYY-MM-DD)
6006
6007 v0.4 - 2016-07-13
6008 - API CHANGE. Make onSeek consistent with dr_flac.
6009 - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac.
6010 - Added support for Sony Wave64.
6011
6012 v0.3a - 2016-05-28
6013 - API CHANGE. Return drwav_bool32 instead of int in onSeek callback.
6014 - Fixed a memory leak.
6015
6016 v0.3 - 2016-05-22
6017 - Lots of API changes for consistency.
6018
6019 v0.2a - 2016-05-16
6020 - Fixed Linux/GCC build.
6021
6022 v0.2 - 2016-05-11
6023 - Added support for reading data as signed 32-bit PCM for consistency with dr_flac.
6024
6025 v0.1a - 2016-05-07
6026 - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize.
6027
6028 v0.1 - 2016-05-04
6029 - Initial versioned release.
6030 */
6031
6032 /*
6033 This software is available as a choice of the following licenses. Choose
6034 whichever you prefer.
6035
6036 ===============================================================================
6037 ALTERNATIVE 1 - Public Domain (www.unlicense.org)
6038 ===============================================================================
6039 This is free and unencumbered software released into the public domain.
6040
6041 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
6042 software, either in source code form or as a compiled binary, for any purpose,
6043 commercial or non-commercial, and by any means.
6044
6045 In jurisdictions that recognize copyright laws, the author or authors of this
6046 software dedicate any and all copyright interest in the software to the public
6047 domain. We make this dedication for the benefit of the public at large and to
6048 the detriment of our heirs and successors. We intend this dedication to be an
6049 overt act of relinquishment in perpetuity of all present and future rights to
6050 this software under copyright law.
6051
6052 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6053 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6054 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6055 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
6056 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
6057 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6058
6059 For more information, please refer to <http://unlicense.org/>
6060
6061 ===============================================================================
6062 ALTERNATIVE 2 - MIT No Attribution
6063 ===============================================================================
6064 Copyright 2020 David Reid
6065
6066 Permission is hereby granted, free of charge, to any person obtaining a copy of
6067 this software and associated documentation files (the "Software"), to deal in
6068 the Software without restriction, including without limitation the rights to
6069 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
6070 of the Software, and to permit persons to whom the Software is furnished to do
6071 so.
6072
6073 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6074 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6075 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6076 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6077 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6078 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
6079 SOFTWARE.
6080 */
6081