summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJustin Worthe <justin.worthe@gmail.com>2017-01-14 23:09:44 +0200
committerJustin Worthe <justin.worthe@gmail.com>2017-01-14 23:14:11 +0200
commit5f68c90c23d0301b80f44ea2d910e931557eea8d (patch)
treed099777c311310cd3846b3d8edcb8ec37ea4dc89 /src
parent2c1eadd54522e25a826a106461465d14606e4460 (diff)
Added graph drawing of FFT
Diffstat (limited to 'src')
-rw-r--r--src/gui.rs85
1 files changed, 59 insertions, 26 deletions
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<pa::NonBlocking, pa::Input<f32>>>
+ pa_stream: Option<pa::Stream<pa::NonBlocking, pa::Input<f32>>>,
+ 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: &gtk::ComboBoxText, microphones: Vec<(u32, Strin
}
}
-fn connect_dropdown_choose_microphone(dropdown: &gtk::ComboBoxText, mic_sender: Sender<Vec<f64>>, state: Rc<RefCell<ApplicationState>>) {
+fn connect_dropdown_choose_microphone(mic_sender: Sender<Vec<f64>>, state: Rc<RefCell<ApplicationState>>) {
+ let outer_state = state.clone();
+ let ref dropdown = outer_state.borrow().ui.dropdown;
dropdown.connect_changed(move |dropdown: &gtk::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<Vec<f64>>, pitch_sender: Sender
});
}
-fn setup_pitch_label_callbacks(pitch_label: gtk::Label, pitch_receiver: Receiver<String>) {
+fn setup_pitch_label_callbacks(pitch_receiver: Receiver<String>, state: Rc<RefCell<ApplicationState>>) {
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<Vec<::transforms::FrequencyBucket>>) {
- 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<Vec<::transforms::FrequencyBucket>>, state: Rc<RefCell<ApplicationState>>) {
+ 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<Vec<::transforms::FrequencyBucket>>, state: Rc<RefCell<ApplicationState>>) {
+ 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)
+ });
+}