Skip to content

Commit

Permalink
Avoid duplicating signals when upscaling channels
Browse files Browse the repository at this point in the history
Mono -> stereo remain the only exception.
  • Loading branch information
ideka committed Mar 26, 2024
1 parent 6de6f22 commit c87da03
Showing 1 changed file with 31 additions and 22 deletions.
53 changes: 31 additions & 22 deletions src/conversions/channels.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use cpal::Sample;

/// Iterator that converts from a certain channel count to another.
#[derive(Clone, Debug)]
pub struct ChannelCountConverter<I>
Expand All @@ -7,7 +9,7 @@ where
input: I,
from: cpal::ChannelCount,
to: cpal::ChannelCount,
sample_repeat: Vec<Option<I::Item>>,
sample_repeat: Option<I::Item>,
next_output_sample_pos: cpal::ChannelCount,
}

Expand All @@ -34,11 +36,7 @@ where
input,
from,
to,
sample_repeat: {
let mut vec = Vec::with_capacity(from as usize);
vec.resize_with(from as usize, || None);
vec
},
sample_repeat: None,
next_output_sample_pos: 0,
}
}
Expand All @@ -53,17 +51,21 @@ where
impl<I> Iterator for ChannelCountConverter<I>
where
I: Iterator,
I::Item: Clone,
I::Item: Sample,
{
type Item = I::Item;

fn next(&mut self) -> Option<I::Item> {
let result = if self.next_output_sample_pos < self.from {
let value = self.input.next();
self.sample_repeat[self.next_output_sample_pos as usize] = value.clone();
value
} else {
self.sample_repeat[(self.next_output_sample_pos % self.from) as usize].clone()
let result = match self.next_output_sample_pos {
0 => {
// save first sample for mono -> stereo conversion
let value = self.input.next();
self.sample_repeat = value;
value
}
x if x < self.from => self.input.next(),
1 => self.sample_repeat,
_ => Some(I::Item::EQUILIBRIUM),
};

self.next_output_sample_pos += 1;
Expand Down Expand Up @@ -97,8 +99,8 @@ where

impl<I> ExactSizeIterator for ChannelCountConverter<I>
where
I: ExactSizeIterator,
I::Item: Clone,
I: Iterator,
I::Item: Sample,
{
}

Expand All @@ -117,27 +119,34 @@ mod test {
assert_eq!(output, [1, 5]);
}

#[test]
fn mono_to_stereo() {
let input = vec![1i16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 1, 2).collect::<Vec<_>>();
assert_eq!(output, [1, 1, 2, 2, 3, 3, 4, 4]);
}

#[test]
fn add_channels() {
let input = vec![1u16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 2, 3).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 1, 3, 4, 3]);
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![1u16, 2, 3, 4];
let input = vec![1i16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 2, 4).collect::<Vec<_>>();
assert_eq!(output, [1, 2, 1, 2, 3, 4, 3, 4]);
assert_eq!(output, [1, 2, 0, 0, 3, 4, 0, 0]);
}

#[test]
fn len_more() {
let input = vec![1u16, 2, 3, 4];
let input = vec![1i16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 2, 3);
assert_eq!(output.len(), 6);
}

#[test]
fn len_less() {
let input = vec![1u16, 2, 3, 4];
let input = vec![1i16, 2, 3, 4];
let output = ChannelCountConverter::new(input.into_iter(), 2, 1);
assert_eq!(output.len(), 2);
}
Expand Down

0 comments on commit c87da03

Please sign in to comment.