use audioadapter_buffers::direct;
use audioadapter_buffers::owned::{InterleavedOwned, SequentialOwned};
use rubato::{
audioadapter::{Adapter, AdapterMut},
ResampleResult, Resampler, Sample,
};
use std::ops::Range;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ResampleQuality {
VeryLow,
Low,
#[default]
High,
HighWithLowLatency,
}
impl From<usize> for ResampleQuality {
fn from(value: usize) -> Self {
match value {
0 => Self::VeryLow,
1 => Self::Low,
2 => Self::High,
_ => Self::HighWithLowLatency,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ResamplerConfig {
pub quality: ResampleQuality,
pub chunk_size: usize,
pub sub_chunks: usize,
}
impl Default for ResamplerConfig {
fn default() -> Self {
Self {
quality: ResampleQuality::default(),
chunk_size: 512,
sub_chunks: 1,
}
}
}
pub fn resampler_from_quality<T: Sample>(
num_channels: usize,
in_sample_rate: u32,
out_sample_rate: u32,
config: ResamplerConfig,
) -> Box<dyn Resampler<T>> {
assert_ne!(num_channels, 0);
assert_ne!(in_sample_rate, 0);
assert_ne!(out_sample_rate, 0);
assert_ne!(config.chunk_size, 0);
assert_ne!(config.sub_chunks, 0);
let low = || -> Box<dyn rubato::Resampler<T>> {
Box::new(
rubato::Async::new_poly(
out_sample_rate as f64 / in_sample_rate as f64,
1.0,
rubato::PolynomialDegree::Cubic,
config.chunk_size,
num_channels,
rubato::FixedAsync::Input,
)
.unwrap(),
)
};
match config.quality {
ResampleQuality::VeryLow => Box::new(
rubato::Async::new_poly(
out_sample_rate as f64 / in_sample_rate as f64,
1.0,
rubato::PolynomialDegree::Linear,
config.chunk_size,
num_channels,
rubato::FixedAsync::Input,
)
.unwrap(),
),
ResampleQuality::Low => low(),
ResampleQuality::High => {
#[cfg(feature = "fft-resampler")]
return Box::new(
rubato::Fft::new(
in_sample_rate as usize,
out_sample_rate as usize,
config.chunk_size,
config.sub_chunks,
num_channels,
rubato::FixedSync::Input,
)
.unwrap(),
);
#[cfg(not(feature = "fft-resampler"))]
return low();
}
ResampleQuality::HighWithLowLatency => {
const SINC_LEN: usize = 128;
const WINDOW_FUNC: rubato::WindowFunction = rubato::WindowFunction::Blackman2;
Box::new(
rubato::Async::new_sinc(
out_sample_rate as f64 / in_sample_rate as f64,
1.0,
&rubato::SincInterpolationParameters {
sinc_len: SINC_LEN,
f_cutoff: rubato::calculate_cutoff(SINC_LEN, WINDOW_FUNC),
oversampling_factor: 256,
interpolation: rubato::SincInterpolationType::Quadratic,
window: WINDOW_FUNC,
},
config.chunk_size,
num_channels,
rubato::FixedAsync::Input,
)
.unwrap(),
)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
enum ResampleRatio {
IntegerSampleRate {
in_sample_rate: u32,
out_sample_rate: u32,
},
Float(f64),
}
pub struct PacketResampler<T: Sample, B: PacketResamplerBuffer<T>> {
resampler: Box<dyn Resampler<T>>,
ratio: ResampleRatio,
num_channels: usize,
buffer: B,
active_channels_mask: Option<Vec<bool>>,
in_buf_len: usize,
delay_frames_left: usize,
}
impl<T: Sample, B: PacketResamplerBuffer<T>> PacketResampler<T, B> {
pub fn new(
num_channels: usize,
in_sample_rate: u32,
out_sample_rate: u32,
config: ResamplerConfig,
) -> Self {
let resampler =
resampler_from_quality(num_channels, in_sample_rate, out_sample_rate, config);
Self::new_inner(resampler, Some((in_sample_rate, out_sample_rate)))
}
pub fn from_custom(resampler: Box<dyn Resampler<T>>) -> Self {
Self::new_inner(resampler, None)
}
fn new_inner(resampler: Box<dyn Resampler<T>>, sr: Option<(u32, u32)>) -> Self {
let ratio = if let Some((in_sample_rate, out_sample_rate)) = sr {
ResampleRatio::IntegerSampleRate {
in_sample_rate,
out_sample_rate,
}
} else {
ResampleRatio::Float(resampler.resample_ratio())
};
let num_channels = resampler.nbr_channels();
let input_frames_max = resampler.input_frames_max();
let output_frames_max = resampler.output_frames_max();
Self {
resampler,
ratio,
num_channels,
buffer: B::new(num_channels, input_frames_max, output_frames_max),
active_channels_mask: Some(vec![false; num_channels]),
in_buf_len: 0,
delay_frames_left: 0,
}
}
pub fn nbr_channels(&self) -> usize {
self.num_channels
}
pub fn ratio(&self) -> f64 {
self.resampler.resample_ratio()
}
pub fn max_input_block_frames(&self) -> usize {
self.resampler.input_frames_max()
}
pub fn max_output_block_frames(&self) -> usize {
self.resampler.output_frames_max()
}
pub fn output_delay(&self) -> usize {
self.resampler.output_delay()
}
pub fn out_alloc_frames(&self, input_frames: u64) -> u64 {
match self.ratio {
ResampleRatio::IntegerSampleRate {
in_sample_rate,
out_sample_rate,
} => ((input_frames * out_sample_rate as u64) / in_sample_rate as u64) + 1,
ResampleRatio::Float(ratio) => (input_frames as f64 * ratio).ceil() as u64,
}
}
#[allow(unused)]
pub(crate) fn tmp_input_frames(&self) -> usize {
self.in_buf_len
}
pub fn process(
&mut self,
buffer_in: &dyn Adapter<'_, T>,
input_range: Option<Range<usize>>,
active_channels_mask: Option<&[bool]>,
mut on_output_packet: impl FnMut(&B::Output, usize),
last_packet: Option<LastPacketInfo>,
trim_delay: bool,
) {
let (input_start, total_frames) = if let Some(range) = input_range {
(range.start, range.end - range.start)
} else {
(0, buffer_in.frames())
};
let use_indexing =
active_channels_mask.is_some() || buffer_in.channels() < self.num_channels;
let indexing = if use_indexing {
let mut m = self.active_channels_mask.take().unwrap();
if let Some(in_mask) = active_channels_mask {
for (in_mask, out_mask) in in_mask.iter().zip(m.iter_mut()) {
*out_mask = *in_mask;
}
} else {
for mask in m.iter_mut().take(buffer_in.channels()) {
*mask = true;
}
}
for mask in m.iter_mut().skip(buffer_in.channels()) {
*mask = false;
}
Some(rubato::Indexing {
input_offset: 0,
output_offset: 0,
partial_len: None,
active_channels_mask: Some(m),
})
} else {
None
};
let mut output_frames_processed: u64 = 0;
let mut frames_left = total_frames;
while frames_left > 0 {
let needed_input_frames = self.resampler.input_frames_next();
if self.in_buf_len < needed_input_frames {
let block_frames_to_copy = frames_left.min(needed_input_frames - self.in_buf_len);
for ch_i in 0..self.num_channels {
let channel_active = ch_i < buffer_in.channels()
&& active_channels_mask
.as_ref()
.map(|m| m.get(ch_i).copied().unwrap_or(false))
.unwrap_or(true);
if channel_active {
self.buffer.copy_from_other_to_input_channel(
buffer_in,
ch_i,
ch_i,
input_start + (total_frames - frames_left),
self.in_buf_len,
block_frames_to_copy,
);
}
}
self.in_buf_len += block_frames_to_copy;
frames_left -= block_frames_to_copy;
}
if self.in_buf_len >= needed_input_frames {
self.in_buf_len = 0;
let (_, mut output_frames) = self
.buffer
.resample(indexing.as_ref(), &mut self.resampler)
.unwrap();
if self.delay_frames_left > 0 {
if self.delay_frames_left >= output_frames {
self.delay_frames_left -= output_frames;
if trim_delay {
continue;
}
} else if trim_delay {
self.buffer.output_copy_frames_within(
self.delay_frames_left,
0,
output_frames,
);
output_frames -= self.delay_frames_left;
self.delay_frames_left = 0;
} else {
self.delay_frames_left = 0;
}
}
output_frames_processed += output_frames as u64;
(on_output_packet)(self.buffer.output(output_frames), output_frames);
}
}
if let Some(info) = &last_packet {
if self.in_buf_len > 0 {
self.buffer.input_fill_frames_with(
self.in_buf_len,
self.resampler.input_frames_max(),
&T::zero(),
);
} else {
self.buffer.input_fill_with(&T::zero());
};
let desired_output_frames = info.desired_output_frames.unwrap_or_else(|| {
output_frames_processed + self.resampler.output_delay() as u64 + 1
});
while output_frames_processed < desired_output_frames {
let (_, mut output_frames) = self
.buffer
.resample(indexing.as_ref(), &mut self.resampler)
.unwrap();
if self.in_buf_len > 0 {
self.buffer.input_fill_with(&T::zero());
self.in_buf_len = 0;
}
if self.delay_frames_left > 0 {
if self.delay_frames_left >= output_frames {
self.delay_frames_left -= output_frames;
if trim_delay {
continue;
}
} else if trim_delay {
self.buffer.output_copy_frames_within(
self.delay_frames_left,
0,
output_frames,
);
output_frames -= self.delay_frames_left;
self.delay_frames_left = 0;
} else {
self.delay_frames_left = 0;
}
}
output_frames =
output_frames.min((desired_output_frames - output_frames_processed) as usize);
output_frames_processed += output_frames as u64;
(on_output_packet)(self.buffer.output(output_frames), output_frames);
}
self.reset();
}
if let Some(i) = indexing {
self.active_channels_mask = i.active_channels_mask;
}
}
pub fn output_delay_frames_left(&self) -> usize {
self.delay_frames_left
}
pub fn reset(&mut self) {
self.resampler.reset();
self.in_buf_len = 0;
self.delay_frames_left = self.resampler.output_delay();
}
pub fn into_inner(self) -> Box<dyn Resampler<T>> {
self.resampler
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LastPacketInfo {
pub desired_output_frames: Option<u64>,
}
pub trait PacketResamplerBuffer<T: Sample> {
type Output: ?Sized;
fn new(channels: usize, input_frames: usize, output_frames: usize) -> Self;
fn output(&self, frames: usize) -> &Self::Output;
fn resample(
&mut self,
indexing: Option<&rubato::Indexing>,
resampler: &mut Box<dyn Resampler<T>>,
) -> ResampleResult<(usize, usize)>;
fn copy_from_other_to_input_channel(
&mut self,
other: &dyn Adapter<'_, T>,
other_channel: usize,
self_channel: usize,
other_skip: usize,
self_skip: usize,
take: usize,
) -> Option<usize>;
fn input_fill_frames_with(&mut self, start: usize, count: usize, value: &T) -> Option<usize>;
fn input_fill_with(&mut self, value: &T);
fn output_copy_frames_within(&mut self, src: usize, dest: usize, count: usize);
}
pub struct Sequential<T: Sample> {
in_buffer: SequentialOwned<T>,
out_buffer: SequentialOwned<T>,
}
impl<T: Sample> PacketResamplerBuffer<T> for Sequential<T> {
type Output = SequentialOwned<T>;
fn new(channels: usize, input_frames: usize, output_frames: usize) -> Self {
Self {
in_buffer: SequentialOwned::new(T::zero(), channels, input_frames),
out_buffer: SequentialOwned::new(T::zero(), channels, output_frames),
}
}
fn output(&self, _frames: usize) -> &Self::Output {
&self.out_buffer
}
fn resample(
&mut self,
indexing: Option<&rubato::Indexing>,
resampler: &mut Box<dyn Resampler<T>>,
) -> ResampleResult<(usize, usize)> {
resampler.process_into_buffer(&self.in_buffer, &mut self.out_buffer, indexing)
}
fn copy_from_other_to_input_channel(
&mut self,
other: &dyn Adapter<'_, T>,
other_channel: usize,
self_channel: usize,
other_skip: usize,
self_skip: usize,
take: usize,
) -> Option<usize> {
self.in_buffer.copy_from_other_to_channel(
other,
other_channel,
self_channel,
other_skip,
self_skip,
take,
)
}
fn input_fill_frames_with(&mut self, start: usize, count: usize, value: &T) -> Option<usize> {
self.in_buffer.fill_frames_with(start, count, value)
}
fn input_fill_with(&mut self, value: &T) {
self.in_buffer.fill_with(value);
}
fn output_copy_frames_within(&mut self, src: usize, dest: usize, count: usize) {
self.out_buffer.copy_frames_within(src, dest, count);
}
}
pub struct Interleaved<T: Sample> {
in_buffer: InterleavedOwned<T>,
out_buffer: Vec<T>,
channels: usize,
output_frames: usize,
}
impl<T: Sample> PacketResamplerBuffer<T> for Interleaved<T> {
type Output = [T];
fn new(channels: usize, input_frames: usize, output_frames: usize) -> Self {
let out_buffer_size = output_frames * channels;
let mut out_buffer = Vec::new();
out_buffer.reserve_exact(out_buffer_size);
out_buffer.resize(out_buffer_size, T::zero());
Self {
in_buffer: InterleavedOwned::new(T::zero(), channels, input_frames),
out_buffer,
channels,
output_frames,
}
}
fn output(&self, frames: usize) -> &Self::Output {
&self.out_buffer[0..frames * self.channels]
}
fn resample(
&mut self,
indexing: Option<&rubato::Indexing>,
resampler: &mut Box<dyn Resampler<T>>,
) -> ResampleResult<(usize, usize)> {
let mut out_buffer_wrapper = direct::InterleavedSlice::new_mut(
&mut self.out_buffer,
self.channels,
self.output_frames,
)
.unwrap();
resampler.process_into_buffer(&self.in_buffer, &mut out_buffer_wrapper, indexing)
}
fn copy_from_other_to_input_channel(
&mut self,
other: &dyn Adapter<'_, T>,
other_channel: usize,
self_channel: usize,
other_skip: usize,
self_skip: usize,
take: usize,
) -> Option<usize> {
self.in_buffer.copy_from_other_to_channel(
other,
other_channel,
self_channel,
other_skip,
self_skip,
take,
)
}
fn input_fill_frames_with(&mut self, start: usize, count: usize, value: &T) -> Option<usize> {
self.in_buffer.fill_frames_with(start, count, value)
}
fn input_fill_with(&mut self, value: &T) {
self.in_buffer.fill_with(value);
}
fn output_copy_frames_within(&mut self, src: usize, dest: usize, count: usize) {
self.out_buffer.copy_within(src..count, dest);
}
}
pub fn extend_from_adapter_channel<T: Sample>(
out_buffer: &mut Vec<T>,
buffer_in: &dyn Adapter<'_, T>,
buffer_in_skip: usize,
buffer_in_channel: usize,
frames: usize,
) -> usize {
assert!(buffer_in_channel < buffer_in.channels());
let out_buffer_len = out_buffer.len();
let available = out_buffer.capacity() - out_buffer_len;
if available < frames {
out_buffer.reserve(frames);
}
unsafe {
out_buffer.set_len(out_buffer_len + frames);
}
let frames_copied = buffer_in.copy_from_channel_to_slice(
buffer_in_channel,
buffer_in_skip,
&mut out_buffer[out_buffer_len..],
);
if frames_copied < frames {
unsafe {
out_buffer.set_len(out_buffer_len + frames_copied);
}
}
frames_copied
}