mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Update linear resampler expected output frame count calculations.
This updates ma_linear_resampler_get_expected_output_frame_count() to calculate the expected output frame count in constant time rather than linear time. This should improve performances of anything using ma_calculate_frame_count_after_resampling() which includes ma_decoder_get_length_in_pcm_frames().
This commit is contained in:
+44
-60
@@ -35867,13 +35867,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
|
||||
framesProcessedIn = 0;
|
||||
framesProcessedOut = 0;
|
||||
|
||||
for (;;) {
|
||||
if (framesProcessedOut >= frameCountOut) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (framesProcessedOut < frameCountOut) {
|
||||
/* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */
|
||||
while (pResampler->inTimeInt > 0 && frameCountIn > 0) {
|
||||
while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
|
||||
ma_uint32 iChannel;
|
||||
|
||||
if (pFramesInS16 != NULL) {
|
||||
@@ -35892,7 +35888,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
|
||||
/* Filter. */
|
||||
ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16);
|
||||
|
||||
frameCountIn -= 1;
|
||||
framesProcessedIn += 1;
|
||||
pResampler->inTimeInt -= 1;
|
||||
}
|
||||
@@ -35946,13 +35941,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
|
||||
framesProcessedIn = 0;
|
||||
framesProcessedOut = 0;
|
||||
|
||||
for (;;) {
|
||||
if (framesProcessedOut >= frameCountOut) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (framesProcessedOut < frameCountOut) {
|
||||
/* Before interpolating we need to load the buffers. */
|
||||
while (pResampler->inTimeInt > 0 && frameCountIn > 0) {
|
||||
while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
|
||||
ma_uint32 iChannel;
|
||||
|
||||
if (pFramesInS16 != NULL) {
|
||||
@@ -35968,7 +35959,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
|
||||
}
|
||||
}
|
||||
|
||||
frameCountIn -= 1;
|
||||
framesProcessedIn += 1;
|
||||
pResampler->inTimeInt -= 1;
|
||||
}
|
||||
@@ -36037,13 +36027,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear
|
||||
framesProcessedIn = 0;
|
||||
framesProcessedOut = 0;
|
||||
|
||||
for (;;) {
|
||||
if (framesProcessedOut >= frameCountOut) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (framesProcessedOut < frameCountOut) {
|
||||
/* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */
|
||||
while (pResampler->inTimeInt > 0 && frameCountIn > 0) {
|
||||
while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
|
||||
ma_uint32 iChannel;
|
||||
|
||||
if (pFramesInF32 != NULL) {
|
||||
@@ -36062,7 +36048,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear
|
||||
/* Filter. */
|
||||
ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32);
|
||||
|
||||
frameCountIn -= 1;
|
||||
framesProcessedIn += 1;
|
||||
pResampler->inTimeInt -= 1;
|
||||
}
|
||||
@@ -36116,13 +36101,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r
|
||||
framesProcessedIn = 0;
|
||||
framesProcessedOut = 0;
|
||||
|
||||
for (;;) {
|
||||
if (framesProcessedOut >= frameCountOut) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (framesProcessedOut < frameCountOut) {
|
||||
/* Before interpolating we need to load the buffers. */
|
||||
while (pResampler->inTimeInt > 0 && frameCountIn > 0) {
|
||||
while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
|
||||
ma_uint32 iChannel;
|
||||
|
||||
if (pFramesInF32 != NULL) {
|
||||
@@ -36138,7 +36119,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r
|
||||
}
|
||||
}
|
||||
|
||||
frameCountIn -= 1;
|
||||
framesProcessedIn += 1;
|
||||
pResampler->inTimeInt -= 1;
|
||||
}
|
||||
@@ -36230,7 +36210,7 @@ MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResamp
|
||||
|
||||
MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(ma_linear_resampler* pResampler, ma_uint64 outputFrameCount)
|
||||
{
|
||||
ma_uint64 count;
|
||||
ma_uint64 inputFrameCount;
|
||||
|
||||
if (pResampler == NULL) {
|
||||
return 0;
|
||||
@@ -36241,51 +36221,48 @@ MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(ma_linear_re
|
||||
}
|
||||
|
||||
/* Any whole input frames are consumed before the first output frame is generated. */
|
||||
count = pResampler->inTimeInt;
|
||||
inputFrameCount = pResampler->inTimeInt;
|
||||
outputFrameCount -= 1;
|
||||
|
||||
/* The rest of the output frames can be calculated in constant time. */
|
||||
count += outputFrameCount * pResampler->inAdvanceInt;
|
||||
count += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut;
|
||||
inputFrameCount += outputFrameCount * pResampler->inAdvanceInt;
|
||||
inputFrameCount += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut;
|
||||
|
||||
return count;
|
||||
return inputFrameCount;
|
||||
}
|
||||
|
||||
MA_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(ma_linear_resampler* pResampler, ma_uint64 inputFrameCount)
|
||||
{
|
||||
ma_uint64 outputFrameCount;
|
||||
ma_uint64 inTimeInt;
|
||||
ma_uint64 inTimeFrac;
|
||||
|
||||
ma_uint64 preliminaryInputFrameCountFromFrac;
|
||||
ma_uint64 preliminaryInputFrameCount;
|
||||
|
||||
if (pResampler == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Try making this run in constant time. */
|
||||
/*
|
||||
The first step is to get a preliminary output frame count. This will either be exactly equal to what we need, or less by 1. We need to
|
||||
determine how many input frames will be consumed by this value. If it's greater than our original input frame count it means we won't
|
||||
be able to generate an extra frame because we will have run out of input data. Otherwise we will have enough input for the generation
|
||||
of an extra output frame. This add-by-one logic is necessary due to how the data loading logic works when processing frames.
|
||||
*/
|
||||
outputFrameCount = (inputFrameCount * pResampler->config.sampleRateOut) / pResampler->config.sampleRateIn;
|
||||
|
||||
outputFrameCount = 0;
|
||||
inTimeInt = pResampler->inTimeInt;
|
||||
inTimeFrac = pResampler->inTimeFrac;
|
||||
|
||||
for (;;) {
|
||||
while (inTimeInt > 0 && inputFrameCount > 0) {
|
||||
inputFrameCount -= 1;
|
||||
inTimeInt -= 1;
|
||||
}
|
||||
|
||||
if (inTimeInt > 0) {
|
||||
break;
|
||||
}
|
||||
/*
|
||||
We need to determine how many *whole* input frames will have been processed to generate our preliminary output frame count. This is
|
||||
used in the logic below to determine whether or not we need to add an extra output frame.
|
||||
*/
|
||||
preliminaryInputFrameCountFromFrac = (pResampler->inTimeFrac + outputFrameCount*pResampler->inAdvanceFrac) / pResampler->config.sampleRateOut;
|
||||
preliminaryInputFrameCount = (pResampler->inTimeInt + outputFrameCount*pResampler->inAdvanceInt ) + preliminaryInputFrameCountFromFrac;
|
||||
|
||||
/*
|
||||
If the total number of *whole* input frames that would be required to generate our preliminary output frame count is greather than
|
||||
the amount of whole input frames we have available as input we need to *not* add an extra output frame as there won't be enough data
|
||||
to actually process. Otherwise we need to add the extra output frame.
|
||||
*/
|
||||
if (preliminaryInputFrameCount <= inputFrameCount) {
|
||||
outputFrameCount += 1;
|
||||
|
||||
/* Advance time forward. */
|
||||
inTimeInt += pResampler->inAdvanceInt;
|
||||
inTimeFrac += pResampler->inAdvanceFrac;
|
||||
if (inTimeFrac >= pResampler->config.sampleRateOut) {
|
||||
inTimeFrac -= pResampler->config.sampleRateOut;
|
||||
inTimeInt += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return outputFrameCount;
|
||||
@@ -43682,11 +43659,18 @@ MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesO
|
||||
MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex)
|
||||
{
|
||||
if (pDecoder == NULL) {
|
||||
return 0;
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (pDecoder->onSeekToPCMFrame) {
|
||||
return pDecoder->onSeekToPCMFrame(pDecoder, frameIndex);
|
||||
ma_uint64 internalFrameIndex;
|
||||
if (pDecoder->internalSampleRate == pDecoder->outputSampleRate) {
|
||||
internalFrameIndex = frameIndex;
|
||||
} else {
|
||||
internalFrameIndex = ma_calculate_frame_count_after_resampling(pDecoder->internalSampleRate, pDecoder->outputSampleRate, frameIndex);
|
||||
}
|
||||
|
||||
return pDecoder->onSeekToPCMFrame(pDecoder, internalFrameIndex);
|
||||
}
|
||||
|
||||
/* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */
|
||||
|
||||
Reference in New Issue
Block a user