Last active
July 4, 2023 06:52
-
-
Save ayyybe/d696ead1b82d4de7ea5a8fe8e38fe93f to your computer and use it in GitHub Desktop.
Revisions
-
ayyybe revised this gist
Jul 4, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -22,7 +22,7 @@ fn sinc_resample( source_hz: f64, target_hz: f64, ) -> impl Signal<Frame = f32> { let ring_buffer = ring_buffer::Fixed::from([f32::EQUILIBRIUM; 10]); let sinc = Sinc::new(ring_buffer); signal.from_hz_to_hz(sinc, source_hz, target_hz) } -
ayyybe created this gist
Jul 4, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,83 @@ // live recording and realtime resampling of any input to 16kHz mono for whisper use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use dasp::{interpolate::sinc::Sinc, ring_buffer, signal, Frame, Signal}; use std::{sync::mpsc, thread}; fn get_voicemeeter_input_device(host: &cpal::Host) -> cpal::Device { host.input_devices() .expect("Failed to get input devices") .find(|device| { device .name() .unwrap() .to_lowercase() .contains("voicemeeter") }) .expect("Failed to find input device") } fn sinc_resample( signal: impl Signal<Frame = f32>, source_hz: f64, target_hz: f64, ) -> impl Signal<Frame = f32> { let ring_buffer = ring_buffer::Fixed::from([f32::EQUILIBRIUM; 50]); let sinc = Sinc::new(ring_buffer); signal.from_hz_to_hz(sinc, source_hz, target_hz) } fn main() -> anyhow::Result<()> { let host = cpal::default_host(); let device = get_voicemeeter_input_device(&host); let config = device.default_input_config()?; let sample_rate = config.sample_rate().0 as f64; let channels = config.channels() as usize; let (tx, rx) = mpsc::channel::<Vec<f32>>(); let stream = device.build_input_stream( &config.into(), move |data: &[f32], _info: &cpal::InputCallbackInfo| { let mono = data .chunks(channels) .map(|frame| frame.iter().sum::<f32>() / channels as f32); tx.send(mono.collect()).unwrap(); }, |err| { eprintln!("warning: input stream error: {}", err); }, None, )?; stream.play()?; let samples = rx.into_iter().flat_map(|x| x.into_iter()); let signal = signal::from_iter(samples); let signal = sinc_resample(signal, sample_rate, 16000.0); // now use the signal however you want (warning: next()/until_exhausted() will block until the stream is dropped) // example: write to a wav file for 10 seconds let processing_thread = thread::spawn(move || { let mut writer = hound::WavWriter::create( "output.wav", hound::WavSpec { channels: 1, sample_rate: 16000, bits_per_sample: 32, sample_format: hound::SampleFormat::Float, }, ) .unwrap(); for sample in signal.until_exhausted() { writer.write_sample(sample).unwrap(); } writer.finalize().unwrap(); }); thread::sleep(std::time::Duration::from_millis(10000)); drop(stream); println!("dropped stream"); processing_thread.join().unwrap(); println!("finished processing"); Ok(()) }