Commit 966aeb07 authored by David Reid's avatar David Reid

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().
parent c92c7764
...@@ -35867,13 +35867,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear ...@@ -35867,13 +35867,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
framesProcessedIn = 0; framesProcessedIn = 0;
framesProcessedOut = 0; framesProcessedOut = 0;
for (;;) { while (framesProcessedOut < frameCountOut) {
if (framesProcessedOut >= frameCountOut) {
break;
}
/* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */ /* 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; ma_uint32 iChannel;
if (pFramesInS16 != NULL) { if (pFramesInS16 != NULL) {
...@@ -35892,7 +35888,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear ...@@ -35892,7 +35888,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
/* Filter. */ /* Filter. */
ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16); ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16);
frameCountIn -= 1;
framesProcessedIn += 1; framesProcessedIn += 1;
pResampler->inTimeInt -= 1; pResampler->inTimeInt -= 1;
} }
...@@ -35946,13 +35941,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r ...@@ -35946,13 +35941,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
framesProcessedIn = 0; framesProcessedIn = 0;
framesProcessedOut = 0; framesProcessedOut = 0;
for (;;) { while (framesProcessedOut < frameCountOut) {
if (framesProcessedOut >= frameCountOut) {
break;
}
/* Before interpolating we need to load the buffers. */ /* Before interpolating we need to load the buffers. */
while (pResampler->inTimeInt > 0 && frameCountIn > 0) { while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
ma_uint32 iChannel; ma_uint32 iChannel;
if (pFramesInS16 != NULL) { if (pFramesInS16 != NULL) {
...@@ -35968,7 +35959,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r ...@@ -35968,7 +35959,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
} }
} }
frameCountIn -= 1;
framesProcessedIn += 1; framesProcessedIn += 1;
pResampler->inTimeInt -= 1; pResampler->inTimeInt -= 1;
} }
...@@ -36037,13 +36027,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear ...@@ -36037,13 +36027,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear
framesProcessedIn = 0; framesProcessedIn = 0;
framesProcessedOut = 0; framesProcessedOut = 0;
for (;;) { while (framesProcessedOut < frameCountOut) {
if (framesProcessedOut >= frameCountOut) {
break;
}
/* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */ /* 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; ma_uint32 iChannel;
if (pFramesInF32 != NULL) { if (pFramesInF32 != NULL) {
...@@ -36062,7 +36048,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear ...@@ -36062,7 +36048,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear
/* Filter. */ /* Filter. */
ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32); ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32);
frameCountIn -= 1;
framesProcessedIn += 1; framesProcessedIn += 1;
pResampler->inTimeInt -= 1; pResampler->inTimeInt -= 1;
} }
...@@ -36116,13 +36101,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r ...@@ -36116,13 +36101,9 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r
framesProcessedIn = 0; framesProcessedIn = 0;
framesProcessedOut = 0; framesProcessedOut = 0;
for (;;) { while (framesProcessedOut < frameCountOut) {
if (framesProcessedOut >= frameCountOut) {
break;
}
/* Before interpolating we need to load the buffers. */ /* Before interpolating we need to load the buffers. */
while (pResampler->inTimeInt > 0 && frameCountIn > 0) { while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
ma_uint32 iChannel; ma_uint32 iChannel;
if (pFramesInF32 != NULL) { if (pFramesInF32 != NULL) {
...@@ -36138,7 +36119,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r ...@@ -36138,7 +36119,6 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r
} }
} }
frameCountIn -= 1;
framesProcessedIn += 1; framesProcessedIn += 1;
pResampler->inTimeInt -= 1; pResampler->inTimeInt -= 1;
} }
...@@ -36230,7 +36210,7 @@ MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResamp ...@@ -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_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) { if (pResampler == NULL) {
return 0; return 0;
...@@ -36241,51 +36221,48 @@ MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(ma_linear_re ...@@ -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. */ /* Any whole input frames are consumed before the first output frame is generated. */
count = pResampler->inTimeInt; inputFrameCount = pResampler->inTimeInt;
outputFrameCount -= 1; outputFrameCount -= 1;
/* The rest of the output frames can be calculated in constant time. */ /* The rest of the output frames can be calculated in constant time. */
count += outputFrameCount * pResampler->inAdvanceInt; inputFrameCount += outputFrameCount * pResampler->inAdvanceInt;
count += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut; 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_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(ma_linear_resampler* pResampler, ma_uint64 inputFrameCount)
{ {
ma_uint64 outputFrameCount; ma_uint64 outputFrameCount;
ma_uint64 inTimeInt; ma_uint64 preliminaryInputFrameCountFromFrac;
ma_uint64 inTimeFrac; ma_uint64 preliminaryInputFrameCount;
if (pResampler == NULL) { if (pResampler == NULL) {
return 0; 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
outputFrameCount = 0; 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
inTimeInt = pResampler->inTimeInt; 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
inTimeFrac = pResampler->inTimeFrac; of an extra output frame. This add-by-one logic is necessary due to how the data loading logic works when processing frames.
*/
for (;;) { outputFrameCount = (inputFrameCount * pResampler->config.sampleRateOut) / pResampler->config.sampleRateIn;
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; outputFrameCount += 1;
/* Advance time forward. */
inTimeInt += pResampler->inAdvanceInt;
inTimeFrac += pResampler->inAdvanceFrac;
if (inTimeFrac >= pResampler->config.sampleRateOut) {
inTimeFrac -= pResampler->config.sampleRateOut;
inTimeInt += 1;
}
} }
return outputFrameCount; return outputFrameCount;
...@@ -43682,11 +43659,18 @@ MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesO ...@@ -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) MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex)
{ {
if (pDecoder == NULL) { if (pDecoder == NULL) {
return 0; return MA_INVALID_ARGS;
} }
if (pDecoder->onSeekToPCMFrame) { 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. */ /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */
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