use std::{ fs::File, io::{stdin, Write}, }; use anyhow::{anyhow, Result}; use midi_keys::{log::load_raw_log, parser::parse_message}; //use enigo::{Direction, Enigo, Key, Keyboard, Settings}; use midir::{MidiInput, MidiInputPort}; fn main() { //let mut enigo = Enigo::new(&Settings::default()).unwrap(); //enigo.text("echo \"hello world\"").unwrap(); //enigo.key(Key::Return, Direction::Press).unwrap(); midi_keys::midi::daemon::run_daemon(); 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) { Ok(m) => m, Err(e) => { println!("error: {}", e); return Ok(()); } }; let port_name = midi_in.port_name(&midi_device)?; let output_file = File::options().append(true).create(true).open("midi.log")?; let _midi_connection = match midi_in.connect( &midi_device, &port_name, handle_midi_event, Some(output_file), ) { Ok(m) => m, Err(err) => return Err(anyhow!("failed to connect to device: {}", err)), }; // TODO: instead, listen for a signal like control-d let mut buf = String::new(); stdin().read_line(&mut buf)?; // TODO let _ = replay_file("assets/windsynth.log"); Ok(()) } fn replay_file(filename: &str) -> Result<()> { let entries = load_raw_log(filename)?; for entry in entries { handle_midi_event(entry.ts, &entry.message, &mut None); } Ok(()) } fn handle_midi_event(timestamp: u64, message: &[u8], file: &mut Option) { if let Some(file) = file { let ts_buf = timestamp.to_be_bytes(); let len_buf = message.len().to_be_bytes(); file.write_all(&ts_buf).unwrap(); file.write_all(&len_buf).unwrap(); file.write_all(message).unwrap(); } let hex_msg = hex::encode(message); let msg = match parse_message(message) { Ok((_n, msg)) => format!("{:?}", msg), Err(_) => "failed to parse message".to_string(), }; println!("{timestamp} > {hex_msg} - {msg}"); } /// Finds the first MIDI input port which corresponds to a physical MIDI device /// connected to this computer. fn find_first_midi_device(midi_in: &MidiInput) -> Result { let ports = midi_in.ports(); // "Midi Through" is automatically created by the snd-seq-dummy kernel module. // We can ignore it, since it's not a physical MIDI device, which is what we // are looking for. // // Source: https://www.reddit.com/r/linuxaudio/comments/jsrl31/comment/gc16qwu/ let mut physical_ports = ports.iter().filter(|p| { midi_in .port_name(p) .map_or(false, |n| !n.starts_with("Midi Through:")) }); physical_ports .next() .cloned() .ok_or(anyhow!("no physical MIDI devices found")) }