Merge pull request #559 from ideka/fix-channel-upscaling

Fix channel count upscaling
This commit is contained in:
David Kleingeld 2024-04-01 21:00:30 +02:00 committed by GitHub
commit e0485beb06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,3 +1,5 @@
use cpal::Sample;
/// Iterator that converts from a certain channel count to another. /// Iterator that converts from a certain channel count to another.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ChannelCountConverter<I> pub struct ChannelCountConverter<I>
@ -19,7 +21,7 @@ where
/// ///
/// # Panic /// # Panic
/// ///
/// Panicks if `from` or `to` are equal to 0. /// Panics if `from` or `to` are equal to 0.
/// ///
#[inline] #[inline]
pub fn new( pub fn new(
@ -49,25 +51,29 @@ where
impl<I> Iterator for ChannelCountConverter<I> impl<I> Iterator for ChannelCountConverter<I>
where where
I: Iterator, I: Iterator,
I::Item: Clone, 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> {
let result = if self.next_output_sample_pos == self.from - 1 { let result = match self.next_output_sample_pos {
let value = self.input.next(); 0 => {
self.sample_repeat = value.clone(); // save first sample for mono -> stereo conversion
value let value = self.input.next();
} else if self.next_output_sample_pos < self.from { self.sample_repeat = value;
self.input.next() value
} else { }
self.sample_repeat.clone() x if x < self.from => self.input.next(),
1 => self.sample_repeat,
_ => Some(I::Item::EQUILIBRIUM),
}; };
self.next_output_sample_pos += 1; if result.is_some() {
self.next_output_sample_pos += 1;
}
if self.next_output_sample_pos == self.to { if self.next_output_sample_pos == self.to {
self.next_output_sample_pos -= self.to; self.next_output_sample_pos = 0;
if self.from > self.to { if self.from > self.to {
for _ in self.to..self.from { for _ in self.to..self.from {
@ -83,11 +89,14 @@ where
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
let (min, max) = self.input.size_hint(); let (min, max) = self.input.size_hint();
let min = let consumed = std::cmp::min(self.from, self.next_output_sample_pos) as usize;
(min / self.from as usize) * self.to as usize + self.next_output_sample_pos as usize; let calculate = |size| {
let max = max.map(|max| { (size + consumed) / self.from as usize * self.to as usize
(max / self.from as usize) * self.to as usize + self.next_output_sample_pos as usize - self.next_output_sample_pos as usize
}); };
let min = calculate(min);
let max = max.map(calculate);
(min, max) (min, max)
} }
@ -96,7 +105,7 @@ where
impl<I> ExactSizeIterator for ChannelCountConverter<I> impl<I> ExactSizeIterator for ChannelCountConverter<I>
where where
I: ExactSizeIterator, I: ExactSizeIterator,
I::Item: Clone, I::Item: Sample,
{ {
} }
@ -106,36 +115,60 @@ mod test {
#[test] #[test]
fn remove_channels() { fn remove_channels() {
let input = vec![1u16, 2, 3, 1, 2, 3]; let input = vec![1u16, 2, 3, 4, 5, 6];
let output = ChannelCountConverter::new(input.into_iter(), 3, 2).collect::<Vec<_>>(); let output = ChannelCountConverter::new(input.into_iter(), 3, 2).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 1, 2]); assert_eq!(output, [1, 2, 4, 5]);
let input = vec![1u16, 2, 3, 4, 1, 2, 3, 4]; let input = vec![1u16, 2, 3, 4, 5, 6, 7, 8];
let output = ChannelCountConverter::new(input.into_iter(), 4, 1).collect::<Vec<_>>(); let output = ChannelCountConverter::new(input.into_iter(), 4, 1).collect::<Vec<_>>();
assert_eq!(output, [1, 1]); assert_eq!(output, [1, 5]);
} }
#[test] #[test]
fn add_channels() { fn add_channels() {
let input = vec![1u16, 2, 1, 2]; let input = vec![1i16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 2, 3).collect::<Vec<_>>(); let output = ChannelCountConverter::new(input.into_iter(), 1, 2).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 2, 1, 2, 2]); assert_eq!(output, [1, 1, 2, 2, 3, 3, 4, 4]);
let input = vec![1u16, 2, 1, 2]; let input = vec![1i16, 2];
let output = ChannelCountConverter::new(input.into_iter(), 1, 4).collect::<Vec<_>>();
assert_eq!(output, [1, 1, 0, 0, 2, 2, 0, 0]);
let input = vec![1i16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 2, 4).collect::<Vec<_>>(); let output = ChannelCountConverter::new(input.into_iter(), 2, 4).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 2, 2, 1, 2, 2, 2]); assert_eq!(output, [1, 2, 0, 0, 3, 4, 0, 0]);
}
#[test]
fn size_hint() {
fn test(input: &[i16], from: cpal::ChannelCount, to: cpal::ChannelCount) {
let mut converter = ChannelCountConverter::new(input.iter().copied(), from, to);
let count = converter.clone().count();
for left_in_iter in (0..=count).rev() {
println!("left_in_iter = {}", left_in_iter);
assert_eq!(converter.size_hint(), (left_in_iter, Some(left_in_iter)));
converter.next();
}
assert_eq!(converter.size_hint(), (0, Some(0)));
}
test(&[1i16, 2, 3], 1, 2);
test(&[1i16, 2, 3, 4], 2, 4);
test(&[1i16, 2, 3, 4], 4, 2);
test(&[1i16, 2, 3, 4, 5, 6], 3, 8);
test(&[1i16, 2, 3, 4, 5, 6, 7, 8], 4, 1);
} }
#[test] #[test]
fn len_more() { fn len_more() {
let input = vec![1u16, 2, 1, 2]; let input = vec![1i16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 2, 3); let output = ChannelCountConverter::new(input.into_iter(), 2, 3);
assert_eq!(output.len(), 6); assert_eq!(output.len(), 6);
} }
#[test] #[test]
fn len_less() { fn len_less() {
let input = vec![1u16, 2, 1, 2]; let input = vec![1i16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 2, 1); let output = ChannelCountConverter::new(input.into_iter(), 2, 1);
assert_eq!(output.len(), 2); assert_eq!(output.len(), 2);
} }