use gtk;
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#"
"#;
struct ApplicationState {
pa: pa::PortAudio,
pa_stream: Option>>
}
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,
pa_stream: None
}));
try!(gtk::init().map_err(|_| "Failed to initialize GTK."));
let gtk_builder = try!(create_window(microphones));
{
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().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 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().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(())
}
fn create_window(microphones: Vec<(u32, String)>) -> Result {
let gtk_builder = gtk::Builder::new_from_string(GUI_XML);
let window: gtk::Window = try!(
gtk_builder.get_object("window")
.ok_or("GUI does not contain an object with id 'window'")
);
window.set_default_size(300, 300);
window.connect_delete_event(|_, _| {
gtk::main_quit();
Inhibit(false)
});
window.show_all();
let dropdown: gtk::ComboBoxText = try!(
gtk_builder.get_object("dropdown")
.ok_or("GUI does not contain an object with id 'dropdown'")
);
set_dropdown_items(&dropdown, microphones);
Ok(gtk_builder)
}
fn set_dropdown_items(dropdown: >k::ComboBoxText, microphones: Vec<(u32, String)>) {
for (index, name) in microphones {
dropdown.append(Some(format!("{}", index).as_ref()), name.as_ref());
}
}