extern crate rubato;
use audioadapter_buffers::number_to_float::InterleavedNumbers;
use audioadapter_sample::sample::I16_LE;
use rubato::{
calculate_cutoff, Async, FixedAsync, Indexing, Resampler, SincInterpolationParameters,
SincInterpolationType, WindowFunction,
};
use std::env;
use std::fs::File;
use std::io::prelude::{Read, Write};
use std::time::Instant;
extern crate env_logger;
extern crate log;
use env_logger::Builder;
use log::LevelFilter;
const BYTE_PER_SAMPLE: usize = std::mem::size_of::<i16>();
fn read_file(filename: &str) -> Vec<u8> {
let mut f = File::open(filename).expect("Can't open file");
let mut data = vec![];
f.read_to_end(&mut data).unwrap();
data
}
fn write_file(filename: &str, data: &[u8], bytes_to_skip: usize, bytes_to_write: usize) {
let mut f = File::create(filename).expect("Can't open file");
f.write_all(&data[bytes_to_skip..bytes_to_skip + bytes_to_write])
.expect("Failed to write data to file");
}
fn main() {
let mut builder = Builder::from_default_env();
builder.filter(None, LevelFilter::Debug).init();
let file_in = env::args().nth(1).expect("Please specify an input file.");
let file_out = env::args().nth(2).expect("Please specify an output file.");
println!("Opening files: {}, {}", file_in, file_out);
let fs_in_str = env::args()
.nth(3)
.expect("Please specify an input sample rate");
let fs_out_str = env::args()
.nth(4)
.expect("Please specify an output sample rate");
let fs_in = fs_in_str.parse::<usize>().unwrap();
let fs_out = fs_out_str.parse::<usize>().unwrap();
println!("Resampling from {} to {}", fs_in, fs_out);
let channels_str = env::args()
.nth(5)
.expect("Please specify number of channels");
let channels = channels_str.parse::<usize>().unwrap();
println!("Copy input file to buffer");
let indata = read_file(&file_in);
let nbr_input_frames = indata.len() / (channels * BYTE_PER_SAMPLE);
let f_ratio = fs_out as f64 / fs_in as f64;
let mut outdata: Vec<u8> =
vec![0; 2 * channels * BYTE_PER_SAMPLE * (nbr_input_frames as f64 * f_ratio) as usize];
println!("Creating resampler");
let sinc_len = 128;
let oversampling_factor = 256;
let interpolation = SincInterpolationType::Quadratic;
let window = WindowFunction::Blackman2;
let f_cutoff = calculate_cutoff(sinc_len, window);
let params = SincInterpolationParameters {
sinc_len,
f_cutoff,
interpolation,
oversampling_factor,
window,
};
let mut resampler =
Async::<f32>::new_sinc(f_ratio, 1.1, ¶ms, 1024, channels, FixedAsync::Input).unwrap();
let mut input_frames_next = resampler.input_frames_next();
let resampler_delay = resampler.output_delay();
let input_adapter =
InterleavedNumbers::<&[I16_LE], f32>::new_from_bytes(&indata, channels, nbr_input_frames)
.unwrap();
let outdata_capacity = outdata.len() / (channels * BYTE_PER_SAMPLE);
let mut output_adapter = InterleavedNumbers::<&mut [I16_LE], f32>::new_from_bytes_mut(
&mut outdata,
channels,
outdata_capacity,
)
.unwrap();
println!("Process all full chunks");
let start = Instant::now();
let mut indexing = Indexing {
input_offset: 0,
output_offset: 0,
active_channels_mask: None,
partial_len: None,
};
let mut input_frames_left = nbr_input_frames;
while input_frames_left >= input_frames_next {
let (nbr_in, nbr_out) = resampler
.process_into_buffer(&input_adapter, &mut output_adapter, Some(&indexing))
.unwrap();
indexing.input_offset += nbr_in;
indexing.output_offset += nbr_out;
input_frames_left -= nbr_in;
input_frames_next = resampler.input_frames_next();
}
println!("Process a partial chunk with the last frames.");
indexing.partial_len = Some(input_frames_left);
let (_nbr_in, _nbr_out) = resampler
.process_into_buffer(&input_adapter, &mut output_adapter, Some(&indexing))
.unwrap();
let duration = start.elapsed();
println!("Resampling took: {:?}", duration);
let nbr_output_frames = (nbr_input_frames as f32 * fs_out as f32 / fs_in as f32) as usize;
println!(
"Processed {} input frames into {} output frames",
nbr_input_frames, nbr_output_frames
);
println!("Write output to file, trimming off the silent frames from both ends.");
write_file(
&file_out,
&outdata,
resampler_delay * channels * BYTE_PER_SAMPLE,
nbr_output_frames * channels * BYTE_PER_SAMPLE,
);
}