use std::{
marker::PhantomData,
num::{NonZeroU32, NonZeroUsize},
str::FromStr,
sync::Arc,
};
use rubato::{
Async, FixedAsync, Indexing, Resampler, SincInterpolationParameters, SincInterpolationType,
WindowFunction, audioadapter_buffers::direct::SequentialSliceOfVecs,
};
use crate::{
errors::{Error, PcmError, Result},
media::{DecodedFrame, FrameRaw},
};
const SINC_FILTER_LEN: usize = 256;
const SINC_OVERSAMPLING_FACTOR: usize = 256;
const SINC_CUTOFF: f32 = 0.95;
const SINC_MAX_RELATIVE_RATIO: f64 = 1.0;
const SOURCE_BUFFER_COMPACT_FRAMES: usize = 32_768;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PcmEncoding {
F32Le,
S16Le,
MuLaw,
ALaw,
}
impl PcmEncoding {
pub fn parse(value: &str) -> Result<Self> {
value.parse().map_err(Error::from)
}
pub const fn as_str(self) -> &'static str {
match self {
Self::F32Le => "pcm_f32le",
Self::S16Le => "pcm_s16le",
Self::MuLaw => "pcm_mulaw",
Self::ALaw => "pcm_alaw",
}
}
pub const fn sample_encoding_name(self) -> &'static str {
match self {
Self::F32Le => F32Le::NAME,
Self::S16Le => S16Le::NAME,
Self::MuLaw => MuLaw::NAME,
Self::ALaw => ALaw::NAME,
}
}
pub const fn bytes_per_sample(self) -> usize {
match self {
Self::F32Le => 4,
Self::S16Le => 2,
Self::MuLaw | Self::ALaw => 1,
}
}
pub fn append_f32(self, data: &[u8], output: &mut Vec<f32>) -> Result<()> {
match self {
Self::F32Le => Samples::<F32Le>::append_f32(&data, output),
Self::S16Le => Samples::<S16Le>::append_f32(&data, output),
Self::MuLaw => Samples::<MuLaw>::append_f32(&data, output),
Self::ALaw => Samples::<ALaw>::append_f32(&data, output),
}
}
}
impl FromStr for PcmEncoding {
type Err = PcmError;
fn from_str(value: &str) -> std::result::Result<Self, Self::Err> {
match value {
"pcm_f32le" => Ok(Self::F32Le),
"pcm_s16le" => Ok(Self::S16Le),
"pcm_mulaw" => Ok(Self::MuLaw),
"pcm_alaw" => Ok(Self::ALaw),
_ => Err(PcmError::UnsupportedEncoding(value.to_string())),
}
}
}
impl std::fmt::Display for PcmEncoding {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PcmChunk {
sample_rate_hz: NonZeroU32,
channels: NonZeroUsize,
encoding: PcmEncoding,
data: Arc<[u8]>,
}
impl PcmChunk {
pub fn new(
sample_rate_hz: NonZeroU32,
channels: NonZeroUsize,
encoding: PcmEncoding,
data: impl Into<Arc<[u8]>>,
) -> Result<Self> {
let data = data.into();
validate_pcm_bytes(encoding, data.len(), channels.get())?;
Ok(Self {
sample_rate_hz,
channels,
encoding,
data,
})
}
pub fn from_bytes(
sample_rate_hz: u32,
channels: usize,
encoding: PcmEncoding,
data: impl Into<Arc<[u8]>>,
) -> Result<Self> {
Self::new(
NonZeroU32::new(sample_rate_hz).ok_or(PcmError::SampleRateZero)?,
NonZeroUsize::new(channels).ok_or(PcmError::ChannelCountZero)?,
encoding,
data,
)
}
pub fn new_mono(
sample_rate_hz: NonZeroU32,
encoding: PcmEncoding,
data: impl Into<Arc<[u8]>>,
) -> Result<Self> {
Self::new(
sample_rate_hz,
NonZeroUsize::new(1).expect("mono channel count is nonzero"),
encoding,
data,
)
}
pub fn from_mono_bytes(
sample_rate_hz: u32,
encoding: PcmEncoding,
data: impl Into<Arc<[u8]>>,
) -> Result<Self> {
Self::from_bytes(sample_rate_hz, 1, encoding, data)
}
pub const fn sample_rate_hz(&self) -> NonZeroU32 {
self.sample_rate_hz
}
pub const fn channels(&self) -> NonZeroUsize {
self.channels
}
pub const fn encoding(&self) -> PcmEncoding {
self.encoding
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn data_arc(&self) -> Arc<[u8]> {
Arc::clone(&self.data)
}
pub fn into_data(self) -> Arc<[u8]> {
self.data
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn byte_len(&self) -> usize {
self.data.len()
}
pub fn sample_count(&self) -> usize {
self.data.len() / self.encoding.bytes_per_sample()
}
pub fn frame_count(&self) -> usize {
self.sample_count() / self.channels.get()
}
pub fn append_f32(&self, output: &mut Vec<f32>) -> Result<usize> {
let start = output.len();
output.reserve(self.sample_count());
self.encoding.append_f32(&self.data, output)?;
let samples = output.len() - start;
validate_channel_alignment(self.channels.get(), samples)?;
Ok(samples / self.channels.get())
}
}
impl AsRef<[u8]> for PcmChunk {
fn as_ref(&self) -> &[u8] {
self.data()
}
}
pub trait SampleEncoding: Copy + Send + Sync + 'static {
const NAME: &'static str;
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct F32;
impl SampleEncoding for F32 {
const NAME: &'static str = "f32";
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct F32Le;
impl SampleEncoding for F32Le {
const NAME: &'static str = "f32le";
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct S16;
impl SampleEncoding for S16 {
const NAME: &'static str = "s16";
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct S16Le;
impl SampleEncoding for S16Le {
const NAME: &'static str = "s16le";
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct MuLaw;
impl SampleEncoding for MuLaw {
const NAME: &'static str = "mulaw";
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ALaw;
impl SampleEncoding for ALaw {
const NAME: &'static str = "alaw";
}
pub trait Samples<E>
where
E: SampleEncoding,
{
fn sample_count(&self) -> Result<usize>;
fn append_f32(&self, output: &mut Vec<f32>) -> Result<()>;
}
impl<T> Samples<F32> for T
where
T: AsRef<[f32]>,
{
fn sample_count(&self) -> Result<usize> {
Ok(self.as_ref().len())
}
fn append_f32(&self, output: &mut Vec<f32>) -> Result<()> {
let samples = self.as_ref();
output.reserve(samples.len());
output.extend(samples.iter().map(|sample| sample.clamp(-1.0, 1.0)));
Ok(())
}
}
impl<T> Samples<S16> for T
where
T: AsRef<[i16]>,
{
fn sample_count(&self) -> Result<usize> {
Ok(self.as_ref().len())
}
fn append_f32(&self, output: &mut Vec<f32>) -> Result<()> {
let samples = self.as_ref();
output.reserve(samples.len());
output.extend(samples.iter().map(|sample| s16_to_f32(*sample)));
Ok(())
}
}
impl<T> Samples<F32Le> for T
where
T: AsRef<[u8]>,
{
fn sample_count(&self) -> Result<usize> {
checked_byte_sample_count::<F32Le>(self.as_ref().len(), std::mem::size_of::<f32>())
}
fn append_f32(&self, output: &mut Vec<f32>) -> Result<()> {
let bytes = self.as_ref();
let samples = checked_byte_sample_count::<F32Le>(bytes.len(), std::mem::size_of::<f32>())?;
output.reserve(samples);
output.extend(bytes.chunks_exact(4).map(|sample| {
f32::from_le_bytes([sample[0], sample[1], sample[2], sample[3]]).clamp(-1.0, 1.0)
}));
Ok(())
}
}
impl<T> Samples<S16Le> for T
where
T: AsRef<[u8]>,
{
fn sample_count(&self) -> Result<usize> {
checked_byte_sample_count::<S16Le>(self.as_ref().len(), std::mem::size_of::<i16>())
}
fn append_f32(&self, output: &mut Vec<f32>) -> Result<()> {
let bytes = self.as_ref();
let samples = checked_byte_sample_count::<S16Le>(bytes.len(), std::mem::size_of::<i16>())?;
output.reserve(samples);
output.extend(
bytes
.chunks_exact(2)
.map(|sample| s16_to_f32(i16::from_le_bytes([sample[0], sample[1]]))),
);
Ok(())
}
}
impl<T> Samples<MuLaw> for T
where
T: AsRef<[u8]>,
{
fn sample_count(&self) -> Result<usize> {
Ok(self.as_ref().len())
}
fn append_f32(&self, output: &mut Vec<f32>) -> Result<()> {
let samples = self.as_ref();
output.reserve(samples.len());
output.extend(
samples
.iter()
.copied()
.map(|sample| s16_to_f32(decode_mulaw(sample))),
);
Ok(())
}
}
impl<T> Samples<ALaw> for T
where
T: AsRef<[u8]>,
{
fn sample_count(&self) -> Result<usize> {
Ok(self.as_ref().len())
}
fn append_f32(&self, output: &mut Vec<f32>) -> Result<()> {
let samples = self.as_ref();
output.reserve(samples.len());
output.extend(
samples
.iter()
.copied()
.map(|sample| s16_to_f32(decode_alaw(sample))),
);
Ok(())
}
}
pub trait ChannelLayout: Copy + Send + Sync + 'static {
const CHANNELS: usize;
fn append_source_f32<E, S>(samples: &S, output: &mut Vec<f32>) -> Result<usize>
where
E: SampleEncoding,
S: Samples<E> + ?Sized;
fn append_stereo_interleaved_from_source<E, S>(
samples: &S,
output: &mut Vec<f32>,
) -> Result<usize>
where
E: SampleEncoding,
S: Samples<E> + ?Sized;
fn append_stereo_interleaved(samples: &[f32], output: &mut Vec<f32>) -> Result<usize>;
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Mono;
impl ChannelLayout for Mono {
const CHANNELS: usize = 1;
fn append_source_f32<E, S>(samples: &S, output: &mut Vec<f32>) -> Result<usize>
where
E: SampleEncoding,
S: Samples<E> + ?Sized,
{
let start = output.len();
samples.append_f32(output)?;
Ok(output.len() - start)
}
fn append_stereo_interleaved_from_source<E, S>(
samples: &S,
output: &mut Vec<f32>,
) -> Result<usize>
where
E: SampleEncoding,
S: Samples<E> + ?Sized,
{
let start = output.len();
let frames = Self::append_source_f32::<E, _>(samples, output)?;
output.resize(start + frames * 2, 0.0);
for index in (0..frames).rev() {
let sample = output[start + index];
output[start + index * 2] = sample;
output[start + index * 2 + 1] = sample;
}
Ok(frames)
}
fn append_stereo_interleaved(samples: &[f32], output: &mut Vec<f32>) -> Result<usize> {
output.reserve(samples.len() * 2);
for sample in samples {
output.extend_from_slice(&[*sample, *sample]);
}
Ok(samples.len())
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct StereoInterleaved;
impl ChannelLayout for StereoInterleaved {
const CHANNELS: usize = 2;
fn append_source_f32<E, S>(samples: &S, output: &mut Vec<f32>) -> Result<usize>
where
E: SampleEncoding,
S: Samples<E> + ?Sized,
{
let sample_count = samples.sample_count()?;
validate_channel_alignment(Self::CHANNELS, sample_count)?;
samples.append_f32(output)?;
Ok(sample_count / Self::CHANNELS)
}
fn append_stereo_interleaved_from_source<E, S>(
samples: &S,
output: &mut Vec<f32>,
) -> Result<usize>
where
E: SampleEncoding,
S: Samples<E> + ?Sized,
{
Self::append_source_f32::<E, _>(samples, output)
}
fn append_stereo_interleaved(samples: &[f32], output: &mut Vec<f32>) -> Result<usize> {
validate_channel_alignment(Self::CHANNELS, samples.len())?;
output.extend_from_slice(samples);
Ok(samples.len() / Self::CHANNELS)
}
}
pub struct StreamingSincResampler<L>
where
L: ChannelLayout,
{
input_sample_rate_hz: NonZeroU32,
output_sample_rate_hz: NonZeroU32,
ratio: f64,
resampler: Option<Async<f32>>,
buffered_source: Vec<Vec<f32>>,
buffered_source_start: usize,
received_source_frames: usize,
emitted_output_frames: usize,
trim_output_frames: usize,
input_scratch: Vec<Vec<f32>>,
output_scratch: Vec<Vec<f32>>,
_layout: PhantomData<L>,
}
pub type MonoSincResampler = StreamingSincResampler<Mono>;
impl<L> StreamingSincResampler<L>
where
L: ChannelLayout,
{
pub fn from_hz(
input_sample_rate_hz: u32,
output_sample_rate_hz: u32,
chunk_frames: usize,
) -> Result<Self> {
Self::new(
NonZeroU32::new(input_sample_rate_hz).ok_or(PcmError::SampleRateZero)?,
NonZeroU32::new(output_sample_rate_hz).ok_or(PcmError::SampleRateZero)?,
chunk_frames,
)
}
pub fn new(
input_sample_rate_hz: NonZeroU32,
output_sample_rate_hz: NonZeroU32,
chunk_frames: usize,
) -> Result<Self> {
if L::CHANNELS == 0 {
return Err(PcmError::ChannelCountZero.into());
}
if chunk_frames == 0 {
return Err(PcmError::ResamplerChunkFramesZero.into());
}
let ratio = f64::from(output_sample_rate_hz.get()) / f64::from(input_sample_rate_hz.get());
let resampler = if input_sample_rate_hz == output_sample_rate_hz {
None
} else {
Some(high_quality_sinc_resampler(
input_sample_rate_hz,
output_sample_rate_hz,
chunk_frames,
L::CHANNELS,
)?)
};
let trim_output_frames = resampler
.as_ref()
.map(Resampler::output_delay)
.unwrap_or_default();
Ok(Self {
input_sample_rate_hz,
output_sample_rate_hz,
ratio,
resampler,
buffered_source: vec![Vec::new(); L::CHANNELS],
buffered_source_start: 0,
received_source_frames: 0,
emitted_output_frames: 0,
trim_output_frames,
input_scratch: vec![Vec::new(); L::CHANNELS],
output_scratch: vec![Vec::new(); L::CHANNELS],
_layout: PhantomData,
})
}
pub fn resampling_required(&self) -> bool {
self.input_sample_rate_hz != self.output_sample_rate_hz
}
pub const fn input_sample_rate_hz(&self) -> NonZeroU32 {
self.input_sample_rate_hz
}
pub const fn output_sample_rate_hz(&self) -> NonZeroU32 {
self.output_sample_rate_hz
}
pub fn push(&mut self, samples: &[f32]) -> Result<Vec<f32>> {
let mut output = Vec::new();
self.push_into(samples, &mut output)?;
Ok(output)
}
pub fn push_into(&mut self, samples: &[f32], output: &mut Vec<f32>) -> Result<()> {
let frames = self.validate_source_samples(samples)?;
self.received_source_frames += frames;
if !self.resampling_required() {
self.emitted_output_frames += frames;
output.extend_from_slice(samples);
return Ok(());
}
self.append_buffered_source(samples);
self.process_available(None, output)
}
pub fn finish(&mut self) -> Result<Vec<f32>> {
let mut output = Vec::new();
self.finish_into(&mut output)?;
Ok(output)
}
pub fn finish_into(&mut self, output: &mut Vec<f32>) -> Result<()> {
if !self.resampling_required() {
return Ok(());
}
let expected_output_frames =
(self.ratio * self.received_source_frames as f64).ceil() as usize;
self.process_available(Some(expected_output_frames), output)
}
fn validate_source_samples(&self, samples: &[f32]) -> Result<usize> {
validate_channel_alignment(L::CHANNELS, samples.len())?;
Ok(samples.len() / L::CHANNELS)
}
fn append_buffered_source(&mut self, samples: &[f32]) {
self.compact_buffered_source();
for frame in samples.chunks_exact(L::CHANNELS) {
for (channel, sample) in frame.iter().enumerate() {
self.buffered_source[channel].push(*sample);
}
}
}
fn buffered_source_frames(&self) -> usize {
self.buffered_source
.first()
.map(|samples| samples.len().saturating_sub(self.buffered_source_start))
.unwrap_or_default()
}
fn compact_buffered_source(&mut self) {
if self.buffered_source_start == 0 {
return;
}
if self.buffered_source_frames() == 0 {
for samples in &mut self.buffered_source {
samples.clear();
}
self.buffered_source_start = 0;
return;
}
if self.buffered_source_start < SOURCE_BUFFER_COMPACT_FRAMES {
return;
}
for samples in &mut self.buffered_source {
let keep = samples.len() - self.buffered_source_start;
samples.copy_within(self.buffered_source_start.., 0);
samples.truncate(keep);
}
self.buffered_source_start = 0;
}
fn process_available(
&mut self,
expected_output_frames: Option<usize>,
output: &mut Vec<f32>,
) -> Result<()> {
while self.buffered_source_frames() >= self.resampler()?.input_frames_next() {
self.process_next_chunk(None, expected_output_frames, output)?;
if self.reached_expected_output(expected_output_frames) {
return Ok(());
}
}
if let Some(expected_output_frames) = expected_output_frames {
let buffered_frames = self.buffered_source_frames();
if buffered_frames > 0 {
self.process_next_chunk(
Some(buffered_frames),
Some(expected_output_frames),
output,
)?;
}
while self.emitted_output_frames < expected_output_frames {
self.process_next_chunk(Some(0), Some(expected_output_frames), output)?;
}
}
Ok(())
}
fn process_next_chunk(
&mut self,
partial_len: Option<usize>,
expected_output_frames: Option<usize>,
output: &mut Vec<f32>,
) -> Result<()> {
let input_frames = self.resampler()?.input_frames_next();
let output_frames = self.resampler()?.output_frames_next();
let valid_input = partial_len.unwrap_or(input_frames);
resize_channels(&mut self.input_scratch, input_frames);
for (channel, samples) in self.input_scratch.iter_mut().enumerate() {
if valid_input < input_frames {
samples[valid_input..].fill(0.0);
}
if valid_input > 0 {
let start = self.buffered_source_start;
samples[..valid_input]
.copy_from_slice(&self.buffered_source[channel][start..start + valid_input]);
}
}
resize_channels(&mut self.output_scratch, output_frames);
let indexing = partial_len.map(|partial_len| Indexing {
input_offset: 0,
output_offset: 0,
partial_len: Some(partial_len),
active_channels_mask: None,
});
let (consumed, written) = {
let input = SequentialSliceOfVecs::new(&self.input_scratch, L::CHANNELS, input_frames)
.map_err(pcm_resampler_error)?;
let mut resampled = SequentialSliceOfVecs::new_mut(
&mut self.output_scratch,
L::CHANNELS,
output_frames,
)
.map_err(pcm_resampler_error)?;
self.resampler
.as_mut()
.ok_or(PcmError::ResamplerNotInitialized)?
.process_into_buffer(&input, &mut resampled, indexing.as_ref())
.map_err(pcm_resampler_error)?
};
if partial_len.is_none() {
self.buffered_source_start += consumed;
self.compact_buffered_source();
} else {
for samples in &mut self.buffered_source {
samples.clear();
}
self.buffered_source_start = 0;
}
self.append_output_samples(written, expected_output_frames, output);
Ok(())
}
fn append_output_samples(
&mut self,
written: usize,
expected_output_frames: Option<usize>,
output: &mut Vec<f32>,
) {
let trim = self.trim_output_frames.min(written);
self.trim_output_frames -= trim;
for frame in trim..written {
if self.reached_expected_output(expected_output_frames) {
break;
}
for channel_samples in self.output_scratch.iter().take(L::CHANNELS) {
output.push(channel_samples[frame].clamp(-1.0, 1.0));
}
self.emitted_output_frames += 1;
}
}
fn reached_expected_output(&self, expected_output_frames: Option<usize>) -> bool {
expected_output_frames.is_some_and(|expected| self.emitted_output_frames >= expected)
}
fn resampler(&self) -> Result<&Async<f32>> {
self.resampler
.as_ref()
.ok_or(PcmError::ResamplerNotInitialized.into())
}
}
pub fn s16_to_f32(sample: i16) -> f32 {
if sample < 0 {
sample as f32 / 32768.0
} else {
sample as f32 / 32767.0
}
}
pub fn f32_to_s16(sample: f32) -> i16 {
let sample = sample.clamp(-1.0, 1.0);
if sample < 0.0 {
(sample * 32768.0).round() as i16
} else {
(sample * 32767.0).round() as i16
}
}
pub fn decode_mulaw(sample: u8) -> i16 {
const BIAS: i32 = 0x84;
let sample = !sample;
let magnitude = ((((sample & 0x0f) as i32) << 3) + BIAS) << ((sample & 0x70) >> 4);
let decoded = if sample & 0x80 == 0 {
magnitude - BIAS
} else {
BIAS - magnitude
};
decoded.clamp(i16::MIN as i32, i16::MAX as i32) as i16
}
pub fn decode_alaw(sample: u8) -> i16 {
let sample = sample ^ 0x55;
let segment = (sample & 0x70) >> 4;
let mut magnitude = ((sample & 0x0f) as i32) << 4;
if segment == 0 {
magnitude += 8;
} else {
magnitude += 0x108;
if segment > 1 {
magnitude <<= segment - 1;
}
}
let decoded = if sample & 0x80 == 0 {
-magnitude
} else {
magnitude
};
decoded.clamp(i16::MIN as i32, i16::MAX as i32) as i16
}
pub fn decoded_frame_to_mono_s16le<Raw>(frame: &DecodedFrame<Raw>) -> Result<Vec<u8>>
where
Raw: FrameRaw,
{
interleaved_i16_to_mono_s16le(&frame.pcm, frame.channels)
}
pub fn interleaved_i16_to_mono_s16le(samples: &[i16], channels: usize) -> Result<Vec<u8>> {
NonZeroUsize::new(channels).ok_or(PcmError::ChannelCountZero)?;
validate_channel_alignment(channels, samples.len())?;
let mut mono = Vec::with_capacity(samples.len() / channels * std::mem::size_of::<i16>());
for frame in samples.chunks_exact(channels) {
let summed = frame.iter().map(|sample| i32::from(*sample)).sum::<i32>();
let clamped = (summed / channels as i32).clamp(i32::from(i16::MIN), i32::from(i16::MAX));
mono.extend((clamped as i16).to_le_bytes());
}
Ok(mono)
}
pub fn s16le_rms(samples: &[u8]) -> Result<f32> {
checked_byte_sample_count::<S16Le>(samples.len(), std::mem::size_of::<i16>())?;
let mut square_sum = 0_f64;
let mut count = 0_u64;
for sample in samples.chunks_exact(2) {
let sample = f64::from(i16::from_le_bytes([sample[0], sample[1]]));
square_sum += sample * sample;
count += 1;
}
Ok(if count == 0 {
0.0
} else {
(square_sum / count as f64).sqrt() as f32
})
}
pub fn validate_channel_alignment(channels: usize, samples: usize) -> Result<()> {
if channels == 0 {
return Err(PcmError::ChannelCountZero.into());
}
if !samples.is_multiple_of(channels) {
return Err(PcmError::ChannelAlignment { channels, samples }.into());
}
Ok(())
}
pub fn checked_byte_sample_count<E>(byte_len: usize, sample_bytes: usize) -> Result<usize>
where
E: SampleEncoding,
{
if !byte_len.is_multiple_of(sample_bytes) {
return Err(PcmError::SampleAlignment {
encoding: E::NAME,
byte_len,
sample_bytes,
}
.into());
}
Ok(byte_len / sample_bytes)
}
fn validate_pcm_bytes(encoding: PcmEncoding, byte_len: usize, channels: usize) -> Result<()> {
let sample_count = checked_byte_sample_count_by_name(
encoding.sample_encoding_name(),
byte_len,
encoding.bytes_per_sample(),
)?;
validate_channel_alignment(channels, sample_count)
}
fn checked_byte_sample_count_by_name(
encoding: &'static str,
byte_len: usize,
sample_bytes: usize,
) -> Result<usize> {
if !byte_len.is_multiple_of(sample_bytes) {
return Err(PcmError::SampleAlignment {
encoding,
byte_len,
sample_bytes,
}
.into());
}
Ok(byte_len / sample_bytes)
}
fn high_quality_sinc_resampler(
input_sample_rate_hz: NonZeroU32,
output_sample_rate_hz: NonZeroU32,
chunk_frames: usize,
channels: usize,
) -> Result<Async<f32>> {
Async::<f32>::new_sinc(
f64::from(output_sample_rate_hz.get()) / f64::from(input_sample_rate_hz.get()),
SINC_MAX_RELATIVE_RATIO,
&SincInterpolationParameters {
sinc_len: SINC_FILTER_LEN,
f_cutoff: SINC_CUTOFF,
oversampling_factor: SINC_OVERSAMPLING_FACTOR,
interpolation: SincInterpolationType::Cubic,
window: WindowFunction::BlackmanHarris2,
},
chunk_frames,
channels,
FixedAsync::Input,
)
.map_err(pcm_resampler_error)
}
fn resize_channels(channels: &mut [Vec<f32>], frames: usize) {
for samples in channels {
samples.resize(frames, 0.0);
}
}
fn pcm_resampler_error(error: impl std::fmt::Display) -> Error {
PcmError::Resampler(error.to_string()).into()
}