Update dr_libs.

This commit is contained in:
Martín Lucas Golini
2025-01-31 00:26:37 -03:00
parent 87fb9538cb
commit 863c0ec1c0
2 changed files with 426 additions and 183 deletions

View File

@@ -1,6 +1,6 @@
/*
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_flac - v0.12.37 - 2022-02-12
dr_flac - v0.12.43 - 2024-12-17
David Reid - mackron@gmail.com
@@ -179,7 +179,7 @@ reports metadata to the application through the use of a callback, and every met
The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style
streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs:
`drflac_open_relaxed()`
`drflac_open_with_metadata_relaxed()`
@@ -210,6 +210,9 @@ Build Options
#define DR_FLAC_NO_SIMD
Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler.
#define DR_FLAC_NO_WCHAR
Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_FLAC_NO_STDIO is also defined.
Notes
@@ -232,12 +235,12 @@ extern "C" {
#define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 37
#define DRFLAC_VERSION_REVISION 43
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
/* Sized types. */
/* Sized Types */
typedef signed char drflac_int8;
typedef unsigned char drflac_uint8;
typedef signed short drflac_int16;
@@ -270,7 +273,9 @@ typedef drflac_uint8 drflac_bool8;
typedef drflac_uint32 drflac_bool32;
#define DRFLAC_TRUE 1
#define DRFLAC_FALSE 0
/* End Sized Types */
/* Decorations */
#if !defined(DRFLAC_API)
#if defined(DRFLAC_DLL)
#if defined(_WIN32)
@@ -300,6 +305,7 @@ typedef drflac_uint32 drflac_bool32;
#define DRFLAC_PRIVATE static
#endif
#endif
/* End Decorations */
#if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */
#define DRFLAC_DEPRECATED __declspec(deprecated)
@@ -318,6 +324,16 @@ typedef drflac_uint32 drflac_bool32;
DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision);
DRFLAC_API const char* drflac_version_string(void);
/* Allocation Callbacks */
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drflac_allocation_callbacks;
/* End Allocation Callbacks */
/*
As data is read from the client it is placed into an internal buffer for fast access. This controls the size of that buffer. Larger values means more speed,
but also more memory. In my testing there is diminishing returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8.
@@ -326,11 +342,22 @@ but also more memory. In my testing there is diminishing returns after about 4KB
#define DR_FLAC_BUFFER_SIZE 4096
#endif
/* Check if we can enable 64-bit optimizations. */
/* Architecture Detection */
#if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
#define DRFLAC_64BIT
#endif
#if defined(__x86_64__) || (defined(_M_X64) && !defined(_M_ARM64EC))
#define DRFLAC_X64
#elif defined(__i386) || defined(_M_IX86)
#define DRFLAC_X86
#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
#define DRFLAC_ARM
#endif
/* End Architecture Detection */
#ifdef DRFLAC_64BIT
typedef drflac_uint64 drflac_cache_t;
#else
@@ -383,15 +410,13 @@ typedef enum
drflac_seek_origin_current
} drflac_seek_origin;
/* Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block. */
#pragma pack(2)
/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */
typedef struct
{
drflac_uint64 firstPCMFrame;
drflac_uint64 flacFrameOffset; /* The offset from the first byte of the header of the first frame. */
drflac_uint16 pcmFrameCount;
} drflac_seekpoint;
#pragma pack()
typedef struct
{
@@ -561,14 +586,6 @@ will be set to one of the DRFLAC_METADATA_BLOCK_TYPE_* tokens.
typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drflac_allocation_callbacks;
/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */
typedef struct
{
@@ -1280,15 +1297,13 @@ typedef struct
const char* pRunningData;
} drflac_cuesheet_track_iterator;
/* Packing is important on this structure because we map this directly to the raw data within the CUESHEET metadata block. */
#pragma pack(4)
/* The order of members here is important because we map this directly to the raw data within the CUESHEET metadata block. */
typedef struct
{
drflac_uint64 offset;
drflac_uint8 index;
drflac_uint8 reserved[3];
} drflac_cuesheet_track_index;
#pragma pack()
typedef struct
{
@@ -1352,6 +1367,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
#include <stdlib.h>
#include <string.h>
/* Inline */
#ifdef _MSC_VER
#define DRFLAC_INLINE __forceinline
#elif defined(__GNUC__)
@@ -1363,24 +1379,22 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
I am using "__inline__" only when we're compiling in strict ANSI mode.
*/
#if defined(__STRICT_ANSI__)
#define DRFLAC_INLINE __inline__ __attribute__((always_inline))
#define DRFLAC_GNUC_INLINE_HINT __inline__
#else
#define DRFLAC_INLINE inline __attribute__((always_inline))
#define DRFLAC_GNUC_INLINE_HINT inline
#endif
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__)
#define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT __attribute__((always_inline))
#else
#define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT
#endif
#elif defined(__WATCOMC__)
#define DRFLAC_INLINE __inline
#else
#define DRFLAC_INLINE
#endif
/* CPU architecture. */
#if defined(__x86_64__) || defined(_M_X64)
#define DRFLAC_X64
#elif defined(__i386) || defined(_M_IX86)
#define DRFLAC_X86
#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
#define DRFLAC_ARM
#endif
/* End Inline */
/*
Intrinsics Support
@@ -1509,9 +1523,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
{
#if defined(DRFLAC_SUPPORT_SSE41)
#if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41)
#if defined(DRFLAC_X64)
return DRFLAC_TRUE; /* 64-bit targets always support SSE4.1. */
#elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE4_1__)
#if defined(__SSE4_1__) || defined(__AVX__)
return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE41 code we can assume support. */
#else
#if defined(DRFLAC_NO_CPUID)
@@ -1576,18 +1588,21 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64);
#pragma aux _watcom_bswap16 = \
"xchg al, ah" \
parm [ax] \
modify [ax];
parm [ax] \
value [ax] \
modify nomemory;
#pragma aux _watcom_bswap32 = \
"bswap eax" \
parm [eax] \
modify [eax];
"bswap eax" \
parm [eax] \
value [eax] \
modify nomemory;
#pragma aux _watcom_bswap64 = \
"bswap eax" \
"bswap edx" \
"xchg eax,edx" \
parm [eax edx] \
modify [eax edx];
value [eax edx] \
modify nomemory;
#endif
@@ -1617,6 +1632,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */
/* Result Codes */
typedef drflac_int32 drflac_result;
#define DRFLAC_SUCCESS 0
#define DRFLAC_ERROR -1 /* A generic error. */
@@ -1672,7 +1688,10 @@ typedef drflac_int32 drflac_result;
#define DRFLAC_CANCELLED -51
#define DRFLAC_MEMORY_ALREADY_MAPPED -52
#define DRFLAC_AT_END -53
#define DRFLAC_CRC_MISMATCH -128
#define DRFLAC_CRC_MISMATCH -100
/* End Result Codes */
#define DRFLAC_SUBFRAME_CONSTANT 0
#define DRFLAC_SUBFRAME_VERBATIM 1
@@ -1688,6 +1707,10 @@ typedef drflac_int32 drflac_result;
#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9
#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10
#define DRFLAC_SEEKPOINT_SIZE_IN_BYTES 18
#define DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES 36
#define DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES 12
#define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a))
@@ -1828,7 +1851,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n)
#if defined(_MSC_VER) && !defined(__clang__)
return _byteswap_ulong(n);
#elif defined(__GNUC__) || defined(__clang__)
#if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */
#if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */
/* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
drflac_uint32 r;
__asm__ __volatile__ (
@@ -2690,6 +2713,10 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs)
#if defined(__WATCOMC__) && defined(__386__)
#define DRFLAC_IMPLEMENT_CLZ_WATCOM
#endif
#ifdef __MRC__
#include <intrinsics.h>
#define DRFLAC_IMPLEMENT_CLZ_MRC
#endif
static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x)
{
@@ -2730,6 +2757,8 @@ static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void)
/* Fast compile time check for ARM. */
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
return DRFLAC_TRUE;
#elif defined(__MRC__)
return DRFLAC_TRUE;
#else
/* If the compiler itself does not support the intrinsic then we'll need to return false. */
#ifdef DRFLAC_HAS_LZCNT_INTRINSIC
@@ -2786,7 +2815,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
return r;
}
#elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
#elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
{
unsigned int r;
__asm__ __volatile__ (
@@ -2839,6 +2868,15 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x)
#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM
static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32);
#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT
/* Use the LZCNT instruction (only available on some processors since the 2010s). */
#pragma aux drflac__clz_watcom_lzcnt = \
"db 0F3h, 0Fh, 0BDh, 0C0h" /* lzcnt eax, eax */ \
parm [eax] \
value [eax] \
modify nomemory;
#else
/* Use the 386+-compatible implementation. */
#pragma aux drflac__clz_watcom = \
"bsr eax, eax" \
"xor eax, 31" \
@@ -2846,6 +2884,7 @@ static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32);
value [eax] \
modify exact [eax] nomemory;
#endif
#endif
static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x)
{
@@ -2857,8 +2896,12 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x)
{
#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
return drflac__clz_msvc(x);
#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT)
return drflac__clz_watcom_lzcnt(x);
#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM)
return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x);
#elif defined(__MRC__)
return __cntlzw(x);
#else
return drflac__clz_software(x);
#endif
@@ -4420,7 +4463,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_
const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
riceParamMask = ~((~0UL) << riceParam);
riceParamMask = (drflac_uint32)~((~0UL) << riceParam);
riceParamMask128 = vdupq_n_u32(riceParamMask);
riceParam128 = vdupq_n_s32(riceParam);
@@ -4606,10 +4649,13 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_
int32x4_t riceParam128;
int64x1_t shift64;
uint32x4_t one128;
int64x2_t prediction128 = { 0 };
uint32x4_t zeroCountPart128;
uint32x4_t riceParamPart128;
const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
riceParamMask = ~((~0UL) << riceParam);
riceParamMask = (drflac_uint32)~((~0UL) << riceParam);
riceParamMask128 = vdupq_n_u32(riceParamMask);
riceParam128 = vdupq_n_s32(riceParam);
@@ -4686,10 +4732,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_
/* For this version we are doing one sample at a time. */
while (pDecodedSamples < pDecodedSamplesEnd) {
int64x2_t prediction128;
uint32x4_t zeroCountPart128;
uint32x4_t riceParamPart128;
if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
@@ -5351,6 +5393,12 @@ static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe
return DRFLAC_FALSE;
}
/*
Default to 0 for the LPC order. It's important that we always set this to 0 for non LPC
and FIXED subframes because we'll be using it in a generic validation check later.
*/
pSubframe->lpcOrder = 0;
type = (header & 0x7E) >> 1;
if (type == 0) {
pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
@@ -5423,6 +5471,18 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame,
pSubframe->pSamplesS32 = pDecodedSamplesOut;
/*
pDecodedSamplesOut will be pointing to a buffer that was allocated with enough memory to store
maxBlockSizeInPCMFrames samples (as specified in the FLAC header). We need to guard against an
overflow here. At a higher level we are checking maxBlockSizeInPCMFrames from the header, but
here we need to do an additional check to ensure this frame's block size fully encompasses any
warmup samples which is determined by the LPC order. For non LPC and FIXED subframes, the LPC
order will be have been set to 0 in drflac__read_subframe_header().
*/
if (frame->header.blockSizeInPCMFrames < pSubframe->lpcOrder) {
return DRFLAC_FALSE;
}
switch (pSubframe->subframeType)
{
case DRFLAC_SUBFRAME_CONSTANT:
@@ -6437,7 +6497,7 @@ static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbac
}
static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeektableSize, drflac_allocation_callbacks* pAllocationCallbacks)
static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks)
{
/*
We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
@@ -6450,7 +6510,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
for (;;) {
drflac_metadata metadata;
drflac_uint8 isLastBlock = 0;
drflac_uint8 blockType;
drflac_uint8 blockType = 0;
drflac_uint32 blockSize;
if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
return DRFLAC_FALSE;
@@ -6497,32 +6557,37 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
seektableSize = blockSize;
if (onMeta) {
drflac_uint32 seekpointCount;
drflac_uint32 iSeekpoint;
void* pRawData;
pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
seekpointCount = blockSize/DRFLAC_SEEKPOINT_SIZE_IN_BYTES;
pRawData = drflac__malloc_from_callbacks(seekpointCount * sizeof(drflac_seekpoint), pAllocationCallbacks);
if (pRawData == NULL) {
return DRFLAC_FALSE;
}
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint);
metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
/* Endian swap. */
for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) {
/* We need to read seekpoint by seekpoint and do some processing. */
for (iSeekpoint = 0; iSeekpoint < seekpointCount; ++iSeekpoint) {
drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint;
if (onRead(pUserData, pSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) != DRFLAC_SEEKPOINT_SIZE_IN_BYTES) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
/* Endian swap. */
pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame);
pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset);
pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount);
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
metadata.data.seektable.seekpointCount = seekpointCount;
metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
@@ -6607,9 +6672,15 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
void* pRawData;
const char* pRunningData;
const char* pRunningDataEnd;
size_t bufferSize;
drflac_uint8 iTrack;
drflac_uint8 iIndex;
void* pTrackData;
/*
This needs to be loaded in two passes. The first pass is used to calculate the size of the memory allocation
we need for storing the necessary data. The second pass will fill that buffer with usable data.
*/
pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
if (pRawData == NULL) {
return DRFLAC_FALSE;
@@ -6630,38 +6701,91 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8;
metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259;
metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1;
metadata.data.cuesheet.pTrackData = pRunningData;
metadata.data.cuesheet.pTrackData = NULL; /* Will be filled later. */
/* Check that the cuesheet tracks are valid before passing it to the callback */
for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
drflac_uint8 indexCount;
drflac_uint32 indexPointSize;
/* Pass 1: Calculate the size of the buffer for the track data. */
{
const char* pRunningDataSaved = pRunningData; /* Will be restored at the end in preparation for the second pass. */
if (pRunningDataEnd - pRunningData < 36) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
bufferSize = metadata.data.cuesheet.trackCount * DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES;
for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
drflac_uint8 indexCount;
drflac_uint32 indexPointSize;
if (pRunningDataEnd - pRunningData < DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
/* Skip to the index point count */
pRunningData += 35;
indexCount = pRunningData[0];
pRunningData += 1;
bufferSize += indexCount * sizeof(drflac_cuesheet_track_index);
/* Quick validation check. */
indexPointSize = indexCount * DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES;
if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
pRunningData += indexPointSize;
}
/* Skip to the index point count */
pRunningData += 35;
indexCount = pRunningData[0]; pRunningData += 1;
indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index);
if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
/* Endian swap. */
for (iIndex = 0; iIndex < indexCount; ++iIndex) {
drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData;
pRunningData += sizeof(drflac_cuesheet_track_index);
pTrack->offset = drflac__be2host_64(pTrack->offset);
}
pRunningData = pRunningDataSaved;
}
/* Pass 2: Allocate a buffer and fill the data. Validation was done in the step above so can be skipped. */
{
char* pRunningTrackData;
pTrackData = drflac__malloc_from_callbacks(bufferSize, pAllocationCallbacks);
if (pTrackData == NULL) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
pRunningTrackData = (char*)pTrackData;
for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
drflac_uint8 indexCount;
DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES);
pRunningData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; /* Skip forward, but not beyond the last byte in the CUESHEET_TRACK block which is the index count. */
pRunningTrackData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1;
/* Grab the index count for the next part. */
indexCount = pRunningData[0];
pRunningData += 1;
pRunningTrackData += 1;
/* Extract each track index. */
for (iIndex = 0; iIndex < indexCount; ++iIndex) {
drflac_cuesheet_track_index* pTrackIndex = (drflac_cuesheet_track_index*)pRunningTrackData;
DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES);
pRunningData += DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES;
pRunningTrackData += sizeof(drflac_cuesheet_track_index);
pTrackIndex->offset = drflac__be2host_64(pTrackIndex->offset);
}
}
metadata.data.cuesheet.pTrackData = pTrackData;
}
/* The original data is no longer needed. */
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
pRawData = NULL;
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
drflac__free_from_callbacks(pTrackData, pAllocationCallbacks);
pTrackData = NULL;
}
} break;
@@ -6700,7 +6824,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength;
metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength;
metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
/* Need space for the rest of the block */
@@ -6708,7 +6832,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength;
metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength;
metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
@@ -6791,9 +6915,9 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
}
}
*pSeektablePos = seektablePos;
*pSeektableSize = seektableSize;
*pFirstFramePos = runningFilePos;
*pSeektablePos = seektablePos;
*pSeekpointCount = seektableSize / DRFLAC_SEEKPOINT_SIZE_IN_BYTES;
*pFirstFramePos = runningFilePos;
return DRFLAC_TRUE;
}
@@ -7823,11 +7947,11 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
drflac_uint32 wholeSIMDVectorCountPerChannel;
drflac_uint32 decodedSamplesAllocationSize;
#ifndef DR_FLAC_NO_OGG
drflac_oggbs oggbs;
drflac_oggbs* pOggbs = NULL;
#endif
drflac_uint64 firstFramePos;
drflac_uint64 seektablePos;
drflac_uint32 seektableSize;
drflac_uint32 seekpointCount;
drflac_allocation_callbacks allocationCallbacks;
drflac* pFlac;
@@ -7881,18 +8005,21 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
/* There's additional data required for Ogg streams. */
if (init.container == drflac_container_ogg) {
allocationSize += sizeof(drflac_oggbs);
}
DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs));
if (init.container == drflac_container_ogg) {
oggbs.onRead = onRead;
oggbs.onSeek = onSeek;
oggbs.pUserData = pUserData;
oggbs.currentBytePos = init.oggFirstBytePos;
oggbs.firstBytePos = init.oggFirstBytePos;
oggbs.serialNumber = init.oggSerial;
oggbs.bosPageHeader = init.oggBosHeader;
oggbs.bytesRemainingInPage = 0;
pOggbs = (drflac_oggbs*)drflac__malloc_from_callbacks(sizeof(*pOggbs), &allocationCallbacks);
if (pOggbs == NULL) {
return NULL; /*DRFLAC_OUT_OF_MEMORY;*/
}
DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs));
pOggbs->onRead = onRead;
pOggbs->onSeek = onSeek;
pOggbs->pUserData = pUserData;
pOggbs->currentBytePos = init.oggFirstBytePos;
pOggbs->firstBytePos = init.oggFirstBytePos;
pOggbs->serialNumber = init.oggSerial;
pOggbs->bosPageHeader = init.oggBosHeader;
pOggbs->bytesRemainingInPage = 0;
}
#endif
@@ -7901,9 +8028,9 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
consist of only a single heap allocation. To this, the size of the seek table needs to be known, which we determine when reading
and decoding the metadata.
*/
firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */
seektablePos = 0;
seektableSize = 0;
firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */
seektablePos = 0;
seekpointCount = 0;
if (init.hasMetadataBlocks) {
drflac_read_proc onReadOverride = onRead;
drflac_seek_proc onSeekOverride = onSeek;
@@ -7913,20 +8040,26 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
if (init.container == drflac_container_ogg) {
onReadOverride = drflac__on_read_ogg;
onSeekOverride = drflac__on_seek_ogg;
pUserDataOverride = (void*)&oggbs;
pUserDataOverride = (void*)pOggbs;
}
#endif
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) {
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) {
#ifndef DR_FLAC_NO_OGG
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
#endif
return NULL;
}
allocationSize += seektableSize;
allocationSize += seekpointCount * sizeof(drflac_seekpoint);
}
pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
if (pFlac == NULL) {
#ifndef DR_FLAC_NO_OGG
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
#endif
return NULL;
}
@@ -7936,8 +8069,12 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
#ifndef DR_FLAC_NO_OGG
if (init.container == drflac_container_ogg) {
drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize);
*pInternalOggbs = oggbs;
drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + (seekpointCount * sizeof(drflac_seekpoint)));
DRFLAC_COPY_MEMORY(pInternalOggbs, pOggbs, sizeof(*pOggbs));
/* At this point the pOggbs object has been handed over to pInternalOggbs and can be freed. */
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
pOggbs = NULL;
/* The Ogg bistream needs to be layered on top of the original bitstream. */
pFlac->bs.onRead = drflac__on_read_ogg;
@@ -7961,7 +8098,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
{
/* If we have a seektable we need to load it now, making sure we move back to where we were previously. */
if (seektablePos != 0) {
pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints);
pFlac->seekpointCount = seekpointCount;
pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize);
DRFLAC_ASSERT(pFlac->bs.onSeek != NULL);
@@ -7969,18 +8106,20 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
/* Seek to the seektable, then just read directly into our seektable buffer. */
if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) {
/* Endian swap. */
drflac_uint32 iSeekpoint;
for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
drflac_uint32 iSeekpoint;
for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) {
if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) == DRFLAC_SEEKPOINT_SIZE_IN_BYTES) {
/* Endian swap. */
pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame);
pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset);
pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount);
} else {
/* Failed to read the seektable. Pretend we don't have one. */
pFlac->pSeekpoints = NULL;
pFlac->seekpointCount = 0;
break;
}
} else {
/* Failed to read the seektable. Pretend we don't have one. */
pFlac->pSeekpoints = NULL;
pFlac->seekpointCount = 0;
}
/* We need to seek back to where we were. If this fails it's a critical error. */
@@ -8029,8 +8168,11 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
#ifndef DR_FLAC_NO_STDIO
#include <stdio.h>
#ifndef DR_FLAC_NO_WCHAR
#include <wchar.h> /* For wcslen(), wcsrtombs() */
#endif
/* Errno */
/* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */
#include <errno.h>
static drflac_result drflac_result_from_errno(int e)
@@ -8434,7 +8576,9 @@ static drflac_result drflac_result_from_errno(int e)
default: return DRFLAC_ERROR;
}
}
/* End Errno */
/* fopen */
static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
@@ -8495,6 +8639,7 @@ fallback, so if you notice your compiler not detecting this properly I'm happy t
#endif
#endif
#ifndef DR_FLAC_NO_WCHAR
static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (ppFile != NULL) {
@@ -8523,10 +8668,23 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons
}
#else
/*
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because
fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note
that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler
error I'll look into improving compatibility.
*/
/*
Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just
need to abort with an error. If you encounter a compiler lacking such support, add it to this list
and submit a bug report and it'll be added to the library upstream.
*/
#if defined(__DJGPP__)
{
/* Nothing to do here. This will fall through to the error check below. */
}
#else
{
mbstate_t mbs;
size_t lenMB;
@@ -8568,6 +8726,7 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons
drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
}
#endif
if (*ppFile == NULL) {
return DRFLAC_ERROR;
@@ -8576,6 +8735,8 @@ static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, cons
return DRFLAC_SUCCESS;
}
#endif
/* End fopen */
static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
{
@@ -8608,6 +8769,7 @@ DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocati
return pFlac;
}
#ifndef DR_FLAC_NO_WCHAR
DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
@@ -8625,6 +8787,7 @@ DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_all
return pFlac;
}
#endif
DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
@@ -8644,6 +8807,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_
return pFlac;
}
#ifndef DR_FLAC_NO_WCHAR
DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
@@ -8661,6 +8825,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, dr
return pFlac;
}
#endif
#endif /* DR_FLAC_NO_STDIO */
static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
@@ -11536,6 +11701,7 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p
/* High Level APIs */
/* SIZE_MAX */
#if defined(SIZE_MAX)
#define DRFLAC_SIZE_MAX SIZE_MAX
#else
@@ -11545,6 +11711,7 @@ DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 p
#define DRFLAC_SIZE_MAX 0xFFFFFFFF
#endif
#endif
/* End SIZE_MAX */
/* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */
@@ -11928,6 +12095,32 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
/*
REVISION HISTORY
================
v0.12.43 - 2024-12-17
- Fix a possible buffer overflow during decoding.
- Improve detection of ARM64EC
v0.12.42 - 2023-11-02
- Fix build for ARMv6-M.
- Fix a compilation warning with GCC.
v0.12.41 - 2023-06-17
- Fix an incorrect date in revision history. No functional change.
v0.12.40 - 2023-05-22
- Minor code restructure. No functional change.
v0.12.39 - 2022-09-17
- Fix compilation with DJGPP.
- Fix compilation error with Visual Studio 2019 and the ARM build.
- Fix an error with SSE 4.1 detection.
- Add support for disabling wchar_t with DR_WAV_NO_WCHAR.
- Improve compatibility with compilers which lack support for explicit struct packing.
- Improve compatibility with low-end and embedded hardware by reducing the amount of stack
allocation when loading an Ogg encapsulated file.
v0.12.38 - 2022-04-10
- Fix compilation error on older versions of GCC.
v0.12.37 - 2022-02-12
- Improve ARM detection.
@@ -12346,7 +12539,7 @@ For more information, please refer to <http://unlicense.org/>
===============================================================================
ALTERNATIVE 2 - MIT No Attribution
===============================================================================
Copyright 2020 David Reid
Copyright 2023 David Reid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -1,6 +1,6 @@
/*
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_mp3 - v0.6.32 - 2021-12-11
dr_mp3 - v0.6.40 - 2024-12-17
David Reid - mackron@gmail.com
@@ -33,7 +33,7 @@ Support for loading a file from a `wchar_t` string has been added via the `drmp3
*/
/*
Introducation
Introduction
=============
dr_mp3 is a single file library. To use it, do something like the following in one .c file.
@@ -95,12 +95,12 @@ extern "C" {
#define DRMP3_VERSION_MAJOR 0
#define DRMP3_VERSION_MINOR 6
#define DRMP3_VERSION_REVISION 32
#define DRMP3_VERSION_REVISION 40
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
/* Sized types. */
/* Sized Types */
typedef signed char drmp3_int8;
typedef unsigned char drmp3_uint8;
typedef signed short drmp3_int16;
@@ -124,7 +124,7 @@ typedef unsigned int drmp3_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 drmp3_uint64 drmp3_uintptr;
#else
typedef drmp3_uint32 drmp3_uintptr;
@@ -133,7 +133,9 @@ typedef drmp3_uint8 drmp3_bool8;
typedef drmp3_uint32 drmp3_bool32;
#define DRMP3_TRUE 1
#define DRMP3_FALSE 0
/* End Sized Types */
/* Decorations */
#if !defined(DRMP3_API)
#if defined(DRMP3_DLL)
#if defined(_WIN32)
@@ -163,7 +165,9 @@ typedef drmp3_uint32 drmp3_bool32;
#define DRMP3_PRIVATE static
#endif
#endif
/* End Decorations */
/* Result Codes */
typedef drmp3_int32 drmp3_result;
#define DRMP3_SUCCESS 0
#define DRMP3_ERROR -1 /* A generic error. */
@@ -219,11 +223,12 @@ typedef drmp3_int32 drmp3_result;
#define DRMP3_CANCELLED -51
#define DRMP3_MEMORY_ALREADY_MAPPED -52
#define DRMP3_AT_END -53
/* End Result Codes */
#define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152
#define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2)
/* Inline */
#ifdef _MSC_VER
#define DRMP3_INLINE __forceinline
#elif defined(__GNUC__)
@@ -235,21 +240,39 @@ typedef drmp3_int32 drmp3_result;
I am using "__inline__" only when we're compiling in strict ANSI mode.
*/
#if defined(__STRICT_ANSI__)
#define DRMP3_INLINE __inline__ __attribute__((always_inline))
#define DRMP3_GNUC_INLINE_HINT __inline__
#else
#define DRMP3_INLINE inline __attribute__((always_inline))
#define DRMP3_GNUC_INLINE_HINT inline
#endif
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__)
#define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT __attribute__((always_inline))
#else
#define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT
#endif
#elif defined(__WATCOMC__)
#define DRMP3_INLINE __inline
#else
#define DRMP3_INLINE
#endif
/* End Inline */
DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision);
DRMP3_API const char* drmp3_version_string(void);
/* Allocation Callbacks */
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drmp3_allocation_callbacks;
/* End Allocation Callbacks */
/*
Low Level Push API
==================
@@ -323,14 +346,6 @@ will be either drmp3_seek_origin_start or drmp3_seek_origin_current.
*/
typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin);
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drmp3_allocation_callbacks;
typedef struct
{
drmp3_uint32 channels;
@@ -340,7 +355,6 @@ typedef struct
typedef struct
{
drmp3dec decoder;
drmp3dec_frame_info frameInfo;
drmp3_uint32 channels;
drmp3_uint32 sampleRate;
drmp3_read_proc onRead;
@@ -590,12 +604,12 @@ DRMP3_API const char* drmp3_version_string(void)
#if !defined(DR_MP3_NO_SIMD)
#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64))
#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC))
/* x64 always have SSE2, arm64 always have neon, no need for generic code */
#define DR_MP3_ONLY_SIMD
#endif
#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__))
#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)))
#if defined(_MSC_VER)
#include <intrin.h>
#endif
@@ -666,7 +680,7 @@ end:
return g_have_simd - 1;
#endif
}
#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)
#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
#include <arm_neon.h>
#define DRMP3_HAVE_SSE 0
#define DRMP3_HAVE_SIMD 1
@@ -699,7 +713,7 @@ static int drmp3_have_simd(void)
#endif
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64)
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC) && !defined(__ARM_ARCH_6M__)
#define DRMP3_HAVE_ARMV6 1
static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a)
{
@@ -1296,7 +1310,7 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g
static const drmp3_int16 tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 };
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_PEEK_BITS(n) (bs_cache >> (32 - (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)
@@ -1864,7 +1878,7 @@ static void drmp3d_DCT_II(float *grbuf, int n)
#if DRMP3_HAVE_SSE
#define DRMP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v)
#else
#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v))
#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[(i)*18], vget_low_f32(v))
#endif
for (i = 0; i < 7; i++, y += 4*18)
{
@@ -1880,7 +1894,7 @@ static void drmp3d_DCT_II(float *grbuf, int n)
DRMP3_VSAVE2(3, t[3][7]);
} else
{
#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[i*18], v)
#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[(i)*18], v)
for (i = 0; i < 7; i++, y += 4*18)
{
drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]);
@@ -1971,8 +1985,8 @@ static drmp3_int16 drmp3d_scale_pcm(float sample)
s32 -= (s32 < 0);
s = (drmp3_int16)drmp3_clip_int16_arm(s32);
#else
if (sample >= 32766.5) return (drmp3_int16) 32767;
if (sample <= -32767.5) return (drmp3_int16)-32768;
if (sample >= 32766.5f) return (drmp3_int16) 32767;
if (sample <= -32767.5f) return (drmp3_int16)-32768;
s = (drmp3_int16)(sample + .5f);
s -= (s < 0); /* away from zero, to be compliant */
#endif
@@ -2103,7 +2117,11 @@ static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins)
vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2);
#endif
#else
#if DRMP3_HAVE_SSE
static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f };
#else
const drmp3_f4 g_scale = vdupq_n_f32(1.0f/32768.0f);
#endif
a = DRMP3_VMUL(a, g_scale);
b = DRMP3_VMUL(b, g_scale);
#if DRMP3_HAVE_SSE
@@ -2386,9 +2404,9 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
for(; i < num_samples; i++)
{
float sample = in[i] * 32768.0f;
if (sample >= 32766.5)
if (sample >= 32766.5f)
out[i] = (drmp3_int16) 32767;
else if (sample <= -32767.5)
else if (sample <= -32767.5f)
out[i] = (drmp3_int16)-32768;
else
{
@@ -2406,8 +2424,7 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
Main Public API
************************************************************************************************************************************************************/
#include <math.h> /* For sin() and exp(). */
/* SIZE_MAX */
#if defined(SIZE_MAX)
#define DRMP3_SIZE_MAX SIZE_MAX
#else
@@ -2417,6 +2434,7 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
#define DRMP3_SIZE_MAX 0xFFFFFFFF
#endif
#endif
/* End SIZE_MAX */
/* Options. */
#ifndef DRMP3_SEEK_LEADING_MP3_FRAMES
@@ -2427,7 +2445,7 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
/* The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends at least 16K, but in an attempt to reduce data movement I'm making this slightly larger. */
#ifndef DRMP3_DATA_CHUNK_SIZE
#define DRMP3_DATA_CHUNK_SIZE DRMP3_MIN_DATA_CHUNK_SIZE*4
#define DRMP3_DATA_CHUNK_SIZE (DRMP3_MIN_DATA_CHUNK_SIZE*4)
#endif
@@ -2472,24 +2490,6 @@ static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b)
}
static DRMP3_INLINE double drmp3_sin(double x)
{
/* TODO: Implement custom sin(x). */
return sin(x);
}
static DRMP3_INLINE double drmp3_exp(double x)
{
/* TODO: Implement custom exp(x). */
return exp(x);
}
static DRMP3_INLINE double drmp3_cos(double x)
{
return drmp3_sin((DRMP3_PI_D*0.5) - x);
}
static void* drmp3__malloc_default(size_t sz, void* pUserData)
{
(void)pUserData;
@@ -2701,6 +2701,11 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa
DRMP3_ASSERT(pMP3->pData != NULL);
DRMP3_ASSERT(pMP3->dataCapacity > 0);
/* Do a runtime check here to try silencing a false-positive from clang-analyzer. */
if (pMP3->pData == NULL) {
return 0;
}
pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */
/* Consume the data. */
@@ -2942,6 +2947,7 @@ DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t
#include <stdio.h>
#include <wchar.h> /* For wcslen(), wcsrtombs() */
/* Errno */
/* drmp3_result_from_errno() is only used inside DR_MP3_NO_STDIO for now. Move this out if it's ever used elsewhere. */
#include <errno.h>
static drmp3_result drmp3_result_from_errno(int e)
@@ -3345,7 +3351,9 @@ static drmp3_result drmp3_result_from_errno(int e)
default: return DRMP3_ERROR;
}
}
/* End Errno */
/* fopen */
static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
@@ -3434,10 +3442,23 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const
}
#else
/*
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because
fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note
that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler
error I'll look into improving compatibility.
*/
/*
Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just
need to abort with an error. If you encounter a compiler lacking such support, add it to this list
and submit a bug report and it'll be added to the library upstream.
*/
#if defined(__DJGPP__)
{
/* Nothing to do here. This will fall through to the error check below. */
}
#else
{
mbstate_t mbs;
size_t lenMB;
@@ -3479,6 +3500,7 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const
drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
}
#endif
if (*ppFile == NULL) {
return DRMP3_ERROR;
@@ -3487,7 +3509,7 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const
return DRMP3_SUCCESS;
}
/* End fopen */
static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
@@ -3542,7 +3564,7 @@ DRMP3_API void drmp3_uninit(drmp3* pMP3)
if (pMP3 == NULL) {
return;
}
#ifndef DR_MP3_NO_STDIO
if (pMP3->onRead == drmp3__on_read_stdio) {
FILE* pFile = (FILE*)pMP3->pUserData;
@@ -3930,7 +3952,7 @@ DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint
/* We'll need to seek back to where we were, so grab the PCM frame we're currently sitting on so we can restore later. */
currentPCMFrame = pMP3->currentPCMFrame;
if (!drmp3_seek_to_start_of_stream(pMP3)) {
return DRMP3_FALSE;
}
@@ -4028,7 +4050,7 @@ DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pS
/* We'll need to seek back to the current sample after calculating the seekpoints so we need to go ahead and grab the current location at the top. */
currentPCMFrame = pMP3->currentPCMFrame;
/* We never do more than the total number of MP3 frames and we limit it to 32-bits. */
if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) {
return DRMP3_FALSE;
@@ -4473,6 +4495,34 @@ counts rather than sample counts.
/*
REVISION HISTORY
================
v0.6.40 - 2024-12-17
- Improve detection of ARM64EC
v0.6.39 - 2024-02-27
- Fix a Wdouble-promotion warning.
v0.6.38 - 2023-11-02
- Fix build for ARMv6-M.
v0.6.37 - 2023-07-07
- Silence a static analysis warning.
v0.6.36 - 2023-06-17
- Fix an incorrect date in revision history. No functional change.
v0.6.35 - 2023-05-22
- Minor code restructure. No functional change.
v0.6.34 - 2022-09-17
- Fix compilation with DJGPP.
- Fix compilation when compiling with x86 with no SSE2.
- Remove an unnecessary variable from the drmp3 structure.
v0.6.33 - 2022-04-10
- Fix compilation error with the MSVC ARM64 build.
- Fix compilation error on older versions of GCC.
- Remove some unused functions.
v0.6.32 - 2021-12-11
- Fix a warning with Clang.
@@ -4764,7 +4814,7 @@ For more information, please refer to <http://unlicense.org/>
===============================================================================
ALTERNATIVE 2 - MIT No Attribution
===============================================================================
Copyright 2020 David Reid
Copyright 2023 David Reid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in