midnote 0.11.1

A terminal application for viewing notes in a MIDI track, with audio.
Documentation
mod helpers;
mod meta_events;

use std::{
	error::Error,
	fs,
	sync::mpsc::{self, Receiver},
};

use meta_events::extract_meta_events;
use midly::{Format, Smf, Timing};
use nodi::Sheet;

use crate::{app, bar, config::Config, player::Player, Response};

pub struct Args {
	pub config: Config,
	pub player: Player,
	pub response: Receiver<Response>,
}

impl Args {
	pub fn parse_args() -> Result<Self, Box<dyn Error>> {
		let m = app::new().get_matches();
		if m.is_present("list") {
			helpers::list_devices()?;
			std::process::exit(0);
		}

		let mut config = m
			.value_of("config")
			.map(Config::read_from)
			.unwrap_or_else(|| Ok(Config::default()))?;

		if m.is_present("no-color") {
			config.colors = false;
		}

		let data = m.value_of("file").map(fs::read).unwrap()?;
		let device_no = m.value_of("device").unwrap().parse::<usize>()?;
		let con = helpers::get_midi(device_no)?;

		let Smf { tracks, header } = Smf::parse(&data)?;

		let tpb = match header.timing {
			Timing::Metrical(n) => u16::from(n),
			_ => return Err("the midi file has an unsupported time format".into()),
		};

		let (sender, receiver) = mpsc::channel();

		let (all, sheet) = match header.format {
			Format::Parallel => {
				let all = Sheet::parallel(&tracks);
				let mut sheet = helpers::choose_track(&tracks[0..]);
				sheet.merge_with(extract_meta_events(&all));
				(all, sheet)
			}
			_ => {
				let sheet = Sheet::sequential(&tracks);
				(sheet.clone(), sheet)
			}
		};

		let player = Player::new(con, sender, bar::bars(all, tpb), bar::bars(sheet, tpb));

		Ok(Self {
			player,
			response: receiver,
			config,
		})
	}
}