mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
(dr_mp3.h) Fix C89_BUILD issues
This commit is contained in:
parent
3583e1e501
commit
e3ce768ad0
595
deps/dr/dr_mp3.h
vendored
595
deps/dr/dr_mp3.h
vendored
@ -9,6 +9,7 @@ extern "C" {
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
typedef int8_t drmp3_int8;
|
||||
typedef uint8_t drmp3_uint8;
|
||||
@ -312,7 +313,7 @@ typedef __m128 drmp3_f4;
|
||||
#if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)
|
||||
#define drmp3_cpuid __cpuid
|
||||
#else
|
||||
static __inline__ __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], const int InfoType)
|
||||
static INLINE __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], const int InfoType)
|
||||
{
|
||||
#if defined(__PIC__)
|
||||
__asm__ __volatile__(
|
||||
@ -1600,13 +1601,14 @@ static void drmp3d_DCT_II(float *grbuf, int n)
|
||||
|
||||
static short drmp3d_scale_pcm(float sample)
|
||||
{
|
||||
if (sample > 32767.0) return (short) 32767;
|
||||
if (sample < -32768.0) return (short)-32768;
|
||||
int s = (int)(sample + .5f);
|
||||
s -= (s < 0); /* away from zero, to be compliant */
|
||||
if (s > 32767) return (short) 32767;
|
||||
if (s < -32768) return (short)-32768;
|
||||
return (short)s;
|
||||
int s;
|
||||
if (sample > 32767.0) return (short) 32767;
|
||||
if (sample < -32768.0) return (short)-32768;
|
||||
s = (int)(sample + .5f);
|
||||
s -= (s < 0); /* away from zero, to be compliant */
|
||||
if (s > 32767) return (short) 32767;
|
||||
if (s < -32768) return (short)-32768;
|
||||
return (short)s;
|
||||
}
|
||||
|
||||
static void drmp3d_synth_pair(short *pcm, int nch, const float *z)
|
||||
@ -1986,14 +1988,15 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes
|
||||
|
||||
#define DRMP3_DATA_CHUNK_SIZE 16384 /* The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends 16K. */
|
||||
|
||||
static inline float drmp3_mix_f32(float x, float y, float a)
|
||||
static INLINE float drmp3_mix_f32(float x, float y, float a)
|
||||
{
|
||||
return x*(1-a) + y*a;
|
||||
}
|
||||
|
||||
static void drmp3_blend_f32(float* pOut, float* pInA, float* pInB, float factor, drmp3_uint32 channels)
|
||||
{
|
||||
for (drmp3_uint32 i = 0; i < channels; ++i)
|
||||
uint32_t i;
|
||||
for (i = 0; i < channels; ++i)
|
||||
pOut[i] = drmp3_mix_f32(pInA[i], pInB[i], factor);
|
||||
}
|
||||
|
||||
@ -2009,52 +2012,55 @@ void drmp3_src_cache_init(drmp3_src* pSRC, drmp3_src_cache* pCache)
|
||||
|
||||
drmp3_uint64 drmp3_src_cache_read_frames(drmp3_src_cache* pCache, drmp3_uint64 frameCount, float* pFramesOut)
|
||||
{
|
||||
drmp3_assert(pCache != NULL);
|
||||
drmp3_assert(pCache->pSRC != NULL);
|
||||
drmp3_assert(pCache->pSRC->onRead != NULL);
|
||||
drmp3_assert(frameCount > 0);
|
||||
drmp3_assert(pFramesOut != NULL);
|
||||
drmp3_uint32 channels;
|
||||
drmp3_uint64 totalFramesRead = 0;
|
||||
|
||||
drmp3_uint32 channels = pCache->pSRC->config.channels;
|
||||
drmp3_assert(pCache != NULL);
|
||||
drmp3_assert(pCache->pSRC != NULL);
|
||||
drmp3_assert(pCache->pSRC->onRead != NULL);
|
||||
drmp3_assert(frameCount > 0);
|
||||
drmp3_assert(pFramesOut != NULL);
|
||||
|
||||
drmp3_uint64 totalFramesRead = 0;
|
||||
while (frameCount > 0)
|
||||
{
|
||||
/* If there's anything in memory go ahead and copy that over first. */
|
||||
drmp3_uint64 framesRemainingInMemory = pCache->cachedFrameCount - pCache->iNextFrame;
|
||||
drmp3_uint64 framesToReadFromMemory = frameCount;
|
||||
if (framesToReadFromMemory > framesRemainingInMemory)
|
||||
framesToReadFromMemory = framesRemainingInMemory;
|
||||
channels = pCache->pSRC->config.channels;
|
||||
|
||||
drmp3_copy_memory(pFramesOut, pCache->pCachedFrames + pCache->iNextFrame*channels, (drmp3_uint32)(framesToReadFromMemory * channels * sizeof(float)));
|
||||
pCache->iNextFrame += (drmp3_uint32)framesToReadFromMemory;
|
||||
while (frameCount > 0)
|
||||
{
|
||||
drmp3_uint32 framesToReadFromClient;
|
||||
/* If there's anything in memory go ahead and copy that over first. */
|
||||
drmp3_uint64 framesRemainingInMemory = pCache->cachedFrameCount - pCache->iNextFrame;
|
||||
drmp3_uint64 framesToReadFromMemory = frameCount;
|
||||
if (framesToReadFromMemory > framesRemainingInMemory)
|
||||
framesToReadFromMemory = framesRemainingInMemory;
|
||||
|
||||
totalFramesRead += framesToReadFromMemory;
|
||||
frameCount -= framesToReadFromMemory;
|
||||
if (frameCount == 0)
|
||||
break;
|
||||
drmp3_copy_memory(pFramesOut, pCache->pCachedFrames + pCache->iNextFrame*channels, (drmp3_uint32)(framesToReadFromMemory * channels * sizeof(float)));
|
||||
pCache->iNextFrame += (drmp3_uint32)framesToReadFromMemory;
|
||||
|
||||
totalFramesRead += framesToReadFromMemory;
|
||||
frameCount -= framesToReadFromMemory;
|
||||
if (frameCount == 0)
|
||||
break;
|
||||
|
||||
|
||||
/* At this point there are still more frames to read from the client, so we'll need to reload the cache with fresh data. */
|
||||
drmp3_assert(frameCount > 0);
|
||||
pFramesOut += framesToReadFromMemory * channels;
|
||||
/* At this point there are still more frames to read from the client, so we'll need to reload the cache with fresh data. */
|
||||
drmp3_assert(frameCount > 0);
|
||||
pFramesOut += framesToReadFromMemory * channels;
|
||||
|
||||
pCache->iNextFrame = 0;
|
||||
pCache->cachedFrameCount = 0;
|
||||
pCache->iNextFrame = 0;
|
||||
pCache->cachedFrameCount = 0;
|
||||
|
||||
drmp3_uint32 framesToReadFromClient = drmp3_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels;
|
||||
if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames)
|
||||
framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames;
|
||||
framesToReadFromClient = drmp3_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels;
|
||||
if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames)
|
||||
framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames;
|
||||
|
||||
pCache->cachedFrameCount = (drmp3_uint32)pCache->pSRC->onRead(pCache->pSRC, framesToReadFromClient, pCache->pCachedFrames, pCache->pSRC->pUserData);
|
||||
pCache->cachedFrameCount = (drmp3_uint32)pCache->pSRC->onRead(pCache->pSRC, framesToReadFromClient, pCache->pCachedFrames, pCache->pSRC->pUserData);
|
||||
|
||||
|
||||
/* Get out of this loop if nothing was able to be retrieved. */
|
||||
if (pCache->cachedFrameCount == 0)
|
||||
break;
|
||||
}
|
||||
/* Get out of this loop if nothing was able to be retrieved. */
|
||||
if (pCache->cachedFrameCount == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return totalFramesRead;
|
||||
return totalFramesRead;
|
||||
}
|
||||
|
||||
|
||||
@ -2106,21 +2112,22 @@ drmp3_bool32 drmp3_src_set_output_sample_rate(drmp3_src* pSRC, drmp3_uint32 samp
|
||||
|
||||
drmp3_uint64 drmp3_src_read_frames_ex(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush)
|
||||
{
|
||||
if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) return 0;
|
||||
drmp3_src_algorithm algorithm;
|
||||
if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) return 0;
|
||||
|
||||
drmp3_src_algorithm algorithm = pSRC->config.algorithm;
|
||||
algorithm = pSRC->config.algorithm;
|
||||
|
||||
/* Always use passthrough if the sample rates are the same. */
|
||||
if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut)
|
||||
algorithm = drmp3_src_algorithm_none;
|
||||
/* Always use passthrough if the sample rates are the same. */
|
||||
if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut)
|
||||
algorithm = drmp3_src_algorithm_none;
|
||||
|
||||
/* Could just use a function pointer instead of a switch for this... */
|
||||
switch (algorithm)
|
||||
{
|
||||
case drmp3_src_algorithm_none: return drmp3_src_read_frames_passthrough(pSRC, frameCount, pFramesOut, flush);
|
||||
case drmp3_src_algorithm_linear: return drmp3_src_read_frames_linear(pSRC, frameCount, pFramesOut, flush);
|
||||
default: return 0;
|
||||
}
|
||||
/* Could just use a function pointer instead of a switch for this... */
|
||||
switch (algorithm)
|
||||
{
|
||||
case drmp3_src_algorithm_none: return drmp3_src_read_frames_passthrough(pSRC, frameCount, pFramesOut, flush);
|
||||
case drmp3_src_algorithm_linear: return drmp3_src_read_frames_linear(pSRC, frameCount, pFramesOut, flush);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
drmp3_uint64 drmp3_src_read_frames(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut)
|
||||
@ -2140,78 +2147,85 @@ drmp3_uint64 drmp3_src_read_frames_passthrough(drmp3_src* pSRC, drmp3_uint64 fra
|
||||
|
||||
drmp3_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush)
|
||||
{
|
||||
drmp3_assert(pSRC != NULL);
|
||||
drmp3_assert(frameCount > 0);
|
||||
drmp3_assert(pFramesOut != NULL);
|
||||
float factor;
|
||||
drmp3_uint64 totalFramesRead = 0;
|
||||
|
||||
/* For linear SRC, the bin is only 2 frames: 1 prior, 1 future. */
|
||||
drmp3_assert(pSRC != NULL);
|
||||
drmp3_assert(frameCount > 0);
|
||||
drmp3_assert(pFramesOut != NULL);
|
||||
|
||||
/* Load the bin if necessary. */
|
||||
if (!pSRC->algo.linear.isPrevFramesLoaded)
|
||||
{
|
||||
drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin);
|
||||
if (framesRead == 0)
|
||||
return 0;
|
||||
pSRC->algo.linear.isPrevFramesLoaded = DRMP3_TRUE;
|
||||
}
|
||||
if (!pSRC->algo.linear.isNextFramesLoaded)
|
||||
{
|
||||
drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin + pSRC->config.channels);
|
||||
if (framesRead == 0)
|
||||
return 0;
|
||||
pSRC->algo.linear.isNextFramesLoaded = DRMP3_TRUE;
|
||||
}
|
||||
/* For linear SRC, the bin is only 2 frames: 1 prior, 1 future. */
|
||||
|
||||
float factor = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut;
|
||||
/* Load the bin if necessary. */
|
||||
if (!pSRC->algo.linear.isPrevFramesLoaded)
|
||||
{
|
||||
drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin);
|
||||
if (framesRead == 0)
|
||||
return 0;
|
||||
pSRC->algo.linear.isPrevFramesLoaded = DRMP3_TRUE;
|
||||
}
|
||||
if (!pSRC->algo.linear.isNextFramesLoaded)
|
||||
{
|
||||
drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin + pSRC->config.channels);
|
||||
if (framesRead == 0)
|
||||
return 0;
|
||||
pSRC->algo.linear.isNextFramesLoaded = DRMP3_TRUE;
|
||||
}
|
||||
|
||||
drmp3_uint64 totalFramesRead = 0;
|
||||
while (frameCount > 0)
|
||||
{
|
||||
/* The bin is where the previous and next frames are located. */
|
||||
float* pPrevFrame = pSRC->bin;
|
||||
float* pNextFrame = pSRC->bin + pSRC->config.channels;
|
||||
factor = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut;
|
||||
|
||||
drmp3_blend_f32((float*)pFramesOut, pPrevFrame, pNextFrame, pSRC->algo.linear.alpha, pSRC->config.channels);
|
||||
while (frameCount > 0)
|
||||
{
|
||||
drmp3_uint32 i;
|
||||
drmp3_uint32 framesToReadFromClient;
|
||||
/* The bin is where the previous and next frames are located. */
|
||||
float* pPrevFrame = pSRC->bin;
|
||||
float* pNextFrame = pSRC->bin + pSRC->config.channels;
|
||||
|
||||
pSRC->algo.linear.alpha += factor;
|
||||
drmp3_blend_f32((float*)pFramesOut, pPrevFrame, pNextFrame, pSRC->algo.linear.alpha, pSRC->config.channels);
|
||||
|
||||
/* The new alpha value is how we determine whether or not we need to read fresh frames. */
|
||||
drmp3_uint32 framesToReadFromClient = (drmp3_uint32)pSRC->algo.linear.alpha;
|
||||
pSRC->algo.linear.alpha = pSRC->algo.linear.alpha - framesToReadFromClient;
|
||||
pSRC->algo.linear.alpha += factor;
|
||||
|
||||
for (drmp3_uint32 i = 0; i < framesToReadFromClient; ++i)
|
||||
{
|
||||
for (drmp3_uint32 j = 0; j < pSRC->config.channels; ++j)
|
||||
pPrevFrame[j] = pNextFrame[j];
|
||||
/* The new alpha value is how we determine whether or not we need to read fresh frames. */
|
||||
framesToReadFromClient = (drmp3_uint32)pSRC->algo.linear.alpha;
|
||||
pSRC->algo.linear.alpha = pSRC->algo.linear.alpha - framesToReadFromClient;
|
||||
|
||||
drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pNextFrame);
|
||||
if (framesRead == 0)
|
||||
for (i = 0; i < framesToReadFromClient; ++i)
|
||||
{
|
||||
drmp3_uint32 j;
|
||||
drmp3_uint64 framesRead;
|
||||
for (j = 0; j < pSRC->config.channels; ++j)
|
||||
pPrevFrame[j] = pNextFrame[j];
|
||||
|
||||
framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pNextFrame);
|
||||
if (framesRead == 0)
|
||||
{
|
||||
drmp3_uint32 j;
|
||||
for (j = 0; j < pSRC->config.channels; ++j)
|
||||
pNextFrame[j] = 0;
|
||||
|
||||
if (pSRC->algo.linear.isNextFramesLoaded)
|
||||
pSRC->algo.linear.isNextFramesLoaded = DRMP3_FALSE;
|
||||
else
|
||||
{
|
||||
for (drmp3_uint32 j = 0; j < pSRC->config.channels; ++j)
|
||||
pNextFrame[j] = 0;
|
||||
|
||||
if (pSRC->algo.linear.isNextFramesLoaded)
|
||||
pSRC->algo.linear.isNextFramesLoaded = DRMP3_FALSE;
|
||||
else
|
||||
{
|
||||
if (flush)
|
||||
pSRC->algo.linear.isPrevFramesLoaded = DRMP3_FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
if (flush)
|
||||
pSRC->algo.linear.isPrevFramesLoaded = DRMP3_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
pFramesOut = (drmp3_uint8*)pFramesOut + (1 * pSRC->config.channels * sizeof(float));
|
||||
frameCount -= 1;
|
||||
totalFramesRead += 1;
|
||||
|
||||
/* If there's no frames available we need to get out of this loop. */
|
||||
if (!pSRC->algo.linear.isNextFramesLoaded && (!flush || !pSRC->algo.linear.isPrevFramesLoaded))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalFramesRead;
|
||||
pFramesOut = (drmp3_uint8*)pFramesOut + (1 * pSRC->config.channels * sizeof(float));
|
||||
frameCount -= 1;
|
||||
totalFramesRead += 1;
|
||||
|
||||
/* If there's no frames available we need to get out of this loop. */
|
||||
if (!pSRC->algo.linear.isNextFramesLoaded && (!flush || !pSRC->algo.linear.isPrevFramesLoaded))
|
||||
break;
|
||||
}
|
||||
|
||||
return totalFramesRead;
|
||||
}
|
||||
|
||||
|
||||
@ -2226,74 +2240,86 @@ static drmp3_bool32 drmp3_decode_next_frame(drmp3* pMP3)
|
||||
|
||||
do
|
||||
{
|
||||
/* minimp3 recommends doing data submission in 16K chunks. If we don't have at least 16K bytes available, get more. */
|
||||
if (pMP3->dataSize < DRMP3_DATA_CHUNK_SIZE)
|
||||
{
|
||||
if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE)
|
||||
{
|
||||
pMP3->dataCapacity = DRMP3_DATA_CHUNK_SIZE;
|
||||
drmp3_uint8* pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity);
|
||||
if (pNewData == NULL)
|
||||
return DRMP3_FALSE; /* Out of memory. */
|
||||
drmp3dec_frame_info info;
|
||||
drmp3_uint32 samplesRead;
|
||||
|
||||
pMP3->pData = pNewData;
|
||||
}
|
||||
/* minimp3 recommends doing data submission in 16K chunks. If we don't have at least 16K bytes available, get more. */
|
||||
if (pMP3->dataSize < DRMP3_DATA_CHUNK_SIZE)
|
||||
{
|
||||
size_t bytesRead;
|
||||
|
||||
size_t bytesRead = pMP3->onRead(pMP3->pUserData, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
pMP3->atEnd = DRMP3_TRUE;
|
||||
return DRMP3_FALSE; /* No data. */
|
||||
}
|
||||
if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE)
|
||||
{
|
||||
drmp3_uint8* pNewData = NULL;
|
||||
pMP3->dataCapacity = DRMP3_DATA_CHUNK_SIZE;
|
||||
|
||||
pMP3->dataSize += bytesRead;
|
||||
}
|
||||
pNewData = (drmp3_uint8*)
|
||||
drmp3_realloc(pMP3->pData, pMP3->dataCapacity);
|
||||
if (pNewData == NULL)
|
||||
return DRMP3_FALSE; /* Out of memory. */
|
||||
|
||||
if (pMP3->dataSize > INT_MAX)
|
||||
{
|
||||
pMP3->atEnd = DRMP3_TRUE;
|
||||
return DRMP3_FALSE; /* File too big. */
|
||||
}
|
||||
pMP3->pData = pNewData;
|
||||
}
|
||||
|
||||
drmp3dec_frame_info info;
|
||||
drmp3_uint32 samplesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData, (int)pMP3->dataSize, pMP3->frames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */
|
||||
if (samplesRead != 0)
|
||||
{
|
||||
size_t i;
|
||||
size_t leftoverDataSize = (pMP3->dataSize - (size_t)info.frame_bytes);
|
||||
for (i = 0; i < leftoverDataSize; ++i)
|
||||
pMP3->pData[i] = pMP3->pData[i + (size_t)info.frame_bytes];
|
||||
bytesRead = pMP3->onRead(pMP3->pUserData, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
pMP3->atEnd = DRMP3_TRUE;
|
||||
return DRMP3_FALSE; /* No data. */
|
||||
}
|
||||
|
||||
pMP3->dataSize = leftoverDataSize;
|
||||
pMP3->framesConsumed = 0;
|
||||
pMP3->framesRemaining = samplesRead;
|
||||
pMP3->frameChannels = info.channels;
|
||||
pMP3->frameSampleRate = info.hz;
|
||||
drmp3_src_set_input_sample_rate(&pMP3->src, pMP3->frameSampleRate);
|
||||
break;
|
||||
} else {
|
||||
/* Need more data. minimp3 recommends doing data submission in 16K chunks. */
|
||||
if (pMP3->dataCapacity == pMP3->dataSize)
|
||||
{
|
||||
/* No room. Expand. */
|
||||
pMP3->dataCapacity += DRMP3_DATA_CHUNK_SIZE;
|
||||
drmp3_uint8* pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity);
|
||||
if (pNewData == NULL)
|
||||
return DRMP3_FALSE; /* Out of memory. */
|
||||
pMP3->dataSize += bytesRead;
|
||||
}
|
||||
|
||||
pMP3->pData = pNewData;
|
||||
}
|
||||
if (pMP3->dataSize > INT_MAX)
|
||||
{
|
||||
pMP3->atEnd = DRMP3_TRUE;
|
||||
return DRMP3_FALSE; /* File too big. */
|
||||
}
|
||||
|
||||
/* Fill in a chunk. */
|
||||
size_t bytesRead = pMP3->onRead(pMP3->pUserData, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
pMP3->atEnd = DRMP3_TRUE;
|
||||
return DRMP3_FALSE; /* Error reading more data. */
|
||||
}
|
||||
samplesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData, (int)pMP3->dataSize, pMP3->frames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */
|
||||
if (samplesRead != 0)
|
||||
{
|
||||
size_t i;
|
||||
size_t leftoverDataSize = (pMP3->dataSize - (size_t)info.frame_bytes);
|
||||
for (i = 0; i < leftoverDataSize; ++i)
|
||||
pMP3->pData[i] = pMP3->pData[i + (size_t)info.frame_bytes];
|
||||
|
||||
pMP3->dataSize += bytesRead;
|
||||
}
|
||||
pMP3->dataSize = leftoverDataSize;
|
||||
pMP3->framesConsumed = 0;
|
||||
pMP3->framesRemaining = samplesRead;
|
||||
pMP3->frameChannels = info.channels;
|
||||
pMP3->frameSampleRate = info.hz;
|
||||
drmp3_src_set_input_sample_rate(&pMP3->src, pMP3->frameSampleRate);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t bytesRead;
|
||||
/* Need more data. minimp3 recommends doing data submission in 16K chunks. */
|
||||
if (pMP3->dataCapacity == pMP3->dataSize)
|
||||
{
|
||||
drmp3_uint8 *pNewData = NULL;
|
||||
/* No room. Expand. */
|
||||
pMP3->dataCapacity += DRMP3_DATA_CHUNK_SIZE;
|
||||
|
||||
pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity);
|
||||
if (pNewData == NULL)
|
||||
return DRMP3_FALSE; /* Out of memory. */
|
||||
|
||||
pMP3->pData = pNewData;
|
||||
}
|
||||
|
||||
/* Fill in a chunk. */
|
||||
bytesRead = pMP3->onRead(pMP3->pUserData, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
pMP3->atEnd = DRMP3_TRUE;
|
||||
return DRMP3_FALSE; /* Error reading more data. */
|
||||
}
|
||||
|
||||
pMP3->dataSize += bytesRead;
|
||||
}
|
||||
} while (DRMP3_TRUE);
|
||||
|
||||
return DRMP3_TRUE;
|
||||
@ -2301,113 +2327,114 @@ static drmp3_bool32 drmp3_decode_next_frame(drmp3* pMP3)
|
||||
|
||||
static drmp3_uint64 drmp3_read_src(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, void* pUserData)
|
||||
{
|
||||
drmp3* pMP3 = (drmp3*)pUserData;
|
||||
drmp3_assert(pMP3 != NULL);
|
||||
drmp3_assert(pMP3->onRead != NULL);
|
||||
float* pFramesOutF;
|
||||
drmp3_uint32 totalFramesRead = 0;
|
||||
drmp3* pMP3 = (drmp3*)pUserData;
|
||||
|
||||
float* pFramesOutF = (float*)pFramesOut;
|
||||
drmp3_uint32 totalFramesRead = 0;
|
||||
drmp3_assert(pMP3 != NULL);
|
||||
drmp3_assert(pMP3->onRead != NULL);
|
||||
|
||||
while (frameCount > 0)
|
||||
{
|
||||
/* Read from the in-memory buffer first. */
|
||||
while (pMP3->framesRemaining > 0 && frameCount > 0)
|
||||
{
|
||||
if (pMP3->frameChannels == 1)
|
||||
pFramesOutF = (float*)pFramesOut;
|
||||
|
||||
while (frameCount > 0)
|
||||
{
|
||||
/* Read from the in-memory buffer first. */
|
||||
while (pMP3->framesRemaining > 0 && frameCount > 0)
|
||||
{
|
||||
if (pMP3->frameChannels == 1)
|
||||
{
|
||||
if (pMP3->channels == 1)
|
||||
{
|
||||
if (pMP3->channels == 1)
|
||||
{
|
||||
/* Mono -> Mono. */
|
||||
pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f;
|
||||
} else {
|
||||
/* Mono -> Stereo. */
|
||||
pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f;
|
||||
pFramesOutF[1] = pMP3->frames[pMP3->framesConsumed] / 32768.0f;
|
||||
}
|
||||
/* Mono -> Mono. */
|
||||
pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f;
|
||||
} else {
|
||||
if (pMP3->channels == 1)
|
||||
{
|
||||
/* Stereo -> Mono */
|
||||
float sample = 0;
|
||||
sample += pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f;
|
||||
sample += pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f;
|
||||
pFramesOutF[0] = sample * 0.5f;
|
||||
} else {
|
||||
/* Stereo -> Stereo */
|
||||
pFramesOutF[0] = pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f;
|
||||
pFramesOutF[1] = pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f;
|
||||
}
|
||||
/* Mono -> Stereo. */
|
||||
pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f;
|
||||
pFramesOutF[1] = pMP3->frames[pMP3->framesConsumed] / 32768.0f;
|
||||
}
|
||||
} else {
|
||||
if (pMP3->channels == 1)
|
||||
{
|
||||
/* Stereo -> Mono */
|
||||
float sample = 0;
|
||||
sample += pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f;
|
||||
sample += pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f;
|
||||
pFramesOutF[0] = sample * 0.5f;
|
||||
} else {
|
||||
/* Stereo -> Stereo */
|
||||
pFramesOutF[0] = pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f;
|
||||
pFramesOutF[1] = pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f;
|
||||
}
|
||||
}
|
||||
|
||||
pMP3->framesConsumed += 1;
|
||||
pMP3->framesRemaining -= 1;
|
||||
frameCount -= 1;
|
||||
totalFramesRead += 1;
|
||||
pFramesOutF += pSRC->config.channels;
|
||||
}
|
||||
pMP3->framesConsumed += 1;
|
||||
pMP3->framesRemaining -= 1;
|
||||
frameCount -= 1;
|
||||
totalFramesRead += 1;
|
||||
pFramesOutF += pSRC->config.channels;
|
||||
}
|
||||
|
||||
if (frameCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (frameCount == 0)
|
||||
break;
|
||||
|
||||
drmp3_assert(pMP3->framesRemaining == 0);
|
||||
drmp3_assert(pMP3->framesRemaining == 0);
|
||||
|
||||
/* At this point we have exhausted our in-memory buffer so we need to re-fill. Note that the sample rate may have changed
|
||||
* at this point which means we'll also need to update our sample rate conversion pipeline. */
|
||||
if (!drmp3_decode_next_frame(pMP3))
|
||||
break;
|
||||
}
|
||||
/* At this point we have exhausted our in-memory buffer so we need to re-fill. Note that the sample rate may have changed
|
||||
* at this point which means we'll also need to update our sample rate conversion pipeline. */
|
||||
if (!drmp3_decode_next_frame(pMP3))
|
||||
break;
|
||||
}
|
||||
|
||||
return totalFramesRead;
|
||||
return totalFramesRead;
|
||||
}
|
||||
|
||||
drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_config* pConfig)
|
||||
{
|
||||
drmp3_assert(pMP3 != NULL);
|
||||
drmp3_assert(onRead != NULL);
|
||||
drmp3_config config;
|
||||
drmp3_src_config srcConfig;
|
||||
|
||||
/* This function assumes the output object has already been reset to 0. Do not do that here, otherwise things will break. */
|
||||
drmp3dec_init(&pMP3->decoder);
|
||||
drmp3_assert(pMP3 != NULL);
|
||||
drmp3_assert(onRead != NULL);
|
||||
|
||||
/* The config can be null in which case we use defaults. */
|
||||
drmp3_config config;
|
||||
if (pConfig != NULL)
|
||||
config = *pConfig;
|
||||
else
|
||||
drmp3_zero_object(&config);
|
||||
/* This function assumes the output object has already been reset to 0. Do not do that here, otherwise things will break. */
|
||||
drmp3dec_init(&pMP3->decoder);
|
||||
|
||||
pMP3->channels = config.outputChannels;
|
||||
if (pMP3->channels == 0)
|
||||
pMP3->channels = DR_MP3_DEFAULT_CHANNELS;
|
||||
/* The config can be null in which case we use defaults. */
|
||||
if (pConfig != NULL)
|
||||
config = *pConfig;
|
||||
else
|
||||
drmp3_zero_object(&config);
|
||||
|
||||
/* Cannot have more than 2 channels. */
|
||||
if (pMP3->channels > 2)
|
||||
pMP3->channels = 2;
|
||||
pMP3->channels = config.outputChannels;
|
||||
if (pMP3->channels == 0)
|
||||
pMP3->channels = DR_MP3_DEFAULT_CHANNELS;
|
||||
|
||||
pMP3->sampleRate = config.outputSampleRate;
|
||||
if (pMP3->sampleRate == 0)
|
||||
pMP3->sampleRate = DR_MP3_DEFAULT_SAMPLE_RATE;
|
||||
/* Cannot have more than 2 channels. */
|
||||
if (pMP3->channels > 2)
|
||||
pMP3->channels = 2;
|
||||
|
||||
pMP3->onRead = onRead;
|
||||
pMP3->onSeek = onSeek;
|
||||
pMP3->pUserData = pUserData;
|
||||
pMP3->sampleRate = config.outputSampleRate;
|
||||
if (pMP3->sampleRate == 0)
|
||||
pMP3->sampleRate = DR_MP3_DEFAULT_SAMPLE_RATE;
|
||||
|
||||
/* We need a sample rate converter for converting the sample rate from the MP3 frames to the requested output sample rate. */
|
||||
drmp3_src_config srcConfig;
|
||||
drmp3_zero_object(&srcConfig);
|
||||
srcConfig.sampleRateIn = DR_MP3_DEFAULT_SAMPLE_RATE;
|
||||
srcConfig.sampleRateOut = pMP3->sampleRate;
|
||||
srcConfig.channels = pMP3->channels;
|
||||
srcConfig.algorithm = drmp3_src_algorithm_linear;
|
||||
if (!drmp3_src_init(&srcConfig, drmp3_read_src, pMP3, &pMP3->src))
|
||||
return DRMP3_FALSE;
|
||||
|
||||
/* Decode the first frame to confirm that it is indeed a valid MP3 stream. */
|
||||
if (!drmp3_decode_next_frame(pMP3))
|
||||
return DRMP3_FALSE; /* Not a valid MP3 stream. */
|
||||
pMP3->onRead = onRead;
|
||||
pMP3->onSeek = onSeek;
|
||||
pMP3->pUserData = pUserData;
|
||||
|
||||
return DRMP3_TRUE;
|
||||
/* We need a sample rate converter for converting the sample rate from the MP3 frames to the requested output sample rate. */
|
||||
drmp3_zero_object(&srcConfig);
|
||||
srcConfig.sampleRateIn = DR_MP3_DEFAULT_SAMPLE_RATE;
|
||||
srcConfig.sampleRateOut = pMP3->sampleRate;
|
||||
srcConfig.channels = pMP3->channels;
|
||||
srcConfig.algorithm = drmp3_src_algorithm_linear;
|
||||
if (!drmp3_src_init(&srcConfig, drmp3_read_src, pMP3, &pMP3->src))
|
||||
return DRMP3_FALSE;
|
||||
|
||||
/* Decode the first frame to confirm that it is indeed a valid MP3 stream. */
|
||||
if (!drmp3_decode_next_frame(pMP3))
|
||||
return DRMP3_FALSE; /* Not a valid MP3 stream. */
|
||||
|
||||
return DRMP3_TRUE;
|
||||
}
|
||||
|
||||
drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_config* pConfig)
|
||||
@ -2531,20 +2558,20 @@ void drmp3_uninit(drmp3* pMP3)
|
||||
|
||||
drmp3_uint64 drmp3_read_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut)
|
||||
{
|
||||
if (pMP3 == NULL || pMP3->onRead == NULL) return 0;
|
||||
|
||||
drmp3_uint64 totalFramesRead = 0;
|
||||
if (pMP3 == NULL || pMP3->onRead == NULL) return 0;
|
||||
|
||||
if (pBufferOut == NULL)
|
||||
{
|
||||
float temp[4096];
|
||||
while (framesToRead > 0)
|
||||
{
|
||||
drmp3_uint64 framesJustRead;
|
||||
drmp3_uint64 framesToReadRightNow = sizeof(temp)/sizeof(temp[0]) / pMP3->channels;
|
||||
if (framesToReadRightNow > framesToRead)
|
||||
framesToReadRightNow = framesToRead;
|
||||
|
||||
drmp3_uint64 framesJustRead = drmp3_read_f32(pMP3, framesToReadRightNow, temp);
|
||||
framesJustRead = drmp3_read_f32(pMP3, framesToReadRightNow, temp);
|
||||
if (framesJustRead == 0)
|
||||
break;
|
||||
|
||||
@ -2560,39 +2587,42 @@ drmp3_uint64 drmp3_read_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBuff
|
||||
|
||||
drmp3_bool32 drmp3_seek_to_frame(drmp3* pMP3, drmp3_uint64 frameIndex)
|
||||
{
|
||||
if (pMP3 == NULL || pMP3->onSeek == NULL) return DRMP3_FALSE;
|
||||
drmp3_uint64 framesRead;
|
||||
|
||||
/* Seek to the start of the stream to begin with. */
|
||||
if (!pMP3->onSeek(pMP3->pUserData, 0, drmp3_seek_origin_start))
|
||||
return DRMP3_FALSE;
|
||||
if (pMP3 == NULL || pMP3->onSeek == NULL) return DRMP3_FALSE;
|
||||
|
||||
/* Clear any cached data. */
|
||||
pMP3->framesConsumed = 0;
|
||||
pMP3->framesRemaining = 0;
|
||||
pMP3->dataSize = 0;
|
||||
pMP3->atEnd = DRMP3_FALSE;
|
||||
/* Seek to the start of the stream to begin with. */
|
||||
if (!pMP3->onSeek(pMP3->pUserData, 0, drmp3_seek_origin_start))
|
||||
return DRMP3_FALSE;
|
||||
|
||||
/* TODO: Optimize.
|
||||
*
|
||||
* This is inefficient. We simply read frames from the start of the stream. */
|
||||
drmp3_uint64 framesRead = drmp3_read_f32(pMP3, frameIndex, NULL);
|
||||
if (framesRead != frameIndex)
|
||||
return DRMP3_FALSE;
|
||||
/* Clear any cached data. */
|
||||
pMP3->framesConsumed = 0;
|
||||
pMP3->framesRemaining = 0;
|
||||
pMP3->dataSize = 0;
|
||||
pMP3->atEnd = DRMP3_FALSE;
|
||||
|
||||
return DRMP3_TRUE;
|
||||
/* TODO: Optimize.
|
||||
*
|
||||
* This is inefficient. We simply read frames from the start of the stream. */
|
||||
framesRead = drmp3_read_f32(pMP3, frameIndex, NULL);
|
||||
if (framesRead != frameIndex)
|
||||
return DRMP3_FALSE;
|
||||
|
||||
return DRMP3_TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float* drmp3__full_decode_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
|
||||
{
|
||||
drmp3_assert(pMP3 != NULL);
|
||||
|
||||
drmp3_uint64 totalFramesRead = 0;
|
||||
drmp3_uint64 framesCapacity = 0;
|
||||
float* pFrames = NULL;
|
||||
|
||||
float temp[4096];
|
||||
|
||||
drmp3_assert(pMP3 != NULL);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
drmp3_uint64 framesToReadRightNow = drmp3_countof(temp) / pMP3->channels;
|
||||
@ -2603,15 +2633,18 @@ float* drmp3__full_decode_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp
|
||||
/* Reallocate the output buffer if there's not enough room. */
|
||||
if (framesCapacity < totalFramesRead + framesJustRead)
|
||||
{
|
||||
float* pNewFrames;
|
||||
drmp3_uint64 newFramesBufferSize;
|
||||
|
||||
framesCapacity *= 2;
|
||||
if (framesCapacity < totalFramesRead + framesJustRead)
|
||||
framesCapacity = totalFramesRead + framesJustRead;
|
||||
|
||||
drmp3_uint64 newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(float);
|
||||
newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(float);
|
||||
if (newFramesBufferSize > SIZE_MAX)
|
||||
break;
|
||||
|
||||
float* pNewFrames = (float*)drmp3_realloc(pFrames, (size_t)newFramesBufferSize);
|
||||
pNewFrames = (float*)drmp3_realloc(pFrames, (size_t)newFramesBufferSize);
|
||||
if (pNewFrames == NULL)
|
||||
{
|
||||
drmp3_free(pFrames);
|
||||
|
Loading…
x
Reference in New Issue
Block a user