cnctd_midi/
lib.rs

1use std::{sync::{mpsc, Arc, Mutex}, thread, time::Duration};
2
3use midi_message::MidiMessage;
4use midir::{MidiInput, MidiOutput};
5use anyhow::anyhow;
6// use tune::midi::ChannelMessage;
7
8pub mod midi_message;
9pub struct Midi;
10
11impl Midi {
12
13    pub fn get_devices() -> anyhow::Result<(Vec<String>, Vec<String>)> {
14        let input = MidiInput::new("inputs")?;
15        let output = MidiOutput::new("outputs")?;
16        let mut input_devices: Vec<String> = vec![];
17        let mut output_devices: Vec<String> = vec![];
18        for (_i, p) in input.ports().iter().enumerate() {
19            input_devices.push(input.port_name(p)?);
20        }
21        for (_i, p) in output.ports().iter().enumerate() {
22            output_devices.push(output.port_name(p)?);
23        }
24        let inputs = input_devices.clone();
25        let outputs = output_devices.clone();
26        Ok((inputs, outputs))
27    }
28
29    pub fn listen_to_device(device: &str, tx: mpsc::Sender<MidiMessage>) -> anyhow::Result<()> {
30        let midi_input = MidiInput::new("inputs")?;
31        let in_port = Self::find_port(&midi_input, device).ok_or_else(|| anyhow!("Midi device not connected"))?;
32
33        let tx = Arc::new(Mutex::new(tx)); // Wrap the sender in Arc and Mutex for safe sharing across threads
34
35        let _conn_in = midi_input.connect(&in_port, "midir-read-input", 
36            move |stamp, message, _,| {
37                let tx = tx.clone(); // Clone the Arc to share across threads
38                let message = message.to_owned(); // Clone the message data
39                if let Some(msg) = MidiMessage::from_raw_message(&message, stamp) {
40                    let tx = tx.lock().unwrap();
41                    tx.send(msg).unwrap(); // Send the message through the channel
42                }
43            }, 
44            (),
45        );
46
47        loop {
48            thread::sleep(Duration::from_secs(10))
49        }
50    }
51
52    fn find_port<T>(midi_io: &T, device: &str) -> Option<T::Port> where T: midir::MidiIO {
53        let mut device_port: Option<T::Port> = None;
54        for port in midi_io.ports() {
55            
56            if let Ok(port_name) = midi_io.port_name(&port) {
57                // println!("port name: {} | device: {}", port_name, device);
58                if port_name.contains(device) {
59                    device_port = Some(port);
60                    break;
61                }
62            }
63        }
64        device_port
65    }
66    
67}
68