Commit f07b84ce authored by David Reid's avatar David Reid

Update extras.

parent f62ce71b
// 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 <endian.h>
#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,8 +2459,11 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_
}
partitionsRemaining -= 1;
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.
//
......
// 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 <intrin.h>
#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)
{
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);
*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(1);
}
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.
//
......
// 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 {
......@@ -1490,17 +1503,25 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS
}
}
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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment