1use lyrica::{MidiFile, MidiOutput, MidiPlayer};
2use std::{
3 env,
4 error::Error,
5 fs,
6 io::{stdin, stdout, Write},
7};
8
9fn main() -> Result<(), Box<dyn Error>> {
10 let args = env::args().collect::<Vec<_>>();
11
12 if args.len() != 2 {
13 println!("usage: {} [filename]", args[0]);
14
15 return Err(format!(
16 "incorrect number of arguments (expected 1, got {})",
17 args.len() - 1
18 )
19 .into());
20 }
21
22 let filename = &args[1];
23
24 let midi_output = MidiOutput::new("lyrica-play")?;
25 let midi_ports = midi_output.ports();
26
27 if midi_ports.is_empty() {
28 eprintln!("there are no MIDI devices available");
29 #[cfg(windows)]
30 eprintln!("if you are on Wine, this is expected behaviour");
31 return Ok(());
32 }
33
34 let port_number = loop {
35 println!("Available MIDI ports:");
36 for (i, port) in midi_ports.iter().enumerate() {
37 println!("{}: {}", i, midi_output.port_name(port)?);
38 }
39
40 print!("Please select a port: ");
41 stdout().flush()?;
42 let mut input = String::new();
43 stdin().read_line(&mut input)?;
44 let trimmed_input = input.trim();
45
46 let port_number = match trimmed_input.parse::<usize>() {
47 Ok(port_number) => port_number,
48
49 Err(_) => {
50 println!("port number must be a number (got {trimmed_input})");
51 continue;
52 }
53 };
54
55 if port_number > midi_output.port_count() {
56 println!(
57 "port number is too high (last port is {})",
58 midi_output.port_count()
59 );
60 continue;
61 }
62
63 break port_number;
64 };
65
66 let connection = midi_output.connect(&midi_ports[port_number], "lyrica-play")?;
67 let file = fs::read(filename)?;
68 let midi_file = MidiFile::from_bytes(&file)?;
69 let mut player = MidiPlayer::new(connection);
70 player.set_midi_file(midi_file)?;
71
72 while !player.is_finished() {
73 player.update()?;
74 }
75
76 Ok(())
77}