Description
When decoding audio you get chunks with constant sample rate and channel count. It seemed natural to extend that into rodio's audio pipeline. The consumer of audio gets the guarantee that the sample rate and channel count will not change for the next n-samples. The consumer can then deal with that like this:
let mut resampler = Resampler::new();
loop {
resampler.set_sample_rate(source.sample_rate());
for _ in 0..source.current_span_len() {
resample.resample(source.next()?);
}
}
This seems very efficient right? It is however no different then:
let mut resampler = Resampler::new();
loop {
resampler.set_sample_rate(source.sample_rate());
while !source.parameters_changed() {
resample.resample(source.next()?);
}
}
Especially if we let the compiler know that the parameters usually do not change using:
impl Source {
#[cold]
fn parameters_changed() -> bool;
..
}
Currently at least skipping, seeking and queue are non-trivial in rodio since we may not break our promised span_len. That span len is however never used except to create the boolean parameters_changed
via a comparison to an increasing index. Replacing current_span_len
by parameters_changed
makes rodio code far simpeler. For example seek:
impl Source {
fn seek(&mut self, some_params: some_type) {
self.parameters_changed = true
// and some code to guarantee frame alignment
// but nothing for span alignment since spans do not exist anymore!
..
}
fn parameters_changed() -> bool {
self.parameters_changed
}
}
All the complex code in queue can just be removed, it can simply forward parameters_changed until a source ends: then it just switches it to true. Right now it is has to play silence to fill the current span if a source ends early. So this change will not only make the code far far simpler it will improve audio latency!
Regarding breaking the Source API, an argument along the line of #690 (comment) can be made. This would also replace #690.
I think this is a wonderful fix/improvement. I might be wrong. Looking forward to your input.