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