From 40c08b91fb5b3961e8ce4f7df7856f73c79696fb Mon Sep 17 00:00:00 2001 From: Nicole Tietz-Sokolskaya <me@ntietz.com> Date: Fri, 20 Dec 2024 17:07:12 -0500 Subject: [PATCH] start ui: implement sending ports to the display thread from a background thread --- src/bin/main.rs | 8 +------- src/parser.rs | 1 - src/ui.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 78d6c3e..1abcf2e 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -15,15 +15,9 @@ fn main() { 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_device = match find_first_midi_device(&midi_in) { diff --git a/src/parser.rs b/src/parser.rs index 0b7cadf..8d98516 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,5 @@ use nom::{ bytes::complete::{tag, take, take_till}, - combinator::opt, IResult, }; diff --git a/src/ui.rs b/src/ui.rs index b97d7a0..ed9ed9a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -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. pub fn run() { let native_options = eframe::NativeOptions::default(); + // TODO: don't ignore result let _ = eframe::run_native( "Midi Keys", @@ -13,21 +17,32 @@ pub fn run() { struct MidiKeysApp { previous_frame_time: Instant, + midi_input_ports: Arc<Mutex<Vec<MidiInputPort>>>, + midi_in: MidiInput, } impl MidiKeysApp { fn new(_cc: &eframe::CreationContext<'_>) -> Self { // 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(); MidiKeysApp { previous_frame_time, + midi_input_ports, + midi_in, } } } 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(); self.previous_frame_time = Instant::now(); @@ -36,6 +51,36 @@ impl eframe::App for MidiKeysApp { let framerate = format!("{:>8.2}", 1. / duration); 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() +}