Implement resampling

This commit is contained in:
jaby 2024-12-01 00:38:28 +00:00
parent 850c2d23e4
commit 3cea8d99ff
1 changed files with 62 additions and 77 deletions

View File

@ -1,7 +1,7 @@
mod error;
use super::Frequency as RequestedFrequencyType;
use rubato::{FftFixedIn, Resampler};
use rubato::{FftFixedInOut, Resampler};
use symphonia::core::{
audio::{Layout, SampleBuffer},
codecs::{Decoder, DecoderOptions, CODEC_TYPE_NULL},
@ -28,55 +28,24 @@ impl Orality {
}
}
pub struct AudioSamples<T> {
samples: Vec::<T>,
pub struct PreparedAudioSamples {
samples: Vec::<i16>,
orality: Orality,
frequency: u32,
}
impl<T> AudioSamples<T> {
pub fn new(samples: Vec<T>, channels: usize, frequency: u32) -> Result<AudioSamples<T>, Error> {
impl PreparedAudioSamples {
pub fn new(samples: Vec<i16>, channels: usize, frequency: u32) -> Result<PreparedAudioSamples, Error> {
let orality = match channels {
0 => return Err(Error::from_str("Input file has no audio channels")),
1 => Orality::Mono,
2 => Orality::Stereo,
_ => return Err(Error::from_str("Only Mono and Stereo input are supported")),
};
Ok(AudioSamples{samples, orality, frequency})
Ok(PreparedAudioSamples{samples, orality, frequency})
}
// TODO: Reconsider passing zero_maker
pub fn to_planar(self, chunk_size: usize, zero_maker: fn()->T) -> Vec<Vec::<T>> {
let (_, chunk_remainder) = self.calculate_chunks(chunk_size);
let num_channel = self.orality.as_channels();
let mut result = Vec::new();
for _ in 0..num_channel {
result.push(Vec::<T>::new());
}
for (idx, sample) in self.samples.into_iter().enumerate() {
result[idx%num_channel].push(sample);
}
for channel in &mut result {
println!("({} - {} = {})", chunk_size, chunk_remainder, chunk_size - chunk_remainder);
for _ in 0..(chunk_size - chunk_remainder) {
channel.push(zero_maker());
}
}
result
}
pub fn calculate_chunks(&self, chunk_size: usize) -> (usize, usize) {
let sample_len = self.samples.len()/self.orality.as_channels();
let div_value = chunk_size;
(sample_len/div_value, sample_len%div_value)
}
pub fn samples(&self) -> &Vec::<T> {
pub fn samples(&self) -> &Vec::<i16> {
&self.samples
}
@ -91,21 +60,21 @@ struct InternalAudioSamples {
}
impl InternalAudioSamples {
pub fn new(planar_samples: Vec<Vec<f32>>, frequency: u32) -> InternalAudioSamples {
InternalAudioSamples{planar_samples, frequency}
}
pub fn calculate_chunks(&self, chunk_size: usize) -> (usize, usize) {
if self.planar_samples.len() > 0 {
let sample_len = self.planar_samples[0].len();
(sample_len/chunk_size, sample_len%chunk_size)
pub fn new(planar_samples: Vec<Vec<f32>>, frequency: u32) -> Result<InternalAudioSamples, Error> {
if planar_samples.len() < 1 {
// TODO: Make better text
Err(Error::from_str("Audio samples can not be empty"))
}
else {
(0, 0)
Ok(InternalAudioSamples{planar_samples, frequency})
}
}
pub fn sample_len(&self) -> usize {
self.planar_samples[0].len()
}
pub fn channels(&self) -> usize {
self.planar_samples.len()
}
@ -120,29 +89,27 @@ impl InternalAudioSamples {
}
}
pub type PreparedAudioSamples = AudioSamples<i16>;
pub fn load_as_i16_audio(input: Input, freq_type: RequestedFrequencyType) -> Result<PreparedAudioSamples, Error> {
let raw_audio = load_raw_audio(input)?;
let raw_audio = resample(raw_audio, 37_800)?;
test_write_wav(raw_audio)?;
test_write_wav(down_sample_interleave(raw_audio)?)?;
Err(Error::not_implemented("Resampling not implemented"))
}
fn test_write_wav(audio_samples: InternalAudioSamples) -> Result<(), Error> {
/*let spec = hound::WavSpec {
fn test_write_wav(audio_samples: PreparedAudioSamples) -> Result<(), Error> {
let spec = hound::WavSpec {
channels: 2,
sample_rate: 37_800,
bits_per_sample: 32,
sample_format: hound::SampleFormat::Float,
bits_per_sample: 16,
sample_format: hound::SampleFormat::Int,
};
let mut file = hound::WavWriter::create("planschi.wav", spec).unwrap();
for sample in audio_samples.samples {
file.write_sample(sample)?;
}
file.finalize()?;*/
file.finalize()?;
Ok(())
}
@ -171,7 +138,7 @@ fn decode(mut format: Box<dyn FormatReader>, mut decoder: Box<dyn Decoder>, trac
Err(err) => {
if let SymError::IoError(io_err) = &err {
if io_err.kind() == std::io::ErrorKind::UnexpectedEof {
return Ok(InternalAudioSamples::new(samples, frequency));
return InternalAudioSamples::new(samples, frequency);
}
}
return Err(error::next_packet(err));
@ -215,13 +182,21 @@ fn decode(mut format: Box<dyn FormatReader>, mut decoder: Box<dyn Decoder>, trac
fn resample(input: InternalAudioSamples, target_frequency: u32) -> Result<InternalAudioSamples, Error> {
const HIGH_QUALITY_CHUNKS:usize = (1024*10)*100;
const SUB_CHUNKS:usize = 20;
fn process_partial(input_option: Option<&[&[f32]]>, resampler: &mut FftFixedInOut<f32>, planar_output: &mut Vec<Vec<f32>>) -> Result<(), Error> {
let new_samples = resampler.process_partial(input_option, None).map_err(error::resample)?;
for (channel, channel_samples) in new_samples.into_iter().enumerate() {
planar_output[channel].extend(channel_samples.iter());
}
Ok(())
}
let (chunk_size, sub_chunks) = (HIGH_QUALITY_CHUNKS, SUB_CHUNKS);
let (chunk_count, chunk_remainder) = input.calculate_chunks(chunk_size);
let mut planar_input = input.planar_slices();
let mut resampler = FftFixedIn::<f32>::new(input.frequency as usize, target_frequency as usize, chunk_size, sub_chunks, input.channels()).map_err(error::resampler_construction)?;
let mut planar_output = {
let chunk_size = HIGH_QUALITY_CHUNKS;
let mut planar_input = input.planar_slices();
let mut resampler = FftFixedInOut::<f32>::new(input.frequency as usize, target_frequency as usize, chunk_size, input.channels()).map_err(error::resampler_construction)?;
let delay = resampler.output_delay();
let mut sample_len = input.sample_len();
let new_sample_len = (sample_len as f64*(target_frequency as f64/input.frequency as f64)) as usize;
let mut planar_output = {
let mut planar_output = Vec::new();
for _ in 0..planar_input.len() {
@ -230,27 +205,34 @@ fn resample(input: InternalAudioSamples, target_frequency: u32) -> Result<Intern
planar_output
};
for _chunk in 0..chunk_count {
loop {
let next_input_frames = resampler.input_frames_next();
if next_input_frames > sample_len {
if sample_len > 0 {
// Still frames left
process_partial(Some(&planar_input), &mut resampler, &mut planar_output)?;
}
break;
}
let new_samples = resampler.process(&planar_input, None).map_err(error::resample)?;
for (channel, slice) in planar_input.iter_mut().enumerate() {
*slice = &slice[chunk_size..];
*slice = &slice[next_input_frames..];
planar_output[channel].extend(new_samples[channel].iter());
}
sample_len -= next_input_frames;
}
let mut process_partial = |input_option: Option<&[&[f32]]>| -> Result<(), Error> {
let new_samples = resampler.process_partial(input_option, None).map_err(error::resample)?;
for (channel, channel_samples) in new_samples.into_iter().enumerate() {
planar_output[channel].extend(channel_samples.iter());
}
Ok(())
};
if chunk_remainder > 0 {
process_partial(Some(&planar_input))?;
if planar_output[0].len() < delay + new_sample_len {
// Flush
process_partial(None, &mut resampler, &mut planar_output)?;
}
for channel in &mut planar_output {
let start = delay;
let end = start + new_sample_len;
*channel = channel[start..end].into();
}
process_partial(None)?;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
let spec = hound::WavSpec {
@ -266,8 +248,11 @@ fn resample(input: InternalAudioSamples, target_frequency: u32) -> Result<Intern
}
file.finalize()?;
InternalAudioSamples::new(planar_output, target_frequency)
}
Err(Error::not_implemented("resample"))
fn down_sample_interleave(input: InternalAudioSamples) -> Result<PreparedAudioSamples, Error> {
Err(Error::not_implemented("down_sample_interleave"))
}
fn load_to_ram(mut input: Input) -> Result<std::io::Cursor<Vec<u8>>, Error> {