mirror of
https://github.com/mii443/maudio-router.git
synced 2025-08-22 16:05:35 +00:00
wip
This commit is contained in:
742
Cargo.lock
generated
742
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,18 @@
|
|||||||
virtual_devices:
|
virtual_devices:
|
||||||
- name: "mic"
|
- name: "mic"
|
||||||
channels: 2
|
channels: 2
|
||||||
sample_rate: 96000
|
sample_rate: 48000
|
||||||
routes:
|
routes:
|
||||||
input:
|
input:
|
||||||
- name: "Mic"
|
- name: "Mic"
|
||||||
virtual_device: "mic"
|
virtual_device: "mic"
|
||||||
device:
|
device:
|
||||||
local:
|
local:
|
||||||
name: "VoiceMeeter Aux Output (VB-Audio VoiceMeeter AUX VAIO)"
|
name: "Voicemeeter Out B2 (VB-Audio Voicemeeter VAIO)"
|
||||||
output:
|
output:
|
||||||
- name: "Speaker"
|
- name: "Speaker"
|
||||||
input:
|
input:
|
||||||
virtual_device: "mic"
|
virtual_device: "mic"
|
||||||
device:
|
device:
|
||||||
local:
|
local:
|
||||||
name: "CABLE Input (VB-Audio Virtual Cable)"
|
name: "CABLE Input (VB-Audio Virtual Cable)"
|
||||||
|
@ -1,49 +1,67 @@
|
|||||||
use num::Complex;
|
use rubato::{Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction};
|
||||||
use rustfft::FftPlanner;
|
|
||||||
|
const MAX_CHUNK_SIZE: usize = 1024;
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn resampling(
|
pub fn resampling(
|
||||||
current_sample_rate: u32,
|
current_sample_rate: u32,
|
||||||
target_sample_rate: u32,
|
target_sample_rate: u32,
|
||||||
data: Vec<Vec<f32>>,
|
data: Vec<Vec<f32>>,
|
||||||
) -> Vec<Vec<f32>> {
|
) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
|
||||||
let mut resampled_data = Vec::new();
|
let channels = data.len();
|
||||||
|
let samples = data[0].len();
|
||||||
|
|
||||||
let mut planner = FftPlanner::new();
|
let resample_ratio = target_sample_rate as f64 / current_sample_rate as f64;
|
||||||
|
|
||||||
for channel_data in data {
|
let params = SincInterpolationParameters {
|
||||||
let mut complex_data: Vec<Complex<f32>> =
|
sinc_len: 256,
|
||||||
channel_data.iter().map(|&x| Complex::new(x, 0.0)).collect();
|
f_cutoff: 0.95,
|
||||||
|
interpolation: SincInterpolationType::Linear,
|
||||||
|
oversampling_factor: 256,
|
||||||
|
window: WindowFunction::BlackmanHarris2,
|
||||||
|
};
|
||||||
|
|
||||||
let fft = planner.plan_fft_forward(complex_data.len());
|
let mut output = vec![Vec::new(); channels];
|
||||||
fft.process(&mut complex_data);
|
let expected_output_len = (samples as f64 * resample_ratio).round() as usize;
|
||||||
|
|
||||||
let adjustment_factor = target_sample_rate as f64 / current_sample_rate as f64;
|
for chunk_start in (0..samples).step_by(MAX_CHUNK_SIZE) {
|
||||||
let new_size = (complex_data.len() as f64 * adjustment_factor).round() as usize;
|
let chunk_end = (chunk_start + MAX_CHUNK_SIZE).min(samples);
|
||||||
let mut adjusted_complex_data;
|
let chunk_size = chunk_end - chunk_start;
|
||||||
|
|
||||||
if adjustment_factor == 1.0 {
|
let mut resampler = SincFixedIn::<f32>::new(
|
||||||
adjusted_complex_data = complex_data;
|
resample_ratio,
|
||||||
} else if adjustment_factor > 1.0 {
|
2.0,
|
||||||
adjusted_complex_data = complex_data.into_iter().collect();
|
SincInterpolationParameters {
|
||||||
adjusted_complex_data.resize(new_size, Complex::new(0.0, 0.0));
|
sinc_len: 256,
|
||||||
} else {
|
f_cutoff: 0.95,
|
||||||
adjusted_complex_data = complex_data.into_iter().collect();
|
interpolation: SincInterpolationType::Linear,
|
||||||
adjusted_complex_data.resize(new_size, Complex::new(0.0, 0.0));
|
oversampling_factor: 256,
|
||||||
}
|
window: WindowFunction::BlackmanHarris2,
|
||||||
|
},
|
||||||
|
chunk_size,
|
||||||
|
channels,
|
||||||
|
)?;
|
||||||
|
|
||||||
let ifft = planner.plan_fft_inverse(adjusted_complex_data.len());
|
let mut input: Vec<&[f32]> = data
|
||||||
ifft.process(&mut adjusted_complex_data);
|
.iter()
|
||||||
|
.map(|channel| &channel[chunk_start..chunk_end])
|
||||||
let len = adjusted_complex_data.len();
|
|
||||||
|
|
||||||
let resampled_channel: Vec<f32> = adjusted_complex_data
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| x.re / len as f32)
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
resampled_data.push(resampled_channel);
|
let mut chunk_output = vec![vec![0.0; resampler.output_frames_next()]; channels];
|
||||||
|
let mut output_buffers: Vec<&mut [f32]> = chunk_output
|
||||||
|
.iter_mut()
|
||||||
|
.map(|channel| channel.as_mut_slice())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let (_, output_frames) = resampler.process_into_buffer(&input, &mut output_buffers, None)?;
|
||||||
|
|
||||||
|
for (channel_output, chunk_channel_output) in output.iter_mut().zip(chunk_output.iter()) {
|
||||||
|
channel_output.extend_from_slice(&chunk_channel_output[..output_frames]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resampled_data
|
for channel in output.iter_mut() {
|
||||||
}
|
channel.truncate(expected_output_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
@ -89,7 +89,14 @@ impl VirtualDevice {
|
|||||||
|
|
||||||
pub fn write_input_multiple_channels(&mut self, input_buffer: &[Vec<f32>]) {
|
pub fn write_input_multiple_channels(&mut self, input_buffer: &[Vec<f32>]) {
|
||||||
for (sample_rate, buffer) in self.output_buffer.iter_mut() {
|
for (sample_rate, buffer) in self.output_buffer.iter_mut() {
|
||||||
let buffer_resample = resampling(self.sample_rate, *sample_rate, input_buffer.to_vec());
|
let buffer_resample = if self.sample_rate == *sample_rate {
|
||||||
|
input_buffer.to_vec()
|
||||||
|
} else {
|
||||||
|
resampling(self.sample_rate, *sample_rate, input_buffer.to_vec()).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Resampling: {} -> {}", input_buffer[0].len(), buffer_resample[0].len());
|
||||||
|
|
||||||
(0..self.channels as usize).for_each(|i| buffer[i].extend(buffer_resample[i].iter()));
|
(0..self.channels as usize).for_each(|i| buffer[i].extend(buffer_resample[i].iter()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user