paired with anya, thank youuuu

This commit is contained in:
Nicole Tietz-Sokolskaya 2025-01-01 16:17:49 -05:00
parent bfbf0e62c0
commit 6f6b0721fe
2 changed files with 61 additions and 40 deletions

View file

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