use {
crate::OperationError,
rodio::{
ChannelCount, Decoder, SampleRate, Source,
buffer::SamplesBuffer,
source::{Spatial, UniformSourceIterator},
},
std::{
io::{Cursor, Error as IoError},
path::Path,
},
tokio::fs::read,
};
pub async fn load_audio<const SR: usize, P>(
audio_path: P,
mono: bool,
) -> Result<(Vec<f32>, usize), OperationError>
where
P: AsRef<Path>,
{
decode_audio::<SR, _>(read(audio_path).await?, mono)
}
pub fn decode_audio<const SR: usize, D>(
audio_data: D,
mono: bool,
) -> Result<(Vec<f32>, usize), OperationError>
where
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 = 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::<Vec<f32>>();
if samples.is_empty() {
return Err(OperationError::InputInvalid("Audio is empty.".to_owned()));
}
Ok((samples, channels))
}
pub fn resample<const SSR: usize, const TSR: usize>(
samples: &[f32],
src_channels: usize,
tgt_channels: usize,
) -> Result<Vec<f32>, OperationError> {
if samples.is_empty() || src_channels == 0 || tgt_channels == 0 {
return Ok(Default::default());
}
Ok(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."))?,
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())
}
pub fn spatial_audio<const SR: usize>(
audio: &[f32],
channels: usize,
emitter_position: [f32; 3],
left_ear: [f32; 3],
right_ear: [f32; 3],
) -> Result<Vec<f32>, OperationError> {
Ok(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."))?,
audio,
),
emitter_position,
left_ear,
right_ear,
)
.collect())
}
pub fn reverb<const SR: usize>(
audio: &[f32],
channels: usize,
room_size: f32,
damping: f32,
wet: f32,
) -> Vec<f32> {
if audio.is_empty() || channels == 0 {
return Vec::new();
}
let mut output = vec![0.0; 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..audio.len() {
let sample = 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;
}
output
}
pub fn speed<const SR: usize>(
audio: &[f32],
channels: usize,
factor: f32,
) -> Result<Vec<f32>, OperationError> {
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 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, audio).speed(factor);
Ok(UniformSourceIterator::new(source, src_channels, src_sample_rate).collect())
}