diff options
author | Justin Worthe <justin.worthe@gmail.com> | 2016-11-05 15:56:24 +0200 |
---|---|---|
committer | Justin Worthe <justin.worthe@gmail.com> | 2016-11-05 15:56:24 +0200 |
commit | 75c9880d1a7bb7e54996743989374a45d5a26e49 (patch) | |
tree | b0b3e14714c464a468c27bf8be42efceab0146f7 | |
parent | 420ad331332bce98f871f1c4ca2c0bea51688767 (diff) |
Reordered passing in channels
-rw-r--r-- | src/audio.rs | 41 | ||||
-rw-r--r-- | src/gui.rs | 41 |
2 files changed, 34 insertions, 48 deletions
diff --git a/src/audio.rs b/src/audio.rs index c989c49..c038080 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -34,13 +34,8 @@ fn get_device_list_returns_devices() { assert!(devices.len() > 0); } - -pub struct OpenRecordingChannel { - pub receiver: Receiver<Vec<f32>>, - pub stream: pa::Stream<pa::NonBlocking, pa::Input<f32>> -} - -pub fn start_listening(pa: &pa::PortAudio, device_index: u32) -> Result<OpenRecordingChannel, pa::Error> { +pub fn start_listening(pa: &pa::PortAudio, device_index: u32, + sender: Sender<Vec<f64>>) -> Result<pa::Stream<pa::NonBlocking, pa::Input<f32>>, pa::Error> { let device_info = try!(pa.device_info(pa::DeviceIndex(device_index))); let latency = device_info.default_low_input_latency; @@ -54,22 +49,16 @@ pub fn start_listening(pa: &pa::PortAudio, device_index: u32) -> Result<OpenReco // Construct the settings with which we'll open our stream. let stream_settings = pa::InputStreamSettings::new(input_params, SAMPLE_RATE, FRAMES as u32); - // This channel will let us read from and control the audio stream - let (sender, receiver) = channel(); - // This callback A callback to pass to the non-blocking stream. let callback = move |pa::InputStreamCallbackArgs { buffer, .. }| { - sender.send(buffer.iter().cloned().collect()).ok(); + sender.send(buffer.iter().map(|&s| s as f64).collect()).ok(); pa::Continue }; let mut stream = try!(pa.open_non_blocking_stream(stream_settings, callback)); try!(stream.start()); - Ok(OpenRecordingChannel { - receiver: receiver, - stream: stream - }) + Ok(stream) } #[test] @@ -77,24 +66,6 @@ fn start_listening_returns_successfully() { let pa = init().expect("Could not init portaudio"); let devices = get_device_list(&pa).expect("Getting devices had an error"); let device = devices.first().expect("Should have at least one device"); - start_listening(&pa, device.0).expect("Error starting listening to first channel"); + let (sender, _) = channel(); + start_listening(&pa, device.0, sender).expect("Error starting listening to first channel"); } - - -/* - let mut samples_index = 0; - while let Ok(samples) = receiver.recv() { - samples_index += 1; - if samples_index % 100 != 0 { - continue; - } - - let frequency_domain = ::transforms::fft(samples, SAMPLE_RATE); - - let max_frequency = frequency_domain.iter() - .fold(None as Option<::transforms::FrequencyBucket>, |max, next| - if max.is_none() || max.clone().unwrap().intensity < next.intensity { Some(next.clone()) } else { max } - ).unwrap().max_freq; - println!("{}Hz", max_frequency.floor()); - } -*/ @@ -3,8 +3,11 @@ use gtk::prelude::*; use std::cell::RefCell; use portaudio as pa; use std::rc::Rc; +use std::sync::Arc; use std::io; use std::io::Write; +use std::thread; +use std::sync::mpsc::*; const GUI_XML: &'static str = r#" <interface> @@ -20,43 +23,55 @@ const GUI_XML: &'static str = r#" struct ApplicationState { pa: pa::PortAudio, - channel: Option<::audio::OpenRecordingChannel> + pa_stream: Option<pa::Stream<pa::NonBlocking, pa::Input<f32>>> } pub fn start_gui() -> Result<(), String> { let pa = try!(::audio::init().map_err(|e| e.to_string())); let microphones = try!(::audio::get_device_list(&pa).map_err(|e| e.to_string())); - + + let (mic_sender, mic_receiver) = channel(); let state = Rc::new(RefCell::new(ApplicationState { pa: pa, - channel: None + pa_stream: None })); try!(gtk::init().map_err(|_| "Failed to initialize GTK.")); let gtk_builder = try!(create_window(microphones)); - let dropdown: gtk::ComboBoxText = try!( - gtk_builder.get_object("dropdown") - .ok_or("GUI does not contain an object with id 'dropdown'") - ); { let state_for_dropdown = state.clone(); + + let dropdown: gtk::ComboBoxText = try!( + gtk_builder.get_object("dropdown").ok_or("GUI does not contain an object with id 'dropdown'") + ); dropdown.connect_changed(move |dropdown: >k::ComboBoxText| { - match state_for_dropdown.borrow_mut().channel { - Some(ref mut channel) => {channel.stream.stop().ok();}, + match state_for_dropdown.borrow_mut().pa_stream { + Some(ref mut stream) => {stream.stop().ok();}, _ => {} } - let selected_mic = dropdown.get_active_id().and_then(|id| id.parse().ok()).expect("Dropdown did not change to a valid value"); - let channel = ::audio::start_listening(&state_for_dropdown.borrow().pa, selected_mic).ok(); - if channel.is_none() { + let stream = ::audio::start_listening(&state_for_dropdown.borrow().pa, selected_mic, mic_sender.clone()).ok(); + if stream.is_none() { writeln!(io::stderr(), "Failed to open audio channel").ok(); } - state_for_dropdown.borrow_mut().channel = channel; + state_for_dropdown.borrow_mut().pa_stream = stream; }); } + let async_thread = thread::spawn(move || { + for samples in mic_receiver { + let frequency_domain = ::transforms::fft(samples, 44100.0); + + let max_frequency = frequency_domain.iter() + .fold(None as Option<::transforms::FrequencyBucket>, |max, next| + if max.is_none() || max.clone().unwrap().intensity < next.intensity { Some(next.clone()) } else { max } + ).unwrap().max_freq; + println!("{}Hz", max_frequency.floor()); + } + }); + gtk::main(); Ok(()) } |