summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Worthe <justin@worthe-it.co.za>2017-12-26 13:04:37 +0200
committerJustin Worthe <justin@worthe-it.co.za>2017-12-26 13:04:37 +0200
commitbbce5d68e2a6007fc8b023bf694ec058373b718c (patch)
tree03c14e541f826ca1d1c380bc26589cd5b6826242
parent5e0a70fa9b181637942d3d0d55f6a51c33fefbad (diff)
Moved overall model updating logic out of the GUI layer
This will be useful eventually for sharing a bit more overall application logic with the wasm build.
-rw-r--r--Cargo.lock20
-rw-r--r--src/gui.rs45
-rw-r--r--src/lib.rs2
-rw-r--r--src/model.rs35
4 files changed, 58 insertions, 44 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7e72f64..b55058d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,13 +1,3 @@
-[root]
-name = "rusty_microphone"
-version = "0.1.0"
-dependencies = [
- "bencher 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "cairo-rs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "gtk 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "portaudio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "atk-sys"
version = "0.3.4"
@@ -304,6 +294,16 @@ dependencies = [
]
[[package]]
+name = "rusty_microphone"
+version = "0.1.0"
+dependencies = [
+ "bencher 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cairo-rs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gtk 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "portaudio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/gui.rs b/src/gui.rs
index c25826a..f0d998e 100644
--- a/src/gui.rs
+++ b/src/gui.rs
@@ -10,6 +10,8 @@ use std::io::Write;
use std::thread;
use std::sync::mpsc::*;
+use model::Model;
+
const FPS: u32 = 60;
struct RustyUi {
@@ -28,14 +30,6 @@ struct ApplicationState {
ui: RustyUi
}
-struct CrossThreadState {
- fundamental_frequency: Option<f32>,
- pitch: String,
- error: Option<f32>,
- signal: Vec<f32>,
- correlation: Vec<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()));
@@ -49,13 +43,7 @@ pub fn start_gui() -> Result<(), String> {
ui: create_window(microphones, default_microphone)
}));
- let cross_thread_state = Arc::new(RwLock::new(CrossThreadState {
- fundamental_frequency: None,
- pitch: String::new(),
- error: None,
- signal: Vec::new(),
- correlation: Vec::new()
- }));
+ let cross_thread_state = Arc::new(RwLock::new(Model::new()));
let (mic_sender, mic_receiver) = channel();
@@ -160,28 +148,17 @@ fn start_listening_current_dropdown_value(dropdown: &gtk::ComboBoxText, mic_send
state.borrow_mut().pa_stream = stream;
}
-fn start_processing_audio(mic_receiver: Receiver<Vec<f32>>, cross_thread_state: Arc<RwLock<CrossThreadState>>) {
+fn start_processing_audio(mic_receiver: Receiver<Vec<f32>>, cross_thread_state: Arc<RwLock<Model>>) {
thread::spawn(move || {
while let Ok(samples) = mic_receiver.recv() {
//just in case we hit performance difficulties, clear out the channel
while mic_receiver.try_recv().ok() != None {}
- let signal = ::transforms::align_to_rising_edge(&samples);
- let correlation = ::transforms::correlation(&samples);
- let fundamental = ::transforms::find_fundamental_frequency(&samples, ::audio::SAMPLE_RATE);
- let pitch = match fundamental {
- Some(fundamental) => ::transforms::hz_to_pitch(fundamental),
- None => String::new()
- };
- let error = fundamental.map(::transforms::hz_to_cents_error);
+ let new_model = Model::from_signal(&samples, ::audio::SAMPLE_RATE);
match cross_thread_state.write() {
- Ok(mut state) => {
- state.fundamental_frequency = fundamental;
- state.pitch = pitch;
- state.signal = signal;
- state.correlation = correlation;
- state.error = error;
+ Ok(mut model) => {
+ *model = new_model
},
Err(err) => {
println!("Error updating cross thread state: {}", err);
@@ -191,7 +168,7 @@ fn start_processing_audio(mic_receiver: Receiver<Vec<f32>>, cross_thread_state:
});
}
-fn setup_pitch_label_callbacks(state: Rc<RefCell<ApplicationState>>, cross_thread_state: Arc<RwLock<CrossThreadState>>) {
+fn setup_pitch_label_callbacks(state: Rc<RefCell<ApplicationState>>, cross_thread_state: Arc<RwLock<Model>>) {
gtk::timeout_add(1000/FPS, move || {
let ui = &state.borrow().ui;
if let Ok(cross_thread_state) = cross_thread_state.read() {
@@ -206,7 +183,7 @@ fn setup_pitch_label_callbacks(state: Rc<RefCell<ApplicationState>>, cross_threa
});
}
-fn setup_pitch_error_indicator_callbacks(state: Rc<RefCell<ApplicationState>>, cross_thread_state: Arc<RwLock<CrossThreadState>>) {
+fn setup_pitch_error_indicator_callbacks(state: Rc<RefCell<ApplicationState>>, cross_thread_state: Arc<RwLock<Model>>) {
let outer_state = state.clone();
let canvas = &outer_state.borrow().ui.pitch_error_indicator;
canvas.connect_draw(move |canvas, context| {
@@ -246,7 +223,7 @@ fn setup_pitch_error_indicator_callbacks(state: Rc<RefCell<ApplicationState>>, c
});
}
-fn setup_oscilloscope_drawing_area_callbacks(state: Rc<RefCell<ApplicationState>>, cross_thread_state: Arc<RwLock<CrossThreadState>>) {
+fn setup_oscilloscope_drawing_area_callbacks(state: Rc<RefCell<ApplicationState>>, cross_thread_state: Arc<RwLock<Model>>) {
let outer_state = state.clone();
let canvas = &outer_state.borrow().ui.oscilloscope_chart;
canvas.connect_draw(move |canvas, context| {
@@ -279,7 +256,7 @@ fn setup_oscilloscope_drawing_area_callbacks(state: Rc<RefCell<ApplicationState>
});
}
-fn setup_correlation_drawing_area_callbacks(state: Rc<RefCell<ApplicationState>>, cross_thread_state: Arc<RwLock<CrossThreadState>>) {
+fn setup_correlation_drawing_area_callbacks(state: Rc<RefCell<ApplicationState>>, cross_thread_state: Arc<RwLock<Model>>) {
let outer_state = state.clone();
let canvas = &outer_state.borrow().ui.correlation_chart;
canvas.connect_draw(move |canvas, context| {
diff --git a/src/lib.rs b/src/lib.rs
index b053e0c..74aeaf1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,3 +14,5 @@ pub mod audio;
#[cfg(target_os = "emscripten")]
pub mod emscripten_api;
+
+pub mod model;
diff --git a/src/model.rs b/src/model.rs
new file mode 100644
index 0000000..7fad354
--- /dev/null
+++ b/src/model.rs
@@ -0,0 +1,35 @@
+use transforms;
+
+#[derive(Default)]
+pub struct Model {
+ pub fundamental_frequency: Option<f32>,
+ pub pitch: String,
+ pub error: Option<f32>,
+ pub signal: Vec<f32>,
+ pub correlation: Vec<f32>
+}
+
+impl Model {
+ pub fn new() -> Model {
+ Model::default()
+ }
+
+ pub fn from_signal(signal: &[f32], sample_rate: f32) -> Model {
+ let correlation = transforms::correlation(signal);
+ let fundamental = transforms::find_fundamental_frequency(signal, sample_rate);
+ let pitch = fundamental.map_or(
+ String::new(),
+ transforms::hz_to_pitch
+ );
+
+ let error = fundamental.map(transforms::hz_to_cents_error);
+
+ Model {
+ fundamental_frequency: fundamental,
+ pitch: pitch,
+ error: error,
+ signal: transforms::align_to_rising_edge(signal),
+ correlation: correlation
+ }
+ }
+}