From e6cbba66fed669c9c6808584a4f1551cfdb5de30 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Thu, 13 Oct 2016 18:07:21 +0200 Subject: Function to start listening on microphone Messy. To clean up once I've seen if it works. --- src/audio.rs | 90 ++++++++++++++++++++++++++++++++++++++---------------------- src/gui.rs | 3 +- 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/src/audio.rs b/src/audio.rs index 526a227..cdeb88a 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -1,58 +1,86 @@ extern crate portaudio; use portaudio as pa; +use std::sync::mpsc::*; + const SAMPLE_RATE: f64 = 44100.0; const FRAMES: usize = 512; -pub fn get_device_list() -> Result, pa::Error> { - let pa = try!(pa::PortAudio::new()); - let default_host = try!(pa.default_host_api()); - println!("Using default host: {:#?}", default_host); +pub fn init() -> Result { + pa::PortAudio::new() +} - let mut list = Vec::new(); - let devices = try!(pa.devices()); - for device in devices { - let (pa::DeviceIndex(idx), info) = try!(device); - if info.max_input_channels == 0 { - continue; - } - list.push((idx, info.name.to_string())); - } +pub fn get_device_list(pa: &pa::PortAudio) -> Result, pa::Error> { + // This pa.devices gives a Result of devices, each of which is + // also a Result. So a Result>>. We + // mould it into devices: a Vec<(index, DeviceInfo)>. + let devices = try!(try!(pa.devices()).map(|device| { + device.map(|(pa::DeviceIndex(idx), info)| (idx, info)) + }).collect::, _>>()); + + let list = devices.iter().filter(|&&(_, ref info)| info.max_input_channels > 0) + .map(|&(idx, ref info)| (idx, info.name.to_string())) + .collect(); Ok(list) } -pub fn run(device_index: u32) -> Result<(), pa::Error> { - let pa = try!(pa::PortAudio::new()); +#[test] +fn get_device_list_returns_devices() { + let pa = init().expect("Could not init portaudio"); + let devices = get_device_list(&pa).expect("Getting devices had an error"); + + // all machines should have at least one input stream, even if + // that's just a virtual stream with a name like "default". + assert!(devices.len() > 0); +} + + +pub struct OpenRecordingChannel<'a> { + receiver: Receiver>, + //pa: &'a portaudio::PortAudio, + stream: pa::Stream<'a, pa::NonBlocking, pa::Input> +} - let input_info = try!(pa.device_info(pa::DeviceIndex(device_index))); - println!("Using {} for input", input_info.name); +pub fn start_listening<'a>(pa: &'a pa::PortAudio, device_index: u32) -> Result, pa::Error> { + //let pa = try!(pa::PortAudio::new()); + let device_info = try!(pa.device_info(pa::DeviceIndex(device_index))); + let latency = device_info.default_low_input_latency; // Construct the input stream parameters. - let latency = input_info.default_low_input_latency; + let input_params = pa::StreamParameters::::new(pa::DeviceIndex(device_index), 1, true, latency); // Check that the stream format is supported. try!(pa.is_input_format_supported(input_params, SAMPLE_RATE)); - // Construct the settings with which we'll open our duplex stream. - let settings = pa::InputStreamSettings::new(input_params, SAMPLE_RATE, FRAMES as u32); + // Construct the settings with which we'll open our stream. + let stream_settings = pa::InputStreamSettings::new(input_params, SAMPLE_RATE, FRAMES as u32); - // We'll use this channel to send the count_down to the main thread for fun. - let (sender, receiver) = ::std::sync::mpsc::channel(); + // This channel will let us read from and control the audio stream + let (sender, receiver) = channel(); - // A callback to pass to the non-blocking stream. + // This callback A callback to pass to the non-blocking stream. let callback = move |pa::InputStreamCallbackArgs { buffer, .. }| { sender.send(buffer.iter().map(|x| *x as f64).collect()).ok(); pa::Continue }; - // Construct a stream with input and output sample types of f32. - let mut stream = try!(pa.open_non_blocking_stream(settings, callback)); - + let mut stream = try!(pa.open_non_blocking_stream(stream_settings, callback)); try!(stream.start()); + + + //How do I call this? try!(stream.stop()); + + Ok(OpenRecordingChannel { + receiver: receiver, +// pa: &pa, + stream: stream + }) +} - let mut samples_index = 0; - // Do some stuff! + +/* + let mut samples_index = 0; while let Ok(samples) = receiver.recv() { samples_index += 1; if samples_index % 100 != 0 { @@ -67,8 +95,4 @@ pub fn run(device_index: u32) -> Result<(), pa::Error> { ).unwrap().max_freq; println!("{}Hz", max_frequency.floor()); } - - try!(stream.stop()); - - Ok(()) -} +*/ diff --git a/src/gui.rs b/src/gui.rs index 66ae1f7..de8a322 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -8,7 +8,8 @@ pub fn start_gui() -> Result<(), String> { let window = gtk::Window::new(gtk::WindowType::Toplevel); window.set_title("Musician Training"); - let audio_devices = try!(::audio::get_device_list().map_err(|e| e.to_string())); + let pa = ::audio::init().expect("Could not init portaudio"); + let audio_devices = try!(::audio::get_device_list(&pa).map_err(|e| e.to_string())); let dropdown = gtk::ComboBoxText::new(); for (index, name) in audio_devices { dropdown.append(Some(format!("{}", index).as_ref()), name.as_ref()); -- cgit v1.2.3