[PATCH 0/5] MR10217: dsound: Speed up resampling, part 3
From: Anton Baskanov <baskanov@gmail.com> --- dlls/dsound/mixer.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index d3c6421627c..7d22e9d78b8 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -315,7 +315,7 @@ static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, UINT count) return count; } -static void resample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq_acc_start, +static void downsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq_acc_start, UINT dsbfirstep, float firgain, UINT count, float *input, float *output) { UINT i; @@ -340,6 +340,42 @@ static void resample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq } } +static void upsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq_acc_start, + UINT dsbfirstep, float firgain, UINT count, float *input, float *output) +{ + UINT i; + + for(i = 0; i < count; ++i) { + LONG64 ipos_num = freq_acc_start + i * freq_adjust_num; + UINT ipos = ipos_num / freq_adjust_den; + + UINT idx_num = ipos_num % freq_adjust_den * dsbfirstep; + UINT idx = dsbfirstep - 1 - idx_num / freq_adjust_den; + float rem = 1.0f - idx_num % freq_adjust_den / (float)freq_adjust_den; + + int fir_used = (fir_len - 1 - idx + dsbfirstep - 1) / dsbfirstep; + + int j; + float sum = 0.0; + float* cache = &input[ipos]; + + for (j = 0; j < fir_used; j++) + sum += (fir[idx + j * dsbfirstep] * (1.0f - rem) + fir[idx + j * dsbfirstep + 1] * rem) * cache[j]; + output[i] = sum * firgain; + } +} + +static void resample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq_acc_start, + UINT dsbfirstep, float firgain, UINT count, float *input, float *output) +{ + if (freq_adjust_num > freq_adjust_den) + downsample(freq_adjust_num, freq_adjust_den, freq_acc_start, dsbfirstep, firgain, count, + input, output); + else + upsample(freq_adjust_num, freq_adjust_den, freq_acc_start, dsbfirstep, firgain, count, + input, output); +} + static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNum) { UINT i, channel; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10217
From: Anton Baskanov <baskanov@gmail.com> --- dlls/dsound/mixer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 7d22e9d78b8..21bd6e4041c 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -341,7 +341,7 @@ static void downsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 fr } static void upsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq_acc_start, - UINT dsbfirstep, float firgain, UINT count, float *input, float *output) + UINT dsbfirstep, UINT count, float *input, float *output) { UINT i; @@ -361,7 +361,7 @@ static void upsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq for (j = 0; j < fir_used; j++) sum += (fir[idx + j * dsbfirstep] * (1.0f - rem) + fir[idx + j * dsbfirstep + 1] * rem) * cache[j]; - output[i] = sum * firgain; + output[i] = sum; } } @@ -372,8 +372,8 @@ static void resample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq downsample(freq_adjust_num, freq_adjust_den, freq_acc_start, dsbfirstep, firgain, count, input, output); else - upsample(freq_adjust_num, freq_adjust_den, freq_acc_start, dsbfirstep, firgain, count, - input, output); + upsample(freq_adjust_num, freq_adjust_den, freq_acc_start, dsbfirstep, count, input, + output); } static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNum) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10217
From: Anton Baskanov <baskanov@gmail.com> --- dlls/dsound/mixer.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 21bd6e4041c..f0dff13dbee 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -341,7 +341,7 @@ static void downsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 fr } static void upsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq_acc_start, - UINT dsbfirstep, UINT count, float *input, float *output) + UINT count, float *input, float *output) { UINT i; @@ -349,18 +349,18 @@ static void upsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq LONG64 ipos_num = freq_acc_start + i * freq_adjust_num; UINT ipos = ipos_num / freq_adjust_den; - UINT idx_num = ipos_num % freq_adjust_den * dsbfirstep; - UINT idx = dsbfirstep - 1 - idx_num / freq_adjust_den; + UINT idx_num = ipos_num % freq_adjust_den * fir_step; + UINT idx = fir_step - 1 - idx_num / freq_adjust_den; float rem = 1.0f - idx_num % freq_adjust_den / (float)freq_adjust_den; - int fir_used = (fir_len - 1 - idx + dsbfirstep - 1) / dsbfirstep; + int fir_used = (fir_len - 1 - idx + fir_step - 1) / fir_step; int j; float sum = 0.0; float* cache = &input[ipos]; for (j = 0; j < fir_used; j++) - sum += (fir[idx + j * dsbfirstep] * (1.0f - rem) + fir[idx + j * dsbfirstep + 1] * rem) * cache[j]; + sum += (fir[idx + j * fir_step] * (1.0f - rem) + fir[idx + j * fir_step + 1] * rem) * cache[j]; output[i] = sum; } } @@ -372,8 +372,7 @@ static void resample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq downsample(freq_adjust_num, freq_adjust_den, freq_acc_start, dsbfirstep, firgain, count, input, output); else - upsample(freq_adjust_num, freq_adjust_den, freq_acc_start, dsbfirstep, count, input, - output); + upsample(freq_adjust_num, freq_adjust_den, freq_acc_start, count, input, output); } static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNum) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10217
From: Anton Baskanov <baskanov@gmail.com> --- dlls/dsound/fir.h | 2 ++ dlls/dsound/mixer.c | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/dsound/fir.h b/dlls/dsound/fir.h index f317d19ba3b..24d93645d12 100644 --- a/dlls/dsound/fir.h +++ b/dlls/dsound/fir.h @@ -87,6 +87,7 @@ int main() fprintf(stderr, "status %s\n", get_pm_status_str(output.status)); printf("static const int fir_len = %d;\n", fir_len); + printf("static const int fir_width = %d;\n", fir_width); printf("static const int fir_step = %d;\n", fir_step); printf("static const float fir[] = {"); for (i = 0; i < fir_len; ++i) @@ -104,6 +105,7 @@ int main() } */ static const int fir_len = 8193; +static const int fir_width = 64; static const int fir_step = 128; static const float fir[] = { 0.0000000000e+00, -2.2207222127e-04, 1.4025302043e-05, 1.3443390954e-05, diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index f0dff13dbee..a89ff021184 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -353,13 +353,11 @@ static void upsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq UINT idx = fir_step - 1 - idx_num / freq_adjust_den; float rem = 1.0f - idx_num % freq_adjust_den / (float)freq_adjust_den; - int fir_used = (fir_len - 1 - idx + fir_step - 1) / fir_step; - int j; float sum = 0.0; float* cache = &input[ipos]; - for (j = 0; j < fir_used; j++) + for (j = 0; j < fir_width; j++) sum += (fir[idx + j * fir_step] * (1.0f - rem) + fir[idx + j * fir_step + 1] * rem) * cache[j]; output[i] = sum; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10217
From: Anton Baskanov <baskanov@gmail.com> --- dlls/dsound/mixer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index a89ff021184..a0f38b126b9 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -351,14 +351,15 @@ static void upsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 freq UINT idx_num = ipos_num % freq_adjust_den * fir_step; UINT idx = fir_step - 1 - idx_num / freq_adjust_den; - float rem = 1.0f - idx_num % freq_adjust_den / (float)freq_adjust_den; + float rem_inv = idx_num % freq_adjust_den / (float)freq_adjust_den; + float rem = 1.0f - rem_inv; int j; float sum = 0.0; float* cache = &input[ipos]; for (j = 0; j < fir_width; j++) - sum += (fir[idx + j * fir_step] * (1.0f - rem) + fir[idx + j * fir_step + 1] * rem) * cache[j]; + sum += (fir[idx + j * fir_step] * rem_inv + fir[idx + j * fir_step + 1] * rem) * cache[j]; output[i] = sum; } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10217
Matteo Bruni (@Mystral) commented about dlls/dsound/mixer.c:
UINT idx_num = ipos_num % freq_adjust_den * fir_step; UINT idx = fir_step - 1 - idx_num / freq_adjust_den; - float rem = 1.0f - idx_num % freq_adjust_den / (float)freq_adjust_den; + float rem_inv = idx_num % freq_adjust_den / (float)freq_adjust_den; + float rem = 1.0f - rem_inv;
I find the variable naming a bit confusing here. Before the previous MR this was probably called `rem` as in "remainder", as it effectively was the fractional part of `(freqAcc_start + i * dsb->freqAdjustNum) * dsbfirstep / dsb->freqAdjustDen`. Now it's a bit of a misnomer since it's `1.0f - <remainder>` of the new division, while `rem_inv` is the actual remainder. I'd make use of the fact that this is also the `t` parameter of the linear interpolation to rename the variable and get rid of the "rem" confusion altogether. Or at least that's how I understood it. Maybe you have a better explanation for the (preexisting) name. :sweat_smile: -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10217#note_130973
This merge request was approved by Matteo Bruni. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10217
MR looks good; I have left a small naming question inline in the last patch. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10217#note_130974
On Mon Mar 2 18:30:28 2026 +0000, Matteo Bruni wrote:
I find the variable naming a bit confusing here. Before the previous MR this was probably called `rem` as in "remainder", as it effectively was the fractional part of `(freqAcc_start + i * dsb->freqAdjustNum) * dsbfirstep / dsb->freqAdjustDen`. Now it's a bit of a misnomer since it's `1.0f - <remainder>` of the new division, while `rem_inv` is the actual remainder. I'd make use of the fact that this is also the `t` parameter of the linear interpolation to rename the variable and get rid of the "rem" confusion altogether. Or at least that's how I understood it. Maybe you have a better explanation for the (preexisting) name. :sweat_smile: I was thinking of `rem` in terms of calculating the value of a continuous FIR function `f(x)`: we split `x` like this: `x = x * fir_step / fir_step = (floor(x * fir_step) + fmod(x * fir_step), 1.0)) / fir_step` so `idx = floor(x * fir_step)` and `rem = fmod(x * fir_step, 1.0)`.
Note that the filter coefficients are accessed in reverse order compared to what a convolution would give. This is where `fir_step - 1 - ...` and `1.0 - ...` come from. It doesn't affect the resulting value because the FIR is symmetric, and it allows the FIR and the input array indices to advance in the same direction, which will be very useful for SIMD. It was already like this in the original code. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10217#note_131052
On Tue Mar 3 10:34:46 2026 +0000, Anton Baskanov wrote:
I was thinking of `rem` in terms of calculating the value of a continuous FIR function `f(x)`: we split `x` like this: `x = x * fir_step / fir_step = (floor(x * fir_step) + fmod(x * fir_step), 1.0)) / fir_step` so `idx = floor(x * fir_step)` and `rem = fmod(x * fir_step, 1.0)`. Note that the filter coefficients are accessed in reverse order compared to what a convolution would give. This is where `fir_step - 1 - ...` and `1.0 - ...` come from. It doesn't affect the resulting value because the FIR is symmetric, and it allows the FIR and the input array indices to advance in the same direction, which will be very useful for SIMD. It was already like this in the original code. Right, I did realize that the resampler goes through the filter coefficients in reverse (I already went through that particular confusion in the past :sweat_smile:). I can also agree that "rem" is technically correct. It's just that this isn't immediately obvious and variable naming doesn't seem to help necessarily. I feel like tweaking some variable names and possibly adding a comment or two would help to avoid retreading the same steps the next time someone needs to touch the resampler, in a few months or a few years.
Maybe I'll give it a shot at the end of this rework. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10217#note_131091
participants (3)
-
Anton Baskanov -
Anton Baskanov (@baskanov) -
Matteo Bruni (@Mystral)