|
|
@@ -1,10 +1,6 @@ |
|
|
|
/* |
|
|
|
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. |
|
|
|
<<<<<<< HEAD |
|
|
|
dr_wav - v0.13.17 - TBD |
|
|
|
======= |
|
|
|
dr_wav - v0.13.16 - 2024-02-27 |
|
|
|
>>>>>>> e80c373575b337720703a41691536272b21b554c |
|
|
|
dr_wav - v0.14.0 - TBD |
|
|
|
|
|
|
|
David Reid - mackron@gmail.com |
|
|
|
|
|
|
@@ -150,12 +146,8 @@ extern "C" { |
|
|
|
#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) |
|
|
|
|
|
|
|
#define DRWAV_VERSION_MAJOR 0 |
|
|
|
#define DRWAV_VERSION_MINOR 13 |
|
|
|
<<<<<<< HEAD |
|
|
|
#define DRWAV_VERSION_REVISION 17 |
|
|
|
======= |
|
|
|
#define DRWAV_VERSION_REVISION 16 |
|
|
|
>>>>>>> e80c373575b337720703a41691536272b21b554c |
|
|
|
#define DRWAV_VERSION_MINOR 14 |
|
|
|
#define DRWAV_VERSION_REVISION 0 |
|
|
|
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) |
|
|
|
|
|
|
|
#include <stddef.h> /* For size_t. */ |
|
|
@@ -184,7 +176,7 @@ typedef unsigned int drwav_uint32; |
|
|
|
#pragma GCC diagnostic pop |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) |
|
|
|
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(__powerpc64__) |
|
|
|
typedef drwav_uint64 drwav_uintptr; |
|
|
|
#else |
|
|
|
typedef drwav_uint32 drwav_uintptr; |
|
|
@@ -563,11 +555,11 @@ typedef struct |
|
|
|
/* See drwav_smpl_loop_type. */ |
|
|
|
drwav_uint32 type; |
|
|
|
|
|
|
|
/* The byte offset of the first sample to be played in the loop. */ |
|
|
|
drwav_uint32 firstSampleByteOffset; |
|
|
|
/* The offset of the first sample to be played in the loop. */ |
|
|
|
drwav_uint32 firstSampleOffset; |
|
|
|
|
|
|
|
/* The byte offset into the audio data of the last sample to be played in the loop. */ |
|
|
|
drwav_uint32 lastSampleByteOffset; |
|
|
|
/* The offset into the audio data of the last sample to be played in the loop. */ |
|
|
|
drwav_uint32 lastSampleOffset; |
|
|
|
|
|
|
|
/* A value to represent that playback should occur at a point between samples. This value ranges from 0 to UINT32_MAX. Where a value of 0 means no fraction, and a value of (UINT32_MAX / 2) would mean half a sample. */ |
|
|
|
drwav_uint32 sampleFraction; |
|
|
@@ -645,8 +637,8 @@ typedef struct |
|
|
|
/* Set to 0 for uncompressed formats. Else the last byte in compressed wave data where decompression can begin to find the value of the corresponding sample value. */ |
|
|
|
drwav_uint32 blockStart; |
|
|
|
|
|
|
|
/* For uncompressed formats this is the byte offset of the cue point into the audio data. For compressed formats this is relative to the block specified with blockStart. */ |
|
|
|
drwav_uint32 sampleByteOffset; |
|
|
|
/* For uncompressed formats this is the offset of the cue point into the audio data. For compressed formats this is relative to the block specified with blockStart. */ |
|
|
|
drwav_uint32 sampleOffset; |
|
|
|
} drwav_cue_point; |
|
|
|
|
|
|
|
typedef struct |
|
|
@@ -1330,8 +1322,6 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); |
|
|
|
#endif |
|
|
|
#endif /* dr_wav_h */ |
|
|
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
======= |
|
|
|
|
|
|
|
/************************************************************************************************************************************************************ |
|
|
|
************************************************************************************************************************************************************ |
|
|
@@ -1394,7 +1384,7 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); |
|
|
|
#define DRWAV_MAX_SIMD_VECTOR_SIZE 32 |
|
|
|
|
|
|
|
/* Architecture Detection */ |
|
|
|
#if defined(__x86_64__) || defined(_M_X64) |
|
|
|
#if defined(__x86_64__) || (defined(_M_X64) && !defined(_M_ARM64EC)) |
|
|
|
#define DRWAV_X64 |
|
|
|
#elif defined(__i386) || defined(_M_IX86) |
|
|
|
#define DRWAV_X86 |
|
|
@@ -2106,7 +2096,7 @@ DRWAV_PRIVATE drwav_uint8* drwav__metadata_get_memory(drwav__metadata_parser* pP |
|
|
|
pParser->pDataCursor += align - modulo; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pResult = pParser->pDataCursor; |
|
|
|
|
|
|
|
/* |
|
|
@@ -2199,12 +2189,12 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars |
|
|
|
bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead); |
|
|
|
|
|
|
|
if (bytesJustRead == sizeof(smplLoopData)) { |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleOffset = drwav_bytes_to_u32(smplLoopData + 8); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleOffset = drwav_bytes_to_u32(smplLoopData + 12); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16); |
|
|
|
pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20); |
|
|
|
} else { |
|
|
|
break; |
|
|
|
} |
|
|
@@ -2264,7 +2254,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parse |
|
|
|
pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11]; |
|
|
|
pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12); |
|
|
|
pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16); |
|
|
|
pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20); |
|
|
|
pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset = drwav_bytes_to_u32(cuePointData + 20); |
|
|
|
} else { |
|
|
|
break; |
|
|
|
} |
|
|
@@ -2417,7 +2407,7 @@ DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader |
|
|
|
size_t bytesRemaining; |
|
|
|
|
|
|
|
DRWAV_ASSERT(pReader != NULL); |
|
|
|
|
|
|
|
|
|
|
|
if (pBytesRead != NULL) { |
|
|
|
*pBytesRead = 0; |
|
|
|
} |
|
|
@@ -2497,7 +2487,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_pars |
|
|
|
size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL); |
|
|
|
|
|
|
|
DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); |
|
|
|
|
|
|
|
|
|
|
|
if (bytesRead == sizeof(bextData)) { |
|
|
|
drwav_buffer_reader reader; |
|
|
|
drwav_uint32 timeReferenceLow; |
|
|
@@ -2559,7 +2549,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav_ |
|
|
|
drwav_uint64 totalBytesRead = 0; |
|
|
|
size_t bytesJustRead = drwav__metadata_parser_read(pParser, cueIDBuffer, sizeof(cueIDBuffer), &totalBytesRead); |
|
|
|
|
|
|
|
DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); |
|
|
|
DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read); |
|
|
|
|
|
|
|
if (bytesJustRead == sizeof(cueIDBuffer)) { |
|
|
|
drwav_uint32 sizeIncludingNullTerminator; |
|
|
@@ -2731,7 +2721,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* |
|
|
|
} |
|
|
|
} else { |
|
|
|
/* Loop count in header does not match the size of the chunk. */ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]); |
|
|
@@ -3352,7 +3342,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on |
|
|
|
if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "data")) || |
|
|
|
((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA))) { |
|
|
|
foundChunk_data = DRWAV_TRUE; |
|
|
|
|
|
|
|
|
|
|
|
pWav->dataChunkDataPos = cursor; |
|
|
|
|
|
|
|
if (pWav->container != drwav_container_rf64) { /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */ |
|
|
@@ -3442,7 +3432,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on |
|
|
|
return DRWAV_FALSE; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
channels = drwav_bytes_to_u16_ex (commData + 0, pWav->container); |
|
|
|
frameCount = drwav_bytes_to_u32_ex (commData + 2, pWav->container); |
|
|
|
sampleSizeInBits = drwav_bytes_to_u16_ex (commData + 6, pWav->container); |
|
|
@@ -3475,12 +3465,15 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on |
|
|
|
compressionFormat = DR_WAVE_FORMAT_MULAW; |
|
|
|
} else if (drwav_fourcc_equal(type, "ima4")) { |
|
|
|
compressionFormat = DR_WAVE_FORMAT_DVI_ADPCM; |
|
|
|
sampleSizeInBits = 4; |
|
|
|
sampleSizeInBits = 4; |
|
|
|
|
|
|
|
/* |
|
|
|
I haven't been able to figure out how to get correct decoding for IMA ADPCM. Until this is figured out |
|
|
|
we'll need to abort when we encounter such an encoding. Advice welcome! |
|
|
|
*/ |
|
|
|
(void)compressionFormat; |
|
|
|
(void)sampleSizeInBits; |
|
|
|
|
|
|
|
return DRWAV_FALSE; |
|
|
|
} else { |
|
|
|
return DRWAV_FALSE; /* Unknown or unsupported compression format. Need to abort. */ |
|
|
@@ -3517,7 +3510,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on |
|
|
|
|
|
|
|
/* In AIFF, samples are padded to 8 byte boundaries. We need to round up our bits per sample here. */ |
|
|
|
fmt.bitsPerSample += (fmt.bitsPerSample & 7); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If the form type is AIFC there will be some additional data in the chunk. We need to seek past it. */ |
|
|
|
if (isAIFCFormType) { |
|
|
@@ -3543,20 +3536,46 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on |
|
|
|
return DRWAV_FALSE; |
|
|
|
} |
|
|
|
|
|
|
|
/* We need to seek forward by the offset. */ |
|
|
|
/* The position of the audio data starts at an offset. */ |
|
|
|
offset = drwav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container); |
|
|
|
if (drwav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == DRWAV_FALSE) { |
|
|
|
return DRWAV_FALSE; |
|
|
|
} |
|
|
|
cursor += offset; |
|
|
|
pWav->dataChunkDataPos = cursor + offset; |
|
|
|
|
|
|
|
pWav->dataChunkDataPos = cursor; |
|
|
|
/* The data chunk size needs to be reduced by the offset or else seeking will break. */ |
|
|
|
dataChunkSize = chunkSize; |
|
|
|
if (dataChunkSize > offset) { |
|
|
|
dataChunkSize -= offset; |
|
|
|
} else { |
|
|
|
dataChunkSize = 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* If we're running in sequential mode, or we're not reading metadata, we have enough now that we can get out of the loop. */ |
|
|
|
if (sequential || !isProcessingMetadata) { |
|
|
|
break; /* No need to keep reading beyond the data chunk. */ |
|
|
|
if (sequential) { |
|
|
|
if (foundChunk_fmt) { /* <-- Name is misleading, but will be set to true if the COMM chunk has been parsed. */ |
|
|
|
/* |
|
|
|
Getting here means we're opening in sequential mode and we've found the SSND (data) and COMM (fmt) chunks. We need |
|
|
|
to get out of the loop here or else we'll end up going past the data chunk and will have no way of getting back to |
|
|
|
it since we're not allowed to seek backwards. |
|
|
|
|
|
|
|
One subtle detail here is that there is an offset with the SSND chunk. We need to make sure we seek past this offset |
|
|
|
so we're left sitting on the first byte of actual audio data. |
|
|
|
*/ |
|
|
|
if (drwav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == DRWAV_FALSE) { |
|
|
|
return DRWAV_FALSE; |
|
|
|
} |
|
|
|
cursor += offset; |
|
|
|
|
|
|
|
break; |
|
|
|
} else { |
|
|
|
/* |
|
|
|
Getting here means the COMM chunk was not found. In sequential mode, if we haven't yet found the COMM chunk |
|
|
|
we'll need to abort because we can't be doing a backwards seek back to the SSND chunk in order to read the |
|
|
|
data. For this reason, this configuration of AIFF files are not supported with sequential mode. |
|
|
|
*/ |
|
|
|
return DRWAV_FALSE; |
|
|
|
} |
|
|
|
} else { |
|
|
|
chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */ |
|
|
|
chunkSize -= sizeof(offsetAndBlockSizeData); /* <-- This was read earlier. */ |
|
|
|
|
|
|
|
if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) { |
|
|
|
break; |
|
|
|
} |
|
|
@@ -3567,7 +3586,6 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Getting here means it's not a chunk that we care about internally, but might need to be handled as metadata by the caller. */ |
|
|
|
if (isProcessingMetadata) { |
|
|
|
drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown); |
|
|
@@ -3659,6 +3677,10 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on |
|
|
|
|
|
|
|
|
|
|
|
/* At this point we should be sitting on the first byte of the raw audio data. */ |
|
|
|
if (drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData) == DRWAV_FALSE) { |
|
|
|
drwav_free(pWav->pMetadata, &pWav->allocationCallbacks); |
|
|
|
return DRWAV_FALSE; |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
I've seen a WAV file in the wild where a RIFF-ecapsulated file has the size of it's "RIFF" and |
|
|
@@ -3680,18 +3702,30 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData) == DRWAV_FALSE) { |
|
|
|
drwav_free(pWav->pMetadata, &pWav->allocationCallbacks); |
|
|
|
return DRWAV_FALSE; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pWav->fmt = fmt; |
|
|
|
pWav->sampleRate = fmt.sampleRate; |
|
|
|
pWav->channels = fmt.channels; |
|
|
|
pWav->bitsPerSample = fmt.bitsPerSample; |
|
|
|
pWav->bytesRemaining = dataChunkSize; |
|
|
|
pWav->translatedFormatTag = translatedFormatTag; |
|
|
|
|
|
|
|
/* |
|
|
|
I've had a report where files would start glitching after seeking. The reason for this is the data |
|
|
|
chunk is not a clean multiple of the PCM frame size in bytes. Where this becomes a problem is when |
|
|
|
seeking, because the number of bytes remaining in the data chunk is used to calculate the current |
|
|
|
byte position. If this byte position is not aligned to the number of bytes in a PCM frame, it will |
|
|
|
result in the seek not being cleanly positioned at the start of the PCM frame thereby resulting in |
|
|
|
all decoded frames after that being corrupted. |
|
|
|
|
|
|
|
To address this, we need to round the data chunk size down to the nearest multiple of the frame size. |
|
|
|
*/ |
|
|
|
if (!drwav__is_compressed_format_tag(translatedFormatTag)) { |
|
|
|
drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); |
|
|
|
if (bytesPerFrame > 0) { |
|
|
|
dataChunkSize -= (dataChunkSize % bytesPerFrame); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pWav->bytesRemaining = dataChunkSize; |
|
|
|
pWav->dataChunkDataSize = dataChunkSize; |
|
|
|
|
|
|
|
if (sampleCountFromFactChunk != 0) { |
|
|
@@ -4005,8 +4039,8 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* |
|
|
|
for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) { |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleOffset); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleOffset); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount); |
|
|
|
} |
|
|
@@ -4046,7 +4080,7 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* |
|
|
|
bytesWritten += drwav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset); |
|
|
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset); |
|
|
|
} |
|
|
|
} break; |
|
|
|
|
|
|
@@ -4205,7 +4239,7 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* |
|
|
|
|
|
|
|
if (pMetadata->data.labelOrNote.stringLength > 0) { |
|
|
|
chunkSize += pMetadata->data.labelOrNote.stringLength + 1; |
|
|
|
} |
|
|
|
} |
|
|
|
} break; |
|
|
|
|
|
|
|
case drwav_metadata_type_list_labelled_cue_region: |
|
|
@@ -4714,7 +4748,7 @@ DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e) |
|
|
|
#ifdef ENOSYS |
|
|
|
case ENOSYS: return DRWAV_NOT_IMPLEMENTED; |
|
|
|
#endif |
|
|
|
#ifdef ENOTEMPTY |
|
|
|
#if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST /* In AIX, ENOTEMPTY and EEXIST use the same value. */ |
|
|
|
case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY; |
|
|
|
#endif |
|
|
|
#ifdef ELOOP |
|
|
@@ -5189,7 +5223,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFi |
|
|
|
fclose(pFile); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags); |
|
|
|
if (result != DRWAV_TRUE) { |
|
|
|
fclose(pFile); |
|
|
@@ -6111,6 +6145,13 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav |
|
|
|
{ |
|
|
|
drwav_uint64 totalFramesRead = 0; |
|
|
|
|
|
|
|
static drwav_int32 adaptationTable[] = { |
|
|
|
230, 230, 230, 230, 307, 409, 512, 614, |
|
|
|
768, 614, 512, 409, 307, 230, 230, 230 |
|
|
|
}; |
|
|
|
static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; |
|
|
|
static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; |
|
|
|
|
|
|
|
DRWAV_ASSERT(pWav != NULL); |
|
|
|
DRWAV_ASSERT(framesToRead > 0); |
|
|
|
|
|
|
@@ -6136,6 +6177,11 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav |
|
|
|
pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0]; |
|
|
|
pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1]; |
|
|
|
pWav->msadpcm.cachedFrameCount = 2; |
|
|
|
|
|
|
|
/* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */ |
|
|
|
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table)) { |
|
|
|
return totalFramesRead; /* Invalid file. */ |
|
|
|
} |
|
|
|
} else { |
|
|
|
/* Stereo. */ |
|
|
|
drwav_uint8 header[14]; |
|
|
@@ -6158,6 +6204,11 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav |
|
|
|
pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1]; |
|
|
|
pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1]; |
|
|
|
pWav->msadpcm.cachedFrameCount = 2; |
|
|
|
|
|
|
|
/* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */ |
|
|
|
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) { |
|
|
|
return totalFramesRead; /* Invalid file. */ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -6191,13 +6242,6 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav |
|
|
|
if (pWav->msadpcm.bytesRemainingInBlock == 0) { |
|
|
|
continue; |
|
|
|
} else { |
|
|
|
static drwav_int32 adaptationTable[] = { |
|
|
|
230, 230, 230, 230, 307, 409, 512, 614, |
|
|
|
768, 614, 512, 409, 307, 230, 230, 230 |
|
|
|
}; |
|
|
|
static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; |
|
|
|
static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; |
|
|
|
|
|
|
|
drwav_uint8 nibbles; |
|
|
|
drwav_int32 nibble0; |
|
|
|
drwav_int32 nibble1; |
|
|
@@ -8360,6 +8404,15 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) |
|
|
|
/* |
|
|
|
REVISION HISTORY |
|
|
|
================ |
|
|
|
v0.14.0 - TBD |
|
|
|
- API CHANGE: The `firstSampleByteOffset`, `lastSampleByteOffset` and `sampleByteOffset` members of `drwav_cue_point` have been renamed to `firstSampleOffset`, `lastSampleOffset` and `sampleOffset`, respectively. |
|
|
|
- Fix a static analysis warning. |
|
|
|
- Fix compilation for AIX OS. |
|
|
|
|
|
|
|
v0.13.17 - 2024-12-17 |
|
|
|
- Fix a possible crash when reading from MS-ADPCM encoded files. |
|
|
|
- Improve detection of ARM64EC |
|
|
|
|
|
|
|
v0.13.16 - 2024-02-27 |
|
|
|
- Fix a Wdouble-promotion warning. |
|
|
|
|
|
|
@@ -8823,4 +8876,3 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
|
SOFTWARE. |
|
|
|
*/ |
|
|
|
>>>>>>> e80c373575b337720703a41691536272b21b554c |