mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-21 15:56:58 +02:00
Resampler: Optimization to the s16 path in the linear resampler.
The main thing here is moving an integer division out of the inner loop.
This commit is contained in:
+32
-22
@@ -3031,6 +3031,12 @@ the input and output sample rates (Nyquist Frequency).
|
||||
The API for the linear resampler is the same as the main resampler API, only it's called
|
||||
`ma_linear_resampler`.
|
||||
|
||||
The linear resampler supports s16 and f32 sample formats. The s16 path uses purely integer math,
|
||||
whereas the f32 path will use floating point. For the s16 path, make sure you use reasonable ratios
|
||||
for the input and output sample rates. It's OK to do make it large like 8000 -> 88200, but it's not
|
||||
OK to use stupid numbers like 8000 -> 89999. If you need ratios like this, use the f32 path, or use
|
||||
a different resampler.
|
||||
|
||||
|
||||
10.3.2. Custom Resamplers
|
||||
-------------------------
|
||||
@@ -59155,41 +59161,41 @@ MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma
|
||||
}
|
||||
}
|
||||
|
||||
static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma_int32 a, const ma_int32 shift)
|
||||
{
|
||||
ma_int32 b;
|
||||
ma_int32 c;
|
||||
ma_int32 r;
|
||||
#define MA_LINEAR_RESAMPLER_LERP_SHIFT 12
|
||||
|
||||
MA_ASSERT(a <= (1<<shift));
|
||||
|
||||
b = x * ((1<<shift) - a);
|
||||
c = y * a;
|
||||
r = b + c;
|
||||
|
||||
return (ma_int16)(r >> shift);
|
||||
}
|
||||
|
||||
static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* MA_RESTRICT pFrameOut)
|
||||
static MA_INLINE void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_uint32 invSampleRateOut, ma_int16* MA_RESTRICT pFrameOut)
|
||||
{
|
||||
ma_uint32 c;
|
||||
ma_uint32 a;
|
||||
const ma_uint32 channels = pResampler->channels;
|
||||
const ma_uint32 shift = 12;
|
||||
|
||||
MA_ASSERT(pResampler != NULL);
|
||||
MA_ASSERT(pFrameOut != NULL);
|
||||
|
||||
a = (pResampler->inTimeFrac << shift) / pResampler->sampleRateOut;
|
||||
/*
|
||||
The fractional component (inTimeFrac) will be between 0 and the output sample rate. We need to apply a scaling
|
||||
factor (invSampleRateOut). It is assumed invSampleRateOut has been shifted by MA_LINEAR_RESAMPLER_LERP_SHIFT.
|
||||
|
||||
The lerp below is based on the ma_mix_f32_fast(), but with fixed point math.
|
||||
*/
|
||||
a = pResampler->inTimeFrac * invSampleRateOut;
|
||||
|
||||
MA_ASSUME(channels > 0);
|
||||
for (c = 0; c < channels; c += 1) {
|
||||
ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift);
|
||||
pFrameOut[c] = s;
|
||||
ma_int16 x, y;
|
||||
ma_int32 d;
|
||||
ma_int32 n;
|
||||
|
||||
x = pResampler->x0.s16[c];
|
||||
y = pResampler->x1.s16[c];
|
||||
d = y - x;
|
||||
n = d * a;
|
||||
|
||||
pFrameOut[c] = (ma_int16)(x + (n >> MA_LINEAR_RESAMPLER_LERP_SHIFT));
|
||||
}
|
||||
}
|
||||
|
||||
static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float invSampleRateOut, float* MA_RESTRICT pFrameOut)
|
||||
static MA_INLINE void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float invSampleRateOut, float* MA_RESTRICT pFrameOut)
|
||||
{
|
||||
ma_uint32 c;
|
||||
float a;
|
||||
@@ -59215,6 +59221,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
|
||||
ma_uint64 frameCountOut;
|
||||
ma_uint64 framesProcessedIn;
|
||||
ma_uint64 framesProcessedOut;
|
||||
ma_uint32 invSampleRateOut;
|
||||
|
||||
MA_ASSERT(pResampler != NULL);
|
||||
MA_ASSERT(pFrameCountIn != NULL);
|
||||
@@ -59226,6 +59233,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
|
||||
frameCountOut = *pFrameCountOut;
|
||||
framesProcessedIn = 0;
|
||||
framesProcessedOut = 0;
|
||||
invSampleRateOut = (1 << MA_LINEAR_RESAMPLER_LERP_SHIFT) / pResampler->sampleRateOut;
|
||||
|
||||
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. */
|
||||
@@ -59261,7 +59269,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear
|
||||
/* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */
|
||||
if (pFramesOutS16 != NULL) {
|
||||
MA_ASSERT(pResampler->inTimeInt == 0);
|
||||
ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
|
||||
ma_linear_resampler_interpolate_frame_s16(pResampler, invSampleRateOut, pFramesOutS16);
|
||||
|
||||
pFramesOutS16 += pResampler->channels;
|
||||
}
|
||||
@@ -59291,6 +59299,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
|
||||
ma_uint64 frameCountOut;
|
||||
ma_uint64 framesProcessedIn;
|
||||
ma_uint64 framesProcessedOut;
|
||||
ma_uint32 invSampleRateOut;
|
||||
|
||||
MA_ASSERT(pResampler != NULL);
|
||||
MA_ASSERT(pFrameCountIn != NULL);
|
||||
@@ -59302,6 +59311,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
|
||||
frameCountOut = *pFrameCountOut;
|
||||
framesProcessedIn = 0;
|
||||
framesProcessedOut = 0;
|
||||
invSampleRateOut = (1 << MA_LINEAR_RESAMPLER_LERP_SHIFT) / pResampler->sampleRateOut;
|
||||
|
||||
while (framesProcessedOut < frameCountOut) {
|
||||
/* Before interpolating we need to load the buffers. */
|
||||
@@ -59332,7 +59342,7 @@ static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_r
|
||||
/* Getting here means the frames have been loaded and we can generate the next output frame. */
|
||||
if (pFramesOutS16 != NULL) {
|
||||
MA_ASSERT(pResampler->inTimeInt == 0);
|
||||
ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
|
||||
ma_linear_resampler_interpolate_frame_s16(pResampler, invSampleRateOut, pFramesOutS16);
|
||||
|
||||
/* Filter. Do not apply filtering if sample rates are the same or else you'll get dangerous glitching. */
|
||||
if (pResampler->inAdvanceInt == 1 && pResampler->inAdvanceFrac == 0) {
|
||||
|
||||
Reference in New Issue
Block a user