mirror of
https://github.com/raysan5/raylib.git
synced 2025-09-05 19:08:13 +00:00
update dr_libs
This commit is contained in:
418
src/external/dr_flac.h
vendored
418
src/external/dr_flac.h
vendored
@@ -1,121 +1,12 @@
|
||||
/*
|
||||
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_flac - v0.12.42 - 2023-11-02
|
||||
dr_flac - v0.13.0 - TBD
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
GitHub: https://github.com/mackron/dr_libs
|
||||
*/
|
||||
|
||||
/*
|
||||
RELEASE NOTES - v0.12.0
|
||||
=======================
|
||||
Version 0.12.0 has breaking API changes including changes to the existing API and the removal of deprecated APIs.
|
||||
|
||||
|
||||
Improved Client-Defined Memory Allocation
|
||||
-----------------------------------------
|
||||
The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
|
||||
existing system of DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE are still in place and will be used by default when no custom
|
||||
allocation callbacks are specified.
|
||||
|
||||
To use the new system, you pass in a pointer to a drflac_allocation_callbacks object to drflac_open() and family, like this:
|
||||
|
||||
void* my_malloc(size_t sz, void* pUserData)
|
||||
{
|
||||
return malloc(sz);
|
||||
}
|
||||
void* my_realloc(void* p, size_t sz, void* pUserData)
|
||||
{
|
||||
return realloc(p, sz);
|
||||
}
|
||||
void my_free(void* p, void* pUserData)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
drflac_allocation_callbacks allocationCallbacks;
|
||||
allocationCallbacks.pUserData = &myData;
|
||||
allocationCallbacks.onMalloc = my_malloc;
|
||||
allocationCallbacks.onRealloc = my_realloc;
|
||||
allocationCallbacks.onFree = my_free;
|
||||
drflac* pFlac = drflac_open_file("my_file.flac", &allocationCallbacks);
|
||||
|
||||
The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
|
||||
|
||||
Passing in null for the allocation callbacks object will cause dr_flac to use defaults which is the same as DRFLAC_MALLOC,
|
||||
DRFLAC_REALLOC and DRFLAC_FREE and the equivalent of how it worked in previous versions.
|
||||
|
||||
Every API that opens a drflac object now takes this extra parameter. These include the following:
|
||||
|
||||
drflac_open()
|
||||
drflac_open_relaxed()
|
||||
drflac_open_with_metadata()
|
||||
drflac_open_with_metadata_relaxed()
|
||||
drflac_open_file()
|
||||
drflac_open_file_with_metadata()
|
||||
drflac_open_memory()
|
||||
drflac_open_memory_with_metadata()
|
||||
drflac_open_and_read_pcm_frames_s32()
|
||||
drflac_open_and_read_pcm_frames_s16()
|
||||
drflac_open_and_read_pcm_frames_f32()
|
||||
drflac_open_file_and_read_pcm_frames_s32()
|
||||
drflac_open_file_and_read_pcm_frames_s16()
|
||||
drflac_open_file_and_read_pcm_frames_f32()
|
||||
drflac_open_memory_and_read_pcm_frames_s32()
|
||||
drflac_open_memory_and_read_pcm_frames_s16()
|
||||
drflac_open_memory_and_read_pcm_frames_f32()
|
||||
|
||||
|
||||
|
||||
Optimizations
|
||||
-------------
|
||||
Seeking performance has been greatly improved. A new binary search based seeking algorithm has been introduced which significantly
|
||||
improves performance over the brute force method which was used when no seek table was present. Seek table based seeking also takes
|
||||
advantage of the new binary search seeking system to further improve performance there as well. Note that this depends on CRC which
|
||||
means it will be disabled when DR_FLAC_NO_CRC is used.
|
||||
|
||||
The SSE4.1 pipeline has been cleaned up and optimized. You should see some improvements with decoding speed of 24-bit files in
|
||||
particular. 16-bit streams should also see some improvement.
|
||||
|
||||
drflac_read_pcm_frames_s16() has been optimized. Previously this sat on top of drflac_read_pcm_frames_s32() and performed it's s32
|
||||
to s16 conversion in a second pass. This is now all done in a single pass. This includes SSE2 and ARM NEON optimized paths.
|
||||
|
||||
A minor optimization has been implemented for drflac_read_pcm_frames_s32(). This will now use an SSE2 optimized pipeline for stereo
|
||||
channel reconstruction which is the last part of the decoding process.
|
||||
|
||||
The ARM build has seen a few improvements. The CLZ (count leading zeroes) and REV (byte swap) instructions are now used when
|
||||
compiling with GCC and Clang which is achieved using inline assembly. The CLZ instruction requires ARM architecture version 5 at
|
||||
compile time and the REV instruction requires ARM architecture version 6.
|
||||
|
||||
An ARM NEON optimized pipeline has been implemented. To enable this you'll need to add -mfpu=neon to the command line when compiling.
|
||||
|
||||
|
||||
Removed APIs
|
||||
------------
|
||||
The following APIs were deprecated in version 0.11.0 and have been completely removed in version 0.12.0:
|
||||
|
||||
drflac_read_s32() -> drflac_read_pcm_frames_s32()
|
||||
drflac_read_s16() -> drflac_read_pcm_frames_s16()
|
||||
drflac_read_f32() -> drflac_read_pcm_frames_f32()
|
||||
drflac_seek_to_sample() -> drflac_seek_to_pcm_frame()
|
||||
drflac_open_and_decode_s32() -> drflac_open_and_read_pcm_frames_s32()
|
||||
drflac_open_and_decode_s16() -> drflac_open_and_read_pcm_frames_s16()
|
||||
drflac_open_and_decode_f32() -> drflac_open_and_read_pcm_frames_f32()
|
||||
drflac_open_and_decode_file_s32() -> drflac_open_file_and_read_pcm_frames_s32()
|
||||
drflac_open_and_decode_file_s16() -> drflac_open_file_and_read_pcm_frames_s16()
|
||||
drflac_open_and_decode_file_f32() -> drflac_open_file_and_read_pcm_frames_f32()
|
||||
drflac_open_and_decode_memory_s32() -> drflac_open_memory_and_read_pcm_frames_s32()
|
||||
drflac_open_and_decode_memory_s16() -> drflac_open_memory_and_read_pcm_frames_s16()
|
||||
drflac_open_and_decode_memory_f32() -> drflac_open_memroy_and_read_pcm_frames_f32()
|
||||
|
||||
Prior versions of dr_flac operated on a per-sample basis whereas now it operates on PCM frames. The removed APIs all relate
|
||||
to the old per-sample APIs. You now need to use the "pcm_frame" versions.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Introduction
|
||||
============
|
||||
@@ -234,8 +125,8 @@ extern "C" {
|
||||
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
|
||||
|
||||
#define DRFLAC_VERSION_MAJOR 0
|
||||
#define DRFLAC_VERSION_MINOR 12
|
||||
#define DRFLAC_VERSION_REVISION 42
|
||||
#define DRFLAC_VERSION_MINOR 13
|
||||
#define DRFLAC_VERSION_REVISION 0
|
||||
#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. */
|
||||
@@ -348,11 +239,11 @@ but also more memory. In my testing there is diminishing returns after about 4KB
|
||||
#define DRFLAC_64BIT
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
#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)
|
||||
#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 */
|
||||
@@ -406,8 +297,9 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
drflac_seek_origin_start,
|
||||
drflac_seek_origin_current
|
||||
DRFLAC_SEEK_SET,
|
||||
DRFLAC_SEEK_CUR,
|
||||
DRFLAC_SEEK_END
|
||||
} drflac_seek_origin;
|
||||
|
||||
/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */
|
||||
@@ -547,7 +439,7 @@ offset (in)
|
||||
The number of bytes to move, relative to the origin. Will never be negative.
|
||||
|
||||
origin (in)
|
||||
The origin of the seek - the current position or the start of the stream.
|
||||
The origin of the seek - the current position, the start of the stream, or the end of the stream.
|
||||
|
||||
|
||||
Return Value
|
||||
@@ -557,14 +449,32 @@ Whether or not the seek was successful.
|
||||
|
||||
Remarks
|
||||
-------
|
||||
The offset will never be negative. Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be
|
||||
either drflac_seek_origin_start or drflac_seek_origin_current.
|
||||
Seeking relative to the start and the current position must always be supported. If seeking from the end of the stream is not supported, return DRFLAC_FALSE.
|
||||
|
||||
When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected
|
||||
and handled by returning DRFLAC_FALSE.
|
||||
*/
|
||||
typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
|
||||
|
||||
/*
|
||||
Callback for when the current position in the stream needs to be retrieved.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pUserData (in)
|
||||
The user data that was passed to drflac_open() and family.
|
||||
|
||||
pCursor (out)
|
||||
A pointer to a variable to receive the current position in the stream.
|
||||
|
||||
|
||||
Return Value
|
||||
------------
|
||||
Whether or not the operation was successful.
|
||||
*/
|
||||
typedef drflac_bool32 (* drflac_tell_proc)(void* pUserData, drflac_int64* pCursor);
|
||||
|
||||
/*
|
||||
Callback for when a metadata block is read.
|
||||
|
||||
@@ -603,6 +513,9 @@ typedef struct
|
||||
/* The function to call when the current read position needs to be moved. */
|
||||
drflac_seek_proc onSeek;
|
||||
|
||||
/* The function to call when the current read position needs to be retrieved. */
|
||||
drflac_tell_proc onTell;
|
||||
|
||||
/* The user data to pass around to onRead and onSeek. */
|
||||
void* pUserData;
|
||||
|
||||
@@ -828,7 +741,7 @@ drflac_open_memory()
|
||||
drflac_open_with_metadata()
|
||||
drflac_close()
|
||||
*/
|
||||
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
|
||||
/*
|
||||
Opens a FLAC stream with relaxed validation of the header block.
|
||||
@@ -869,7 +782,7 @@ force your `onRead` callback to return 0, which dr_flac will use as an indicator
|
||||
|
||||
Use `drflac_open_with_metadata_relaxed()` if you need access to metadata.
|
||||
*/
|
||||
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
|
||||
/*
|
||||
Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
|
||||
@@ -926,7 +839,7 @@ drflac_open_memory_with_metadata()
|
||||
drflac_open()
|
||||
drflac_close()
|
||||
*/
|
||||
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
|
||||
/*
|
||||
The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present.
|
||||
@@ -936,7 +849,7 @@ See Also
|
||||
drflac_open_with_metadata()
|
||||
drflac_open_relaxed()
|
||||
*/
|
||||
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
|
||||
/*
|
||||
Closes the given FLAC decoder.
|
||||
@@ -1234,13 +1147,13 @@ read samples into a dynamically sized buffer on the heap until no samples are le
|
||||
|
||||
Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
|
||||
*/
|
||||
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
|
||||
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
|
||||
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
|
||||
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
|
||||
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||
|
||||
#ifndef DR_FLAC_NO_STDIO
|
||||
/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */
|
||||
@@ -2960,25 +2873,25 @@ static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFro
|
||||
*/
|
||||
if (offsetFromStart > 0x7FFFFFFF) {
|
||||
drflac_uint64 bytesRemaining = offsetFromStart;
|
||||
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
|
||||
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_SET)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
bytesRemaining -= 0x7FFFFFFF;
|
||||
|
||||
while (bytesRemaining > 0x7FFFFFFF) {
|
||||
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
|
||||
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
bytesRemaining -= 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
if (bytesRemaining > 0) {
|
||||
if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
|
||||
if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
|
||||
if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, DRFLAC_SEEK_SET)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -5393,6 +5306,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;
|
||||
@@ -5465,6 +5384,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:
|
||||
@@ -6312,6 +6243,7 @@ typedef struct
|
||||
{
|
||||
drflac_read_proc onRead;
|
||||
drflac_seek_proc onSeek;
|
||||
drflac_tell_proc onTell;
|
||||
drflac_meta_proc onMeta;
|
||||
drflac_container container;
|
||||
void* pUserData;
|
||||
@@ -6479,7 +6411,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* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, 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
|
||||
@@ -6489,6 +6421,8 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
||||
drflac_uint64 seektablePos = 0;
|
||||
drflac_uint32 seektableSize = 0;
|
||||
|
||||
(void)onTell;
|
||||
|
||||
for (;;) {
|
||||
drflac_metadata metadata;
|
||||
drflac_uint8 isLastBlock = 0;
|
||||
@@ -6840,7 +6774,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
||||
metadata.data.padding.unused = 0;
|
||||
|
||||
/* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */
|
||||
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
|
||||
isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
|
||||
} else {
|
||||
onMeta(pUserDataMD, &metadata);
|
||||
@@ -6852,7 +6786,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
||||
{
|
||||
/* Invalid chunk. Just skip over this one. */
|
||||
if (onMeta) {
|
||||
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
|
||||
isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
|
||||
}
|
||||
}
|
||||
@@ -6886,7 +6820,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
||||
|
||||
/* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */
|
||||
if (onMeta == NULL && blockSize > 0) {
|
||||
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
|
||||
isLastBlock = DRFLAC_TRUE;
|
||||
}
|
||||
}
|
||||
@@ -7220,6 +7154,7 @@ typedef struct
|
||||
{
|
||||
drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */
|
||||
drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */
|
||||
drflac_tell_proc onTell; /* The original onTell callback from drflac_open() and family. */
|
||||
void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */
|
||||
drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */
|
||||
drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */
|
||||
@@ -7241,32 +7176,32 @@ static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut,
|
||||
|
||||
static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin)
|
||||
{
|
||||
if (origin == drflac_seek_origin_start) {
|
||||
if (origin == DRFLAC_SEEK_SET) {
|
||||
if (offset <= 0x7FFFFFFF) {
|
||||
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
|
||||
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, DRFLAC_SEEK_SET)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
oggbs->currentBytePos = offset;
|
||||
|
||||
return DRFLAC_TRUE;
|
||||
} else {
|
||||
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
|
||||
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_SET)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
oggbs->currentBytePos = offset;
|
||||
|
||||
return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
|
||||
return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, DRFLAC_SEEK_CUR);
|
||||
}
|
||||
} else {
|
||||
while (offset > 0x7FFFFFFF) {
|
||||
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
|
||||
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
oggbs->currentBytePos += 0x7FFFFFFF;
|
||||
offset -= 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { /* <-- Safe cast thanks to the loop above. */
|
||||
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, DRFLAC_SEEK_CUR)) { /* <-- Safe cast thanks to the loop above. */
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
oggbs->currentBytePos += offset;
|
||||
@@ -7298,7 +7233,7 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og
|
||||
|
||||
if (header.serialNumber != oggbs->serialNumber) {
|
||||
/* It's not a FLAC page. Skip it. */
|
||||
if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) {
|
||||
if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
continue;
|
||||
@@ -7384,7 +7319,7 @@ static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
|
||||
At this point we will have found either the packet or the end of the page. If were at the end of the page we'll
|
||||
want to load the next page and keep searching for the end of the packet.
|
||||
*/
|
||||
drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
|
||||
drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, DRFLAC_SEEK_CUR);
|
||||
oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
|
||||
|
||||
if (atEndOfPage) {
|
||||
@@ -7462,8 +7397,8 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see
|
||||
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
|
||||
|
||||
/* Seeking is always forward which makes things a lot simpler. */
|
||||
if (origin == drflac_seek_origin_start) {
|
||||
if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) {
|
||||
if (origin == DRFLAC_SEEK_SET) {
|
||||
if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, DRFLAC_SEEK_SET)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
@@ -7471,11 +7406,8 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
|
||||
}
|
||||
|
||||
DRFLAC_ASSERT(origin == drflac_seek_origin_current);
|
||||
|
||||
return drflac__on_seek_ogg(pUserData, offset, DRFLAC_SEEK_CUR);
|
||||
} else if (origin == DRFLAC_SEEK_CUR) {
|
||||
while (bytesSeeked < offset) {
|
||||
int bytesRemainingToSeek = offset - bytesSeeked;
|
||||
DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
|
||||
@@ -7499,10 +7431,25 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
} else if (origin == DRFLAC_SEEK_END) {
|
||||
/* Seeking to the end is not supported. */
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
return DRFLAC_TRUE;
|
||||
}
|
||||
|
||||
static drflac_bool32 drflac__on_tell_ogg(void* pUserData, drflac_int64* pCursor)
|
||||
{
|
||||
/*
|
||||
Not implemented for Ogg containers because we don't currently track the byte position of the logical bitstream. To support this, we'll need
|
||||
to track the position in drflac__on_read_ogg and drflac__on_seek_ogg.
|
||||
*/
|
||||
(void)pUserData;
|
||||
(void)pCursor;
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
|
||||
{
|
||||
@@ -7525,7 +7472,7 @@ static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64
|
||||
runningGranulePosition = 0;
|
||||
for (;;) {
|
||||
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
|
||||
drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
|
||||
drflac_oggbs__seek_physical(oggbs, originalBytePos, DRFLAC_SEEK_SET);
|
||||
return DRFLAC_FALSE; /* Never did find that sample... */
|
||||
}
|
||||
|
||||
@@ -7559,7 +7506,7 @@ static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64
|
||||
a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
|
||||
we find the one containing the target sample.
|
||||
*/
|
||||
if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
|
||||
if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, DRFLAC_SEEK_SET)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
|
||||
@@ -7726,7 +7673,7 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
|
||||
The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to
|
||||
be handling it in a generic way based on the serial number and packet types.
|
||||
*/
|
||||
if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, 2, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
@@ -7783,18 +7730,18 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
|
||||
}
|
||||
} else {
|
||||
/* Not a FLAC header. Skip it. */
|
||||
if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, bytesRemainingInPage, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Not a FLAC header. Seek past the entire page and move on to the next. */
|
||||
if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, bytesRemainingInPage, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, pageBodySize, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -7819,18 +7766,19 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
|
||||
}
|
||||
#endif
|
||||
|
||||
static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
|
||||
static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
|
||||
{
|
||||
drflac_bool32 relaxed;
|
||||
drflac_uint8 id[4];
|
||||
|
||||
if (pInit == NULL || onRead == NULL || onSeek == NULL) {
|
||||
if (pInit == NULL || onRead == NULL || onSeek == NULL) { /* <-- onTell is optional. */
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit));
|
||||
pInit->onRead = onRead;
|
||||
pInit->onSeek = onSeek;
|
||||
pInit->onTell = onTell;
|
||||
pInit->onMeta = onMeta;
|
||||
pInit->container = container;
|
||||
pInit->pUserData = pUserData;
|
||||
@@ -7838,6 +7786,7 @@ static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_p
|
||||
|
||||
pInit->bs.onRead = onRead;
|
||||
pInit->bs.onSeek = onSeek;
|
||||
pInit->bs.onTell = onTell;
|
||||
pInit->bs.pUserData = pUserData;
|
||||
drflac__reset_cache(&pInit->bs);
|
||||
|
||||
@@ -7870,7 +7819,7 @@ static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_p
|
||||
headerSize += 10;
|
||||
}
|
||||
|
||||
if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, headerSize, DRFLAC_SEEK_CUR)) {
|
||||
return DRFLAC_FALSE; /* Failed to seek past the tag. */
|
||||
}
|
||||
pInit->runningFilePos += headerSize;
|
||||
@@ -7922,7 +7871,7 @@ static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
|
||||
}
|
||||
|
||||
|
||||
static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
drflac_init_info init;
|
||||
drflac_uint32 allocationSize;
|
||||
@@ -7940,7 +7889,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
||||
/* CPU support first. */
|
||||
drflac__init_cpu_caps();
|
||||
|
||||
if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
|
||||
if (!drflac__init_private(&init, onRead, onSeek, onTell, onMeta, container, pUserData, pUserDataMD)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -7996,6 +7945,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
||||
DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs));
|
||||
pOggbs->onRead = onRead;
|
||||
pOggbs->onSeek = onSeek;
|
||||
pOggbs->onTell = onTell;
|
||||
pOggbs->pUserData = pUserData;
|
||||
pOggbs->currentBytePos = init.oggFirstBytePos;
|
||||
pOggbs->firstBytePos = init.oggFirstBytePos;
|
||||
@@ -8016,17 +7966,19 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
||||
if (init.hasMetadataBlocks) {
|
||||
drflac_read_proc onReadOverride = onRead;
|
||||
drflac_seek_proc onSeekOverride = onSeek;
|
||||
drflac_tell_proc onTellOverride = onTell;
|
||||
void* pUserDataOverride = pUserData;
|
||||
|
||||
#ifndef DR_FLAC_NO_OGG
|
||||
if (init.container == drflac_container_ogg) {
|
||||
onReadOverride = drflac__on_read_ogg;
|
||||
onSeekOverride = drflac__on_seek_ogg;
|
||||
onTellOverride = drflac__on_tell_ogg;
|
||||
pUserDataOverride = (void*)pOggbs;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) {
|
||||
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onTellOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) {
|
||||
#ifndef DR_FLAC_NO_OGG
|
||||
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
|
||||
#endif
|
||||
@@ -8061,6 +8013,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
||||
/* The Ogg bistream needs to be layered on top of the original bitstream. */
|
||||
pFlac->bs.onRead = drflac__on_read_ogg;
|
||||
pFlac->bs.onSeek = drflac__on_seek_ogg;
|
||||
pFlac->bs.onTell = drflac__on_tell_ogg;
|
||||
pFlac->bs.pUserData = (void*)pInternalOggbs;
|
||||
pFlac->_oggbs = (void*)pInternalOggbs;
|
||||
}
|
||||
@@ -8087,7 +8040,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
||||
DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
|
||||
|
||||
/* 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.onSeek(pFlac->bs.pUserData, (int)seektablePos, DRFLAC_SEEK_SET)) {
|
||||
drflac_uint32 iSeekpoint;
|
||||
|
||||
for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) {
|
||||
@@ -8105,7 +8058,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
||||
}
|
||||
|
||||
/* We need to seek back to where we were. If this fails it's a critical error. */
|
||||
if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
|
||||
if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, DRFLAC_SEEK_SET)) {
|
||||
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
|
||||
return NULL;
|
||||
}
|
||||
@@ -8276,7 +8229,7 @@ static drflac_result drflac_result_from_errno(int e)
|
||||
#ifdef ENOSYS
|
||||
case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
#ifdef ENOTEMPTY
|
||||
#if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST /* In AIX, ENOTEMPTY and EEXIST use the same value. */
|
||||
case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
|
||||
#endif
|
||||
#ifdef ELOOP
|
||||
@@ -8727,11 +8680,41 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt
|
||||
|
||||
static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
|
||||
{
|
||||
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
|
||||
int whence = SEEK_SET;
|
||||
if (origin == DRFLAC_SEEK_CUR) {
|
||||
whence = SEEK_CUR;
|
||||
} else if (origin == DRFLAC_SEEK_END) {
|
||||
whence = SEEK_END;
|
||||
}
|
||||
|
||||
return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
|
||||
return fseek((FILE*)pUserData, offset, whence) == 0;
|
||||
}
|
||||
|
||||
static drflac_bool32 drflac__on_tell_stdio(void* pUserData, drflac_int64* pCursor)
|
||||
{
|
||||
FILE* pFileStdio = (FILE*)pUserData;
|
||||
drflac_int64 result;
|
||||
|
||||
/* These were all validated at a higher level. */
|
||||
DRFLAC_ASSERT(pFileStdio != NULL);
|
||||
DRFLAC_ASSERT(pCursor != NULL);
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
result = _ftelli64(pFileStdio);
|
||||
#else
|
||||
result = ftell(pFileStdio);
|
||||
#endif
|
||||
#else
|
||||
result = ftell(pFileStdio);
|
||||
#endif
|
||||
|
||||
*pCursor = result;
|
||||
|
||||
return DRFLAC_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
@@ -8742,7 +8725,7 @@ DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocati
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
|
||||
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
fclose(pFile);
|
||||
return NULL;
|
||||
@@ -8761,7 +8744,7 @@ DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_all
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
|
||||
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
fclose(pFile);
|
||||
return NULL;
|
||||
@@ -8780,7 +8763,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
|
||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
fclose(pFile);
|
||||
return pFlac;
|
||||
@@ -8799,7 +8782,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, dr
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
|
||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
fclose(pFile);
|
||||
return pFlac;
|
||||
@@ -8834,28 +8817,45 @@ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t by
|
||||
static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
|
||||
{
|
||||
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
|
||||
drflac_int64 newCursor;
|
||||
|
||||
DRFLAC_ASSERT(memoryStream != NULL);
|
||||
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
|
||||
|
||||
if (offset > (drflac_int64)memoryStream->dataSize) {
|
||||
newCursor = memoryStream->currentReadPos;
|
||||
|
||||
if (origin == DRFLAC_SEEK_SET) {
|
||||
newCursor = 0;
|
||||
} else if (origin == DRFLAC_SEEK_CUR) {
|
||||
newCursor = (drflac_int64)memoryStream->currentReadPos;
|
||||
} else if (origin == DRFLAC_SEEK_END) {
|
||||
newCursor = (drflac_int64)memoryStream->dataSize;
|
||||
} else {
|
||||
DRFLAC_ASSERT(!"Invalid seek origin");
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
|
||||
if (origin == drflac_seek_origin_current) {
|
||||
if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
|
||||
memoryStream->currentReadPos += offset;
|
||||
} else {
|
||||
return DRFLAC_FALSE; /* Trying to seek too far forward. */
|
||||
}
|
||||
} else {
|
||||
if ((drflac_uint32)offset <= memoryStream->dataSize) {
|
||||
memoryStream->currentReadPos = offset;
|
||||
} else {
|
||||
return DRFLAC_FALSE; /* Trying to seek too far forward. */
|
||||
newCursor += offset;
|
||||
|
||||
if (newCursor < 0) {
|
||||
return DRFLAC_FALSE; /* Trying to seek prior to the start of the buffer. */
|
||||
}
|
||||
if ((size_t)newCursor > memoryStream->dataSize) {
|
||||
return DRFLAC_FALSE; /* Trying to seek beyond the end of the buffer. */
|
||||
}
|
||||
|
||||
memoryStream->currentReadPos = (size_t)newCursor;
|
||||
|
||||
return DRFLAC_TRUE;
|
||||
}
|
||||
|
||||
static drflac_bool32 drflac__on_tell_memory(void* pUserData, drflac_int64* pCursor)
|
||||
{
|
||||
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
|
||||
|
||||
DRFLAC_ASSERT(memoryStream != NULL);
|
||||
DRFLAC_ASSERT(pCursor != NULL);
|
||||
|
||||
*pCursor = (drflac_int64)memoryStream->currentReadPos;
|
||||
return DRFLAC_TRUE;
|
||||
}
|
||||
|
||||
@@ -8867,7 +8867,7 @@ DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const
|
||||
memoryStream.data = (const drflac_uint8*)pData;
|
||||
memoryStream.dataSize = dataSize;
|
||||
memoryStream.currentReadPos = 0;
|
||||
pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks);
|
||||
pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, drflac__on_tell_memory, &memoryStream, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -8898,7 +8898,7 @@ DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t da
|
||||
memoryStream.data = (const drflac_uint8*)pData;
|
||||
memoryStream.dataSize = dataSize;
|
||||
memoryStream.currentReadPos = 0;
|
||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
|
||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, drflac__on_tell_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -8923,22 +8923,22 @@ DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t da
|
||||
|
||||
|
||||
|
||||
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
|
||||
return drflac_open_with_metadata_private(onRead, onSeek, onTell, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
|
||||
}
|
||||
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
|
||||
return drflac_open_with_metadata_private(onRead, onSeek, onTell, NULL, container, pUserData, pUserData, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
|
||||
return drflac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
|
||||
}
|
||||
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
|
||||
return drflac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
DRFLAC_API void drflac_close(drflac* pFlac)
|
||||
@@ -11770,7 +11770,7 @@ DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
|
||||
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
|
||||
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
|
||||
|
||||
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
drflac* pFlac;
|
||||
|
||||
@@ -11784,7 +11784,7 @@ DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc on
|
||||
*totalPCMFrameCountOut = 0;
|
||||
}
|
||||
|
||||
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
|
||||
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -11792,7 +11792,7 @@ DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc on
|
||||
return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
|
||||
}
|
||||
|
||||
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
drflac* pFlac;
|
||||
|
||||
@@ -11806,7 +11806,7 @@ DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc on
|
||||
*totalPCMFrameCountOut = 0;
|
||||
}
|
||||
|
||||
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
|
||||
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -11814,7 +11814,7 @@ DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc on
|
||||
return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
|
||||
}
|
||||
|
||||
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
drflac* pFlac;
|
||||
|
||||
@@ -11828,7 +11828,7 @@ DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, d
|
||||
*totalPCMFrameCountOut = 0;
|
||||
}
|
||||
|
||||
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
|
||||
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
|
||||
if (pFlac == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -12077,6 +12077,26 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
|
||||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.13.0 - TBD
|
||||
- API CHANGE: Seek origin enums have been renamed to match the naming convention used by other dr_libs libraries:
|
||||
- drflac_seek_origin_start -> DRFLAC_SEEK_SET
|
||||
- drflac_seek_origin_current -> DRFLAC_SEEK_CUR
|
||||
- DRFLAC_SEEK_END (new)
|
||||
- API CHANGE: A new seek origin has been added to allow seeking from the end of the file. If you implement your own `onSeek` callback, you should now detect and handle `DRFLAC_SEEK_END`. If seeking to the end is not supported, return `DRFLAC_FALSE`. If you only use `*_open_file()` or `*_open_memory()`, you need not change anything.
|
||||
- API CHANGE: An `onTell` callback has been added to the following functions:
|
||||
- drflac_open()
|
||||
- drflac_open_relaxed()
|
||||
- drflac_open_with_metadata()
|
||||
- drflac_open_with_metadata_relaxed()
|
||||
- drflac_open_and_read_pcm_frames_s32()
|
||||
- drflac_open_and_read_pcm_frames_s16()
|
||||
- drflac_open_and_read_pcm_frames_f32()
|
||||
- Fix compilation for AIX OS.
|
||||
|
||||
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.
|
||||
|
859
src/external/dr_mp3.h
vendored
859
src/external/dr_mp3.h
vendored
File diff suppressed because it is too large
Load Diff
430
src/external/dr_wav.h
vendored
430
src/external/dr_wav.h
vendored
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_wav - v0.13.16 - 2024-02-27
|
||||
dr_wav - v0.14.0 - TBD
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
@@ -146,8 +146,8 @@ extern "C" {
|
||||
#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
|
||||
|
||||
#define DRWAV_VERSION_MAJOR 0
|
||||
#define DRWAV_VERSION_MINOR 13
|
||||
#define DRWAV_VERSION_REVISION 16
|
||||
#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. */
|
||||
@@ -176,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;
|
||||
@@ -305,8 +305,9 @@ typedef struct
|
||||
|
||||
typedef enum
|
||||
{
|
||||
drwav_seek_origin_start,
|
||||
drwav_seek_origin_current
|
||||
DRWAV_SEEK_SET,
|
||||
DRWAV_SEEK_CUR,
|
||||
DRWAV_SEEK_END
|
||||
} drwav_seek_origin;
|
||||
|
||||
typedef enum
|
||||
@@ -415,11 +416,21 @@ origin [in] The origin of the seek - the current position or the start of the
|
||||
|
||||
Returns whether or not the seek was successful.
|
||||
|
||||
Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either drwav_seek_origin_start or
|
||||
drwav_seek_origin_current.
|
||||
Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either DRWAV_SEEK_SET or
|
||||
DRWAV_SEEK_CUR.
|
||||
*/
|
||||
typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
|
||||
|
||||
/*
|
||||
Callback for when the current position in the stream needs to be retrieved.
|
||||
|
||||
pUserData [in] The user data that was passed to drwav_init() and family.
|
||||
pCursor [out] A pointer to a variable to receive the current position in the stream.
|
||||
|
||||
Returns whether or not the operation was successful.
|
||||
*/
|
||||
typedef drwav_bool32 (* drwav_tell_proc)(void* pUserData, drwav_int64* pCursor);
|
||||
|
||||
/*
|
||||
Callback for when drwav_init_ex() finds a chunk.
|
||||
|
||||
@@ -514,6 +525,11 @@ typedef enum
|
||||
drwav_metadata_type_list_info_genre = 1 << 15,
|
||||
drwav_metadata_type_list_info_album = 1 << 16,
|
||||
drwav_metadata_type_list_info_tracknumber = 1 << 17,
|
||||
drwav_metadata_type_list_info_location = 1 << 18,
|
||||
drwav_metadata_type_list_info_organization = 1 << 19,
|
||||
drwav_metadata_type_list_info_keywords = 1 << 20,
|
||||
drwav_metadata_type_list_info_medium = 1 << 21,
|
||||
drwav_metadata_type_list_info_description = 1 << 22,
|
||||
|
||||
/* Other type constants for convenience. */
|
||||
drwav_metadata_type_list_all_info_strings = drwav_metadata_type_list_info_software
|
||||
@@ -524,7 +540,12 @@ typedef enum
|
||||
| drwav_metadata_type_list_info_date
|
||||
| drwav_metadata_type_list_info_genre
|
||||
| drwav_metadata_type_list_info_album
|
||||
| drwav_metadata_type_list_info_tracknumber,
|
||||
| drwav_metadata_type_list_info_tracknumber
|
||||
| drwav_metadata_type_list_info_location
|
||||
| drwav_metadata_type_list_info_organization
|
||||
| drwav_metadata_type_list_info_keywords
|
||||
| drwav_metadata_type_list_info_medium
|
||||
| drwav_metadata_type_list_info_description,
|
||||
|
||||
drwav_metadata_type_list_all_adtl = drwav_metadata_type_list_label
|
||||
| drwav_metadata_type_list_note
|
||||
@@ -555,11 +576,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;
|
||||
@@ -637,8 +658,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
|
||||
@@ -846,6 +867,9 @@ typedef struct
|
||||
/* A pointer to the function to call when the wav file needs to be seeked. */
|
||||
drwav_seek_proc onSeek;
|
||||
|
||||
/* A pointer to the function to call when the position of the stream needs to be retrieved. */
|
||||
drwav_tell_proc onTell;
|
||||
|
||||
/* The user data to pass to callbacks. */
|
||||
void* pUserData;
|
||||
|
||||
@@ -968,9 +992,9 @@ after the function returns.
|
||||
|
||||
See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
|
||||
*/
|
||||
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, drwav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
|
||||
/*
|
||||
Initializes a pre-allocated drwav object for writing.
|
||||
@@ -1273,9 +1297,9 @@ Opens and reads an entire wav file in a single operation.
|
||||
|
||||
The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
|
||||
*/
|
||||
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||
#ifndef DR_WAV_NO_STDIO
|
||||
/*
|
||||
Opens and decodes an entire wav file in a single operation.
|
||||
@@ -1384,7 +1408,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
|
||||
@@ -1962,12 +1986,12 @@ DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uin
|
||||
drwav_uint64 bytesRemainingToSeek = offset;
|
||||
while (bytesRemainingToSeek > 0) {
|
||||
if (bytesRemainingToSeek > 0x7FFFFFFF) {
|
||||
if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_CUR)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
bytesRemainingToSeek -= 0x7FFFFFFF;
|
||||
} else {
|
||||
if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, (int)bytesRemainingToSeek, DRWAV_SEEK_CUR)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
bytesRemainingToSeek = 0;
|
||||
@@ -1980,21 +2004,21 @@ DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uin
|
||||
DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
|
||||
{
|
||||
if (offset <= 0x7FFFFFFF) {
|
||||
return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
|
||||
return onSeek(pUserData, (int)offset, DRWAV_SEEK_SET);
|
||||
}
|
||||
|
||||
/* Larger than 32-bit seek. */
|
||||
if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
|
||||
if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_SET)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
offset -= 0x7FFFFFFF;
|
||||
|
||||
for (;;) {
|
||||
if (offset <= 0x7FFFFFFF) {
|
||||
return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
|
||||
return onSeek(pUserData, (int)offset, DRWAV_SEEK_CUR);
|
||||
}
|
||||
|
||||
if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
|
||||
if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_CUR)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
offset -= 0x7FFFFFFF;
|
||||
@@ -2028,7 +2052,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserDat
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
if (origin == drwav_seek_origin_start) {
|
||||
if (origin == DRWAV_SEEK_SET) {
|
||||
*pCursor = offset;
|
||||
} else {
|
||||
*pCursor += offset;
|
||||
@@ -2191,8 +2215,8 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars
|
||||
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].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 {
|
||||
@@ -2254,7 +2278,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;
|
||||
}
|
||||
@@ -2698,7 +2722,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
||||
drwav_uint8 buffer[4];
|
||||
size_t bytesJustRead;
|
||||
|
||||
if (!pParser->onSeek(pParser->pReadSeekUserData, 28, drwav_seek_origin_current)) {
|
||||
if (!pParser->onSeek(pParser->pReadSeekUserData, 28, DRWAV_SEEK_CUR)) {
|
||||
return bytesRead;
|
||||
}
|
||||
bytesRead += 28;
|
||||
@@ -2811,7 +2835,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
||||
return bytesRead;
|
||||
}
|
||||
allocSizeNeeded += drwav__strlen(buffer) + 1;
|
||||
allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES; /* Coding history. */
|
||||
allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES + 1; /* Coding history. */
|
||||
|
||||
drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
|
||||
|
||||
@@ -2916,6 +2940,16 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album);
|
||||
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) {
|
||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber);
|
||||
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_location, "IARL")) {
|
||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_location);
|
||||
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_organization, "ICMS")) {
|
||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_organization);
|
||||
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_keywords, "IKEY")) {
|
||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_keywords);
|
||||
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_medium, "IMED")) {
|
||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_medium);
|
||||
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_description, "ISBJ")) {
|
||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_description);
|
||||
} else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
|
||||
subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType);
|
||||
}
|
||||
@@ -2926,14 +2960,14 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
||||
if (subchunkBytesRead < subchunkDataSize) {
|
||||
drwav_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead;
|
||||
|
||||
if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, drwav_seek_origin_current)) {
|
||||
if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, DRWAV_SEEK_CUR)) {
|
||||
break;
|
||||
}
|
||||
bytesRead += bytesToSeek;
|
||||
}
|
||||
|
||||
if ((subchunkDataSize % 2) == 1) {
|
||||
if (!pParser->onSeek(pParser->pReadSeekUserData, 1, drwav_seek_origin_current)) {
|
||||
if (!pParser->onSeek(pParser->pReadSeekUserData, 1, DRWAV_SEEK_CUR)) {
|
||||
break;
|
||||
}
|
||||
bytesRead += 1;
|
||||
@@ -2985,16 +3019,17 @@ DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
|
||||
}
|
||||
}
|
||||
|
||||
DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pReadSeekTellUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
if (pWav == NULL || onRead == NULL || onSeek == NULL) {
|
||||
if (pWav == NULL || onRead == NULL || onSeek == NULL) { /* <-- onTell is optional. */
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
|
||||
pWav->onRead = onRead;
|
||||
pWav->onSeek = onSeek;
|
||||
pWav->pUserData = pReadSeekUserData;
|
||||
pWav->onTell = onTell;
|
||||
pWav->pUserData = pReadSeekTellUserData;
|
||||
pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
|
||||
|
||||
if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
|
||||
@@ -3311,7 +3346,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
||||
fmt.channelMask = drwav_bytes_to_u32_ex(fmtext + 2, pWav->container);
|
||||
drwav_bytes_to_guid(fmtext + 6, fmt.subFormat);
|
||||
} else {
|
||||
if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, drwav_seek_origin_current) == DRWAV_FALSE) {
|
||||
if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, DRWAV_SEEK_CUR) == DRWAV_FALSE) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -3321,7 +3356,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
||||
}
|
||||
|
||||
/* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */
|
||||
if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current) == DRWAV_FALSE) {
|
||||
if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), DRWAV_SEEK_CUR) == DRWAV_FALSE) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
cursor += (header.sizeInBytes - bytesReadSoFar);
|
||||
@@ -3471,6 +3506,9 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
||||
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. */
|
||||
@@ -3533,20 +3571,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);
|
||||
pWav->dataChunkDataPos = cursor + offset;
|
||||
|
||||
/* 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 (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;
|
||||
|
||||
pWav->dataChunkDataPos = cursor;
|
||||
dataChunkSize = chunkSize;
|
||||
|
||||
/* 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. */
|
||||
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;
|
||||
}
|
||||
@@ -3557,7 +3621,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);
|
||||
@@ -3647,8 +3710,26 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
||||
pWav->metadataCount = metadataParser.metadataCount;
|
||||
}
|
||||
|
||||
|
||||
/* At this point we should be sitting on the first byte of the raw audio data. */
|
||||
/*
|
||||
It's possible for the size reported in the data chunk to be greater than that of the file. We
|
||||
need to do a validation check here to make sure we don't exceed the file size. To skip this
|
||||
check, set the onTell callback to NULL.
|
||||
*/
|
||||
if (pWav->onTell != NULL && pWav->onSeek != NULL) {
|
||||
if (pWav->onSeek(pWav->pUserData, 0, DRWAV_SEEK_END) == DRWAV_TRUE) {
|
||||
drwav_int64 fileSize;
|
||||
if (pWav->onTell(pWav->pUserData, &fileSize)) {
|
||||
if (dataChunkSize + pWav->dataChunkDataPos > (drwav_uint64)fileSize) {
|
||||
dataChunkSize = (drwav_uint64)fileSize - pWav->dataChunkDataPos;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
Failed to seek to the end of the file. It might not be supported by the backend so in
|
||||
this case we cannot perform the validation check.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
I've seen a WAV file in the wild where a RIFF-ecapsulated file has the size of it's "RIFF" and
|
||||
@@ -3670,6 +3751,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point we want to 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;
|
||||
@@ -3680,8 +3762,26 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
||||
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) {
|
||||
@@ -3764,23 +3864,23 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
||||
return DRWAV_TRUE;
|
||||
}
|
||||
|
||||
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
|
||||
return drwav_init_ex(pWav, onRead, onSeek, onTell, NULL, pUserData, NULL, 0, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, drwav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
|
||||
if (!drwav_preinit(pWav, onRead, onSeek, onTell, pReadSeekTellUserData, pAllocationCallbacks)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
|
||||
}
|
||||
|
||||
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
if (!drwav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
|
||||
if (!drwav_preinit(pWav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
@@ -3995,8 +4095,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);
|
||||
}
|
||||
@@ -4036,7 +4136,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;
|
||||
|
||||
@@ -4151,6 +4251,11 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata*
|
||||
case drwav_metadata_type_list_info_genre: pID = "IGNR"; break;
|
||||
case drwav_metadata_type_list_info_album: pID = "IPRD"; break;
|
||||
case drwav_metadata_type_list_info_tracknumber: pID = "ITRK"; break;
|
||||
case drwav_metadata_type_list_info_location: pID = "IARL"; break;
|
||||
case drwav_metadata_type_list_info_organization: pID = "ICMS"; break;
|
||||
case drwav_metadata_type_list_info_keywords: pID = "IKEY"; break;
|
||||
case drwav_metadata_type_list_info_medium: pID = "IMED"; break;
|
||||
case drwav_metadata_type_list_info_description: pID = "ISBJ"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -4434,7 +4539,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_d
|
||||
|
||||
/* "RIFF" chunk. */
|
||||
if (pFormat->container == drwav_container_riff) {
|
||||
drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; /* +28 = "WAVE" + [sizeof "fmt " chunk] */
|
||||
drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize; /* +36 = "WAVE" + [sizeof "fmt " chunk] + [data chunk header] */
|
||||
runningPos += drwav__write(pWav, "RIFF", 4);
|
||||
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
|
||||
runningPos += drwav__write(pWav, "WAVE", 4);
|
||||
@@ -4704,7 +4809,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
|
||||
@@ -5161,7 +5266,38 @@ DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, s
|
||||
|
||||
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
|
||||
{
|
||||
return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
|
||||
int whence = SEEK_SET;
|
||||
if (origin == DRWAV_SEEK_CUR) {
|
||||
whence = SEEK_CUR;
|
||||
} else if (origin == DRWAV_SEEK_END) {
|
||||
whence = SEEK_END;
|
||||
}
|
||||
|
||||
return fseek((FILE*)pUserData, offset, whence) == 0;
|
||||
}
|
||||
|
||||
DRWAV_PRIVATE drwav_bool32 drwav__on_tell_stdio(void* pUserData, drwav_int64* pCursor)
|
||||
{
|
||||
FILE* pFileStdio = (FILE*)pUserData;
|
||||
drwav_int64 result;
|
||||
|
||||
/* These were all validated at a higher level. */
|
||||
DRWAV_ASSERT(pFileStdio != NULL);
|
||||
DRWAV_ASSERT(pCursor != NULL);
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
result = _ftelli64(pFileStdio);
|
||||
#else
|
||||
result = ftell(pFileStdio);
|
||||
#endif
|
||||
#else
|
||||
result = ftell(pFileStdio);
|
||||
#endif
|
||||
|
||||
*pCursor = result;
|
||||
|
||||
return DRWAV_TRUE;
|
||||
}
|
||||
|
||||
DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
@@ -5174,7 +5310,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFi
|
||||
{
|
||||
drwav_bool32 result;
|
||||
|
||||
result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
|
||||
result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, drwav__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
|
||||
if (result != DRWAV_TRUE) {
|
||||
fclose(pFile);
|
||||
return result;
|
||||
@@ -5352,29 +5488,34 @@ DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, si
|
||||
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
|
||||
{
|
||||
drwav* pWav = (drwav*)pUserData;
|
||||
drwav_int64 newCursor;
|
||||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
|
||||
if (origin == drwav_seek_origin_current) {
|
||||
if (offset > 0) {
|
||||
if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
|
||||
return DRWAV_FALSE; /* Trying to seek too far forward. */
|
||||
}
|
||||
newCursor = pWav->memoryStream.currentReadPos;
|
||||
|
||||
if (origin == DRWAV_SEEK_SET) {
|
||||
newCursor = 0;
|
||||
} else if (origin == DRWAV_SEEK_CUR) {
|
||||
newCursor = (drwav_int64)pWav->memoryStream.currentReadPos;
|
||||
} else if (origin == DRWAV_SEEK_END) {
|
||||
newCursor = (drwav_int64)pWav->memoryStream.dataSize;
|
||||
} else {
|
||||
if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
|
||||
return DRWAV_FALSE; /* Trying to seek too far backwards. */
|
||||
}
|
||||
DRWAV_ASSERT(!"Invalid seek origin");
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
/* This will never underflow thanks to the clamps above. */
|
||||
pWav->memoryStream.currentReadPos += offset;
|
||||
} else {
|
||||
if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
|
||||
pWav->memoryStream.currentReadPos = offset;
|
||||
} else {
|
||||
return DRWAV_FALSE; /* Trying to seek too far forward. */
|
||||
newCursor += offset;
|
||||
|
||||
if (newCursor < 0) {
|
||||
return DRWAV_FALSE; /* Trying to seek prior to the start of the buffer. */
|
||||
}
|
||||
if ((size_t)newCursor > pWav->memoryStream.dataSize) {
|
||||
return DRWAV_FALSE; /* Trying to seek beyond the end of the buffer. */
|
||||
}
|
||||
|
||||
pWav->memoryStream.currentReadPos = (size_t)newCursor;
|
||||
|
||||
return DRWAV_TRUE;
|
||||
}
|
||||
|
||||
@@ -5421,29 +5562,45 @@ DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn
|
||||
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
|
||||
{
|
||||
drwav* pWav = (drwav*)pUserData;
|
||||
drwav_int64 newCursor;
|
||||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
|
||||
if (origin == drwav_seek_origin_current) {
|
||||
if (offset > 0) {
|
||||
if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
|
||||
offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); /* Trying to seek too far forward. */
|
||||
}
|
||||
newCursor = pWav->memoryStreamWrite.currentWritePos;
|
||||
|
||||
if (origin == DRWAV_SEEK_SET) {
|
||||
newCursor = 0;
|
||||
} else if (origin == DRWAV_SEEK_CUR) {
|
||||
newCursor = (drwav_int64)pWav->memoryStreamWrite.currentWritePos;
|
||||
} else if (origin == DRWAV_SEEK_END) {
|
||||
newCursor = (drwav_int64)pWav->memoryStreamWrite.dataSize;
|
||||
} else {
|
||||
if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
|
||||
offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */
|
||||
}
|
||||
DRWAV_ASSERT(!"Invalid seek origin");
|
||||
return DRWAV_INVALID_ARGS;
|
||||
}
|
||||
|
||||
/* This will never underflow thanks to the clamps above. */
|
||||
pWav->memoryStreamWrite.currentWritePos += offset;
|
||||
} else {
|
||||
if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
|
||||
pWav->memoryStreamWrite.currentWritePos = offset;
|
||||
} else {
|
||||
pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */
|
||||
newCursor += offset;
|
||||
|
||||
if (newCursor < 0) {
|
||||
return DRWAV_FALSE; /* Trying to seek prior to the start of the buffer. */
|
||||
}
|
||||
if ((size_t)newCursor > pWav->memoryStreamWrite.dataSize) {
|
||||
return DRWAV_FALSE; /* Trying to seek beyond the end of the buffer. */
|
||||
}
|
||||
|
||||
pWav->memoryStreamWrite.currentWritePos = (size_t)newCursor;
|
||||
|
||||
return DRWAV_TRUE;
|
||||
}
|
||||
|
||||
DRWAV_PRIVATE drwav_bool32 drwav__on_tell_memory(void* pUserData, drwav_int64* pCursor)
|
||||
{
|
||||
drwav* pWav = (drwav*)pUserData;
|
||||
|
||||
DRWAV_ASSERT(pWav != NULL);
|
||||
DRWAV_ASSERT(pCursor != NULL);
|
||||
|
||||
*pCursor = (drwav_int64)pWav->memoryStream.currentReadPos;
|
||||
return DRWAV_TRUE;
|
||||
}
|
||||
|
||||
@@ -5458,7 +5615,7 @@ DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
|
||||
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, drwav__on_tell_memory, pWav, pAllocationCallbacks)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
@@ -5475,7 +5632,7 @@ DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void*
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
|
||||
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, drwav__on_tell_memory, pWav, pAllocationCallbacks)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
@@ -5565,25 +5722,25 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
|
||||
if (pWav->onSeek && !pWav->isSequentialWrite) {
|
||||
if (pWav->container == drwav_container_riff) {
|
||||
/* The "RIFF" chunk size. */
|
||||
if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
|
||||
if (pWav->onSeek(pWav->pUserData, 4, DRWAV_SEEK_SET)) {
|
||||
drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
|
||||
drwav__write_u32ne_to_le(pWav, riffChunkSize);
|
||||
}
|
||||
|
||||
/* The "data" chunk size. */
|
||||
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, drwav_seek_origin_start)) {
|
||||
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, DRWAV_SEEK_SET)) {
|
||||
drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
|
||||
drwav__write_u32ne_to_le(pWav, dataChunkSize);
|
||||
}
|
||||
} else if (pWav->container == drwav_container_w64) {
|
||||
/* The "RIFF" chunk size. */
|
||||
if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
|
||||
if (pWav->onSeek(pWav->pUserData, 16, DRWAV_SEEK_SET)) {
|
||||
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
|
||||
drwav__write_u64ne_to_le(pWav, riffChunkSize);
|
||||
}
|
||||
|
||||
/* The "data" chunk size. */
|
||||
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, drwav_seek_origin_start)) {
|
||||
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, DRWAV_SEEK_SET)) {
|
||||
drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
|
||||
drwav__write_u64ne_to_le(pWav, dataChunkSize);
|
||||
}
|
||||
@@ -5592,13 +5749,13 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
|
||||
int ds64BodyPos = 12 + 8;
|
||||
|
||||
/* The "RIFF" chunk size. */
|
||||
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
|
||||
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, DRWAV_SEEK_SET)) {
|
||||
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
|
||||
drwav__write_u64ne_to_le(pWav, riffChunkSize);
|
||||
}
|
||||
|
||||
/* The "data" chunk size. */
|
||||
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
|
||||
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, DRWAV_SEEK_SET)) {
|
||||
drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
|
||||
drwav__write_u64ne_to_le(pWav, dataChunkSize);
|
||||
}
|
||||
@@ -5663,7 +5820,7 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu
|
||||
bytesToSeek = 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) {
|
||||
if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, DRWAV_SEEK_CUR) == DRWAV_FALSE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5810,7 +5967,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
|
||||
return DRWAV_FALSE; /* No seeking in write mode. */
|
||||
}
|
||||
|
||||
if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
|
||||
if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, DRWAV_SEEK_SET)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
@@ -5928,7 +6085,7 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF
|
||||
|
||||
while (offset > 0) {
|
||||
int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
|
||||
if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
|
||||
if (!pWav->onSeek(pWav->pUserData, offset32, DRWAV_SEEK_CUR)) {
|
||||
return DRWAV_FALSE;
|
||||
}
|
||||
|
||||
@@ -6101,6 +6258,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);
|
||||
|
||||
@@ -6126,6 +6290,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];
|
||||
@@ -6148,6 +6317,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. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6181,13 +6355,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;
|
||||
@@ -6320,7 +6487,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin
|
||||
pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
|
||||
|
||||
if (header[2] >= drwav_countof(stepTable)) {
|
||||
pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
|
||||
pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, DRWAV_SEEK_CUR);
|
||||
pWav->ima.bytesRemainingInBlock = 0;
|
||||
return totalFramesRead; /* Invalid data. */
|
||||
}
|
||||
@@ -6338,7 +6505,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin
|
||||
pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
|
||||
|
||||
if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
|
||||
pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
|
||||
pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, DRWAV_SEEK_CUR);
|
||||
pWav->ima.bytesRemainingInBlock = 0;
|
||||
return totalFramesRead; /* Invalid data. */
|
||||
}
|
||||
@@ -8006,7 +8173,7 @@ DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, uns
|
||||
|
||||
|
||||
|
||||
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
drwav wav;
|
||||
|
||||
@@ -8020,14 +8187,14 @@ DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead
|
||||
*totalFrameCountOut = 0;
|
||||
}
|
||||
|
||||
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
|
||||
if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
|
||||
}
|
||||
|
||||
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
drwav wav;
|
||||
|
||||
@@ -8041,14 +8208,14 @@ DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwa
|
||||
*totalFrameCountOut = 0;
|
||||
}
|
||||
|
||||
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
|
||||
if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
|
||||
}
|
||||
|
||||
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
drwav wav;
|
||||
|
||||
@@ -8062,7 +8229,7 @@ DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead
|
||||
*totalFrameCountOut = 0;
|
||||
}
|
||||
|
||||
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
|
||||
if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -8350,6 +8517,27 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
|
||||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.14.0 - TBD
|
||||
- API CHANGE: Seek origin enums have been renamed to the following:
|
||||
- drwav_seek_origin_start -> DRWAV_SEEK_SET
|
||||
- drwav_seek_origin_current -> DRWAV_SEEK_CUR
|
||||
- DRWAV_SEEK_END (new)
|
||||
- API CHANGE: A new seek origin has been added to allow seeking from the end of the file. If you implement your own `onSeek` callback, you must now handle `DRWAV_SEEK_END`. If you only use `*_init_file()` or `*_init_memory()`, you need not change anything.
|
||||
- API CHANGE: An `onTell` callback has been added to the following functions:
|
||||
- drwav_init()
|
||||
- drwav_init_ex()
|
||||
- drwav_init_with_metadata()
|
||||
- drwav_open_and_read_pcm_frames_s16()
|
||||
- drwav_open_and_read_pcm_frames_f32()
|
||||
- drwav_open_and_read_pcm_frames_s32()
|
||||
- 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.
|
||||
|
||||
|
Reference in New Issue
Block a user