Re: [PATCH v2 0/5] MR9588: dsound: Introduce a cubic spline interpolation resampler.
Jan. 12, 2026
1:30 p.m.
On Mon Jan 12 10:50:32 2026 +0000, Anton Baskanov wrote:
> Thanks for the detailed explanation.
> > Otherwise we could bring in the sinc resampler, which is theoretically
> very solid and still quite a bit faster than the old FIR resampler.
> I studied the code of the openal-soft sinc resampler, and I think that
> our resampler is theoretically better:
> - Our upsampling window width is 65.89 samples, which is much wider than
> openal-soft's 24. This should result in a sharper pass-band to stop-band
> transition, which means less aliasing.
> - openal-soft's downsampling window is limited to 48 samples, whereas we
> don’t have such a limit.
> - The way openal-soft expands the upsampling window by linearly
> interpolating between windows of different sizes is a bit questionable.
> We expand the window by varying `dsbfirstep`, which should provide a
> smoother transition.
> > The FIR resampler used a fixed Gaussian window instead of the
> parametrized Kaiser that's customarily used for audio resampling.
> It shouldn't be too hard to change the window function in `make_fir`.
> > Additionally, the position computation (`total_fir_steps`, `rem`)
> using floats wasn't exact, which in turn caused some mid-high frequency distortion.
> This can be easily fixed by using integer arithmetic:
> <details>
> <summary>Click to expand</summary>
> ```diff
> diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
> index b50d9f3a8c8..fe1c8a70db3 100644
> --- a/dlls/dsound/mixer.c
> +++ b/dlls/dsound/mixer.c
> @@ -365,12 +365,12 @@ static UINT
> cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *
> }
>
> for(i = 0; i < count; ++i) {
> - UINT int_fir_steps = (freqAcc_start + i * dsb->freqAdjustNum) *
> dsbfirstep / dsb->freqAdjustDen;
> - float total_fir_steps = (freqAcc_start + i *
> dsb->freqAdjustNum) * dsbfirstep / (float)dsb->freqAdjustDen;
> + LONG64 fir_steps_num = (freqAcc_start + i * dsb->freqAdjustNum)
> * dsbfirstep;
> + UINT int_fir_steps = fir_steps_num / dsb->freqAdjustDen;
> UINT ipos = int_fir_steps / dsbfirstep;
>
> UINT idx = (ipos + 1) * dsbfirstep - int_fir_steps - 1;
> - float rem = int_fir_steps + 1.0 - total_fir_steps;
> + float rem = 1.0 - (fir_steps_num - int_fir_steps *
> dsb->freqAdjustDen) / (float)dsb->freqAdjustDen;
>
> int fir_used = 0;
> while (idx < fir_len - 1) {
> ```
> </details>
> I also did some experiments, and I was able to make our resampler 5
> times faster without sacrificing the quality by rearranging the FIR
> array and using SSE. Maybe we should give it a try. I'll try to come up
> with a draft MR.
I'm curious about your changes. All things being equal it would be preferable to improve the existing resampler rather than introducing a different one. The problem is that I'm not sure we can make it fast enough without effectively rewriting it from scratch.
When I wrote this MR I felt like the current resampler might be hopelessly too complex for realtime resampling of 100+ sound buffers (which is what Fallout 3 and New Vegas can end up with on occasion). I benchmarked Wine's dsound resampling and compared the performance to Windows. I also tested plugging resamplers from other common libraries (speexdsp and libsamplerate, before openal-soft) into Wine's dsound, and that kinda reinforced my view. The fastest fsinc implementation I tried (which is from openal-soft) is still about half as fast as Win 10 / 11's, IIRC.
I can go look at the actual numbers but I'm pretty sure a 5x improvement when using explicit SSE does not quite cut it.
I'll mention that, since I wrote this MR, I have prepared a few more patches to improve on other pieces of the dsound mixer, which become the bottleneck once the resampler itself gets fast enough. You can find it at https://gitlab.winehq.org/Mystral/wine/-/commits/dsound-perf (I cleaned the patches up locally since I pushed all that to gitlab, but the gist should be there already). For reference, these are the changes:
- Prepare all the input samples and store all the generated output samples in one go instead of doing it sample-by-sample
- Don't use indirect function calls for sample conversion
- Don't use indirect function calls for channel interleaving
- Interleave channels after mixing
- Mix and apply volume at the same time
- SSE mixing
These patches give some incremental performance improvements. It's possible that the combination of these and an improved version of the current resampler gets us where we want, although I'm not super hopeful...
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/9588#note_126630
73
Age (days ago)
73
Last active (days ago)
0 comments
1 participants
participants (1)
-
Matteo Bruni (@Mystral)