From f07b84ce9ab34baa3a5f04b5341e0e4b526d39a1 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 21 Apr 2018 17:39:35 +1000 Subject: [PATCH] Update extras. --- extras/dr_flac.h | 44 ++++- extras/dr_mp3.h | 80 ++++---- extras/dr_wav.h | 466 +++++++++++++++++++++++++++++------------------ 3 files changed, 367 insertions(+), 223 deletions(-) diff --git a/extras/dr_flac.h b/extras/dr_flac.h index 60f57ece..ff23bdd1 100644 --- a/extras/dr_flac.h +++ b/extras/dr_flac.h @@ -1,5 +1,5 @@ // FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_flac - v0.8d - 2017-09-22 +// dr_flac - v0.8g - 2018-04-19 // // David Reid - mackron@gmail.com @@ -106,6 +106,7 @@ // // // QUICK NOTES +// - dr_flac does not currently support changing the sample rate nor channel count mid stream. // - Audio data is output as signed 32-bit PCM, regardless of the bits per sample the FLAC stream is encoded as. // - This has not been tested on big-endian architectures. // - Rice codes in unencoded binary form (see https://xiph.org/flac/format.html#rice_partition) has not been tested. If anybody @@ -759,6 +760,8 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr #define DRFLAC_X64 #elif defined(__i386) || defined(_M_IX86) #define DRFLAC_X86 +#elif defined(__arm__) || defined(_M_ARM) +#define DRFLAC_ARM #endif // Compile-time CPU feature support. @@ -806,7 +809,7 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr #include #endif -#if defined(_MSC_VER) && _MSC_VER >= 1500 +#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) #define DRFLAC_HAS_LZCNT_INTRINSIC #elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) #define DRFLAC_HAS_LZCNT_INTRINSIC @@ -1694,7 +1697,7 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) #if !defined(DR_FLAC_NO_SIMD) && defined(DRFLAC_HAS_LZCNT_INTRINSIC) #define DRFLAC_IMPLEMENT_CLZ_LZCNT #endif -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) #define DRFLAC_IMPLEMENT_CLZ_MSVC #endif @@ -2402,6 +2405,16 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ return DRFLAC_FALSE; } + // From the FLAC spec: + // The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + if (partitionOrder > 8) { + return DRFLAC_FALSE; + } + + // Validation check. + if ((blockSize / (1 << partitionOrder)) <= order) { + return DRFLAC_FALSE; + } drflac_uint32 samplesInPartition = (blockSize / (1 << partitionOrder)) - order; drflac_uint32 partitionsRemaining = (1 << partitionOrder); @@ -2446,7 +2459,10 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ } partitionsRemaining -= 1; - samplesInPartition = blockSize / (1 << partitionOrder); + + if (partitionOrder != 0) { + samplesInPartition = blockSize / (1 << partitionOrder); + } } return DRFLAC_TRUE; @@ -2982,7 +2998,17 @@ static drflac_result drflac__decode_frame(drflac* pFlac) // This function should be called while the stream is sitting on the first byte after the frame header. drflac_zero_memory(pFlac->currentFrame.subframes, sizeof(pFlac->currentFrame.subframes)); + // The frame block size must never be larger than the maximum block size defined by the FLAC stream. + if (pFlac->currentFrame.header.blockSize > pFlac->maxBlockSize) { + return DRFLAC_ERROR; + } + + // The number of channels in the frame must match the channel count from the STREAMINFO block. int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); + if (channelCount != (int)pFlac->channels) { + return DRFLAC_ERROR; + } + for (int i = 0; i < channelCount; ++i) { if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFrame, i, pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * i))) { return DRFLAC_ERROR; @@ -5498,6 +5524,16 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr // REVISION HISTORY // +// v0.8g - 2018-04-19 +// - Fix build on non-x86/x64 architectures. +// +// v0.8f - 2018-02-02 +// - Stop pretending to support changing rate/channels mid stream. +// +// v0.8e - 2018-02-01 +// - Fix a crash when the block size of a frame is larger than the maximum block size defined by the FLAC stream. +// - Fix a crash the the Rice partition order is invalid. +// // v0.8d - 2017-09-22 // - Add support for decoding streams with ID3 tags. ID3 tags are just skipped. // diff --git a/extras/dr_mp3.h b/extras/dr_mp3.h index f96da76f..7ee01290 100644 --- a/extras/dr_mp3.h +++ b/extras/dr_mp3.h @@ -1,5 +1,5 @@ // MP3 audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_mp3 - v0.1c - 2018-03-11 +// dr_mp3 - v0.2 - 2018-04-21 // // David Reid - mackron@gmail.com // @@ -333,12 +333,12 @@ void drmp3_free(void* p); #define DRMP3_HDR_GET_LAYER(h) (((h[1]) >> 1) & 3) #define DRMP3_HDR_GET_BITRATE(h) ((h[2]) >> 4) #define DRMP3_HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3) -#define DRMP3_HDR_GET_MY_SAMPLE_RATE(h) (DRMP3_HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1)) * 3) +#define DRMP3_HDR_GET_MY_SAMPLE_RATE(h) (DRMP3_HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3) #define DRMP3_HDR_IS_FRAME_576(h) ((h[1] & 14) == 2) #define DRMP3_HDR_IS_LAYER_1(h) ((h[1] & 6) == 6) #define DRMP3_BITS_DEQUANTIZER_OUT -1 -#define DRMP3_MAX_SCF (255 + DRMP3_BITS_DEQUANTIZER_OUT * 4 - 210) +#define DRMP3_MAX_SCF (255 + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210) #define DRMP3_MAX_SCFI ((DRMP3_MAX_SCF + 3) & ~3) #define DRMP3_MIN(a, b) ((a) > (b) ? (b) : (a)) @@ -351,7 +351,7 @@ void drmp3_free(void* p); #define DR_MP3_ONLY_SIMD #endif -#if defined(_MSC_VER) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) +#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) #if defined(_MSC_VER) #include #endif @@ -571,7 +571,7 @@ static unsigned drmp3_hdr_frame_samples(const drmp3_uint8 *h) static int drmp3_hdr_frame_bytes(const drmp3_uint8 *h, int free_format_size) { - int frame_bytes = drmp3_hdr_frame_samples(h) * drmp3_hdr_bitrate_kbps(h) * 125 / drmp3_hdr_sample_rate_hz(h); + int frame_bytes = drmp3_hdr_frame_samples(h)*drmp3_hdr_bitrate_kbps(h)*125/drmp3_hdr_sample_rate_hz(h); if (DRMP3_HDR_IS_LAYER_1(h)) { frame_bytes &= ~3; /* slot align */ @@ -647,7 +647,7 @@ static void drmp3_L12_read_scalefactors(drmp3_bs *bs, drmp3_uint8 *pba, drmp3_ui if (mask & m) { int b = drmp3_bs_get_bits(bs, 6); - s = g_deq_L12[ba*3 - 6 + b % 3] * (1 << 21 >> b/3); + s = g_deq_L12[ba*3 - 6 + b % 3]*(1 << 21 >> b/3); } *scf++ = s; } @@ -665,7 +665,7 @@ static void drmp3_L12_read_scale_info(const drmp3_uint8 *hdr, drmp3_bs *bs, drmp 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14, 0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16 }; - const drmp3_L12_subband_alloc * subband_alloc = drmp3_L12_subband_alloc_table(hdr, sci); + const drmp3_L12_subband_alloc *subband_alloc = drmp3_L12_subband_alloc_table(hdr, sci); int i, k = 0, ba_bits = 0; const drmp3_uint8 *ba_code_tab = g_bitalloc_code_tab; @@ -689,12 +689,12 @@ static void drmp3_L12_read_scale_info(const drmp3_uint8 *hdr, drmp3_bs *bs, drmp sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0; } - for (i = 0; i < 2 * sci->total_bands; i++) + for (i = 0; i < 2*sci->total_bands; i++) { sci->scfcod[i] = (drmp3_uint8)(sci->bitalloc[i] ? DRMP3_HDR_IS_LAYER_1(hdr) ? 2 : drmp3_bs_get_bits(bs, 2) : 6); } - drmp3_L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands * 2, sci->scf); + drmp3_L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf); for (i = sci->stereo_bands; i < sci->total_bands; i++) { @@ -1008,7 +1008,7 @@ static float drmp3_L3_pow_43(int x) sign = 2*x & 64; frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return g_pow43[(x + sign) >> 6] * (1.f + frac * ((4.f/3) + frac * (2.f/9))) * mult; + return g_pow43[(x + sign) >> 6]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; } static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) @@ -1036,7 +1036,7 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g static const drmp3_uint8 g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; #define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - n)) -#define DRMP3_FLUSH_BITS(n) {bs_cache <<= (n); bs_sh += (n);} +#define DRMP3_FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } #define DRMP3_CHECK_BITS while (bs_sh >= 0) { bs_cache |= (drmp3_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } #define DRMP3_BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) @@ -1052,7 +1052,7 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g { int tab_num = gr_info->table_select[ireg]; int sfb_cnt = gr_info->region_count[ireg++]; - const short * codebook = tabindex[tab_num]; + const short *codebook = tabindex[tab_num]; int linbits = g_linbits[tab_num]; do { @@ -1074,24 +1074,21 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g for (j = 0; j < 2; j++, dst++, leaf >>= 4) { int lsb = leaf & 0x0F; - if (lsb) + if (lsb == 15 && linbits) { - if (lsb == 15 && linbits) - { - lsb += DRMP3_PEEK_BITS(linbits); - DRMP3_FLUSH_BITS(linbits); - DRMP3_CHECK_BITS; - *dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1); - } else - { - *dst = g_pow43_signed[lsb*2 + (bs_cache >> 31)]*one; - } - DRMP3_FLUSH_BITS(1); + lsb += DRMP3_PEEK_BITS(linbits); + DRMP3_FLUSH_BITS(linbits); + DRMP3_CHECK_BITS; + *dst = one*drmp3_L3_pow_43(lsb)*((int32_t)bs_cache < 0 ? -1: 1); + } else + { + *dst = g_pow43_signed[lsb*2 + (bs_cache >> 31)]*one; } + DRMP3_FLUSH_BITS(lsb ? 1 : 0); } DRMP3_CHECK_BITS; } while (--pairs_to_decode); - } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0 ); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); } for (np = 1 - big_val_cnt;; dst += 4) @@ -1107,8 +1104,8 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g { break; } -#define DRMP3_RELOAD_SCALEFACTOR if (!--np) {np = *sfb++/2; if (!np) break; one = *scf++;} -#define DRMP3_DEQ_COUNT1(s) if (leaf & (128 >> s)) {dst[s] = ((drmp3_int32)bs_cache < 0) ? -one : one; DRMP3_FLUSH_BITS(1)} +#define DRMP3_RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; } +#define DRMP3_DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((drmp3_int32)bs_cache < 0) ? -one : one; DRMP3_FLUSH_BITS(1) } DRMP3_RELOAD_SCALEFACTOR; DRMP3_DEQ_COUNT1(0); DRMP3_DEQ_COUNT1(1); @@ -1241,7 +1238,7 @@ static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sf *dst++ = src[2*len]; } } - memcpy(grbuf, scratch, (dst - scratch) * sizeof(float)); + memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); } static void drmp3_L3_antialias(float *grbuf, int nbands) @@ -1720,8 +1717,8 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494, -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290 }; - float * zlin = lins + 15*64; - const float * w = g_win; + float *zlin = lins + 15*64; + const float *w = g_win; zlin[4*15] = xl[18*16]; zlin[4*15 + 1] = xr[18*16]; @@ -1742,10 +1739,10 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) if (drmp3_have_simd()) for (i = 14; i >= 0; i--) { #define DRMP3_VLOAD(k) drmp3_f4 w0 = DRMP3_VSET(*w++); drmp3_f4 w1 = DRMP3_VSET(*w++); drmp3_f4 vz = DRMP3_VLD(&zlin[4*i - 64*k]); drmp3_f4 vy = DRMP3_VLD(&zlin[4*i - 64*(15 - k)]); -#define DRMP3_V0(k) {DRMP3_VLOAD(k) b = DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0)) ; a = DRMP3_VSUB(DRMP3_VMUL(vz, w0),DRMP3_VMUL(vy, w1)); } -#define DRMP3_V1(k) {DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vz, w0),DRMP3_VMUL(vy, w1))); } -#define DRMP3_V2(k) {DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vy, w1),DRMP3_VMUL(vz, w0))); } - drmp3_f4 a,b; +#define DRMP3_V0(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0)) ; a = DRMP3_VSUB(DRMP3_VMUL(vz, w0), DRMP3_VMUL(vy, w1)); } +#define DRMP3_V1(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vz, w0), DRMP3_VMUL(vy, w1))); } +#define DRMP3_V2(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vy, w1), DRMP3_VMUL(vz, w0))); } + drmp3_f4 a, b; zlin[4*i] = xl[18*(31 - i)]; zlin[4*i + 1] = xr[18*(31 - i)]; zlin[4*i + 2] = xl[1 + 18*(31 - i)]; @@ -1794,10 +1791,10 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) #else for (i = 14; i >= 0; i--) { -#define DRMP3_LOAD(k) float w0 = *w++; float w1 = *w++; float * vz = &zlin[4*i - k*64]; float * vy = &zlin[4*i - (15 - k)*64]; -#define DRMP3_S0(k) {int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j] * w1 + vy[j] * w0, a[j] = vz[j] * w0 - vy[j] * w1;} -#define DRMP3_S1(k) {int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j] * w1 + vy[j] * w0, a[j] += vz[j] * w0 - vy[j] * w1;} -#define DRMP3_S2(k) {int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j] * w1 + vy[j] * w0, a[j] += vy[j] * w1 - vz[j] * w0;} +#define DRMP3_LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64]; +#define DRMP3_S0(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; } +#define DRMP3_S1(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; } +#define DRMP3_S2(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; } float a[4], b[4]; zlin[4*i] = xl[18*(31 - i)]; @@ -2747,6 +2744,13 @@ void drmp3_free(void* p) // REVISION HISTORY // =============== // +// v0.2 - 2018-04-21 +// - Bring up to date with minimp3. +// - Start using major.minor.revision versioning. +// +// v0.1d - 2018-03-30 +// - Bring up to date with minimp3. +// // v0.1c - 2018-03-11 // - Fix C++ build error. // diff --git a/extras/dr_wav.h b/extras/dr_wav.h index 536df8f3..f11dc2a8 100644 --- a/extras/dr_wav.h +++ b/extras/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 - mackron@gmail.com @@ -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; @@ -1850,30 +1884,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.