use {
crate::OperationError,
rodio::{
ChannelCount, Decoder, SampleRate, Source,
buffer::SamplesBuffer,
source::{Spatial, UniformSourceIterator},
},
std::{
io::{Cursor, Error as IoError},
path::Path,
slice::from_raw_parts,
},
tokio::fs::read,
};
pub trait GenericSample: Clone {
fn is_f32() -> bool {
false
}
fn is_i16() -> bool {
false
}
fn zero() -> Self;
fn to_f32(&self) -> f32;
fn from_f32(value: f32) -> Self;
}
impl GenericSample for f32 {
fn is_f32() -> bool {
true
}
fn zero() -> Self {
0.0
}
fn to_f32(&self) -> f32 {
*self
}
fn from_f32(value: f32) -> Self {
value
}
}
impl GenericSample for i16 {
fn is_i16() -> bool {
true
}
fn zero() -> Self {
0
}
fn to_f32(&self) -> f32 {
*self as f32 / i16::MAX as f32
}
fn from_f32(value: f32) -> Self {
(value * i16::MAX as f32).clamp(i16::MIN as f32, i16::MAX as f32) as i16
}
}
pub(super) fn samples_to_f32<S>(samples: &[S]) -> Vec<f32>
where
S: GenericSample,
{
if S::is_f32() {
unsafe { from_raw_parts(samples.as_ptr() as *const f32, samples.len()) }.to_vec()
} else {
samples.iter().map(|s| s.to_f32()).collect()
}
}
fn f32_to_samples<S>(samples: &[f32]) -> Vec<S>
where
S: GenericSample,
{
if S::is_f32() {
unsafe { from_raw_parts(samples.as_ptr() as *const S, samples.len()) }.to_vec()
} else {
samples.iter().map(|&v| S::from_f32(v)).collect()
}
}
pub async fn load_audio<const SR: usize, S, P>(
audio_path: P,
mono: bool,
) -> Result<(Vec<S>, usize), OperationError>
where
S: GenericSample,
P: AsRef<Path>,
{
decode_audio::<SR, S, _>(read(audio_path).await?, mono)
}
pub fn decode_audio<const SR: usize, S, D>(
audio_data: D,
mono: bool,
) -> Result<(Vec<S>, usize), OperationError>
where
S: GenericSample,
D: AsRef<[u8]> + Send + Sync + 'static,
{
let file = Cursor::new(audio_data);
let decoder = Decoder::new(file)?;
let channels = if mono { 1 } else { decoder.channels().into() } as usize;
let samples: Vec<f32> = UniformSourceIterator::new(
decoder,
ChannelCount::new(channels as _).ok_or(IoError::other("Invalid channel count."))?,
SampleRate::new(SR as _).ok_or(IoError::other("Invalid sample rate."))?,
)
.collect();
if samples.is_empty() {
return Err(OperationError::InputInvalid("Audio is empty.".to_owned()));
}
Ok((f32_to_samples(&samples), channels))
}
pub fn resample<const SSR: usize, const TSR: usize, S>(
samples: &[S],
src_channels: usize,
tgt_channels: usize,
) -> Result<Vec<S>, OperationError>
where
S: GenericSample,
{
resample_dynamic(samples, SSR, TSR, src_channels, tgt_channels)
}
pub fn resample_dynamic<S>(
samples: &[S],
ssr: usize,
tsr: usize,
src_channels: usize,
tgt_channels: usize,
) -> Result<Vec<S>, OperationError>
where
S: GenericSample,
{
if samples.is_empty() || src_channels == 0 || tgt_channels == 0 {
return Ok(Default::default());
}
let f32_samples = samples_to_f32(samples);
let resampled: Vec<f32> = UniformSourceIterator::new(
SamplesBuffer::new(
ChannelCount::new(src_channels as _).ok_or(IoError::other("Invalid channel count."))?,
SampleRate::new(ssr as _).ok_or(IoError::other("Invalid sample rate."))?,
f32_samples,
),
ChannelCount::new(tgt_channels as _).ok_or(IoError::other("Invalid channel count."))?,
SampleRate::new(tsr as _).ok_or(IoError::other("Invalid sample rate."))?,
)
.collect();
Ok(f32_to_samples(&resampled))
}
pub fn spatial_audio<const SR: usize, S>(
audio: &[S],
channels: usize,
emitter_position: [f32; 3],
left_ear: [f32; 3],
right_ear: [f32; 3],
) -> Result<Vec<S>, OperationError>
where
S: GenericSample,
{
let f32_audio = samples_to_f32(audio);
let result: Vec<f32> = Spatial::new(
SamplesBuffer::new(
ChannelCount::new(channels as _).ok_or(IoError::other("Invalid channel count."))?,
SampleRate::new(SR as _).ok_or(IoError::other("Invalid sample rate."))?,
f32_audio,
),
emitter_position,
left_ear,
right_ear,
)
.collect();
Ok(f32_to_samples(&result))
}
pub fn reverb<const SR: usize, S>(
audio: &[S],
channels: usize,
room_size: f32,
damping: f32,
wet: f32,
) -> Vec<S>
where
S: GenericSample,
{
if audio.is_empty() || channels == 0 {
return Vec::new();
}
let f32_audio = samples_to_f32(audio);
let mut output = vec![0.0; f32_audio.len()];
let mut delay_lines = vec![vec![0.0; (SR as f32 * 0.1) as usize]; 8]; let mut delay_pos = [0; 8];
let delay_lengths = [
(SR as f32 * 0.0297) as usize,
(SR as f32 * 0.0371) as usize,
(SR as f32 * 0.0411) as usize,
(SR as f32 * 0.0437) as usize,
(SR as f32 * 0.005) as usize,
(SR as f32 * 0.0157) as usize,
(SR as f32 * 0.0201) as usize,
(SR as f32 * 0.0263) as usize,
];
for i in 0..f32_audio.len() {
let sample = f32_audio[i];
let mut reverb_sample = 0.0;
for j in 0..8 {
let delayed = delay_lines[j][delay_pos[j]];
reverb_sample += delayed * 0.125; delay_lines[j][delay_pos[j]] = sample + delayed * damping;
delay_pos[j] = (delay_pos[j] + 1) % delay_lengths[j];
}
output[i] = sample * (1.0 - wet) + reverb_sample * wet * room_size;
}
f32_to_samples(&output)
}
pub fn speed<const SR: usize, S>(
audio: &[S],
channels: usize,
factor: f32,
) -> Result<Vec<S>, OperationError>
where
S: GenericSample,
{
if audio.is_empty() || channels == 0 {
return Ok(Default::default());
}
if factor <= 0.0 {
return Err(OperationError::InputInvalid(
"Speed factor must be greater than 0.".to_owned(),
));
}
if (factor - 1.0).abs() < f32::EPSILON {
return Ok(audio.to_vec());
}
let f32_audio = samples_to_f32(audio);
let src_channels =
ChannelCount::new(channels as _).ok_or(IoError::other("Invalid channel count."))?;
let src_sample_rate = SampleRate::new(SR as _).ok_or(IoError::other("Invalid sample rate."))?;
let source = SamplesBuffer::new(src_channels, src_sample_rate, f32_audio).speed(factor);
let result: Vec<f32> =
UniformSourceIterator::new(source, src_channels, src_sample_rate).collect();
Ok(f32_to_samples(&result))
}