Rustを使ったMIDI通信を下記を参考にやってみました。
参考) https://github.com/Boddlnagg/midir/tree/master/examples
他のプログラムとの連携を考えて、名前付きパイプで入力した数値を音程データとして出力するようにしました。
MIDIポートを選択後、そのポートにMIDIノートオン・オフメッセージを出力します。
名前付きパイプには、コンソールからechoコマンドでリダイレクトしたため改行が入力字列の末尾にふくまれます。
そのため文字列末尾を削除しました。
文字列”qqq”を入力すると終了します。
環境) macOS HighSierra
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
extern crate midir; use std::fs::File; use std::error::Error; use std::io::{stdin, stdout, Write, BufRead, BufReader}; use std::thread::sleep; use std::time::Duration; use midir::{MidiOutput, MidiIO, MidiOutputConnection}; fn play_note(conn_out: &mut MidiOutputConnection, note: u8, duration: u64) { const NOTE_ON_MSG: u8 = 0x90; const NOTE_OFF_MSG: u8 = 0x80; const VELOCITY: u8 = 0x64; let _ = conn_out.send(&[NOTE_ON_MSG, note, VELOCITY]); sleep(Duration::from_millis(duration * 150)); let _ = conn_out.send(&[NOTE_OFF_MSG, note, VELOCITY]); } fn main() -> Result<(), Box<dyn std::error::Error>> { let mut buf = String::new(); let midi_out = MidiOutput::new("midir forwarding output")?; let out_port = select_port(&midi_out, "output")?; let out_port_name = midi_out.port_name(&out_port)?; let mut conn_out = midi_out.connect(&out_port, "midir-forward")?; println!("out port: {}", out_port_name); let mut reader = BufReader::new(File::open("/tmp/ff")?); // named pipe loop { reader.read_line(&mut buf); print!("{}", buf); if buf.len() > 0 { buf.pop(); if buf == "qqq".to_string() { println!("quit"); break; } match buf.parse(){ Ok(num) => play_note(&mut conn_out, num, 1), Err(_e) => () } } buf.clear(); } Ok(()) } fn select_port<T: MidiIO>(midi_io: &T, descr: &str) -> Result<T::Port, Box<dyn Error>> { println!("Available {} ports:", descr); let midi_ports = midi_io.ports(); for (i, p) in midi_ports.iter().enumerate() { println!("{}: {}", i, midi_io.port_name(p)?); } print!("Please select {} port: ", descr); stdout().flush()?; let mut input = String::new(); stdin().read_line(&mut input)?; let port = midi_ports.get(input.trim().parse::<usize>()?) .ok_or("Invalid port number")?; Ok(port.clone()) } |
ノートオフタイミングは固定になっていますが、ノートオフデータも入力するのか、ノートオン時間も入力して計測してノートオフするのか、用途に応じて考えたいと思います。