start ui: implement sending ports to the display thread from a background thread

This commit is contained in:
Nicole Tietz-Sokolskaya 2024-12-20 17:07:12 -05:00
parent de6dd59e48
commit 40c08b91fb
3 changed files with 48 additions and 10 deletions

View file

@ -15,15 +15,9 @@ fn main() {
midi_keys::ui::run(); midi_keys::ui::run();
match run() {
Ok(_) => {}
Err(err) => {
println!("Ended with error: {}", err);
}
}
} }
fn run() -> Result<()> { pub fn run() -> Result<()> {
let midi_in = MidiInput::new("keyboard")?; let midi_in = MidiInput::new("keyboard")?;
let midi_device = match find_first_midi_device(&midi_in) { let midi_device = match find_first_midi_device(&midi_in) {

View file

@ -1,6 +1,5 @@
use nom::{ use nom::{
bytes::complete::{tag, take, take_till}, bytes::complete::{tag, take, take_till},
combinator::opt,
IResult, IResult,
}; };

View file

@ -1,8 +1,12 @@
use std::time::Instant; use std::{sync::Arc, thread::JoinHandle, time::Instant};
use egui::mutex::Mutex;
use midir::{MidiInput, MidiInputPort};
/// Launches the UI and runs it until it's done executing. /// Launches the UI and runs it until it's done executing.
pub fn run() { pub fn run() {
let native_options = eframe::NativeOptions::default(); let native_options = eframe::NativeOptions::default();
// TODO: don't ignore result // TODO: don't ignore result
let _ = eframe::run_native( let _ = eframe::run_native(
"Midi Keys", "Midi Keys",
@ -13,21 +17,32 @@ pub fn run() {
struct MidiKeysApp { struct MidiKeysApp {
previous_frame_time: Instant, previous_frame_time: Instant,
midi_input_ports: Arc<Mutex<Vec<MidiInputPort>>>,
midi_in: MidiInput,
} }
impl MidiKeysApp { impl MidiKeysApp {
fn new(_cc: &eframe::CreationContext<'_>) -> Self { fn new(_cc: &eframe::CreationContext<'_>) -> Self {
// this is where to hook in for customizing eguji, like fonts and visuals. // this is where to hook in for customizing eguji, like fonts and visuals.
let midi_in: MidiInput =
MidiInput::new("midi-keys").expect("could not connect to system MIDI");
let midi_input_ports = Arc::new(Mutex::new(Vec::new()));
// TODO: have a way to shut down the midi daemon?
let _ = launch_midi_daemon(midi_input_ports.clone());
let previous_frame_time = Instant::now(); let previous_frame_time = Instant::now();
MidiKeysApp { MidiKeysApp {
previous_frame_time, previous_frame_time,
midi_input_ports,
midi_in,
} }
} }
} }
impl eframe::App for MidiKeysApp { impl eframe::App for MidiKeysApp {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
let duration = self.previous_frame_time.elapsed().as_secs_f32(); let duration = self.previous_frame_time.elapsed().as_secs_f32();
self.previous_frame_time = Instant::now(); self.previous_frame_time = Instant::now();
@ -36,6 +51,36 @@ impl eframe::App for MidiKeysApp {
let framerate = format!("{:>8.2}", 1. / duration); let framerate = format!("{:>8.2}", 1. / duration);
ui.label(framerate); ui.label(framerate);
for input_port in self.midi_input_ports.lock().iter() {
let port_name = self
.midi_in
.port_name(input_port)
.unwrap_or("unknown".to_string());
ui.label(port_name);
}
}); });
} }
} }
pub fn launch_midi_daemon(target_field: Arc<Mutex<Vec<MidiInputPort>>>) -> JoinHandle<()> {
let daemon_handle = std::thread::spawn(move || midi_daemon(target_field));
daemon_handle
}
pub fn midi_daemon(target_field: Arc<Mutex<Vec<MidiInputPort>>>) {
let midi_in: MidiInput = MidiInput::new("midi-keys").expect("could not connect to system MIDI");
loop {
let midi_input_ports = get_connnected_midi_devices(&midi_in);
*target_field.lock() = midi_input_ports;
std::thread::sleep(std::time::Duration::from_millis(100));
}
}
pub fn get_connnected_midi_devices(midi_in: &MidiInput) -> Vec<MidiInputPort> {
midi_in.ports()
}