Update the linear resampler in preparation for some optimizing.

This commit is contained in:
David Reid
2026-02-04 16:59:05 +10:00
parent 1e2427f5f7
commit 2683601481
+66 -56
View File
@@ -5588,7 +5588,12 @@ MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format form
typedef struct
{
ma_linear_resampler_config config;
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRateIn;
ma_uint32 sampleRateOut;
ma_uint32 lpfOrder;
double lpfNyquistFactor;
ma_uint32 inAdvanceInt;
ma_uint32 inAdvanceFrac;
ma_uint32 inTimeInt;
@@ -58939,25 +58944,25 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes
return MA_INVALID_ARGS;
}
oldSampleRateOut = pResampler->config.sampleRateOut;
oldSampleRateOut = pResampler->sampleRateOut;
pResampler->config.sampleRateIn = sampleRateIn;
pResampler->config.sampleRateOut = sampleRateOut;
pResampler->sampleRateIn = sampleRateIn;
pResampler->sampleRateOut = sampleRateOut;
/* Simplify the sample rate. */
gcf = ma_gcf_u32(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut);
pResampler->config.sampleRateIn /= gcf;
pResampler->config.sampleRateOut /= gcf;
gcf = ma_gcf_u32(pResampler->sampleRateIn, pResampler->sampleRateOut);
pResampler->sampleRateIn /= gcf;
pResampler->sampleRateOut /= gcf;
/* Always initialize the low-pass filter, even when the order is 0. */
if (pResampler->config.lpfOrder > MA_MAX_FILTER_ORDER) {
if (pResampler->lpfOrder > MA_MAX_FILTER_ORDER) {
return MA_INVALID_ARGS;
}
lpfSampleRate = (ma_uint32)(ma_max(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut));
lpfCutoffFrequency = ( double)(ma_min(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut) * 0.5 * pResampler->config.lpfNyquistFactor);
lpfSampleRate = (ma_uint32)(ma_max(pResampler->sampleRateIn, pResampler->sampleRateOut));
lpfCutoffFrequency = ( double)(ma_min(pResampler->sampleRateIn, pResampler->sampleRateOut) * 0.5 * pResampler->lpfNyquistFactor);
lpfConfig = ma_lpf_config_init(pResampler->config.format, pResampler->config.channels, lpfSampleRate, lpfCutoffFrequency, pResampler->config.lpfOrder);
lpfConfig = ma_lpf_config_init(pResampler->format, pResampler->channels, lpfSampleRate, lpfCutoffFrequency, pResampler->lpfOrder);
/*
If the resampler is already initialized we don't want to do a fresh initialization of the low-pass filter because it will result in the cached frames
@@ -58974,11 +58979,11 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes
}
pResampler->inAdvanceInt = pResampler->config.sampleRateIn / pResampler->config.sampleRateOut;
pResampler->inAdvanceFrac = pResampler->config.sampleRateIn % pResampler->config.sampleRateOut;
pResampler->inAdvanceInt = pResampler->sampleRateIn / pResampler->sampleRateOut;
pResampler->inAdvanceFrac = pResampler->sampleRateIn % pResampler->sampleRateOut;
/* Our timer was based on the old rate. We need to adjust it so that it's based on the new rate. */
ma_linear_resampler_adjust_timer_for_new_rate(pResampler, oldSampleRateOut, pResampler->config.sampleRateOut);
ma_linear_resampler_adjust_timer_for_new_rate(pResampler, oldSampleRateOut, pResampler->sampleRateOut);
return MA_SUCCESS;
}
@@ -59077,7 +59082,12 @@ MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler
return result;
}
pResampler->config = *pConfig;
pResampler->format = pConfig->format;
pResampler->channels = pConfig->channels;
pResampler->sampleRateIn = pConfig->sampleRateIn;
pResampler->sampleRateOut = pConfig->sampleRateOut;
pResampler->lpfOrder = pConfig->lpfOrder;
pResampler->lpfNyquistFactor = pConfig->lpfNyquistFactor;
pResampler->_pHeap = pHeap;
MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
@@ -59164,13 +59174,13 @@ static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResa
{
ma_uint32 c;
ma_uint32 a;
const ma_uint32 channels = pResampler->config.channels;
const ma_uint32 channels = pResampler->channels;
const ma_uint32 shift = 12;
MA_ASSERT(pResampler != NULL);
MA_ASSERT(pFrameOut != NULL);
a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut;
a = (pResampler->inTimeFrac << shift) / pResampler->sampleRateOut;
MA_ASSUME(channels > 0);
for (c = 0; c < channels; c += 1) {
@@ -59184,7 +59194,7 @@ static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResa
{
ma_uint32 c;
float a;
const ma_uint32 channels = pResampler->config.channels;
const ma_uint32 channels = pResampler->channels;
MA_ASSERT(pResampler != NULL);
MA_ASSERT(pFrameOut != NULL);
@@ -59224,20 +59234,20 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
ma_uint32 iChannel;
if (pFramesInS16 != NULL) {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
pResampler->x1.s16[iChannel] = pFramesInS16[iChannel];
}
pFramesInS16 += pResampler->config.channels;
pFramesInS16 += pResampler->channels;
} else {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
pResampler->x1.s16[iChannel] = 0;
}
}
/* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */
if (pResampler->config.sampleRateIn != pResampler->config.sampleRateOut) {
if (pResampler->inAdvanceInt == 1 && pResampler->inAdvanceFrac == 0) {
ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16);
}
@@ -59254,7 +59264,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
MA_ASSERT(pResampler->inTimeInt == 0);
ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
pFramesOutS16 += pResampler->config.channels;
pFramesOutS16 += pResampler->channels;
}
framesProcessedOut += 1;
@@ -59262,8 +59272,8 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
/* Advance time forward. */
pResampler->inTimeInt += pResampler->inAdvanceInt;
pResampler->inTimeFrac += pResampler->inAdvanceFrac;
if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
if (pResampler->inTimeFrac >= pResampler->sampleRateOut) {
pResampler->inTimeFrac -= pResampler->sampleRateOut;
pResampler->inTimeInt += 1;
}
}
@@ -59300,13 +59310,13 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
ma_uint32 iChannel;
if (pFramesInS16 != NULL) {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
pResampler->x1.s16[iChannel] = pFramesInS16[iChannel];
}
pFramesInS16 += pResampler->config.channels;
pFramesInS16 += pResampler->channels;
} else {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
pResampler->x1.s16[iChannel] = 0;
}
@@ -59326,11 +59336,11 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
/* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */
if (pResampler->config.sampleRateIn != pResampler->config.sampleRateOut) {
if (pResampler->inAdvanceInt == 1 && pResampler->inAdvanceFrac == 0) {
ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pFramesOutS16, pFramesOutS16);
}
pFramesOutS16 += pResampler->config.channels;
pFramesOutS16 += pResampler->channels;
}
framesProcessedOut += 1;
@@ -59338,8 +59348,8 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
/* Advance time forward. */
pResampler->inTimeInt += pResampler->inAdvanceInt;
pResampler->inTimeFrac += pResampler->inAdvanceFrac;
if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
if (pResampler->inTimeFrac >= pResampler->sampleRateOut) {
pResampler->inTimeFrac -= pResampler->sampleRateOut;
pResampler->inTimeInt += 1;
}
}
@@ -59354,7 +59364,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16(ma_linear_resampler*
{
MA_ASSERT(pResampler != NULL);
if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) {
if (pResampler->inAdvanceInt > 0) {
return ma_linear_resampler_process_pcm_frames_s16_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
} else {
return ma_linear_resampler_process_pcm_frames_s16_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
@@ -59388,20 +59398,20 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear
ma_uint32 iChannel;
if (pFramesInF32 != NULL) {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
pResampler->x1.f32[iChannel] = pFramesInF32[iChannel];
}
pFramesInF32 += pResampler->config.channels;
pFramesInF32 += pResampler->channels;
} else {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
pResampler->x1.f32[iChannel] = 0;
}
}
/* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */
if (pResampler->config.sampleRateIn != pResampler->config.sampleRateOut) {
if (pResampler->inAdvanceInt == 1 && pResampler->inAdvanceFrac == 0) {
ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32);
}
@@ -59418,7 +59428,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear
MA_ASSERT(pResampler->inTimeInt == 0);
ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32);
pFramesOutF32 += pResampler->config.channels;
pFramesOutF32 += pResampler->channels;
}
framesProcessedOut += 1;
@@ -59426,8 +59436,8 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear
/* Advance time forward. */
pResampler->inTimeInt += pResampler->inAdvanceInt;
pResampler->inTimeFrac += pResampler->inAdvanceFrac;
if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
if (pResampler->inTimeFrac >= pResampler->sampleRateOut) {
pResampler->inTimeFrac -= pResampler->sampleRateOut;
pResampler->inTimeInt += 1;
}
}
@@ -59464,13 +59474,13 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r
ma_uint32 iChannel;
if (pFramesInF32 != NULL) {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
pResampler->x1.f32[iChannel] = pFramesInF32[iChannel];
}
pFramesInF32 += pResampler->config.channels;
pFramesInF32 += pResampler->channels;
} else {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
pResampler->x1.f32[iChannel] = 0;
}
@@ -59490,11 +59500,11 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r
ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32);
/* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */
if (pResampler->config.sampleRateIn != pResampler->config.sampleRateOut) {
if (pResampler->inAdvanceInt == 1 && pResampler->inAdvanceFrac == 0) {
ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pFramesOutF32, pFramesOutF32);
}
pFramesOutF32 += pResampler->config.channels;
pFramesOutF32 += pResampler->channels;
}
framesProcessedOut += 1;
@@ -59502,8 +59512,8 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_r
/* Advance time forward. */
pResampler->inTimeInt += pResampler->inAdvanceInt;
pResampler->inTimeFrac += pResampler->inAdvanceFrac;
if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
if (pResampler->inTimeFrac >= pResampler->sampleRateOut) {
pResampler->inTimeFrac -= pResampler->sampleRateOut;
pResampler->inTimeInt += 1;
}
}
@@ -59518,7 +59528,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_f32(ma_linear_resampler*
{
MA_ASSERT(pResampler != NULL);
if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) {
if (pResampler->inAdvanceInt > 0) {
return ma_linear_resampler_process_pcm_frames_f32_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
} else {
return ma_linear_resampler_process_pcm_frames_f32_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
@@ -59532,9 +59542,9 @@ MA_API ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pRe
return MA_INVALID_ARGS;
}
/* */ if (pResampler->config.format == ma_format_s16) {
/* */ if (pResampler->format == ma_format_s16) {
return ma_linear_resampler_process_pcm_frames_s16(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
} else if (pResampler->config.format == ma_format_f32) {
} else if (pResampler->format == ma_format_f32) {
return ma_linear_resampler_process_pcm_frames_f32(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
} else {
/* Should never get here. Getting here means the format is not supported and you didn't check the return value of ma_linear_resampler_init(). */
@@ -59589,7 +59599,7 @@ MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resample
return 0;
}
return ma_linear_resampler_get_input_latency(pResampler) * pResampler->config.sampleRateOut / pResampler->config.sampleRateIn;
return ma_linear_resampler_get_input_latency(pResampler) * pResampler->sampleRateOut / pResampler->sampleRateIn;
}
MA_API ma_result ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount)
@@ -59616,7 +59626,7 @@ MA_API ma_result ma_linear_resampler_get_required_input_frame_count(const ma_lin
/* The rest of the output frames can be calculated in constant time. */
inputFrameCount += outputFrameCount * pResampler->inAdvanceInt;
inputFrameCount += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut;
inputFrameCount += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->sampleRateOut;
*pInputFrameCount = inputFrameCount;
@@ -59676,7 +59686,7 @@ MA_API ma_result ma_linear_resampler_get_expected_output_frame_count(const ma_li
return MA_INVALID_ARGS;
}
return ma_linear_resampler_get_expected_output_frame_count_ex(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut, pResampler->inTimeInt, pResampler->inTimeFrac, pResampler->inAdvanceInt, pResampler->inAdvanceFrac, inputFrameCount, pOutputFrameCount);
return ma_linear_resampler_get_expected_output_frame_count_ex(pResampler->sampleRateIn, pResampler->sampleRateOut, pResampler->inTimeInt, pResampler->inTimeFrac, pResampler->inAdvanceInt, pResampler->inAdvanceFrac, inputFrameCount, pOutputFrameCount);
}
MA_API ma_result ma_linear_resampler_reset(ma_linear_resampler* pResampler)
@@ -59692,13 +59702,13 @@ MA_API ma_result ma_linear_resampler_reset(ma_linear_resampler* pResampler)
pResampler->inTimeFrac = 0;
/* Cached samples need to be cleared. */
if (pResampler->config.format == ma_format_f32) {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
if (pResampler->format == ma_format_f32) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.f32[iChannel] = 0;
pResampler->x1.f32[iChannel] = 0;
}
} else {
for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
for (iChannel = 0; iChannel < pResampler->channels; iChannel += 1) {
pResampler->x0.s16[iChannel] = 0;
pResampler->x1.s16[iChannel] = 0;
}