use crate::audio_util;
use crate::push_sinc_resampler::PushSincResampler;
const MAX_NUMBER_OF_CHANNELS: usize = 8;
pub trait Sample: Copy + Default + 'static {
fn resample_channel(
resampler: &mut PushSincResampler,
source: &[Self],
destination: &mut [Self],
) -> usize;
}
impl Sample for f32 {
fn resample_channel(
resampler: &mut PushSincResampler,
source: &[Self],
destination: &mut [Self],
) -> usize {
resampler.resample(source, destination)
}
}
impl Sample for i16 {
fn resample_channel(
resampler: &mut PushSincResampler,
source: &[Self],
destination: &mut [Self],
) -> usize {
resampler.resample_i16(source, destination)
}
}
#[derive(Debug)]
pub struct PushResampler<T: Sample> {
resamplers: Vec<PushSincResampler>,
source_buf: Vec<T>,
dest_buf: Vec<T>,
src_samples_per_channel: usize,
dst_samples_per_channel: usize,
num_channels: usize,
}
impl<T: Sample> PushResampler<T> {
pub fn new(
src_samples_per_channel: usize,
dst_samples_per_channel: usize,
num_channels: usize,
) -> Self {
assert!(src_samples_per_channel > 0);
assert!(dst_samples_per_channel > 0);
assert!(num_channels > 0);
assert!(
num_channels <= MAX_NUMBER_OF_CHANNELS,
"max {MAX_NUMBER_OF_CHANNELS} channels supported"
);
assert!(
src_samples_per_channel <= audio_util::MAX_SAMPLES_PER_CHANNEL_10MS,
"source frames exceed maximum"
);
assert!(
dst_samples_per_channel <= audio_util::MAX_SAMPLES_PER_CHANNEL_10MS,
"destination frames exceed maximum"
);
let resamplers = (0..num_channels)
.map(|_| PushSincResampler::new(src_samples_per_channel, dst_samples_per_channel))
.collect();
Self {
resamplers,
source_buf: vec![T::default(); src_samples_per_channel * num_channels],
dest_buf: vec![T::default(); dst_samples_per_channel * num_channels],
src_samples_per_channel,
dst_samples_per_channel,
num_channels,
}
}
pub fn resample(&mut self, src: &[T], dst: &mut [T]) {
let expected_src_len = self.src_samples_per_channel * self.num_channels;
let expected_dst_len = self.dst_samples_per_channel * self.num_channels;
assert_eq!(
src.len(),
expected_src_len,
"source length must be {} (got {})",
expected_src_len,
src.len()
);
assert!(
dst.len() >= expected_dst_len,
"destination length must be at least {} (got {})",
expected_dst_len,
dst.len()
);
if self.src_samples_per_channel == self.dst_samples_per_channel {
dst[..expected_dst_len].copy_from_slice(&src[..expected_src_len]);
return;
}
if self.num_channels == 1 {
T::resample_channel(&mut self.resamplers[0], src, dst);
return;
}
deinterleave_to_planar(
src,
&mut self.source_buf,
self.src_samples_per_channel,
self.num_channels,
);
for ch in 0..self.num_channels {
let src_start = ch * self.src_samples_per_channel;
let src_end = src_start + self.src_samples_per_channel;
let dst_start = ch * self.dst_samples_per_channel;
let dst_end = dst_start + self.dst_samples_per_channel;
let src_slice = &self.source_buf[src_start..src_end];
let n = T::resample_channel(
&mut self.resamplers[ch],
src_slice,
&mut self.dest_buf[dst_start..dst_end],
);
debug_assert_eq!(n, self.dst_samples_per_channel);
}
interleave_from_planar(
&self.dest_buf,
dst,
self.dst_samples_per_channel,
self.num_channels,
);
}
pub fn resample_mono(&mut self, src: &[T], dst: &mut [T]) {
assert_eq!(self.num_channels, 1, "resample_mono requires 1 channel");
assert_eq!(src.len(), self.src_samples_per_channel);
assert!(dst.len() >= self.dst_samples_per_channel);
if self.src_samples_per_channel == self.dst_samples_per_channel {
dst[..self.dst_samples_per_channel]
.copy_from_slice(&src[..self.src_samples_per_channel]);
} else {
T::resample_channel(&mut self.resamplers[0], src, dst);
}
}
}
fn deinterleave_to_planar<T: Copy>(
interleaved: &[T],
planar: &mut [T],
frames_per_channel: usize,
num_channels: usize,
) {
for ch in 0..num_channels {
let dst_start = ch * frames_per_channel;
for frame in 0..frames_per_channel {
planar[dst_start + frame] = interleaved[frame * num_channels + ch];
}
}
}
fn interleave_from_planar<T: Copy>(
planar: &[T],
interleaved: &mut [T],
frames_per_channel: usize,
num_channels: usize,
) {
for ch in 0..num_channels {
let src_start = ch * frames_per_channel;
for frame in 0..frames_per_channel {
interleaved[frame * num_channels + ch] = planar[src_start + frame];
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mono_identity() {
let frames = 480;
let mut r = PushResampler::<f32>::new(frames, frames, 1);
let input: Vec<f32> = (0..frames).map(|i| i as f32 * 0.001).collect();
let mut output = vec![0.0_f32; frames];
r.resample(&input, &mut output);
assert_eq!(&input, &output);
}
#[test]
fn stereo_identity() {
let frames = 480;
let mut r = PushResampler::<f32>::new(frames, frames, 2);
let input: Vec<f32> = (0..frames * 2).map(|i| i as f32 * 0.001).collect();
let mut output = vec![0.0_f32; frames * 2];
r.resample(&input, &mut output);
assert_eq!(&input, &output);
}
#[test]
fn mono_downsample() {
let mut r = PushResampler::<f32>::new(480, 160, 1);
let input: Vec<f32> = (0..480).map(|i| (i as f32 * 0.02).sin()).collect();
let mut output = vec![0.0_f32; 160];
for _ in 0..3 {
r.resample(&input, &mut output);
}
let energy: f32 = output.iter().map(|v| v * v).sum();
assert!(energy > 0.01, "output should have signal energy");
}
#[test]
fn stereo_downsample() {
let mut r = PushResampler::<f32>::new(480, 160, 2);
let input: Vec<f32> = (0..480)
.flat_map(|i| {
let t = i as f32 * 0.02;
[t.sin(), t.cos()]
})
.collect();
let mut output = vec![0.0_f32; 160 * 2];
for _ in 0..3 {
r.resample(&input, &mut output);
}
let energy: f32 = output.iter().map(|v| v * v).sum();
assert!(energy > 0.01, "stereo output should have signal energy");
}
#[test]
fn i16_mono_downsample() {
let mut r = PushResampler::<i16>::new(480, 160, 1);
let input: Vec<i16> = (0..480)
.map(|i| (5000.0 * (i as f32 * 0.02).sin()) as i16)
.collect();
let mut output = vec![0_i16; 160];
for _ in 0..3 {
r.resample(&input, &mut output);
}
let has_signal = output.iter().any(|&v| v.unsigned_abs() > 10);
assert!(has_signal, "i16 output should have signal");
}
#[test]
fn mono_upsample() {
let mut r = PushResampler::<f32>::new(160, 480, 1);
let input: Vec<f32> = (0..160).map(|i| (i as f32 * 0.05).sin()).collect();
let mut output = vec![0.0_f32; 480];
for _ in 0..3 {
r.resample(&input, &mut output);
}
let energy: f32 = output.iter().map(|v| v * v).sum();
assert!(energy > 0.01, "upsampled output should have signal energy");
}
#[test]
fn resample_mono_api() {
let mut r = PushResampler::<f32>::new(480, 160, 1);
let input: Vec<f32> = (0..480).map(|i| (i as f32 * 0.02).sin()).collect();
let mut output = vec![0.0_f32; 160];
for _ in 0..3 {
r.resample_mono(&input, &mut output);
}
let energy: f32 = output.iter().map(|v| v * v).sum();
assert!(energy > 0.01);
}
#[test]
fn deinterleave_interleave_roundtrip() {
let frames = 4;
let channels = 3;
let interleaved: Vec<f32> = (0..frames * channels).map(|i| i as f32).collect();
let mut planar = vec![0.0_f32; frames * channels];
let mut result = vec![0.0_f32; frames * channels];
deinterleave_to_planar(&interleaved, &mut planar, frames, channels);
assert_eq!(&planar[0..4], &[0.0, 3.0, 6.0, 9.0]);
assert_eq!(&planar[4..8], &[1.0, 4.0, 7.0, 10.0]);
assert_eq!(&planar[8..12], &[2.0, 5.0, 8.0, 11.0]);
interleave_from_planar(&planar, &mut result, frames, channels);
assert_eq!(&interleaved, &result);
}
}