diff options
| author | David Reid <[email protected]> | 2018-04-21 17:34:56 +1000 |
|---|---|---|
| committer | David Reid <[email protected]> | 2018-04-21 18:57:00 +1000 |
| commit | 0febaa2446f81744b133349b15a19367daacab07 (patch) | |
| tree | 19dc1356008556b00eace05691f2bdcfa23ff622 /src/external/dr_wav.h | |
| parent | f5ebbfb6bc80e5d5555e84ee505ff794c2bc64b6 (diff) | |
| download | raylib-0febaa2446f81744b133349b15a19367daacab07.tar.gz raylib-0febaa2446f81744b133349b15a19367daacab07.zip | |
Update external audio libraries.
Diffstat (limited to 'src/external/dr_wav.h')
| -rw-r--r-- | src/external/dr_wav.h | 466 |
1 files changed, 285 insertions, 181 deletions
diff --git a/src/external/dr_wav.h b/src/external/dr_wav.h index 536df8f3..f11dc2a8 100644 --- a/src/external/dr_wav.h +++ b/src/external/dr_wav.h @@ -1,5 +1,5 @@ // WAV audio loader and writer. Public domain. See "unlicense" statement at the end of this file. -// dr_wav - v0.7a - 2017-11-17 +// dr_wav - v0.7f - 2018-02-05 // // David Reid - [email protected] @@ -103,8 +103,8 @@ // - Signed 16-bit PCM // - Signed 24-bit PCM // - Signed 32-bit PCM -// - IEEE 32-bit floating point. -// - IEEE 64-bit floating point. +// - IEEE 32-bit floating point +// - IEEE 64-bit floating point // - A-law and u-law // - Microsoft ADPCM // - IMA ADPCM (DVI, format code 0x11) @@ -643,13 +643,13 @@ drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onS float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); #ifndef DR_WAV_NO_STDIO -// Opens an decodes a wav file in a single operation. +// Opens and decodes a wav file in a single operation. drwav_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); #endif -// Opens an decodes a wav file from a block of memory in a single operation. +// Opens and decodes a wav file from a block of memory in a single operation. drwav_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); drwav_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); @@ -820,6 +820,9 @@ static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 fo } +drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); +drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); + typedef struct { union @@ -1395,6 +1398,11 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS return DRWAV_FALSE; // Failed to read the "fmt " chunk. } + // Basic validation. + if (fmt.sampleRate == 0 || fmt.channels == 0 || fmt.bitsPerSample == 0 || fmt.blockAlign == 0) { + return DRWAV_FALSE; // Invalid channel count. Probably an invalid WAV file. + } + // Translate the internal format. unsigned short translatedFormatTag = fmt.formatTag; @@ -1470,11 +1478,16 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS pWav->sampleRate = fmt.sampleRate; pWav->channels = fmt.channels; pWav->bitsPerSample = fmt.bitsPerSample; - pWav->bytesPerSample = (unsigned int)(fmt.blockAlign / fmt.channels); + pWav->bytesPerSample = fmt.blockAlign / fmt.channels; pWav->bytesRemaining = dataSize; pWav->translatedFormatTag = translatedFormatTag; pWav->dataChunkDataSize = dataSize; + // The bytes per sample should never be 0 at this point. This would indicate an invalid WAV file. + if (pWav->bytesPerSample == 0) { + return DRWAV_FALSE; + } + if (sampleCountFromFactChunk != 0) { pWav->totalSampleCount = sampleCountFromFactChunk * fmt.channels; } else { @@ -1489,18 +1502,26 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS pWav->totalSampleCount = ((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels); } } - - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + + // The way we calculate the bytes per sample does not make sense for compressed formats so we just set it to 0. + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { pWav->bytesPerSample = 0; } + // Some formats only support a certain number of channels. + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + if (pWav->channels > 2) { + return DRWAV_FALSE; + } + } + #ifdef DR_WAV_LIBSNDFILE_COMPAT // I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), // it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count // from the number of blocks, however this results in the inclusion of the extra silent samples at the end of the last block. The correct // way to know the total sample count is to inspect the "fact" chunk which should always be present for compressed formats, and should // 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 - // correctness tests against libsndfile and is disabled by default. + // correctness tests against libsndfile, and is disabled by default. if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 blockCount = dataSize / fmt.blockAlign; pWav->totalSampleCount = (blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2; // x2 because two samples per byte. @@ -1798,27 +1819,40 @@ drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample) // to seek back to the start. if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { // TODO: This can be optimized. + + // 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, + // we first need to seek back to the start and then just do the same thing as a forward seek. + if (sample < pWav->compressed.iCurrentSample) { + if (!drwav_seek_to_first_sample(pWav)) { + return DRWAV_FALSE; + } + } + if (sample > pWav->compressed.iCurrentSample) { - // Seeking forward - just move from the current position. drwav_uint64 offset = sample - pWav->compressed.iCurrentSample; drwav_int16 devnull[2048]; while (offset > 0) { - drwav_uint64 samplesToRead = sample; + drwav_uint64 samplesToRead = offset; if (samplesToRead > 2048) { samplesToRead = 2048; } - drwav_uint64 samplesRead = drwav_read_s16(pWav, samplesToRead, devnull); + drwav_uint64 samplesRead = 0; + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + samplesRead = drwav_read_s16__msadpcm(pWav, samplesToRead, devnull); + } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + samplesRead = drwav_read_s16__ima(pWav, samplesToRead, devnull); + } else { + 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. + } + if (samplesRead != samplesToRead) { return DRWAV_FALSE; } offset -= samplesRead; } - } else { - // Seeking backwards. Just use the fallback. - goto fallback; } } else { drwav_uint64 totalSizeInBytes = pWav->totalSampleCount * pWav->bytesPerSample; @@ -1851,30 +1885,6 @@ drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample) } return DRWAV_TRUE; - -fallback: - // This is a generic seek implementation that just continuously reads samples into a temporary buffer. This should work for all supported - // formats, but it is not efficient. This should be used as a fall back. - if (!drwav_seek_to_first_sample(pWav)) { - return DRWAV_FALSE; - } - - drwav_int16 devnull[2048]; - while (sample > 0) { - drwav_uint64 samplesToRead = sample; - if (samplesToRead > 2048) { - samplesToRead = 2048; - } - - drwav_uint64 samplesRead = drwav_read_s16(pWav, samplesToRead, devnull); - if (samplesRead != samplesToRead) { - return DRWAV_FALSE; - } - - sample -= samplesRead; - } - - return DRWAV_TRUE; } @@ -1906,132 +1916,6 @@ drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* p } -#ifndef DR_WAV_NO_CONVERSION_API -static unsigned short g_drwavAlawTable[256] = { - 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, - 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, - 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, - 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, - 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, - 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, - 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, - 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, - 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, - 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, - 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, - 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, - 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, - 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, - 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, - 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 -}; - -static unsigned short g_drwavMulawTable[256] = { - 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, - 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, - 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, - 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, - 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, - 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, - 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, - 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, - 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, - 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, - 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, - 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, - 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, - 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, - 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, - 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 -}; - -static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) -{ - return (short)g_drwavAlawTable[sampleIn]; -} - -static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) -{ - return (short)g_drwavMulawTable[sampleIn]; -} - - - -static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) -{ - // Special case for 8-bit sample data because it's treated as unsigned. - if (bytesPerSample == 1) { - drwav_u8_to_s16(pOut, pIn, totalSampleCount); - return; - } - - - // Slightly more optimal implementation for common formats. - if (bytesPerSample == 2) { - for (unsigned int i = 0; i < totalSampleCount; ++i) { - *pOut++ = ((drwav_int16*)pIn)[i]; - } - return; - } - if (bytesPerSample == 3) { - drwav_s24_to_s16(pOut, pIn, totalSampleCount); - return; - } - if (bytesPerSample == 4) { - drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); - return; - } - - - // Generic, slow converter. - for (unsigned int i = 0; i < totalSampleCount; ++i) { - unsigned short sample = 0; - unsigned short shift = (8 - bytesPerSample) * 8; - for (unsigned short j = 0; j < bytesPerSample && j < 2; ++j) { - sample |= (unsigned short)(pIn[j]) << shift; - shift += 8; - } - - pIn += bytesPerSample; - *pOut++ = sample; - } -} - -static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) -{ - if (bytesPerSample == 4) { - drwav_f32_to_s16(pOut, (float*)pIn, totalSampleCount); - return; - } else { - drwav_f64_to_s16(pOut, (double*)pIn, totalSampleCount); - return; - } -} - -drwav_uint64 drwav_read_s16__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) -{ - // Fast path. - if (pWav->bytesPerSample == 2) { - return drwav_read(pWav, samplesToRead, pBufferOut); - } - - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { - break; - } - - drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); - - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; - } - - return totalSamplesRead; -} drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) { @@ -2334,6 +2218,147 @@ drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ return totalSamplesRead; } + +#ifndef DR_WAV_NO_CONVERSION_API +static unsigned short g_drwavAlawTable[256] = { + 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, + 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, + 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, + 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, + 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, + 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, + 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, + 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, + 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, + 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, + 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, + 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, + 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, + 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, + 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, + 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 +}; + +static unsigned short g_drwavMulawTable[256] = { + 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, + 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, + 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, + 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, + 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, + 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, + 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, + 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, + 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, + 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, + 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, + 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, + 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, + 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +}; + +static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavAlawTable[sampleIn]; +} + +static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavMulawTable[sampleIn]; +} + + + +static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) +{ + // Special case for 8-bit sample data because it's treated as unsigned. + if (bytesPerSample == 1) { + drwav_u8_to_s16(pOut, pIn, totalSampleCount); + return; + } + + + // Slightly more optimal implementation for common formats. + if (bytesPerSample == 2) { + for (unsigned int i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((drwav_int16*)pIn)[i]; + } + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_s16(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); + return; + } + + + // Anything more than 64 bits per sample is not supported. + if (bytesPerSample > 8) { + drwav_zero_memory(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + + + // Generic, slow converter. + for (unsigned int i = 0; i < totalSampleCount; ++i) { + drwav_uint64 sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + + unsigned int j; + for (j = 0; j < bytesPerSample && j < 8; j += 1) { + sample |= (drwav_uint64)(pIn[j]) << shift; + shift += 8; + } + + pIn += j; + *pOut++ = (drwav_int16)((drwav_int64)sample >> 48); + } +} + +static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) +{ + if (bytesPerSample == 4) { + drwav_f32_to_s16(pOut, (float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_s16(pOut, (double*)pIn, totalSampleCount); + return; + } else { + // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. + drwav_zero_memory(pOut, totalSampleCount * sizeof(*pOut)); + return; + } +} + +drwav_uint64 drwav_read_s16__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +{ + // Fast path. + if (pWav->bytesPerSample == 2) { + return drwav_read(pWav, samplesToRead, pBufferOut); + } + + drwav_uint64 totalSamplesRead = 0; + unsigned char sampleData[4096]; + while (samplesToRead > 0) { + drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); + if (samplesRead == 0) { + break; + } + + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + + pBufferOut += samplesRead; + samplesToRead -= samplesRead; + totalSamplesRead += samplesRead; + } + + return totalSamplesRead; +} + drwav_uint64 drwav_read_s16__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) { drwav_uint64 totalSamplesRead = 0; @@ -2529,17 +2554,27 @@ static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t samp return; } + + // Anything more than 64 bits per sample is not supported. + if (bytesPerSample > 8) { + drwav_zero_memory(pOut, sampleCount * sizeof(*pOut)); + return; + } + + // Generic, slow converter. for (unsigned int i = 0; i < sampleCount; ++i) { - unsigned int sample = 0; + drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; - for (unsigned short j = 0; j < bytesPerSample && j < 4; ++j) { - sample |= (unsigned int)(pIn[j]) << shift; + + unsigned int j; + for (j = 0; j < bytesPerSample && j < 8; j += 1) { + sample |= (drwav_uint64)(pIn[j]) << shift; shift += 8; } - pIn += bytesPerSample; - *pOut++ = (float)((int)sample / 2147483648.0); + pIn += j; + *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0); } } @@ -2550,15 +2585,23 @@ static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sam *pOut++ = ((float*)pIn)[i]; } return; - } else { + } else if (bytesPerSample == 8) { drwav_f64_to_f32(pOut, (double*)pIn, sampleCount); return; + } else { + // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. + drwav_zero_memory(pOut, sampleCount * sizeof(*pOut)); + return; } } drwav_uint64 drwav_read_f32__pcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { + if (pWav->bytesPerSample == 0) { + return 0; + } + drwav_uint64 totalSamplesRead = 0; unsigned char sampleData[4096]; while (samplesToRead > 0) { @@ -2628,6 +2671,10 @@ drwav_uint64 drwav_read_f32__ieee(drwav* pWav, drwav_uint64 samplesToRead, float return drwav_read(pWav, samplesToRead, pBufferOut); } + if (pWav->bytesPerSample == 0) { + return 0; + } + drwav_uint64 totalSamplesRead = 0; unsigned char sampleData[4096]; while (samplesToRead > 0) { @@ -2648,6 +2695,10 @@ drwav_uint64 drwav_read_f32__ieee(drwav* pWav, drwav_uint64 samplesToRead, float drwav_uint64 drwav_read_f32__alaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { + if (pWav->bytesPerSample == 0) { + return 0; + } + drwav_uint64 totalSamplesRead = 0; unsigned char sampleData[4096]; while (samplesToRead > 0) { @@ -2668,6 +2719,10 @@ drwav_uint64 drwav_read_f32__alaw(drwav* pWav, drwav_uint64 samplesToRead, float drwav_uint64 drwav_read_f32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { + if (pWav->bytesPerSample == 0) { + return 0; + } + drwav_uint64 totalSamplesRead = 0; unsigned char sampleData[4096]; while (samplesToRead > 0) { @@ -2842,17 +2897,27 @@ static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_ return; } + + // Anything more than 64 bits per sample is not supported. + if (bytesPerSample > 8) { + drwav_zero_memory(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + + // Generic, slow converter. for (unsigned int i = 0; i < totalSampleCount; ++i) { - unsigned int sample = 0; + drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; - for (unsigned short j = 0; j < bytesPerSample && j < 4; ++j) { - sample |= (unsigned int)(pIn[j]) << shift; + + unsigned int j; + for (j = 0; j < bytesPerSample && j < 8; j += 1) { + sample |= (drwav_uint64)(pIn[j]) << shift; shift += 8; } - pIn += bytesPerSample; - *pOut++ = sample; + pIn += j; + *pOut++ = (drwav_int32)((drwav_int64)sample >> 32); } } @@ -2861,9 +2926,13 @@ static void drwav__ieee_to_s32(drwav_int32* pOut, const unsigned char* pIn, size if (bytesPerSample == 4) { drwav_f32_to_s32(pOut, (float*)pIn, totalSampleCount); return; - } else { + } else if (bytesPerSample == 8) { drwav_f64_to_s32(pOut, (double*)pIn, totalSampleCount); return; + } else { + // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. + drwav_zero_memory(pOut, totalSampleCount * sizeof(*pOut)); + return; } } @@ -2875,6 +2944,10 @@ drwav_uint64 drwav_read_s32__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_ return drwav_read(pWav, samplesToRead, pBufferOut); } + if (pWav->bytesPerSample == 0) { + return 0; + } + drwav_uint64 totalSamplesRead = 0; unsigned char sampleData[4096]; while (samplesToRead > 0) { @@ -2939,6 +3012,10 @@ drwav_uint64 drwav_read_s32__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ drwav_uint64 drwav_read_s32__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { + if (pWav->bytesPerSample == 0) { + return 0; + } + drwav_uint64 totalSamplesRead = 0; unsigned char sampleData[4096]; while (samplesToRead > 0) { @@ -2959,6 +3036,10 @@ drwav_uint64 drwav_read_s32__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav drwav_uint64 drwav_read_s32__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { + if (pWav->bytesPerSample == 0) { + return 0; + } + drwav_uint64 totalSamplesRead = 0; unsigned char sampleData[4096]; while (samplesToRead > 0) { @@ -2979,6 +3060,10 @@ drwav_uint64 drwav_read_s32__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav drwav_uint64 drwav_read_s32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { + if (pWav->bytesPerSample == 0) { + return 0; + } + drwav_uint64 totalSamplesRead = 0; unsigned char sampleData[4096]; while (samplesToRead > 0) { @@ -3354,6 +3439,25 @@ void drwav_free(void* pDataReturnedByOpenAndRead) // REVISION HISTORY // +// v0.7f - 2018-02-05 +// - Restrict ADPCM formats to a maximum of 2 channels. +// +// v0.7e - 2018-02-02 +// - Fix a crash. +// +// v0.7d - 2018-02-01 +// - Fix a crash. +// +// v0.7c - 2018-02-01 +// - Set drwav.bytesPerSample to 0 for all compressed formats. +// - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for +// all format conversion reading APIs (*_s16, *_s32, *_f32 APIs). +// - Fix some divide-by-zero errors. +// +// v0.7b - 2018-01-22 +// - Fix errors with seeking of compressed formats. +// - Fix compilation error when DR_WAV_NO_CONVERSION_API +// // v0.7a - 2017-11-17 // - Fix some GCC warnings. // @@ -3393,7 +3497,7 @@ void drwav_free(void* pDataReturnedByOpenAndRead) // // v0.5 - 2016-09-29 // - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to -// keep it consistent with dr_audio and drwav_flac. +// keep it consistent with dr_audio and dr_flac. // // v0.4b - 2016-09-18 // - Fixed a typo in documentation. @@ -3403,8 +3507,8 @@ void drwav_free(void* pDataReturnedByOpenAndRead) // - Change date format to ISO 8601 (YYYY-MM-DD) // // v0.4 - 2016-07-13 -// - API CHANGE. Make onSeek consistent with drwav_flac. -// - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with drwav_flac. +// - API CHANGE. Make onSeek consistent with dr_flac. +// - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac. // - Added support for Sony Wave64. // // v0.3a - 2016-05-28 @@ -3418,7 +3522,7 @@ void drwav_free(void* pDataReturnedByOpenAndRead) // - Fixed Linux/GCC build. // // v0.2 - 2016-05-11 -// - Added support for reading data as signed 32-bit PCM for consistency with drwav_flac. +// - Added support for reading data as signed 32-bit PCM for consistency with dr_flac. // // v0.1a - 2016-05-07 // - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. |
