Created
September 26, 2019 06:45
-
-
Save mitchhentges/eddd95e9df3b7464f853d336d1c6574f to your computer and use it in GitHub Desktop.
This file contains 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 characters
use cpal::traits::{DeviceTrait, EventLoopTrait, HostTrait}; | |
use sample::{ring_buffer, interpolate, signal, Sample, Signal}; | |
fn main() -> Result<(), failure::Error> { | |
let host = cpal::default_host(); | |
let event_loop = host.event_loop(); | |
// Default devices. | |
let input_device = host.default_input_device().expect("failed to get default input device"); | |
let output_device = host.default_output_device().expect("failed to get default output device"); | |
println!("Using default input device: \"{}\"", input_device.name()?); | |
println!("Using default output device: \"{}\"", output_device.name()?); | |
// We'll try and use the same format between streams to keep it simple | |
let mut input_format = input_device.default_input_format()?; | |
input_format.data_type = cpal::SampleFormat::I16; | |
input_format.channels = 1; | |
let mut output_format = output_device.default_output_format()?; | |
output_format.data_type = cpal::SampleFormat::I16; | |
output_format.channels = 1; | |
// Build streams. | |
println!("Attempting to build both streams with `{:?}`|`{:?}`.", input_format, output_format); | |
let input_stream_id = event_loop.build_input_stream(&input_device, &input_format)?; | |
let output_stream_id = event_loop.build_output_stream(&output_device, &output_format)?; | |
println!("Successfully built streams."); | |
// The channel to share samples. | |
let (tx, rx) = std::sync::mpsc::sync_channel(48000); | |
// Play the streams. | |
println!("Starting the input and output streams."); | |
event_loop.play_stream(input_stream_id.clone())?; | |
event_loop.play_stream(output_stream_id.clone())?; | |
let ring_buffer = ring_buffer::Fixed::from([[0.0]; 100]); | |
let sinc = interpolate::Sinc::new(ring_buffer); | |
let signal = signal::from_iter(rx.try_iter()); | |
let mut new_signal = signal.from_hz_to_hz(sinc, input_format.sample_rate.0 as f64, output_format.sample_rate.0 as f64); | |
event_loop.run(move |id, result| { | |
let data = match result { | |
Ok(data) => data, | |
Err(err) => { | |
eprintln!("an error occurred on stream {:?}: {}", id, err); | |
return; | |
} | |
}; | |
match data { | |
cpal::StreamData::Input { buffer: cpal::UnknownTypeInputBuffer::I16(buffer) } => { | |
assert_eq!(id, input_stream_id); | |
let mut output_fell_behind = false; | |
for &sample in buffer.iter() { | |
let frame = [sample.to_sample::<f64>()]; | |
if tx.try_send(frame).is_err() { | |
output_fell_behind = true; | |
} | |
} | |
if output_fell_behind { | |
eprintln!("output stream fell behind: try increasing latency"); | |
} | |
}, | |
cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => { | |
assert_eq!(id, output_stream_id); | |
let mut input_fell_behind = None; | |
for sample in buffer.iter_mut() { | |
*sample = match signal.is_exhausted() { | |
false => new_signal.next()[0].to_sample::<i16>(), | |
true => { | |
input_fell_behind = Some("whoops"); | |
new_signal.next()[0].to_sample::<i16>() | |
}, | |
}; | |
} | |
if let Some(err) = input_fell_behind { | |
eprintln!("input stream fell behind: {}: try increasing latency", err); | |
} | |
}, | |
_ => panic!("we're expecting i16 data"), | |
} | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment