use anyhow::{Result, bail};
use log::info;
use std::ptr;
const MIN_RATE: u32 = 4_000;
const MAX_RATE: u32 = 384_000;
use super::sinc_kernel::{generate_polyphase_bank, generate_polyphase_bank_linear};
mod core;
mod delay_line;
use core::ResamplerCore;
pub use core::ResamplerProgress;
enum PhaseType {
Minimum,
Linear,
}
pub struct NamResampler {
inner: Option<ResamplerCore>,
outer: Option<ResamplerCore>,
host_rate: u32,
nam_rate: u32,
}
impl NamResampler {
#[cold]
fn new_inner(host_rate: u32, nam_rate: u32, phase: PhaseType) -> Result<Self> {
if !(MIN_RATE..=MAX_RATE).contains(&host_rate) || !(MIN_RATE..=MAX_RATE).contains(&nam_rate)
{
bail!(
"NamResampler: sample rates must be in range {}-{}, got host={} nam={}",
MIN_RATE,
MAX_RATE,
host_rate,
nam_rate
);
}
if host_rate == nam_rate {
let label = match phase {
PhaseType::Minimum => "Bypass",
PhaseType::Linear => "Linear-phase bypass",
};
info!(
"[Resampler] {label}: host_rate={}, nam_rate={} (match)",
host_rate, nam_rate
);
return Ok(Self {
inner: None,
outer: None,
host_rate,
nam_rate,
});
}
let gen_bank = match phase {
PhaseType::Minimum => generate_polyphase_bank,
PhaseType::Linear => generate_polyphase_bank_linear,
};
let inner = ResamplerCore::new(
host_rate,
nam_rate,
gen_bank(host_rate, nam_rate).map_err(|e| anyhow::anyhow!("{e}"))?,
)?;
let outer = ResamplerCore::new(
nam_rate,
host_rate,
gen_bank(nam_rate, host_rate).map_err(|e| anyhow::anyhow!("{e}"))?,
)?;
let label = match phase {
PhaseType::Minimum => "Minimum-phase",
PhaseType::Linear => "Linear-phase",
};
info!(
"[Resampler] {label} resampler built: host_rate={}, nam_rate={}",
host_rate, nam_rate
);
Ok(Self {
inner: Some(inner),
outer: Some(outer),
host_rate,
nam_rate,
})
}
#[cold]
pub fn new(host_rate: u32, nam_rate: u32, _chunk_size: usize) -> Result<Self> {
Self::new_inner(host_rate, nam_rate, PhaseType::Minimum)
}
#[cold]
pub fn new_linear(host_rate: u32, nam_rate: u32, _chunk_size: usize) -> Result<Self> {
Self::new_inner(host_rate, nam_rate, PhaseType::Linear)
}
#[inline]
pub fn is_bypass(&self) -> bool {
self.inner.is_none()
}
#[inline]
pub fn host_rate(&self) -> u32 {
self.host_rate
}
#[inline]
pub fn nam_rate(&self) -> u32 {
self.nam_rate
}
pub fn latency_samples(&self, _host_rate: u32) -> u32 {
if self.is_bypass() {
return 0;
}
let delay_in = match self.inner {
Some(ref core) => core.group_delay(),
None => 0.0,
};
let delay_out = match self.outer {
Some(ref core) => core.group_delay() * (self.host_rate as f64 / self.nam_rate as f64),
None => 0.0,
};
(delay_in + delay_out).round() as u32
}
#[inline]
pub fn min_output_samples(input_samples: usize, in_rate: u32, out_rate: u32) -> usize {
let numer = if let Some(v) = (input_samples as u64).checked_mul(out_rate as u64) {
v
} else {
return usize::MAX;
};
let denom = in_rate as u64;
let min = numer.div_ceil(denom);
if min > usize::MAX as u64 {
usize::MAX
} else {
min as usize
}
}
#[inline]
pub fn max_input_samples(output_capacity: usize, in_rate: u32, out_rate: u32) -> usize {
let numer = if let Some(v) = (output_capacity as u64).checked_mul(in_rate as u64) {
v
} else {
return usize::MAX;
};
let denom = out_rate as u64;
let max = numer / denom;
if max > usize::MAX as u64 {
usize::MAX
} else {
max as usize
}
}
pub fn process_input(
&mut self,
in_l: &[f32],
in_r: &[f32],
out_l: &mut [f32],
out_r: &mut [f32],
) -> ResamplerProgress {
let Some(ref mut core) = self.inner else {
let n = in_l.len().min(in_r.len()).min(out_l.len()).min(out_r.len());
unsafe {
ptr::copy_nonoverlapping(in_l.as_ptr(), out_l.as_mut_ptr(), n);
ptr::copy_nonoverlapping(in_r.as_ptr(), out_r.as_mut_ptr(), n);
}
return ResamplerProgress {
samples_read: n,
samples_written: n,
};
};
core.process_static_stereo(in_l, in_r, out_l, out_r)
}
pub fn process_output(
&mut self,
in_l: &[f32],
in_r: &[f32],
out_l: &mut [f32],
out_r: &mut [f32],
) -> ResamplerProgress {
let Some(ref mut core) = self.outer else {
let n = in_l.len().min(in_r.len()).min(out_l.len()).min(out_r.len());
unsafe {
ptr::copy_nonoverlapping(in_l.as_ptr(), out_l.as_mut_ptr(), n);
ptr::copy_nonoverlapping(in_r.as_ptr(), out_r.as_mut_ptr(), n);
}
return ResamplerProgress {
samples_read: n,
samples_written: n,
};
};
core.process_static_stereo(in_l, in_r, out_l, out_r)
}
pub fn process_input_mono(
&mut self,
in_l: &[f32],
out_l: &mut [f32],
out_r: &mut [f32],
) -> ResamplerProgress {
let Some(ref mut core) = self.inner else {
let n = in_l.len().min(out_l.len()).min(out_r.len());
unsafe {
ptr::copy_nonoverlapping(in_l.as_ptr(), out_l.as_mut_ptr(), n);
ptr::copy_nonoverlapping(in_l.as_ptr(), out_r.as_mut_ptr(), n);
}
return ResamplerProgress {
samples_read: n,
samples_written: n,
};
};
core.process_static_mono(in_l, out_l, out_r)
}
pub fn process_output_mono(
&mut self,
in_l: &[f32],
out_l: &mut [f32],
out_r: &mut [f32],
) -> ResamplerProgress {
let Some(ref mut core) = self.outer else {
let n = in_l.len().min(out_l.len()).min(out_r.len());
unsafe {
ptr::copy_nonoverlapping(in_l.as_ptr(), out_l.as_mut_ptr(), n);
ptr::copy_nonoverlapping(in_l.as_ptr(), out_r.as_mut_ptr(), n);
}
return ResamplerProgress {
samples_read: n,
samples_written: n,
};
};
core.process_static_mono(in_l, out_l, out_r)
}
}
#[cfg(test)]
#[path = "../resampler_test.rs"]
mod resampler_test;