-
Notifications
You must be signed in to change notification settings - Fork 239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adopt a higher quality resampler #647
Comments
I like this idea 👍 might give a good middle ground between low quality fast and high quality but slow. Lets first see what the perf difference the different resamplers. I've already looked at rubato and it looks great. I'm not sure about rust-samplerate. I do not like adding a C-dependency. Those complicate cross-compiling a lot..... Instead we could try the resampler in dasp: https://docs.rs/dasp/latest/dasp/interpolate/sinc/struct.Sinc.html. |
This is, indeed a issue. In our investigation into the playback quality of Rune, our player, which used Rodio as the playback backend, the issue happened. To rule out software-related influences, we controlled all external parameters:
This setup resulted in a clean, smooth spectrum, confirming that there are no inherent development errors within Rune affecting audio quality. However, we observed that Rodio's resampling process has flaws, particularly when downsampling from 48000Hz to 44100Hz, leading to suboptimal signal quality. By subtracting Rodio's decoded output from the Ground Truth signal, the flaws in the resampling parameters become evident.The period of the mixed signal is four seconds. That is to say, the output frequency is 0.25hz lower/higher. We hope these observations could help. Best regards. |
I just looked at the investigation in the rune player and they went through quite some trouble before finding the issue is our resampler. Given rodio is a playback lib I think it can be expected it does not introduce artifacts.... So I am going to mark this a bug. @PetrGlad do you want to pick this up or shall I? |
@dvdsk You can pick it if you want. |
and through it mixer, yeah its gonna be a challenge. I have an idea, we could do the same as I propose here: #646 (comment), so make the sink/stream instruct its parents/children on what re-sampler to use. Though that could impact performance, but maybe not that much as most re-samplers operate on groups of samples. An alternative would be to make every source that does resampling (UniformSourceIterator and through it mixer) generic over the resampling implementation. With static dispatch (so not Box) the optimizer can really do its thing. Do you have any suggestions? Right now I am thinking of doing both and comparing the perf. |
@dvdsk You have answered this question before, but now I am thinking again about introducing "uniform source" trait whose implementations do not change their stream format (sample format, sample frequency, or channels number) mid-flight. This way complicated logic can be contained only where it is really needed. I imagine having convering 'UniformSourceIterator' next to external inputs, and using simpler processing steps everywhere else, except maybe an additional conversion may be needed just before the output device. With such simplified sources, when an input is added, it is only asserted once that stream parameters match what is expected and then the code in down-stream steps can just rely on that. |
Could you explain why? I was thinking about having the choice of a fast lowfi resampler (what we have now) and a hifi resampler like rubato. I do support using a trait to decouple the implementation from rodio's codebase. That is usefull if the resampler ever gets abandoned and we want to swap it out for another. But I would keep that trait private to rodio. |
The disadvantage is that you then have two processes (one simpel, one complex) instead of just one. It might have performance benefits, but no one has complained about rodio's current performance (one or two issues in the distant past but that had to do with clear bugs if I remember correctly). |
Maybe this one could be a reference? |
@dvdsk I'd think that giving a resampler choice if implemented properly may result in code that is less coupled and easier to change afterwards. That is not a requirement, of course. |
oh I'm all for decoupling. I just like to keep the API as small and simple as reasonable. Internally this can be a trait implemented by different resamplers. |
relevent work in progress PR #670 |
Currently implemented sample rate converter uses simple linear interpolation algorithm and is prone to producing high frequency noise in output. See for example #584 and #316 related to the resampler implementation. However the algorithm is fast and requires little resources, so we should keep it at least as an option.
We should integrate an existing sample rate converter and let users to pick a resampler implementation depending on their needs. A simple optional low-pass filter may be also implemented as post-processing step for existing Rodio's SampleRateConverter to improve its audio quality.
It seems that there are 2 implementations that we can use:
Note that all of these libraries process only floating point samples.
The text was updated successfully, but these errors were encountered: