pub use tek::*; pub(crate) use clap::{self, Parser, Subcommand}; /// Application entrypoint. pub fn main () -> Usually<()> { Cli::parse().run() } #[derive(Debug, Parser)] #[command(version, about = Some(HEADER), long_about = Some(HEADER))] pub struct Cli { /// Which app to initialize #[command(subcommand)] mode: Mode, /// Name of JACK client #[arg(short='n', long)] name: Option, /// Whether to attempt to become transport master #[arg(short='S', long, default_value_t = false)] sync_lead: bool, /// Whether to sync to external transport master #[arg(short='s', long, default_value_t = true)] sync_follow: bool, /// Initial tempo in beats per minute #[arg(short='b', long, default_value = None)] bpm: Option, /// Whether to include a transport toolbar (default: true) #[arg(short='t', long, default_value_t = true)] show_clock: bool, /// MIDI outs to connect to (multiple instances accepted) #[arg(short='I', long)] midi_from: Vec, /// MIDI outs to connect to (multiple instances accepted) #[arg(short='i', long)] midi_from_re: Vec, /// MIDI ins to connect to (multiple instances accepted) #[arg(short='O', long)] midi_to: Vec, /// MIDI ins to connect to (multiple instances accepted) #[arg(short='o', long)] midi_to_re: Vec, /// Audio outs to connect to left input #[arg(short='l', long)] left_from: Vec, /// Audio outs to connect to right input #[arg(short='r', long)] right_from: Vec, /// Audio ins to connect from left output #[arg(short='L', long)] left_to: Vec, /// Audio ins to connect from right output #[arg(short='R', long)] right_to: Vec, } #[derive(Debug, Clone, Subcommand)] pub enum Mode { /// A standalone transport clock. Clock, /// A MIDI sequencer. Sequencer, /// A MIDI-controlled audio sampler. Sampler, /// Sequencer and sampler together.12 Groovebox, /// Multi-track MIDI sequencer. Arranger { /// Number of scenes #[arg(short = 'y', long, default_value_t = 4)] scenes: usize, /// Number of tracks #[arg(short = 'x', long, default_value_t = 4)] tracks: usize, /// Width of tracks #[arg(short = 'w', long, default_value_t = 12)] track_width: usize, }, /// TODO: A MIDI-controlled audio mixer Mixer, /// TODO: A customizable channel strip Track, /// TODO: An audio plugin host Plugin, } impl Cli { pub fn run (&self) -> Usually<()> { let name = self.name.as_ref().map_or("tek", |x|x.as_str()); //let color = ItemPalette::random(); let jack = Jack::new(name)?; let engine = Tui::new()?; let empty = &[] as &[&str]; let midi_froms = PortConnect::collect(&self.midi_from, empty, &self.midi_from_re); let midi_tos = PortConnect::collect(&self.midi_to, empty, &self.midi_to_re); let left_froms = PortConnect::collect(&self.left_from, empty, empty); let left_tos = PortConnect::collect(&self.left_to, empty, empty); let right_froms = PortConnect::collect(&self.right_from, empty, empty); let right_tos = PortConnect::collect(&self.right_to, empty, empty); let audio_froms = &[left_froms.as_slice(), right_froms.as_slice()]; let audio_tos = &[left_tos.as_slice(), right_tos.as_slice() ]; let jack = jack.run(|jack|match self.mode { Mode::Clock => Tek::new_clock( jack, self.bpm, self.sync_lead, self.sync_follow, &midi_froms, &midi_tos), Mode::Sequencer => Tek::new_sequencer( jack, self.bpm, self.sync_lead, self.sync_follow, &midi_froms, &midi_tos), Mode::Groovebox => Tek::new_groovebox( jack, self.bpm, self.sync_lead, self.sync_follow, &midi_froms, &midi_tos, &audio_froms, &audio_tos), Mode::Arranger { scenes, tracks, track_width, .. } => Tek::new_arranger( jack, self.bpm, self.sync_lead, self.sync_follow, &midi_froms, &midi_tos, &audio_froms, &audio_tos, scenes, tracks, track_width), _ => todo!() })?; engine.run(&jack) } } const HEADER: &'static str = r#" ░▒▓████████▓▒░▒▓███████▓▒░▒▓█▓▒░░▒▓█▓▒░░ ░░░░▒▓█▓▒░░░░░▒▓█▓▒░░░░░░░▒▓█▓▒░▒▓█▓▒░░░ ░░░░▒▓█▓▒░░░░░▒▓█████▓▒░░░▒▓██████▓▒░░░░ ░░░░▒▓█▓▒░░░░░▒▓█▓▒░░░░░░░▒▓█▓▒░▒▓█▓▒░░░ ░░░░▒▓█▓▒░░░░░▒▓█▓▒░░░░░░░▒▓█▓▒░░▒▓█▓▒░░ ░░░░▒▓█▓▒░░░░░▒▓███████▓▒░▒▓█▓▒░░▒▓█▓▒░░"#; #[cfg(test)] #[test] fn test_cli () { use clap::CommandFactory; Cli::command().debug_assert(); let jack = Jack::default(); //TODO: //let _ = Tek::new_clock(&jack, None, false, false, &[], &[]); //let _ = Tek::new_sequencer(&jack, None, false, false, &[], &[]); //let _ = Tek::new_groovebox(&jack, None, false, false, &[], &[], &[&[], &[]], &[&[], &[]]); //let _ = Tek::new_arranger(&jack, None, false, false, &[], &[], &[&[], &[]], &[&[], &[]], 0, 0, 0); }