Commit 959885a3 authored by David Reid's avatar David Reid

SRC/Speex: Add support for querying required input frame counts.

parent 3e8f261c
......@@ -6,6 +6,8 @@
#define RANDOM_PREFIX ma_speex
#include "thirdparty/speex_resampler.h"
int ma_speex_resampler_get_required_input_frame_count(SpeexResamplerState* st, spx_uint32_t out_len, spx_uint32_t* in_len);
#endif /* ma_speex_resampler_h */
#if defined(MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION)
......@@ -23,4 +25,31 @@
#else
#pragma GCC diagnostic pop
#endif
EXPORT int ma_speex_resampler_get_required_input_frame_count(SpeexResamplerState* st, spx_uint32_t out_len, spx_uint32_t* in_len)
{
spx_uint32_t count;
if (st == NULL || in_len == NULL) {
return RESAMPLER_ERR_INVALID_ARG;
}
*in_len = 0;
if (out_len == 0) {
return RESAMPLER_ERR_SUCCESS; /* Nothing to do. */
}
/* miniaudio only uses interleaved APIs so we can safely just use channel index 0 for the calculations. */
if (st->nb_channels == 0) {
return RESAMPLER_ERR_BAD_STATE;
}
count = out_len * st->int_advance;
count += (st->samp_frac_num[0] + (out_len * st->frac_advance)) / st->den_rate;
*in_len = count;
return RESAMPLER_ERR_SUCCESS;
}
#endif
\ No newline at end of file
......@@ -59,6 +59,9 @@ typedef struct
struct
{
void* pSpeexResamplerState; /* SpeexResamplerState* */
ma_uint64 runningTimeIn;
ma_uint64 runningTimeOut;
double t; /* For tracking the input time so we can query required input and expected output frame counts. */
} speex;
} state;
} ma_resampler;
......@@ -137,7 +140,7 @@ Implementation
#define MA_RESAMPLER_MAX_RATIO 48.0
#endif
#if defined(SPEEX_RESAMPLER_H)
#if defined(ma_speex_resampler_h)
#define MA_HAS_SPEEX_RESAMPLER
static ma_result ma_result_from_speex_err(int err)
......@@ -497,36 +500,44 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, co
#if defined(MA_HAS_SPEEX_RESAMPLER)
static ma_result ma_resampler_process__read__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
{
/* To do this we just read using the non-filtered linear pipeline, and then do an in-place filter on the output buffer. */
int speexErr;
ma_uint64 frameCountOut;
ma_uint64 frameCountIn;
ma_uint64 framesProcessedOut;
ma_uint64 framesProcessedIn;
unsigned int framesPerIteration = 32768;
double ratioInOut;
MA_ASSERT(pResampler != NULL);
MA_ASSERT(pFramesOut != NULL);
MA_ASSERT(pFrameCountOut != NULL);
MA_ASSERT(pFrameCountIn != NULL);
/* Speex uses unsigned int counts, whereas miniaudio uses 64-bit. We'll need to process in a loop. */
/*
Reading from the Speex resampler requires a bit of dancing around for a few reasons. The first thing is that it's frame counts
are in unsigned int's whereas ours is in ma_uint64. We therefore need to run the conversion in a loop. The other, more complicated
problem, is that we need to keep track of the input time, similar to what we do with the linear resampler. The reason we need to
do this is for ma_resampler_get_required_input_frame_count() and ma_resampler_get_expected_output_frame_count().
*/
frameCountOut = *pFrameCountOut;
frameCountIn = *pFrameCountIn;
framesProcessedOut = 0;
framesProcessedIn = 0;
ratioInOut = (double)pResampler->config.sampleRateIn / (double)pResampler->config.sampleRateOut;
while (framesProcessedOut < frameCountOut && framesProcessedIn < frameCountIn) {
unsigned int frameCountInThisIteration;
unsigned int frameCountOutThisIteration;
const void* pFramesInThisIteration;
void* pFramesOutThisIteration;
frameCountInThisIteration = UINT_MAX;
frameCountInThisIteration = framesPerIteration;
if ((ma_uint64)frameCountInThisIteration > (frameCountIn - framesProcessedIn)) {
frameCountInThisIteration = (unsigned int)(frameCountIn - framesProcessedIn);
}
frameCountOutThisIteration = UINT_MAX;
frameCountOutThisIteration = framesPerIteration;
if ((ma_uint64)frameCountOutThisIteration > (frameCountOut - framesProcessedOut)) {
frameCountOutThisIteration = (unsigned int)(frameCountOut - framesProcessedOut);
}
......@@ -550,8 +561,14 @@ static ma_result ma_resampler_process__read__speex(ma_resampler* pResampler, con
framesProcessedIn += frameCountInThisIteration;
framesProcessedOut += frameCountOutThisIteration;
pResampler->state.speex.t += frameCountOutThisIteration * ratioInOut;
//pResampler->state.speex.t = pResampler->state.speex.t - floor(pResampler->state.speex.t);
}
pResampler->state.speex.runningTimeOut += framesProcessedOut;
pResampler->state.speex.runningTimeIn += framesProcessedIn;
*pFrameCountOut = framesProcessedOut;
*pFrameCountIn = framesProcessedIn;
......@@ -726,7 +743,22 @@ ma_uint64 ma_resampler_get_required_input_frame_count(ma_resampler* pResampler,
case ma_resample_algorithm_speex:
{
#if defined(MA_HAS_SPEEX_RESAMPLER)
return 0;
#if 0
ma_uint64 count;
double t = pResampler->state.speex.t;
#if 0
count = (ma_uint64)floor(t + (outputFrameCount * ratioInOut) + 0.00000001);
#else
count = (ma_uint64)(floor(t + (outputFrameCount * ratioInOut)) - floor(t));
#endif
return count;
#endif
ma_uint32 count;
ma_speex_resampler_get_required_input_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (unsigned int)outputFrameCount, &count);
return count;
#else
break;
#endif
......@@ -774,6 +806,7 @@ ma_uint64 ma_resampler_get_expected_output_frame_count(ma_resampler* pResampler,
{
#if defined(MA_HAS_SPEEX_RESAMPLER)
/* TODO: Implement me. */
return 0;
#else
break;
#endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment