42 lines
1.6 KiB
Rust
42 lines
1.6 KiB
Rust
//! MIDI input. galdr owns a virtual input port named "galdr" (symmetric with
|
|||
|
|
//! orca's virtual output), so orca or any client connects to it in the graph.
|
||
|
|
|
||
|
|
use anyhow::{anyhow, Result};
|
||
|
|
use midir::os::unix::VirtualInput;
|
||
|
|
use midir::{MidiInput, MidiInputConnection};
|
||
|
|
use rtrb::Producer;
|
||
|
|
|
||
|
|
use crate::engine::Event;
|
||
|
|
|
||
|
|
pub fn connect(prod: Producer<Event>, port_name: Option<String>) -> Result<MidiInputConnection<Producer<Event>>> {
|
||
|
|
let mut input = MidiInput::new("galdr").map_err(|e| anyhow!("MIDI init: {e}"))?;
|
||
|
|
input.ignore(midir::Ignore::None);
|
||
|
|
|
||
|
|
let cb = move |_stamp: u64, msg: &[u8], prod: &mut Producer<Event>| {
|
||
|
|
if msg.len() < 2 {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
let status = msg[0] & 0xF0;
|
||
|
|
let ev = match status {
|
||
|
|
0x90 if msg[2] > 0 => Event::NoteOn { note: msg[1], vel: msg[2] },
|
||
|
|
0x80 => Event::NoteOff { note: msg[1] },
|
||
|
|
0x90 => Event::NoteOff { note: msg[1] }, // note-on velocity 0
|
||
|
|
0xB0 => Event::Cc { idx: msg[1], val: msg[2] },
|
||
|
|
_ => return,
|
||
|
|
};
|
||
|
|
let _ = prod.push(ev);
|
||
|
|
};
|
||
|
|
|
||
|
|
if let Some(name) = port_name {
|
||
|
|
let ports = input.ports();
|
||
|
|
let port = ports
|
||
|
|
.iter()
|
||
|
|
.find(|p| input.port_name(p).map(|n| n.contains(&name)).unwrap_or(false))
|
||
|
|
.cloned()
|
||
|
|
.ok_or_else(|| anyhow!("no MIDI input port matching {name:?}"))?;
|
||
|
|
input.connect(&port, "galdr-in", cb, prod).map_err(|e| anyhow!("MIDI connect: {e}"))
|
||
|
|
} else {
|
||
|
|
input.create_virtual("galdr", cb, prod).map_err(|e| anyhow!("create virtual MIDI port: {e}"))
|
||
|
|
}
|
||
|
|
}
|