55 lines
1.7 KiB
Rust
55 lines
1.7 KiB
Rust
mod audio;
|
|
mod gui;
|
|
|
|
use std::{
|
|
sync::{atomic::Ordering, Arc},
|
|
thread,
|
|
};
|
|
|
|
const FLOAT_MAX: f64 = i16::max_value() as f64;
|
|
|
|
fn main() {
|
|
// Initialize state shared between audio and GUI threads.
|
|
// The struct itself is Sync and therefore safe to share between
|
|
// threads, but an Arc pointer is used to workaround Rust's
|
|
// ownership rules. Calling `clone` on the pointer increments its
|
|
// internal reference count allowing for safe memory management
|
|
// between threads. This should not cause a runtime penalty inside
|
|
// the audio callback.
|
|
let global_state = Arc::new(audio::AudioState::new());
|
|
let audio_state = global_state.clone();
|
|
let gui_state = global_state.clone();
|
|
|
|
// Spawn a thread for the audio engine:
|
|
thread::spawn(move || {
|
|
audio::start(&audio_state).unwrap();
|
|
});
|
|
|
|
// Setup GUI:
|
|
gui::init().unwrap();
|
|
let the_gui = gui::Gui::new("VUMeter-Rust");
|
|
|
|
// Setup a timer on the main thread to poll the audio state and
|
|
// update the GUI. It takes a second `clone`d copy of the Arc pointer.
|
|
gui::add_timeout(50, move || {
|
|
// Atomically swap the `gui_up_to_date` value:
|
|
let result = gui_state.gui_up_to_date.compare_exchange(
|
|
false,
|
|
true,
|
|
Ordering::SeqCst,
|
|
Ordering::SeqCst,
|
|
);
|
|
|
|
if let Ok(false) = result {
|
|
// if the maximum value has changed, load it into a local
|
|
// variable and convert it to range 0..1.0.
|
|
// Then as we are on the main thread we can update the
|
|
// GUI safely.
|
|
let val = gui_state.max_value.load(Ordering::SeqCst);
|
|
the_gui.set_level((val as f64) / FLOAT_MAX);
|
|
}
|
|
});
|
|
|
|
gui::run();
|
|
}
|