lock-free-vumeter/src/main.rs

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();
}