(dr_mp3.h) Fix C89_BUILD issues

This commit is contained in:
twinaphex 2018-04-28 14:32:10 +02:00
parent 3583e1e501
commit e3ce768ad0
1 changed files with 314 additions and 281 deletions

595
deps/dr/dr_mp3.h vendored
View File

@ -9,6 +9,7 @@ extern "C" {
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <retro_inline.h>
typedef int8_t drmp3_int8; typedef int8_t drmp3_int8;
typedef uint8_t drmp3_uint8; typedef uint8_t drmp3_uint8;
@ -312,7 +313,7 @@ typedef __m128 drmp3_f4;
#if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD) #if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)
#define drmp3_cpuid __cpuid #define drmp3_cpuid __cpuid
#else #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__) #if defined(__PIC__)
__asm__ __volatile__( __asm__ __volatile__(
@ -1600,13 +1601,14 @@ static void drmp3d_DCT_II(float *grbuf, int n)
static short drmp3d_scale_pcm(float sample) static short drmp3d_scale_pcm(float sample)
{ {
if (sample > 32767.0) return (short) 32767; int s;
if (sample < -32768.0) return (short)-32768; if (sample > 32767.0) return (short) 32767;
int s = (int)(sample + .5f); if (sample < -32768.0) return (short)-32768;
s -= (s < 0); /* away from zero, to be compliant */ s = (int)(sample + .5f);
if (s > 32767) return (short) 32767; s -= (s < 0); /* away from zero, to be compliant */
if (s < -32768) return (short)-32768; if (s > 32767) return (short) 32767;
return (short)s; if (s < -32768) return (short)-32768;
return (short)s;
} }
static void drmp3d_synth_pair(short *pcm, int nch, const float *z) 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. */ #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; return x*(1-a) + y*a;
} }
static void drmp3_blend_f32(float* pOut, float* pInA, float* pInB, float factor, drmp3_uint32 channels) 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); 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_uint64 drmp3_src_cache_read_frames(drmp3_src_cache* pCache, drmp3_uint64 frameCount, float* pFramesOut)
{ {
drmp3_assert(pCache != NULL); drmp3_uint32 channels;
drmp3_assert(pCache->pSRC != NULL); drmp3_uint64 totalFramesRead = 0;
drmp3_assert(pCache->pSRC->onRead != NULL);
drmp3_assert(frameCount > 0);
drmp3_assert(pFramesOut != NULL);
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; channels = pCache->pSRC->config.channels;
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;
drmp3_copy_memory(pFramesOut, pCache->pCachedFrames + pCache->iNextFrame*channels, (drmp3_uint32)(framesToReadFromMemory * channels * sizeof(float))); while (frameCount > 0)
pCache->iNextFrame += (drmp3_uint32)framesToReadFromMemory; {
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; drmp3_copy_memory(pFramesOut, pCache->pCachedFrames + pCache->iNextFrame*channels, (drmp3_uint32)(framesToReadFromMemory * channels * sizeof(float)));
frameCount -= framesToReadFromMemory; pCache->iNextFrame += (drmp3_uint32)framesToReadFromMemory;
if (frameCount == 0)
break; 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. */ /* 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); drmp3_assert(frameCount > 0);
pFramesOut += framesToReadFromMemory * channels; pFramesOut += framesToReadFromMemory * channels;
pCache->iNextFrame = 0; pCache->iNextFrame = 0;
pCache->cachedFrameCount = 0; pCache->cachedFrameCount = 0;
drmp3_uint32 framesToReadFromClient = drmp3_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels; framesToReadFromClient = drmp3_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels;
if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames) if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames)
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. */ /* Get out of this loop if nothing was able to be retrieved. */
if (pCache->cachedFrameCount == 0) if (pCache->cachedFrameCount == 0)
break; 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) 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. */ /* Always use passthrough if the sample rates are the same. */
if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut) if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut)
algorithm = drmp3_src_algorithm_none; algorithm = drmp3_src_algorithm_none;
/* Could just use a function pointer instead of a switch for this... */ /* Could just use a function pointer instead of a switch for this... */
switch (algorithm) switch (algorithm)
{ {
case drmp3_src_algorithm_none: return drmp3_src_read_frames_passthrough(pSRC, frameCount, pFramesOut, flush); 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); case drmp3_src_algorithm_linear: return drmp3_src_read_frames_linear(pSRC, frameCount, pFramesOut, flush);
default: return 0; default: return 0;
} }
} }
drmp3_uint64 drmp3_src_read_frames(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut) 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_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush)
{ {
drmp3_assert(pSRC != NULL); float factor;
drmp3_assert(frameCount > 0); drmp3_uint64 totalFramesRead = 0;
drmp3_assert(pFramesOut != NULL);
/* 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. */ /* For linear SRC, the bin is only 2 frames: 1 prior, 1 future. */
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;
}
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; factor = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut;
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;
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. */ pSRC->algo.linear.alpha += factor;
drmp3_uint32 framesToReadFromClient = (drmp3_uint32)pSRC->algo.linear.alpha;
pSRC->algo.linear.alpha = pSRC->algo.linear.alpha - framesToReadFromClient;
for (drmp3_uint32 i = 0; i < framesToReadFromClient; ++i) /* The new alpha value is how we determine whether or not we need to read fresh frames. */
{ framesToReadFromClient = (drmp3_uint32)pSRC->algo.linear.alpha;
for (drmp3_uint32 j = 0; j < pSRC->config.channels; ++j) pSRC->algo.linear.alpha = pSRC->algo.linear.alpha - framesToReadFromClient;
pPrevFrame[j] = pNextFrame[j];
drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pNextFrame); for (i = 0; i < framesToReadFromClient; ++i)
if (framesRead == 0) {
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) if (flush)
pNextFrame[j] = 0; pSRC->algo.linear.isPrevFramesLoaded = DRMP3_FALSE;
if (pSRC->algo.linear.isNextFramesLoaded)
pSRC->algo.linear.isNextFramesLoaded = DRMP3_FALSE;
else
{
if (flush)
pSRC->algo.linear.isPrevFramesLoaded = DRMP3_FALSE;
}
break;
} }
}
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; 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 do
{ {
/* minimp3 recommends doing data submission in 16K chunks. If we don't have at least 16K bytes available, get more. */ drmp3dec_frame_info info;
if (pMP3->dataSize < DRMP3_DATA_CHUNK_SIZE) drmp3_uint32 samplesRead;
{
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. */
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 (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE)
if (bytesRead == 0) {
{ drmp3_uint8* pNewData = NULL;
pMP3->atEnd = DRMP3_TRUE; pMP3->dataCapacity = DRMP3_DATA_CHUNK_SIZE;
return DRMP3_FALSE; /* No data. */
}
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->pData = pNewData;
{ }
pMP3->atEnd = DRMP3_TRUE;
return DRMP3_FALSE; /* File too big. */
}
drmp3dec_frame_info info; bytesRead = pMP3->onRead(pMP3->pUserData, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
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 (bytesRead == 0)
if (samplesRead != 0) {
{ pMP3->atEnd = DRMP3_TRUE;
size_t i; return DRMP3_FALSE; /* No data. */
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 = leftoverDataSize; pMP3->dataSize += bytesRead;
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->pData = pNewData; if (pMP3->dataSize > INT_MAX)
} {
pMP3->atEnd = DRMP3_TRUE;
return DRMP3_FALSE; /* File too big. */
}
/* Fill in a chunk. */ samplesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData, (int)pMP3->dataSize, pMP3->frames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */
size_t bytesRead = pMP3->onRead(pMP3->pUserData, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (samplesRead != 0)
if (bytesRead == 0) {
{ size_t i;
pMP3->atEnd = DRMP3_TRUE; size_t leftoverDataSize = (pMP3->dataSize - (size_t)info.frame_bytes);
return DRMP3_FALSE; /* Error reading more data. */ 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); } while (DRMP3_TRUE);
return 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) static drmp3_uint64 drmp3_read_src(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, void* pUserData)
{ {
drmp3* pMP3 = (drmp3*)pUserData; float* pFramesOutF;
drmp3_assert(pMP3 != NULL); drmp3_uint32 totalFramesRead = 0;
drmp3_assert(pMP3->onRead != NULL); drmp3* pMP3 = (drmp3*)pUserData;
float* pFramesOutF = (float*)pFramesOut; drmp3_assert(pMP3 != NULL);
drmp3_uint32 totalFramesRead = 0; drmp3_assert(pMP3->onRead != NULL);
while (frameCount > 0) pFramesOutF = (float*)pFramesOut;
{
/* Read from the in-memory buffer first. */ while (frameCount > 0)
while (pMP3->framesRemaining > 0 && frameCount > 0) {
{ /* Read from the in-memory buffer first. */
if (pMP3->frameChannels == 1) 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;
/* 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;
}
} else { } else {
if (pMP3->channels == 1) /* Mono -> Stereo. */
{ pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f;
/* Stereo -> Mono */ pFramesOutF[1] = pMP3->frames[pMP3->framesConsumed] / 32768.0f;
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;
}
} }
} 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->framesConsumed += 1;
pMP3->framesRemaining -= 1; pMP3->framesRemaining -= 1;
frameCount -= 1; frameCount -= 1;
totalFramesRead += 1; totalFramesRead += 1;
pFramesOutF += pSRC->config.channels; pFramesOutF += pSRC->config.channels;
} }
if (frameCount == 0) if (frameCount == 0)
{ break;
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 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. */ * at this point which means we'll also need to update our sample rate conversion pipeline. */
if (!drmp3_decode_next_frame(pMP3)) if (!drmp3_decode_next_frame(pMP3))
break; 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_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_config config;
drmp3_assert(onRead != NULL); 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. */ drmp3_assert(pMP3 != NULL);
drmp3dec_init(&pMP3->decoder); drmp3_assert(onRead != NULL);
/* The config can be null in which case we use defaults. */ /* This function assumes the output object has already been reset to 0. Do not do that here, otherwise things will break. */
drmp3_config config; drmp3dec_init(&pMP3->decoder);
if (pConfig != NULL)
config = *pConfig;
else
drmp3_zero_object(&config);
pMP3->channels = config.outputChannels; /* The config can be null in which case we use defaults. */
if (pMP3->channels == 0) if (pConfig != NULL)
pMP3->channels = DR_MP3_DEFAULT_CHANNELS; config = *pConfig;
else
drmp3_zero_object(&config);
/* Cannot have more than 2 channels. */ pMP3->channels = config.outputChannels;
if (pMP3->channels > 2) if (pMP3->channels == 0)
pMP3->channels = 2; pMP3->channels = DR_MP3_DEFAULT_CHANNELS;
pMP3->sampleRate = config.outputSampleRate; /* Cannot have more than 2 channels. */
if (pMP3->sampleRate == 0) if (pMP3->channels > 2)
pMP3->sampleRate = DR_MP3_DEFAULT_SAMPLE_RATE; pMP3->channels = 2;
pMP3->onRead = onRead; pMP3->sampleRate = config.outputSampleRate;
pMP3->onSeek = onSeek; if (pMP3->sampleRate == 0)
pMP3->pUserData = pUserData; 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. */ pMP3->onRead = onRead;
drmp3_src_config srcConfig; pMP3->onSeek = onSeek;
drmp3_zero_object(&srcConfig); pMP3->pUserData = pUserData;
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; /* 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) 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) drmp3_uint64 drmp3_read_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut)
{ {
if (pMP3 == NULL || pMP3->onRead == NULL) return 0;
drmp3_uint64 totalFramesRead = 0; drmp3_uint64 totalFramesRead = 0;
if (pMP3 == NULL || pMP3->onRead == NULL) return 0;
if (pBufferOut == NULL) if (pBufferOut == NULL)
{ {
float temp[4096]; float temp[4096];
while (framesToRead > 0) while (framesToRead > 0)
{ {
drmp3_uint64 framesJustRead;
drmp3_uint64 framesToReadRightNow = sizeof(temp)/sizeof(temp[0]) / pMP3->channels; drmp3_uint64 framesToReadRightNow = sizeof(temp)/sizeof(temp[0]) / pMP3->channels;
if (framesToReadRightNow > framesToRead) if (framesToReadRightNow > framesToRead)
framesToReadRightNow = framesToRead; framesToReadRightNow = framesToRead;
drmp3_uint64 framesJustRead = drmp3_read_f32(pMP3, framesToReadRightNow, temp); framesJustRead = drmp3_read_f32(pMP3, framesToReadRightNow, temp);
if (framesJustRead == 0) if (framesJustRead == 0)
break; 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) 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 == NULL || pMP3->onSeek == NULL) return DRMP3_FALSE;
if (!pMP3->onSeek(pMP3->pUserData, 0, drmp3_seek_origin_start))
return DRMP3_FALSE;
/* Clear any cached data. */ /* Seek to the start of the stream to begin with. */
pMP3->framesConsumed = 0; if (!pMP3->onSeek(pMP3->pUserData, 0, drmp3_seek_origin_start))
pMP3->framesRemaining = 0; return DRMP3_FALSE;
pMP3->dataSize = 0;
pMP3->atEnd = DRMP3_FALSE;
/* TODO: Optimize. /* Clear any cached data. */
* pMP3->framesConsumed = 0;
* This is inefficient. We simply read frames from the start of the stream. */ pMP3->framesRemaining = 0;
drmp3_uint64 framesRead = drmp3_read_f32(pMP3, frameIndex, NULL); pMP3->dataSize = 0;
if (framesRead != frameIndex) pMP3->atEnd = DRMP3_FALSE;
return 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) 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 totalFramesRead = 0;
drmp3_uint64 framesCapacity = 0; drmp3_uint64 framesCapacity = 0;
float* pFrames = NULL; float* pFrames = NULL;
float temp[4096]; float temp[4096];
drmp3_assert(pMP3 != NULL);
for (;;) for (;;)
{ {
drmp3_uint64 framesToReadRightNow = drmp3_countof(temp) / pMP3->channels; 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. */ /* Reallocate the output buffer if there's not enough room. */
if (framesCapacity < totalFramesRead + framesJustRead) if (framesCapacity < totalFramesRead + framesJustRead)
{ {
float* pNewFrames;
drmp3_uint64 newFramesBufferSize;
framesCapacity *= 2; framesCapacity *= 2;
if (framesCapacity < totalFramesRead + framesJustRead) if (framesCapacity < totalFramesRead + framesJustRead)
framesCapacity = totalFramesRead + framesJustRead; framesCapacity = totalFramesRead + framesJustRead;
drmp3_uint64 newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(float); newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(float);
if (newFramesBufferSize > SIZE_MAX) if (newFramesBufferSize > SIZE_MAX)
break; break;
float* pNewFrames = (float*)drmp3_realloc(pFrames, (size_t)newFramesBufferSize); pNewFrames = (float*)drmp3_realloc(pFrames, (size_t)newFramesBufferSize);
if (pNewFrames == NULL) if (pNewFrames == NULL)
{ {
drmp3_free(pFrames); drmp3_free(pFrames);