Skip to content

Instantly share code, notes, and snippets.

@mitchhentges
Created September 26, 2019 06:45
Show Gist options
  • Save mitchhentges/eddd95e9df3b7464f853d336d1c6574f to your computer and use it in GitHub Desktop.
Save mitchhentges/eddd95e9df3b7464f853d336d1c6574f to your computer and use it in GitHub Desktop.
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