From 2683601481b020fd9d35ac5758231e390c1b5841 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 4 Feb 2026 16:59:05 +1000 Subject: [PATCH] Update the linear resampler in preparation for some optimizing. --- miniaudio.h | 122 ++++++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 25deeb6f..e9e9f1e2 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -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; }