implement midi autoconnect for arranger

This commit is contained in:
🪞👃🪞 2024-12-25 00:25:48 +01:00
parent f1847b62b8
commit 512e466af1
3 changed files with 107 additions and 13 deletions

View file

@ -31,9 +31,31 @@ transport-release:
arranger:
reset
cargo run --bin tek_arranger
arranger-ext:
reset
cargo run --bin tek_arranger -- -n tek \
-i "1=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-o "1=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-i "2=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-o "2=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-i "3=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-o "3=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-i "4=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-o "4=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
arranger-release:
reset
cargo run --release --bin tek_arranger
arranger-release-ext:
reset
cargo run --release --bin tek_arranger -- -n tek \
-i "1=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-o "1=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-i "2=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-o "2=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-i "3=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-o "3=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1" \
-i "4=Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" \
-o "4=Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
groovebox:
reset

View file

@ -4,22 +4,33 @@ pub fn main () -> Usually<()> {
ArrangerCli::parse().run()
}
/// Parses CLI arguments to the `tek_arranger` invocation.
/// Launches an interactive MIDI arranger.
#[derive(Debug, Parser)]
#[command(version, about, long_about = None)]
pub struct ArrangerCli {
/// Name of JACK client
#[arg(short, long)]
name: Option<String>,
name: Option<String>,
/// Whether to include a transport toolbar (default: true)
#[arg(short, long, default_value_t = true)]
transport: bool,
/// Number of tracks
#[arg(short = 'x', long, default_value_t = 4)]
tracks: usize,
tracks: usize,
/// Number of scenes
#[arg(short, long, default_value_t = 8)]
scenes: usize,
scenes: usize,
/// MIDI outs to connect each track to.
#[arg(short='i', long)]
midi_from: Vec<String>,
/// MIDI ins to connect each track to.
#[arg(short='o', long)]
midi_to: Vec<String>,
}
impl ArrangerCli {
@ -31,8 +42,9 @@ impl ArrangerCli {
}
Tui::run(JackClient::new(client_name.as_str())?.activate_with(|jack|{
let mut app = ArrangerTui::try_from(jack)?;
let jack = jack.read().unwrap();
app.color = ItemPalette::random();
add_tracks(&mut app, self.tracks)?;
add_tracks(&jack, &mut app, &self)?;
add_scenes(&mut app, self.scenes)?;
Ok(app)
})?)?;
@ -40,7 +52,8 @@ impl ArrangerCli {
}
}
fn add_tracks (app: &mut ArrangerTui, n: usize) -> Usually<()> {
fn add_tracks (jack: &JackClient, app: &mut ArrangerTui, cli: &ArrangerCli) -> Usually<()> {
let n = cli.tracks;
let track_color_1 = ItemColor::random();
let track_color_2 = ItemColor::random();
for i in 0..n {
@ -48,6 +61,60 @@ fn add_tracks (app: &mut ArrangerTui, n: usize) -> Usually<()> {
track_color_1.mix(track_color_2, i as f32 / n as f32).into()
))?;
track.width = 8;
let name = track.name.read().unwrap();
track.player.midi_ins.push(
jack.register_port(&format!("{}I", &name), MidiIn::default())?
);
track.player.midi_outs.push(
jack.register_port(&format!("{}O", &name), MidiOut::default())?
);
}
for connection in cli.midi_from.iter() {
let mut split = connection.split("=");
let number = split.next().unwrap().trim();
if let Ok(track) = number.parse::<usize>() {
if track < 1 {
panic!("Tracks are zero-indexed")
}
if track > n {
panic!("Tried to connect track {track} or {n}. Pass -t {track} to increase number of tracks.")
}
if let Some(port) = split.next() {
if let Some(port) = jack.port_by_name(&port) {
jack.client().connect_ports(&port, &app.tracks[track-1].player.midi_ins[0])?;
//jack.client().connect_ports(&port, &app.tracks[track].player.midi_ins[0])?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
} else {
panic!("No port specified for track {track}. Format is TRACK_NUMBER=PORT_NAME")
}
} else {
panic!("Failed to parse track number: {number}")
}
}
for connection in cli.midi_to.iter() {
let mut split = connection.split("=");
let number = split.next().unwrap().trim();
if let Ok(track) = number.parse::<usize>() {
if track < 1 {
panic!("Tracks are zero-indexed")
}
if track > n {
panic!("Tried to connect track {track} or {n}. Pass -t {track} to increase number of tracks.")
}
if let Some(port) = split.next() {
if let Some(port) = jack.port_by_name(&port) {
jack.client().connect_ports(&app.tracks[track-1].player.midi_outs[0], &port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
} else {
panic!("No port specified for track {track}. Format is TRACK_NUMBER=PORT_NAME")
}
} else {
panic!("Failed to parse track number: {number}")
}
}
Ok(())
}

View file

@ -4,24 +4,29 @@ pub fn main () -> Usually<()> {
SequencerCli::parse().run()
}
/// Launches a single interactive MIDI sequencer.
#[derive(Debug, Parser)]
#[command(version, about, long_about = None)]
pub struct SequencerCli {
/// Name of JACK client
#[arg(short, long)]
name: Option<String>,
/// Whether to include a transport toolbar (default: true)
#[arg(short, long, default_value_t = true)]
transport: bool,
/// MIDI outs to connect to (multiple instances accepted)
#[arg(short='i', long)]
midi_from: Vec<String>,
/// MIDI ins to connect to (multiple instances accepted)
#[arg(short='o', long)]
midi_to: Vec<String>,
/// Default phrase duration (in pulses; default: 4 * PPQ = 1 bar)
#[arg(short, long)]
length: Option<usize>,
/// Whether to include a transport toolbar (default: true)
#[arg(short, long, default_value_t = true)]
transport: bool
}
impl SequencerCli {
@ -30,8 +35,8 @@ impl SequencerCli {
Tui::run(JackClient::new(name)?.activate_with(|jack|{
let mut app = SequencerTui::try_from(jack)?;
let jack = jack.read().unwrap();
let midi_in = jack.register_port("in", MidiIn::default())?;
let midi_out = jack.register_port("out", MidiOut::default())?;
let midi_in = jack.register_port("i", MidiIn::default())?;
let midi_out = jack.register_port("o", MidiOut::default())?;
connect_from(&jack, &midi_in, &self.midi_from)?;
connect_to(&jack, &midi_out, &self.midi_to)?;
app.player.midi_ins.push(midi_in);
@ -52,7 +57,7 @@ fn connect_from (jack: &JackClient, input: &Port<MidiIn>, ports: &[String]) -> U
if let Some(port) = jack.port_by_name(&port) {
jack.client().connect_ports(&port, &input)?;
} else {
panic!("Missing MIDI output: {port}");
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
@ -63,7 +68,7 @@ fn connect_to (jack: &JackClient, output: &Port<MidiOut>, ports: &[String]) -> U
if let Some(port) = jack.port_by_name(&port) {
jack.client().connect_ports(&output, &port)?;
} else {
panic!("Missing MIDI output: {port}");
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())