launchkey_sdk/midi/
input.rs1use crate::midi::to_hex::ToHexString;
2use midir::{Ignore, MidiInput, MidiInputConnection};
3use std::io;
4use std::io::Write;
5use std::sync::mpsc;
6use wmidi::{ControlFunction, MidiMessage, U7};
7
8pub fn get_named_midi_ports(midi_in: &MidiInput) -> Vec<(usize, String)> {
9 midi_in
10 .ports()
11 .iter()
12 .enumerate()
13 .filter_map(|(i, port)| midi_in.port_name(port).ok().map(|name| (i, name)))
14 .collect()
15}
16
17pub fn select_port(ports: &[(usize, String)]) -> Option<usize> {
18 println!("Select a MIDI input port:");
19 for (i, name) in ports.iter().enumerate() {
20 println!("{}: {}", i, name.1);
21 }
22
23 print!("Enter port index: ");
24 io::stdout().flush().unwrap();
25
26 let mut input = String::new();
27 io::stdin().read_line(&mut input).unwrap();
28
29 input.trim().parse::<usize>().ok().and_then(
30 |idx| {
31 if idx < ports.len() {
32 Some(idx)
33 } else {
34 None
35 }
36 },
37 )
38}
39
40pub fn connect_to_port(
41 midi_in: MidiInput,
42 port_index: usize,
43 tx: mpsc::Sender<Vec<u8>>,
44) -> Result<MidiInputConnection<()>, String> {
45 let ports = midi_in.ports();
46 let port = ports
47 .get(port_index)
48 .ok_or_else(|| "Invalid port index".to_string())?;
49
50 let conn_in = midi_in
52 .connect(
53 port,
54 "midi-input",
55 move |_timestamp, message, _context| {
56 tx.send(message.to_vec()).unwrap();
57 },
58 (),
59 )
60 .map_err(|_| "Failed to connect to MIDI port".to_string())?;
61
62 Ok(conn_in)
63}
64
65pub fn connect_all_midi_ports(
66 ports: &[(usize, String)],
67 tx: mpsc::Sender<Vec<u8>>,
68) -> Vec<MidiInputConnection<()>> {
69 ports
70 .iter()
71 .filter_map(|(i, name)| {
72 let mut midi_in = MidiInput::new(&format!("{} Listener", name)).ok()?;
73 midi_in.ignore(Ignore::None);
74 connect_to_port(midi_in, *i, tx.clone()).ok()
75 })
76 .collect()
77}
78
79pub fn log_midi_message(message: MidiMessage) {
80 match message {
81 MidiMessage::NoteOff(channel, note, _) => println!("Note Off: {:?} {}", channel, note),
82 MidiMessage::NoteOn(channel, note, velocity) => {
83 println!("Note On: {:?} {} (Velocity: {:?})", channel, note, velocity)
84 }
85 MidiMessage::PolyphonicKeyPressure(_, note, velocity) => println!(
86 "Polyphonic Key Pressure: {} (Velocity: {:?})",
87 note, velocity
88 ),
89 MidiMessage::ControlChange(channel, control_function, value) => println!(
90 "Control Change: {:?} Controller {:?} Value {:?}",
91 channel, control_function, value
92 ),
93 MidiMessage::ProgramChange(_, program_number) => {
94 println!("Program Change: Program {:?}", program_number)
95 }
96 MidiMessage::ChannelPressure(channel, velocity) => {
97 println!("Channel Pressure: {:?} (Velocity: {:?})", channel, velocity)
98 }
99 MidiMessage::PitchBendChange(_, pitch_bend) => println!("Pitch Bend: {:?}", pitch_bend),
100 MidiMessage::SysEx(data) => {
101 println!("SysEx Message: {}", data.to_hex_string());
102 }
103 MidiMessage::Start => println!("Start"),
104 MidiMessage::Continue => println!("Continue"),
105 MidiMessage::Stop => println!("Stop"),
106 _ => {}
107 }
108}
109
110pub trait ControlFunctionExt {
111 fn equals_u8(&self, value: u8) -> bool;
112}
113
114impl ControlFunctionExt for ControlFunction {
115 fn equals_u8(&self, value: u8) -> bool {
116 self.0 == U7::from_u8_lossy(value)
117 }
118}