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 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) {
|
||||||
|
|
|
@ -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 {
|
||||||
state.refresh_ports();
|
select! {
|
||||||
std::thread::sleep_ms(250);
|
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 {
|
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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue