1mod helpers;
2mod meta_events;
3
4use std::{
5 error::Error,
6 fs,
7 sync::mpsc::{self, Receiver},
8};
9
10use meta_events::extract_meta_events;
11use midly::{Format, Smf, Timing};
12use nodi::Sheet;
13
14use crate::{app, bar, config::Config, player::Player, Response};
15
16pub struct Args {
17 pub config: Config,
18 pub player: Player,
19 pub response: Receiver<Response>,
20}
21
22impl Args {
23 pub fn parse_args() -> Result<Self, Box<dyn Error>> {
24 let m = app::new().get_matches();
25 if m.is_present("list") {
26 helpers::list_devices()?;
27 std::process::exit(0);
28 }
29
30 let mut config = m
31 .value_of("config")
32 .map(Config::read_from)
33 .unwrap_or_else(|| Ok(Config::default()))?;
34
35 if m.is_present("no-color") {
36 config.colors = false;
37 }
38
39 let data = m.value_of("file").map(fs::read).unwrap()?;
40 let device_no = m.value_of("device").unwrap().parse::<usize>()?;
41 let con = helpers::get_midi(device_no)?;
42
43 let Smf { tracks, header } = Smf::parse(&data)?;
44
45 let tpb = match header.timing {
46 Timing::Metrical(n) => u16::from(n),
47 _ => return Err("the midi file has an unsupported time format".into()),
48 };
49
50 let (sender, receiver) = mpsc::channel();
51
52 let (all, sheet) = match header.format {
53 Format::Parallel => {
54 let all = Sheet::parallel(&tracks);
55 let mut sheet = helpers::choose_track(&tracks[0..]);
56 sheet.merge_with(extract_meta_events(&all));
57 (all, sheet)
58 }
59 _ => {
60 let sheet = Sheet::sequential(&tracks);
61 (sheet.clone(), sheet)
62 }
63 };
64
65 let player = Player::new(con, sender, bar::bars(all, tpb), bar::bars(sheet, tpb));
66
67 Ok(Self {
68 player,
69 response: receiver,
70 config,
71 })
72 }
73}