paired with anya, thank youuuu
This commit is contained in:
parent
bfbf0e62c0
commit
6f6b0721fe
2 changed files with 61 additions and 40 deletions
|
@ -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) {
|
||||
|
|
|
@ -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<CTM>;
|
||||
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 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<MidiInputPort>,
|
||||
connections: HashMap<
|
||||
String,
|
||||
MidiInputConnection<(ConnectionId, Sender<(ConnectionId, TimestampedMessage)>)>,
|
||||
>,
|
||||
connections: HashMap<String, MidiInputConnection<(ConnectionId, Sender<CTM>)>>,
|
||||
|
||||
message_receive: Receiver<(ConnectionId, TimestampedMessage)>,
|
||||
message_send: Sender<(ConnectionId, TimestampedMessage)>,
|
||||
message_receive: Receiver<CTM>,
|
||||
message_send: Sender<CTM>,
|
||||
}
|
||||
|
||||
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<CTM> {
|
||||
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<CTM>) {
|
||||
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
|
||||
|
||||
|
|
Loading…
Reference in a new issue