DOSBox-X
|
00001 /* 00002 WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. 00003 dr_wav - v0.12.4 - 2020-05-16 00004 00005 David Reid - mackron@gmail.com 00006 00007 GitHub: https://github.com/mackron/dr_libs 00008 */ 00009 00010 /* 00011 RELEASE NOTES - VERSION 0.12 00012 ============================ 00013 Version 0.12 includes breaking changes to custom chunk handling. 00014 00015 00016 Changes to Chunk Callback 00017 ------------------------- 00018 dr_wav supports the ability to fire a callback when a chunk is encounted (except for WAVE and FMT chunks). The callback has been update to include both the 00019 container (RIFF or Wave64) and the FMT chunk which contains information about the format of the data in the wave file. 00020 00021 Previously, there was no direct way to determine the container, and therefore no way discriminate against the different IDs in the chunk header (RIFF and 00022 Wave64 containers encode chunk ID's differently). The `container` parameter can be used to know which ID to use. 00023 00024 Sometimes it can be useful to know the data format at the time the chunk callback is fired. A pointer to a `drwav_fmt` object is now passed into the chunk 00025 callback which will give you information about the data format. To determine the sample format, use `drwav_fmt_get_format()`. This will return one of the 00026 `DR_WAVE_FORMAT_*` tokens. 00027 */ 00028 00029 /* 00030 Introduction 00031 ============ 00032 This is a single file library. To use it, do something like the following in one .c file. 00033 00034 ```c 00035 #define DR_WAV_IMPLEMENTATION 00036 #include "dr_wav.h" 00037 ``` 00038 00039 You can then #include this file in other parts of the program as you would with any other header file. Do something like the following to read audio data: 00040 00041 ```c 00042 drwav wav; 00043 if (!drwav_init_file(&wav, "my_song.wav", NULL)) { 00044 // Error opening WAV file. 00045 } 00046 00047 drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32)); 00048 size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames); 00049 00050 ... 00051 00052 drwav_uninit(&wav); 00053 ``` 00054 00055 If you just want to quickly open and read the audio data in a single operation you can do something like this: 00056 00057 ```c 00058 unsigned int channels; 00059 unsigned int sampleRate; 00060 drwav_uint64 totalPCMFrameCount; 00061 float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount, NULL); 00062 if (pSampleData == NULL) { 00063 // Error opening and reading WAV file. 00064 } 00065 00066 ... 00067 00068 drwav_free(pSampleData); 00069 ``` 00070 00071 The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in this case), but you can still output the 00072 audio data in its internal format (see notes below for supported formats): 00073 00074 ```c 00075 size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames); 00076 ``` 00077 00078 You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for a particular data format: 00079 00080 ```c 00081 size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer); 00082 ``` 00083 00084 dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at `drwav_init_write()`, 00085 `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. 00086 00087 ```c 00088 drwav_data_format format; 00089 format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. 00090 format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. 00091 format.channels = 2; 00092 format.sampleRate = 44100; 00093 format.bitsPerSample = 16; 00094 drwav_init_file_write(&wav, "data/recording.wav", &format, NULL); 00095 00096 ... 00097 00098 drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples); 00099 ``` 00100 00101 dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work without any manual intervention. 00102 00103 00104 Build Options 00105 ============= 00106 #define these options before including this file. 00107 00108 #define DR_WAV_NO_CONVERSION_API 00109 Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`. 00110 00111 #define DR_WAV_NO_STDIO 00112 Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc. 00113 00114 00115 00116 Notes 00117 ===== 00118 - Samples are always interleaved. 00119 - 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()` 00120 to read and convert audio data to 32-bit floating point, signed 32-bit integer and signed 16-bit integer samples respectively. Tested and supported internal 00121 formats include the following: 00122 - Unsigned 8-bit PCM 00123 - Signed 12-bit PCM 00124 - Signed 16-bit PCM 00125 - Signed 24-bit PCM 00126 - Signed 32-bit PCM 00127 - IEEE 32-bit floating point 00128 - IEEE 64-bit floating point 00129 - A-law and u-law 00130 - Microsoft ADPCM 00131 - IMA ADPCM (DVI, format code 0x11) 00132 - dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format. 00133 */ 00134 00135 #ifndef dr_wav_h 00136 #define dr_wav_h 00137 00138 #ifdef __cplusplus 00139 extern "C" { 00140 #endif 00141 00142 #define DRWAV_STRINGIFY(x) #x 00143 #define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) 00144 00145 #define DRWAV_VERSION_MAJOR 0 00146 #define DRWAV_VERSION_MINOR 12 00147 #define DRWAV_VERSION_REVISION 4 00148 #define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) 00149 00150 #include <stddef.h> /* For size_t. */ 00151 00152 /* Sized types. Prefer built-in types. Fall back to stdint. */ 00153 #ifdef _MSC_VER 00154 #if defined(__clang__) 00155 #pragma GCC diagnostic push 00156 #pragma GCC diagnostic ignored "-Wlanguage-extension-token" 00157 #pragma GCC diagnostic ignored "-Wlong-long" 00158 #pragma GCC diagnostic ignored "-Wc++11-long-long" 00159 #endif 00160 typedef signed __int8 drwav_int8; 00161 typedef unsigned __int8 drwav_uint8; 00162 typedef signed __int16 drwav_int16; 00163 typedef unsigned __int16 drwav_uint16; 00164 typedef signed __int32 drwav_int32; 00165 typedef unsigned __int32 drwav_uint32; 00166 typedef signed __int64 drwav_int64; 00167 typedef unsigned __int64 drwav_uint64; 00168 #if defined(__clang__) 00169 #pragma GCC diagnostic pop 00170 #endif 00171 #else 00172 #include <stdint.h> 00173 typedef int8_t drwav_int8; 00174 typedef uint8_t drwav_uint8; 00175 typedef int16_t drwav_int16; 00176 typedef uint16_t drwav_uint16; 00177 typedef int32_t drwav_int32; 00178 typedef uint32_t drwav_uint32; 00179 typedef int64_t drwav_int64; 00180 typedef uint64_t drwav_uint64; 00181 #endif 00182 typedef drwav_uint8 drwav_bool8; 00183 typedef drwav_uint32 drwav_bool32; 00184 #define DRWAV_TRUE 1 00185 #define DRWAV_FALSE 0 00186 00187 #if !defined(DRWAV_API) 00188 #if defined(DRWAV_DLL) 00189 #if defined(_WIN32) 00190 #define DRWAV_DLL_IMPORT __declspec(dllimport) 00191 #define DRWAV_DLL_EXPORT __declspec(dllexport) 00192 #define DRWAV_DLL_PRIVATE static 00193 #else 00194 #if defined(__GNUC__) && __GNUC__ >= 4 00195 #define DRWAV_DLL_IMPORT __attribute__((visibility("default"))) 00196 #define DRWAV_DLL_EXPORT __attribute__((visibility("default"))) 00197 #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden"))) 00198 #else 00199 #define DRWAV_DLL_IMPORT 00200 #define DRWAV_DLL_EXPORT 00201 #define DRWAV_DLL_PRIVATE static 00202 #endif 00203 #endif 00204 00205 #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION) 00206 #define DRWAV_API DRWAV_DLL_EXPORT 00207 #else 00208 #define DRWAV_API DRWAV_DLL_IMPORT 00209 #endif 00210 #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE 00211 #else 00212 #define DRWAV_API extern 00213 #define DRWAV_PRIVATE static 00214 #endif 00215 #endif 00216 00217 typedef drwav_int32 drwav_result; 00218 #define DRWAV_SUCCESS 0 00219 #define DRWAV_ERROR -1 /* A generic error. */ 00220 #define DRWAV_INVALID_ARGS -2 00221 #define DRWAV_INVALID_OPERATION -3 00222 #define DRWAV_OUT_OF_MEMORY -4 00223 #define DRWAV_OUT_OF_RANGE -5 00224 #define DRWAV_ACCESS_DENIED -6 00225 #define DRWAV_DOES_NOT_EXIST -7 00226 #define DRWAV_ALREADY_EXISTS -8 00227 #define DRWAV_TOO_MANY_OPEN_FILES -9 00228 #define DRWAV_INVALID_FILE -10 00229 #define DRWAV_TOO_BIG -11 00230 #define DRWAV_PATH_TOO_LONG -12 00231 #define DRWAV_NAME_TOO_LONG -13 00232 #define DRWAV_NOT_DIRECTORY -14 00233 #define DRWAV_IS_DIRECTORY -15 00234 #define DRWAV_DIRECTORY_NOT_EMPTY -16 00235 #define DRWAV_END_OF_FILE -17 00236 #define DRWAV_NO_SPACE -18 00237 #define DRWAV_BUSY -19 00238 #define DRWAV_IO_ERROR -20 00239 #define DRWAV_INTERRUPT -21 00240 #define DRWAV_UNAVAILABLE -22 00241 #define DRWAV_ALREADY_IN_USE -23 00242 #define DRWAV_BAD_ADDRESS -24 00243 #define DRWAV_BAD_SEEK -25 00244 #define DRWAV_BAD_PIPE -26 00245 #define DRWAV_DEADLOCK -27 00246 #define DRWAV_TOO_MANY_LINKS -28 00247 #define DRWAV_NOT_IMPLEMENTED -29 00248 #define DRWAV_NO_MESSAGE -30 00249 #define DRWAV_BAD_MESSAGE -31 00250 #define DRWAV_NO_DATA_AVAILABLE -32 00251 #define DRWAV_INVALID_DATA -33 00252 #define DRWAV_TIMEOUT -34 00253 #define DRWAV_NO_NETWORK -35 00254 #define DRWAV_NOT_UNIQUE -36 00255 #define DRWAV_NOT_SOCKET -37 00256 #define DRWAV_NO_ADDRESS -38 00257 #define DRWAV_BAD_PROTOCOL -39 00258 #define DRWAV_PROTOCOL_UNAVAILABLE -40 00259 #define DRWAV_PROTOCOL_NOT_SUPPORTED -41 00260 #define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42 00261 #define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED -43 00262 #define DRWAV_SOCKET_NOT_SUPPORTED -44 00263 #define DRWAV_CONNECTION_RESET -45 00264 #define DRWAV_ALREADY_CONNECTED -46 00265 #define DRWAV_NOT_CONNECTED -47 00266 #define DRWAV_CONNECTION_REFUSED -48 00267 #define DRWAV_NO_HOST -49 00268 #define DRWAV_IN_PROGRESS -50 00269 #define DRWAV_CANCELLED -51 00270 #define DRWAV_MEMORY_ALREADY_MAPPED -52 00271 #define DRWAV_AT_END -53 00272 00273 /* Common data formats. */ 00274 #define DR_WAVE_FORMAT_PCM 0x1 00275 #define DR_WAVE_FORMAT_ADPCM 0x2 00276 #define DR_WAVE_FORMAT_IEEE_FLOAT 0x3 00277 #define DR_WAVE_FORMAT_ALAW 0x6 00278 #define DR_WAVE_FORMAT_MULAW 0x7 00279 #define DR_WAVE_FORMAT_DVI_ADPCM 0x11 00280 #define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE 00281 00282 /* Constants. */ 00283 #ifndef DRWAV_MAX_SMPL_LOOPS 00284 #define DRWAV_MAX_SMPL_LOOPS 1 00285 #endif 00286 00287 /* Flags to pass into drwav_init_ex(), etc. */ 00288 #define DRWAV_SEQUENTIAL 0x00000001 00289 00290 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision); 00291 DRWAV_API const char* drwav_version_string(); 00292 00293 typedef enum 00294 { 00295 drwav_seek_origin_start, 00296 drwav_seek_origin_current 00297 } drwav_seek_origin; 00298 00299 typedef enum 00300 { 00301 drwav_container_riff, 00302 drwav_container_w64 00303 } drwav_container; 00304 00305 typedef struct 00306 { 00307 union 00308 { 00309 drwav_uint8 fourcc[4]; 00310 drwav_uint8 guid[16]; 00311 } id; 00312 00313 /* The size in bytes of the chunk. */ 00314 drwav_uint64 sizeInBytes; 00315 00316 /* 00317 RIFF = 2 byte alignment. 00318 W64 = 8 byte alignment. 00319 */ 00320 unsigned int paddingSize; 00321 } drwav_chunk_header; 00322 00323 typedef struct 00324 { 00325 /* 00326 The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications 00327 that require support for data formats not natively supported by dr_wav. 00328 */ 00329 drwav_uint16 formatTag; 00330 00331 /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */ 00332 drwav_uint16 channels; 00333 00334 /* The sample rate. Usually set to something like 44100. */ 00335 drwav_uint32 sampleRate; 00336 00337 /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */ 00338 drwav_uint32 avgBytesPerSec; 00339 00340 /* Block align. This is equal to the number of channels * bytes per sample. */ 00341 drwav_uint16 blockAlign; 00342 00343 /* Bits per sample. */ 00344 drwav_uint16 bitsPerSample; 00345 00346 /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */ 00347 drwav_uint16 extendedSize; 00348 00349 /* 00350 The number of valid bits per sample. When <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample> 00351 is always rounded up to the nearest multiple of 8. This variable contains information about exactly how 00352 many bits are valid per sample. Mainly used for informational purposes. 00353 */ 00354 drwav_uint16 validBitsPerSample; 00355 00356 /* The channel mask. Not used at the moment. */ 00357 drwav_uint32 channelMask; 00358 00359 /* The sub-format, exactly as specified by the wave file. */ 00360 drwav_uint8 subFormat[16]; 00361 } drwav_fmt; 00362 00363 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT); 00364 00365 00366 /* 00367 Callback for when data is read. Return value is the number of bytes actually read. 00368 00369 pUserData [in] The user data that was passed to drwav_init() and family. 00370 pBufferOut [out] The output buffer. 00371 bytesToRead [in] The number of bytes to read. 00372 00373 Returns the number of bytes actually read. 00374 00375 A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until 00376 either the entire bytesToRead is filled or you have reached the end of the stream. 00377 */ 00378 typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); 00379 00380 /* 00381 Callback for when data is written. Returns value is the number of bytes actually written. 00382 00383 pUserData [in] The user data that was passed to drwav_init_write() and family. 00384 pData [out] A pointer to the data to write. 00385 bytesToWrite [in] The number of bytes to write. 00386 00387 Returns the number of bytes actually written. 00388 00389 If the return value differs from bytesToWrite, it indicates an error. 00390 */ 00391 typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); 00392 00393 /* 00394 Callback for when data needs to be seeked. 00395 00396 pUserData [in] The user data that was passed to drwav_init() and family. 00397 offset [in] The number of bytes to move, relative to the origin. Will never be negative. 00398 origin [in] The origin of the seek - the current position or the start of the stream. 00399 00400 Returns whether or not the seek was successful. 00401 00402 Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either drwav_seek_origin_start or 00403 drwav_seek_origin_current. 00404 */ 00405 typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin); 00406 00407 /* 00408 Callback for when drwav_init_ex() finds a chunk. 00409 00410 pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family. 00411 onRead [in] A pointer to the function to call when reading. 00412 onSeek [in] A pointer to the function to call when seeking. 00413 pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family. 00414 pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk. 00415 container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF. 00416 pFMT [in] A pointer to the object containing the contents of the "fmt" chunk. 00417 00418 Returns the number of bytes read + seeked. 00419 00420 To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same for seeking with onSeek(). The return value must 00421 be the total number of bytes you have read _plus_ seeked. 00422 00423 Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` you should use `id.fourcc`, 00424 otherwise you should use `id.guid`. 00425 00426 The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the 00427 `DR_WAVE_FORMAT_*` identifiers. 00428 00429 The read pointer will be sitting on the first byte after the chunk's header. You must not attempt to read beyond the boundary of the chunk. 00430 */ 00431 typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT); 00432 00433 typedef struct 00434 { 00435 void* pUserData; 00436 void* (* onMalloc)(size_t sz, void* pUserData); 00437 void* (* onRealloc)(void* p, size_t sz, void* pUserData); 00438 void (* onFree)(void* p, void* pUserData); 00439 } drwav_allocation_callbacks; 00440 00441 /* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */ 00442 typedef struct 00443 { 00444 const drwav_uint8* data; 00445 size_t dataSize; 00446 size_t currentReadPos; 00447 } drwav__memory_stream; 00448 00449 /* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */ 00450 typedef struct 00451 { 00452 void** ppData; 00453 size_t* pDataSize; 00454 size_t dataSize; 00455 size_t dataCapacity; 00456 size_t currentWritePos; 00457 } drwav__memory_stream_write; 00458 00459 typedef struct 00460 { 00461 drwav_container container; /* RIFF, W64. */ 00462 drwav_uint32 format; /* DR_WAVE_FORMAT_* */ 00463 drwav_uint32 channels; 00464 drwav_uint32 sampleRate; 00465 drwav_uint32 bitsPerSample; 00466 } drwav_data_format; 00467 00468 00469 /* See the following for details on the 'smpl' chunk: https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl */ 00470 typedef struct 00471 { 00472 drwav_uint32 cuePointId; 00473 drwav_uint32 type; 00474 drwav_uint32 start; 00475 drwav_uint32 end; 00476 drwav_uint32 fraction; 00477 drwav_uint32 playCount; 00478 } drwav_smpl_loop; 00479 00480 typedef struct 00481 { 00482 drwav_uint32 manufacturer; 00483 drwav_uint32 product; 00484 drwav_uint32 samplePeriod; 00485 drwav_uint32 midiUnityNotes; 00486 drwav_uint32 midiPitchFraction; 00487 drwav_uint32 smpteFormat; 00488 drwav_uint32 smpteOffset; 00489 drwav_uint32 numSampleLoops; 00490 drwav_uint32 samplerData; 00491 drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS]; 00492 } drwav_smpl; 00493 00494 typedef struct 00495 { 00496 /* A pointer to the function to call when more data is needed. */ 00497 drwav_read_proc onRead; 00498 00499 /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */ 00500 drwav_write_proc onWrite; 00501 00502 /* A pointer to the function to call when the wav file needs to be seeked. */ 00503 drwav_seek_proc onSeek; 00504 00505 /* The user data to pass to callbacks. */ 00506 void* pUserData; 00507 00508 /* Allocation callbacks. */ 00509 drwav_allocation_callbacks allocationCallbacks; 00510 00511 00512 /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */ 00513 drwav_container container; 00514 00515 00516 /* Structure containing format information exactly as specified by the wav file. */ 00517 drwav_fmt fmt; 00518 00519 /* The sample rate. Will be set to something like 44100. */ 00520 drwav_uint32 sampleRate; 00521 00522 /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */ 00523 drwav_uint16 channels; 00524 00525 /* The bits per sample. Will be set to something like 16, 24, etc. */ 00526 drwav_uint16 bitsPerSample; 00527 00528 /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */ 00529 drwav_uint16 translatedFormatTag; 00530 00531 /* The total number of PCM frames making up the audio data. */ 00532 drwav_uint64 totalPCMFrameCount; 00533 00534 00535 /* The size in bytes of the data chunk. */ 00536 drwav_uint64 dataChunkDataSize; 00537 00538 /* The position in the stream of the first byte of the data chunk. This is used for seeking. */ 00539 drwav_uint64 dataChunkDataPos; 00540 00541 /* The number of bytes remaining in the data chunk. */ 00542 drwav_uint64 bytesRemaining; 00543 00544 00545 /* 00546 Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always 00547 set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation. 00548 */ 00549 drwav_uint64 dataChunkDataSizeTargetWrite; 00550 00551 /* Keeps track of whether or not the wav writer was initialized in sequential mode. */ 00552 drwav_bool32 isSequentialWrite; 00553 00554 00555 /* smpl chunk. */ 00556 drwav_smpl smpl; 00557 00558 00559 /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */ 00560 drwav__memory_stream memoryStream; 00561 drwav__memory_stream_write memoryStreamWrite; 00562 00563 /* Generic data for compressed formats. This data is shared across all block-compressed formats. */ 00564 struct 00565 { 00566 drwav_uint64 iCurrentPCMFrame; /* The index of the next PCM frame that will be read by drwav_read_*(). This is used with "totalPCMFrameCount" to ensure we don't read excess samples at the end of the last block. */ 00567 } compressed; 00568 00569 /* Microsoft ADPCM specific data. */ 00570 struct 00571 { 00572 drwav_uint32 bytesRemainingInBlock; 00573 drwav_uint16 predictor[2]; 00574 drwav_int32 delta[2]; 00575 drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */ 00576 drwav_uint32 cachedFrameCount; 00577 drwav_int32 prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */ 00578 } msadpcm; 00579 00580 /* IMA ADPCM specific data. */ 00581 struct 00582 { 00583 drwav_uint32 bytesRemainingInBlock; 00584 drwav_int32 predictor[2]; 00585 drwav_int32 stepIndex[2]; 00586 drwav_int32 cachedFrames[16]; /* Samples are stored in this cache during decoding. */ 00587 drwav_uint32 cachedFrameCount; 00588 } ima; 00589 } drwav; 00590 00591 00592 /* 00593 Initializes a pre-allocated drwav object for reading. 00594 00595 pWav [out] A pointer to the drwav object being initialized. 00596 onRead [in] The function to call when data needs to be read from the client. 00597 onSeek [in] The function to call when the read position of the client data needs to move. 00598 onChunk [in, optional] The function to call when a chunk is enumerated at initialized time. 00599 pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. 00600 pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk. 00601 flags [in, optional] A set of flags for controlling how things are loaded. 00602 00603 Returns true if successful; false otherwise. 00604 00605 Close the loader with drwav_uninit(). 00606 00607 This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() 00608 to open the stream from a file or from a block of memory respectively. 00609 00610 Possible values for flags: 00611 DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function 00612 to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored. 00613 00614 drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);". 00615 00616 The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt 00617 after the function returns. 00618 00619 See also: drwav_init_file(), drwav_init_memory(), drwav_uninit() 00620 */ 00621 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); 00622 DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); 00623 00624 /* 00625 Initializes a pre-allocated drwav object for writing. 00626 00627 onWrite [in] The function to call when data needs to be written. 00628 onSeek [in] The function to call when the write position needs to move. 00629 pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. 00630 00631 Returns true if successful; false otherwise. 00632 00633 Close the writer with drwav_uninit(). 00634 00635 This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write() 00636 to open the stream from a file or from a block of memory respectively. 00637 00638 If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform 00639 a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek. 00640 00641 See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit() 00642 */ 00643 DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); 00644 DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); 00645 DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); 00646 00647 /* 00648 Utility function to determine the target size of the entire data to be written (including all headers and chunks). 00649 00650 Returns the target size in bytes. 00651 00652 Useful if the application needs to know the size to allocate. 00653 00654 Only writing to the RIFF chunk and one data chunk is currently supported. 00655 00656 See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write() 00657 */ 00658 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); 00659 00660 /* 00661 Uninitializes the given drwav object. 00662 00663 Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()). 00664 */ 00665 DRWAV_API drwav_result drwav_uninit(drwav* pWav); 00666 00667 00668 /* 00669 Reads raw audio data. 00670 00671 This is the lowest level function for reading audio data. It simply reads the given number of 00672 bytes of the raw internal sample data. 00673 00674 Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for 00675 reading sample data in a consistent format. 00676 00677 Returns the number of bytes actually read. 00678 */ 00679 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut); 00680 00681 /* 00682 Reads up to the specified number of PCM frames from the WAV file. 00683 00684 The output data will be in the file's internal format, converted to native-endian byte order. Use 00685 drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format. 00686 00687 If the return value is less than <framesToRead> it means the end of the file has been reached or 00688 you have requested more PCM frames than can possibly fit in the output buffer. 00689 00690 This function will only work when sample data is of a fixed size and uncompressed. If you are 00691 using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32(). 00692 */ 00693 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); 00694 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); 00695 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); 00696 00697 /* 00698 Seeks to the given PCM frame. 00699 00700 Returns true if successful; false otherwise. 00701 */ 00702 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex); 00703 00704 00705 /* 00706 Writes raw audio data. 00707 00708 Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error. 00709 */ 00710 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData); 00711 00712 /* 00713 Writes PCM frames. 00714 00715 Returns the number of PCM frames written. 00716 00717 Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to 00718 little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion. 00719 */ 00720 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); 00721 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); 00722 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); 00723 00724 00725 /* Conversion Utilities */ 00726 #ifndef DR_WAV_NO_CONVERSION_API 00727 00728 /* 00729 Reads a chunk of audio data and converts it to signed 16-bit PCM samples. 00730 00731 Returns the number of PCM frames actually read. 00732 00733 If the return value is less than <framesToRead> it means the end of the file has been reached. 00734 */ 00735 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); 00736 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); 00737 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); 00738 00739 /* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */ 00740 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); 00741 00742 /* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */ 00743 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); 00744 00745 /* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */ 00746 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount); 00747 00748 /* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */ 00749 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount); 00750 00751 /* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */ 00752 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount); 00753 00754 /* Low-level function for converting A-law samples to signed 16-bit PCM samples. */ 00755 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); 00756 00757 /* Low-level function for converting u-law samples to signed 16-bit PCM samples. */ 00758 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); 00759 00760 00761 /* 00762 Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples. 00763 00764 Returns the number of PCM frames actually read. 00765 00766 If the return value is less than <framesToRead> it means the end of the file has been reached. 00767 */ 00768 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); 00769 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); 00770 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); 00771 00772 /* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */ 00773 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); 00774 00775 /* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */ 00776 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount); 00777 00778 /* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */ 00779 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); 00780 00781 /* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */ 00782 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount); 00783 00784 /* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */ 00785 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); 00786 00787 /* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */ 00788 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); 00789 00790 /* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */ 00791 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); 00792 00793 00794 /* 00795 Reads a chunk of audio data and converts it to signed 32-bit PCM samples. 00796 00797 Returns the number of PCM frames actually read. 00798 00799 If the return value is less than <framesToRead> it means the end of the file has been reached. 00800 */ 00801 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); 00802 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); 00803 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); 00804 00805 /* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */ 00806 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); 00807 00808 /* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */ 00809 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount); 00810 00811 /* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */ 00812 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); 00813 00814 /* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */ 00815 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount); 00816 00817 /* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */ 00818 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount); 00819 00820 /* Low-level function for converting A-law samples to signed 32-bit PCM samples. */ 00821 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); 00822 00823 /* Low-level function for converting u-law samples to signed 32-bit PCM samples. */ 00824 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); 00825 00826 #endif /* DR_WAV_NO_CONVERSION_API */ 00827 00828 00829 /* High-Level Convenience Helpers */ 00830 00831 #ifndef DR_WAV_NO_STDIO 00832 /* 00833 Helper for initializing a wave file for reading using stdio. 00834 00835 This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav 00836 objects because the operating system may restrict the number of file handles an application can have open at 00837 any given time. 00838 */ 00839 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks); 00840 DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); 00841 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks); 00842 DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); 00843 00844 /* 00845 Helper for initializing a wave file for writing using stdio. 00846 00847 This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav 00848 objects because the operating system may restrict the number of file handles an application can have open at 00849 any given time. 00850 */ 00851 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); 00852 DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); 00853 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); 00854 DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); 00855 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); 00856 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); 00857 #endif /* DR_WAV_NO_STDIO */ 00858 00859 /* 00860 Helper for initializing a loader from a pre-allocated memory buffer. 00861 00862 This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for 00863 the lifetime of the drwav object. 00864 00865 The buffer should contain the contents of the entire wave file, not just the sample data. 00866 */ 00867 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks); 00868 DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); 00869 00870 /* 00871 Helper for initializing a writer which outputs data to a memory buffer. 00872 00873 dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). 00874 00875 The buffer will remain allocated even after drwav_uninit() is called. Indeed, the buffer should not be 00876 considered valid until after drwav_uninit() has been called anyway. 00877 */ 00878 DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); 00879 DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); 00880 DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); 00881 00882 00883 #ifndef DR_WAV_NO_CONVERSION_API 00884 /* 00885 Opens and reads an entire wav file in a single operation. 00886 00887 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. 00888 */ 00889 DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00890 DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00891 DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00892 #ifndef DR_WAV_NO_STDIO 00893 /* 00894 Opens and decodes an entire wav file in a single operation. 00895 00896 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. 00897 */ 00898 DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00899 DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00900 DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00901 DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00902 DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00903 DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00904 #endif 00905 /* 00906 Opens and decodes an entire wav file from a block of memory in a single operation. 00907 00908 The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. 00909 */ 00910 DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00911 DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00912 DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); 00913 #endif 00914 00915 /* Frees data that was allocated internally by dr_wav. */ 00916 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks); 00917 00918 /* Converts bytes from a wav stream to a sized type of native endian. */ 00919 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data); 00920 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data); 00921 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data); 00922 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data); 00923 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data); 00924 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data); 00925 00926 /* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */ 00927 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]); 00928 00929 /* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */ 00930 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); 00931 00932 #ifdef __cplusplus 00933 } 00934 #endif 00935 #endif /* dr_wav_h */ 00936 00937 00938 /************************************************************************************************************************************************************ 00939 ************************************************************************************************************************************************************ 00940 00941 IMPLEMENTATION 00942 00943 ************************************************************************************************************************************************************ 00944 ************************************************************************************************************************************************************/ 00945 #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION) 00946 #include <stdlib.h> 00947 #include <string.h> /* For memcpy(), memset() */ 00948 #include <limits.h> /* For INT_MAX */ 00949 00950 #ifndef DR_WAV_NO_STDIO 00951 #include <stdio.h> 00952 #include <wchar.h> 00953 #endif 00954 00955 /* Standard library stuff. */ 00956 #ifndef DRWAV_ASSERT 00957 #include <assert.h> 00958 #define DRWAV_ASSERT(expression) assert(expression) 00959 #endif 00960 #ifndef DRWAV_MALLOC 00961 #define DRWAV_MALLOC(sz) malloc((sz)) 00962 #endif 00963 #ifndef DRWAV_REALLOC 00964 #define DRWAV_REALLOC(p, sz) realloc((p), (sz)) 00965 #endif 00966 #ifndef DRWAV_FREE 00967 #define DRWAV_FREE(p) free((p)) 00968 #endif 00969 #ifndef DRWAV_COPY_MEMORY 00970 #define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) 00971 #endif 00972 #ifndef DRWAV_ZERO_MEMORY 00973 #define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) 00974 #endif 00975 #ifndef DRWAV_ZERO_OBJECT 00976 #define DRWAV_ZERO_OBJECT(p) DRWAV_ZERO_MEMORY((p), sizeof(*p)) 00977 #endif 00978 00979 #define drwav_countof(x) (sizeof(x) / sizeof(x[0])) 00980 #define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) 00981 #define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) 00982 #define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) 00983 #define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) 00984 00985 #define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ 00986 00987 /* CPU architecture. */ 00988 #if defined(__x86_64__) || defined(_M_X64) 00989 #define DRWAV_X64 00990 #elif defined(__i386) || defined(_M_IX86) 00991 #define DRWAV_X86 00992 #elif defined(__arm__) || defined(_M_ARM) 00993 #define DRWAV_ARM 00994 #endif 00995 00996 #ifdef _MSC_VER 00997 #define DRWAV_INLINE __forceinline 00998 #elif defined(__GNUC__) 00999 /* 01000 I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when 01001 the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some 01002 case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the 01003 command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue 01004 I am using "__inline__" only when we're compiling in strict ANSI mode. 01005 */ 01006 #if defined(__STRICT_ANSI__) 01007 #define DRWAV_INLINE __inline__ __attribute__((always_inline)) 01008 #else 01009 #define DRWAV_INLINE inline __attribute__((always_inline)) 01010 #endif 01011 #else 01012 #define DRWAV_INLINE 01013 #endif 01014 01015 #if defined(SIZE_MAX) 01016 #define DRWAV_SIZE_MAX SIZE_MAX 01017 #else 01018 #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) 01019 #define DRWAV_SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF) 01020 #else 01021 #define DRWAV_SIZE_MAX 0xFFFFFFFF 01022 #endif 01023 #endif 01024 01025 #if defined(_MSC_VER) && _MSC_VER >= 1400 01026 #define DRWAV_HAS_BYTESWAP16_INTRINSIC 01027 #define DRWAV_HAS_BYTESWAP32_INTRINSIC 01028 #define DRWAV_HAS_BYTESWAP64_INTRINSIC 01029 #elif defined(__clang__) 01030 #if defined(__has_builtin) 01031 #if __has_builtin(__builtin_bswap16) 01032 #define DRWAV_HAS_BYTESWAP16_INTRINSIC 01033 #endif 01034 #if __has_builtin(__builtin_bswap32) 01035 #define DRWAV_HAS_BYTESWAP32_INTRINSIC 01036 #endif 01037 #if __has_builtin(__builtin_bswap64) 01038 #define DRWAV_HAS_BYTESWAP64_INTRINSIC 01039 #endif 01040 #endif 01041 #elif defined(__GNUC__) 01042 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) 01043 #define DRWAV_HAS_BYTESWAP32_INTRINSIC 01044 #define DRWAV_HAS_BYTESWAP64_INTRINSIC 01045 #endif 01046 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) 01047 #define DRWAV_HAS_BYTESWAP16_INTRINSIC 01048 #endif 01049 #endif 01050 01051 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision) 01052 { 01053 if (pMajor) { 01054 *pMajor = DRWAV_VERSION_MAJOR; 01055 } 01056 01057 if (pMinor) { 01058 *pMinor = DRWAV_VERSION_MINOR; 01059 } 01060 01061 if (pRevision) { 01062 *pRevision = DRWAV_VERSION_REVISION; 01063 } 01064 } 01065 01066 DRWAV_API const char* drwav_version_string() 01067 { 01068 return DRWAV_VERSION_STRING; 01069 } 01070 01071 /* 01072 These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are 01073 you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation. 01074 */ 01075 #ifndef DRWAV_MAX_SAMPLE_RATE 01076 #define DRWAV_MAX_SAMPLE_RATE 384000 01077 #endif 01078 #ifndef DRWAV_MAX_CHANNELS 01079 #define DRWAV_MAX_CHANNELS 256 01080 #endif 01081 #ifndef DRWAV_MAX_BITS_PER_SAMPLE 01082 #define DRWAV_MAX_BITS_PER_SAMPLE 64 01083 #endif 01084 01085 static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; /* 66666972-912E-11CF-A5D6-28DB04C10000 */ 01086 static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */ 01087 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 */ 01088 static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */ 01089 static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 74636166-ACF3-11D3-8CD1-00C04F8EDB8A */ 01090 static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */ 01091 static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A */ 01092 01093 static DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) 01094 { 01095 int i; 01096 for (i = 0; i < 16; i += 1) { 01097 if (a[i] != b[i]) { 01098 return DRWAV_FALSE; 01099 } 01100 } 01101 01102 return DRWAV_TRUE; 01103 } 01104 01105 static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const drwav_uint8* a, const char* b) 01106 { 01107 return 01108 a[0] == b[0] && 01109 a[1] == b[1] && 01110 a[2] == b[2] && 01111 a[3] == b[3]; 01112 } 01113 01114 01115 01116 static DRWAV_INLINE int drwav__is_little_endian(void) 01117 { 01118 #if defined(DRWAV_X86) || defined(DRWAV_X64) 01119 return DRWAV_TRUE; 01120 #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN 01121 return DRWAV_TRUE; 01122 #else 01123 int n = 1; 01124 return (*(char*)&n) == 1; 01125 #endif 01126 } 01127 01128 static DRWAV_INLINE drwav_uint16 drwav__bytes_to_u16(const drwav_uint8* data) 01129 { 01130 return (data[0] << 0) | (data[1] << 8); 01131 } 01132 01133 static DRWAV_INLINE drwav_int16 drwav__bytes_to_s16(const drwav_uint8* data) 01134 { 01135 return (short)drwav__bytes_to_u16(data); 01136 } 01137 01138 static DRWAV_INLINE drwav_uint32 drwav__bytes_to_u32(const drwav_uint8* data) 01139 { 01140 return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); 01141 } 01142 01143 static DRWAV_INLINE drwav_int32 drwav__bytes_to_s32(const drwav_uint8* data) 01144 { 01145 return (drwav_int32)drwav__bytes_to_u32(data); 01146 } 01147 01148 static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const drwav_uint8* data) 01149 { 01150 return 01151 ((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) | 01152 ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56); 01153 } 01154 01155 static DRWAV_INLINE drwav_int64 drwav__bytes_to_s64(const drwav_uint8* data) 01156 { 01157 return (drwav_int64)drwav__bytes_to_u64(data); 01158 } 01159 01160 static DRWAV_INLINE void drwav__bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid) 01161 { 01162 int i; 01163 for (i = 0; i < 16; ++i) { 01164 guid[i] = data[i]; 01165 } 01166 } 01167 01168 01169 static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n) 01170 { 01171 #ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC 01172 #if defined(_MSC_VER) 01173 return _byteswap_ushort(n); 01174 #elif defined(__GNUC__) || defined(__clang__) 01175 return __builtin_bswap16(n); 01176 #else 01177 #error "This compiler does not support the byte swap intrinsic." 01178 #endif 01179 #else 01180 return ((n & 0xFF00) >> 8) | 01181 ((n & 0x00FF) << 8); 01182 #endif 01183 } 01184 01185 static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n) 01186 { 01187 #ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC 01188 #if defined(_MSC_VER) 01189 return _byteswap_ulong(n); 01190 #elif defined(__GNUC__) || defined(__clang__) 01191 #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. */ 01192 /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */ 01193 drwav_uint32 r; 01194 __asm__ __volatile__ ( 01195 #if defined(DRWAV_64BIT) 01196 "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! */ 01197 #else 01198 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) 01199 #endif 01200 ); 01201 return r; 01202 #else 01203 return __builtin_bswap32(n); 01204 #endif 01205 #else 01206 #error "This compiler does not support the byte swap intrinsic." 01207 #endif 01208 #else 01209 return ((n & 0xFF000000) >> 24) | 01210 ((n & 0x00FF0000) >> 8) | 01211 ((n & 0x0000FF00) << 8) | 01212 ((n & 0x000000FF) << 24); 01213 #endif 01214 } 01215 01216 static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n) 01217 { 01218 #ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC 01219 #if defined(_MSC_VER) 01220 return _byteswap_uint64(n); 01221 #elif defined(__GNUC__) || defined(__clang__) 01222 return __builtin_bswap64(n); 01223 #else 01224 #error "This compiler does not support the byte swap intrinsic." 01225 #endif 01226 #else 01227 return ((n & (drwav_uint64)0xFF00000000000000) >> 56) | 01228 ((n & (drwav_uint64)0x00FF000000000000) >> 40) | 01229 ((n & (drwav_uint64)0x0000FF0000000000) >> 24) | 01230 ((n & (drwav_uint64)0x000000FF00000000) >> 8) | 01231 ((n & (drwav_uint64)0x00000000FF000000) << 8) | 01232 ((n & (drwav_uint64)0x0000000000FF0000) << 24) | 01233 ((n & (drwav_uint64)0x000000000000FF00) << 40) | 01234 ((n & (drwav_uint64)0x00000000000000FF) << 56); 01235 #endif 01236 } 01237 01238 01239 static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n) 01240 { 01241 return (drwav_int16)drwav__bswap16((drwav_uint16)n); 01242 } 01243 01244 static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount) 01245 { 01246 drwav_uint64 iSample; 01247 for (iSample = 0; iSample < sampleCount; iSample += 1) { 01248 pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]); 01249 } 01250 } 01251 01252 01253 static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p) 01254 { 01255 drwav_uint8 t; 01256 t = p[0]; 01257 p[0] = p[2]; 01258 p[2] = t; 01259 } 01260 01261 static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount) 01262 { 01263 drwav_uint64 iSample; 01264 for (iSample = 0; iSample < sampleCount; iSample += 1) { 01265 drwav_uint8* pSample = pSamples + (iSample*3); 01266 drwav__bswap_s24(pSample); 01267 } 01268 } 01269 01270 01271 static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n) 01272 { 01273 return (drwav_int32)drwav__bswap32((drwav_uint32)n); 01274 } 01275 01276 static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount) 01277 { 01278 drwav_uint64 iSample; 01279 for (iSample = 0; iSample < sampleCount; iSample += 1) { 01280 pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]); 01281 } 01282 } 01283 01284 01285 static DRWAV_INLINE float drwav__bswap_f32(float n) 01286 { 01287 union { 01288 drwav_uint32 i; 01289 float f; 01290 } x; 01291 x.f = n; 01292 x.i = drwav__bswap32(x.i); 01293 01294 return x.f; 01295 } 01296 01297 static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount) 01298 { 01299 drwav_uint64 iSample; 01300 for (iSample = 0; iSample < sampleCount; iSample += 1) { 01301 pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]); 01302 } 01303 } 01304 01305 01306 static DRWAV_INLINE double drwav__bswap_f64(double n) 01307 { 01308 union { 01309 drwav_uint64 i; 01310 double f; 01311 } x; 01312 x.f = n; 01313 x.i = drwav__bswap64(x.i); 01314 01315 return x.f; 01316 } 01317 01318 static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount) 01319 { 01320 drwav_uint64 iSample; 01321 for (iSample = 0; iSample < sampleCount; iSample += 1) { 01322 pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]); 01323 } 01324 } 01325 01326 01327 static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) 01328 { 01329 /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */ 01330 switch (bytesPerSample) 01331 { 01332 case 2: /* s16, s12 (loosely packed) */ 01333 { 01334 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); 01335 } break; 01336 case 3: /* s24 */ 01337 { 01338 drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount); 01339 } break; 01340 case 4: /* s32 */ 01341 { 01342 drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount); 01343 } break; 01344 default: 01345 { 01346 /* Unsupported format. */ 01347 DRWAV_ASSERT(DRWAV_FALSE); 01348 } break; 01349 } 01350 } 01351 01352 static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) 01353 { 01354 switch (bytesPerSample) 01355 { 01356 #if 0 /* Contributions welcome for f16 support. */ 01357 case 2: /* f16 */ 01358 { 01359 drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount); 01360 } break; 01361 #endif 01362 case 4: /* f32 */ 01363 { 01364 drwav__bswap_samples_f32((float*)pSamples, sampleCount); 01365 } break; 01366 case 8: /* f64 */ 01367 { 01368 drwav__bswap_samples_f64((double*)pSamples, sampleCount); 01369 } break; 01370 default: 01371 { 01372 /* Unsupported format. */ 01373 DRWAV_ASSERT(DRWAV_FALSE); 01374 } break; 01375 } 01376 } 01377 01378 static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format) 01379 { 01380 switch (format) 01381 { 01382 case DR_WAVE_FORMAT_PCM: 01383 { 01384 drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample); 01385 } break; 01386 01387 case DR_WAVE_FORMAT_IEEE_FLOAT: 01388 { 01389 drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample); 01390 } break; 01391 01392 case DR_WAVE_FORMAT_ALAW: 01393 case DR_WAVE_FORMAT_MULAW: 01394 { 01395 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); 01396 } break; 01397 01398 case DR_WAVE_FORMAT_ADPCM: 01399 case DR_WAVE_FORMAT_DVI_ADPCM: 01400 default: 01401 { 01402 /* Unsupported format. */ 01403 DRWAV_ASSERT(DRWAV_FALSE); 01404 } break; 01405 } 01406 } 01407 01408 01409 static void* drwav__malloc_default(size_t sz, void* pUserData) 01410 { 01411 (void)pUserData; 01412 return DRWAV_MALLOC(sz); 01413 } 01414 01415 static void* drwav__realloc_default(void* p, size_t sz, void* pUserData) 01416 { 01417 (void)pUserData; 01418 return DRWAV_REALLOC(p, sz); 01419 } 01420 01421 static void drwav__free_default(void* p, void* pUserData) 01422 { 01423 (void)pUserData; 01424 DRWAV_FREE(p); 01425 } 01426 01427 01428 static void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks) 01429 { 01430 if (pAllocationCallbacks == NULL) { 01431 return NULL; 01432 } 01433 01434 if (pAllocationCallbacks->onMalloc != NULL) { 01435 return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); 01436 } 01437 01438 /* Try using realloc(). */ 01439 if (pAllocationCallbacks->onRealloc != NULL) { 01440 return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); 01441 } 01442 01443 return NULL; 01444 } 01445 01446 static void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks) 01447 { 01448 if (pAllocationCallbacks == NULL) { 01449 return NULL; 01450 } 01451 01452 if (pAllocationCallbacks->onRealloc != NULL) { 01453 return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData); 01454 } 01455 01456 /* Try emulating realloc() in terms of malloc()/free(). */ 01457 if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { 01458 void* p2; 01459 01460 p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); 01461 if (p2 == NULL) { 01462 return NULL; 01463 } 01464 01465 if (p != NULL) { 01466 DRWAV_COPY_MEMORY(p2, p, szOld); 01467 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); 01468 } 01469 01470 return p2; 01471 } 01472 01473 return NULL; 01474 } 01475 01476 static void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) 01477 { 01478 if (p == NULL || pAllocationCallbacks == NULL) { 01479 return; 01480 } 01481 01482 if (pAllocationCallbacks->onFree != NULL) { 01483 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); 01484 } 01485 } 01486 01487 01488 static drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks) 01489 { 01490 if (pAllocationCallbacks != NULL) { 01491 /* Copy. */ 01492 return *pAllocationCallbacks; 01493 } else { 01494 /* Defaults. */ 01495 drwav_allocation_callbacks allocationCallbacks; 01496 allocationCallbacks.pUserData = NULL; 01497 allocationCallbacks.onMalloc = drwav__malloc_default; 01498 allocationCallbacks.onRealloc = drwav__realloc_default; 01499 allocationCallbacks.onFree = drwav__free_default; 01500 return allocationCallbacks; 01501 } 01502 } 01503 01504 01505 static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag) 01506 { 01507 return 01508 formatTag == DR_WAVE_FORMAT_ADPCM || 01509 formatTag == DR_WAVE_FORMAT_DVI_ADPCM; 01510 } 01511 01512 static unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize) 01513 { 01514 return (unsigned int)(chunkSize % 2); 01515 } 01516 01517 static unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize) 01518 { 01519 return (unsigned int)(chunkSize % 8); 01520 } 01521 01522 static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); 01523 static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); 01524 static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); 01525 01526 static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut) 01527 { 01528 if (container == drwav_container_riff) { 01529 drwav_uint8 sizeInBytes[4]; 01530 01531 if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { 01532 return DRWAV_AT_END; 01533 } 01534 01535 if (onRead(pUserData, sizeInBytes, 4) != 4) { 01536 return DRWAV_INVALID_FILE; 01537 } 01538 01539 pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes); 01540 pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes); 01541 *pRunningBytesReadOut += 8; 01542 } else { 01543 drwav_uint8 sizeInBytes[8]; 01544 01545 if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { 01546 return DRWAV_AT_END; 01547 } 01548 01549 if (onRead(pUserData, sizeInBytes, 8) != 8) { 01550 return DRWAV_INVALID_FILE; 01551 } 01552 01553 pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */ 01554 pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes); 01555 *pRunningBytesReadOut += 24; 01556 } 01557 01558 return DRWAV_SUCCESS; 01559 } 01560 01561 static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) 01562 { 01563 drwav_uint64 bytesRemainingToSeek = offset; 01564 while (bytesRemainingToSeek > 0) { 01565 if (bytesRemainingToSeek > 0x7FFFFFFF) { 01566 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { 01567 return DRWAV_FALSE; 01568 } 01569 bytesRemainingToSeek -= 0x7FFFFFFF; 01570 } else { 01571 if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) { 01572 return DRWAV_FALSE; 01573 } 01574 bytesRemainingToSeek = 0; 01575 } 01576 } 01577 01578 return DRWAV_TRUE; 01579 } 01580 01581 static drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) 01582 { 01583 if (offset <= 0x7FFFFFFF) { 01584 return onSeek(pUserData, (int)offset, drwav_seek_origin_start); 01585 } 01586 01587 /* Larger than 32-bit seek. */ 01588 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) { 01589 return DRWAV_FALSE; 01590 } 01591 offset -= 0x7FFFFFFF; 01592 01593 for (;;) { 01594 if (offset <= 0x7FFFFFFF) { 01595 return onSeek(pUserData, (int)offset, drwav_seek_origin_current); 01596 } 01597 01598 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { 01599 return DRWAV_FALSE; 01600 } 01601 offset -= 0x7FFFFFFF; 01602 } 01603 01604 /* Should never get here. */ 01605 /*return DRWAV_TRUE; */ 01606 } 01607 01608 01609 static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut) 01610 { 01611 drwav_chunk_header header; 01612 drwav_uint8 fmt[16]; 01613 01614 if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { 01615 return DRWAV_FALSE; 01616 } 01617 01618 01619 /* Skip non-fmt chunks. */ 01620 while ((container == drwav_container_riff && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) { 01621 if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { 01622 return DRWAV_FALSE; 01623 } 01624 *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; 01625 01626 /* Try the next header. */ 01627 if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { 01628 return DRWAV_FALSE; 01629 } 01630 } 01631 01632 01633 /* Validation. */ 01634 if (container == drwav_container_riff) { 01635 if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) { 01636 return DRWAV_FALSE; 01637 } 01638 } else { 01639 if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) { 01640 return DRWAV_FALSE; 01641 } 01642 } 01643 01644 01645 if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) { 01646 return DRWAV_FALSE; 01647 } 01648 *pRunningBytesReadOut += sizeof(fmt); 01649 01650 fmtOut->formatTag = drwav__bytes_to_u16(fmt + 0); 01651 fmtOut->channels = drwav__bytes_to_u16(fmt + 2); 01652 fmtOut->sampleRate = drwav__bytes_to_u32(fmt + 4); 01653 fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8); 01654 fmtOut->blockAlign = drwav__bytes_to_u16(fmt + 12); 01655 fmtOut->bitsPerSample = drwav__bytes_to_u16(fmt + 14); 01656 01657 fmtOut->extendedSize = 0; 01658 fmtOut->validBitsPerSample = 0; 01659 fmtOut->channelMask = 0; 01660 memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat)); 01661 01662 if (header.sizeInBytes > 16) { 01663 drwav_uint8 fmt_cbSize[2]; 01664 int bytesReadSoFar = 0; 01665 01666 if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { 01667 return DRWAV_FALSE; /* Expecting more data. */ 01668 } 01669 *pRunningBytesReadOut += sizeof(fmt_cbSize); 01670 01671 bytesReadSoFar = 18; 01672 01673 fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize); 01674 if (fmtOut->extendedSize > 0) { 01675 /* Simple validation. */ 01676 if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { 01677 if (fmtOut->extendedSize != 22) { 01678 return DRWAV_FALSE; 01679 } 01680 } 01681 01682 if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { 01683 drwav_uint8 fmtext[22]; 01684 if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) { 01685 return DRWAV_FALSE; /* Expecting more data. */ 01686 } 01687 01688 fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0); 01689 fmtOut->channelMask = drwav__bytes_to_u32(fmtext + 2); 01690 drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat); 01691 } else { 01692 if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) { 01693 return DRWAV_FALSE; 01694 } 01695 } 01696 *pRunningBytesReadOut += fmtOut->extendedSize; 01697 01698 bytesReadSoFar += fmtOut->extendedSize; 01699 } 01700 01701 /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */ 01702 if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) { 01703 return DRWAV_FALSE; 01704 } 01705 *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar); 01706 } 01707 01708 if (header.paddingSize > 0) { 01709 if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) { 01710 return DRWAV_FALSE; 01711 } 01712 *pRunningBytesReadOut += header.paddingSize; 01713 } 01714 01715 return DRWAV_TRUE; 01716 } 01717 01718 01719 static size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor) 01720 { 01721 size_t bytesRead; 01722 01723 DRWAV_ASSERT(onRead != NULL); 01724 DRWAV_ASSERT(pCursor != NULL); 01725 01726 bytesRead = onRead(pUserData, pBufferOut, bytesToRead); 01727 *pCursor += bytesRead; 01728 return bytesRead; 01729 } 01730 01731 #if 0 01732 static drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor) 01733 { 01734 DRWAV_ASSERT(onSeek != NULL); 01735 DRWAV_ASSERT(pCursor != NULL); 01736 01737 if (!onSeek(pUserData, offset, origin)) { 01738 return DRWAV_FALSE; 01739 } 01740 01741 if (origin == drwav_seek_origin_start) { 01742 *pCursor = offset; 01743 } else { 01744 *pCursor += offset; 01745 } 01746 01747 return DRWAV_TRUE; 01748 } 01749 #endif 01750 01751 01752 01753 static drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) 01754 { 01755 /* 01756 The bytes per frame is a bit ambiguous. It can be either be based on the bits per sample, or the block align. The way I'm doing it here 01757 is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align. 01758 */ 01759 if ((pWav->bitsPerSample & 0x7) == 0) { 01760 /* Bits per sample is a multiple of 8. */ 01761 return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; 01762 } else { 01763 return pWav->fmt.blockAlign; 01764 } 01765 } 01766 01767 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) 01768 { 01769 if (pFMT == NULL) { 01770 return 0; 01771 } 01772 01773 if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) { 01774 return pFMT->formatTag; 01775 } else { 01776 return drwav__bytes_to_u16(pFMT->subFormat); /* Only the first two bytes are required. */ 01777 } 01778 } 01779 01780 static drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks) 01781 { 01782 if (pWav == NULL || onRead == NULL || onSeek == NULL) { 01783 return DRWAV_FALSE; 01784 } 01785 01786 DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); 01787 pWav->onRead = onRead; 01788 pWav->onSeek = onSeek; 01789 pWav->pUserData = pReadSeekUserData; 01790 pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); 01791 01792 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { 01793 return DRWAV_FALSE; /* Invalid allocation callbacks. */ 01794 } 01795 01796 return DRWAV_TRUE; 01797 } 01798 01799 static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) 01800 { 01801 /* This function assumes drwav_preinit() has been called beforehand. */ 01802 01803 drwav_uint64 cursor; /* <-- Keeps track of the byte position so we can seek to specific locations. */ 01804 drwav_bool32 sequential; 01805 drwav_uint8 riff[4]; 01806 drwav_fmt fmt; 01807 unsigned short translatedFormatTag; 01808 drwav_uint64 sampleCountFromFactChunk; 01809 drwav_bool32 foundDataChunk; 01810 drwav_uint64 dataChunkSize; 01811 drwav_uint64 chunkSize; 01812 01813 cursor = 0; 01814 sequential = (flags & DRWAV_SEQUENTIAL) != 0; 01815 01816 /* The first 4 bytes should be the RIFF identifier. */ 01817 if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) { 01818 return DRWAV_FALSE; 01819 } 01820 01821 /* 01822 The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for 01823 w64 it will start with "riff". 01824 */ 01825 if (drwav__fourcc_equal(riff, "RIFF")) { 01826 pWav->container = drwav_container_riff; 01827 } else if (drwav__fourcc_equal(riff, "riff")) { 01828 int i; 01829 drwav_uint8 riff2[12]; 01830 01831 pWav->container = drwav_container_w64; 01832 01833 /* Check the rest of the GUID for validity. */ 01834 if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) { 01835 return DRWAV_FALSE; 01836 } 01837 01838 for (i = 0; i < 12; ++i) { 01839 if (riff2[i] != drwavGUID_W64_RIFF[i+4]) { 01840 return DRWAV_FALSE; 01841 } 01842 } 01843 } else { 01844 return DRWAV_FALSE; /* Unknown or unsupported container. */ 01845 } 01846 01847 01848 if (pWav->container == drwav_container_riff) { 01849 drwav_uint8 chunkSizeBytes[4]; 01850 drwav_uint8 wave[4]; 01851 01852 /* RIFF/WAVE */ 01853 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { 01854 return DRWAV_FALSE; 01855 } 01856 01857 if (drwav__bytes_to_u32(chunkSizeBytes) < 36) { 01858 return DRWAV_FALSE; /* Chunk size should always be at least 36 bytes. */ 01859 } 01860 01861 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { 01862 return DRWAV_FALSE; 01863 } 01864 01865 if (!drwav__fourcc_equal(wave, "WAVE")) { 01866 return DRWAV_FALSE; /* Expecting "WAVE". */ 01867 } 01868 } else { 01869 drwav_uint8 chunkSizeBytes[8]; 01870 drwav_uint8 wave[16]; 01871 01872 /* W64 */ 01873 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { 01874 return DRWAV_FALSE; 01875 } 01876 01877 if (drwav__bytes_to_u64(chunkSizeBytes) < 80) { 01878 return DRWAV_FALSE; 01879 } 01880 01881 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { 01882 return DRWAV_FALSE; 01883 } 01884 01885 if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) { 01886 return DRWAV_FALSE; 01887 } 01888 } 01889 01890 01891 /* The next bytes should be the "fmt " chunk. */ 01892 if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) { 01893 return DRWAV_FALSE; /* Failed to read the "fmt " chunk. */ 01894 } 01895 01896 /* Basic validation. */ 01897 if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE) || 01898 (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS) || 01899 (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) || 01900 fmt.blockAlign == 0) { 01901 return DRWAV_FALSE; /* Probably an invalid WAV file. */ 01902 } 01903 01904 01905 /* Translate the internal format. */ 01906 translatedFormatTag = fmt.formatTag; 01907 if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { 01908 translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0); 01909 } 01910 01911 01912 01913 sampleCountFromFactChunk = 0; 01914 01915 /* 01916 We need to enumerate over each chunk for two reasons: 01917 1) The "data" chunk may not be the next one 01918 2) We may want to report each chunk back to the client 01919 01920 In order to correctly report each chunk back to the client we will need to keep looping until the end of the file. 01921 */ 01922 foundDataChunk = DRWAV_FALSE; 01923 dataChunkSize = 0; 01924 01925 /* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */ 01926 for (;;) 01927 { 01928 drwav_chunk_header header; 01929 drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); 01930 if (result != DRWAV_SUCCESS) { 01931 if (!foundDataChunk) { 01932 return DRWAV_FALSE; 01933 } else { 01934 break; /* Probably at the end of the file. Get out of the loop. */ 01935 } 01936 } 01937 01938 /* Tell the client about this chunk. */ 01939 if (!sequential && onChunk != NULL) { 01940 drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt); 01941 01942 /* 01943 dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before 01944 we called the callback. 01945 */ 01946 if (callbackBytesRead > 0) { 01947 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) { 01948 return DRWAV_FALSE; 01949 } 01950 } 01951 } 01952 01953 01954 if (!foundDataChunk) { 01955 pWav->dataChunkDataPos = cursor; 01956 } 01957 01958 chunkSize = header.sizeInBytes; 01959 if (pWav->container == drwav_container_riff) { 01960 if (drwav__fourcc_equal(header.id.fourcc, "data")) { 01961 foundDataChunk = DRWAV_TRUE; 01962 dataChunkSize = chunkSize; 01963 } 01964 } else { 01965 if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) { 01966 foundDataChunk = DRWAV_TRUE; 01967 dataChunkSize = chunkSize; 01968 } 01969 } 01970 01971 /* 01972 If at this point we have found the data chunk and we're running in sequential mode, we need to break out of this loop. The reason for 01973 this is that we would otherwise require a backwards seek which sequential mode forbids. 01974 */ 01975 if (foundDataChunk && sequential) { 01976 break; 01977 } 01978 01979 /* Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. */ 01980 if (pWav->container == drwav_container_riff) { 01981 if (drwav__fourcc_equal(header.id.fourcc, "fact")) { 01982 drwav_uint32 sampleCount; 01983 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) { 01984 return DRWAV_FALSE; 01985 } 01986 chunkSize -= 4; 01987 01988 if (!foundDataChunk) { 01989 pWav->dataChunkDataPos = cursor; 01990 } 01991 01992 /* 01993 The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this 01994 for Microsoft ADPCM formats. 01995 */ 01996 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { 01997 sampleCountFromFactChunk = sampleCount; 01998 } else { 01999 sampleCountFromFactChunk = 0; 02000 } 02001 } 02002 } else { 02003 if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) { 02004 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) { 02005 return DRWAV_FALSE; 02006 } 02007 chunkSize -= 8; 02008 02009 if (!foundDataChunk) { 02010 pWav->dataChunkDataPos = cursor; 02011 } 02012 } 02013 } 02014 02015 /* "smpl" chunk. */ 02016 if (pWav->container == drwav_container_riff) { 02017 if (drwav__fourcc_equal(header.id.fourcc, "smpl")) { 02018 drwav_uint8 smplHeaderData[36]; /* 36 = size of the smpl header section, not including the loop data. */ 02019 if (chunkSize >= sizeof(smplHeaderData)) { 02020 drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor); 02021 chunkSize -= bytesJustRead; 02022 02023 if (bytesJustRead == sizeof(smplHeaderData)) { 02024 drwav_uint32 iLoop; 02025 02026 pWav->smpl.manufacturer = drwav__bytes_to_u32(smplHeaderData+0); 02027 pWav->smpl.product = drwav__bytes_to_u32(smplHeaderData+4); 02028 pWav->smpl.samplePeriod = drwav__bytes_to_u32(smplHeaderData+8); 02029 pWav->smpl.midiUnityNotes = drwav__bytes_to_u32(smplHeaderData+12); 02030 pWav->smpl.midiPitchFraction = drwav__bytes_to_u32(smplHeaderData+16); 02031 pWav->smpl.smpteFormat = drwav__bytes_to_u32(smplHeaderData+20); 02032 pWav->smpl.smpteOffset = drwav__bytes_to_u32(smplHeaderData+24); 02033 pWav->smpl.numSampleLoops = drwav__bytes_to_u32(smplHeaderData+28); 02034 pWav->smpl.samplerData = drwav__bytes_to_u32(smplHeaderData+32); 02035 02036 for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) { 02037 drwav_uint8 smplLoopData[24]; /* 24 = size of a loop section in the smpl chunk. */ 02038 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor); 02039 chunkSize -= bytesJustRead; 02040 02041 if (bytesJustRead == sizeof(smplLoopData)) { 02042 pWav->smpl.loops[iLoop].cuePointId = drwav__bytes_to_u32(smplLoopData+0); 02043 pWav->smpl.loops[iLoop].type = drwav__bytes_to_u32(smplLoopData+4); 02044 pWav->smpl.loops[iLoop].start = drwav__bytes_to_u32(smplLoopData+8); 02045 pWav->smpl.loops[iLoop].end = drwav__bytes_to_u32(smplLoopData+12); 02046 pWav->smpl.loops[iLoop].fraction = drwav__bytes_to_u32(smplLoopData+16); 02047 pWav->smpl.loops[iLoop].playCount = drwav__bytes_to_u32(smplLoopData+20); 02048 } else { 02049 break; /* Break from the smpl loop for loop. */ 02050 } 02051 } 02052 } 02053 } else { 02054 /* Looks like invalid data. Ignore the chunk. */ 02055 } 02056 } 02057 } else { 02058 if (drwav__guid_equal(header.id.guid, drwavGUID_W64_SMPL)) { 02059 /* 02060 This path will be hit when a W64 WAV file contains a smpl chunk. I don't have a sample file to test this path, so a contribution 02061 is welcome to add support for this. 02062 */ 02063 } 02064 } 02065 02066 /* Make sure we seek past the padding. */ 02067 chunkSize += header.paddingSize; 02068 if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) { 02069 break; 02070 } 02071 cursor += chunkSize; 02072 02073 if (!foundDataChunk) { 02074 pWav->dataChunkDataPos = cursor; 02075 } 02076 } 02077 02078 /* If we haven't found a data chunk, return an error. */ 02079 if (!foundDataChunk) { 02080 return DRWAV_FALSE; 02081 } 02082 02083 /* 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. */ 02084 if (!sequential) { 02085 if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) { 02086 return DRWAV_FALSE; 02087 } 02088 cursor = pWav->dataChunkDataPos; 02089 } 02090 02091 02092 /* At this point we should be sitting on the first byte of the raw audio data. */ 02093 02094 pWav->fmt = fmt; 02095 pWav->sampleRate = fmt.sampleRate; 02096 pWav->channels = fmt.channels; 02097 pWav->bitsPerSample = fmt.bitsPerSample; 02098 pWav->bytesRemaining = dataChunkSize; 02099 pWav->translatedFormatTag = translatedFormatTag; 02100 pWav->dataChunkDataSize = dataChunkSize; 02101 02102 if (sampleCountFromFactChunk != 0) { 02103 pWav->totalPCMFrameCount = sampleCountFromFactChunk; 02104 } else { 02105 pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); 02106 02107 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { 02108 drwav_uint64 totalBlockHeaderSizeInBytes; 02109 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; 02110 02111 /* Make sure any trailing partial block is accounted for. */ 02112 if ((blockCount * fmt.blockAlign) < dataChunkSize) { 02113 blockCount += 1; 02114 } 02115 02116 /* 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. */ 02117 totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels); 02118 pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; 02119 } 02120 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { 02121 drwav_uint64 totalBlockHeaderSizeInBytes; 02122 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; 02123 02124 /* Make sure any trailing partial block is accounted for. */ 02125 if ((blockCount * fmt.blockAlign) < dataChunkSize) { 02126 blockCount += 1; 02127 } 02128 02129 /* 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. */ 02130 totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels); 02131 pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; 02132 02133 /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */ 02134 pWav->totalPCMFrameCount += blockCount; 02135 } 02136 } 02137 02138 /* Some formats only support a certain number of channels. */ 02139 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { 02140 if (pWav->channels > 2) { 02141 return DRWAV_FALSE; 02142 } 02143 } 02144 02145 #ifdef DR_WAV_LIBSNDFILE_COMPAT 02146 /* 02147 I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), 02148 it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count 02149 from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct 02150 way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should 02151 always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my 02152 correctness tests against libsndfile, and is disabled by default. 02153 */ 02154 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { 02155 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; 02156 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */ 02157 } 02158 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { 02159 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; 02160 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels; 02161 } 02162 #endif 02163 02164 return DRWAV_TRUE; 02165 } 02166 02167 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) 02168 { 02169 return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); 02170 } 02171 02172 DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) 02173 { 02174 if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { 02175 return DRWAV_FALSE; 02176 } 02177 02178 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); 02179 } 02180 02181 02182 static drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize) 02183 { 02184 drwav_uint32 dataSubchunkPaddingSize = drwav__chunk_padding_size_riff(dataChunkSize); 02185 02186 if (dataChunkSize <= (0xFFFFFFFFUL - 36 - dataSubchunkPaddingSize)) { 02187 return 36 + (drwav_uint32)(dataChunkSize + dataSubchunkPaddingSize); 02188 } else { 02189 return 0xFFFFFFFF; 02190 } 02191 } 02192 02193 static drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize) 02194 { 02195 if (dataChunkSize <= 0xFFFFFFFFUL) { 02196 return (drwav_uint32)dataChunkSize; 02197 } else { 02198 return 0xFFFFFFFFUL; 02199 } 02200 } 02201 02202 static drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize) 02203 { 02204 drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize); 02205 02206 return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */ 02207 } 02208 02209 static drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize) 02210 { 02211 return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ 02212 } 02213 02214 02215 static drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) 02216 { 02217 if (pWav == NULL || onWrite == NULL) { 02218 return DRWAV_FALSE; 02219 } 02220 02221 if (!isSequential && onSeek == NULL) { 02222 return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */ 02223 } 02224 02225 /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */ 02226 if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) { 02227 return DRWAV_FALSE; 02228 } 02229 if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) { 02230 return DRWAV_FALSE; 02231 } 02232 02233 DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); 02234 pWav->onWrite = onWrite; 02235 pWav->onSeek = onSeek; 02236 pWav->pUserData = pUserData; 02237 pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); 02238 02239 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { 02240 return DRWAV_FALSE; /* Invalid allocation callbacks. */ 02241 } 02242 02243 pWav->fmt.formatTag = (drwav_uint16)pFormat->format; 02244 pWav->fmt.channels = (drwav_uint16)pFormat->channels; 02245 pWav->fmt.sampleRate = pFormat->sampleRate; 02246 pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8); 02247 pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8); 02248 pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; 02249 pWav->fmt.extendedSize = 0; 02250 pWav->isSequentialWrite = isSequential; 02251 02252 return DRWAV_TRUE; 02253 } 02254 02255 static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) 02256 { 02257 /* The function assumes drwav_preinit_write() was called beforehand. */ 02258 02259 size_t runningPos = 0; 02260 drwav_uint64 initialDataChunkSize = 0; 02261 drwav_uint64 chunkSizeFMT; 02262 02263 /* 02264 The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In 02265 sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non- 02266 sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek. 02267 */ 02268 if (pWav->isSequentialWrite) { 02269 initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8; 02270 02271 /* 02272 The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64 02273 so for the sake of simplicity I'm not doing any validation for that. 02274 */ 02275 if (pFormat->container == drwav_container_riff) { 02276 if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) { 02277 return DRWAV_FALSE; /* Not enough room to store every sample. */ 02278 } 02279 } 02280 } 02281 02282 pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; 02283 02284 02285 /* "RIFF" chunk. */ 02286 if (pFormat->container == drwav_container_riff) { 02287 drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize; /* +36 = "RIFF"+[RIFF Chunk Size]+"WAVE" + [sizeof "fmt " chunk] */ 02288 runningPos += pWav->onWrite(pWav->pUserData, "RIFF", 4); 02289 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeRIFF, 4); 02290 runningPos += pWav->onWrite(pWav->pUserData, "WAVE", 4); 02291 } else { 02292 drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ 02293 runningPos += pWav->onWrite(pWav->pUserData, drwavGUID_W64_RIFF, 16); 02294 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeRIFF, 8); 02295 runningPos += pWav->onWrite(pWav->pUserData, drwavGUID_W64_WAVE, 16); 02296 } 02297 02298 /* "fmt " chunk. */ 02299 if (pFormat->container == drwav_container_riff) { 02300 chunkSizeFMT = 16; 02301 runningPos += pWav->onWrite(pWav->pUserData, "fmt ", 4); 02302 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeFMT, 4); 02303 } else { 02304 chunkSizeFMT = 40; 02305 runningPos += pWav->onWrite(pWav->pUserData, drwavGUID_W64_FMT, 16); 02306 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeFMT, 8); 02307 } 02308 02309 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.formatTag, 2); 02310 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.channels, 2); 02311 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.sampleRate, 4); 02312 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.avgBytesPerSec, 4); 02313 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.blockAlign, 2); 02314 runningPos += pWav->onWrite(pWav->pUserData, &pWav->fmt.bitsPerSample, 2); 02315 02316 pWav->dataChunkDataPos = runningPos; 02317 02318 /* "data" chunk. */ 02319 if (pFormat->container == drwav_container_riff) { 02320 drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize; 02321 runningPos += pWav->onWrite(pWav->pUserData, "data", 4); 02322 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeDATA, 4); 02323 } else { 02324 drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ 02325 runningPos += pWav->onWrite(pWav->pUserData, drwavGUID_W64_DATA, 16); 02326 runningPos += pWav->onWrite(pWav->pUserData, &chunkSizeDATA, 8); 02327 } 02328 02329 02330 /* Simple validation. */ 02331 if (pFormat->container == drwav_container_riff) { 02332 if (runningPos != 20 + chunkSizeFMT + 8) { 02333 return DRWAV_FALSE; 02334 } 02335 } else { 02336 if (runningPos != 40 + chunkSizeFMT + 24) { 02337 return DRWAV_FALSE; 02338 } 02339 } 02340 02341 02342 /* Set some properties for the client's convenience. */ 02343 pWav->container = pFormat->container; 02344 pWav->channels = (drwav_uint16)pFormat->channels; 02345 pWav->sampleRate = pFormat->sampleRate; 02346 pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; 02347 pWav->translatedFormatTag = (drwav_uint16)pFormat->format; 02348 02349 return DRWAV_TRUE; 02350 } 02351 02352 02353 DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) 02354 { 02355 if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { 02356 return DRWAV_FALSE; 02357 } 02358 02359 return drwav_init_write__internal(pWav, pFormat, 0); /* DRWAV_FALSE = Not Sequential */ 02360 } 02361 02362 DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) 02363 { 02364 if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) { 02365 return DRWAV_FALSE; 02366 } 02367 02368 return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */ 02369 } 02370 02371 DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) 02372 { 02373 if (pFormat == NULL) { 02374 return DRWAV_FALSE; 02375 } 02376 02377 return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks); 02378 } 02379 02380 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) 02381 { 02382 /* Casting totalSampleCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */ 02383 drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0); 02384 drwav_uint64 riffChunkSizeBytes; 02385 drwav_uint64 fileSizeBytes; 02386 02387 if (pFormat->container == drwav_container_riff) { 02388 riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes); 02389 fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */ 02390 } else { 02391 riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes); 02392 fileSizeBytes = riffChunkSizeBytes; 02393 } 02394 02395 return fileSizeBytes; 02396 } 02397 02398 02399 #ifndef DR_WAV_NO_STDIO 02400 02401 /* 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. */ 02402 #include <errno.h> 02403 static drwav_result drwav_result_from_errno(int e) 02404 { 02405 switch (e) 02406 { 02407 case 0: return DRWAV_SUCCESS; 02408 #ifdef EPERM 02409 case EPERM: return DRWAV_INVALID_OPERATION; 02410 #endif 02411 #ifdef ENOENT 02412 case ENOENT: return DRWAV_DOES_NOT_EXIST; 02413 #endif 02414 #ifdef ESRCH 02415 case ESRCH: return DRWAV_DOES_NOT_EXIST; 02416 #endif 02417 #ifdef EINTR 02418 case EINTR: return DRWAV_INTERRUPT; 02419 #endif 02420 #ifdef EIO 02421 case EIO: return DRWAV_IO_ERROR; 02422 #endif 02423 #ifdef ENXIO 02424 case ENXIO: return DRWAV_DOES_NOT_EXIST; 02425 #endif 02426 #ifdef E2BIG 02427 case E2BIG: return DRWAV_INVALID_ARGS; 02428 #endif 02429 #ifdef ENOEXEC 02430 case ENOEXEC: return DRWAV_INVALID_FILE; 02431 #endif 02432 #ifdef EBADF 02433 case EBADF: return DRWAV_INVALID_FILE; 02434 #endif 02435 #ifdef ECHILD 02436 case ECHILD: return DRWAV_ERROR; 02437 #endif 02438 #ifdef EAGAIN 02439 case EAGAIN: return DRWAV_UNAVAILABLE; 02440 #endif 02441 #ifdef ENOMEM 02442 case ENOMEM: return DRWAV_OUT_OF_MEMORY; 02443 #endif 02444 #ifdef EACCES 02445 case EACCES: return DRWAV_ACCESS_DENIED; 02446 #endif 02447 #ifdef EFAULT 02448 case EFAULT: return DRWAV_BAD_ADDRESS; 02449 #endif 02450 #ifdef ENOTBLK 02451 case ENOTBLK: return DRWAV_ERROR; 02452 #endif 02453 #ifdef EBUSY 02454 case EBUSY: return DRWAV_BUSY; 02455 #endif 02456 #ifdef EEXIST 02457 case EEXIST: return DRWAV_ALREADY_EXISTS; 02458 #endif 02459 #ifdef EXDEV 02460 case EXDEV: return DRWAV_ERROR; 02461 #endif 02462 #ifdef ENODEV 02463 case ENODEV: return DRWAV_DOES_NOT_EXIST; 02464 #endif 02465 #ifdef ENOTDIR 02466 case ENOTDIR: return DRWAV_NOT_DIRECTORY; 02467 #endif 02468 #ifdef EISDIR 02469 case EISDIR: return DRWAV_IS_DIRECTORY; 02470 #endif 02471 #ifdef EINVAL 02472 case EINVAL: return DRWAV_INVALID_ARGS; 02473 #endif 02474 #ifdef ENFILE 02475 case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES; 02476 #endif 02477 #ifdef EMFILE 02478 case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES; 02479 #endif 02480 #ifdef ENOTTY 02481 case ENOTTY: return DRWAV_INVALID_OPERATION; 02482 #endif 02483 #ifdef ETXTBSY 02484 case ETXTBSY: return DRWAV_BUSY; 02485 #endif 02486 #ifdef EFBIG 02487 case EFBIG: return DRWAV_TOO_BIG; 02488 #endif 02489 #ifdef ENOSPC 02490 case ENOSPC: return DRWAV_NO_SPACE; 02491 #endif 02492 #ifdef ESPIPE 02493 case ESPIPE: return DRWAV_BAD_SEEK; 02494 #endif 02495 #ifdef EROFS 02496 case EROFS: return DRWAV_ACCESS_DENIED; 02497 #endif 02498 #ifdef EMLINK 02499 case EMLINK: return DRWAV_TOO_MANY_LINKS; 02500 #endif 02501 #ifdef EPIPE 02502 case EPIPE: return DRWAV_BAD_PIPE; 02503 #endif 02504 #ifdef EDOM 02505 case EDOM: return DRWAV_OUT_OF_RANGE; 02506 #endif 02507 #ifdef ERANGE 02508 case ERANGE: return DRWAV_OUT_OF_RANGE; 02509 #endif 02510 #ifdef EDEADLK 02511 case EDEADLK: return DRWAV_DEADLOCK; 02512 #endif 02513 #ifdef ENAMETOOLONG 02514 case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG; 02515 #endif 02516 #ifdef ENOLCK 02517 case ENOLCK: return DRWAV_ERROR; 02518 #endif 02519 #ifdef ENOSYS 02520 case ENOSYS: return DRWAV_NOT_IMPLEMENTED; 02521 #endif 02522 #ifdef ENOTEMPTY 02523 case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY; 02524 #endif 02525 #ifdef ELOOP 02526 case ELOOP: return DRWAV_TOO_MANY_LINKS; 02527 #endif 02528 #ifdef ENOMSG 02529 case ENOMSG: return DRWAV_NO_MESSAGE; 02530 #endif 02531 #ifdef EIDRM 02532 case EIDRM: return DRWAV_ERROR; 02533 #endif 02534 #ifdef ECHRNG 02535 case ECHRNG: return DRWAV_ERROR; 02536 #endif 02537 #ifdef EL2NSYNC 02538 case EL2NSYNC: return DRWAV_ERROR; 02539 #endif 02540 #ifdef EL3HLT 02541 case EL3HLT: return DRWAV_ERROR; 02542 #endif 02543 #ifdef EL3RST 02544 case EL3RST: return DRWAV_ERROR; 02545 #endif 02546 #ifdef ELNRNG 02547 case ELNRNG: return DRWAV_OUT_OF_RANGE; 02548 #endif 02549 #ifdef EUNATCH 02550 case EUNATCH: return DRWAV_ERROR; 02551 #endif 02552 #ifdef ENOCSI 02553 case ENOCSI: return DRWAV_ERROR; 02554 #endif 02555 #ifdef EL2HLT 02556 case EL2HLT: return DRWAV_ERROR; 02557 #endif 02558 #ifdef EBADE 02559 case EBADE: return DRWAV_ERROR; 02560 #endif 02561 #ifdef EBADR 02562 case EBADR: return DRWAV_ERROR; 02563 #endif 02564 #ifdef EXFULL 02565 case EXFULL: return DRWAV_ERROR; 02566 #endif 02567 #ifdef ENOANO 02568 case ENOANO: return DRWAV_ERROR; 02569 #endif 02570 #ifdef EBADRQC 02571 case EBADRQC: return DRWAV_ERROR; 02572 #endif 02573 #ifdef EBADSLT 02574 case EBADSLT: return DRWAV_ERROR; 02575 #endif 02576 #ifdef EBFONT 02577 case EBFONT: return DRWAV_INVALID_FILE; 02578 #endif 02579 #ifdef ENOSTR 02580 case ENOSTR: return DRWAV_ERROR; 02581 #endif 02582 #ifdef ENODATA 02583 case ENODATA: return DRWAV_NO_DATA_AVAILABLE; 02584 #endif 02585 #ifdef ETIME 02586 case ETIME: return DRWAV_TIMEOUT; 02587 #endif 02588 #ifdef ENOSR 02589 case ENOSR: return DRWAV_NO_DATA_AVAILABLE; 02590 #endif 02591 #ifdef ENONET 02592 case ENONET: return DRWAV_NO_NETWORK; 02593 #endif 02594 #ifdef ENOPKG 02595 case ENOPKG: return DRWAV_ERROR; 02596 #endif 02597 #ifdef EREMOTE 02598 case EREMOTE: return DRWAV_ERROR; 02599 #endif 02600 #ifdef ENOLINK 02601 case ENOLINK: return DRWAV_ERROR; 02602 #endif 02603 #ifdef EADV 02604 case EADV: return DRWAV_ERROR; 02605 #endif 02606 #ifdef ESRMNT 02607 case ESRMNT: return DRWAV_ERROR; 02608 #endif 02609 #ifdef ECOMM 02610 case ECOMM: return DRWAV_ERROR; 02611 #endif 02612 #ifdef EPROTO 02613 case EPROTO: return DRWAV_ERROR; 02614 #endif 02615 #ifdef EMULTIHOP 02616 case EMULTIHOP: return DRWAV_ERROR; 02617 #endif 02618 #ifdef EDOTDOT 02619 case EDOTDOT: return DRWAV_ERROR; 02620 #endif 02621 #ifdef EBADMSG 02622 case EBADMSG: return DRWAV_BAD_MESSAGE; 02623 #endif 02624 #ifdef EOVERFLOW 02625 case EOVERFLOW: return DRWAV_TOO_BIG; 02626 #endif 02627 #ifdef ENOTUNIQ 02628 case ENOTUNIQ: return DRWAV_NOT_UNIQUE; 02629 #endif 02630 #ifdef EBADFD 02631 case EBADFD: return DRWAV_ERROR; 02632 #endif 02633 #ifdef EREMCHG 02634 case EREMCHG: return DRWAV_ERROR; 02635 #endif 02636 #ifdef ELIBACC 02637 case ELIBACC: return DRWAV_ACCESS_DENIED; 02638 #endif 02639 #ifdef ELIBBAD 02640 case ELIBBAD: return DRWAV_INVALID_FILE; 02641 #endif 02642 #ifdef ELIBSCN 02643 case ELIBSCN: return DRWAV_INVALID_FILE; 02644 #endif 02645 #ifdef ELIBMAX 02646 case ELIBMAX: return DRWAV_ERROR; 02647 #endif 02648 #ifdef ELIBEXEC 02649 case ELIBEXEC: return DRWAV_ERROR; 02650 #endif 02651 #ifdef EILSEQ 02652 case EILSEQ: return DRWAV_INVALID_DATA; 02653 #endif 02654 #ifdef ERESTART 02655 case ERESTART: return DRWAV_ERROR; 02656 #endif 02657 #ifdef ESTRPIPE 02658 case ESTRPIPE: return DRWAV_ERROR; 02659 #endif 02660 #ifdef EUSERS 02661 case EUSERS: return DRWAV_ERROR; 02662 #endif 02663 #ifdef ENOTSOCK 02664 case ENOTSOCK: return DRWAV_NOT_SOCKET; 02665 #endif 02666 #ifdef EDESTADDRREQ 02667 case EDESTADDRREQ: return DRWAV_NO_ADDRESS; 02668 #endif 02669 #ifdef EMSGSIZE 02670 case EMSGSIZE: return DRWAV_TOO_BIG; 02671 #endif 02672 #ifdef EPROTOTYPE 02673 case EPROTOTYPE: return DRWAV_BAD_PROTOCOL; 02674 #endif 02675 #ifdef ENOPROTOOPT 02676 case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE; 02677 #endif 02678 #ifdef EPROTONOSUPPORT 02679 case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED; 02680 #endif 02681 #ifdef ESOCKTNOSUPPORT 02682 case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED; 02683 #endif 02684 #ifdef EOPNOTSUPP 02685 case EOPNOTSUPP: return DRWAV_INVALID_OPERATION; 02686 #endif 02687 #ifdef EPFNOSUPPORT 02688 case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED; 02689 #endif 02690 #ifdef EAFNOSUPPORT 02691 case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED; 02692 #endif 02693 #ifdef EADDRINUSE 02694 case EADDRINUSE: return DRWAV_ALREADY_IN_USE; 02695 #endif 02696 #ifdef EADDRNOTAVAIL 02697 case EADDRNOTAVAIL: return DRWAV_ERROR; 02698 #endif 02699 #ifdef ENETDOWN 02700 case ENETDOWN: return DRWAV_NO_NETWORK; 02701 #endif 02702 #ifdef ENETUNREACH 02703 case ENETUNREACH: return DRWAV_NO_NETWORK; 02704 #endif 02705 #ifdef ENETRESET 02706 case ENETRESET: return DRWAV_NO_NETWORK; 02707 #endif 02708 #ifdef ECONNABORTED 02709 case ECONNABORTED: return DRWAV_NO_NETWORK; 02710 #endif 02711 #ifdef ECONNRESET 02712 case ECONNRESET: return DRWAV_CONNECTION_RESET; 02713 #endif 02714 #ifdef ENOBUFS 02715 case ENOBUFS: return DRWAV_NO_SPACE; 02716 #endif 02717 #ifdef EISCONN 02718 case EISCONN: return DRWAV_ALREADY_CONNECTED; 02719 #endif 02720 #ifdef ENOTCONN 02721 case ENOTCONN: return DRWAV_NOT_CONNECTED; 02722 #endif 02723 #ifdef ESHUTDOWN 02724 case ESHUTDOWN: return DRWAV_ERROR; 02725 #endif 02726 #ifdef ETOOMANYREFS 02727 case ETOOMANYREFS: return DRWAV_ERROR; 02728 #endif 02729 #ifdef ETIMEDOUT 02730 case ETIMEDOUT: return DRWAV_TIMEOUT; 02731 #endif 02732 #ifdef ECONNREFUSED 02733 case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED; 02734 #endif 02735 #ifdef EHOSTDOWN 02736 case EHOSTDOWN: return DRWAV_NO_HOST; 02737 #endif 02738 #ifdef EHOSTUNREACH 02739 case EHOSTUNREACH: return DRWAV_NO_HOST; 02740 #endif 02741 #ifdef EALREADY 02742 case EALREADY: return DRWAV_IN_PROGRESS; 02743 #endif 02744 #ifdef EINPROGRESS 02745 case EINPROGRESS: return DRWAV_IN_PROGRESS; 02746 #endif 02747 #ifdef ESTALE 02748 case ESTALE: return DRWAV_INVALID_FILE; 02749 #endif 02750 #ifdef EUCLEAN 02751 case EUCLEAN: return DRWAV_ERROR; 02752 #endif 02753 #ifdef ENOTNAM 02754 case ENOTNAM: return DRWAV_ERROR; 02755 #endif 02756 #ifdef ENAVAIL 02757 case ENAVAIL: return DRWAV_ERROR; 02758 #endif 02759 #ifdef EISNAM 02760 case EISNAM: return DRWAV_ERROR; 02761 #endif 02762 #ifdef EREMOTEIO 02763 case EREMOTEIO: return DRWAV_IO_ERROR; 02764 #endif 02765 #ifdef EDQUOT 02766 case EDQUOT: return DRWAV_NO_SPACE; 02767 #endif 02768 #ifdef ENOMEDIUM 02769 case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST; 02770 #endif 02771 #ifdef EMEDIUMTYPE 02772 case EMEDIUMTYPE: return DRWAV_ERROR; 02773 #endif 02774 #ifdef ECANCELED 02775 case ECANCELED: return DRWAV_CANCELLED; 02776 #endif 02777 #ifdef ENOKEY 02778 case ENOKEY: return DRWAV_ERROR; 02779 #endif 02780 #ifdef EKEYEXPIRED 02781 case EKEYEXPIRED: return DRWAV_ERROR; 02782 #endif 02783 #ifdef EKEYREVOKED 02784 case EKEYREVOKED: return DRWAV_ERROR; 02785 #endif 02786 #ifdef EKEYREJECTED 02787 case EKEYREJECTED: return DRWAV_ERROR; 02788 #endif 02789 #ifdef EOWNERDEAD 02790 case EOWNERDEAD: return DRWAV_ERROR; 02791 #endif 02792 #ifdef ENOTRECOVERABLE 02793 case ENOTRECOVERABLE: return DRWAV_ERROR; 02794 #endif 02795 #ifdef ERFKILL 02796 case ERFKILL: return DRWAV_ERROR; 02797 #endif 02798 #ifdef EHWPOISON 02799 case EHWPOISON: return DRWAV_ERROR; 02800 #endif 02801 default: return DRWAV_ERROR; 02802 } 02803 } 02804 02805 static drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) 02806 { 02807 #if _MSC_VER && _MSC_VER >= 1400 02808 errno_t err; 02809 #endif 02810 02811 if (ppFile != NULL) { 02812 *ppFile = NULL; /* Safety. */ 02813 } 02814 02815 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { 02816 return DRWAV_INVALID_ARGS; 02817 } 02818 02819 #if _MSC_VER && _MSC_VER >= 1400 02820 err = fopen_s(ppFile, pFilePath, pOpenMode); 02821 if (err != 0) { 02822 return drwav_result_from_errno(err); 02823 } 02824 #else 02825 #if defined(_WIN32) || defined(__APPLE__) 02826 *ppFile = fopen(pFilePath, pOpenMode); 02827 #else 02828 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) 02829 *ppFile = fopen64(pFilePath, pOpenMode); 02830 #else 02831 *ppFile = fopen(pFilePath, pOpenMode); 02832 #endif 02833 #endif 02834 if (*ppFile == NULL) { 02835 drwav_result result = drwav_result_from_errno(errno); 02836 if (result == DRWAV_SUCCESS) { 02837 result = DRWAV_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ 02838 } 02839 02840 return result; 02841 } 02842 #endif 02843 02844 return DRWAV_SUCCESS; 02845 } 02846 02847 /* 02848 _wfopen() isn't always available in all compilation environments. 02849 02850 * Windows only. 02851 * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). 02852 * MinGW-64 (both 32- and 64-bit) seems to support it. 02853 * MinGW wraps it in !defined(__STRICT_ANSI__). 02854 02855 This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() 02856 fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. 02857 */ 02858 #if defined(_WIN32) 02859 #if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__) 02860 #define DRWAV_HAS_WFOPEN 02861 #endif 02862 #endif 02863 02864 static drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks) 02865 { 02866 if (ppFile != NULL) { 02867 *ppFile = NULL; /* Safety. */ 02868 } 02869 02870 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { 02871 return DRWAV_INVALID_ARGS; 02872 } 02873 02874 #if defined(DRWAV_HAS_WFOPEN) 02875 { 02876 /* Use _wfopen() on Windows. */ 02877 #if defined(_MSC_VER) && _MSC_VER >= 1400 02878 errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); 02879 if (err != 0) { 02880 return drwav_result_from_errno(err); 02881 } 02882 #else 02883 *ppFile = _wfopen(pFilePath, pOpenMode); 02884 if (*ppFile == NULL) { 02885 return drwav_result_from_errno(errno); 02886 } 02887 #endif 02888 (void)pAllocationCallbacks; 02889 } 02890 #else 02891 /* 02892 Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can 02893 think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for 02894 maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. 02895 */ 02896 { 02897 mbstate_t mbs; 02898 size_t lenMB; 02899 const wchar_t* pFilePathTemp = pFilePath; 02900 char* pFilePathMB = NULL; 02901 char pOpenModeMB[32] = {0}; 02902 02903 /* Get the length first. */ 02904 DRWAV_ZERO_OBJECT(&mbs); 02905 lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); 02906 if (lenMB == (size_t)-1) { 02907 return drwav_result_from_errno(errno); 02908 } 02909 02910 pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); 02911 if (pFilePathMB == NULL) { 02912 return DRWAV_OUT_OF_MEMORY; 02913 } 02914 02915 pFilePathTemp = pFilePath; 02916 DRWAV_ZERO_OBJECT(&mbs); 02917 wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); 02918 02919 /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ 02920 { 02921 size_t i = 0; 02922 for (;;) { 02923 if (pOpenMode[i] == 0) { 02924 pOpenModeMB[i] = '\0'; 02925 break; 02926 } 02927 02928 pOpenModeMB[i] = (char)pOpenMode[i]; 02929 i += 1; 02930 } 02931 } 02932 02933 *ppFile = fopen(pFilePathMB, pOpenModeMB); 02934 02935 drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks); 02936 } 02937 02938 if (*ppFile == NULL) { 02939 return DRWAV_ERROR; 02940 } 02941 #endif 02942 02943 return DRWAV_SUCCESS; 02944 } 02945 02946 02947 static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) 02948 { 02949 return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); 02950 } 02951 02952 static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite) 02953 { 02954 return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData); 02955 } 02956 02957 static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin) 02958 { 02959 return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; 02960 } 02961 02962 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks) 02963 { 02964 return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); 02965 } 02966 02967 02968 static drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) 02969 { 02970 drwav_bool32 result; 02971 02972 result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); 02973 if (result != DRWAV_TRUE) { 02974 fclose(pFile); 02975 return result; 02976 } 02977 02978 result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags); 02979 if (result != DRWAV_TRUE) { 02980 fclose(pFile); 02981 return result; 02982 } 02983 02984 return DRWAV_TRUE; 02985 } 02986 02987 DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) 02988 { 02989 FILE* pFile; 02990 if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) { 02991 return DRWAV_FALSE; 02992 } 02993 02994 /* This takes ownership of the FILE* object. */ 02995 return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); 02996 } 02997 02998 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks) 02999 { 03000 return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); 03001 } 03002 03003 DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) 03004 { 03005 FILE* pFile; 03006 if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) { 03007 return DRWAV_FALSE; 03008 } 03009 03010 /* This takes ownership of the FILE* object. */ 03011 return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); 03012 } 03013 03014 03015 static drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) 03016 { 03017 drwav_bool32 result; 03018 03019 result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); 03020 if (result != DRWAV_TRUE) { 03021 fclose(pFile); 03022 return result; 03023 } 03024 03025 result = drwav_init_write__internal(pWav, pFormat, totalSampleCount); 03026 if (result != DRWAV_TRUE) { 03027 fclose(pFile); 03028 return result; 03029 } 03030 03031 return DRWAV_TRUE; 03032 } 03033 03034 static drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) 03035 { 03036 FILE* pFile; 03037 if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) { 03038 return DRWAV_FALSE; 03039 } 03040 03041 /* This takes ownership of the FILE* object. */ 03042 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); 03043 } 03044 03045 static drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) 03046 { 03047 FILE* pFile; 03048 if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) { 03049 return DRWAV_FALSE; 03050 } 03051 03052 /* This takes ownership of the FILE* object. */ 03053 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); 03054 } 03055 03056 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) 03057 { 03058 return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); 03059 } 03060 03061 DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) 03062 { 03063 return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); 03064 } 03065 03066 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) 03067 { 03068 if (pFormat == NULL) { 03069 return DRWAV_FALSE; 03070 } 03071 03072 return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); 03073 } 03074 03075 DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) 03076 { 03077 return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); 03078 } 03079 03080 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) 03081 { 03082 return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); 03083 } 03084 03085 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) 03086 { 03087 if (pFormat == NULL) { 03088 return DRWAV_FALSE; 03089 } 03090 03091 return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); 03092 } 03093 #endif /* DR_WAV_NO_STDIO */ 03094 03095 03096 static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) 03097 { 03098 drwav* pWav = (drwav*)pUserData; 03099 size_t bytesRemaining; 03100 03101 DRWAV_ASSERT(pWav != NULL); 03102 DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos); 03103 03104 bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos; 03105 if (bytesToRead > bytesRemaining) { 03106 bytesToRead = bytesRemaining; 03107 } 03108 03109 if (bytesToRead > 0) { 03110 DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead); 03111 pWav->memoryStream.currentReadPos += bytesToRead; 03112 } 03113 03114 return bytesToRead; 03115 } 03116 03117 static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin) 03118 { 03119 drwav* pWav = (drwav*)pUserData; 03120 DRWAV_ASSERT(pWav != NULL); 03121 03122 if (origin == drwav_seek_origin_current) { 03123 if (offset > 0) { 03124 if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { 03125 return DRWAV_FALSE; /* Trying to seek too far forward. */ 03126 } 03127 } else { 03128 if (pWav->memoryStream.currentReadPos < (size_t)-offset) { 03129 return DRWAV_FALSE; /* Trying to seek too far backwards. */ 03130 } 03131 } 03132 03133 /* This will never underflow thanks to the clamps above. */ 03134 pWav->memoryStream.currentReadPos += offset; 03135 } else { 03136 if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) { 03137 pWav->memoryStream.currentReadPos = offset; 03138 } else { 03139 return DRWAV_FALSE; /* Trying to seek too far forward. */ 03140 } 03141 } 03142 03143 return DRWAV_TRUE; 03144 } 03145 03146 static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) 03147 { 03148 drwav* pWav = (drwav*)pUserData; 03149 size_t bytesRemaining; 03150 03151 DRWAV_ASSERT(pWav != NULL); 03152 DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos); 03153 03154 bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos; 03155 if (bytesRemaining < bytesToWrite) { 03156 /* Need to reallocate. */ 03157 void* pNewData; 03158 size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2; 03159 03160 /* If doubling wasn't enough, just make it the minimum required size to write the data. */ 03161 if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) { 03162 newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite; 03163 } 03164 03165 pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks); 03166 if (pNewData == NULL) { 03167 return 0; 03168 } 03169 03170 *pWav->memoryStreamWrite.ppData = pNewData; 03171 pWav->memoryStreamWrite.dataCapacity = newDataCapacity; 03172 } 03173 03174 DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite); 03175 03176 pWav->memoryStreamWrite.currentWritePos += bytesToWrite; 03177 if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) { 03178 pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos; 03179 } 03180 03181 *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize; 03182 03183 return bytesToWrite; 03184 } 03185 03186 static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin) 03187 { 03188 drwav* pWav = (drwav*)pUserData; 03189 DRWAV_ASSERT(pWav != NULL); 03190 03191 if (origin == drwav_seek_origin_current) { 03192 if (offset > 0) { 03193 if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { 03194 offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); /* Trying to seek too far forward. */ 03195 } 03196 } else { 03197 if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { 03198 offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */ 03199 } 03200 } 03201 03202 /* This will never underflow thanks to the clamps above. */ 03203 pWav->memoryStreamWrite.currentWritePos += offset; 03204 } else { 03205 if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) { 03206 pWav->memoryStreamWrite.currentWritePos = offset; 03207 } else { 03208 pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */ 03209 } 03210 } 03211 03212 return DRWAV_TRUE; 03213 } 03214 03215 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks) 03216 { 03217 return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks); 03218 } 03219 03220 DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) 03221 { 03222 if (data == NULL || dataSize == 0) { 03223 return DRWAV_FALSE; 03224 } 03225 03226 if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) { 03227 return DRWAV_FALSE; 03228 } 03229 03230 pWav->memoryStream.data = (const drwav_uint8*)data; 03231 pWav->memoryStream.dataSize = dataSize; 03232 pWav->memoryStream.currentReadPos = 0; 03233 03234 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); 03235 } 03236 03237 03238 static drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) 03239 { 03240 if (ppData == NULL || pDataSize == NULL) { 03241 return DRWAV_FALSE; 03242 } 03243 03244 *ppData = NULL; /* Important because we're using realloc()! */ 03245 *pDataSize = 0; 03246 03247 if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) { 03248 return DRWAV_FALSE; 03249 } 03250 03251 pWav->memoryStreamWrite.ppData = ppData; 03252 pWav->memoryStreamWrite.pDataSize = pDataSize; 03253 pWav->memoryStreamWrite.dataSize = 0; 03254 pWav->memoryStreamWrite.dataCapacity = 0; 03255 pWav->memoryStreamWrite.currentWritePos = 0; 03256 03257 return drwav_init_write__internal(pWav, pFormat, totalSampleCount); 03258 } 03259 03260 DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) 03261 { 03262 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); 03263 } 03264 03265 DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) 03266 { 03267 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); 03268 } 03269 03270 DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) 03271 { 03272 if (pFormat == NULL) { 03273 return DRWAV_FALSE; 03274 } 03275 03276 return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); 03277 } 03278 03279 03280 03281 DRWAV_API drwav_result drwav_uninit(drwav* pWav) 03282 { 03283 drwav_result result = DRWAV_SUCCESS; 03284 03285 if (pWav == NULL) { 03286 return DRWAV_INVALID_ARGS; 03287 } 03288 03289 /* 03290 If the drwav object was opened in write mode we'll need to finalize a few things: 03291 - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers. 03292 - Set the size of the "data" chunk. 03293 */ 03294 if (pWav->onWrite != NULL) { 03295 drwav_uint32 paddingSize = 0; 03296 03297 /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */ 03298 if (pWav->container == drwav_container_riff) { 03299 paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize); 03300 } else { 03301 paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize); 03302 } 03303 03304 if (paddingSize > 0) { 03305 drwav_uint64 paddingData = 0; 03306 pWav->onWrite(pWav->pUserData, &paddingData, paddingSize); 03307 } 03308 03309 /* 03310 Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need 03311 to do this when using non-sequential mode. 03312 */ 03313 if (pWav->onSeek && !pWav->isSequentialWrite) { 03314 if (pWav->container == drwav_container_riff) { 03315 /* The "RIFF" chunk size. */ 03316 if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) { 03317 drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize); 03318 pWav->onWrite(pWav->pUserData, &riffChunkSize, 4); 03319 } 03320 03321 /* the "data" chunk size. */ 03322 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) { 03323 drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize); 03324 pWav->onWrite(pWav->pUserData, &dataChunkSize, 4); 03325 } 03326 } else { 03327 /* The "RIFF" chunk size. */ 03328 if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) { 03329 drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize); 03330 pWav->onWrite(pWav->pUserData, &riffChunkSize, 8); 03331 } 03332 03333 /* The "data" chunk size. */ 03334 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) { 03335 drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize); 03336 pWav->onWrite(pWav->pUserData, &dataChunkSize, 8); 03337 } 03338 } 03339 } 03340 03341 /* Validation for sequential mode. */ 03342 if (pWav->isSequentialWrite) { 03343 if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) { 03344 result = DRWAV_INVALID_FILE; 03345 } 03346 } 03347 } 03348 03349 #ifndef DR_WAV_NO_STDIO 03350 /* 03351 If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file() 03352 was used by looking at the onRead and onSeek callbacks. 03353 */ 03354 if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) { 03355 fclose((FILE*)pWav->pUserData); 03356 } 03357 #endif 03358 03359 return result; 03360 } 03361 03362 03363 03364 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) 03365 { 03366 size_t bytesRead; 03367 03368 if (pWav == NULL || bytesToRead == 0 || pBufferOut == NULL) { 03369 return 0; 03370 } 03371 03372 if (bytesToRead > pWav->bytesRemaining) { 03373 bytesToRead = (size_t)pWav->bytesRemaining; 03374 } 03375 03376 bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); 03377 03378 pWav->bytesRemaining -= bytesRead; 03379 return bytesRead; 03380 } 03381 03382 03383 03384 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) 03385 { 03386 drwav_uint32 bytesPerFrame; 03387 03388 if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) { 03389 return 0; 03390 } 03391 03392 /* Cannot use this function for compressed formats. */ 03393 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { 03394 return 0; 03395 } 03396 03397 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 03398 if (bytesPerFrame == 0) { 03399 return 0; 03400 } 03401 03402 /* Don't try to read more samples than can potentially fit in the output buffer. */ 03403 if (framesToRead * bytesPerFrame > DRWAV_SIZE_MAX) { 03404 framesToRead = DRWAV_SIZE_MAX / bytesPerFrame; 03405 } 03406 03407 return drwav_read_raw(pWav, (size_t)(framesToRead * bytesPerFrame), pBufferOut) / bytesPerFrame; 03408 } 03409 03410 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) 03411 { 03412 drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); 03413 drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); 03414 03415 return framesRead; 03416 } 03417 03418 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) 03419 { 03420 if (drwav__is_little_endian()) { 03421 return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); 03422 } else { 03423 return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); 03424 } 03425 } 03426 03427 03428 03429 DRWAV_API drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) 03430 { 03431 if (pWav->onWrite != NULL) { 03432 return DRWAV_FALSE; /* No seeking in write mode. */ 03433 } 03434 03435 if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) { 03436 return DRWAV_FALSE; 03437 } 03438 03439 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { 03440 pWav->compressed.iCurrentPCMFrame = 0; 03441 } 03442 03443 pWav->bytesRemaining = pWav->dataChunkDataSize; 03444 return DRWAV_TRUE; 03445 } 03446 03447 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex) 03448 { 03449 /* Seeking should be compatible with wave files > 2GB. */ 03450 03451 if (pWav == NULL || pWav->onSeek == NULL) { 03452 return DRWAV_FALSE; 03453 } 03454 03455 /* No seeking in write mode. */ 03456 if (pWav->onWrite != NULL) { 03457 return DRWAV_FALSE; 03458 } 03459 03460 /* If there are no samples, just return DRWAV_TRUE without doing anything. */ 03461 if (pWav->totalPCMFrameCount == 0) { 03462 return DRWAV_TRUE; 03463 } 03464 03465 /* Make sure the sample is clamped. */ 03466 if (targetFrameIndex >= pWav->totalPCMFrameCount) { 03467 targetFrameIndex = pWav->totalPCMFrameCount - 1; 03468 } 03469 03470 /* 03471 For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need 03472 to seek back to the start. 03473 */ 03474 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { 03475 /* TODO: This can be optimized. */ 03476 03477 /* 03478 If we're seeking forward it's simple - just keep reading samples until we hit the sample we're requesting. If we're seeking backwards, 03479 we first need to seek back to the start and then just do the same thing as a forward seek. 03480 */ 03481 if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) { 03482 if (!drwav_seek_to_first_pcm_frame(pWav)) { 03483 return DRWAV_FALSE; 03484 } 03485 } 03486 03487 if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) { 03488 drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame; 03489 03490 drwav_int16 devnull[2048]; 03491 while (offsetInFrames > 0) { 03492 drwav_uint64 framesRead = 0; 03493 drwav_uint64 framesToRead = offsetInFrames; 03494 if (framesToRead > drwav_countof(devnull)/pWav->channels) { 03495 framesToRead = drwav_countof(devnull)/pWav->channels; 03496 } 03497 03498 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { 03499 framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull); 03500 } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { 03501 framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull); 03502 } else { 03503 DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */ 03504 } 03505 03506 if (framesRead != framesToRead) { 03507 return DRWAV_FALSE; 03508 } 03509 03510 offsetInFrames -= framesRead; 03511 } 03512 } 03513 } else { 03514 drwav_uint64 totalSizeInBytes; 03515 drwav_uint64 currentBytePos; 03516 drwav_uint64 targetBytePos; 03517 drwav_uint64 offset; 03518 03519 totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); 03520 DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); 03521 03522 currentBytePos = totalSizeInBytes - pWav->bytesRemaining; 03523 targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); 03524 03525 if (currentBytePos < targetBytePos) { 03526 /* Offset forwards. */ 03527 offset = (targetBytePos - currentBytePos); 03528 } else { 03529 /* Offset backwards. */ 03530 if (!drwav_seek_to_first_pcm_frame(pWav)) { 03531 return DRWAV_FALSE; 03532 } 03533 offset = targetBytePos; 03534 } 03535 03536 while (offset > 0) { 03537 int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); 03538 if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) { 03539 return DRWAV_FALSE; 03540 } 03541 03542 pWav->bytesRemaining -= offset32; 03543 offset -= offset32; 03544 } 03545 } 03546 03547 return DRWAV_TRUE; 03548 } 03549 03550 03551 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) 03552 { 03553 size_t bytesWritten; 03554 03555 if (pWav == NULL || bytesToWrite == 0 || pData == NULL) { 03556 return 0; 03557 } 03558 03559 bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); 03560 pWav->dataChunkDataSize += bytesWritten; 03561 03562 return bytesWritten; 03563 } 03564 03565 03566 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) 03567 { 03568 drwav_uint64 bytesToWrite; 03569 drwav_uint64 bytesWritten; 03570 const drwav_uint8* pRunningData; 03571 03572 if (pWav == NULL || framesToWrite == 0 || pData == NULL) { 03573 return 0; 03574 } 03575 03576 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); 03577 if (bytesToWrite > DRWAV_SIZE_MAX) { 03578 return 0; 03579 } 03580 03581 bytesWritten = 0; 03582 pRunningData = (const drwav_uint8*)pData; 03583 03584 while (bytesToWrite > 0) { 03585 size_t bytesJustWritten; 03586 drwav_uint64 bytesToWriteThisIteration; 03587 03588 bytesToWriteThisIteration = bytesToWrite; 03589 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */ 03590 03591 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); 03592 if (bytesJustWritten == 0) { 03593 break; 03594 } 03595 03596 bytesToWrite -= bytesJustWritten; 03597 bytesWritten += bytesJustWritten; 03598 pRunningData += bytesJustWritten; 03599 } 03600 03601 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; 03602 } 03603 03604 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) 03605 { 03606 drwav_uint64 bytesToWrite; 03607 drwav_uint64 bytesWritten; 03608 drwav_uint32 bytesPerSample; 03609 const drwav_uint8* pRunningData; 03610 03611 if (pWav == NULL || framesToWrite == 0 || pData == NULL) { 03612 return 0; 03613 } 03614 03615 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); 03616 if (bytesToWrite > DRWAV_SIZE_MAX) { 03617 return 0; 03618 } 03619 03620 bytesWritten = 0; 03621 pRunningData = (const drwav_uint8*)pData; 03622 03623 bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; 03624 03625 while (bytesToWrite > 0) { 03626 drwav_uint8 temp[4096]; 03627 drwav_uint32 sampleCount; 03628 size_t bytesJustWritten; 03629 drwav_uint64 bytesToWriteThisIteration; 03630 03631 bytesToWriteThisIteration = bytesToWrite; 03632 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */ 03633 03634 /* 03635 WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need 03636 to use an intermediary buffer for the conversion. 03637 */ 03638 sampleCount = sizeof(temp)/bytesPerSample; 03639 03640 if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) { 03641 bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample; 03642 } 03643 03644 DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration); 03645 drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag); 03646 03647 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp); 03648 if (bytesJustWritten == 0) { 03649 break; 03650 } 03651 03652 bytesToWrite -= bytesJustWritten; 03653 bytesWritten += bytesJustWritten; 03654 pRunningData += bytesJustWritten; 03655 } 03656 03657 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; 03658 } 03659 03660 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) 03661 { 03662 if (drwav__is_little_endian()) { 03663 return drwav_write_pcm_frames_le(pWav, framesToWrite, pData); 03664 } else { 03665 return drwav_write_pcm_frames_be(pWav, framesToWrite, pData); 03666 } 03667 } 03668 03669 03670 static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 03671 { 03672 drwav_uint64 totalFramesRead = 0; 03673 03674 DRWAV_ASSERT(pWav != NULL); 03675 DRWAV_ASSERT(framesToRead > 0); 03676 DRWAV_ASSERT(pBufferOut != NULL); 03677 03678 /* TODO: Lots of room for optimization here. */ 03679 03680 while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { 03681 /* If there are no cached frames we need to load a new block. */ 03682 if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { 03683 if (pWav->channels == 1) { 03684 /* Mono. */ 03685 drwav_uint8 header[7]; 03686 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { 03687 return totalFramesRead; 03688 } 03689 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); 03690 03691 pWav->msadpcm.predictor[0] = header[0]; 03692 pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 1); 03693 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 3); 03694 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 5); 03695 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0]; 03696 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1]; 03697 pWav->msadpcm.cachedFrameCount = 2; 03698 } else { 03699 /* Stereo. */ 03700 drwav_uint8 header[14]; 03701 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { 03702 return totalFramesRead; 03703 } 03704 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); 03705 03706 pWav->msadpcm.predictor[0] = header[0]; 03707 pWav->msadpcm.predictor[1] = header[1]; 03708 pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 2); 03709 pWav->msadpcm.delta[1] = drwav__bytes_to_s16(header + 4); 03710 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 6); 03711 pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav__bytes_to_s16(header + 8); 03712 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 10); 03713 pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav__bytes_to_s16(header + 12); 03714 03715 pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0]; 03716 pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0]; 03717 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1]; 03718 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1]; 03719 pWav->msadpcm.cachedFrameCount = 2; 03720 } 03721 } 03722 03723 /* Output anything that's cached. */ 03724 while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { 03725 drwav_uint32 iSample = 0; 03726 for (iSample = 0; iSample < pWav->channels; iSample += 1) { 03727 pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample]; 03728 } 03729 03730 pBufferOut += pWav->channels; 03731 framesToRead -= 1; 03732 totalFramesRead += 1; 03733 pWav->compressed.iCurrentPCMFrame += 1; 03734 pWav->msadpcm.cachedFrameCount -= 1; 03735 } 03736 03737 if (framesToRead == 0) { 03738 return totalFramesRead; 03739 } 03740 03741 03742 /* 03743 If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next 03744 loop iteration which will trigger the loading of a new block. 03745 */ 03746 if (pWav->msadpcm.cachedFrameCount == 0) { 03747 if (pWav->msadpcm.bytesRemainingInBlock == 0) { 03748 continue; 03749 } else { 03750 static drwav_int32 adaptationTable[] = { 03751 230, 230, 230, 230, 307, 409, 512, 614, 03752 768, 614, 512, 409, 307, 230, 230, 230 03753 }; 03754 static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; 03755 static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; 03756 03757 drwav_uint8 nibbles; 03758 drwav_int32 nibble0; 03759 drwav_int32 nibble1; 03760 03761 if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { 03762 return totalFramesRead; 03763 } 03764 pWav->msadpcm.bytesRemainingInBlock -= 1; 03765 03766 /* TODO: Optimize away these if statements. */ 03767 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } 03768 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } 03769 03770 if (pWav->channels == 1) { 03771 /* Mono. */ 03772 drwav_int32 newSample0; 03773 drwav_int32 newSample1; 03774 03775 newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; 03776 newSample0 += nibble0 * pWav->msadpcm.delta[0]; 03777 newSample0 = drwav_clamp(newSample0, -32768, 32767); 03778 03779 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; 03780 if (pWav->msadpcm.delta[0] < 16) { 03781 pWav->msadpcm.delta[0] = 16; 03782 } 03783 03784 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; 03785 pWav->msadpcm.prevFrames[0][1] = newSample0; 03786 03787 03788 newSample1 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; 03789 newSample1 += nibble1 * pWav->msadpcm.delta[0]; 03790 newSample1 = drwav_clamp(newSample1, -32768, 32767); 03791 03792 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8; 03793 if (pWav->msadpcm.delta[0] < 16) { 03794 pWav->msadpcm.delta[0] = 16; 03795 } 03796 03797 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; 03798 pWav->msadpcm.prevFrames[0][1] = newSample1; 03799 03800 03801 pWav->msadpcm.cachedFrames[2] = newSample0; 03802 pWav->msadpcm.cachedFrames[3] = newSample1; 03803 pWav->msadpcm.cachedFrameCount = 2; 03804 } else { 03805 /* Stereo. */ 03806 drwav_int32 newSample0; 03807 drwav_int32 newSample1; 03808 03809 /* Left. */ 03810 newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; 03811 newSample0 += nibble0 * pWav->msadpcm.delta[0]; 03812 newSample0 = drwav_clamp(newSample0, -32768, 32767); 03813 03814 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; 03815 if (pWav->msadpcm.delta[0] < 16) { 03816 pWav->msadpcm.delta[0] = 16; 03817 } 03818 03819 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; 03820 pWav->msadpcm.prevFrames[0][1] = newSample0; 03821 03822 03823 /* Right. */ 03824 newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8; 03825 newSample1 += nibble1 * pWav->msadpcm.delta[1]; 03826 newSample1 = drwav_clamp(newSample1, -32768, 32767); 03827 03828 pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8; 03829 if (pWav->msadpcm.delta[1] < 16) { 03830 pWav->msadpcm.delta[1] = 16; 03831 } 03832 03833 pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1]; 03834 pWav->msadpcm.prevFrames[1][1] = newSample1; 03835 03836 pWav->msadpcm.cachedFrames[2] = newSample0; 03837 pWav->msadpcm.cachedFrames[3] = newSample1; 03838 pWav->msadpcm.cachedFrameCount = 1; 03839 } 03840 } 03841 } 03842 } 03843 03844 return totalFramesRead; 03845 } 03846 03847 03848 static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 03849 { 03850 drwav_uint64 totalFramesRead = 0; 03851 03852 DRWAV_ASSERT(pWav != NULL); 03853 DRWAV_ASSERT(framesToRead > 0); 03854 DRWAV_ASSERT(pBufferOut != NULL); 03855 03856 /* TODO: Lots of room for optimization here. */ 03857 03858 while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { 03859 /* If there are no cached samples we need to load a new block. */ 03860 if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { 03861 if (pWav->channels == 1) { 03862 /* Mono. */ 03863 drwav_uint8 header[4]; 03864 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { 03865 return totalFramesRead; 03866 } 03867 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); 03868 03869 pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); 03870 pWav->ima.stepIndex[0] = header[2]; 03871 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; 03872 pWav->ima.cachedFrameCount = 1; 03873 } else { 03874 /* Stereo. */ 03875 drwav_uint8 header[8]; 03876 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { 03877 return totalFramesRead; 03878 } 03879 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); 03880 03881 pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); 03882 pWav->ima.stepIndex[0] = header[2]; 03883 pWav->ima.predictor[1] = drwav__bytes_to_s16(header + 4); 03884 pWav->ima.stepIndex[1] = header[6]; 03885 03886 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; 03887 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; 03888 pWav->ima.cachedFrameCount = 1; 03889 } 03890 } 03891 03892 /* Output anything that's cached. */ 03893 while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { 03894 drwav_uint32 iSample; 03895 for (iSample = 0; iSample < pWav->channels; iSample += 1) { 03896 pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample]; 03897 } 03898 03899 pBufferOut += pWav->channels; 03900 framesToRead -= 1; 03901 totalFramesRead += 1; 03902 pWav->compressed.iCurrentPCMFrame += 1; 03903 pWav->ima.cachedFrameCount -= 1; 03904 } 03905 03906 if (framesToRead == 0) { 03907 return totalFramesRead; 03908 } 03909 03910 /* 03911 If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next 03912 loop iteration which will trigger the loading of a new block. 03913 */ 03914 if (pWav->ima.cachedFrameCount == 0) { 03915 if (pWav->ima.bytesRemainingInBlock == 0) { 03916 continue; 03917 } else { 03918 static drwav_int32 indexTable[16] = { 03919 -1, -1, -1, -1, 2, 4, 6, 8, 03920 -1, -1, -1, -1, 2, 4, 6, 8 03921 }; 03922 03923 static drwav_int32 stepTable[89] = { 03924 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 03925 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 03926 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 03927 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 03928 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 03929 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 03930 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 03931 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 03932 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 03933 }; 03934 03935 drwav_uint32 iChannel; 03936 03937 /* 03938 From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the 03939 left channel, 4 bytes for the right channel. 03940 */ 03941 pWav->ima.cachedFrameCount = 8; 03942 for (iChannel = 0; iChannel < pWav->channels; ++iChannel) { 03943 drwav_uint32 iByte; 03944 drwav_uint8 nibbles[4]; 03945 if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) { 03946 pWav->ima.cachedFrameCount = 0; 03947 return totalFramesRead; 03948 } 03949 pWav->ima.bytesRemainingInBlock -= 4; 03950 03951 for (iByte = 0; iByte < 4; ++iByte) { 03952 drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0); 03953 drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4); 03954 03955 drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]]; 03956 drwav_int32 predictor = pWav->ima.predictor[iChannel]; 03957 03958 drwav_int32 diff = step >> 3; 03959 if (nibble0 & 1) diff += step >> 2; 03960 if (nibble0 & 2) diff += step >> 1; 03961 if (nibble0 & 4) diff += step; 03962 if (nibble0 & 8) diff = -diff; 03963 03964 predictor = drwav_clamp(predictor + diff, -32768, 32767); 03965 pWav->ima.predictor[iChannel] = predictor; 03966 pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1); 03967 pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor; 03968 03969 03970 step = stepTable[pWav->ima.stepIndex[iChannel]]; 03971 predictor = pWav->ima.predictor[iChannel]; 03972 03973 diff = step >> 3; 03974 if (nibble1 & 1) diff += step >> 2; 03975 if (nibble1 & 2) diff += step >> 1; 03976 if (nibble1 & 4) diff += step; 03977 if (nibble1 & 8) diff = -diff; 03978 03979 predictor = drwav_clamp(predictor + diff, -32768, 32767); 03980 pWav->ima.predictor[iChannel] = predictor; 03981 pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1); 03982 pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor; 03983 } 03984 } 03985 } 03986 } 03987 } 03988 03989 return totalFramesRead; 03990 } 03991 03992 03993 #ifndef DR_WAV_NO_CONVERSION_API 03994 static unsigned short g_drwavAlawTable[256] = { 03995 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, 03996 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, 03997 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, 03998 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, 03999 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, 04000 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, 04001 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, 04002 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, 04003 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, 04004 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, 04005 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, 04006 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, 04007 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, 04008 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, 04009 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, 04010 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 04011 }; 04012 04013 static unsigned short g_drwavMulawTable[256] = { 04014 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, 04015 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, 04016 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, 04017 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, 04018 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, 04019 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, 04020 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, 04021 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, 04022 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, 04023 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, 04024 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, 04025 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, 04026 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, 04027 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, 04028 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, 04029 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 04030 }; 04031 04032 static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) 04033 { 04034 return (short)g_drwavAlawTable[sampleIn]; 04035 } 04036 04037 static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) 04038 { 04039 return (short)g_drwavMulawTable[sampleIn]; 04040 } 04041 04042 04043 04044 static void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) 04045 { 04046 unsigned int i; 04047 04048 /* Special case for 8-bit sample data because it's treated as unsigned. */ 04049 if (bytesPerSample == 1) { 04050 drwav_u8_to_s16(pOut, pIn, totalSampleCount); 04051 return; 04052 } 04053 04054 04055 /* Slightly more optimal implementation for common formats. */ 04056 if (bytesPerSample == 2) { 04057 for (i = 0; i < totalSampleCount; ++i) { 04058 *pOut++ = ((const drwav_int16*)pIn)[i]; 04059 } 04060 return; 04061 } 04062 if (bytesPerSample == 3) { 04063 drwav_s24_to_s16(pOut, pIn, totalSampleCount); 04064 return; 04065 } 04066 if (bytesPerSample == 4) { 04067 drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); 04068 return; 04069 } 04070 04071 04072 /* Anything more than 64 bits per sample is not supported. */ 04073 if (bytesPerSample > 8) { 04074 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); 04075 return; 04076 } 04077 04078 04079 /* Generic, slow converter. */ 04080 for (i = 0; i < totalSampleCount; ++i) { 04081 drwav_uint64 sample = 0; 04082 unsigned int shift = (8 - bytesPerSample) * 8; 04083 04084 unsigned int j; 04085 for (j = 0; j < bytesPerSample; j += 1) { 04086 DRWAV_ASSERT(j < 8); 04087 sample |= (drwav_uint64)(pIn[j]) << shift; 04088 shift += 8; 04089 } 04090 04091 pIn += j; 04092 *pOut++ = (drwav_int16)((drwav_int64)sample >> 48); 04093 } 04094 } 04095 04096 static void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) 04097 { 04098 if (bytesPerSample == 4) { 04099 drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount); 04100 return; 04101 } else if (bytesPerSample == 8) { 04102 drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); 04103 return; 04104 } else { 04105 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ 04106 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); 04107 return; 04108 } 04109 } 04110 04111 static drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 04112 { 04113 drwav_uint32 bytesPerFrame; 04114 drwav_uint64 totalFramesRead; 04115 drwav_uint8 sampleData[4096]; 04116 04117 /* Fast path. */ 04118 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) { 04119 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); 04120 } 04121 04122 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04123 if (bytesPerFrame == 0) { 04124 return 0; 04125 } 04126 04127 totalFramesRead = 0; 04128 04129 while (framesToRead > 0) { 04130 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04131 if (framesRead == 0) { 04132 break; 04133 } 04134 04135 drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); 04136 04137 pBufferOut += framesRead*pWav->channels; 04138 framesToRead -= framesRead; 04139 totalFramesRead += framesRead; 04140 } 04141 04142 return totalFramesRead; 04143 } 04144 04145 static drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 04146 { 04147 drwav_uint64 totalFramesRead; 04148 drwav_uint8 sampleData[4096]; 04149 04150 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04151 if (bytesPerFrame == 0) { 04152 return 0; 04153 } 04154 04155 totalFramesRead = 0; 04156 04157 while (framesToRead > 0) { 04158 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04159 if (framesRead == 0) { 04160 break; 04161 } 04162 04163 drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); 04164 04165 pBufferOut += framesRead*pWav->channels; 04166 framesToRead -= framesRead; 04167 totalFramesRead += framesRead; 04168 } 04169 04170 return totalFramesRead; 04171 } 04172 04173 static drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 04174 { 04175 drwav_uint64 totalFramesRead; 04176 drwav_uint8 sampleData[4096]; 04177 04178 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04179 if (bytesPerFrame == 0) { 04180 return 0; 04181 } 04182 04183 totalFramesRead = 0; 04184 04185 while (framesToRead > 0) { 04186 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04187 if (framesRead == 0) { 04188 break; 04189 } 04190 04191 drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); 04192 04193 pBufferOut += framesRead*pWav->channels; 04194 framesToRead -= framesRead; 04195 totalFramesRead += framesRead; 04196 } 04197 04198 return totalFramesRead; 04199 } 04200 04201 static drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 04202 { 04203 drwav_uint64 totalFramesRead; 04204 drwav_uint8 sampleData[4096]; 04205 04206 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04207 if (bytesPerFrame == 0) { 04208 return 0; 04209 } 04210 04211 totalFramesRead = 0; 04212 04213 while (framesToRead > 0) { 04214 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04215 if (framesRead == 0) { 04216 break; 04217 } 04218 04219 drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); 04220 04221 pBufferOut += framesRead*pWav->channels; 04222 framesToRead -= framesRead; 04223 totalFramesRead += framesRead; 04224 } 04225 04226 return totalFramesRead; 04227 } 04228 04229 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 04230 { 04231 if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) { 04232 return 0; 04233 } 04234 04235 /* Don't try to read more samples than can potentially fit in the output buffer. */ 04236 if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) { 04237 framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels; 04238 } 04239 04240 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { 04241 return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut); 04242 } 04243 04244 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { 04245 return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut); 04246 } 04247 04248 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { 04249 return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut); 04250 } 04251 04252 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { 04253 return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut); 04254 } 04255 04256 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { 04257 return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut); 04258 } 04259 04260 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { 04261 return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut); 04262 } 04263 04264 return 0; 04265 } 04266 04267 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 04268 { 04269 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); 04270 if (!drwav__is_little_endian()) { 04271 drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); 04272 } 04273 04274 return framesRead; 04275 } 04276 04277 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) 04278 { 04279 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); 04280 if (drwav__is_little_endian()) { 04281 drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); 04282 } 04283 04284 return framesRead; 04285 } 04286 04287 04288 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) 04289 { 04290 int r; 04291 size_t i; 04292 for (i = 0; i < sampleCount; ++i) { 04293 int x = pIn[i]; 04294 r = x << 8; 04295 r = r - 32768; 04296 pOut[i] = (short)r; 04297 } 04298 } 04299 04300 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) 04301 { 04302 int r; 04303 size_t i; 04304 for (i = 0; i < sampleCount; ++i) { 04305 int x = ((int)(((unsigned int)(((const drwav_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+2])) << 24)) >> 8; 04306 r = x >> 8; 04307 pOut[i] = (short)r; 04308 } 04309 } 04310 04311 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount) 04312 { 04313 int r; 04314 size_t i; 04315 for (i = 0; i < sampleCount; ++i) { 04316 int x = pIn[i]; 04317 r = x >> 16; 04318 pOut[i] = (short)r; 04319 } 04320 } 04321 04322 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount) 04323 { 04324 int r; 04325 size_t i; 04326 for (i = 0; i < sampleCount; ++i) { 04327 float x = pIn[i]; 04328 float c; 04329 c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); 04330 c = c + 1; 04331 r = (int)(c * 32767.5f); 04332 r = r - 32768; 04333 pOut[i] = (short)r; 04334 } 04335 } 04336 04337 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount) 04338 { 04339 int r; 04340 size_t i; 04341 for (i = 0; i < sampleCount; ++i) { 04342 double x = pIn[i]; 04343 double c; 04344 c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); 04345 c = c + 1; 04346 r = (int)(c * 32767.5); 04347 r = r - 32768; 04348 pOut[i] = (short)r; 04349 } 04350 } 04351 04352 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) 04353 { 04354 size_t i; 04355 for (i = 0; i < sampleCount; ++i) { 04356 pOut[i] = drwav__alaw_to_s16(pIn[i]); 04357 } 04358 } 04359 04360 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) 04361 { 04362 size_t i; 04363 for (i = 0; i < sampleCount; ++i) { 04364 pOut[i] = drwav__mulaw_to_s16(pIn[i]); 04365 } 04366 } 04367 04368 04369 04370 static void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) 04371 { 04372 unsigned int i; 04373 04374 /* Special case for 8-bit sample data because it's treated as unsigned. */ 04375 if (bytesPerSample == 1) { 04376 drwav_u8_to_f32(pOut, pIn, sampleCount); 04377 return; 04378 } 04379 04380 /* Slightly more optimal implementation for common formats. */ 04381 if (bytesPerSample == 2) { 04382 drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount); 04383 return; 04384 } 04385 if (bytesPerSample == 3) { 04386 drwav_s24_to_f32(pOut, pIn, sampleCount); 04387 return; 04388 } 04389 if (bytesPerSample == 4) { 04390 drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount); 04391 return; 04392 } 04393 04394 04395 /* Anything more than 64 bits per sample is not supported. */ 04396 if (bytesPerSample > 8) { 04397 DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); 04398 return; 04399 } 04400 04401 04402 /* Generic, slow converter. */ 04403 for (i = 0; i < sampleCount; ++i) { 04404 drwav_uint64 sample = 0; 04405 unsigned int shift = (8 - bytesPerSample) * 8; 04406 04407 unsigned int j; 04408 for (j = 0; j < bytesPerSample; j += 1) { 04409 DRWAV_ASSERT(j < 8); 04410 sample |= (drwav_uint64)(pIn[j]) << shift; 04411 shift += 8; 04412 } 04413 04414 pIn += j; 04415 *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0); 04416 } 04417 } 04418 04419 static void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) 04420 { 04421 if (bytesPerSample == 4) { 04422 unsigned int i; 04423 for (i = 0; i < sampleCount; ++i) { 04424 *pOut++ = ((const float*)pIn)[i]; 04425 } 04426 return; 04427 } else if (bytesPerSample == 8) { 04428 drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount); 04429 return; 04430 } else { 04431 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ 04432 DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); 04433 return; 04434 } 04435 } 04436 04437 04438 static drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04439 { 04440 drwav_uint64 totalFramesRead; 04441 drwav_uint8 sampleData[4096]; 04442 04443 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04444 if (bytesPerFrame == 0) { 04445 return 0; 04446 } 04447 04448 totalFramesRead = 0; 04449 04450 while (framesToRead > 0) { 04451 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04452 if (framesRead == 0) { 04453 break; 04454 } 04455 04456 drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); 04457 04458 pBufferOut += framesRead*pWav->channels; 04459 framesToRead -= framesRead; 04460 totalFramesRead += framesRead; 04461 } 04462 04463 return totalFramesRead; 04464 } 04465 04466 static drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04467 { 04468 /* 04469 We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't 04470 want to duplicate that code. 04471 */ 04472 drwav_uint64 totalFramesRead = 0; 04473 drwav_int16 samples16[2048]; 04474 while (framesToRead > 0) { 04475 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); 04476 if (framesRead == 0) { 04477 break; 04478 } 04479 04480 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ 04481 04482 pBufferOut += framesRead*pWav->channels; 04483 framesToRead -= framesRead; 04484 totalFramesRead += framesRead; 04485 } 04486 04487 return totalFramesRead; 04488 } 04489 04490 static drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04491 { 04492 /* 04493 We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't 04494 want to duplicate that code. 04495 */ 04496 drwav_uint64 totalFramesRead = 0; 04497 drwav_int16 samples16[2048]; 04498 while (framesToRead > 0) { 04499 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); 04500 if (framesRead == 0) { 04501 break; 04502 } 04503 04504 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ 04505 04506 pBufferOut += framesRead*pWav->channels; 04507 framesToRead -= framesRead; 04508 totalFramesRead += framesRead; 04509 } 04510 04511 return totalFramesRead; 04512 } 04513 04514 static drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04515 { 04516 drwav_uint64 totalFramesRead; 04517 drwav_uint8 sampleData[4096]; 04518 drwav_uint32 bytesPerFrame; 04519 04520 /* Fast path. */ 04521 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { 04522 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); 04523 } 04524 04525 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04526 if (bytesPerFrame == 0) { 04527 return 0; 04528 } 04529 04530 totalFramesRead = 0; 04531 04532 while (framesToRead > 0) { 04533 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04534 if (framesRead == 0) { 04535 break; 04536 } 04537 04538 drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); 04539 04540 pBufferOut += framesRead*pWav->channels; 04541 framesToRead -= framesRead; 04542 totalFramesRead += framesRead; 04543 } 04544 04545 return totalFramesRead; 04546 } 04547 04548 static drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04549 { 04550 drwav_uint64 totalFramesRead; 04551 drwav_uint8 sampleData[4096]; 04552 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04553 if (bytesPerFrame == 0) { 04554 return 0; 04555 } 04556 04557 totalFramesRead = 0; 04558 04559 while (framesToRead > 0) { 04560 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04561 if (framesRead == 0) { 04562 break; 04563 } 04564 04565 drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); 04566 04567 pBufferOut += framesRead*pWav->channels; 04568 framesToRead -= framesRead; 04569 totalFramesRead += framesRead; 04570 } 04571 04572 return totalFramesRead; 04573 } 04574 04575 static drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04576 { 04577 drwav_uint64 totalFramesRead; 04578 drwav_uint8 sampleData[4096]; 04579 04580 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04581 if (bytesPerFrame == 0) { 04582 return 0; 04583 } 04584 04585 totalFramesRead = 0; 04586 04587 while (framesToRead > 0) { 04588 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04589 if (framesRead == 0) { 04590 break; 04591 } 04592 04593 drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); 04594 04595 pBufferOut += framesRead*pWav->channels; 04596 framesToRead -= framesRead; 04597 totalFramesRead += framesRead; 04598 } 04599 04600 return totalFramesRead; 04601 } 04602 04603 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04604 { 04605 if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) { 04606 return 0; 04607 } 04608 04609 /* Don't try to read more samples than can potentially fit in the output buffer. */ 04610 if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) { 04611 framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels; 04612 } 04613 04614 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { 04615 return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); 04616 } 04617 04618 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { 04619 return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); 04620 } 04621 04622 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { 04623 return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); 04624 } 04625 04626 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { 04627 return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut); 04628 } 04629 04630 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { 04631 return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); 04632 } 04633 04634 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { 04635 return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); 04636 } 04637 04638 return 0; 04639 } 04640 04641 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04642 { 04643 drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); 04644 if (!drwav__is_little_endian()) { 04645 drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); 04646 } 04647 04648 return framesRead; 04649 } 04650 04651 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) 04652 { 04653 drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); 04654 if (drwav__is_little_endian()) { 04655 drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); 04656 } 04657 04658 return framesRead; 04659 } 04660 04661 04662 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) 04663 { 04664 size_t i; 04665 04666 if (pOut == NULL || pIn == NULL) { 04667 return; 04668 } 04669 04670 #ifdef DR_WAV_LIBSNDFILE_COMPAT 04671 /* 04672 It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears 04673 libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note 04674 the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated 04675 correctness testing. This is disabled by default. 04676 */ 04677 for (i = 0; i < sampleCount; ++i) { 04678 *pOut++ = (pIn[i] / 256.0f) * 2 - 1; 04679 } 04680 #else 04681 for (i = 0; i < sampleCount; ++i) { 04682 float x = pIn[i]; 04683 x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */ 04684 x = x - 1; /* 0..2 to -1..1 */ 04685 04686 *pOut++ = x; 04687 } 04688 #endif 04689 } 04690 04691 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount) 04692 { 04693 size_t i; 04694 04695 if (pOut == NULL || pIn == NULL) { 04696 return; 04697 } 04698 04699 for (i = 0; i < sampleCount; ++i) { 04700 *pOut++ = pIn[i] * 0.000030517578125f; 04701 } 04702 } 04703 04704 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) 04705 { 04706 size_t i; 04707 04708 if (pOut == NULL || pIn == NULL) { 04709 return; 04710 } 04711 04712 for (i = 0; i < sampleCount; ++i) { 04713 double x = (double)(((drwav_int32)(((drwav_uint32)(pIn[i*3+0]) << 8) | ((drwav_uint32)(pIn[i*3+1]) << 16) | ((drwav_uint32)(pIn[i*3+2])) << 24)) >> 8); 04714 *pOut++ = (float)(x * 0.00000011920928955078125); 04715 } 04716 } 04717 04718 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount) 04719 { 04720 size_t i; 04721 if (pOut == NULL || pIn == NULL) { 04722 return; 04723 } 04724 04725 for (i = 0; i < sampleCount; ++i) { 04726 *pOut++ = (float)(pIn[i] / 2147483648.0); 04727 } 04728 } 04729 04730 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount) 04731 { 04732 size_t i; 04733 04734 if (pOut == NULL || pIn == NULL) { 04735 return; 04736 } 04737 04738 for (i = 0; i < sampleCount; ++i) { 04739 *pOut++ = (float)pIn[i]; 04740 } 04741 } 04742 04743 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) 04744 { 04745 size_t i; 04746 04747 if (pOut == NULL || pIn == NULL) { 04748 return; 04749 } 04750 04751 for (i = 0; i < sampleCount; ++i) { 04752 *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f; 04753 } 04754 } 04755 04756 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) 04757 { 04758 size_t i; 04759 04760 if (pOut == NULL || pIn == NULL) { 04761 return; 04762 } 04763 04764 for (i = 0; i < sampleCount; ++i) { 04765 *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f; 04766 } 04767 } 04768 04769 04770 04771 static void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) 04772 { 04773 unsigned int i; 04774 04775 /* Special case for 8-bit sample data because it's treated as unsigned. */ 04776 if (bytesPerSample == 1) { 04777 drwav_u8_to_s32(pOut, pIn, totalSampleCount); 04778 return; 04779 } 04780 04781 /* Slightly more optimal implementation for common formats. */ 04782 if (bytesPerSample == 2) { 04783 drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount); 04784 return; 04785 } 04786 if (bytesPerSample == 3) { 04787 drwav_s24_to_s32(pOut, pIn, totalSampleCount); 04788 return; 04789 } 04790 if (bytesPerSample == 4) { 04791 for (i = 0; i < totalSampleCount; ++i) { 04792 *pOut++ = ((const drwav_int32*)pIn)[i]; 04793 } 04794 return; 04795 } 04796 04797 04798 /* Anything more than 64 bits per sample is not supported. */ 04799 if (bytesPerSample > 8) { 04800 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); 04801 return; 04802 } 04803 04804 04805 /* Generic, slow converter. */ 04806 for (i = 0; i < totalSampleCount; ++i) { 04807 drwav_uint64 sample = 0; 04808 unsigned int shift = (8 - bytesPerSample) * 8; 04809 04810 unsigned int j; 04811 for (j = 0; j < bytesPerSample; j += 1) { 04812 DRWAV_ASSERT(j < 8); 04813 sample |= (drwav_uint64)(pIn[j]) << shift; 04814 shift += 8; 04815 } 04816 04817 pIn += j; 04818 *pOut++ = (drwav_int32)((drwav_int64)sample >> 32); 04819 } 04820 } 04821 04822 static void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) 04823 { 04824 if (bytesPerSample == 4) { 04825 drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount); 04826 return; 04827 } else if (bytesPerSample == 8) { 04828 drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); 04829 return; 04830 } else { 04831 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ 04832 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); 04833 return; 04834 } 04835 } 04836 04837 04838 static drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 04839 { 04840 drwav_uint64 totalFramesRead; 04841 drwav_uint8 sampleData[4096]; 04842 drwav_uint32 bytesPerFrame; 04843 04844 /* Fast path. */ 04845 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { 04846 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); 04847 } 04848 04849 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04850 if (bytesPerFrame == 0) { 04851 return 0; 04852 } 04853 04854 totalFramesRead = 0; 04855 04856 while (framesToRead > 0) { 04857 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04858 if (framesRead == 0) { 04859 break; 04860 } 04861 04862 drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); 04863 04864 pBufferOut += framesRead*pWav->channels; 04865 framesToRead -= framesRead; 04866 totalFramesRead += framesRead; 04867 } 04868 04869 return totalFramesRead; 04870 } 04871 04872 static drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 04873 { 04874 /* 04875 We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't 04876 want to duplicate that code. 04877 */ 04878 drwav_uint64 totalFramesRead = 0; 04879 drwav_int16 samples16[2048]; 04880 while (framesToRead > 0) { 04881 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); 04882 if (framesRead == 0) { 04883 break; 04884 } 04885 04886 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ 04887 04888 pBufferOut += framesRead*pWav->channels; 04889 framesToRead -= framesRead; 04890 totalFramesRead += framesRead; 04891 } 04892 04893 return totalFramesRead; 04894 } 04895 04896 static drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 04897 { 04898 /* 04899 We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't 04900 want to duplicate that code. 04901 */ 04902 drwav_uint64 totalFramesRead = 0; 04903 drwav_int16 samples16[2048]; 04904 while (framesToRead > 0) { 04905 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); 04906 if (framesRead == 0) { 04907 break; 04908 } 04909 04910 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ 04911 04912 pBufferOut += framesRead*pWav->channels; 04913 framesToRead -= framesRead; 04914 totalFramesRead += framesRead; 04915 } 04916 04917 return totalFramesRead; 04918 } 04919 04920 static drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 04921 { 04922 drwav_uint64 totalFramesRead; 04923 drwav_uint8 sampleData[4096]; 04924 04925 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04926 if (bytesPerFrame == 0) { 04927 return 0; 04928 } 04929 04930 totalFramesRead = 0; 04931 04932 while (framesToRead > 0) { 04933 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04934 if (framesRead == 0) { 04935 break; 04936 } 04937 04938 drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); 04939 04940 pBufferOut += framesRead*pWav->channels; 04941 framesToRead -= framesRead; 04942 totalFramesRead += framesRead; 04943 } 04944 04945 return totalFramesRead; 04946 } 04947 04948 static drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 04949 { 04950 drwav_uint64 totalFramesRead; 04951 drwav_uint8 sampleData[4096]; 04952 04953 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04954 if (bytesPerFrame == 0) { 04955 return 0; 04956 } 04957 04958 totalFramesRead = 0; 04959 04960 while (framesToRead > 0) { 04961 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04962 if (framesRead == 0) { 04963 break; 04964 } 04965 04966 drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); 04967 04968 pBufferOut += framesRead*pWav->channels; 04969 framesToRead -= framesRead; 04970 totalFramesRead += framesRead; 04971 } 04972 04973 return totalFramesRead; 04974 } 04975 04976 static drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 04977 { 04978 drwav_uint64 totalFramesRead; 04979 drwav_uint8 sampleData[4096]; 04980 04981 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); 04982 if (bytesPerFrame == 0) { 04983 return 0; 04984 } 04985 04986 totalFramesRead = 0; 04987 04988 while (framesToRead > 0) { 04989 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); 04990 if (framesRead == 0) { 04991 break; 04992 } 04993 04994 drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); 04995 04996 pBufferOut += framesRead*pWav->channels; 04997 framesToRead -= framesRead; 04998 totalFramesRead += framesRead; 04999 } 05000 05001 return totalFramesRead; 05002 } 05003 05004 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 05005 { 05006 if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) { 05007 return 0; 05008 } 05009 05010 /* Don't try to read more samples than can potentially fit in the output buffer. */ 05011 if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) { 05012 framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels; 05013 } 05014 05015 05016 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { 05017 return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); 05018 } 05019 05020 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { 05021 return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); 05022 } 05023 05024 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { 05025 return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); 05026 } 05027 05028 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { 05029 return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut); 05030 } 05031 05032 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { 05033 return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); 05034 } 05035 05036 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { 05037 return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); 05038 } 05039 05040 return 0; 05041 } 05042 05043 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 05044 { 05045 drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); 05046 if (!drwav__is_little_endian()) { 05047 drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); 05048 } 05049 05050 return framesRead; 05051 } 05052 05053 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) 05054 { 05055 drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); 05056 if (drwav__is_little_endian()) { 05057 drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); 05058 } 05059 05060 return framesRead; 05061 } 05062 05063 05064 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) 05065 { 05066 size_t i; 05067 05068 if (pOut == NULL || pIn == NULL) { 05069 return; 05070 } 05071 05072 for (i = 0; i < sampleCount; ++i) { 05073 *pOut++ = ((int)pIn[i] - 128) << 24; 05074 } 05075 } 05076 05077 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount) 05078 { 05079 size_t i; 05080 05081 if (pOut == NULL || pIn == NULL) { 05082 return; 05083 } 05084 05085 for (i = 0; i < sampleCount; ++i) { 05086 *pOut++ = pIn[i] << 16; 05087 } 05088 } 05089 05090 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) 05091 { 05092 size_t i; 05093 05094 if (pOut == NULL || pIn == NULL) { 05095 return; 05096 } 05097 05098 for (i = 0; i < sampleCount; ++i) { 05099 unsigned int s0 = pIn[i*3 + 0]; 05100 unsigned int s1 = pIn[i*3 + 1]; 05101 unsigned int s2 = pIn[i*3 + 2]; 05102 05103 drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24)); 05104 *pOut++ = sample32; 05105 } 05106 } 05107 05108 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount) 05109 { 05110 size_t i; 05111 05112 if (pOut == NULL || pIn == NULL) { 05113 return; 05114 } 05115 05116 for (i = 0; i < sampleCount; ++i) { 05117 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); 05118 } 05119 } 05120 05121 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount) 05122 { 05123 size_t i; 05124 05125 if (pOut == NULL || pIn == NULL) { 05126 return; 05127 } 05128 05129 for (i = 0; i < sampleCount; ++i) { 05130 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); 05131 } 05132 } 05133 05134 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) 05135 { 05136 size_t i; 05137 05138 if (pOut == NULL || pIn == NULL) { 05139 return; 05140 } 05141 05142 for (i = 0; i < sampleCount; ++i) { 05143 *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16; 05144 } 05145 } 05146 05147 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) 05148 { 05149 size_t i; 05150 05151 if (pOut == NULL || pIn == NULL) { 05152 return; 05153 } 05154 05155 for (i= 0; i < sampleCount; ++i) { 05156 *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16; 05157 } 05158 } 05159 05160 05161 05162 static drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) 05163 { 05164 drwav_uint64 sampleDataSize; 05165 drwav_int16* pSampleData; 05166 drwav_uint64 framesRead; 05167 05168 DRWAV_ASSERT(pWav != NULL); 05169 05170 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16); 05171 if (sampleDataSize > DRWAV_SIZE_MAX) { 05172 drwav_uninit(pWav); 05173 return NULL; /* File's too big. */ 05174 } 05175 05176 pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ 05177 if (pSampleData == NULL) { 05178 drwav_uninit(pWav); 05179 return NULL; /* Failed to allocate memory. */ 05180 } 05181 05182 framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); 05183 if (framesRead != pWav->totalPCMFrameCount) { 05184 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); 05185 drwav_uninit(pWav); 05186 return NULL; /* There was an error reading the samples. */ 05187 } 05188 05189 drwav_uninit(pWav); 05190 05191 if (sampleRate) { 05192 *sampleRate = pWav->sampleRate; 05193 } 05194 if (channels) { 05195 *channels = pWav->channels; 05196 } 05197 if (totalFrameCount) { 05198 *totalFrameCount = pWav->totalPCMFrameCount; 05199 } 05200 05201 return pSampleData; 05202 } 05203 05204 static float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) 05205 { 05206 drwav_uint64 sampleDataSize; 05207 float* pSampleData; 05208 drwav_uint64 framesRead; 05209 05210 DRWAV_ASSERT(pWav != NULL); 05211 05212 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float); 05213 if (sampleDataSize > DRWAV_SIZE_MAX) { 05214 drwav_uninit(pWav); 05215 return NULL; /* File's too big. */ 05216 } 05217 05218 pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ 05219 if (pSampleData == NULL) { 05220 drwav_uninit(pWav); 05221 return NULL; /* Failed to allocate memory. */ 05222 } 05223 05224 framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); 05225 if (framesRead != pWav->totalPCMFrameCount) { 05226 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); 05227 drwav_uninit(pWav); 05228 return NULL; /* There was an error reading the samples. */ 05229 } 05230 05231 drwav_uninit(pWav); 05232 05233 if (sampleRate) { 05234 *sampleRate = pWav->sampleRate; 05235 } 05236 if (channels) { 05237 *channels = pWav->channels; 05238 } 05239 if (totalFrameCount) { 05240 *totalFrameCount = pWav->totalPCMFrameCount; 05241 } 05242 05243 return pSampleData; 05244 } 05245 05246 static drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) 05247 { 05248 drwav_uint64 sampleDataSize; 05249 drwav_int32* pSampleData; 05250 drwav_uint64 framesRead; 05251 05252 DRWAV_ASSERT(pWav != NULL); 05253 05254 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32); 05255 if (sampleDataSize > DRWAV_SIZE_MAX) { 05256 drwav_uninit(pWav); 05257 return NULL; /* File's too big. */ 05258 } 05259 05260 pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ 05261 if (pSampleData == NULL) { 05262 drwav_uninit(pWav); 05263 return NULL; /* Failed to allocate memory. */ 05264 } 05265 05266 framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); 05267 if (framesRead != pWav->totalPCMFrameCount) { 05268 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); 05269 drwav_uninit(pWav); 05270 return NULL; /* There was an error reading the samples. */ 05271 } 05272 05273 drwav_uninit(pWav); 05274 05275 if (sampleRate) { 05276 *sampleRate = pWav->sampleRate; 05277 } 05278 if (channels) { 05279 *channels = pWav->channels; 05280 } 05281 if (totalFrameCount) { 05282 *totalFrameCount = pWav->totalPCMFrameCount; 05283 } 05284 05285 return pSampleData; 05286 } 05287 05288 05289 05290 DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05291 { 05292 drwav wav; 05293 05294 if (channelsOut) { 05295 *channelsOut = 0; 05296 } 05297 if (sampleRateOut) { 05298 *sampleRateOut = 0; 05299 } 05300 if (totalFrameCountOut) { 05301 *totalFrameCountOut = 0; 05302 } 05303 05304 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { 05305 return NULL; 05306 } 05307 05308 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05309 } 05310 05311 DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05312 { 05313 drwav wav; 05314 05315 if (channelsOut) { 05316 *channelsOut = 0; 05317 } 05318 if (sampleRateOut) { 05319 *sampleRateOut = 0; 05320 } 05321 if (totalFrameCountOut) { 05322 *totalFrameCountOut = 0; 05323 } 05324 05325 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { 05326 return NULL; 05327 } 05328 05329 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05330 } 05331 05332 DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05333 { 05334 drwav wav; 05335 05336 if (channelsOut) { 05337 *channelsOut = 0; 05338 } 05339 if (sampleRateOut) { 05340 *sampleRateOut = 0; 05341 } 05342 if (totalFrameCountOut) { 05343 *totalFrameCountOut = 0; 05344 } 05345 05346 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { 05347 return NULL; 05348 } 05349 05350 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05351 } 05352 05353 #ifndef DR_WAV_NO_STDIO 05354 DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05355 { 05356 drwav wav; 05357 05358 if (channelsOut) { 05359 *channelsOut = 0; 05360 } 05361 if (sampleRateOut) { 05362 *sampleRateOut = 0; 05363 } 05364 if (totalFrameCountOut) { 05365 *totalFrameCountOut = 0; 05366 } 05367 05368 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { 05369 return NULL; 05370 } 05371 05372 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05373 } 05374 05375 DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05376 { 05377 drwav wav; 05378 05379 if (channelsOut) { 05380 *channelsOut = 0; 05381 } 05382 if (sampleRateOut) { 05383 *sampleRateOut = 0; 05384 } 05385 if (totalFrameCountOut) { 05386 *totalFrameCountOut = 0; 05387 } 05388 05389 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { 05390 return NULL; 05391 } 05392 05393 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05394 } 05395 05396 DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05397 { 05398 drwav wav; 05399 05400 if (channelsOut) { 05401 *channelsOut = 0; 05402 } 05403 if (sampleRateOut) { 05404 *sampleRateOut = 0; 05405 } 05406 if (totalFrameCountOut) { 05407 *totalFrameCountOut = 0; 05408 } 05409 05410 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { 05411 return NULL; 05412 } 05413 05414 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05415 } 05416 05417 05418 DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05419 { 05420 drwav wav; 05421 05422 if (sampleRateOut) { 05423 *sampleRateOut = 0; 05424 } 05425 if (channelsOut) { 05426 *channelsOut = 0; 05427 } 05428 if (totalFrameCountOut) { 05429 *totalFrameCountOut = 0; 05430 } 05431 05432 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { 05433 return NULL; 05434 } 05435 05436 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05437 } 05438 05439 DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05440 { 05441 drwav wav; 05442 05443 if (sampleRateOut) { 05444 *sampleRateOut = 0; 05445 } 05446 if (channelsOut) { 05447 *channelsOut = 0; 05448 } 05449 if (totalFrameCountOut) { 05450 *totalFrameCountOut = 0; 05451 } 05452 05453 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { 05454 return NULL; 05455 } 05456 05457 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05458 } 05459 05460 DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05461 { 05462 drwav wav; 05463 05464 if (sampleRateOut) { 05465 *sampleRateOut = 0; 05466 } 05467 if (channelsOut) { 05468 *channelsOut = 0; 05469 } 05470 if (totalFrameCountOut) { 05471 *totalFrameCountOut = 0; 05472 } 05473 05474 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { 05475 return NULL; 05476 } 05477 05478 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05479 } 05480 #endif 05481 05482 DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05483 { 05484 drwav wav; 05485 05486 if (channelsOut) { 05487 *channelsOut = 0; 05488 } 05489 if (sampleRateOut) { 05490 *sampleRateOut = 0; 05491 } 05492 if (totalFrameCountOut) { 05493 *totalFrameCountOut = 0; 05494 } 05495 05496 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { 05497 return NULL; 05498 } 05499 05500 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05501 } 05502 05503 DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05504 { 05505 drwav wav; 05506 05507 if (channelsOut) { 05508 *channelsOut = 0; 05509 } 05510 if (sampleRateOut) { 05511 *sampleRateOut = 0; 05512 } 05513 if (totalFrameCountOut) { 05514 *totalFrameCountOut = 0; 05515 } 05516 05517 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { 05518 return NULL; 05519 } 05520 05521 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05522 } 05523 05524 DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) 05525 { 05526 drwav wav; 05527 05528 if (channelsOut) { 05529 *channelsOut = 0; 05530 } 05531 if (sampleRateOut) { 05532 *sampleRateOut = 0; 05533 } 05534 if (totalFrameCountOut) { 05535 *totalFrameCountOut = 0; 05536 } 05537 05538 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { 05539 return NULL; 05540 } 05541 05542 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); 05543 } 05544 #endif /* DR_WAV_NO_CONVERSION_API */ 05545 05546 05547 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) 05548 { 05549 if (pAllocationCallbacks != NULL) { 05550 drwav__free_from_callbacks(p, pAllocationCallbacks); 05551 } else { 05552 drwav__free_default(p, NULL); 05553 } 05554 } 05555 05556 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data) 05557 { 05558 return drwav__bytes_to_u16(data); 05559 } 05560 05561 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data) 05562 { 05563 return drwav__bytes_to_s16(data); 05564 } 05565 05566 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data) 05567 { 05568 return drwav__bytes_to_u32(data); 05569 } 05570 05571 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data) 05572 { 05573 return drwav__bytes_to_s32(data); 05574 } 05575 05576 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data) 05577 { 05578 return drwav__bytes_to_u64(data); 05579 } 05580 05581 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data) 05582 { 05583 return drwav__bytes_to_s64(data); 05584 } 05585 05586 05587 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) 05588 { 05589 return drwav__guid_equal(a, b); 05590 } 05591 05592 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) 05593 { 05594 return drwav__fourcc_equal(a, b); 05595 } 05596 05597 #endif /* DR_WAV_IMPLEMENTATION */ 05598 05599 /* 05600 RELEASE NOTES - v0.11.0 05601 ======================= 05602 Version 0.11.0 has breaking API changes. 05603 05604 Improved Client-Defined Memory Allocation 05605 ----------------------------------------- 05606 The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The 05607 existing system of DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE are still in place and will be used by default when no custom 05608 allocation callbacks are specified. 05609 05610 To use the new system, you pass in a pointer to a drwav_allocation_callbacks object to drwav_init() and family, like this: 05611 05612 void* my_malloc(size_t sz, void* pUserData) 05613 { 05614 return malloc(sz); 05615 } 05616 void* my_realloc(void* p, size_t sz, void* pUserData) 05617 { 05618 return realloc(p, sz); 05619 } 05620 void my_free(void* p, void* pUserData) 05621 { 05622 free(p); 05623 } 05624 05625 ... 05626 05627 drwav_allocation_callbacks allocationCallbacks; 05628 allocationCallbacks.pUserData = &myData; 05629 allocationCallbacks.onMalloc = my_malloc; 05630 allocationCallbacks.onRealloc = my_realloc; 05631 allocationCallbacks.onFree = my_free; 05632 drwav_init_file(&wav, "my_file.wav", &allocationCallbacks); 05633 05634 The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines. 05635 05636 Passing in null for the allocation callbacks object will cause dr_wav to use defaults which is the same as DRWAV_MALLOC, 05637 DRWAV_REALLOC and DRWAV_FREE and the equivalent of how it worked in previous versions. 05638 05639 Every API that opens a drwav object now takes this extra parameter. These include the following: 05640 05641 drwav_init() 05642 drwav_init_ex() 05643 drwav_init_file() 05644 drwav_init_file_ex() 05645 drwav_init_file_w() 05646 drwav_init_file_w_ex() 05647 drwav_init_memory() 05648 drwav_init_memory_ex() 05649 drwav_init_write() 05650 drwav_init_write_sequential() 05651 drwav_init_write_sequential_pcm_frames() 05652 drwav_init_file_write() 05653 drwav_init_file_write_sequential() 05654 drwav_init_file_write_sequential_pcm_frames() 05655 drwav_init_file_write_w() 05656 drwav_init_file_write_sequential_w() 05657 drwav_init_file_write_sequential_pcm_frames_w() 05658 drwav_init_memory_write() 05659 drwav_init_memory_write_sequential() 05660 drwav_init_memory_write_sequential_pcm_frames() 05661 drwav_open_and_read_pcm_frames_s16() 05662 drwav_open_and_read_pcm_frames_f32() 05663 drwav_open_and_read_pcm_frames_s32() 05664 drwav_open_file_and_read_pcm_frames_s16() 05665 drwav_open_file_and_read_pcm_frames_f32() 05666 drwav_open_file_and_read_pcm_frames_s32() 05667 drwav_open_file_and_read_pcm_frames_s16_w() 05668 drwav_open_file_and_read_pcm_frames_f32_w() 05669 drwav_open_file_and_read_pcm_frames_s32_w() 05670 drwav_open_memory_and_read_pcm_frames_s16() 05671 drwav_open_memory_and_read_pcm_frames_f32() 05672 drwav_open_memory_and_read_pcm_frames_s32() 05673 05674 Endian Improvements 05675 ------------------- 05676 Previously, the following APIs returned little-endian audio data. These now return native-endian data. This improves compatibility 05677 on big-endian architectures. 05678 05679 drwav_read_pcm_frames() 05680 drwav_read_pcm_frames_s16() 05681 drwav_read_pcm_frames_s32() 05682 drwav_read_pcm_frames_f32() 05683 drwav_open_and_read_pcm_frames_s16() 05684 drwav_open_and_read_pcm_frames_s32() 05685 drwav_open_and_read_pcm_frames_f32() 05686 drwav_open_file_and_read_pcm_frames_s16() 05687 drwav_open_file_and_read_pcm_frames_s32() 05688 drwav_open_file_and_read_pcm_frames_f32() 05689 drwav_open_file_and_read_pcm_frames_s16_w() 05690 drwav_open_file_and_read_pcm_frames_s32_w() 05691 drwav_open_file_and_read_pcm_frames_f32_w() 05692 drwav_open_memory_and_read_pcm_frames_s16() 05693 drwav_open_memory_and_read_pcm_frames_s32() 05694 drwav_open_memory_and_read_pcm_frames_f32() 05695 05696 APIs have been added to give you explicit control over whether or not audio data is read or written in big- or little-endian byte 05697 order: 05698 05699 drwav_read_pcm_frames_le() 05700 drwav_read_pcm_frames_be() 05701 drwav_read_pcm_frames_s16le() 05702 drwav_read_pcm_frames_s16be() 05703 drwav_read_pcm_frames_f32le() 05704 drwav_read_pcm_frames_f32be() 05705 drwav_read_pcm_frames_s32le() 05706 drwav_read_pcm_frames_s32be() 05707 drwav_write_pcm_frames_le() 05708 drwav_write_pcm_frames_be() 05709 05710 Removed APIs 05711 ------------ 05712 The following APIs were deprecated in version 0.10.0 and have now been removed: 05713 05714 drwav_open() 05715 drwav_open_ex() 05716 drwav_open_write() 05717 drwav_open_write_sequential() 05718 drwav_open_file() 05719 drwav_open_file_ex() 05720 drwav_open_file_write() 05721 drwav_open_file_write_sequential() 05722 drwav_open_memory() 05723 drwav_open_memory_ex() 05724 drwav_open_memory_write() 05725 drwav_open_memory_write_sequential() 05726 drwav_close() 05727 05728 05729 05730 RELEASE NOTES - v0.10.0 05731 ======================= 05732 Version 0.10.0 has breaking API changes. There are no significant bug fixes in this release, so if you are affected you do 05733 not need to upgrade. 05734 05735 Removed APIs 05736 ------------ 05737 The following APIs were deprecated in version 0.9.0 and have been completely removed in version 0.10.0: 05738 05739 drwav_read() 05740 drwav_read_s16() 05741 drwav_read_f32() 05742 drwav_read_s32() 05743 drwav_seek_to_sample() 05744 drwav_write() 05745 drwav_open_and_read_s16() 05746 drwav_open_and_read_f32() 05747 drwav_open_and_read_s32() 05748 drwav_open_file_and_read_s16() 05749 drwav_open_file_and_read_f32() 05750 drwav_open_file_and_read_s32() 05751 drwav_open_memory_and_read_s16() 05752 drwav_open_memory_and_read_f32() 05753 drwav_open_memory_and_read_s32() 05754 drwav::totalSampleCount 05755 05756 See release notes for version 0.9.0 at the bottom of this file for replacement APIs. 05757 05758 Deprecated APIs 05759 --------------- 05760 The following APIs have been deprecated. There is a confusing and completely arbitrary difference between drwav_init*() and 05761 drwav_open*(), where drwav_init*() initializes a pre-allocated drwav object, whereas drwav_open*() will first allocated a 05762 drwav object on the heap and then initialize it. drwav_open*() has been deprecated which means you must now use a pre- 05763 allocated drwav object with drwav_init*(). If you need the previous functionality, you can just do a malloc() followed by 05764 a called to one of the drwav_init*() APIs. 05765 05766 drwav_open() 05767 drwav_open_ex() 05768 drwav_open_write() 05769 drwav_open_write_sequential() 05770 drwav_open_file() 05771 drwav_open_file_ex() 05772 drwav_open_file_write() 05773 drwav_open_file_write_sequential() 05774 drwav_open_memory() 05775 drwav_open_memory_ex() 05776 drwav_open_memory_write() 05777 drwav_open_memory_write_sequential() 05778 drwav_close() 05779 05780 These APIs will be removed completely in a future version. The rationale for this change is to remove confusion between the 05781 two different ways to initialize a drwav object. 05782 */ 05783 05784 /* 05785 REVISION HISTORY 05786 ================ 05787 v0.12.4 - 2020-05-16 05788 - Replace assert() with DRWAV_ASSERT(). 05789 - Add compile-time and run-time version querying. 05790 - DRWAV_VERSION_MINOR 05791 - DRWAV_VERSION_MAJOR 05792 - DRWAV_VERSION_REVISION 05793 - DRWAV_VERSION_STRING 05794 - drwav_version() 05795 - drwav_version_string() 05796 05797 v0.12.3 - 2020-04-30 05798 - Fix compilation errors with VC6. 05799 05800 v0.12.2 - 2020-04-21 05801 - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file. 05802 05803 v0.12.1 - 2020-04-13 05804 - Fix some pedantic warnings. 05805 05806 v0.12.0 - 2020-04-04 05807 - API CHANGE: Add container and format parameters to the chunk callback. 05808 - Minor documentation updates. 05809 05810 v0.11.5 - 2020-03-07 05811 - Fix compilation error with Visual Studio .NET 2003. 05812 05813 v0.11.4 - 2020-01-29 05814 - Fix some static analysis warnings. 05815 - Fix a bug when reading f32 samples from an A-law encoded stream. 05816 05817 v0.11.3 - 2020-01-12 05818 - Minor changes to some f32 format conversion routines. 05819 - Minor bug fix for ADPCM conversion when end of file is reached. 05820 05821 v0.11.2 - 2019-12-02 05822 - Fix a possible crash when using custom memory allocators without a custom realloc() implementation. 05823 - Fix an integer overflow bug. 05824 - Fix a null pointer dereference bug. 05825 - Add limits to sample rate, channels and bits per sample to tighten up some validation. 05826 05827 v0.11.1 - 2019-10-07 05828 - Internal code clean up. 05829 05830 v0.11.0 - 2019-10-06 05831 - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation 05832 routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs: 05833 - drwav_init() 05834 - drwav_init_ex() 05835 - drwav_init_file() 05836 - drwav_init_file_ex() 05837 - drwav_init_file_w() 05838 - drwav_init_file_w_ex() 05839 - drwav_init_memory() 05840 - drwav_init_memory_ex() 05841 - drwav_init_write() 05842 - drwav_init_write_sequential() 05843 - drwav_init_write_sequential_pcm_frames() 05844 - drwav_init_file_write() 05845 - drwav_init_file_write_sequential() 05846 - drwav_init_file_write_sequential_pcm_frames() 05847 - drwav_init_file_write_w() 05848 - drwav_init_file_write_sequential_w() 05849 - drwav_init_file_write_sequential_pcm_frames_w() 05850 - drwav_init_memory_write() 05851 - drwav_init_memory_write_sequential() 05852 - drwav_init_memory_write_sequential_pcm_frames() 05853 - drwav_open_and_read_pcm_frames_s16() 05854 - drwav_open_and_read_pcm_frames_f32() 05855 - drwav_open_and_read_pcm_frames_s32() 05856 - drwav_open_file_and_read_pcm_frames_s16() 05857 - drwav_open_file_and_read_pcm_frames_f32() 05858 - drwav_open_file_and_read_pcm_frames_s32() 05859 - drwav_open_file_and_read_pcm_frames_s16_w() 05860 - drwav_open_file_and_read_pcm_frames_f32_w() 05861 - drwav_open_file_and_read_pcm_frames_s32_w() 05862 - drwav_open_memory_and_read_pcm_frames_s16() 05863 - drwav_open_memory_and_read_pcm_frames_f32() 05864 - drwav_open_memory_and_read_pcm_frames_s32() 05865 Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use 05866 DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE. 05867 - Add support for reading and writing PCM frames in an explicit endianness. New APIs: 05868 - drwav_read_pcm_frames_le() 05869 - drwav_read_pcm_frames_be() 05870 - drwav_read_pcm_frames_s16le() 05871 - drwav_read_pcm_frames_s16be() 05872 - drwav_read_pcm_frames_f32le() 05873 - drwav_read_pcm_frames_f32be() 05874 - drwav_read_pcm_frames_s32le() 05875 - drwav_read_pcm_frames_s32be() 05876 - drwav_write_pcm_frames_le() 05877 - drwav_write_pcm_frames_be() 05878 - Remove deprecated APIs. 05879 - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data. 05880 - drwav_read_pcm_frames() 05881 - drwav_read_pcm_frames_s16() 05882 - drwav_read_pcm_frames_s32() 05883 - drwav_read_pcm_frames_f32() 05884 - drwav_open_and_read_pcm_frames_s16() 05885 - drwav_open_and_read_pcm_frames_s32() 05886 - drwav_open_and_read_pcm_frames_f32() 05887 - drwav_open_file_and_read_pcm_frames_s16() 05888 - drwav_open_file_and_read_pcm_frames_s32() 05889 - drwav_open_file_and_read_pcm_frames_f32() 05890 - drwav_open_file_and_read_pcm_frames_s16_w() 05891 - drwav_open_file_and_read_pcm_frames_s32_w() 05892 - drwav_open_file_and_read_pcm_frames_f32_w() 05893 - drwav_open_memory_and_read_pcm_frames_s16() 05894 - drwav_open_memory_and_read_pcm_frames_s32() 05895 - drwav_open_memory_and_read_pcm_frames_f32() 05896 05897 v0.10.1 - 2019-08-31 05898 - Correctly handle partial trailing ADPCM blocks. 05899 05900 v0.10.0 - 2019-08-04 05901 - Remove deprecated APIs. 05902 - Add wchar_t variants for file loading APIs: 05903 drwav_init_file_w() 05904 drwav_init_file_ex_w() 05905 drwav_init_file_write_w() 05906 drwav_init_file_write_sequential_w() 05907 - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count. 05908 - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode: 05909 drwav_init_write_sequential_pcm_frames() 05910 drwav_init_file_write_sequential_pcm_frames() 05911 drwav_init_file_write_sequential_pcm_frames_w() 05912 drwav_init_memory_write_sequential_pcm_frames() 05913 - Deprecate drwav_open*() and drwav_close(): 05914 drwav_open() 05915 drwav_open_ex() 05916 drwav_open_write() 05917 drwav_open_write_sequential() 05918 drwav_open_file() 05919 drwav_open_file_ex() 05920 drwav_open_file_write() 05921 drwav_open_file_write_sequential() 05922 drwav_open_memory() 05923 drwav_open_memory_ex() 05924 drwav_open_memory_write() 05925 drwav_open_memory_write_sequential() 05926 drwav_close() 05927 - Minor documentation updates. 05928 05929 v0.9.2 - 2019-05-21 05930 - Fix warnings. 05931 05932 v0.9.1 - 2019-05-05 05933 - Add support for C89. 05934 - Change license to choice of public domain or MIT-0. 05935 05936 v0.9.0 - 2018-12-16 05937 - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and 05938 will be removed in v0.10.0. Deprecated APIs and their replacements: 05939 drwav_read() -> drwav_read_pcm_frames() 05940 drwav_read_s16() -> drwav_read_pcm_frames_s16() 05941 drwav_read_f32() -> drwav_read_pcm_frames_f32() 05942 drwav_read_s32() -> drwav_read_pcm_frames_s32() 05943 drwav_seek_to_sample() -> drwav_seek_to_pcm_frame() 05944 drwav_write() -> drwav_write_pcm_frames() 05945 drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16() 05946 drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32() 05947 drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32() 05948 drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16() 05949 drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32() 05950 drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32() 05951 drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16() 05952 drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32() 05953 drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32() 05954 drwav::totalSampleCount -> drwav::totalPCMFrameCount 05955 - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*(). 05956 - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*(). 05957 - Add built-in support for smpl chunks. 05958 - Add support for firing a callback for each chunk in the file at initialization time. 05959 - This is enabled through the drwav_init_ex(), etc. family of APIs. 05960 - Handle invalid FMT chunks more robustly. 05961 05962 v0.8.5 - 2018-09-11 05963 - Const correctness. 05964 - Fix a potential stack overflow. 05965 05966 v0.8.4 - 2018-08-07 05967 - Improve 64-bit detection. 05968 05969 v0.8.3 - 2018-08-05 05970 - Fix C++ build on older versions of GCC. 05971 05972 v0.8.2 - 2018-08-02 05973 - Fix some big-endian bugs. 05974 05975 v0.8.1 - 2018-06-29 05976 - Add support for sequential writing APIs. 05977 - Disable seeking in write mode. 05978 - Fix bugs with Wave64. 05979 - Fix typos. 05980 05981 v0.8 - 2018-04-27 05982 - Bug fix. 05983 - Start using major.minor.revision versioning. 05984 05985 v0.7f - 2018-02-05 05986 - Restrict ADPCM formats to a maximum of 2 channels. 05987 05988 v0.7e - 2018-02-02 05989 - Fix a crash. 05990 05991 v0.7d - 2018-02-01 05992 - Fix a crash. 05993 05994 v0.7c - 2018-02-01 05995 - Set drwav.bytesPerSample to 0 for all compressed formats. 05996 - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for 05997 all format conversion reading APIs (*_s16, *_s32, *_f32 APIs). 05998 - Fix some divide-by-zero errors. 05999 06000 v0.7b - 2018-01-22 06001 - Fix errors with seeking of compressed formats. 06002 - Fix compilation error when DR_WAV_NO_CONVERSION_API 06003 06004 v0.7a - 2017-11-17 06005 - Fix some GCC warnings. 06006 06007 v0.7 - 2017-11-04 06008 - Add writing APIs. 06009 06010 v0.6 - 2017-08-16 06011 - API CHANGE: Rename dr_* types to drwav_*. 06012 - Add support for custom implementations of malloc(), realloc(), etc. 06013 - Add support for Microsoft ADPCM. 06014 - Add support for IMA ADPCM (DVI, format code 0x11). 06015 - Optimizations to drwav_read_s16(). 06016 - Bug fixes. 06017 06018 v0.5g - 2017-07-16 06019 - Change underlying type for booleans to unsigned. 06020 06021 v0.5f - 2017-04-04 06022 - Fix a minor bug with drwav_open_and_read_s16() and family. 06023 06024 v0.5e - 2016-12-29 06025 - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this. 06026 - Minor fixes to documentation. 06027 06028 v0.5d - 2016-12-28 06029 - Use drwav_int* and drwav_uint* sized types to improve compiler support. 06030 06031 v0.5c - 2016-11-11 06032 - Properly handle JUNK chunks that come before the FMT chunk. 06033 06034 v0.5b - 2016-10-23 06035 - A minor change to drwav_bool8 and drwav_bool32 types. 06036 06037 v0.5a - 2016-10-11 06038 - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering. 06039 - Improve A-law and mu-law efficiency. 06040 06041 v0.5 - 2016-09-29 06042 - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to 06043 keep it consistent with dr_audio and dr_flac. 06044 06045 v0.4b - 2016-09-18 06046 - Fixed a typo in documentation. 06047 06048 v0.4a - 2016-09-18 06049 - Fixed a typo. 06050 - Change date format to ISO 8601 (YYYY-MM-DD) 06051 06052 v0.4 - 2016-07-13 06053 - API CHANGE. Make onSeek consistent with dr_flac. 06054 - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac. 06055 - Added support for Sony Wave64. 06056 06057 v0.3a - 2016-05-28 06058 - API CHANGE. Return drwav_bool32 instead of int in onSeek callback. 06059 - Fixed a memory leak. 06060 06061 v0.3 - 2016-05-22 06062 - Lots of API changes for consistency. 06063 06064 v0.2a - 2016-05-16 06065 - Fixed Linux/GCC build. 06066 06067 v0.2 - 2016-05-11 06068 - Added support for reading data as signed 32-bit PCM for consistency with dr_flac. 06069 06070 v0.1a - 2016-05-07 06071 - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. 06072 06073 v0.1 - 2016-05-04 06074 - Initial versioned release. 06075 */ 06076 06077 /* 06078 This software is available as a choice of the following licenses. Choose 06079 whichever you prefer. 06080 06081 =============================================================================== 06082 ALTERNATIVE 1 - Public Domain (www.unlicense.org) 06083 =============================================================================== 06084 This is free and unencumbered software released into the public domain. 06085 06086 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 06087 software, either in source code form or as a compiled binary, for any purpose, 06088 commercial or non-commercial, and by any means. 06089 06090 In jurisdictions that recognize copyright laws, the author or authors of this 06091 software dedicate any and all copyright interest in the software to the public 06092 domain. We make this dedication for the benefit of the public at large and to 06093 the detriment of our heirs and successors. We intend this dedication to be an 06094 overt act of relinquishment in perpetuity of all present and future rights to 06095 this software under copyright law. 06096 06097 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 06098 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 06099 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 06100 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 06101 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 06102 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 06103 06104 For more information, please refer to <http://unlicense.org/> 06105 06106 =============================================================================== 06107 ALTERNATIVE 2 - MIT No Attribution 06108 =============================================================================== 06109 Copyright 2020 David Reid 06110 06111 Permission is hereby granted, free of charge, to any person obtaining a copy of 06112 this software and associated documentation files (the "Software"), to deal in 06113 the Software without restriction, including without limitation the rights to 06114 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 06115 of the Software, and to permit persons to whom the Software is furnished to do 06116 so. 06117 06118 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 06119 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 06120 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 06121 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 06122 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 06123 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 06124 SOFTWARE. 06125 */