Update external audio libraries.

This commit is contained in:
David Reid 2018-04-21 17:34:56 +10:00
parent f5ebbfb6bc
commit 0febaa2446
4 changed files with 12908 additions and 3889 deletions

View File

@ -296,7 +296,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
(void)pDevice; (void)pDevice;
// Mixing is basically just an accumulation. We need to initialize the output buffer to 0. // Mixing is basically just an accumulation. We need to initialize the output buffer to 0.
memset(pFramesOut, 0, frameCount*pDevice->channels*mal_get_sample_size_in_bytes(pDevice->format)); memset(pFramesOut, 0, frameCount*pDevice->channels*mal_get_bytes_per_sample(pDevice->format));
// Using a mutex here for thread-safety which makes things not real-time. This is unlikely to be necessary for this project, but may // Using a mutex here for thread-safety which makes things not real-time. This is unlikely to be necessary for this project, but may
// want to consider how you might want to avoid this. // want to consider how you might want to avoid this.
@ -334,7 +334,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
// last few samples. // last few samples.
bool flushDSP = !audioBuffer->looping; bool flushDSP = !audioBuffer->looping;
mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, flushDSP); mal_uint32 framesJustRead = mal_dsp_read_ex(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, flushDSP, audioBuffer->dsp.pUserData);
if (framesJustRead > 0) if (framesJustRead > 0)
{ {
float *framesOut = (float *)pFramesOut + (framesRead*device.channels); float *framesOut = (float *)pFramesOut + (framesRead*device.channels);
@ -394,7 +394,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0]; isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0];
isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1]; isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1];
mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)*audioBuffer->dsp.config.channelsIn; mal_uint32 frameSizeInBytes = mal_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn)*audioBuffer->dsp.formatConverterIn.config.channels;
// Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0. // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0.
mal_uint32 framesRead = 0; mal_uint32 framesRead = 0;
@ -640,7 +640,7 @@ void SetMasterVolume(float volume)
// Create a new audio buffer. Initially filled with silence // Create a new audio buffer. Initially filled with silence
AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage) AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage)
{ {
AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_sample_size_in_bytes(format)), 1); AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_bytes_per_sample(format)), 1);
if (audioBuffer == NULL) if (audioBuffer == NULL)
{ {
TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to allocate memory for audio buffer"); TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to allocate memory for audio buffer");
@ -656,7 +656,10 @@ AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint3
dspConfig.channelsOut = DEVICE_CHANNELS; dspConfig.channelsOut = DEVICE_CHANNELS;
dspConfig.sampleRateIn = sampleRate; dspConfig.sampleRateIn = sampleRate;
dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE; dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE;
mal_result resultMAL = mal_dsp_init(&dspConfig, OnAudioBufferDSPRead, audioBuffer, &audioBuffer->dsp); dspConfig.onRead = OnAudioBufferDSPRead;
dspConfig.pUserData = audioBuffer;
dspConfig.allowDynamicSampleRate = MAL_TRUE; // <-- Required for pitch shifting.
mal_result resultMAL = mal_dsp_init(&dspConfig, &audioBuffer->dsp);
if (resultMAL != MAL_SUCCESS) if (resultMAL != MAL_SUCCESS)
{ {
TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline"); TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline");
@ -791,7 +794,7 @@ void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
// Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches
// will make the sound faster; lower pitches make it slower. // will make the sound faster; lower pitches make it slower.
mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.config.sampleRateOut / (float)audioBuffer->dsp.config.sampleRateIn) / pitch) * audioBuffer->dsp.config.sampleRateIn); mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.src.config.sampleRateOut / (float)audioBuffer->dsp.src.config.sampleRateIn) / pitch) * audioBuffer->dsp.src.config.sampleRateIn);
mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate); mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate);
} }
@ -913,7 +916,7 @@ Sound LoadSoundFromWave(Wave wave)
AudioBuffer* audioBuffer = CreateAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC); AudioBuffer* audioBuffer = CreateAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC);
if (audioBuffer == NULL) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Failed to create audio buffer"); if (audioBuffer == NULL) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Failed to create audio buffer");
frameCount = mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.config.formatIn, audioBuffer->dsp.config.channelsIn, audioBuffer->dsp.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn); frameCount = mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.formatConverterIn.config.formatIn, audioBuffer->dsp.formatConverterIn.config.channels, audioBuffer->dsp.src.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn);
if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Format conversion failed"); if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Format conversion failed");
sound.audioBuffer = audioBuffer; sound.audioBuffer = audioBuffer;
@ -1015,7 +1018,7 @@ void UpdateSound(Sound sound, const void *data, int samplesCount)
StopAudioBuffer(audioBuffer); StopAudioBuffer(audioBuffer);
// TODO: May want to lock/unlock this since this data buffer is read at mixing time. // TODO: May want to lock/unlock this since this data buffer is read at mixing time.
memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.config.channelsIn*mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)); memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.formatConverterIn.config.channels*mal_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn));
#else #else
ALint sampleRate, sampleSize, channels; ALint sampleRate, sampleSize, channels;
alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate);

View File

@ -1,5 +1,5 @@
// FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file. // 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 // David Reid - mackron@gmail.com
@ -106,6 +106,7 @@
// //
// //
// QUICK NOTES // 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. // - 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. // - 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 // - 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 #define DRFLAC_X64
#elif defined(__i386) || defined(_M_IX86) #elif defined(__i386) || defined(_M_IX86)
#define DRFLAC_X86 #define DRFLAC_X86
#elif defined(__arm__) || defined(_M_ARM)
#define DRFLAC_ARM
#endif #endif
// Compile-time CPU feature support. // Compile-time CPU feature support.
@ -806,7 +809,7 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr
#include <endian.h> #include <endian.h>
#endif #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 #define DRFLAC_HAS_LZCNT_INTRINSIC
#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) #elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
#define DRFLAC_HAS_LZCNT_INTRINSIC #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) #if !defined(DR_FLAC_NO_SIMD) && defined(DRFLAC_HAS_LZCNT_INTRINSIC)
#define DRFLAC_IMPLEMENT_CLZ_LZCNT #define DRFLAC_IMPLEMENT_CLZ_LZCNT
#endif #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 #define DRFLAC_IMPLEMENT_CLZ_MSVC
#endif #endif
@ -2402,6 +2405,16 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_
return DRFLAC_FALSE; 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 samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
drflac_uint32 partitionsRemaining = (1 << partitionOrder); drflac_uint32 partitionsRemaining = (1 << partitionOrder);
@ -2446,7 +2459,10 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_
} }
partitionsRemaining -= 1; partitionsRemaining -= 1;
samplesInPartition = blockSize / (1 << partitionOrder);
if (partitionOrder != 0) {
samplesInPartition = blockSize / (1 << partitionOrder);
}
} }
return DRFLAC_TRUE; 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. // 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)); 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); 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) { for (int i = 0; i < channelCount; ++i) {
if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFrame, i, pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * i))) { if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFrame, i, pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * i))) {
return DRFLAC_ERROR; return DRFLAC_ERROR;
@ -5498,6 +5524,16 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr
// REVISION HISTORY // 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 // v0.8d - 2017-09-22
// - Add support for decoding streams with ID3 tags. ID3 tags are just skipped. // - Add support for decoding streams with ID3 tags. ID3 tags are just skipped.
// //

464
src/external/dr_wav.h vendored
View File

@ -1,5 +1,5 @@
// WAV audio loader and writer. Public domain. See "unlicense" statement at the end of this file. // 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 // David Reid - mackron@gmail.com
@ -103,8 +103,8 @@
// - Signed 16-bit PCM // - Signed 16-bit PCM
// - Signed 24-bit PCM // - Signed 24-bit PCM
// - Signed 32-bit PCM // - Signed 32-bit PCM
// - IEEE 32-bit floating point. // - IEEE 32-bit floating point
// - IEEE 64-bit floating point. // - IEEE 64-bit floating point
// - A-law and u-law // - A-law and u-law
// - Microsoft ADPCM // - Microsoft ADPCM
// - IMA ADPCM (DVI, format code 0x11) // - 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); 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); 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 #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); 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); 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); drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
#endif #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); 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); 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); 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 typedef struct
{ {
union 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. 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. // Translate the internal format.
unsigned short translatedFormatTag = fmt.formatTag; 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->sampleRate = fmt.sampleRate;
pWav->channels = fmt.channels; pWav->channels = fmt.channels;
pWav->bitsPerSample = fmt.bitsPerSample; pWav->bitsPerSample = fmt.bitsPerSample;
pWav->bytesPerSample = (unsigned int)(fmt.blockAlign / fmt.channels); pWav->bytesPerSample = fmt.blockAlign / fmt.channels;
pWav->bytesRemaining = dataSize; pWav->bytesRemaining = dataSize;
pWav->translatedFormatTag = translatedFormatTag; pWav->translatedFormatTag = translatedFormatTag;
pWav->dataChunkDataSize = dataSize; 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) { if (sampleCountFromFactChunk != 0) {
pWav->totalSampleCount = sampleCountFromFactChunk * fmt.channels; pWav->totalSampleCount = sampleCountFromFactChunk * fmt.channels;
} else { } 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; 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 #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), // 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 // 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 // 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 // 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 // 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) { if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
drwav_uint64 blockCount = dataSize / fmt.blockAlign; drwav_uint64 blockCount = dataSize / fmt.blockAlign;
pWav->totalSampleCount = (blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2; // x2 because two samples per byte. 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. // to seek back to the start.
if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
// TODO: This can be optimized. // 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) { if (sample > pWav->compressed.iCurrentSample) {
// Seeking forward - just move from the current position.
drwav_uint64 offset = sample - pWav->compressed.iCurrentSample; drwav_uint64 offset = sample - pWav->compressed.iCurrentSample;
drwav_int16 devnull[2048]; drwav_int16 devnull[2048];
while (offset > 0) { while (offset > 0) {
drwav_uint64 samplesToRead = sample; drwav_uint64 samplesToRead = offset;
if (samplesToRead > 2048) { if (samplesToRead > 2048) {
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) { if (samplesRead != samplesToRead) {
return DRWAV_FALSE; return DRWAV_FALSE;
} }
offset -= samplesRead; offset -= samplesRead;
} }
} else {
// Seeking backwards. Just use the fallback.
goto fallback;
} }
} else { } else {
drwav_uint64 totalSizeInBytes = pWav->totalSampleCount * pWav->bytesPerSample; 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; 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) 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; 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 drwav_read_s16__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut)
{ {
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
@ -2529,17 +2554,27 @@ static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t samp
return; 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. // Generic, slow converter.
for (unsigned int i = 0; i < sampleCount; ++i) { for (unsigned int i = 0; i < sampleCount; ++i) {
unsigned int sample = 0; drwav_uint64 sample = 0;
unsigned int shift = (8 - bytesPerSample) * 8; 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; shift += 8;
} }
pIn += bytesPerSample; pIn += j;
*pOut++ = (float)((int)sample / 2147483648.0); *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]; *pOut++ = ((float*)pIn)[i];
} }
return; return;
} else { } else if (bytesPerSample == 8) {
drwav_f64_to_f32(pOut, (double*)pIn, sampleCount); drwav_f64_to_f32(pOut, (double*)pIn, sampleCount);
return; 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) drwav_uint64 drwav_read_f32__pcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
{ {
if (pWav->bytesPerSample == 0) {
return 0;
}
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
unsigned char sampleData[4096]; unsigned char sampleData[4096];
while (samplesToRead > 0) { 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); return drwav_read(pWav, samplesToRead, pBufferOut);
} }
if (pWav->bytesPerSample == 0) {
return 0;
}
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
unsigned char sampleData[4096]; unsigned char sampleData[4096];
while (samplesToRead > 0) { 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) drwav_uint64 drwav_read_f32__alaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
{ {
if (pWav->bytesPerSample == 0) {
return 0;
}
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
unsigned char sampleData[4096]; unsigned char sampleData[4096];
while (samplesToRead > 0) { 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) drwav_uint64 drwav_read_f32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
{ {
if (pWav->bytesPerSample == 0) {
return 0;
}
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
unsigned char sampleData[4096]; unsigned char sampleData[4096];
while (samplesToRead > 0) { while (samplesToRead > 0) {
@ -2842,17 +2897,27 @@ static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_
return; 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. // Generic, slow converter.
for (unsigned int i = 0; i < totalSampleCount; ++i) { for (unsigned int i = 0; i < totalSampleCount; ++i) {
unsigned int sample = 0; drwav_uint64 sample = 0;
unsigned int shift = (8 - bytesPerSample) * 8; 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; shift += 8;
} }
pIn += bytesPerSample; pIn += j;
*pOut++ = sample; *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) { if (bytesPerSample == 4) {
drwav_f32_to_s32(pOut, (float*)pIn, totalSampleCount); drwav_f32_to_s32(pOut, (float*)pIn, totalSampleCount);
return; return;
} else { } else if (bytesPerSample == 8) {
drwav_f64_to_s32(pOut, (double*)pIn, totalSampleCount); drwav_f64_to_s32(pOut, (double*)pIn, totalSampleCount);
return; 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); return drwav_read(pWav, samplesToRead, pBufferOut);
} }
if (pWav->bytesPerSample == 0) {
return 0;
}
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
unsigned char sampleData[4096]; unsigned char sampleData[4096];
while (samplesToRead > 0) { 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) drwav_uint64 drwav_read_s32__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
{ {
if (pWav->bytesPerSample == 0) {
return 0;
}
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
unsigned char sampleData[4096]; unsigned char sampleData[4096];
while (samplesToRead > 0) { 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) drwav_uint64 drwav_read_s32__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
{ {
if (pWav->bytesPerSample == 0) {
return 0;
}
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
unsigned char sampleData[4096]; unsigned char sampleData[4096];
while (samplesToRead > 0) { 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) drwav_uint64 drwav_read_s32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
{ {
if (pWav->bytesPerSample == 0) {
return 0;
}
drwav_uint64 totalSamplesRead = 0; drwav_uint64 totalSamplesRead = 0;
unsigned char sampleData[4096]; unsigned char sampleData[4096];
while (samplesToRead > 0) { while (samplesToRead > 0) {
@ -3354,6 +3439,25 @@ void drwav_free(void* pDataReturnedByOpenAndRead)
// REVISION HISTORY // 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 // v0.7a - 2017-11-17
// - Fix some GCC warnings. // - Fix some GCC warnings.
// //
@ -3393,7 +3497,7 @@ void drwav_free(void* pDataReturnedByOpenAndRead)
// //
// v0.5 - 2016-09-29 // 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 // - 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 // v0.4b - 2016-09-18
// - Fixed a typo in documentation. // - Fixed a typo in documentation.
@ -3403,8 +3507,8 @@ void drwav_free(void* pDataReturnedByOpenAndRead)
// - Change date format to ISO 8601 (YYYY-MM-DD) // - Change date format to ISO 8601 (YYYY-MM-DD)
// //
// v0.4 - 2016-07-13 // v0.4 - 2016-07-13
// - API CHANGE. Make onSeek consistent 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 drwav_flac. // - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac.
// - Added support for Sony Wave64. // - Added support for Sony Wave64.
// //
// v0.3a - 2016-05-28 // v0.3a - 2016-05-28
@ -3418,7 +3522,7 @@ void drwav_free(void* pDataReturnedByOpenAndRead)
// - Fixed Linux/GCC build. // - Fixed Linux/GCC build.
// //
// v0.2 - 2016-05-11 // 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 // 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. // - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize.

16262
src/external/mini_al.h vendored

File diff suppressed because it is too large Load Diff