mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 14:14:21 +00:00
Fix samples rate converter not taking interleaved channels into account
This commit is contained in:
parent
f3a4c6e170
commit
580e0c4309
3 changed files with 39 additions and 28 deletions
|
@ -1,5 +1,6 @@
|
||||||
use cpal;
|
use cpal;
|
||||||
use conversions::Sample;
|
use conversions::Sample;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
/// Iterator that converts from a certain samples rate to another.
|
/// Iterator that converts from a certain samples rate to another.
|
||||||
pub struct SamplesRateConverter<I> where I: Iterator {
|
pub struct SamplesRateConverter<I> where I: Iterator {
|
||||||
|
@ -9,15 +10,17 @@ pub struct SamplesRateConverter<I> where I: Iterator {
|
||||||
from: u32,
|
from: u32,
|
||||||
/// We convert chunks of `from` samples into chunks of `to` samples.
|
/// We convert chunks of `from` samples into chunks of `to` samples.
|
||||||
to: u32,
|
to: u32,
|
||||||
/// One sample extracted from `input`.
|
/// One sample per channel, extracted from `input`.
|
||||||
current_sample: Option<I::Item>,
|
current_samples: Vec<I::Item>,
|
||||||
/// Position of `current_sample` modulo `from`.
|
/// Position of `current_sample` modulo `from`.
|
||||||
current_sample_pos_in_chunk: u32,
|
current_sample_pos_in_chunk: u32,
|
||||||
/// The sample right after `current_sample`, extracted from `input`.
|
/// The samples right after `current_sample` (one per channel), extracted from `input`.
|
||||||
next_sample: Option<I::Item>,
|
next_samples: Vec<I::Item>,
|
||||||
/// The position of the next sample that the iterator should return, modulo `to`.
|
/// The position of the next sample that the iterator should return, modulo `to`.
|
||||||
/// This counter is incremented (modulo `to`) every time the iterator is called.
|
/// This counter is incremented (modulo `to`) every time the iterator is called.
|
||||||
next_output_sample_pos_in_chunk: u32,
|
next_output_sample_pos_in_chunk: u32,
|
||||||
|
/// The buffer containing the samples waiting to be output.
|
||||||
|
output_buffer: Vec<I::Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> SamplesRateConverter<I> where I: Iterator {
|
impl<I> SamplesRateConverter<I> where I: Iterator {
|
||||||
|
@ -28,8 +31,8 @@ impl<I> SamplesRateConverter<I> where I: Iterator {
|
||||||
/// Panicks if `from` or `to` are equal to 0.
|
/// Panicks if `from` or `to` are equal to 0.
|
||||||
///
|
///
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(mut input: I, from: cpal::SamplesRate, to: cpal::SamplesRate)
|
pub fn new(mut input: I, from: cpal::SamplesRate, to: cpal::SamplesRate,
|
||||||
-> SamplesRateConverter<I>
|
num_channels: cpal::ChannelsCount) -> SamplesRateConverter<I>
|
||||||
{
|
{
|
||||||
let from = from.0;
|
let from = from.0;
|
||||||
let to = to.0;
|
let to = to.0;
|
||||||
|
@ -51,8 +54,8 @@ impl<I> SamplesRateConverter<I> where I: Iterator {
|
||||||
gcd(from, to)
|
gcd(from, to)
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_sample = input.next();
|
let first_samples = input.by_ref().take(num_channels as usize).collect();
|
||||||
let second_sample = input.next();
|
let second_samples = input.by_ref().take(num_channels as usize).collect();
|
||||||
|
|
||||||
SamplesRateConverter {
|
SamplesRateConverter {
|
||||||
input: input,
|
input: input,
|
||||||
|
@ -60,8 +63,9 @@ impl<I> SamplesRateConverter<I> where I: Iterator {
|
||||||
to: to / gcd,
|
to: to / gcd,
|
||||||
current_sample_pos_in_chunk: 0,
|
current_sample_pos_in_chunk: 0,
|
||||||
next_output_sample_pos_in_chunk: 0,
|
next_output_sample_pos_in_chunk: 0,
|
||||||
current_sample: first_sample,
|
current_samples: first_samples,
|
||||||
next_sample: second_sample,
|
next_samples: second_samples,
|
||||||
|
output_buffer: Vec::with_capacity(num_channels as usize),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +74,14 @@ impl<I> Iterator for SamplesRateConverter<I> where I: Iterator, I::Item: Sample
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<I::Item> {
|
fn next(&mut self) -> Option<I::Item> {
|
||||||
|
if self.output_buffer.len() >= 1 {
|
||||||
|
return Some(self.output_buffer.remove(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.current_samples.len() == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// The sample we are going to return from this function will be a linear interpolation
|
// The sample we are going to return from this function will be a linear interpolation
|
||||||
// between `self.current_sample` and `self.next_sample`.
|
// between `self.current_sample` and `self.next_sample`.
|
||||||
|
|
||||||
|
@ -82,29 +94,28 @@ impl<I> Iterator for SamplesRateConverter<I> where I: Iterator, I::Item: Sample
|
||||||
while self.current_sample_pos_in_chunk != req_left_sample {
|
while self.current_sample_pos_in_chunk != req_left_sample {
|
||||||
self.current_sample_pos_in_chunk += 1;
|
self.current_sample_pos_in_chunk += 1;
|
||||||
self.current_sample_pos_in_chunk %= self.from;
|
self.current_sample_pos_in_chunk %= self.from;
|
||||||
self.current_sample = self.next_sample;
|
|
||||||
self.next_sample = self.input.next();
|
let new_samples = self.input.by_ref().take(self.current_samples.capacity()).collect();
|
||||||
|
mem::swap(&mut self.current_samples, &mut self.next_samples);
|
||||||
|
mem::replace(&mut self.next_samples, new_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doing the linear interpolation. We handle a possible end of stream here.
|
self.output_buffer = self.current_samples.iter().zip(self.next_samples.iter())
|
||||||
let result = match (self.current_sample, self.next_sample) {
|
.map(|(cur, next)|
|
||||||
(Some(ref cur), Some(ref next)) => {
|
{
|
||||||
let numerator = (self.from * self.next_output_sample_pos_in_chunk) % self.to;
|
let numerator = (self.from * self.next_output_sample_pos_in_chunk) % self.to;
|
||||||
Sample::lerp(cur.clone(), next.clone(), numerator, self.to)
|
Sample::lerp(cur.clone(), next.clone(), numerator, self.to)
|
||||||
},
|
}).collect();
|
||||||
|
|
||||||
(Some(ref cur), None) if self.next_output_sample_pos_in_chunk == 0 => {
|
|
||||||
cur.clone()
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Incrementing the counter for the next iteration.
|
// Incrementing the counter for the next iteration.
|
||||||
self.next_output_sample_pos_in_chunk += 1;
|
self.next_output_sample_pos_in_chunk += 1;
|
||||||
self.next_output_sample_pos_in_chunk %= self.to;
|
self.next_output_sample_pos_in_chunk %= self.to;
|
||||||
|
|
||||||
Some(result)
|
if self.output_buffer.len() >= 1 {
|
||||||
|
Some(self.output_buffer.remove(0))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl VorbisDecoder {
|
||||||
let reader = conversions::ChannelsCountConverter::new(reader, packet.channels,
|
let reader = conversions::ChannelsCountConverter::new(reader, packet.channels,
|
||||||
to_channels);
|
to_channels);
|
||||||
let reader = conversions::SamplesRateConverter::new(reader, cpal::SamplesRate(packet.rate as u32),
|
let reader = conversions::SamplesRateConverter::new(reader, cpal::SamplesRate(packet.rate as u32),
|
||||||
to_samples_rate);
|
to_samples_rate, to_channels);
|
||||||
reader
|
reader
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ impl WavDecoder {
|
||||||
let reader = conversions::ChannelsCountConverter::new(reader, spec.channels,
|
let reader = conversions::ChannelsCountConverter::new(reader, spec.channels,
|
||||||
voice.get_channels());
|
voice.get_channels());
|
||||||
let reader = conversions::SamplesRateConverter::new(reader, cpal::SamplesRate(spec.sample_rate),
|
let reader = conversions::SamplesRateConverter::new(reader, cpal::SamplesRate(spec.sample_rate),
|
||||||
voice.get_samples_rate());
|
voice.get_samples_rate(), voice.get_channels());
|
||||||
|
|
||||||
Ok(WavDecoder {
|
Ok(WavDecoder {
|
||||||
reader: conversions::AmplifierIterator::new(Box::new(reader), 1.0),
|
reader: conversions::AmplifierIterator::new(Box::new(reader), 1.0),
|
||||||
|
|
Loading…
Reference in a new issue