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.19 - 2021-02-21
5 David Reid - mackron@gmail.com
7 GitHub: https://github.com/mackron/dr_libs
11 RELEASE NOTES - VERSION 0.12
12 ============================
13 Version 0.12 includes breaking changes to custom chunk handling.
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 updated 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.
21 Previously, there was no direct way to determine the container, and therefore no way to 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.
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.
32 This is a single file library. To use it, do something like the following in one .c file.
35 #define DR_WAV_IMPLEMENTATION
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:
43 if (!drwav_init_file(&wav, "my_song.wav", NULL)) {
44 // Error opening WAV file.
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);
55 If you just want to quickly open and read the audio data in a single operation you can do something like this:
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.
68 drwav_free(pSampleData, NULL);
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):
75 size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
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:
81 size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer);
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.
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.
92 format.sampleRate = 44100;
93 format.bitsPerSample = 16;
94 drwav_init_file_write(&wav, "data/recording.wav", &format, NULL);
98 drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples);
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.
106 #define these options before including this file.
108 #define DR_WAV_NO_CONVERSION_API
109 Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`.
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.
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:
127 - IEEE 32-bit floating point
128 - IEEE 64-bit floating point
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.
142 #define DRWAV_STRINGIFY(x) #x
143 #define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
145 #define DRWAV_VERSION_MAJOR 0
146 #define DRWAV_VERSION_MINOR 12
147 #define DRWAV_VERSION_REVISION 19
148 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
150 #include <stddef.h> /* For size_t. */
153 typedef signed char drwav_int8;
154 typedef unsigned char drwav_uint8;
155 typedef signed short drwav_int16;
156 typedef unsigned short drwav_uint16;
157 typedef signed int drwav_int32;
158 typedef unsigned int drwav_uint32;
159 #if defined(_MSC_VER)
160 typedef signed __int64 drwav_int64;
161 typedef unsigned __int64 drwav_uint64;
163 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
164 #pragma GCC diagnostic push
165 #pragma GCC diagnostic ignored "-Wlong-long"
166 #if defined(__clang__)
167 #pragma GCC diagnostic ignored "-Wc++11-long-long"
170 typedef signed long long drwav_int64;
171 typedef unsigned long long drwav_uint64;
172 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
173 #pragma GCC diagnostic pop
176 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
177 typedef drwav_uint64 drwav_uintptr;
179 typedef drwav_uint32 drwav_uintptr;
181 typedef drwav_uint8 drwav_bool8;
182 typedef drwav_uint32 drwav_bool32;
184 #define DRWAV_FALSE 0
186 #if !defined(DRWAV_API)
187 #if defined(DRWAV_DLL)
189 #define DRWAV_DLL_IMPORT __declspec(dllimport)
190 #define DRWAV_DLL_EXPORT __declspec(dllexport)
191 #define DRWAV_DLL_PRIVATE static
193 #if defined(__GNUC__) && __GNUC__ >= 4
194 #define DRWAV_DLL_IMPORT __attribute__((visibility("default")))
195 #define DRWAV_DLL_EXPORT __attribute__((visibility("default")))
196 #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden")))
198 #define DRWAV_DLL_IMPORT
199 #define DRWAV_DLL_EXPORT
200 #define DRWAV_DLL_PRIVATE static
204 #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
205 #define DRWAV_API DRWAV_DLL_EXPORT
207 #define DRWAV_API DRWAV_DLL_IMPORT
209 #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE
211 #define DRWAV_API extern
212 #define DRWAV_PRIVATE static
216 typedef drwav_int32 drwav_result;
217 #define DRWAV_SUCCESS 0
218 #define DRWAV_ERROR -1 /* A generic error. */
219 #define DRWAV_INVALID_ARGS -2
220 #define DRWAV_INVALID_OPERATION -3
221 #define DRWAV_OUT_OF_MEMORY -4
222 #define DRWAV_OUT_OF_RANGE -5
223 #define DRWAV_ACCESS_DENIED -6
224 #define DRWAV_DOES_NOT_EXIST -7
225 #define DRWAV_ALREADY_EXISTS -8
226 #define DRWAV_TOO_MANY_OPEN_FILES -9
227 #define DRWAV_INVALID_FILE -10
228 #define DRWAV_TOO_BIG -11
229 #define DRWAV_PATH_TOO_LONG -12
230 #define DRWAV_NAME_TOO_LONG -13
231 #define DRWAV_NOT_DIRECTORY -14
232 #define DRWAV_IS_DIRECTORY -15
233 #define DRWAV_DIRECTORY_NOT_EMPTY -16
234 #define DRWAV_END_OF_FILE -17
235 #define DRWAV_NO_SPACE -18
236 #define DRWAV_BUSY -19
237 #define DRWAV_IO_ERROR -20
238 #define DRWAV_INTERRUPT -21
239 #define DRWAV_UNAVAILABLE -22
240 #define DRWAV_ALREADY_IN_USE -23
241 #define DRWAV_BAD_ADDRESS -24
242 #define DRWAV_BAD_SEEK -25
243 #define DRWAV_BAD_PIPE -26
244 #define DRWAV_DEADLOCK -27
245 #define DRWAV_TOO_MANY_LINKS -28
246 #define DRWAV_NOT_IMPLEMENTED -29
247 #define DRWAV_NO_MESSAGE -30
248 #define DRWAV_BAD_MESSAGE -31
249 #define DRWAV_NO_DATA_AVAILABLE -32
250 #define DRWAV_INVALID_DATA -33
251 #define DRWAV_TIMEOUT -34
252 #define DRWAV_NO_NETWORK -35
253 #define DRWAV_NOT_UNIQUE -36
254 #define DRWAV_NOT_SOCKET -37
255 #define DRWAV_NO_ADDRESS -38
256 #define DRWAV_BAD_PROTOCOL -39
257 #define DRWAV_PROTOCOL_UNAVAILABLE -40
258 #define DRWAV_PROTOCOL_NOT_SUPPORTED -41
259 #define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42
260 #define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED -43
261 #define DRWAV_SOCKET_NOT_SUPPORTED -44
262 #define DRWAV_CONNECTION_RESET -45
263 #define DRWAV_ALREADY_CONNECTED -46
264 #define DRWAV_NOT_CONNECTED -47
265 #define DRWAV_CONNECTION_REFUSED -48
266 #define DRWAV_NO_HOST -49
267 #define DRWAV_IN_PROGRESS -50
268 #define DRWAV_CANCELLED -51
269 #define DRWAV_MEMORY_ALREADY_MAPPED -52
270 #define DRWAV_AT_END -53
272 /* Common data formats. */
273 #define DR_WAVE_FORMAT_PCM 0x1
274 #define DR_WAVE_FORMAT_ADPCM 0x2
275 #define DR_WAVE_FORMAT_IEEE_FLOAT 0x3
276 #define DR_WAVE_FORMAT_ALAW 0x6
277 #define DR_WAVE_FORMAT_MULAW 0x7
278 #define DR_WAVE_FORMAT_DVI_ADPCM 0x11
279 #define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE
282 #ifndef DRWAV_MAX_SMPL_LOOPS
283 #define DRWAV_MAX_SMPL_LOOPS 1
286 /* Flags to pass into drwav_init_ex(), etc. */
287 #define DRWAV_SEQUENTIAL 0x00000001
289 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
290 DRWAV_API const char* drwav_version_string(void);
294 drwav_seek_origin_start,
295 drwav_seek_origin_current
300 drwav_container_riff,
309 drwav_uint8 fourcc[4];
310 drwav_uint8 guid[16];
313 /* The size in bytes of the chunk. */
314 drwav_uint64 sizeInBytes;
317 RIFF = 2 byte alignment.
318 W64 = 8 byte alignment.
320 unsigned int paddingSize;
321 } drwav_chunk_header;
326 The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
327 that require support for data formats not natively supported by dr_wav.
329 drwav_uint16 formatTag;
331 /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */
332 drwav_uint16 channels;
334 /* The sample rate. Usually set to something like 44100. */
335 drwav_uint32 sampleRate;
337 /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */
338 drwav_uint32 avgBytesPerSec;
340 /* Block align. This is equal to the number of channels * bytes per sample. */
341 drwav_uint16 blockAlign;
343 /* Bits per sample. */
344 drwav_uint16 bitsPerSample;
346 /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */
347 drwav_uint16 extendedSize;
350 The number of valid bits per sample. When <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample>
351 is always rounded up to the nearest multiple of 8. This variable contains information about exactly how
352 many bits are valid per sample. Mainly used for informational purposes.
354 drwav_uint16 validBitsPerSample;
356 /* The channel mask. Not used at the moment. */
357 drwav_uint32 channelMask;
359 /* The sub-format, exactly as specified by the wave file. */
360 drwav_uint8 subFormat[16];
363 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
367 Callback for when data is read. Return value is the number of bytes actually read.
369 pUserData [in] The user data that was passed to drwav_init() and family.
370 pBufferOut [out] The output buffer.
371 bytesToRead [in] The number of bytes to read.
373 Returns the number of bytes actually read.
375 A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until
376 either the entire bytesToRead is filled or you have reached the end of the stream.
378 typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
381 Callback for when data is written. Returns value is the number of bytes actually written.
383 pUserData [in] The user data that was passed to drwav_init_write() and family.
384 pData [out] A pointer to the data to write.
385 bytesToWrite [in] The number of bytes to write.
387 Returns the number of bytes actually written.
389 If the return value differs from bytesToWrite, it indicates an error.
391 typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
394 Callback for when data needs to be seeked.
396 pUserData [in] The user data that was passed to drwav_init() and family.
397 offset [in] The number of bytes to move, relative to the origin. Will never be negative.
398 origin [in] The origin of the seek - the current position or the start of the stream.
400 Returns whether or not the seek was successful.
402 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
403 drwav_seek_origin_current.
405 typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
408 Callback for when drwav_init_ex() finds a chunk.
410 pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family.
411 onRead [in] A pointer to the function to call when reading.
412 onSeek [in] A pointer to the function to call when seeking.
413 pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family.
414 pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk.
415 container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF.
416 pFMT [in] A pointer to the object containing the contents of the "fmt" chunk.
418 Returns the number of bytes read + seeked.
420 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
421 be the total number of bytes you have read _plus_ seeked.
423 Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should
424 use `id.fourcc`, otherwise you should use `id.guid`.
426 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
427 `DR_WAVE_FORMAT_*` identifiers.
429 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.
431 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);
436 void* (* onMalloc)(size_t sz, void* pUserData);
437 void* (* onRealloc)(void* p, size_t sz, void* pUserData);
438 void (* onFree)(void* p, void* pUserData);
439 } drwav_allocation_callbacks;
441 /* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */
444 const drwav_uint8* data;
446 size_t currentReadPos;
447 } drwav__memory_stream;
449 /* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */
456 size_t currentWritePos;
457 } drwav__memory_stream_write;
461 drwav_container container; /* RIFF, W64. */
462 drwav_uint32 format; /* DR_WAVE_FORMAT_* */
463 drwav_uint32 channels;
464 drwav_uint32 sampleRate;
465 drwav_uint32 bitsPerSample;
469 /* See the following for details on the 'smpl' chunk: https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl */
472 drwav_uint32 cuePointId;
476 drwav_uint32 fraction;
477 drwav_uint32 playCount;
482 drwav_uint32 manufacturer;
483 drwav_uint32 product;
484 drwav_uint32 samplePeriod;
485 drwav_uint32 midiUnityNotes;
486 drwav_uint32 midiPitchFraction;
487 drwav_uint32 smpteFormat;
488 drwav_uint32 smpteOffset;
489 drwav_uint32 numSampleLoops;
490 drwav_uint32 samplerData;
491 drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS];
496 /* A pointer to the function to call when more data is needed. */
497 drwav_read_proc onRead;
499 /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */
500 drwav_write_proc onWrite;
502 /* A pointer to the function to call when the wav file needs to be seeked. */
503 drwav_seek_proc onSeek;
505 /* The user data to pass to callbacks. */
508 /* Allocation callbacks. */
509 drwav_allocation_callbacks allocationCallbacks;
512 /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */
513 drwav_container container;
516 /* Structure containing format information exactly as specified by the wav file. */
519 /* The sample rate. Will be set to something like 44100. */
520 drwav_uint32 sampleRate;
522 /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */
523 drwav_uint16 channels;
525 /* The bits per sample. Will be set to something like 16, 24, etc. */
526 drwav_uint16 bitsPerSample;
528 /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */
529 drwav_uint16 translatedFormatTag;
531 /* The total number of PCM frames making up the audio data. */
532 drwav_uint64 totalPCMFrameCount;
535 /* The size in bytes of the data chunk. */
536 drwav_uint64 dataChunkDataSize;
538 /* The position in the stream of the first data byte of the data chunk. This is used for seeking. */
539 drwav_uint64 dataChunkDataPos;
541 /* The number of bytes remaining in the data chunk. */
542 drwav_uint64 bytesRemaining;
546 Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always
547 set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation.
549 drwav_uint64 dataChunkDataSizeTargetWrite;
551 /* Keeps track of whether or not the wav writer was initialized in sequential mode. */
552 drwav_bool32 isSequentialWrite;
559 /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */
560 drwav__memory_stream memoryStream;
561 drwav__memory_stream_write memoryStreamWrite;
563 /* Generic data for compressed formats. This data is shared across all block-compressed formats. */
566 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. */
569 /* Microsoft ADPCM specific data. */
572 drwav_uint32 bytesRemainingInBlock;
573 drwav_uint16 predictor[2];
574 drwav_int32 delta[2];
575 drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */
576 drwav_uint32 cachedFrameCount;
577 drwav_int32 prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */
580 /* IMA ADPCM specific data. */
583 drwav_uint32 bytesRemainingInBlock;
584 drwav_int32 predictor[2];
585 drwav_int32 stepIndex[2];
586 drwav_int32 cachedFrames[16]; /* Samples are stored in this cache during decoding. */
587 drwav_uint32 cachedFrameCount;
593 Initializes a pre-allocated drwav object for reading.
595 pWav [out] A pointer to the drwav object being initialized.
596 onRead [in] The function to call when data needs to be read from the client.
597 onSeek [in] The function to call when the read position of the client data needs to move.
598 onChunk [in, optional] The function to call when a chunk is enumerated at initialized time.
599 pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
600 pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk.
601 flags [in, optional] A set of flags for controlling how things are loaded.
603 Returns true if successful; false otherwise.
605 Close the loader with drwav_uninit().
607 This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory()
608 to open the stream from a file or from a block of memory respectively.
610 Possible values for flags:
611 DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function
612 to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored.
614 drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);".
616 The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt
617 after the function returns.
619 See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
621 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
622 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);
625 Initializes a pre-allocated drwav object for writing.
627 onWrite [in] The function to call when data needs to be written.
628 onSeek [in] The function to call when the write position needs to move.
629 pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek.
631 Returns true if successful; false otherwise.
633 Close the writer with drwav_uninit().
635 This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write()
636 to open the stream from a file or from a block of memory respectively.
638 If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform
639 a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek.
641 See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit()
643 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);
644 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);
645 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);
648 Utility function to determine the target size of the entire data to be written (including all headers and chunks).
650 Returns the target size in bytes.
652 Useful if the application needs to know the size to allocate.
654 Only writing to the RIFF chunk and one data chunk is currently supported.
656 See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write()
658 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
661 Uninitializes the given drwav object.
663 Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()).
665 DRWAV_API drwav_result drwav_uninit(drwav* pWav);
669 Reads raw audio data.
671 This is the lowest level function for reading audio data. It simply reads the given number of
672 bytes of the raw internal sample data.
674 Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for
675 reading sample data in a consistent format.
677 pBufferOut can be NULL in which case a seek will be performed.
679 Returns the number of bytes actually read.
681 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
684 Reads up to the specified number of PCM frames from the WAV file.
686 The output data will be in the file's internal format, converted to native-endian byte order. Use
687 drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format.
689 If the return value is less than <framesToRead> it means the end of the file has been reached or
690 you have requested more PCM frames than can possibly fit in the output buffer.
692 This function will only work when sample data is of a fixed size and uncompressed. If you are
693 using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32().
695 pBufferOut can be NULL in which case a seek will be performed.
697 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
698 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
699 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
702 Seeks to the given PCM frame.
704 Returns true if successful; false otherwise.
706 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
710 Writes raw audio data.
712 Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error.
714 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
719 Returns the number of PCM frames written.
721 Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to
722 little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion.
724 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
725 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
726 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
729 /* Conversion Utilities */
730 #ifndef DR_WAV_NO_CONVERSION_API
733 Reads a chunk of audio data and converts it to signed 16-bit PCM samples.
735 pBufferOut can be NULL in which case a seek will be performed.
737 Returns the number of PCM frames actually read.
739 If the return value is less than <framesToRead> it means the end of the file has been reached.
741 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
742 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
743 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
745 /* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */
746 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
748 /* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */
749 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
751 /* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */
752 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
754 /* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */
755 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
757 /* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */
758 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
760 /* Low-level function for converting A-law samples to signed 16-bit PCM samples. */
761 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
763 /* Low-level function for converting u-law samples to signed 16-bit PCM samples. */
764 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
768 Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples.
770 pBufferOut can be NULL in which case a seek will be performed.
772 Returns the number of PCM frames actually read.
774 If the return value is less than <framesToRead> it means the end of the file has been reached.
776 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
777 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
778 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
780 /* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */
781 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
783 /* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */
784 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
786 /* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */
787 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
789 /* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */
790 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
792 /* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */
793 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
795 /* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */
796 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
798 /* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */
799 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
803 Reads a chunk of audio data and converts it to signed 32-bit PCM samples.
805 pBufferOut can be NULL in which case a seek will be performed.
807 Returns the number of PCM frames actually read.
809 If the return value is less than <framesToRead> it means the end of the file has been reached.
811 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
812 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
813 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
815 /* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */
816 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
818 /* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */
819 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
821 /* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */
822 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
824 /* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */
825 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
827 /* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */
828 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
830 /* Low-level function for converting A-law samples to signed 32-bit PCM samples. */
831 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
833 /* Low-level function for converting u-law samples to signed 32-bit PCM samples. */
834 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
836 #endif /* DR_WAV_NO_CONVERSION_API */
839 /* High-Level Convenience Helpers */
841 #ifndef DR_WAV_NO_STDIO
843 Helper for initializing a wave file for reading using stdio.
845 This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
846 objects because the operating system may restrict the number of file handles an application can have open at
849 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
850 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);
851 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
852 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);
855 Helper for initializing a wave file for writing using stdio.
857 This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
858 objects because the operating system may restrict the number of file handles an application can have open at
861 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
862 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);
863 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);
864 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);
865 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);
866 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);
867 #endif /* DR_WAV_NO_STDIO */
870 Helper for initializing a loader from a pre-allocated memory buffer.
872 This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
873 the lifetime of the drwav object.
875 The buffer should contain the contents of the entire wave file, not just the sample data.
877 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
878 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);
881 Helper for initializing a writer which outputs data to a memory buffer.
883 dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
885 The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid
886 until after drwav_uninit() has been called.
888 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);
889 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);
890 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);
893 #ifndef DR_WAV_NO_CONVERSION_API
895 Opens and reads an entire wav file in a single operation.
897 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
899 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);
900 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);
901 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);
902 #ifndef DR_WAV_NO_STDIO
904 Opens and decodes an entire wav file in a single operation.
906 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
908 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);
909 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);
910 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);
911 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);
912 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);
913 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);
916 Opens and decodes an entire wav file from a block of memory in a single operation.
918 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
920 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);
921 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);
922 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);
925 /* Frees data that was allocated internally by dr_wav. */
926 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
928 /* Converts bytes from a wav stream to a sized type of native endian. */
929 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data);
930 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data);
931 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data);
932 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data);
933 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data);
934 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data);
936 /* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */
937 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
939 /* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */
940 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
945 #endif /* dr_wav_h */
948 /************************************************************************************************************************************************************
949 ************************************************************************************************************************************************************
953 ************************************************************************************************************************************************************
954 ************************************************************************************************************************************************************/
955 #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
960 #include <string.h> /* For memcpy(), memset() */
961 #include <limits.h> /* For INT_MAX */
963 #ifndef DR_WAV_NO_STDIO
968 /* Standard library stuff. */
971 #define DRWAV_ASSERT(expression) assert(expression)
974 #define DRWAV_MALLOC(sz) malloc((sz))
976 #ifndef DRWAV_REALLOC
977 #define DRWAV_REALLOC(p, sz) realloc((p), (sz))
980 #define DRWAV_FREE(p) free((p))
982 #ifndef DRWAV_COPY_MEMORY
983 #define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
985 #ifndef DRWAV_ZERO_MEMORY
986 #define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
988 #ifndef DRWAV_ZERO_OBJECT
989 #define DRWAV_ZERO_OBJECT(p) DRWAV_ZERO_MEMORY((p), sizeof(*p))
992 #define drwav_countof(x) (sizeof(x) / sizeof(x[0]))
993 #define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a))
994 #define drwav_min(a, b) (((a) < (b)) ? (a) : (b))
995 #define drwav_max(a, b) (((a) > (b)) ? (a) : (b))
996 #define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x))))
998 #define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */
1000 /* CPU architecture. */
1001 #if defined(__x86_64__) || defined(_M_X64)
1003 #elif defined(__i386) || defined(_M_IX86)
1005 #elif defined(__arm__) || defined(_M_ARM)
1010 #define DRWAV_INLINE __forceinline
1011 #elif defined(__GNUC__)
1013 I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
1014 the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
1015 case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
1016 command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
1017 I am using "__inline__" only when we're compiling in strict ANSI mode.
1019 #if defined(__STRICT_ANSI__)
1020 #define DRWAV_INLINE __inline__ __attribute__((always_inline))
1022 #define DRWAV_INLINE inline __attribute__((always_inline))
1024 #elif defined(__WATCOMC__)
1025 #define DRWAV_INLINE __inline
1027 #define DRWAV_INLINE
1030 #if defined(SIZE_MAX)
1031 #define DRWAV_SIZE_MAX SIZE_MAX
1033 #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
1034 #define DRWAV_SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
1036 #define DRWAV_SIZE_MAX 0xFFFFFFFF
1040 #if defined(_MSC_VER) && _MSC_VER >= 1400
1041 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1042 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1043 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1044 #elif defined(__clang__)
1045 #if defined(__has_builtin)
1046 #if __has_builtin(__builtin_bswap16)
1047 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1049 #if __has_builtin(__builtin_bswap32)
1050 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1052 #if __has_builtin(__builtin_bswap64)
1053 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1056 #elif defined(__GNUC__)
1057 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
1058 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1059 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1061 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
1062 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1066 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision)
1069 *pMajor = DRWAV_VERSION_MAJOR;
1073 *pMinor = DRWAV_VERSION_MINOR;
1077 *pRevision = DRWAV_VERSION_REVISION;
1081 DRWAV_API const char* drwav_version_string(void)
1083 return DRWAV_VERSION_STRING;
1087 These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are
1088 you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation.
1090 #ifndef DRWAV_MAX_SAMPLE_RATE
1091 #define DRWAV_MAX_SAMPLE_RATE 384000
1093 #ifndef DRWAV_MAX_CHANNELS
1094 #define DRWAV_MAX_CHANNELS 256
1096 #ifndef DRWAV_MAX_BITS_PER_SAMPLE
1097 #define DRWAV_MAX_BITS_PER_SAMPLE 64
1100 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 */
1101 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 */
1102 /*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 */
1103 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 */
1104 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 */
1105 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 */
1106 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 */
1109 static DRWAV_INLINE int drwav__is_little_endian(void)
1111 #if defined(DRWAV_X86) || defined(DRWAV_X64)
1113 #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
1117 return (*(char*)&n) == 1;
1122 static DRWAV_INLINE void drwav__bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid)
1125 for (i = 0; i < 16; ++i) {
1131 static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n)
1133 #ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC
1134 #if defined(_MSC_VER)
1135 return _byteswap_ushort(n);
1136 #elif defined(__GNUC__) || defined(__clang__)
1137 return __builtin_bswap16(n);
1139 #error "This compiler does not support the byte swap intrinsic."
1142 return ((n & 0xFF00) >> 8) |
1143 ((n & 0x00FF) << 8);
1147 static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n)
1149 #ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC
1150 #if defined(_MSC_VER)
1151 return _byteswap_ulong(n);
1152 #elif defined(__GNUC__) || defined(__clang__)
1153 #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. */
1154 /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
1156 __asm__ __volatile__ (
1157 #if defined(DRWAV_64BIT)
1158 "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! */
1160 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
1165 return __builtin_bswap32(n);
1168 #error "This compiler does not support the byte swap intrinsic."
1171 return ((n & 0xFF000000) >> 24) |
1172 ((n & 0x00FF0000) >> 8) |
1173 ((n & 0x0000FF00) << 8) |
1174 ((n & 0x000000FF) << 24);
1178 static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
1180 #ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC
1181 #if defined(_MSC_VER)
1182 return _byteswap_uint64(n);
1183 #elif defined(__GNUC__) || defined(__clang__)
1184 return __builtin_bswap64(n);
1186 #error "This compiler does not support the byte swap intrinsic."
1189 /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
1190 return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) |
1191 ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) |
1192 ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) |
1193 ((n & ((drwav_uint64)0x000000FF << 32)) >> 8) |
1194 ((n & ((drwav_uint64)0xFF000000 )) << 8) |
1195 ((n & ((drwav_uint64)0x00FF0000 )) << 24) |
1196 ((n & ((drwav_uint64)0x0000FF00 )) << 40) |
1197 ((n & ((drwav_uint64)0x000000FF )) << 56);
1202 static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
1204 return (drwav_int16)drwav__bswap16((drwav_uint16)n);
1207 static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount)
1209 drwav_uint64 iSample;
1210 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1211 pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]);
1216 static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p)
1224 static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount)
1226 drwav_uint64 iSample;
1227 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1228 drwav_uint8* pSample = pSamples + (iSample*3);
1229 drwav__bswap_s24(pSample);
1234 static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n)
1236 return (drwav_int32)drwav__bswap32((drwav_uint32)n);
1239 static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount)
1241 drwav_uint64 iSample;
1242 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1243 pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]);
1248 static DRWAV_INLINE float drwav__bswap_f32(float n)
1255 x.i = drwav__bswap32(x.i);
1260 static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount)
1262 drwav_uint64 iSample;
1263 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1264 pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]);
1269 static DRWAV_INLINE double drwav__bswap_f64(double n)
1276 x.i = drwav__bswap64(x.i);
1281 static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount)
1283 drwav_uint64 iSample;
1284 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1285 pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]);
1290 static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1292 /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */
1293 switch (bytesPerSample)
1295 case 2: /* s16, s12 (loosely packed) */
1297 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1301 drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount);
1305 drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount);
1309 /* Unsupported format. */
1310 DRWAV_ASSERT(DRWAV_FALSE);
1315 static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1317 switch (bytesPerSample)
1319 #if 0 /* Contributions welcome for f16 support. */
1322 drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount);
1327 drwav__bswap_samples_f32((float*)pSamples, sampleCount);
1331 drwav__bswap_samples_f64((double*)pSamples, sampleCount);
1335 /* Unsupported format. */
1336 DRWAV_ASSERT(DRWAV_FALSE);
1341 static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format)
1345 case DR_WAVE_FORMAT_PCM:
1347 drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample);
1350 case DR_WAVE_FORMAT_IEEE_FLOAT:
1352 drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample);
1355 case DR_WAVE_FORMAT_ALAW:
1356 case DR_WAVE_FORMAT_MULAW:
1358 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1361 case DR_WAVE_FORMAT_ADPCM:
1362 case DR_WAVE_FORMAT_DVI_ADPCM:
1365 /* Unsupported format. */
1366 DRWAV_ASSERT(DRWAV_FALSE);
1372 DRWAV_PRIVATE void* drwav__malloc_default(size_t sz, void* pUserData)
1375 return DRWAV_MALLOC(sz);
1378 DRWAV_PRIVATE void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
1381 return DRWAV_REALLOC(p, sz);
1384 DRWAV_PRIVATE void drwav__free_default(void* p, void* pUserData)
1391 DRWAV_PRIVATE void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
1393 if (pAllocationCallbacks == NULL) {
1397 if (pAllocationCallbacks->onMalloc != NULL) {
1398 return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
1401 /* Try using realloc(). */
1402 if (pAllocationCallbacks->onRealloc != NULL) {
1403 return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
1409 DRWAV_PRIVATE void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
1411 if (pAllocationCallbacks == NULL) {
1415 if (pAllocationCallbacks->onRealloc != NULL) {
1416 return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
1419 /* Try emulating realloc() in terms of malloc()/free(). */
1420 if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
1423 p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
1429 DRWAV_COPY_MEMORY(p2, p, szOld);
1430 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1439 DRWAV_PRIVATE void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
1441 if (p == NULL || pAllocationCallbacks == NULL) {
1445 if (pAllocationCallbacks->onFree != NULL) {
1446 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1451 DRWAV_PRIVATE drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
1453 if (pAllocationCallbacks != NULL) {
1455 return *pAllocationCallbacks;
1458 drwav_allocation_callbacks allocationCallbacks;
1459 allocationCallbacks.pUserData = NULL;
1460 allocationCallbacks.onMalloc = drwav__malloc_default;
1461 allocationCallbacks.onRealloc = drwav__realloc_default;
1462 allocationCallbacks.onFree = drwav__free_default;
1463 return allocationCallbacks;
1468 static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
1471 formatTag == DR_WAVE_FORMAT_ADPCM ||
1472 formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
1475 DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
1477 return (unsigned int)(chunkSize % 2);
1480 DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
1482 return (unsigned int)(chunkSize % 8);
1485 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1486 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1487 DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
1489 DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
1491 if (container == drwav_container_riff || container == drwav_container_rf64) {
1492 drwav_uint8 sizeInBytes[4];
1494 if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
1495 return DRWAV_AT_END;
1498 if (onRead(pUserData, sizeInBytes, 4) != 4) {
1499 return DRWAV_INVALID_FILE;
1502 pHeaderOut->sizeInBytes = drwav_bytes_to_u32(sizeInBytes);
1503 pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes);
1504 *pRunningBytesReadOut += 8;
1506 drwav_uint8 sizeInBytes[8];
1508 if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
1509 return DRWAV_AT_END;
1512 if (onRead(pUserData, sizeInBytes, 8) != 8) {
1513 return DRWAV_INVALID_FILE;
1516 pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */
1517 pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
1518 *pRunningBytesReadOut += 24;
1521 return DRWAV_SUCCESS;
1524 DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1526 drwav_uint64 bytesRemainingToSeek = offset;
1527 while (bytesRemainingToSeek > 0) {
1528 if (bytesRemainingToSeek > 0x7FFFFFFF) {
1529 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1532 bytesRemainingToSeek -= 0x7FFFFFFF;
1534 if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
1537 bytesRemainingToSeek = 0;
1544 DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1546 if (offset <= 0x7FFFFFFF) {
1547 return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
1550 /* Larger than 32-bit seek. */
1551 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
1554 offset -= 0x7FFFFFFF;
1557 if (offset <= 0x7FFFFFFF) {
1558 return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
1561 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1564 offset -= 0x7FFFFFFF;
1567 /* Should never get here. */
1568 /*return DRWAV_TRUE; */
1572 DRWAV_PRIVATE drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut)
1574 drwav_chunk_header header;
1575 drwav_uint8 fmt[16];
1577 if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
1582 /* Skip non-fmt chunks. */
1583 while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav_fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
1584 if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
1587 *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize;
1589 /* Try the next header. */
1590 if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
1597 if (container == drwav_container_riff || container == drwav_container_rf64) {
1598 if (!drwav_fourcc_equal(header.id.fourcc, "fmt ")) {
1602 if (!drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
1608 if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
1611 *pRunningBytesReadOut += sizeof(fmt);
1613 fmtOut->formatTag = drwav_bytes_to_u16(fmt + 0);
1614 fmtOut->channels = drwav_bytes_to_u16(fmt + 2);
1615 fmtOut->sampleRate = drwav_bytes_to_u32(fmt + 4);
1616 fmtOut->avgBytesPerSec = drwav_bytes_to_u32(fmt + 8);
1617 fmtOut->blockAlign = drwav_bytes_to_u16(fmt + 12);
1618 fmtOut->bitsPerSample = drwav_bytes_to_u16(fmt + 14);
1620 fmtOut->extendedSize = 0;
1621 fmtOut->validBitsPerSample = 0;
1622 fmtOut->channelMask = 0;
1623 memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
1625 if (header.sizeInBytes > 16) {
1626 drwav_uint8 fmt_cbSize[2];
1627 int bytesReadSoFar = 0;
1629 if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
1630 return DRWAV_FALSE; /* Expecting more data. */
1632 *pRunningBytesReadOut += sizeof(fmt_cbSize);
1634 bytesReadSoFar = 18;
1636 fmtOut->extendedSize = drwav_bytes_to_u16(fmt_cbSize);
1637 if (fmtOut->extendedSize > 0) {
1638 /* Simple validation. */
1639 if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1640 if (fmtOut->extendedSize != 22) {
1645 if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1646 drwav_uint8 fmtext[22];
1647 if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) {
1648 return DRWAV_FALSE; /* Expecting more data. */
1651 fmtOut->validBitsPerSample = drwav_bytes_to_u16(fmtext + 0);
1652 fmtOut->channelMask = drwav_bytes_to_u32(fmtext + 2);
1653 drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat);
1655 if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) {
1659 *pRunningBytesReadOut += fmtOut->extendedSize;
1661 bytesReadSoFar += fmtOut->extendedSize;
1664 /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */
1665 if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) {
1668 *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
1671 if (header.paddingSize > 0) {
1672 if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
1675 *pRunningBytesReadOut += header.paddingSize;
1682 DRWAV_PRIVATE size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
1686 DRWAV_ASSERT(onRead != NULL);
1687 DRWAV_ASSERT(pCursor != NULL);
1689 bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
1690 *pCursor += bytesRead;
1695 DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
1697 DRWAV_ASSERT(onSeek != NULL);
1698 DRWAV_ASSERT(pCursor != NULL);
1700 if (!onSeek(pUserData, offset, origin)) {
1704 if (origin == drwav_seek_origin_start) {
1716 DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
1719 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
1720 is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align.
1722 if ((pWav->bitsPerSample & 0x7) == 0) {
1723 /* Bits per sample is a multiple of 8. */
1724 return (pWav->bitsPerSample * pWav->fmt.channels) >> 3;
1726 return pWav->fmt.blockAlign;
1730 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
1736 if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) {
1737 return pFMT->formatTag;
1739 return drwav_bytes_to_u16(pFMT->subFormat); /* Only the first two bytes are required. */
1743 DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
1745 if (pWav == NULL || onRead == NULL || onSeek == NULL) {
1749 DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
1750 pWav->onRead = onRead;
1751 pWav->onSeek = onSeek;
1752 pWav->pUserData = pReadSeekUserData;
1753 pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
1755 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
1756 return DRWAV_FALSE; /* Invalid allocation callbacks. */
1762 DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
1764 /* This function assumes drwav_preinit() has been called beforehand. */
1766 drwav_uint64 cursor; /* <-- Keeps track of the byte position so we can seek to specific locations. */
1767 drwav_bool32 sequential;
1768 drwav_uint8 riff[4];
1770 unsigned short translatedFormatTag;
1771 drwav_bool32 foundDataChunk;
1772 drwav_uint64 dataChunkSize = 0; /* <-- Important! Don't explicitly set this to 0 anywhere else. Calculation of the size of the data chunk is performed in different paths depending on the container. */
1773 drwav_uint64 sampleCountFromFactChunk = 0; /* Same as dataChunkSize - make sure this is the only place this is initialized to 0. */
1774 drwav_uint64 chunkSize;
1777 sequential = (flags & DRWAV_SEQUENTIAL) != 0;
1779 /* The first 4 bytes should be the RIFF identifier. */
1780 if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) {
1785 The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for
1786 w64 it will start with "riff".
1788 if (drwav_fourcc_equal(riff, "RIFF")) {
1789 pWav->container = drwav_container_riff;
1790 } else if (drwav_fourcc_equal(riff, "riff")) {
1792 drwav_uint8 riff2[12];
1794 pWav->container = drwav_container_w64;
1796 /* Check the rest of the GUID for validity. */
1797 if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) {
1801 for (i = 0; i < 12; ++i) {
1802 if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
1806 } else if (drwav_fourcc_equal(riff, "RF64")) {
1807 pWav->container = drwav_container_rf64;
1809 return DRWAV_FALSE; /* Unknown or unsupported container. */
1813 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
1814 drwav_uint8 chunkSizeBytes[4];
1815 drwav_uint8 wave[4];
1818 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
1822 if (pWav->container == drwav_container_riff) {
1823 if (drwav_bytes_to_u32(chunkSizeBytes) < 36) {
1824 return DRWAV_FALSE; /* Chunk size should always be at least 36 bytes. */
1827 if (drwav_bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) {
1828 return DRWAV_FALSE; /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */
1832 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
1836 if (!drwav_fourcc_equal(wave, "WAVE")) {
1837 return DRWAV_FALSE; /* Expecting "WAVE". */
1840 drwav_uint8 chunkSizeBytes[8];
1841 drwav_uint8 wave[16];
1844 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
1848 if (drwav_bytes_to_u64(chunkSizeBytes) < 80) {
1852 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
1856 if (!drwav_guid_equal(wave, drwavGUID_W64_WAVE)) {
1862 /* For RF64, the "ds64" chunk must come next, before the "fmt " chunk. */
1863 if (pWav->container == drwav_container_rf64) {
1864 drwav_uint8 sizeBytes[8];
1865 drwav_uint64 bytesRemainingInChunk;
1866 drwav_chunk_header header;
1867 drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
1868 if (result != DRWAV_SUCCESS) {
1872 if (!drwav_fourcc_equal(header.id.fourcc, "ds64")) {
1873 return DRWAV_FALSE; /* Expecting "ds64". */
1876 bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
1878 /* We don't care about the size of the RIFF chunk - skip it. */
1879 if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
1882 bytesRemainingInChunk -= 8;
1886 /* Next 8 bytes is the size of the "data" chunk. */
1887 if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
1890 bytesRemainingInChunk -= 8;
1891 dataChunkSize = drwav_bytes_to_u64(sizeBytes);
1894 /* Next 8 bytes is the same count which we would usually derived from the FACT chunk if it was available. */
1895 if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
1898 bytesRemainingInChunk -= 8;
1899 sampleCountFromFactChunk = drwav_bytes_to_u64(sizeBytes);
1902 /* Skip over everything else. */
1903 if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
1906 cursor += bytesRemainingInChunk;
1910 /* The next bytes should be the "fmt " chunk. */
1911 if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) {
1912 return DRWAV_FALSE; /* Failed to read the "fmt " chunk. */
1915 /* Basic validation. */
1916 if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE) ||
1917 (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS) ||
1918 (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) ||
1919 fmt.blockAlign == 0) {
1920 return DRWAV_FALSE; /* Probably an invalid WAV file. */
1924 /* Translate the internal format. */
1925 translatedFormatTag = fmt.formatTag;
1926 if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
1927 translatedFormatTag = drwav_bytes_to_u16(fmt.subFormat + 0);
1932 We need to enumerate over each chunk for two reasons:
1933 1) The "data" chunk may not be the next one
1934 2) We may want to report each chunk back to the client
1936 In order to correctly report each chunk back to the client we will need to keep looping until the end of the file.
1938 foundDataChunk = DRWAV_FALSE;
1940 /* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */
1943 drwav_chunk_header header;
1944 drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
1945 if (result != DRWAV_SUCCESS) {
1946 if (!foundDataChunk) {
1949 break; /* Probably at the end of the file. Get out of the loop. */
1953 /* Tell the client about this chunk. */
1954 if (!sequential && onChunk != NULL) {
1955 drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt);
1958 dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before
1959 we called the callback.
1961 if (callbackBytesRead > 0) {
1962 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
1969 if (!foundDataChunk) {
1970 pWav->dataChunkDataPos = cursor;
1973 chunkSize = header.sizeInBytes;
1974 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
1975 if (drwav_fourcc_equal(header.id.fourcc, "data")) {
1976 foundDataChunk = DRWAV_TRUE;
1977 if (pWav->container != drwav_container_rf64) { /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */
1978 dataChunkSize = chunkSize;
1982 if (drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
1983 foundDataChunk = DRWAV_TRUE;
1984 dataChunkSize = chunkSize;
1989 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
1990 this is that we would otherwise require a backwards seek which sequential mode forbids.
1992 if (foundDataChunk && sequential) {
1996 /* Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. */
1997 if (pWav->container == drwav_container_riff) {
1998 if (drwav_fourcc_equal(header.id.fourcc, "fact")) {
1999 drwav_uint32 sampleCount;
2000 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) {
2005 if (!foundDataChunk) {
2006 pWav->dataChunkDataPos = cursor;
2010 The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this
2011 for Microsoft ADPCM formats.
2013 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
2014 sampleCountFromFactChunk = sampleCount;
2016 sampleCountFromFactChunk = 0;
2019 } else if (pWav->container == drwav_container_w64) {
2020 if (drwav_guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
2021 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
2026 if (!foundDataChunk) {
2027 pWav->dataChunkDataPos = cursor;
2030 } else if (pWav->container == drwav_container_rf64) {
2031 /* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */
2035 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
2036 if (drwav_fourcc_equal(header.id.fourcc, "smpl")) {
2037 drwav_uint8 smplHeaderData[36]; /* 36 = size of the smpl header section, not including the loop data. */
2038 if (chunkSize >= sizeof(smplHeaderData)) {
2039 drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor);
2040 chunkSize -= bytesJustRead;
2042 if (bytesJustRead == sizeof(smplHeaderData)) {
2045 pWav->smpl.manufacturer = drwav_bytes_to_u32(smplHeaderData+0);
2046 pWav->smpl.product = drwav_bytes_to_u32(smplHeaderData+4);
2047 pWav->smpl.samplePeriod = drwav_bytes_to_u32(smplHeaderData+8);
2048 pWav->smpl.midiUnityNotes = drwav_bytes_to_u32(smplHeaderData+12);
2049 pWav->smpl.midiPitchFraction = drwav_bytes_to_u32(smplHeaderData+16);
2050 pWav->smpl.smpteFormat = drwav_bytes_to_u32(smplHeaderData+20);
2051 pWav->smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData+24);
2052 pWav->smpl.numSampleLoops = drwav_bytes_to_u32(smplHeaderData+28);
2053 pWav->smpl.samplerData = drwav_bytes_to_u32(smplHeaderData+32);
2055 for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) {
2056 drwav_uint8 smplLoopData[24]; /* 24 = size of a loop section in the smpl chunk. */
2057 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor);
2058 chunkSize -= bytesJustRead;
2060 if (bytesJustRead == sizeof(smplLoopData)) {
2061 pWav->smpl.loops[iLoop].cuePointId = drwav_bytes_to_u32(smplLoopData+0);
2062 pWav->smpl.loops[iLoop].type = drwav_bytes_to_u32(smplLoopData+4);
2063 pWav->smpl.loops[iLoop].start = drwav_bytes_to_u32(smplLoopData+8);
2064 pWav->smpl.loops[iLoop].end = drwav_bytes_to_u32(smplLoopData+12);
2065 pWav->smpl.loops[iLoop].fraction = drwav_bytes_to_u32(smplLoopData+16);
2066 pWav->smpl.loops[iLoop].playCount = drwav_bytes_to_u32(smplLoopData+20);
2068 break; /* Break from the smpl loop for loop. */
2073 /* Looks like invalid data. Ignore the chunk. */
2077 if (drwav_guid_equal(header.id.guid, drwavGUID_W64_SMPL)) {
2079 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
2080 is welcome to add support for this.
2085 /* Make sure we seek past the padding. */
2086 chunkSize += header.paddingSize;
2087 if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) {
2090 cursor += chunkSize;
2092 if (!foundDataChunk) {
2093 pWav->dataChunkDataPos = cursor;
2097 /* If we haven't found a data chunk, return an error. */
2098 if (!foundDataChunk) {
2102 /* 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. */
2104 if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) {
2107 cursor = pWav->dataChunkDataPos;
2111 /* At this point we should be sitting on the first byte of the raw audio data. */
2114 pWav->sampleRate = fmt.sampleRate;
2115 pWav->channels = fmt.channels;
2116 pWav->bitsPerSample = fmt.bitsPerSample;
2117 pWav->bytesRemaining = dataChunkSize;
2118 pWav->translatedFormatTag = translatedFormatTag;
2119 pWav->dataChunkDataSize = dataChunkSize;
2121 if (sampleCountFromFactChunk != 0) {
2122 pWav->totalPCMFrameCount = sampleCountFromFactChunk;
2124 pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav);
2126 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
2127 drwav_uint64 totalBlockHeaderSizeInBytes;
2128 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2130 /* Make sure any trailing partial block is accounted for. */
2131 if ((blockCount * fmt.blockAlign) < dataChunkSize) {
2135 /* 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. */
2136 totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
2137 pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
2139 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2140 drwav_uint64 totalBlockHeaderSizeInBytes;
2141 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2143 /* Make sure any trailing partial block is accounted for. */
2144 if ((blockCount * fmt.blockAlign) < dataChunkSize) {
2148 /* 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. */
2149 totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
2150 pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
2152 /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */
2153 pWav->totalPCMFrameCount += blockCount;
2157 /* Some formats only support a certain number of channels. */
2158 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2159 if (pWav->channels > 2) {
2164 #ifdef DR_WAV_LIBSNDFILE_COMPAT
2166 I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website),
2167 it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count
2168 from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct
2169 way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should
2170 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
2171 correctness tests against libsndfile, and is disabled by default.
2173 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
2174 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2175 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */
2177 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
2178 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
2179 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
2186 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2188 return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
2191 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)
2193 if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
2197 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
2201 DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize)
2203 drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. */
2204 if (chunkSize > 0xFFFFFFFFUL) {
2205 chunkSize = 0xFFFFFFFFUL;
2208 return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */
2211 DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
2213 if (dataChunkSize <= 0xFFFFFFFFUL) {
2214 return (drwav_uint32)dataChunkSize;
2216 return 0xFFFFFFFFUL;
2220 DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
2222 drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
2224 return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */
2227 DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
2229 return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
2232 DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize)
2234 drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. */
2235 if (chunkSize > 0xFFFFFFFFUL) {
2236 chunkSize = 0xFFFFFFFFUL;
2242 DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
2244 return dataChunkSize;
2248 DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
2250 DRWAV_ASSERT(pWav != NULL);
2251 DRWAV_ASSERT(pWav->onWrite != NULL);
2253 /* Generic write. Assumes no byte reordering required. */
2254 return pWav->onWrite(pWav->pUserData, pData, dataSize);
2257 DRWAV_PRIVATE size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value)
2259 DRWAV_ASSERT(pWav != NULL);
2260 DRWAV_ASSERT(pWav->onWrite != NULL);
2262 if (!drwav__is_little_endian()) {
2263 value = drwav__bswap16(value);
2266 return drwav__write(pWav, &value, 2);
2269 DRWAV_PRIVATE size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value)
2271 DRWAV_ASSERT(pWav != NULL);
2272 DRWAV_ASSERT(pWav->onWrite != NULL);
2274 if (!drwav__is_little_endian()) {
2275 value = drwav__bswap32(value);
2278 return drwav__write(pWav, &value, 4);
2281 DRWAV_PRIVATE size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value)
2283 DRWAV_ASSERT(pWav != NULL);
2284 DRWAV_ASSERT(pWav->onWrite != NULL);
2286 if (!drwav__is_little_endian()) {
2287 value = drwav__bswap64(value);
2290 return drwav__write(pWav, &value, 8);
2294 DRWAV_PRIVATE drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2296 if (pWav == NULL || onWrite == NULL) {
2300 if (!isSequential && onSeek == NULL) {
2301 return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */
2304 /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */
2305 if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
2308 if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
2312 DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
2313 pWav->onWrite = onWrite;
2314 pWav->onSeek = onSeek;
2315 pWav->pUserData = pUserData;
2316 pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
2318 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
2319 return DRWAV_FALSE; /* Invalid allocation callbacks. */
2322 pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
2323 pWav->fmt.channels = (drwav_uint16)pFormat->channels;
2324 pWav->fmt.sampleRate = pFormat->sampleRate;
2325 pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8);
2326 pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8);
2327 pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
2328 pWav->fmt.extendedSize = 0;
2329 pWav->isSequentialWrite = isSequential;
2334 DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
2336 /* The function assumes drwav_preinit_write() was called beforehand. */
2338 size_t runningPos = 0;
2339 drwav_uint64 initialDataChunkSize = 0;
2340 drwav_uint64 chunkSizeFMT;
2343 The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In
2344 sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non-
2345 sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek.
2347 if (pWav->isSequentialWrite) {
2348 initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
2351 The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64
2352 so for the sake of simplicity I'm not doing any validation for that.
2354 if (pFormat->container == drwav_container_riff) {
2355 if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
2356 return DRWAV_FALSE; /* Not enough room to store every sample. */
2361 pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
2365 if (pFormat->container == drwav_container_riff) {
2366 drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; /* +28 = "WAVE" + [sizeof "fmt " chunk] */
2367 runningPos += drwav__write(pWav, "RIFF", 4);
2368 runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
2369 runningPos += drwav__write(pWav, "WAVE", 4);
2370 } else if (pFormat->container == drwav_container_w64) {
2371 drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
2372 runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
2373 runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
2374 runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
2375 } else if (pFormat->container == drwav_container_rf64) {
2376 runningPos += drwav__write(pWav, "RF64", 4);
2377 runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always 0xFFFFFFFF for RF64. Set to a proper value in the "ds64" chunk. */
2378 runningPos += drwav__write(pWav, "WAVE", 4);
2382 /* "ds64" chunk (RF64 only). */
2383 if (pFormat->container == drwav_container_rf64) {
2384 drwav_uint32 initialds64ChunkSize = 28; /* 28 = [Size of RIFF (8 bytes)] + [Size of DATA (8 bytes)] + [Sample Count (8 bytes)] + [Table Length (4 bytes)]. Table length always set to 0. */
2385 drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize; /* +8 for the ds64 header. */
2387 runningPos += drwav__write(pWav, "ds64", 4);
2388 runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize); /* Size of ds64. */
2389 runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize); /* Size of RIFF. Set to true value at the end. */
2390 runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize); /* Size of DATA. Set to true value at the end. */
2391 runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount); /* Sample count. */
2392 runningPos += drwav__write_u32ne_to_le(pWav, 0); /* Table length. Always set to zero in our case since we're not doing any other chunks than "DATA". */
2397 if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
2399 runningPos += drwav__write(pWav, "fmt ", 4);
2400 runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
2401 } else if (pFormat->container == drwav_container_w64) {
2403 runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
2404 runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
2407 runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag);
2408 runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels);
2409 runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate);
2410 runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec);
2411 runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign);
2412 runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample);
2415 if (pFormat->container == drwav_container_riff) {
2416 drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
2417 runningPos += drwav__write(pWav, "data", 4);
2418 runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
2419 } else if (pFormat->container == drwav_container_w64) {
2420 drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
2421 runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
2422 runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
2423 } else if (pFormat->container == drwav_container_rf64) {
2424 runningPos += drwav__write(pWav, "data", 4);
2425 runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always set to 0xFFFFFFFF for RF64. The true size of the data chunk is specified in the ds64 chunk. */
2428 /* Set some properties for the client's convenience. */
2429 pWav->container = pFormat->container;
2430 pWav->channels = (drwav_uint16)pFormat->channels;
2431 pWav->sampleRate = pFormat->sampleRate;
2432 pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
2433 pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
2434 pWav->dataChunkDataPos = runningPos;
2440 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)
2442 if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
2446 return drwav_init_write__internal(pWav, pFormat, 0); /* DRWAV_FALSE = Not Sequential */
2449 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)
2451 if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
2455 return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */
2458 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)
2460 if (pFormat == NULL) {
2464 return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
2467 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
2469 /* Casting totalSampleCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */
2470 drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0);
2471 drwav_uint64 riffChunkSizeBytes;
2472 drwav_uint64 fileSizeBytes = 0;
2474 if (pFormat->container == drwav_container_riff) {
2475 riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes);
2476 fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
2477 } else if (pFormat->container == drwav_container_w64) {
2478 riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
2479 fileSizeBytes = riffChunkSizeBytes;
2480 } else if (pFormat->container == drwav_container_rf64) {
2481 riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes);
2482 fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
2485 return fileSizeBytes;
2489 #ifndef DR_WAV_NO_STDIO
2491 /* 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. */
2493 DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e)
2497 case 0: return DRWAV_SUCCESS;
2499 case EPERM: return DRWAV_INVALID_OPERATION;
2502 case ENOENT: return DRWAV_DOES_NOT_EXIST;
2505 case ESRCH: return DRWAV_DOES_NOT_EXIST;
2508 case EINTR: return DRWAV_INTERRUPT;
2511 case EIO: return DRWAV_IO_ERROR;
2514 case ENXIO: return DRWAV_DOES_NOT_EXIST;
2517 case E2BIG: return DRWAV_INVALID_ARGS;
2520 case ENOEXEC: return DRWAV_INVALID_FILE;
2523 case EBADF: return DRWAV_INVALID_FILE;
2526 case ECHILD: return DRWAV_ERROR;
2529 case EAGAIN: return DRWAV_UNAVAILABLE;
2532 case ENOMEM: return DRWAV_OUT_OF_MEMORY;
2535 case EACCES: return DRWAV_ACCESS_DENIED;
2538 case EFAULT: return DRWAV_BAD_ADDRESS;
2541 case ENOTBLK: return DRWAV_ERROR;
2544 case EBUSY: return DRWAV_BUSY;
2547 case EEXIST: return DRWAV_ALREADY_EXISTS;
2550 case EXDEV: return DRWAV_ERROR;
2553 case ENODEV: return DRWAV_DOES_NOT_EXIST;
2556 case ENOTDIR: return DRWAV_NOT_DIRECTORY;
2559 case EISDIR: return DRWAV_IS_DIRECTORY;
2562 case EINVAL: return DRWAV_INVALID_ARGS;
2565 case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES;
2568 case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES;
2571 case ENOTTY: return DRWAV_INVALID_OPERATION;
2574 case ETXTBSY: return DRWAV_BUSY;
2577 case EFBIG: return DRWAV_TOO_BIG;
2580 case ENOSPC: return DRWAV_NO_SPACE;
2583 case ESPIPE: return DRWAV_BAD_SEEK;
2586 case EROFS: return DRWAV_ACCESS_DENIED;
2589 case EMLINK: return DRWAV_TOO_MANY_LINKS;
2592 case EPIPE: return DRWAV_BAD_PIPE;
2595 case EDOM: return DRWAV_OUT_OF_RANGE;
2598 case ERANGE: return DRWAV_OUT_OF_RANGE;
2601 case EDEADLK: return DRWAV_DEADLOCK;
2604 case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG;
2607 case ENOLCK: return DRWAV_ERROR;
2610 case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
2613 case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
2616 case ELOOP: return DRWAV_TOO_MANY_LINKS;
2619 case ENOMSG: return DRWAV_NO_MESSAGE;
2622 case EIDRM: return DRWAV_ERROR;
2625 case ECHRNG: return DRWAV_ERROR;
2628 case EL2NSYNC: return DRWAV_ERROR;
2631 case EL3HLT: return DRWAV_ERROR;
2634 case EL3RST: return DRWAV_ERROR;
2637 case ELNRNG: return DRWAV_OUT_OF_RANGE;
2640 case EUNATCH: return DRWAV_ERROR;
2643 case ENOCSI: return DRWAV_ERROR;
2646 case EL2HLT: return DRWAV_ERROR;
2649 case EBADE: return DRWAV_ERROR;
2652 case EBADR: return DRWAV_ERROR;
2655 case EXFULL: return DRWAV_ERROR;
2658 case ENOANO: return DRWAV_ERROR;
2661 case EBADRQC: return DRWAV_ERROR;
2664 case EBADSLT: return DRWAV_ERROR;
2667 case EBFONT: return DRWAV_INVALID_FILE;
2670 case ENOSTR: return DRWAV_ERROR;
2673 case ENODATA: return DRWAV_NO_DATA_AVAILABLE;
2676 case ETIME: return DRWAV_TIMEOUT;
2679 case ENOSR: return DRWAV_NO_DATA_AVAILABLE;
2682 case ENONET: return DRWAV_NO_NETWORK;
2685 case ENOPKG: return DRWAV_ERROR;
2688 case EREMOTE: return DRWAV_ERROR;
2691 case ENOLINK: return DRWAV_ERROR;
2694 case EADV: return DRWAV_ERROR;
2697 case ESRMNT: return DRWAV_ERROR;
2700 case ECOMM: return DRWAV_ERROR;
2703 case EPROTO: return DRWAV_ERROR;
2706 case EMULTIHOP: return DRWAV_ERROR;
2709 case EDOTDOT: return DRWAV_ERROR;
2712 case EBADMSG: return DRWAV_BAD_MESSAGE;
2715 case EOVERFLOW: return DRWAV_TOO_BIG;
2718 case ENOTUNIQ: return DRWAV_NOT_UNIQUE;
2721 case EBADFD: return DRWAV_ERROR;
2724 case EREMCHG: return DRWAV_ERROR;
2727 case ELIBACC: return DRWAV_ACCESS_DENIED;
2730 case ELIBBAD: return DRWAV_INVALID_FILE;
2733 case ELIBSCN: return DRWAV_INVALID_FILE;
2736 case ELIBMAX: return DRWAV_ERROR;
2739 case ELIBEXEC: return DRWAV_ERROR;
2742 case EILSEQ: return DRWAV_INVALID_DATA;
2745 case ERESTART: return DRWAV_ERROR;
2748 case ESTRPIPE: return DRWAV_ERROR;
2751 case EUSERS: return DRWAV_ERROR;
2754 case ENOTSOCK: return DRWAV_NOT_SOCKET;
2757 case EDESTADDRREQ: return DRWAV_NO_ADDRESS;
2760 case EMSGSIZE: return DRWAV_TOO_BIG;
2763 case EPROTOTYPE: return DRWAV_BAD_PROTOCOL;
2766 case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE;
2768 #ifdef EPROTONOSUPPORT
2769 case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED;
2771 #ifdef ESOCKTNOSUPPORT
2772 case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED;
2775 case EOPNOTSUPP: return DRWAV_INVALID_OPERATION;
2778 case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED;
2781 case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED;
2784 case EADDRINUSE: return DRWAV_ALREADY_IN_USE;
2786 #ifdef EADDRNOTAVAIL
2787 case EADDRNOTAVAIL: return DRWAV_ERROR;
2790 case ENETDOWN: return DRWAV_NO_NETWORK;
2793 case ENETUNREACH: return DRWAV_NO_NETWORK;
2796 case ENETRESET: return DRWAV_NO_NETWORK;
2799 case ECONNABORTED: return DRWAV_NO_NETWORK;
2802 case ECONNRESET: return DRWAV_CONNECTION_RESET;
2805 case ENOBUFS: return DRWAV_NO_SPACE;
2808 case EISCONN: return DRWAV_ALREADY_CONNECTED;
2811 case ENOTCONN: return DRWAV_NOT_CONNECTED;
2814 case ESHUTDOWN: return DRWAV_ERROR;
2817 case ETOOMANYREFS: return DRWAV_ERROR;
2820 case ETIMEDOUT: return DRWAV_TIMEOUT;
2823 case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED;
2826 case EHOSTDOWN: return DRWAV_NO_HOST;
2829 case EHOSTUNREACH: return DRWAV_NO_HOST;
2832 case EALREADY: return DRWAV_IN_PROGRESS;
2835 case EINPROGRESS: return DRWAV_IN_PROGRESS;
2838 case ESTALE: return DRWAV_INVALID_FILE;
2841 case EUCLEAN: return DRWAV_ERROR;
2844 case ENOTNAM: return DRWAV_ERROR;
2847 case ENAVAIL: return DRWAV_ERROR;
2850 case EISNAM: return DRWAV_ERROR;
2853 case EREMOTEIO: return DRWAV_IO_ERROR;
2856 case EDQUOT: return DRWAV_NO_SPACE;
2859 case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST;
2862 case EMEDIUMTYPE: return DRWAV_ERROR;
2865 case ECANCELED: return DRWAV_CANCELLED;
2868 case ENOKEY: return DRWAV_ERROR;
2871 case EKEYEXPIRED: return DRWAV_ERROR;
2874 case EKEYREVOKED: return DRWAV_ERROR;
2877 case EKEYREJECTED: return DRWAV_ERROR;
2880 case EOWNERDEAD: return DRWAV_ERROR;
2882 #ifdef ENOTRECOVERABLE
2883 case ENOTRECOVERABLE: return DRWAV_ERROR;
2886 case ERFKILL: return DRWAV_ERROR;
2889 case EHWPOISON: return DRWAV_ERROR;
2891 default: return DRWAV_ERROR;
2895 DRWAV_PRIVATE drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
2897 #if defined(_MSC_VER) && _MSC_VER >= 1400
2901 if (ppFile != NULL) {
2902 *ppFile = NULL; /* Safety. */
2905 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
2906 return DRWAV_INVALID_ARGS;
2909 #if defined(_MSC_VER) && _MSC_VER >= 1400
2910 err = fopen_s(ppFile, pFilePath, pOpenMode);
2912 return drwav_result_from_errno(err);
2915 #if defined(_WIN32) || defined(__APPLE__)
2916 *ppFile = fopen(pFilePath, pOpenMode);
2918 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
2919 *ppFile = fopen64(pFilePath, pOpenMode);
2921 *ppFile = fopen(pFilePath, pOpenMode);
2924 if (*ppFile == NULL) {
2925 drwav_result result = drwav_result_from_errno(errno);
2926 if (result == DRWAV_SUCCESS) {
2927 result = DRWAV_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */
2934 return DRWAV_SUCCESS;
2938 _wfopen() isn't always available in all compilation environments.
2941 * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
2942 * MinGW-64 (both 32- and 64-bit) seems to support it.
2943 * MinGW wraps it in !defined(__STRICT_ANSI__).
2944 * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
2946 This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
2947 fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
2950 #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
2951 #define DRWAV_HAS_WFOPEN
2955 DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
2957 if (ppFile != NULL) {
2958 *ppFile = NULL; /* Safety. */
2961 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
2962 return DRWAV_INVALID_ARGS;
2965 #if defined(DRWAV_HAS_WFOPEN)
2967 /* Use _wfopen() on Windows. */
2968 #if defined(_MSC_VER) && _MSC_VER >= 1400
2969 errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
2971 return drwav_result_from_errno(err);
2974 *ppFile = _wfopen(pFilePath, pOpenMode);
2975 if (*ppFile == NULL) {
2976 return drwav_result_from_errno(errno);
2979 (void)pAllocationCallbacks;
2983 Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
2984 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
2985 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.
2990 const wchar_t* pFilePathTemp = pFilePath;
2991 char* pFilePathMB = NULL;
2992 char pOpenModeMB[32] = {0};
2994 /* Get the length first. */
2995 DRWAV_ZERO_OBJECT(&mbs);
2996 lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
2997 if (lenMB == (size_t)-1) {
2998 return drwav_result_from_errno(errno);
3001 pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
3002 if (pFilePathMB == NULL) {
3003 return DRWAV_OUT_OF_MEMORY;
3006 pFilePathTemp = pFilePath;
3007 DRWAV_ZERO_OBJECT(&mbs);
3008 wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
3010 /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
3014 if (pOpenMode[i] == 0) {
3015 pOpenModeMB[i] = '\0';
3019 pOpenModeMB[i] = (char)pOpenMode[i];
3024 *ppFile = fopen(pFilePathMB, pOpenModeMB);
3026 drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
3029 if (*ppFile == NULL) {
3034 return DRWAV_SUCCESS;
3038 DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
3040 return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
3043 DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
3045 return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
3048 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
3050 return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
3053 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
3055 return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
3059 DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
3061 drwav_bool32 result;
3063 result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
3064 if (result != DRWAV_TRUE) {
3069 result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
3070 if (result != DRWAV_TRUE) {
3078 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)
3081 if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
3085 /* This takes ownership of the FILE* object. */
3086 return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
3089 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
3091 return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
3094 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)
3097 if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
3101 /* This takes ownership of the FILE* object. */
3102 return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
3106 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
3108 drwav_bool32 result;
3110 result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
3111 if (result != DRWAV_TRUE) {
3116 result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
3117 if (result != DRWAV_TRUE) {
3125 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
3128 if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
3132 /* This takes ownership of the FILE* object. */
3133 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
3136 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
3139 if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
3143 /* This takes ownership of the FILE* object. */
3144 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
3147 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
3149 return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3152 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)
3154 return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3157 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)
3159 if (pFormat == NULL) {
3163 return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3166 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)
3168 return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3171 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)
3173 return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3176 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)
3178 if (pFormat == NULL) {
3182 return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3184 #endif /* DR_WAV_NO_STDIO */
3187 DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
3189 drwav* pWav = (drwav*)pUserData;
3190 size_t bytesRemaining;
3192 DRWAV_ASSERT(pWav != NULL);
3193 DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
3195 bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
3196 if (bytesToRead > bytesRemaining) {
3197 bytesToRead = bytesRemaining;
3200 if (bytesToRead > 0) {
3201 DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
3202 pWav->memoryStream.currentReadPos += bytesToRead;
3208 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
3210 drwav* pWav = (drwav*)pUserData;
3211 DRWAV_ASSERT(pWav != NULL);
3213 if (origin == drwav_seek_origin_current) {
3215 if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
3216 return DRWAV_FALSE; /* Trying to seek too far forward. */
3219 if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
3220 return DRWAV_FALSE; /* Trying to seek too far backwards. */
3224 /* This will never underflow thanks to the clamps above. */
3225 pWav->memoryStream.currentReadPos += offset;
3227 if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
3228 pWav->memoryStream.currentReadPos = offset;
3230 return DRWAV_FALSE; /* Trying to seek too far forward. */
3237 DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
3239 drwav* pWav = (drwav*)pUserData;
3240 size_t bytesRemaining;
3242 DRWAV_ASSERT(pWav != NULL);
3243 DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
3245 bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos;
3246 if (bytesRemaining < bytesToWrite) {
3247 /* Need to reallocate. */
3249 size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2;
3251 /* If doubling wasn't enough, just make it the minimum required size to write the data. */
3252 if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) {
3253 newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite;
3256 pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
3257 if (pNewData == NULL) {
3261 *pWav->memoryStreamWrite.ppData = pNewData;
3262 pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
3265 DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
3267 pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
3268 if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
3269 pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
3272 *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
3274 return bytesToWrite;
3277 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
3279 drwav* pWav = (drwav*)pUserData;
3280 DRWAV_ASSERT(pWav != NULL);
3282 if (origin == drwav_seek_origin_current) {
3284 if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
3285 offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); /* Trying to seek too far forward. */
3288 if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
3289 offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */
3293 /* This will never underflow thanks to the clamps above. */
3294 pWav->memoryStreamWrite.currentWritePos += offset;
3296 if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
3297 pWav->memoryStreamWrite.currentWritePos = offset;
3299 pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */
3306 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
3308 return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
3311 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)
3313 if (data == NULL || dataSize == 0) {
3317 if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
3321 pWav->memoryStream.data = (const drwav_uint8*)data;
3322 pWav->memoryStream.dataSize = dataSize;
3323 pWav->memoryStream.currentReadPos = 0;
3325 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
3329 DRWAV_PRIVATE drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
3331 if (ppData == NULL || pDataSize == NULL) {
3335 *ppData = NULL; /* Important because we're using realloc()! */
3338 if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
3342 pWav->memoryStreamWrite.ppData = ppData;
3343 pWav->memoryStreamWrite.pDataSize = pDataSize;
3344 pWav->memoryStreamWrite.dataSize = 0;
3345 pWav->memoryStreamWrite.dataCapacity = 0;
3346 pWav->memoryStreamWrite.currentWritePos = 0;
3348 return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
3351 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)
3353 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
3356 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)
3358 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
3361 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)
3363 if (pFormat == NULL) {
3367 return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
3372 DRWAV_API drwav_result drwav_uninit(drwav* pWav)
3374 drwav_result result = DRWAV_SUCCESS;
3377 return DRWAV_INVALID_ARGS;
3381 If the drwav object was opened in write mode we'll need to finalize a few things:
3382 - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers.
3383 - Set the size of the "data" chunk.
3385 if (pWav->onWrite != NULL) {
3386 drwav_uint32 paddingSize = 0;
3388 /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */
3389 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
3390 paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
3392 paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
3395 if (paddingSize > 0) {
3396 drwav_uint64 paddingData = 0;
3397 drwav__write(pWav, &paddingData, paddingSize); /* Byte order does not matter for this. */
3401 Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need
3402 to do this when using non-sequential mode.
3404 if (pWav->onSeek && !pWav->isSequentialWrite) {
3405 if (pWav->container == drwav_container_riff) {
3406 /* The "RIFF" chunk size. */
3407 if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
3408 drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize);
3409 drwav__write_u32ne_to_le(pWav, riffChunkSize);
3412 /* The "data" chunk size. */
3413 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, drwav_seek_origin_start)) {
3414 drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
3415 drwav__write_u32ne_to_le(pWav, dataChunkSize);
3417 } else if (pWav->container == drwav_container_w64) {
3418 /* The "RIFF" chunk size. */
3419 if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
3420 drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
3421 drwav__write_u64ne_to_le(pWav, riffChunkSize);
3424 /* The "data" chunk size. */
3425 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, drwav_seek_origin_start)) {
3426 drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
3427 drwav__write_u64ne_to_le(pWav, dataChunkSize);
3429 } else if (pWav->container == drwav_container_rf64) {
3430 /* We only need to update the ds64 chunk. The "RIFF" and "data" chunks always have their sizes set to 0xFFFFFFFF for RF64. */
3431 int ds64BodyPos = 12 + 8;
3433 /* The "RIFF" chunk size. */
3434 if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
3435 drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize);
3436 drwav__write_u64ne_to_le(pWav, riffChunkSize);
3439 /* The "data" chunk size. */
3440 if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
3441 drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
3442 drwav__write_u64ne_to_le(pWav, dataChunkSize);
3447 /* Validation for sequential mode. */
3448 if (pWav->isSequentialWrite) {
3449 if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
3450 result = DRWAV_INVALID_FILE;
3455 #ifndef DR_WAV_NO_STDIO
3457 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()
3458 was used by looking at the onRead and onSeek callbacks.
3460 if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
3461 fclose((FILE*)pWav->pUserData);
3470 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
3474 if (pWav == NULL || bytesToRead == 0) {
3478 if (bytesToRead > pWav->bytesRemaining) {
3479 bytesToRead = (size_t)pWav->bytesRemaining;
3482 if (pBufferOut != NULL) {
3483 bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
3485 /* We need to seek. If we fail, we need to read-and-discard to make sure we get a good byte count. */
3487 while (bytesRead < bytesToRead) {
3488 size_t bytesToSeek = (bytesToRead - bytesRead);
3489 if (bytesToSeek > 0x7FFFFFFF) {
3490 bytesToSeek = 0x7FFFFFFF;
3493 if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) {
3497 bytesRead += bytesToSeek;
3500 /* When we get here we may need to read-and-discard some data. */
3501 while (bytesRead < bytesToRead) {
3502 drwav_uint8 buffer[4096];
3504 size_t bytesToSeek = (bytesToRead - bytesRead);
3505 if (bytesToSeek > sizeof(buffer)) {
3506 bytesToSeek = sizeof(buffer);
3509 bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek);
3510 bytesRead += bytesSeeked;
3512 if (bytesSeeked < bytesToSeek) {
3513 break; /* Reached the end. */
3518 pWav->bytesRemaining -= bytesRead;
3524 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3526 drwav_uint32 bytesPerFrame;
3527 drwav_uint64 bytesToRead; /* Intentionally uint64 instead of size_t so we can do a check that we're not reading too much on 32-bit builds. */
3529 if (pWav == NULL || framesToRead == 0) {
3533 /* Cannot use this function for compressed formats. */
3534 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3538 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
3539 if (bytesPerFrame == 0) {
3543 /* Don't try to read more samples than can potentially fit in the output buffer. */
3544 bytesToRead = framesToRead * bytesPerFrame;
3545 if (bytesToRead > DRWAV_SIZE_MAX) {
3546 bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame; /* Round the number of bytes to read to a clean frame boundary. */
3550 Doing an explicit check here just to make it clear that we don't want to be attempt to read anything if there's no bytes to read. There
3551 *could* be a time where it evaluates to 0 due to overflowing.
3553 if (bytesToRead == 0) {
3557 return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame;
3560 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3562 drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
3564 if (pBufferOut != NULL) {
3565 drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag);
3571 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
3573 if (drwav__is_little_endian()) {
3574 return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
3576 return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
3582 DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
3584 if (pWav->onWrite != NULL) {
3585 return DRWAV_FALSE; /* No seeking in write mode. */
3588 if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
3592 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3593 pWav->compressed.iCurrentPCMFrame = 0;
3595 /* Cached data needs to be cleared for compressed formats. */
3596 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3597 DRWAV_ZERO_OBJECT(&pWav->msadpcm);
3598 } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3599 DRWAV_ZERO_OBJECT(&pWav->ima);
3601 DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */
3605 pWav->bytesRemaining = pWav->dataChunkDataSize;
3609 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex)
3611 /* Seeking should be compatible with wave files > 2GB. */
3613 if (pWav == NULL || pWav->onSeek == NULL) {
3617 /* No seeking in write mode. */
3618 if (pWav->onWrite != NULL) {
3622 /* If there are no samples, just return DRWAV_TRUE without doing anything. */
3623 if (pWav->totalPCMFrameCount == 0) {
3627 /* Make sure the sample is clamped. */
3628 if (targetFrameIndex >= pWav->totalPCMFrameCount) {
3629 targetFrameIndex = pWav->totalPCMFrameCount - 1;
3633 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
3634 to seek back to the start.
3636 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
3637 /* TODO: This can be optimized. */
3640 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,
3641 we first need to seek back to the start and then just do the same thing as a forward seek.
3643 if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) {
3644 if (!drwav_seek_to_first_pcm_frame(pWav)) {
3649 if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) {
3650 drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame;
3652 drwav_int16 devnull[2048];
3653 while (offsetInFrames > 0) {
3654 drwav_uint64 framesRead = 0;
3655 drwav_uint64 framesToRead = offsetInFrames;
3656 if (framesToRead > drwav_countof(devnull)/pWav->channels) {
3657 framesToRead = drwav_countof(devnull)/pWav->channels;
3660 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3661 framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull);
3662 } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3663 framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull);
3665 DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */
3668 if (framesRead != framesToRead) {
3672 offsetInFrames -= framesRead;
3676 drwav_uint64 totalSizeInBytes;
3677 drwav_uint64 currentBytePos;
3678 drwav_uint64 targetBytePos;
3679 drwav_uint64 offset;
3681 totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav);
3682 DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);
3684 currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
3685 targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav);
3687 if (currentBytePos < targetBytePos) {
3688 /* Offset forwards. */
3689 offset = (targetBytePos - currentBytePos);
3691 /* Offset backwards. */
3692 if (!drwav_seek_to_first_pcm_frame(pWav)) {
3695 offset = targetBytePos;
3698 while (offset > 0) {
3699 int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
3700 if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
3704 pWav->bytesRemaining -= offset32;
3713 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
3715 size_t bytesWritten;
3717 if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
3721 bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
3722 pWav->dataChunkDataSize += bytesWritten;
3724 return bytesWritten;
3728 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3730 drwav_uint64 bytesToWrite;
3731 drwav_uint64 bytesWritten;
3732 const drwav_uint8* pRunningData;
3734 if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
3738 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
3739 if (bytesToWrite > DRWAV_SIZE_MAX) {
3744 pRunningData = (const drwav_uint8*)pData;
3746 while (bytesToWrite > 0) {
3747 size_t bytesJustWritten;
3748 drwav_uint64 bytesToWriteThisIteration;
3750 bytesToWriteThisIteration = bytesToWrite;
3751 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */
3753 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData);
3754 if (bytesJustWritten == 0) {
3758 bytesToWrite -= bytesJustWritten;
3759 bytesWritten += bytesJustWritten;
3760 pRunningData += bytesJustWritten;
3763 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
3766 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3768 drwav_uint64 bytesToWrite;
3769 drwav_uint64 bytesWritten;
3770 drwav_uint32 bytesPerSample;
3771 const drwav_uint8* pRunningData;
3773 if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
3777 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
3778 if (bytesToWrite > DRWAV_SIZE_MAX) {
3783 pRunningData = (const drwav_uint8*)pData;
3785 bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels;
3787 while (bytesToWrite > 0) {
3788 drwav_uint8 temp[4096];
3789 drwav_uint32 sampleCount;
3790 size_t bytesJustWritten;
3791 drwav_uint64 bytesToWriteThisIteration;
3793 bytesToWriteThisIteration = bytesToWrite;
3794 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */
3797 WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need
3798 to use an intermediary buffer for the conversion.
3800 sampleCount = sizeof(temp)/bytesPerSample;
3802 if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) {
3803 bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample;
3806 DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration);
3807 drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag);
3809 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp);
3810 if (bytesJustWritten == 0) {
3814 bytesToWrite -= bytesJustWritten;
3815 bytesWritten += bytesJustWritten;
3816 pRunningData += bytesJustWritten;
3819 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
3822 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
3824 if (drwav__is_little_endian()) {
3825 return drwav_write_pcm_frames_le(pWav, framesToWrite, pData);
3827 return drwav_write_pcm_frames_be(pWav, framesToWrite, pData);
3832 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
3834 drwav_uint64 totalFramesRead = 0;
3836 DRWAV_ASSERT(pWav != NULL);
3837 DRWAV_ASSERT(framesToRead > 0);
3839 /* TODO: Lots of room for optimization here. */
3841 while (pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
3842 DRWAV_ASSERT(framesToRead > 0); /* This loop iteration will never get hit with framesToRead == 0 because it's asserted at the top, and we check for 0 inside the loop just below. */
3844 /* If there are no cached frames we need to load a new block. */
3845 if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) {
3846 if (pWav->channels == 1) {
3848 drwav_uint8 header[7];
3849 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
3850 return totalFramesRead;
3852 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
3854 pWav->msadpcm.predictor[0] = header[0];
3855 pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 1);
3856 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 3);
3857 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 5);
3858 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0];
3859 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1];
3860 pWav->msadpcm.cachedFrameCount = 2;
3863 drwav_uint8 header[14];
3864 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
3865 return totalFramesRead;
3867 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
3869 pWav->msadpcm.predictor[0] = header[0];
3870 pWav->msadpcm.predictor[1] = header[1];
3871 pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 2);
3872 pWav->msadpcm.delta[1] = drwav_bytes_to_s16(header + 4);
3873 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 6);
3874 pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav_bytes_to_s16(header + 8);
3875 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 10);
3876 pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav_bytes_to_s16(header + 12);
3878 pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0];
3879 pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0];
3880 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
3881 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
3882 pWav->msadpcm.cachedFrameCount = 2;
3886 /* Output anything that's cached. */
3887 while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
3888 if (pBufferOut != NULL) {
3889 drwav_uint32 iSample = 0;
3890 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
3891 pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample];
3894 pBufferOut += pWav->channels;
3898 totalFramesRead += 1;
3899 pWav->compressed.iCurrentPCMFrame += 1;
3900 pWav->msadpcm.cachedFrameCount -= 1;
3903 if (framesToRead == 0) {
3909 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
3910 loop iteration which will trigger the loading of a new block.
3912 if (pWav->msadpcm.cachedFrameCount == 0) {
3913 if (pWav->msadpcm.bytesRemainingInBlock == 0) {
3916 static drwav_int32 adaptationTable[] = {
3917 230, 230, 230, 230, 307, 409, 512, 614,
3918 768, 614, 512, 409, 307, 230, 230, 230
3920 static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
3921 static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
3923 drwav_uint8 nibbles;
3924 drwav_int32 nibble0;
3925 drwav_int32 nibble1;
3927 if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
3928 return totalFramesRead;
3930 pWav->msadpcm.bytesRemainingInBlock -= 1;
3932 /* TODO: Optimize away these if statements. */
3933 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; }
3934 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; }
3936 if (pWav->channels == 1) {
3938 drwav_int32 newSample0;
3939 drwav_int32 newSample1;
3941 newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
3942 newSample0 += nibble0 * pWav->msadpcm.delta[0];
3943 newSample0 = drwav_clamp(newSample0, -32768, 32767);
3945 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
3946 if (pWav->msadpcm.delta[0] < 16) {
3947 pWav->msadpcm.delta[0] = 16;
3950 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
3951 pWav->msadpcm.prevFrames[0][1] = newSample0;
3954 newSample1 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
3955 newSample1 += nibble1 * pWav->msadpcm.delta[0];
3956 newSample1 = drwav_clamp(newSample1, -32768, 32767);
3958 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
3959 if (pWav->msadpcm.delta[0] < 16) {
3960 pWav->msadpcm.delta[0] = 16;
3963 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
3964 pWav->msadpcm.prevFrames[0][1] = newSample1;
3967 pWav->msadpcm.cachedFrames[2] = newSample0;
3968 pWav->msadpcm.cachedFrames[3] = newSample1;
3969 pWav->msadpcm.cachedFrameCount = 2;
3972 drwav_int32 newSample0;
3973 drwav_int32 newSample1;
3976 newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
3977 newSample0 += nibble0 * pWav->msadpcm.delta[0];
3978 newSample0 = drwav_clamp(newSample0, -32768, 32767);
3980 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
3981 if (pWav->msadpcm.delta[0] < 16) {
3982 pWav->msadpcm.delta[0] = 16;
3985 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
3986 pWav->msadpcm.prevFrames[0][1] = newSample0;
3990 newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
3991 newSample1 += nibble1 * pWav->msadpcm.delta[1];
3992 newSample1 = drwav_clamp(newSample1, -32768, 32767);
3994 pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
3995 if (pWav->msadpcm.delta[1] < 16) {
3996 pWav->msadpcm.delta[1] = 16;
3999 pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
4000 pWav->msadpcm.prevFrames[1][1] = newSample1;
4002 pWav->msadpcm.cachedFrames[2] = newSample0;
4003 pWav->msadpcm.cachedFrames[3] = newSample1;
4004 pWav->msadpcm.cachedFrameCount = 1;
4010 return totalFramesRead;
4014 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4016 drwav_uint64 totalFramesRead = 0;
4017 drwav_uint32 iChannel;
4019 static drwav_int32 indexTable[16] = {
4020 -1, -1, -1, -1, 2, 4, 6, 8,
4021 -1, -1, -1, -1, 2, 4, 6, 8
4024 static drwav_int32 stepTable[89] = {
4025 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
4026 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
4027 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
4028 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
4029 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
4030 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
4031 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
4032 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
4033 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
4036 DRWAV_ASSERT(pWav != NULL);
4037 DRWAV_ASSERT(framesToRead > 0);
4039 /* TODO: Lots of room for optimization here. */
4041 while (pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
4042 DRWAV_ASSERT(framesToRead > 0); /* This loop iteration will never get hit with framesToRead == 0 because it's asserted at the top, and we check for 0 inside the loop just below. */
4044 /* If there are no cached samples we need to load a new block. */
4045 if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) {
4046 if (pWav->channels == 1) {
4048 drwav_uint8 header[4];
4049 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
4050 return totalFramesRead;
4052 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
4054 if (header[2] >= drwav_countof(stepTable)) {
4055 pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
4056 pWav->ima.bytesRemainingInBlock = 0;
4057 return totalFramesRead; /* Invalid data. */
4060 pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0);
4061 pWav->ima.stepIndex[0] = header[2];
4062 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0];
4063 pWav->ima.cachedFrameCount = 1;
4066 drwav_uint8 header[8];
4067 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
4068 return totalFramesRead;
4070 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
4072 if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
4073 pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
4074 pWav->ima.bytesRemainingInBlock = 0;
4075 return totalFramesRead; /* Invalid data. */
4078 pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0);
4079 pWav->ima.stepIndex[0] = header[2];
4080 pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4);
4081 pWav->ima.stepIndex[1] = header[6];
4083 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0];
4084 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1];
4085 pWav->ima.cachedFrameCount = 1;
4089 /* Output anything that's cached. */
4090 while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
4091 if (pBufferOut != NULL) {
4092 drwav_uint32 iSample;
4093 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
4094 pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample];
4096 pBufferOut += pWav->channels;
4100 totalFramesRead += 1;
4101 pWav->compressed.iCurrentPCMFrame += 1;
4102 pWav->ima.cachedFrameCount -= 1;
4105 if (framesToRead == 0) {
4110 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
4111 loop iteration which will trigger the loading of a new block.
4113 if (pWav->ima.cachedFrameCount == 0) {
4114 if (pWav->ima.bytesRemainingInBlock == 0) {
4118 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
4119 left channel, 4 bytes for the right channel.
4121 pWav->ima.cachedFrameCount = 8;
4122 for (iChannel = 0; iChannel < pWav->channels; ++iChannel) {
4124 drwav_uint8 nibbles[4];
4125 if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) {
4126 pWav->ima.cachedFrameCount = 0;
4127 return totalFramesRead;
4129 pWav->ima.bytesRemainingInBlock -= 4;
4131 for (iByte = 0; iByte < 4; ++iByte) {
4132 drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
4133 drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
4135 drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]];
4136 drwav_int32 predictor = pWav->ima.predictor[iChannel];
4138 drwav_int32 diff = step >> 3;
4139 if (nibble0 & 1) diff += step >> 2;
4140 if (nibble0 & 2) diff += step >> 1;
4141 if (nibble0 & 4) diff += step;
4142 if (nibble0 & 8) diff = -diff;
4144 predictor = drwav_clamp(predictor + diff, -32768, 32767);
4145 pWav->ima.predictor[iChannel] = predictor;
4146 pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1);
4147 pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor;
4150 step = stepTable[pWav->ima.stepIndex[iChannel]];
4151 predictor = pWav->ima.predictor[iChannel];
4154 if (nibble1 & 1) diff += step >> 2;
4155 if (nibble1 & 2) diff += step >> 1;
4156 if (nibble1 & 4) diff += step;
4157 if (nibble1 & 8) diff = -diff;
4159 predictor = drwav_clamp(predictor + diff, -32768, 32767);
4160 pWav->ima.predictor[iChannel] = predictor;
4161 pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1);
4162 pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor;
4169 return totalFramesRead;
4173 #ifndef DR_WAV_NO_CONVERSION_API
4174 static unsigned short g_drwavAlawTable[256] = {
4175 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
4176 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
4177 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
4178 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
4179 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
4180 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
4181 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
4182 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
4183 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
4184 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
4185 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
4186 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
4187 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
4188 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
4189 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
4190 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
4193 static unsigned short g_drwavMulawTable[256] = {
4194 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
4195 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
4196 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
4197 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
4198 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
4199 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
4200 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
4201 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
4202 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
4203 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
4204 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
4205 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
4206 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
4207 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
4208 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
4209 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
4212 static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
4214 return (short)g_drwavAlawTable[sampleIn];
4217 static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
4219 return (short)g_drwavMulawTable[sampleIn];
4224 DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4228 /* Special case for 8-bit sample data because it's treated as unsigned. */
4229 if (bytesPerSample == 1) {
4230 drwav_u8_to_s16(pOut, pIn, totalSampleCount);
4235 /* Slightly more optimal implementation for common formats. */
4236 if (bytesPerSample == 2) {
4237 for (i = 0; i < totalSampleCount; ++i) {
4238 *pOut++ = ((const drwav_int16*)pIn)[i];
4242 if (bytesPerSample == 3) {
4243 drwav_s24_to_s16(pOut, pIn, totalSampleCount);
4246 if (bytesPerSample == 4) {
4247 drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
4252 /* Anything more than 64 bits per sample is not supported. */
4253 if (bytesPerSample > 8) {
4254 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
4259 /* Generic, slow converter. */
4260 for (i = 0; i < totalSampleCount; ++i) {
4261 drwav_uint64 sample = 0;
4262 unsigned int shift = (8 - bytesPerSample) * 8;
4265 for (j = 0; j < bytesPerSample; j += 1) {
4266 DRWAV_ASSERT(j < 8);
4267 sample |= (drwav_uint64)(pIn[j]) << shift;
4272 *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
4276 DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4278 if (bytesPerSample == 4) {
4279 drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount);
4281 } else if (bytesPerSample == 8) {
4282 drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount);
4285 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
4286 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
4291 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4293 drwav_uint64 totalFramesRead;
4294 drwav_uint8 sampleData[4096];
4295 drwav_uint32 bytesPerFrame;
4298 if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) {
4299 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
4302 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4303 if (bytesPerFrame == 0) {
4307 totalFramesRead = 0;
4309 while (framesToRead > 0) {
4310 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4311 if (framesRead == 0) {
4315 drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4317 pBufferOut += framesRead*pWav->channels;
4318 framesToRead -= framesRead;
4319 totalFramesRead += framesRead;
4322 return totalFramesRead;
4325 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4327 drwav_uint64 totalFramesRead;
4328 drwav_uint8 sampleData[4096];
4329 drwav_uint32 bytesPerFrame;
4331 if (pBufferOut == NULL) {
4332 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4335 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4336 if (bytesPerFrame == 0) {
4340 totalFramesRead = 0;
4342 while (framesToRead > 0) {
4343 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4344 if (framesRead == 0) {
4348 drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4350 pBufferOut += framesRead*pWav->channels;
4351 framesToRead -= framesRead;
4352 totalFramesRead += framesRead;
4355 return totalFramesRead;
4358 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4360 drwav_uint64 totalFramesRead;
4361 drwav_uint8 sampleData[4096];
4362 drwav_uint32 bytesPerFrame;
4364 if (pBufferOut == NULL) {
4365 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4368 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4369 if (bytesPerFrame == 0) {
4373 totalFramesRead = 0;
4375 while (framesToRead > 0) {
4376 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4377 if (framesRead == 0) {
4381 drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4383 pBufferOut += framesRead*pWav->channels;
4384 framesToRead -= framesRead;
4385 totalFramesRead += framesRead;
4388 return totalFramesRead;
4391 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4393 drwav_uint64 totalFramesRead;
4394 drwav_uint8 sampleData[4096];
4395 drwav_uint32 bytesPerFrame;
4397 if (pBufferOut == NULL) {
4398 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4401 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4402 if (bytesPerFrame == 0) {
4406 totalFramesRead = 0;
4408 while (framesToRead > 0) {
4409 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4410 if (framesRead == 0) {
4414 drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4416 pBufferOut += framesRead*pWav->channels;
4417 framesToRead -= framesRead;
4418 totalFramesRead += framesRead;
4421 return totalFramesRead;
4424 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4426 if (pWav == NULL || framesToRead == 0) {
4430 if (pBufferOut == NULL) {
4431 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4434 /* Don't try to read more samples than can potentially fit in the output buffer. */
4435 if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) {
4436 framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels;
4439 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
4440 return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut);
4443 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
4444 return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut);
4447 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
4448 return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut);
4451 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
4452 return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut);
4455 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
4456 return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut);
4459 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
4460 return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut);
4466 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4468 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
4469 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
4470 drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
4476 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
4478 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
4479 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
4480 drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
4487 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4491 for (i = 0; i < sampleCount; ++i) {
4499 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4503 for (i = 0; i < sampleCount; ++i) {
4504 int x = ((int)(((unsigned int)(((const drwav_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+2])) << 24)) >> 8;
4510 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
4514 for (i = 0; i < sampleCount; ++i) {
4521 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
4525 for (i = 0; i < sampleCount; ++i) {
4528 c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
4530 r = (int)(c * 32767.5f);
4536 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
4540 for (i = 0; i < sampleCount; ++i) {
4543 c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
4545 r = (int)(c * 32767.5);
4551 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4554 for (i = 0; i < sampleCount; ++i) {
4555 pOut[i] = drwav__alaw_to_s16(pIn[i]);
4559 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
4562 for (i = 0; i < sampleCount; ++i) {
4563 pOut[i] = drwav__mulaw_to_s16(pIn[i]);
4569 DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
4573 /* Special case for 8-bit sample data because it's treated as unsigned. */
4574 if (bytesPerSample == 1) {
4575 drwav_u8_to_f32(pOut, pIn, sampleCount);
4579 /* Slightly more optimal implementation for common formats. */
4580 if (bytesPerSample == 2) {
4581 drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount);
4584 if (bytesPerSample == 3) {
4585 drwav_s24_to_f32(pOut, pIn, sampleCount);
4588 if (bytesPerSample == 4) {
4589 drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
4594 /* Anything more than 64 bits per sample is not supported. */
4595 if (bytesPerSample > 8) {
4596 DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
4601 /* Generic, slow converter. */
4602 for (i = 0; i < sampleCount; ++i) {
4603 drwav_uint64 sample = 0;
4604 unsigned int shift = (8 - bytesPerSample) * 8;
4607 for (j = 0; j < bytesPerSample; j += 1) {
4608 DRWAV_ASSERT(j < 8);
4609 sample |= (drwav_uint64)(pIn[j]) << shift;
4614 *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
4618 DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
4620 if (bytesPerSample == 4) {
4622 for (i = 0; i < sampleCount; ++i) {
4623 *pOut++ = ((const float*)pIn)[i];
4626 } else if (bytesPerSample == 8) {
4627 drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount);
4630 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
4631 DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
4637 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4639 drwav_uint64 totalFramesRead;
4640 drwav_uint8 sampleData[4096];
4641 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4643 if (bytesPerFrame == 0) {
4647 totalFramesRead = 0;
4649 while (framesToRead > 0) {
4650 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4651 if (framesRead == 0) {
4655 drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels);
4657 pBufferOut += framesRead*pWav->channels;
4658 framesToRead -= framesRead;
4659 totalFramesRead += framesRead;
4662 return totalFramesRead;
4665 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4668 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
4669 want to duplicate that code.
4671 drwav_uint64 totalFramesRead = 0;
4672 drwav_int16 samples16[2048];
4674 while (framesToRead > 0) {
4675 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
4676 if (framesRead == 0) {
4680 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
4682 pBufferOut += framesRead*pWav->channels;
4683 framesToRead -= framesRead;
4684 totalFramesRead += framesRead;
4687 return totalFramesRead;
4690 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4693 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
4694 want to duplicate that code.
4696 drwav_uint64 totalFramesRead = 0;
4697 drwav_int16 samples16[2048];
4699 while (framesToRead > 0) {
4700 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
4701 if (framesRead == 0) {
4705 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
4707 pBufferOut += framesRead*pWav->channels;
4708 framesToRead -= framesRead;
4709 totalFramesRead += framesRead;
4712 return totalFramesRead;
4715 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4717 drwav_uint64 totalFramesRead;
4718 drwav_uint8 sampleData[4096];
4719 drwav_uint32 bytesPerFrame;
4722 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) {
4723 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
4726 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4727 if (bytesPerFrame == 0) {
4731 totalFramesRead = 0;
4733 while (framesToRead > 0) {
4734 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4735 if (framesRead == 0) {
4739 drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
4741 pBufferOut += framesRead*pWav->channels;
4742 framesToRead -= framesRead;
4743 totalFramesRead += framesRead;
4746 return totalFramesRead;
4749 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4751 drwav_uint64 totalFramesRead;
4752 drwav_uint8 sampleData[4096];
4753 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4755 if (bytesPerFrame == 0) {
4759 totalFramesRead = 0;
4761 while (framesToRead > 0) {
4762 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4763 if (framesRead == 0) {
4767 drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4769 pBufferOut += framesRead*pWav->channels;
4770 framesToRead -= framesRead;
4771 totalFramesRead += framesRead;
4774 return totalFramesRead;
4777 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4779 drwav_uint64 totalFramesRead;
4780 drwav_uint8 sampleData[4096];
4781 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
4783 if (bytesPerFrame == 0) {
4787 totalFramesRead = 0;
4789 while (framesToRead > 0) {
4790 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
4791 if (framesRead == 0) {
4795 drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
4797 pBufferOut += framesRead*pWav->channels;
4798 framesToRead -= framesRead;
4799 totalFramesRead += framesRead;
4802 return totalFramesRead;
4805 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4807 if (pWav == NULL || framesToRead == 0) {
4811 if (pBufferOut == NULL) {
4812 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
4815 /* Don't try to read more samples than can potentially fit in the output buffer. */
4816 if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) {
4817 framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels;
4820 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
4821 return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut);
4824 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
4825 return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut);
4828 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
4829 return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut);
4832 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
4833 return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut);
4836 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
4837 return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut);
4840 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
4841 return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut);
4847 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4849 drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
4850 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
4851 drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
4857 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
4859 drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
4860 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
4861 drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
4868 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4872 if (pOut == NULL || pIn == NULL) {
4876 #ifdef DR_WAV_LIBSNDFILE_COMPAT
4878 It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears
4879 libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note
4880 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
4881 correctness testing. This is disabled by default.
4883 for (i = 0; i < sampleCount; ++i) {
4884 *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
4887 for (i = 0; i < sampleCount; ++i) {
4889 x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */
4890 x = x - 1; /* 0..2 to -1..1 */
4897 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
4901 if (pOut == NULL || pIn == NULL) {
4905 for (i = 0; i < sampleCount; ++i) {
4906 *pOut++ = pIn[i] * 0.000030517578125f;
4910 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4914 if (pOut == NULL || pIn == NULL) {
4918 for (i = 0; i < sampleCount; ++i) {
4920 drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) << 8);
4921 drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16);
4922 drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24);
4924 x = (double)((drwav_int32)(a | b | c) >> 8);
4925 *pOut++ = (float)(x * 0.00000011920928955078125);
4929 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
4932 if (pOut == NULL || pIn == NULL) {
4936 for (i = 0; i < sampleCount; ++i) {
4937 *pOut++ = (float)(pIn[i] / 2147483648.0);
4941 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
4945 if (pOut == NULL || pIn == NULL) {
4949 for (i = 0; i < sampleCount; ++i) {
4950 *pOut++ = (float)pIn[i];
4954 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4958 if (pOut == NULL || pIn == NULL) {
4962 for (i = 0; i < sampleCount; ++i) {
4963 *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
4967 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
4971 if (pOut == NULL || pIn == NULL) {
4975 for (i = 0; i < sampleCount; ++i) {
4976 *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
4982 DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
4986 /* Special case for 8-bit sample data because it's treated as unsigned. */
4987 if (bytesPerSample == 1) {
4988 drwav_u8_to_s32(pOut, pIn, totalSampleCount);
4992 /* Slightly more optimal implementation for common formats. */
4993 if (bytesPerSample == 2) {
4994 drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount);
4997 if (bytesPerSample == 3) {
4998 drwav_s24_to_s32(pOut, pIn, totalSampleCount);
5001 if (bytesPerSample == 4) {
5002 for (i = 0; i < totalSampleCount; ++i) {
5003 *pOut++ = ((const drwav_int32*)pIn)[i];
5009 /* Anything more than 64 bits per sample is not supported. */
5010 if (bytesPerSample > 8) {
5011 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
5016 /* Generic, slow converter. */
5017 for (i = 0; i < totalSampleCount; ++i) {
5018 drwav_uint64 sample = 0;
5019 unsigned int shift = (8 - bytesPerSample) * 8;
5022 for (j = 0; j < bytesPerSample; j += 1) {
5023 DRWAV_ASSERT(j < 8);
5024 sample |= (drwav_uint64)(pIn[j]) << shift;
5029 *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
5033 DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
5035 if (bytesPerSample == 4) {
5036 drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount);
5038 } else if (bytesPerSample == 8) {
5039 drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount);
5042 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
5043 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
5049 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5051 drwav_uint64 totalFramesRead;
5052 drwav_uint8 sampleData[4096];
5053 drwav_uint32 bytesPerFrame;
5056 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) {
5057 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
5060 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5061 if (bytesPerFrame == 0) {
5065 totalFramesRead = 0;
5067 while (framesToRead > 0) {
5068 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
5069 if (framesRead == 0) {
5073 drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
5075 pBufferOut += framesRead*pWav->channels;
5076 framesToRead -= framesRead;
5077 totalFramesRead += framesRead;
5080 return totalFramesRead;
5083 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5086 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
5087 want to duplicate that code.
5089 drwav_uint64 totalFramesRead = 0;
5090 drwav_int16 samples16[2048];
5092 while (framesToRead > 0) {
5093 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
5094 if (framesRead == 0) {
5098 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
5100 pBufferOut += framesRead*pWav->channels;
5101 framesToRead -= framesRead;
5102 totalFramesRead += framesRead;
5105 return totalFramesRead;
5108 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5111 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
5112 want to duplicate that code.
5114 drwav_uint64 totalFramesRead = 0;
5115 drwav_int16 samples16[2048];
5117 while (framesToRead > 0) {
5118 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
5119 if (framesRead == 0) {
5123 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
5125 pBufferOut += framesRead*pWav->channels;
5126 framesToRead -= framesRead;
5127 totalFramesRead += framesRead;
5130 return totalFramesRead;
5133 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5135 drwav_uint64 totalFramesRead;
5136 drwav_uint8 sampleData[4096];
5137 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5139 if (bytesPerFrame == 0) {
5143 totalFramesRead = 0;
5145 while (framesToRead > 0) {
5146 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
5147 if (framesRead == 0) {
5151 drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
5153 pBufferOut += framesRead*pWav->channels;
5154 framesToRead -= framesRead;
5155 totalFramesRead += framesRead;
5158 return totalFramesRead;
5161 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5163 drwav_uint64 totalFramesRead;
5164 drwav_uint8 sampleData[4096];
5165 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5167 if (bytesPerFrame == 0) {
5171 totalFramesRead = 0;
5173 while (framesToRead > 0) {
5174 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
5175 if (framesRead == 0) {
5179 drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
5181 pBufferOut += framesRead*pWav->channels;
5182 framesToRead -= framesRead;
5183 totalFramesRead += framesRead;
5186 return totalFramesRead;
5189 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5191 drwav_uint64 totalFramesRead;
5192 drwav_uint8 sampleData[4096];
5193 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5195 if (bytesPerFrame == 0) {
5199 totalFramesRead = 0;
5201 while (framesToRead > 0) {
5202 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
5203 if (framesRead == 0) {
5207 drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
5209 pBufferOut += framesRead*pWav->channels;
5210 framesToRead -= framesRead;
5211 totalFramesRead += framesRead;
5214 return totalFramesRead;
5217 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5219 if (pWav == NULL || framesToRead == 0) {
5223 if (pBufferOut == NULL) {
5224 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
5227 /* Don't try to read more samples than can potentially fit in the output buffer. */
5228 if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) {
5229 framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels;
5232 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
5233 return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut);
5236 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
5237 return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut);
5240 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
5241 return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut);
5244 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
5245 return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut);
5248 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
5249 return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut);
5252 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
5253 return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut);
5259 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5261 drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
5262 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
5263 drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
5269 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
5271 drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
5272 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
5273 drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
5280 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5284 if (pOut == NULL || pIn == NULL) {
5288 for (i = 0; i < sampleCount; ++i) {
5289 *pOut++ = ((int)pIn[i] - 128) << 24;
5293 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
5297 if (pOut == NULL || pIn == NULL) {
5301 for (i = 0; i < sampleCount; ++i) {
5302 *pOut++ = pIn[i] << 16;
5306 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5310 if (pOut == NULL || pIn == NULL) {
5314 for (i = 0; i < sampleCount; ++i) {
5315 unsigned int s0 = pIn[i*3 + 0];
5316 unsigned int s1 = pIn[i*3 + 1];
5317 unsigned int s2 = pIn[i*3 + 2];
5319 drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
5324 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
5328 if (pOut == NULL || pIn == NULL) {
5332 for (i = 0; i < sampleCount; ++i) {
5333 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
5337 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
5341 if (pOut == NULL || pIn == NULL) {
5345 for (i = 0; i < sampleCount; ++i) {
5346 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
5350 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5354 if (pOut == NULL || pIn == NULL) {
5358 for (i = 0; i < sampleCount; ++i) {
5359 *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
5363 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
5367 if (pOut == NULL || pIn == NULL) {
5371 for (i= 0; i < sampleCount; ++i) {
5372 *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
5378 DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5380 drwav_uint64 sampleDataSize;
5381 drwav_int16* pSampleData;
5382 drwav_uint64 framesRead;
5384 DRWAV_ASSERT(pWav != NULL);
5386 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
5387 if (sampleDataSize > DRWAV_SIZE_MAX) {
5389 return NULL; /* File's too big. */
5392 pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5393 if (pSampleData == NULL) {
5395 return NULL; /* Failed to allocate memory. */
5398 framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5399 if (framesRead != pWav->totalPCMFrameCount) {
5400 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5402 return NULL; /* There was an error reading the samples. */
5408 *sampleRate = pWav->sampleRate;
5411 *channels = pWav->channels;
5413 if (totalFrameCount) {
5414 *totalFrameCount = pWav->totalPCMFrameCount;
5420 DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5422 drwav_uint64 sampleDataSize;
5424 drwav_uint64 framesRead;
5426 DRWAV_ASSERT(pWav != NULL);
5428 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
5429 if (sampleDataSize > DRWAV_SIZE_MAX) {
5431 return NULL; /* File's too big. */
5434 pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5435 if (pSampleData == NULL) {
5437 return NULL; /* Failed to allocate memory. */
5440 framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5441 if (framesRead != pWav->totalPCMFrameCount) {
5442 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5444 return NULL; /* There was an error reading the samples. */
5450 *sampleRate = pWav->sampleRate;
5453 *channels = pWav->channels;
5455 if (totalFrameCount) {
5456 *totalFrameCount = pWav->totalPCMFrameCount;
5462 DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
5464 drwav_uint64 sampleDataSize;
5465 drwav_int32* pSampleData;
5466 drwav_uint64 framesRead;
5468 DRWAV_ASSERT(pWav != NULL);
5470 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
5471 if (sampleDataSize > DRWAV_SIZE_MAX) {
5473 return NULL; /* File's too big. */
5476 pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
5477 if (pSampleData == NULL) {
5479 return NULL; /* Failed to allocate memory. */
5482 framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
5483 if (framesRead != pWav->totalPCMFrameCount) {
5484 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
5486 return NULL; /* There was an error reading the samples. */
5492 *sampleRate = pWav->sampleRate;
5495 *channels = pWav->channels;
5497 if (totalFrameCount) {
5498 *totalFrameCount = pWav->totalPCMFrameCount;
5506 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)
5513 if (sampleRateOut) {
5516 if (totalFrameCountOut) {
5517 *totalFrameCountOut = 0;
5520 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5524 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5527 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)
5534 if (sampleRateOut) {
5537 if (totalFrameCountOut) {
5538 *totalFrameCountOut = 0;
5541 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5545 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5548 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)
5555 if (sampleRateOut) {
5558 if (totalFrameCountOut) {
5559 *totalFrameCountOut = 0;
5562 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
5566 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5569 #ifndef DR_WAV_NO_STDIO
5570 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)
5577 if (sampleRateOut) {
5580 if (totalFrameCountOut) {
5581 *totalFrameCountOut = 0;
5584 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5588 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5591 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)
5598 if (sampleRateOut) {
5601 if (totalFrameCountOut) {
5602 *totalFrameCountOut = 0;
5605 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5609 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5612 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)
5619 if (sampleRateOut) {
5622 if (totalFrameCountOut) {
5623 *totalFrameCountOut = 0;
5626 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
5630 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5634 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)
5638 if (sampleRateOut) {
5644 if (totalFrameCountOut) {
5645 *totalFrameCountOut = 0;
5648 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5652 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5655 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)
5659 if (sampleRateOut) {
5665 if (totalFrameCountOut) {
5666 *totalFrameCountOut = 0;
5669 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5673 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5676 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)
5680 if (sampleRateOut) {
5686 if (totalFrameCountOut) {
5687 *totalFrameCountOut = 0;
5690 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
5694 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5698 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)
5705 if (sampleRateOut) {
5708 if (totalFrameCountOut) {
5709 *totalFrameCountOut = 0;
5712 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5716 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5719 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)
5726 if (sampleRateOut) {
5729 if (totalFrameCountOut) {
5730 *totalFrameCountOut = 0;
5733 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5737 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5740 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)
5747 if (sampleRateOut) {
5750 if (totalFrameCountOut) {
5751 *totalFrameCountOut = 0;
5754 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
5758 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
5760 #endif /* DR_WAV_NO_CONVERSION_API */
5763 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
5765 if (pAllocationCallbacks != NULL) {
5766 drwav__free_from_callbacks(p, pAllocationCallbacks);
5768 drwav__free_default(p, NULL);
5772 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data)
5774 return (data[0] << 0) | (data[1] << 8);
5777 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data)
5779 return (short)drwav_bytes_to_u16(data);
5782 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data)
5784 return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
5787 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data)
5789 return (drwav_int32)drwav_bytes_to_u32(data);
5792 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data)
5795 ((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
5796 ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
5799 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data)
5801 return (drwav_int64)drwav_bytes_to_u64(data);
5805 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
5808 for (i = 0; i < 16; i += 1) {
5817 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
5826 #endif /* dr_wav_c */
5827 #endif /* DR_WAV_IMPLEMENTATION */
5830 RELEASE NOTES - v0.11.0
5831 =======================
5832 Version 0.11.0 has breaking API changes.
5834 Improved Client-Defined Memory Allocation
5835 -----------------------------------------
5836 The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
5837 existing system of DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE are still in place and will be used by default when no custom
5838 allocation callbacks are specified.
5840 To use the new system, you pass in a pointer to a drwav_allocation_callbacks object to drwav_init() and family, like this:
5842 void* my_malloc(size_t sz, void* pUserData)
5846 void* my_realloc(void* p, size_t sz, void* pUserData)
5848 return realloc(p, sz);
5850 void my_free(void* p, void* pUserData)
5857 drwav_allocation_callbacks allocationCallbacks;
5858 allocationCallbacks.pUserData = &myData;
5859 allocationCallbacks.onMalloc = my_malloc;
5860 allocationCallbacks.onRealloc = my_realloc;
5861 allocationCallbacks.onFree = my_free;
5862 drwav_init_file(&wav, "my_file.wav", &allocationCallbacks);
5864 The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
5866 Passing in null for the allocation callbacks object will cause dr_wav to use defaults which is the same as DRWAV_MALLOC,
5867 DRWAV_REALLOC and DRWAV_FREE and the equivalent of how it worked in previous versions.
5869 Every API that opens a drwav object now takes this extra parameter. These include the following:
5874 drwav_init_file_ex()
5876 drwav_init_file_w_ex()
5878 drwav_init_memory_ex()
5880 drwav_init_write_sequential()
5881 drwav_init_write_sequential_pcm_frames()
5882 drwav_init_file_write()
5883 drwav_init_file_write_sequential()
5884 drwav_init_file_write_sequential_pcm_frames()
5885 drwav_init_file_write_w()
5886 drwav_init_file_write_sequential_w()
5887 drwav_init_file_write_sequential_pcm_frames_w()
5888 drwav_init_memory_write()
5889 drwav_init_memory_write_sequential()
5890 drwav_init_memory_write_sequential_pcm_frames()
5891 drwav_open_and_read_pcm_frames_s16()
5892 drwav_open_and_read_pcm_frames_f32()
5893 drwav_open_and_read_pcm_frames_s32()
5894 drwav_open_file_and_read_pcm_frames_s16()
5895 drwav_open_file_and_read_pcm_frames_f32()
5896 drwav_open_file_and_read_pcm_frames_s32()
5897 drwav_open_file_and_read_pcm_frames_s16_w()
5898 drwav_open_file_and_read_pcm_frames_f32_w()
5899 drwav_open_file_and_read_pcm_frames_s32_w()
5900 drwav_open_memory_and_read_pcm_frames_s16()
5901 drwav_open_memory_and_read_pcm_frames_f32()
5902 drwav_open_memory_and_read_pcm_frames_s32()
5906 Previously, the following APIs returned little-endian audio data. These now return native-endian data. This improves compatibility
5907 on big-endian architectures.
5909 drwav_read_pcm_frames()
5910 drwav_read_pcm_frames_s16()
5911 drwav_read_pcm_frames_s32()
5912 drwav_read_pcm_frames_f32()
5913 drwav_open_and_read_pcm_frames_s16()
5914 drwav_open_and_read_pcm_frames_s32()
5915 drwav_open_and_read_pcm_frames_f32()
5916 drwav_open_file_and_read_pcm_frames_s16()
5917 drwav_open_file_and_read_pcm_frames_s32()
5918 drwav_open_file_and_read_pcm_frames_f32()
5919 drwav_open_file_and_read_pcm_frames_s16_w()
5920 drwav_open_file_and_read_pcm_frames_s32_w()
5921 drwav_open_file_and_read_pcm_frames_f32_w()
5922 drwav_open_memory_and_read_pcm_frames_s16()
5923 drwav_open_memory_and_read_pcm_frames_s32()
5924 drwav_open_memory_and_read_pcm_frames_f32()
5926 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
5929 drwav_read_pcm_frames_le()
5930 drwav_read_pcm_frames_be()
5931 drwav_read_pcm_frames_s16le()
5932 drwav_read_pcm_frames_s16be()
5933 drwav_read_pcm_frames_f32le()
5934 drwav_read_pcm_frames_f32be()
5935 drwav_read_pcm_frames_s32le()
5936 drwav_read_pcm_frames_s32be()
5937 drwav_write_pcm_frames_le()
5938 drwav_write_pcm_frames_be()
5942 The following APIs were deprecated in version 0.10.0 and have now been removed:
5947 drwav_open_write_sequential()
5949 drwav_open_file_ex()
5950 drwav_open_file_write()
5951 drwav_open_file_write_sequential()
5953 drwav_open_memory_ex()
5954 drwav_open_memory_write()
5955 drwav_open_memory_write_sequential()
5960 RELEASE NOTES - v0.10.0
5961 =======================
5962 Version 0.10.0 has breaking API changes. There are no significant bug fixes in this release, so if you are affected you do
5963 not need to upgrade.
5967 The following APIs were deprecated in version 0.9.0 and have been completely removed in version 0.10.0:
5973 drwav_seek_to_sample()
5975 drwav_open_and_read_s16()
5976 drwav_open_and_read_f32()
5977 drwav_open_and_read_s32()
5978 drwav_open_file_and_read_s16()
5979 drwav_open_file_and_read_f32()
5980 drwav_open_file_and_read_s32()
5981 drwav_open_memory_and_read_s16()
5982 drwav_open_memory_and_read_f32()
5983 drwav_open_memory_and_read_s32()
5984 drwav::totalSampleCount
5986 See release notes for version 0.9.0 at the bottom of this file for replacement APIs.
5990 The following APIs have been deprecated. There is a confusing and completely arbitrary difference between drwav_init*() and
5991 drwav_open*(), where drwav_init*() initializes a pre-allocated drwav object, whereas drwav_open*() will first allocated a
5992 drwav object on the heap and then initialize it. drwav_open*() has been deprecated which means you must now use a pre-
5993 allocated drwav object with drwav_init*(). If you need the previous functionality, you can just do a malloc() followed by
5994 a called to one of the drwav_init*() APIs.
5999 drwav_open_write_sequential()
6001 drwav_open_file_ex()
6002 drwav_open_file_write()
6003 drwav_open_file_write_sequential()
6005 drwav_open_memory_ex()
6006 drwav_open_memory_write()
6007 drwav_open_memory_write_sequential()
6010 These APIs will be removed completely in a future version. The rationale for this change is to remove confusion between the
6011 two different ways to initialize a drwav object.
6017 v0.12.19 - 2021-02-21
6018 - Fix a warning due to referencing _MSC_VER when it is undefined.
6019 - Minor improvements to the management of some internal state concerning the data chunk cursor.
6021 v0.12.18 - 2021-01-31
6022 - Clean up some static analysis warnings.
6024 v0.12.17 - 2021-01-17
6025 - Minor fix to sample code in documentation.
6026 - Correctly qualify a private API as private rather than public.
6029 v0.12.16 - 2020-12-02
6030 - Fix a bug when trying to read more bytes than can fit in a size_t.
6032 v0.12.15 - 2020-11-21
6033 - Fix compilation with OpenWatcom.
6035 v0.12.14 - 2020-11-13
6036 - Minor code clean up.
6038 v0.12.13 - 2020-11-01
6039 - Improve compiler support for older versions of GCC.
6041 v0.12.12 - 2020-09-28
6042 - Add support for RF64.
6043 - Fix a bug in writing mode where the size of the RIFF chunk incorrectly includes the header section.
6045 v0.12.11 - 2020-09-08
6046 - Fix a compilation error on older compilers.
6048 v0.12.10 - 2020-08-24
6049 - Fix a bug when seeking with ADPCM formats.
6051 v0.12.9 - 2020-08-02
6052 - Simplify sized types.
6054 v0.12.8 - 2020-07-25
6055 - Fix a compilation warning.
6057 v0.12.7 - 2020-07-15
6058 - Fix some bugs on big-endian architectures.
6059 - Fix an error in s24 to f32 conversion.
6061 v0.12.6 - 2020-06-23
6062 - Change drwav_read_*() to allow NULL to be passed in as the output buffer which is equivalent to a forward seek.
6063 - Fix a buffer overflow when trying to decode invalid IMA-ADPCM files.
6064 - Add include guard for the implementation section.
6066 v0.12.5 - 2020-05-27
6067 - Minor documentation fix.
6069 v0.12.4 - 2020-05-16
6070 - Replace assert() with DRWAV_ASSERT().
6071 - Add compile-time and run-time version querying.
6072 - DRWAV_VERSION_MINOR
6073 - DRWAV_VERSION_MAJOR
6074 - DRWAV_VERSION_REVISION
6075 - DRWAV_VERSION_STRING
6077 - drwav_version_string()
6079 v0.12.3 - 2020-04-30
6080 - Fix compilation errors with VC6.
6082 v0.12.2 - 2020-04-21
6083 - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file.
6085 v0.12.1 - 2020-04-13
6086 - Fix some pedantic warnings.
6088 v0.12.0 - 2020-04-04
6089 - API CHANGE: Add container and format parameters to the chunk callback.
6090 - Minor documentation updates.
6092 v0.11.5 - 2020-03-07
6093 - Fix compilation error with Visual Studio .NET 2003.
6095 v0.11.4 - 2020-01-29
6096 - Fix some static analysis warnings.
6097 - Fix a bug when reading f32 samples from an A-law encoded stream.
6099 v0.11.3 - 2020-01-12
6100 - Minor changes to some f32 format conversion routines.
6101 - Minor bug fix for ADPCM conversion when end of file is reached.
6103 v0.11.2 - 2019-12-02
6104 - Fix a possible crash when using custom memory allocators without a custom realloc() implementation.
6105 - Fix an integer overflow bug.
6106 - Fix a null pointer dereference bug.
6107 - Add limits to sample rate, channels and bits per sample to tighten up some validation.
6109 v0.11.1 - 2019-10-07
6110 - Internal code clean up.
6112 v0.11.0 - 2019-10-06
6113 - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
6114 routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
6118 - drwav_init_file_ex()
6119 - drwav_init_file_w()
6120 - drwav_init_file_w_ex()
6121 - drwav_init_memory()
6122 - drwav_init_memory_ex()
6123 - drwav_init_write()
6124 - drwav_init_write_sequential()
6125 - drwav_init_write_sequential_pcm_frames()
6126 - drwav_init_file_write()
6127 - drwav_init_file_write_sequential()
6128 - drwav_init_file_write_sequential_pcm_frames()
6129 - drwav_init_file_write_w()
6130 - drwav_init_file_write_sequential_w()
6131 - drwav_init_file_write_sequential_pcm_frames_w()
6132 - drwav_init_memory_write()
6133 - drwav_init_memory_write_sequential()
6134 - drwav_init_memory_write_sequential_pcm_frames()
6135 - drwav_open_and_read_pcm_frames_s16()
6136 - drwav_open_and_read_pcm_frames_f32()
6137 - drwav_open_and_read_pcm_frames_s32()
6138 - drwav_open_file_and_read_pcm_frames_s16()
6139 - drwav_open_file_and_read_pcm_frames_f32()
6140 - drwav_open_file_and_read_pcm_frames_s32()
6141 - drwav_open_file_and_read_pcm_frames_s16_w()
6142 - drwav_open_file_and_read_pcm_frames_f32_w()
6143 - drwav_open_file_and_read_pcm_frames_s32_w()
6144 - drwav_open_memory_and_read_pcm_frames_s16()
6145 - drwav_open_memory_and_read_pcm_frames_f32()
6146 - drwav_open_memory_and_read_pcm_frames_s32()
6147 Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use
6148 DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE.
6149 - Add support for reading and writing PCM frames in an explicit endianness. New APIs:
6150 - drwav_read_pcm_frames_le()
6151 - drwav_read_pcm_frames_be()
6152 - drwav_read_pcm_frames_s16le()
6153 - drwav_read_pcm_frames_s16be()
6154 - drwav_read_pcm_frames_f32le()
6155 - drwav_read_pcm_frames_f32be()
6156 - drwav_read_pcm_frames_s32le()
6157 - drwav_read_pcm_frames_s32be()
6158 - drwav_write_pcm_frames_le()
6159 - drwav_write_pcm_frames_be()
6160 - Remove deprecated APIs.
6161 - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data.
6162 - drwav_read_pcm_frames()
6163 - drwav_read_pcm_frames_s16()
6164 - drwav_read_pcm_frames_s32()
6165 - drwav_read_pcm_frames_f32()
6166 - drwav_open_and_read_pcm_frames_s16()
6167 - drwav_open_and_read_pcm_frames_s32()
6168 - drwav_open_and_read_pcm_frames_f32()
6169 - drwav_open_file_and_read_pcm_frames_s16()
6170 - drwav_open_file_and_read_pcm_frames_s32()
6171 - drwav_open_file_and_read_pcm_frames_f32()
6172 - drwav_open_file_and_read_pcm_frames_s16_w()
6173 - drwav_open_file_and_read_pcm_frames_s32_w()
6174 - drwav_open_file_and_read_pcm_frames_f32_w()
6175 - drwav_open_memory_and_read_pcm_frames_s16()
6176 - drwav_open_memory_and_read_pcm_frames_s32()
6177 - drwav_open_memory_and_read_pcm_frames_f32()
6179 v0.10.1 - 2019-08-31
6180 - Correctly handle partial trailing ADPCM blocks.
6182 v0.10.0 - 2019-08-04
6183 - Remove deprecated APIs.
6184 - Add wchar_t variants for file loading APIs:
6186 drwav_init_file_ex_w()
6187 drwav_init_file_write_w()
6188 drwav_init_file_write_sequential_w()
6189 - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count.
6190 - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode:
6191 drwav_init_write_sequential_pcm_frames()
6192 drwav_init_file_write_sequential_pcm_frames()
6193 drwav_init_file_write_sequential_pcm_frames_w()
6194 drwav_init_memory_write_sequential_pcm_frames()
6195 - Deprecate drwav_open*() and drwav_close():
6199 drwav_open_write_sequential()
6201 drwav_open_file_ex()
6202 drwav_open_file_write()
6203 drwav_open_file_write_sequential()
6205 drwav_open_memory_ex()
6206 drwav_open_memory_write()
6207 drwav_open_memory_write_sequential()
6209 - Minor documentation updates.
6215 - Add support for C89.
6216 - Change license to choice of public domain or MIT-0.
6219 - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and
6220 will be removed in v0.10.0. Deprecated APIs and their replacements:
6221 drwav_read() -> drwav_read_pcm_frames()
6222 drwav_read_s16() -> drwav_read_pcm_frames_s16()
6223 drwav_read_f32() -> drwav_read_pcm_frames_f32()
6224 drwav_read_s32() -> drwav_read_pcm_frames_s32()
6225 drwav_seek_to_sample() -> drwav_seek_to_pcm_frame()
6226 drwav_write() -> drwav_write_pcm_frames()
6227 drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16()
6228 drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32()
6229 drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32()
6230 drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16()
6231 drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32()
6232 drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32()
6233 drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16()
6234 drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32()
6235 drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32()
6236 drwav::totalSampleCount -> drwav::totalPCMFrameCount
6237 - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*().
6238 - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*().
6239 - Add built-in support for smpl chunks.
6240 - Add support for firing a callback for each chunk in the file at initialization time.
6241 - This is enabled through the drwav_init_ex(), etc. family of APIs.
6242 - Handle invalid FMT chunks more robustly.
6245 - Const correctness.
6246 - Fix a potential stack overflow.
6249 - Improve 64-bit detection.
6252 - Fix C++ build on older versions of GCC.
6255 - Fix some big-endian bugs.
6258 - Add support for sequential writing APIs.
6259 - Disable seeking in write mode.
6260 - Fix bugs with Wave64.
6265 - Start using major.minor.revision versioning.
6268 - Restrict ADPCM formats to a maximum of 2 channels.
6277 - Set drwav.bytesPerSample to 0 for all compressed formats.
6278 - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for
6279 all format conversion reading APIs (*_s16, *_s32, *_f32 APIs).
6280 - Fix some divide-by-zero errors.
6283 - Fix errors with seeking of compressed formats.
6284 - Fix compilation error when DR_WAV_NO_CONVERSION_API
6287 - Fix some GCC warnings.
6293 - API CHANGE: Rename dr_* types to drwav_*.
6294 - Add support for custom implementations of malloc(), realloc(), etc.
6295 - Add support for Microsoft ADPCM.
6296 - Add support for IMA ADPCM (DVI, format code 0x11).
6297 - Optimizations to drwav_read_s16().
6301 - Change underlying type for booleans to unsigned.
6304 - Fix a minor bug with drwav_open_and_read_s16() and family.
6307 - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this.
6308 - Minor fixes to documentation.
6311 - Use drwav_int* and drwav_uint* sized types to improve compiler support.
6314 - Properly handle JUNK chunks that come before the FMT chunk.
6317 - A minor change to drwav_bool8 and drwav_bool32 types.
6320 - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering.
6321 - Improve A-law and mu-law efficiency.
6324 - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to
6325 keep it consistent with dr_audio and dr_flac.
6328 - Fixed a typo in documentation.
6332 - Change date format to ISO 8601 (YYYY-MM-DD)
6335 - API CHANGE. Make onSeek consistent with dr_flac.
6336 - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac.
6337 - Added support for Sony Wave64.
6340 - API CHANGE. Return drwav_bool32 instead of int in onSeek callback.
6341 - Fixed a memory leak.
6344 - Lots of API changes for consistency.
6347 - Fixed Linux/GCC build.
6350 - Added support for reading data as signed 32-bit PCM for consistency with dr_flac.
6353 - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize.
6356 - Initial versioned release.
6360 This software is available as a choice of the following licenses. Choose
6361 whichever you prefer.
6363 ===============================================================================
6364 ALTERNATIVE 1 - Public Domain (www.unlicense.org)
6365 ===============================================================================
6366 This is free and unencumbered software released into the public domain.
6368 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
6369 software, either in source code form or as a compiled binary, for any purpose,
6370 commercial or non-commercial, and by any means.
6372 In jurisdictions that recognize copyright laws, the author or authors of this
6373 software dedicate any and all copyright interest in the software to the public
6374 domain. We make this dedication for the benefit of the public at large and to
6375 the detriment of our heirs and successors. We intend this dedication to be an
6376 overt act of relinquishment in perpetuity of all present and future rights to
6377 this software under copyright law.
6379 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6380 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6381 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6382 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
6383 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
6384 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6386 For more information, please refer to <http://unlicense.org/>
6388 ===============================================================================
6389 ALTERNATIVE 2 - MIT No Attribution
6390 ===============================================================================
6391 Copyright 2020 David Reid
6393 Permission is hereby granted, free of charge, to any person obtaining a copy of
6394 this software and associated documentation files (the "Software"), to deal in
6395 the Software without restriction, including without limitation the rights to
6396 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
6397 of the Software, and to permit persons to whom the Software is furnished to do
6400 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6401 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6402 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6403 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6404 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6405 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE