diff --git a/src/bin/main.rs b/src/bin/main.rs index a6b8d89..f17b5ac 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -13,19 +13,37 @@ fn main() { //enigo.text("echo \"hello world\"").unwrap(); //enigo.key(Key::Return, Direction::Press).unwrap(); - let (send, receive) = crossbeam::channel::unbounded(); + let (dbg_send, dbg_recv) = crossbeam::channel::unbounded(); + let (ws_send, ws_recv) = crossbeam::channel::unbounded(); + let (drum_send, drum_recv) = crossbeam::channel::unbounded(); let all = Category::All; std::thread::spawn(move || { - midi_keys::midi::daemon::run_daemon(vec![(all, send)]); + midi_keys::midi::daemon::run_daemon(vec![ + (all, dbg_send), + (Category::WindSynth, ws_send), + (Category::Drums, drum_send), + ]); }); std::thread::spawn(move || loop { - match receive.recv() { - Ok(m) => println!("got: {m:?}"), + match dbg_recv.recv() { + Ok(m) => println!("debug: {m:?}"), Err(err) => println!("err: {err:?}"), } }); + std::thread::spawn(move || loop { + match ws_recv.recv() { + Ok(m) => println!("windsynth: {m:?}"), + Err(err) => println!("err(ws): {err:?}"), + } + }); + std::thread::spawn(move || loop { + match drum_recv.recv() { + Ok(m) => println!("drum: {m:?}"), + Err(err) => println!("err(drum): {err:?}"), + } + }); midi_keys::ui::run(); } diff --git a/src/midi/daemon.rs b/src/midi/daemon.rs index a703b2c..f232c1f 100644 --- a/src/midi/daemon.rs +++ b/src/midi/daemon.rs @@ -10,6 +10,7 @@ use crate::parser::parse_message; use super::Message; +#[derive(PartialEq, Eq, Debug)] pub enum Category { All, Drums, @@ -36,7 +37,6 @@ pub enum Category { type ConnectionId = String; type Timestamp = u64; -type TimestampedMessage = (Timestamp, Message); type CTM = (ConnectionId, Timestamp, Message); type MidiSend = crossbeam::channel::Sender<CTM>; @@ -44,25 +44,39 @@ type MidiRecv = crossbeam::channel::Receiver<CTM>; pub fn run_daemon(routes: Vec<(Category, MidiSend)>) { let mut state = State::new(); - let messages = state.message_queue(); + let mut conn_mapping: HashMap<ConnectionId, Category> = HashMap::new(); + + let messages_q = state.message_queue(); + let conn_mapping_q = state.connection_mapping_queue(); let ticker = crossbeam::channel::tick(Duration::from_millis(250)); loop { select! { recv(ticker) -> m => match m { - Ok(ts) => { - println!("refreshing ports at {ts:?}"); + Ok(_ts) => { state.refresh_ports(); } Err(e) => { println!("borken {e:?}"); } }, - recv(messages) -> m => match m { + recv(conn_mapping_q) -> m => match m { + Ok((conn_id, category)) => { + conn_mapping.insert(conn_id, category); + }, + Err(e) => { + println!("borken3 {e:?}"); + } + }, + recv(messages_q) -> m => match m { Ok(ctm) => { - for (_cat, q) in routes.iter() { - q.send(ctm.clone()); + let (cid, _ts, _msg) = &ctm; + let msg_cat = conn_mapping.get(cid).unwrap_or(&Category::Ignore); + for (route_cat, q) in routes.iter() { + if route_cat == msg_cat || *route_cat == Category::All { + let _ = q.send(ctm.clone()); + } } } Err(e) => { @@ -80,18 +94,24 @@ pub struct State { message_receive: Receiver<CTM>, message_send: Sender<CTM>, + + conn_map_receive: Receiver<(ConnectionId, Category)>, + conn_map_send: Sender<(ConnectionId, Category)>, } impl State { pub fn new() -> State { - let (tx, rx) = crossbeam::channel::unbounded(); + let (msg_tx, msg_rx) = crossbeam::channel::unbounded(); + let (conn_tx, conn_rx) = crossbeam::channel::unbounded(); State { midi: MidiInput::new("midi-keys daemon").expect("could not connect to system MIDI"), ports: vec![], connections: HashMap::new(), - message_receive: rx, - message_send: tx, + message_receive: msg_rx, + message_send: msg_tx, + conn_map_receive: conn_rx, + conn_map_send: conn_tx, } } @@ -99,6 +119,10 @@ impl State { self.message_receive.clone() } + pub fn connection_mapping_queue(&self) -> Receiver<(ConnectionId, Category)> { + self.conn_map_receive.clone() + } + pub fn refresh_ports(&mut self) { let ports = self.midi.ports(); for port in ports.iter() { @@ -136,11 +160,28 @@ impl State { }, (port.id(), send_queue), ) { + let category = guess_catgory(&name); + println!("guessing category:"); + println!(" name> {name}"); + println!(" id> {}", port.id()); + println!(" cat> {category:?}"); + + let _ = self.conn_map_send.send((port.id(), category)); // TODO error handler self.connections.insert(port.id(), conn); } } } +fn guess_catgory(name: &str) -> Category { + if name.contains("TravelSax2") || name.contains("AE-20") { + Category::WindSynth + } else if name.contains("MultiPad") { + Category::Drums + } else { + Category::Ignore + } +} + fn handle_message(ts: Timestamp, bytes: &[u8], conn_id: &ConnectionId, tx: &Sender<CTM>) { if let Ok((_rem, msg)) = parse_message(bytes) { let _ = tx.send((conn_id.clone(), ts, msg)); diff --git a/src/ui.rs b/src/ui.rs index 552d06b..870bd5c 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -156,9 +156,7 @@ impl eframe::App for MidiKeysApp { } } -struct MidiDaemon { - -} +struct MidiDaemon {} pub fn launch_midi_daemon(target_field: Arc<Mutex<Vec<MidiInputPort>>>) -> JoinHandle<()> { let daemon_handle = std::thread::spawn(move || midi_daemon(target_field));