From 5f68c90c23d0301b80f44ea2d910e931557eea8d Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Sat, 14 Jan 2017 23:09:44 +0200 Subject: Added graph drawing of FFT --- src/gui.rs | 85 +++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/gui.rs b/src/gui.rs index 5591cd7..aa4d817 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -17,32 +17,35 @@ struct RustyUi { struct ApplicationState { pa: pa::PortAudio, - pa_stream: Option>> + pa_stream: Option>>, + freq_spectrum: Vec<::transforms::FrequencyBucket>, + ui: RustyUi } 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(); + try!(gtk::init().map_err(|_| "Failed to initialize GTK.")); + let state = Rc::new(RefCell::new(ApplicationState { pa: pa, - pa_stream: None + pa_stream: None, + freq_spectrum: Vec::new(), + ui: create_window(microphones) })); - - try!(gtk::init().map_err(|_| "Failed to initialize GTK.")); - - let ui = create_window(microphones); - - connect_dropdown_choose_microphone(&ui.dropdown, mic_sender, state.clone()); + //let ui = create_window(microphones); + + let (mic_sender, mic_receiver) = channel(); let (pitch_sender, pitch_receiver) = channel(); let (freq_sender, freq_receiver) = channel(); + + connect_dropdown_choose_microphone(mic_sender, state.clone()); start_processing_audio(mic_receiver, pitch_sender, freq_sender); - - setup_pitch_label_callbacks(ui.pitch_label, pitch_receiver); - setup_drawing_area_callbacks(ui.freq_chart, freq_receiver); + setup_pitch_label_callbacks(pitch_receiver, state.clone()); + setup_drawing_area_callbacks(freq_receiver, state.clone()); gtk::main(); Ok(()) @@ -86,7 +89,9 @@ fn set_dropdown_items(dropdown: >k::ComboBoxText, microphones: Vec<(u32, Strin } } -fn connect_dropdown_choose_microphone(dropdown: >k::ComboBoxText, mic_sender: Sender>, state: Rc>) { +fn connect_dropdown_choose_microphone(mic_sender: Sender>, state: Rc>) { + let outer_state = state.clone(); + let ref dropdown = outer_state.borrow().ui.dropdown; dropdown.connect_changed(move |dropdown: >k::ComboBoxText| { match state.borrow_mut().pa_stream { Some(ref mut stream) => {stream.stop().ok();}, @@ -119,7 +124,7 @@ fn start_processing_audio(mic_receiver: Receiver>, pitch_sender: Sender }); } -fn setup_pitch_label_callbacks(pitch_label: gtk::Label, pitch_receiver: Receiver) { +fn setup_pitch_label_callbacks(pitch_receiver: Receiver, state: Rc>) { gtk::timeout_add(100, move || { let mut pitch = None; loop { @@ -130,29 +135,57 @@ fn setup_pitch_label_callbacks(pitch_label: gtk::Label, pitch_receiver: Receiver pitch = next; } match pitch { - Some(pitch) => {pitch_label.set_label(pitch.as_ref());}, + Some(pitch) => {state.borrow().ui.pitch_label.set_label(pitch.as_ref());}, None => {} }; + state.borrow().ui.freq_chart.queue_draw(); gtk::Continue(true) }); } -fn setup_drawing_area_callbacks(canvas: gtk::DrawingArea, freq_receiver: Receiver>) { - canvas.connect_draw(move |ref canvas, ref context| { - let mut last_signal = Vec::new(); - loop { - let next = freq_receiver.try_recv().ok(); - if next.is_none() { - break; - } - last_signal = next.unwrap(); - } +fn setup_drawing_area_callbacks(spectrum_receiver: Receiver>, state: Rc>) { + setup_frequency_spectrum_callback(spectrum_receiver, state.clone()); + let outer_state = state.clone(); + let ref canvas = outer_state.borrow().ui.freq_chart; + canvas.connect_draw(move |ref canvas, ref context| { + let ref spectrum = state.borrow().freq_spectrum; + let width = canvas.get_allocated_width() as f64; + let height = canvas.get_allocated_height() as f64; + let max = spectrum.iter().map(|x| x.intensity).fold(0.0, |max, x| if max > x { max } else { x }); + let len = spectrum.len() as f64; + context.new_path(); context.move_to(0.0, 0.0); - context.line_to(canvas.get_allocated_width() as f64, canvas.get_allocated_height() as f64); + + for (i, bucket) in spectrum.iter().enumerate() { + let x = i as f64 * width / len; + let y = height - (bucket.intensity * height / max); + context.line_to(x, y); + } + context.stroke(); gtk::Inhibit(false) }); } + +fn setup_frequency_spectrum_callback(spectrum_receiver: Receiver>, state: Rc>) { + gtk::timeout_add(100, move || { + let mut spectrum = None; + loop { + let next = spectrum_receiver.try_recv().ok(); + if next.is_none() { + break; + } + spectrum = next; + } + match spectrum { + Some(spectrum) => { + state.borrow_mut().freq_spectrum = spectrum; + }, + None => {} + }; + gtk::Continue(true) + }); +} -- cgit v1.2.3