diff --git a/src/bin/main.rs b/src/bin/main.rs index f41ba18..a6b8d89 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -4,7 +4,7 @@ use std::{ }; use anyhow::{anyhow, Result}; -use midi_keys::{log::load_raw_log, parser::parse_message}; +use midi_keys::{log::load_raw_log, midi::daemon::Category, parser::parse_message}; //use enigo::{Direction, Enigo, Key, Keyboard, Settings}; use midir::{MidiInput, MidiInputPort}; @@ -13,14 +13,24 @@ fn main() { //enigo.text("echo \"hello world\"").unwrap(); //enigo.key(Key::Return, Direction::Press).unwrap(); - midi_keys::midi::daemon::run_daemon(); - midi_keys::ui::run(); + let (send, receive) = crossbeam::channel::unbounded(); + let all = Category::All; + std::thread::spawn(move || { + midi_keys::midi::daemon::run_daemon(vec![(all, send)]); + }); + + std::thread::spawn(move || loop { + match receive.recv() { + Ok(m) => println!("got: {m:?}"), + Err(err) => println!("err: {err:?}"), + } + }); + + midi_keys::ui::run(); } pub fn run() -> Result<()> { - midi_keys::midi::daemon::run_daemon(); - let midi_in = MidiInput::new("keyboard")?; let midi_device = match find_first_midi_device(&midi_in) { diff --git a/src/midi/daemon.rs b/src/midi/daemon.rs index fe070f0..a703b2c 100644 --- a/src/midi/daemon.rs +++ b/src/midi/daemon.rs @@ -1,15 +1,17 @@ -use std::{ - collections::HashMap, - sync::mpsc::{self, Receiver, Sender}, -}; +use std::{collections::HashMap, time::Duration}; +use crossbeam::{ + channel::{Receiver, Sender}, + select, +}; use midir::{MidiInput, MidiInputConnection, MidiInputPort}; use crate::parser::parse_message; use super::Message; -enum Category { +pub enum Category { + All, Drums, WindSynth, Piano, @@ -35,31 +37,54 @@ enum Category { type ConnectionId = String; type Timestamp = u64; type TimestampedMessage = (Timestamp, Message); +type CTM = (ConnectionId, Timestamp, Message); -pub fn run_daemon() { +type MidiSend = crossbeam::channel::Sender; +type MidiRecv = crossbeam::channel::Receiver; + +pub fn run_daemon(routes: Vec<(Category, MidiSend)>) { let mut state = State::new(); + let messages = state.message_queue(); + + let ticker = crossbeam::channel::tick(Duration::from_millis(250)); loop { - state.refresh_ports(); - std::thread::sleep_ms(250); + select! { + recv(ticker) -> m => match m { + Ok(ts) => { + println!("refreshing ports at {ts:?}"); + state.refresh_ports(); + } + Err(e) => { + println!("borken {e:?}"); + } + }, + recv(messages) -> m => match m { + Ok(ctm) => { + for (_cat, q) in routes.iter() { + q.send(ctm.clone()); + } + } + Err(e) => { + println!("borken2 {e:?}"); + } + }, + } } } pub struct State { midi: MidiInput, ports: Vec, - connections: HashMap< - String, - MidiInputConnection<(ConnectionId, Sender<(ConnectionId, TimestampedMessage)>)>, - >, + connections: HashMap)>>, - message_receive: Receiver<(ConnectionId, TimestampedMessage)>, - message_send: Sender<(ConnectionId, TimestampedMessage)>, + message_receive: Receiver, + message_send: Sender, } impl State { pub fn new() -> State { - let (tx, rx) = mpsc::channel(); + let (tx, rx) = crossbeam::channel::unbounded(); State { midi: MidiInput::new("midi-keys daemon").expect("could not connect to system MIDI"), @@ -70,24 +95,21 @@ impl State { } } - pub fn refresh_ports(&mut self) { - let start = std::time::Instant::now(); + pub fn message_queue(&self) -> Receiver { + self.message_receive.clone() + } + pub fn refresh_ports(&mut self) { let ports = self.midi.ports(); for port in ports.iter() { self.refresh_port(port); } self.ports = ports; - - let duration = std::time::Instant::now().duration_since(start).as_micros(); - println!("refreshing ports took {} microseconds", duration); } pub fn refresh_port(&mut self, port: &MidiInputPort) { - let start = std::time::Instant::now(); let connected = self.connections.contains_key(&port.id()); - println!("checking conn took {} microseconds", std::time::Instant::now().duration_since(start).as_micros()); let name = match self.midi.port_name(port) { Ok(s) => s, Err(_) => { @@ -99,16 +121,12 @@ impl State { } }; - println!("getting name took {} microseconds", std::time::Instant::now().duration_since(start).as_micros()); - if connected { return; } let midi = MidiInput::new("midi-keys").expect("could not connect to system MIDI"); - println!("midi input init took {} microseconds", std::time::Instant::now().duration_since(start).as_micros()); let send_queue = self.message_send.clone(); - println!("cloning queue took {} microseconds", std::time::Instant::now().duration_since(start).as_micros()); if let Ok(conn) = midi.connect( &port, @@ -120,19 +138,12 @@ impl State { ) { self.connections.insert(port.id(), conn); } - println!("midi conn took {} microseconds", std::time::Instant::now().duration_since(start).as_micros()); } } -fn handle_message( - ts: Timestamp, - bytes: &[u8], - conn_id: &ConnectionId, - tx: &Sender<(ConnectionId, TimestampedMessage)>, -) { +fn handle_message(ts: Timestamp, bytes: &[u8], conn_id: &ConnectionId, tx: &Sender) { if let Ok((_rem, msg)) = parse_message(bytes) { - let _ = tx.send((conn_id.clone(), (ts, msg))); + let _ = tx.send((conn_id.clone(), ts, msg)); } } // TODO: chain of handlers? -> handle event as keypress, send to UI -