mirror of
https://github.com/RustAudio/rodio
synced 2024-12-13 21:52:38 +00:00
Fix sources sometimes playing in the wrong channels
For example, if a stereo source starts playing on an odd-numbered call to DynamicMixer::next() then the output stream will play its first sample in the right channel, its second in the left, etc. This is wrong. The first sample should be played in the left channel.
This commit is contained in:
parent
2e08a7efa6
commit
437bcf4ce7
1 changed files with 38 additions and 4 deletions
|
@ -30,6 +30,8 @@ where
|
||||||
let output = DynamicMixer {
|
let output = DynamicMixer {
|
||||||
current_sources: Vec::with_capacity(16),
|
current_sources: Vec::with_capacity(16),
|
||||||
input: input.clone(),
|
input: input.clone(),
|
||||||
|
sample_count: 0,
|
||||||
|
still_pending: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
(input, output)
|
(input, output)
|
||||||
|
@ -69,6 +71,12 @@ pub struct DynamicMixer<S> {
|
||||||
|
|
||||||
// The pending sounds.
|
// The pending sounds.
|
||||||
input: Arc<DynamicMixerController<S>>,
|
input: Arc<DynamicMixerController<S>>,
|
||||||
|
|
||||||
|
// The number of samples produced so far.
|
||||||
|
sample_count: usize,
|
||||||
|
|
||||||
|
// A temporary vec used in start_pending_sources.
|
||||||
|
still_pending: Vec<Box<dyn Source<Item = S> + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Source for DynamicMixer<S>
|
impl<S> Source for DynamicMixer<S>
|
||||||
|
@ -105,12 +113,11 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<S> {
|
fn next(&mut self) -> Option<S> {
|
||||||
if self.input.has_pending.load(Ordering::SeqCst) {
|
if self.input.has_pending.load(Ordering::SeqCst) {
|
||||||
// TODO: relax ordering?
|
self.start_pending_sources();
|
||||||
let mut pending = self.input.pending_sources.lock().unwrap();
|
|
||||||
self.current_sources.extend(pending.drain(..));
|
|
||||||
self.input.has_pending.store(false, Ordering::SeqCst); // TODO: relax ordering?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.sample_count += 1;
|
||||||
|
|
||||||
if self.current_sources.is_empty() {
|
if self.current_sources.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +150,33 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S> DynamicMixer<S>
|
||||||
|
where
|
||||||
|
S: Sample + Send + 'static,
|
||||||
|
{
|
||||||
|
// Samples from the #next() function are interlaced for each of the channels.
|
||||||
|
// We need to ensure we start playing sources so that their samples are
|
||||||
|
// in-step with the modulo of the samples produced so far. Otherwise, the
|
||||||
|
// sound will play on the wrong channels, e.g. left / right will be reversed.
|
||||||
|
fn start_pending_sources(&mut self) {
|
||||||
|
let mut pending = self.input.pending_sources.lock().unwrap(); // TODO: relax ordering?
|
||||||
|
|
||||||
|
for source in pending.drain(..) {
|
||||||
|
let in_step = self.sample_count % source.channels() as usize == 0;
|
||||||
|
|
||||||
|
if in_step {
|
||||||
|
self.current_sources.push(source);
|
||||||
|
} else {
|
||||||
|
self.still_pending.push(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::mem::swap(&mut self.still_pending, &mut pending);
|
||||||
|
|
||||||
|
let has_pending = !pending.is_empty();
|
||||||
|
self.input.has_pending.store(has_pending, Ordering::SeqCst); // TODO: relax ordering?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::buffer::SamplesBuffer;
|
use crate::buffer::SamplesBuffer;
|
||||||
|
|
Loading…
Reference in a new issue