103 lines
3.8 KiB
Rust
103 lines
3.8 KiB
Rust
|
|
use std::process::exit;
|
||
|
|
|
||
|
|
use orca_rs::io::{EventOutputs, MidiOut, OscOut, UdpOut};
|
||
|
|
use orca_rs::tui::{self, TuiConfig};
|
||
|
|
|
||
|
|
const USAGE: &str = "\
|
||
|
|
Usage: orca-rs [options] [file.orca]
|
||
|
|
|
||
|
|
Open the Orca live-coding environment. If the file does not exist it will
|
||
|
|
be created on first save; with no file, edits save to untitled.orca.
|
||
|
|
|
||
|
|
Options:
|
||
|
|
--bpm <n> Tempo (default: 120)
|
||
|
|
--seed <n> Random seed for the R operator (default: 1)
|
||
|
|
--udp-port <n> Send ';' operator strings over UDP to this port
|
||
|
|
--udp-host <h> UDP destination host (default: 127.0.0.1)
|
||
|
|
--osc-port <n> Send '=' operator messages over OSC to this port
|
||
|
|
--osc-host <h> OSC destination host (default: 127.0.0.1)
|
||
|
|
--no-midi Disable MIDI output (on by default: creates a virtual
|
||
|
|
ALSA port named 'orca-rs', visible in PipeWire)
|
||
|
|
--midi-name <s> Connect to the MIDI output port whose name contains <s>
|
||
|
|
instead of creating a virtual port
|
||
|
|
--list-midi List available MIDI output ports and exit
|
||
|
|
-h, --help Print this message and exit
|
||
|
|
";
|
||
|
|
|
||
|
|
fn die(msg: &str) -> ! {
|
||
|
|
eprintln!("{msg}");
|
||
|
|
exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
fn parse_num(args: &mut impl Iterator<Item = String>, flag: &str) -> usize {
|
||
|
|
args.next()
|
||
|
|
.and_then(|v| v.parse().ok())
|
||
|
|
.unwrap_or_else(|| die(&format!("{flag} requires a number")))
|
||
|
|
}
|
||
|
|
|
||
|
|
fn main() {
|
||
|
|
let mut path: Option<String> = None;
|
||
|
|
let mut bpm: usize = 120;
|
||
|
|
let mut seed: usize = 1;
|
||
|
|
let mut udp_host = "127.0.0.1".to_string();
|
||
|
|
let mut udp_port: Option<u16> = None;
|
||
|
|
let mut osc_host = "127.0.0.1".to_string();
|
||
|
|
let mut osc_port: Option<u16> = None;
|
||
|
|
let mut midi = true;
|
||
|
|
let mut midi_name: Option<String> = None;
|
||
|
|
|
||
|
|
let mut args = std::env::args().skip(1);
|
||
|
|
while let Some(arg) = args.next() {
|
||
|
|
match arg.as_str() {
|
||
|
|
"--bpm" => bpm = parse_num(&mut args, "--bpm").clamp(10, 999),
|
||
|
|
"--seed" => seed = parse_num(&mut args, "--seed"),
|
||
|
|
"--udp-port" => udp_port = Some(parse_num(&mut args, "--udp-port") as u16),
|
||
|
|
"--udp-host" => udp_host = args.next().unwrap_or_else(|| die("--udp-host requires a value")),
|
||
|
|
"--osc-port" => osc_port = Some(parse_num(&mut args, "--osc-port") as u16),
|
||
|
|
"--osc-host" => osc_host = args.next().unwrap_or_else(|| die("--osc-host requires a value")),
|
||
|
|
"--midi" => midi = true,
|
||
|
|
"--no-midi" => midi = false,
|
||
|
|
"--midi-name" => {
|
||
|
|
midi = true;
|
||
|
|
midi_name = Some(args.next().unwrap_or_else(|| die("--midi-name requires a value")));
|
||
|
|
}
|
||
|
|
"--list-midi" => {
|
||
|
|
let ports = MidiOut::list_ports();
|
||
|
|
if ports.is_empty() {
|
||
|
|
println!("no MIDI output ports found");
|
||
|
|
} else {
|
||
|
|
for p in ports {
|
||
|
|
println!("{p}");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
"-h" | "--help" => {
|
||
|
|
print!("{USAGE}");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
_ if path.is_none() && !arg.starts_with('-') => path = Some(arg),
|
||
|
|
_ => die(USAGE),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let mut outputs = EventOutputs::default();
|
||
|
|
if let Some(port) = udp_port {
|
||
|
|
outputs.udp =
|
||
|
|
Some(UdpOut::new(&udp_host, port).unwrap_or_else(|e| die(&format!("UDP setup failed: {e}"))));
|
||
|
|
}
|
||
|
|
if let Some(port) = osc_port {
|
||
|
|
outputs.osc =
|
||
|
|
Some(OscOut::new(&osc_host, port).unwrap_or_else(|e| die(&format!("OSC setup failed: {e}"))));
|
||
|
|
}
|
||
|
|
if midi {
|
||
|
|
outputs.midi = Some(MidiOut::open(midi_name.as_deref()).unwrap_or_else(|e| {
|
||
|
|
die(&format!("MIDI setup failed: {e} (use --no-midi to run without MIDI)"))
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
|
||
|
|
if let Err(e) = tui::run(TuiConfig { path, bpm, seed, outputs }) {
|
||
|
|
die(&e);
|
||
|
|
}
|
||
|
|
}
|