add cli args to connect sequencer to midi ports

This commit is contained in:
🪞👃🪞 2024-12-24 23:19:40 +01:00
parent 48ec9af019
commit 8644d84ad6
9 changed files with 222 additions and 194 deletions

View file

@ -45,9 +45,15 @@ groovebox-release:
sequencer: sequencer:
reset reset
cargo run --bin tek_sequencer cargo run --bin tek_sequencer
sequencer-ext:
reset
cargo run --bin tek_sequencer -- -i "Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" -o "Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
sequencer-release: sequencer-release:
reset reset
cargo run --release --bin tek_sequencer cargo run --release --bin tek_sequencer
sequencer-release-ext:
reset
cargo run --release --bin tek_sequencer -- -i "Midi-Bridge:nanoKEY Studio 2:(capture_0) nanoKEY Studio nanoKEY Studio _" -o "Midi-Bridge:Komplete Audio 6 1:(playback_0) Komplete Audio 6 MIDI 1"
mixer: mixer:
reset reset

View file

@ -106,11 +106,12 @@ impl Content for Demo<Tui> {
impl Handle<Tui> for Demo<Tui> { impl Handle<Tui> for Demo<Tui> {
fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> { fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> {
use KeyCode::{PageUp, PageDown};
match from.event() { match from.event() {
key!(KeyCode::PageUp) => { key_expr!(PageUp) => {
self.index = (self.index + 1) % self.items.len(); self.index = (self.index + 1) % self.items.len();
}, },
key!(KeyCode::PageDown) => { key_expr!(PageDown) => {
self.index = if self.index > 1 { self.index = if self.index > 1 {
self.index - 1 self.index - 1
} else { } else {

View file

@ -1,4 +1,4 @@
use tek::{core::*, layout::*, tui::*, *}; use tek::*;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
fn main () -> Usually<()> { fn main () -> Usually<()> {

View file

@ -1,4 +1,4 @@
use tek_api::*; use tek::*;
struct ExamplePhrases(Vec<Arc<RwLock<Phrase>>>); struct ExamplePhrases(Vec<Arc<RwLock<Phrase>>>);

View file

@ -52,3 +52,8 @@ impl ArrangerCli {
Ok(()) Ok(())
} }
} }
#[test] fn verify_arranger_cli () {
use clap::CommandFactory;
ArrangerCli::command().debug_assert();
}

View file

@ -8,31 +8,49 @@ pub fn main () -> Usually<()> {
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
pub struct SequencerCli { pub struct SequencerCli {
/// Name of JACK client /// Name of JACK client
#[arg(short, long)] name: Option<String>, #[arg(short, long)]
/// Pulses per quarter note (sequencer resolution; default: 96) name: Option<String>,
#[arg(short, long)] ppq: Option<usize>, /// 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) /// Default phrase duration (in pulses; default: 4 * PPQ = 1 bar)
#[arg(short, long)] length: Option<usize>, #[arg(short, long)]
length: Option<usize>,
/// Whether to include a transport toolbar (default: true) /// Whether to include a transport toolbar (default: true)
#[arg(short, long, default_value_t = true)] transport: bool #[arg(short, long, default_value_t = true)]
transport: bool
} }
impl SequencerCli { impl SequencerCli {
fn run (&self) -> Usually<()> { fn run (&self) -> Usually<()> {
Tui::run(JackClient::new("tek_sequencer")?.activate_with(|jack|{ let name = self.name.as_ref().map(|n|n.as_str()).unwrap_or("tek_sequencer");
let midi_in = jack.read().unwrap().register_port("in", MidiIn::default())?; Tui::run(JackClient::new(name)?.activate_with(|jack|{
let midi_out = jack.read().unwrap().register_port("out", MidiOut::default())?;
let mut app = SequencerTui::try_from(jack)?; let mut app = SequencerTui::try_from(jack)?;
//app.editor.view_mode.set_time_zoom(1); let jack = jack.read().unwrap();
// TODO: create from arguments let midi_in = jack.register_port("in", MidiIn::default())?;
let midi_out = jack.register_port("out", MidiOut::default())?;
for port in self.midi_from.iter() {
if let Some(port) = jack.port_by_name(&port) {
jack.client().connect_ports(&port, &midi_in)?;
} else {
panic!("Missing MIDI output: {port}");
}
}
for port in self.midi_to.iter() {
if let Some(port) = jack.port_by_name(&port) {
jack.client().connect_ports(&midi_out, &port)?;
} else {
panic!("Missing MIDI output: {port}");
}
}
app.player.midi_ins.push(midi_in); app.player.midi_ins.push(midi_in);
app.player.midi_outs.push(midi_out); app.player.midi_outs.push(midi_out);
if let Some(_) = self.name.as_ref() { if let Some(_) = self.name.as_ref() {
// TODO: sequencer.name = Arc::new(RwLock::new(name.clone())); // TODO: sequencer.name = Arc::new(RwLock::new(name.clone()));
} }
if let Some(_) = self.ppq {
// TODO: sequencer.ppq = ppq;
}
if let Some(_) = self.length { if let Some(_) = self.length {
// TODO: if let Some(phrase) = sequencer.phrase.as_mut() { // TODO: if let Some(phrase) = sequencer.phrase.as_mut() {
//phrase.write().unwrap().length = length; //phrase.write().unwrap().length = length;
@ -43,3 +61,8 @@ impl SequencerCli {
Ok(()) Ok(())
} }
} }
#[test] fn verify_sequencer_cli () {
use clap::CommandFactory;
SequencerCli::command().debug_assert();
}

View file

@ -1,4 +1,4 @@
pub mod core; pub(crate) use self::core::*; pub mod core; pub use self::core::*;
pub mod time; pub(crate) use self::time::*; pub mod time; pub(crate) use self::time::*;
pub mod space; pub(crate) use self::space::*; pub mod space; pub(crate) use self::space::*;
pub mod tui; pub(crate) use self::tui::*; pub mod tui; pub(crate) use self::tui::*;

View file

@ -1,190 +1,183 @@
use crate::*; //use crate::*;
struct TestEngine([u16;4], Vec<Vec<char>>); //struct TestEngine([u16;4], Vec<Vec<char>>);
impl Engine for TestEngine { //impl Engine for TestEngine {
type Unit = u16; //type Unit = u16;
type Size = [Self::Unit;2]; //type Size = [Self::Unit;2];
type Area = [Self::Unit;4]; //type Area = [Self::Unit;4];
type Input = Self; //type Input = Self;
type Handled = bool; //type Handled = bool;
fn exited (&self) -> bool { //fn exited (&self) -> bool {
true //true
} //}
fn area (&self) -> Self::Area { //}
self.0
}
fn area_mut (&mut self) -> &mut Self::Area {
&mut self.0
}
}
#[derive(Copy, Clone)] //#[derive(Copy, Clone)]
struct TestArea(u16, u16); //struct TestArea(u16, u16);
impl Render for TestArea { //impl Render<TestEngine> for TestArea {
type Engine = TestEngine; //fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> { //Ok(Some([to[0], to[1], self.0, self.1]))
Ok(Some([to[0], to[1], self.0, self.1])) //}
} //fn render (&self, to: &mut TestEngine) -> Perhaps<[u16;4]> {
fn render (&self, to: &mut Self::Engine) -> Perhaps<[u16;4]> { //if let Some(layout) = self.layout(to.area())? {
if let Some(layout) = self.layout(to.area())? { //for y in layout.y()..layout.y()+layout.h()-1 {
for y in layout.y()..layout.y()+layout.h()-1 { //for x in layout.x()..layout.x()+layout.w()-1 {
for x in layout.x()..layout.x()+layout.w()-1 { //to.1[y as usize][x as usize] = '*';
to.1[y as usize][x as usize] = '*'; //}
} //}
} //Ok(Some(layout))
Ok(Some(layout)) //} else {
} else { //Ok(None)
Ok(None) //}
} //}
} //}
}
#[test]
fn test_plus_minus () -> Usually<()> {
let area = [0, 0, 10, 10];
let engine = TestEngine(area, vec![vec![' ';10];10]);
let test = TestArea(4, 4);
assert_eq!(test.layout(area)?, Some([0, 0, 4, 4]));
assert_eq!(Push::X(1, test).layout(area)?, Some([1, 0, 4, 4]));
Ok(())
}
#[test]
fn test_outset_align () -> Usually<()> {
let area = [0, 0, 10, 10];
let engine = TestEngine(area, vec![vec![' ';10];10]);
let test = TestArea(4, 4);
assert_eq!(test.layout(area)?, Some([0, 0, 4, 4]));
assert_eq!(Outset::X(1, test).layout(area)?, Some([0, 0, 6, 4]));
assert_eq!(Align::X(test).layout(area)?, Some([3, 0, 4, 4]));
assert_eq!(Align::X(Outset::X(1, test)).layout(area)?, Some([2, 0, 6, 4]));
assert_eq!(Outset::X(1, Align::X(test)).layout(area)?, Some([2, 0, 6, 4]));
Ok(())
}
//#[test] //#[test]
//fn test_misc () -> Usually<()> { //fn test_plus_minus () -> Usually<()> {
//let area: [u16;4] = [0, 0, 10, 10]; //let area = [0, 0, 10, 10];
//let test = TestArea(4, 4); //let engine = TestEngine(area, vec![vec![' ';10];10]);
//assert_eq!(test.layout(area)?, //let test = TestArea(4, 4);
//Some([0, 0, 4, 4])); //assert_eq!(test.layout(area)?, Some([0, 0, 4, 4]));
//assert_eq!(Align::Center(test).layout(area)?, //assert_eq!(Push::X(1, test).layout(area)?, Some([1, 0, 4, 4]));
//Some([3, 3, 4, 4]));
//assert_eq!(Align::Center(Stack::down(|add|{
//add(&test)?;
//add(&test)
//})).layout(area)?,
//Some([3, 1, 4, 8]));
//assert_eq!(Align::Center(Stack::down(|add|{
//add(&Outset::XY(2, 2, test))?;
//add(&test)
//})).layout(area)?,
//Some([2, 0, 6, 10]));
//assert_eq!(Align::Center(Stack::down(|add|{
//add(&Outset::XY(2, 2, test))?;
//add(&Inset::XY(2, 2, test))
//})).layout(area)?,
//Some([2, 1, 6, 8]));
//assert_eq!(Stack::down(|add|{
//add(&Outset::XY(2, 2, test))?;
//add(&Inset::XY(2, 2, test))
//}).layout(area)?,
//Some([0, 0, 6, 8]));
//assert_eq!(Stack::right(|add|{
//add(&Stack::down(|add|{
//add(&Outset::XY(2, 2, test))?;
//add(&Inset::XY(2, 2, test))
//}))?;
//add(&Align::Center(TestArea(2 ,2)))
//}).layout(area)?,
//Some([0, 0, 8, 8]));
//Ok(()) //Ok(())
//} //}
//#[test] //#[test]
//fn test_offset () -> Usually<()> { //fn test_outset_align () -> Usually<()> {
//let area: [u16;4] = [50, 50, 100, 100]; //let area = [0, 0, 10, 10];
//let test = TestArea(3, 3); //let engine = TestEngine(area, vec![vec![' ';10];10]);
//assert_eq!(Push::X(1, test).layout(area)?, Some([51, 50, 3, 3])); //let test = TestArea(4, 4);
//assert_eq!(Push::Y(1, test).layout(area)?, Some([50, 51, 3, 3])); //assert_eq!(test.layout(area)?, Some([0, 0, 4, 4]));
//assert_eq!(Push::XY(1, 1, test).layout(area)?, Some([51, 51, 3, 3])); //assert_eq!(Outset::X(1, test).layout(area)?, Some([0, 0, 6, 4]));
//assert_eq!(Align::X(test).layout(area)?, Some([3, 0, 4, 4]));
//assert_eq!(Align::X(Outset::X(1, test)).layout(area)?, Some([2, 0, 6, 4]));
//assert_eq!(Outset::X(1, Align::X(test)).layout(area)?, Some([2, 0, 6, 4]));
//Ok(()) //Ok(())
//} //}
//#[test] ////#[test]
//fn test_outset () -> Usually<()> { ////fn test_misc () -> Usually<()> {
//let area: [u16;4] = [50, 50, 100, 100]; ////let area: [u16;4] = [0, 0, 10, 10];
//let test = TestArea(3, 3); ////let test = TestArea(4, 4);
//assert_eq!(Outset::X(1, test).layout(area)?, Some([49, 50, 5, 3])); ////assert_eq!(test.layout(area)?,
//assert_eq!(Outset::Y(1, test).layout(area)?, Some([50, 49, 3, 5])); ////Some([0, 0, 4, 4]));
//assert_eq!(Outset::XY(1, 1, test).layout(area)?, Some([49, 49, 5, 5])); ////assert_eq!(Align::Center(test).layout(area)?,
//Ok(()) ////Some([3, 3, 4, 4]));
//} ////assert_eq!(Align::Center(Stack::down(|add|{
////add(&test)?;
////add(&test)
////})).layout(area)?,
////Some([3, 1, 4, 8]));
////assert_eq!(Align::Center(Stack::down(|add|{
////add(&Outset::XY(2, 2, test))?;
////add(&test)
////})).layout(area)?,
////Some([2, 0, 6, 10]));
////assert_eq!(Align::Center(Stack::down(|add|{
////add(&Outset::XY(2, 2, test))?;
////add(&Inset::XY(2, 2, test))
////})).layout(area)?,
////Some([2, 1, 6, 8]));
////assert_eq!(Stack::down(|add|{
////add(&Outset::XY(2, 2, test))?;
////add(&Inset::XY(2, 2, test))
////}).layout(area)?,
////Some([0, 0, 6, 8]));
////assert_eq!(Stack::right(|add|{
////add(&Stack::down(|add|{
////add(&Outset::XY(2, 2, test))?;
////add(&Inset::XY(2, 2, test))
////}))?;
////add(&Align::Center(TestArea(2 ,2)))
////}).layout(area)?,
////Some([0, 0, 8, 8]));
////Ok(())
////}
//#[test] ////#[test]
//fn test_inset () -> Usually<()> { ////fn test_offset () -> Usually<()> {
//let area: [u16;4] = [50, 50, 100, 100]; ////let area: [u16;4] = [50, 50, 100, 100];
//let test = TestArea(3, 3); ////let test = TestArea(3, 3);
//assert_eq!(Inset::X(1, test).layout(area)?, Some([51, 50, 1, 3])); ////assert_eq!(Push::X(1, test).layout(area)?, Some([51, 50, 3, 3]));
//assert_eq!(Inset::Y(1, test).layout(area)?, Some([50, 51, 3, 1])); ////assert_eq!(Push::Y(1, test).layout(area)?, Some([50, 51, 3, 3]));
//assert_eq!(Inset::XY(1, 1, test).layout(area)?, Some([51, 51, 1, 1])); ////assert_eq!(Push::XY(1, 1, test).layout(area)?, Some([51, 51, 3, 3]));
//Ok(()) ////Ok(())
//} ////}
//#[test] ////#[test]
//fn test_stuff () -> Usually<()> { ////fn test_outset () -> Usually<()> {
//let area: [u16;4] = [0, 0, 100, 100]; ////let area: [u16;4] = [50, 50, 100, 100];
//assert_eq!("1".layout(area)?, ////let test = TestArea(3, 3);
//Some([0, 0, 1, 1])); ////assert_eq!(Outset::X(1, test).layout(area)?, Some([49, 50, 5, 3]));
//assert_eq!("333".layout(area)?, ////assert_eq!(Outset::Y(1, test).layout(area)?, Some([50, 49, 3, 5]));
//Some([0, 0, 3, 1])); ////assert_eq!(Outset::XY(1, 1, test).layout(area)?, Some([49, 49, 5, 5]));
//assert_eq!(Layers::new(|add|{add(&"1")?;add(&"333")}).layout(area)?, ////Ok(())
//Some([0, 0, 3, 1])); ////}
//assert_eq!(Stack::down(|add|{add(&"1")?;add(&"333")}).layout(area)?,
//Some([0, 0, 3, 2])); ////#[test]
//assert_eq!(Stack::right(|add|{add(&"1")?;add(&"333")}).layout(area)?, ////fn test_inset () -> Usually<()> {
//Some([0, 0, 4, 1])); ////let area: [u16;4] = [50, 50, 100, 100];
//assert_eq!(Stack::down(|add|{ ////let test = TestArea(3, 3);
//add(&Stack::right(|add|{add(&"1")?;add(&"333")}))?; ////assert_eq!(Inset::X(1, test).layout(area)?, Some([51, 50, 1, 3]));
//add(&"55555") ////assert_eq!(Inset::Y(1, test).layout(area)?, Some([50, 51, 3, 1]));
//}).layout(area)?, ////assert_eq!(Inset::XY(1, 1, test).layout(area)?, Some([51, 51, 1, 1]));
//Some([0, 0, 5, 2])); ////Ok(())
//let area: [u16;4] = [1, 1, 100, 100]; ////}
//assert_eq!(Outset::X(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
//Some([0, 1, 6, 1])); ////#[test]
//assert_eq!(Outset::Y(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, ////fn test_stuff () -> Usually<()> {
//Some([1, 0, 4, 3])); ////let area: [u16;4] = [0, 0, 100, 100];
//assert_eq!(Outset::XY(1, 1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?, ////assert_eq!("1".layout(area)?,
//Some([0, 0, 6, 3])); ////Some([0, 0, 1, 1]));
//assert_eq!(Stack::down(|add|{ ////assert_eq!("333".layout(area)?,
//add(&Outset::XY(1, 1, "1"))?; ////Some([0, 0, 3, 1]));
//add(&Outset::XY(1, 1, "333")) ////assert_eq!(Layers::new(|add|{add(&"1")?;add(&"333")}).layout(area)?,
//}).layout(area)?, ////Some([0, 0, 3, 1]));
//Some([1, 1, 5, 6])); ////assert_eq!(Stack::down(|add|{add(&"1")?;add(&"333")}).layout(area)?,
//let area: [u16;4] = [1, 1, 95, 100]; ////Some([0, 0, 3, 2]));
//assert_eq!(Align::Center(Stack::down(|add|{ ////assert_eq!(Stack::right(|add|{add(&"1")?;add(&"333")}).layout(area)?,
//add(&Outset::XY(1, 1, "1"))?; ////Some([0, 0, 4, 1]));
//add(&Outset::XY(1, 1, "333")) ////assert_eq!(Stack::down(|add|{
//})).layout(area)?, ////add(&Stack::right(|add|{add(&"1")?;add(&"333")}))?;
//Some([46, 48, 5, 6])); ////add(&"55555")
//assert_eq!(Align::Center(Stack::down(|add|{ ////}).layout(area)?,
//add(&Layers::new(|add|{ ////Some([0, 0, 5, 2]));
////add(&Outset::XY(1, 1, Background(Color::Rgb(0,128,0))))?; ////let area: [u16;4] = [1, 1, 100, 100];
//add(&Outset::XY(1, 1, "1"))?; ////assert_eq!(Outset::X(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
//add(&Outset::XY(1, 1, "333"))?; ////Some([0, 1, 6, 1]));
////add(&Background(Color::Rgb(0,128,0)))?; ////assert_eq!(Outset::Y(1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
//Ok(()) ////Some([1, 0, 4, 3]));
//}))?; ////assert_eq!(Outset::XY(1, 1, Stack::right(|add|{add(&"1")?;add(&"333")})).layout(area)?,
//add(&Layers::new(|add|{ ////Some([0, 0, 6, 3]));
////add(&Outset::XY(1, 1, Background(Color::Rgb(0,0,128))))?; ////assert_eq!(Stack::down(|add|{
//add(&Outset::XY(1, 1, "555"))?; ////add(&Outset::XY(1, 1, "1"))?;
//add(&Outset::XY(1, 1, "777777"))?; ////add(&Outset::XY(1, 1, "333"))
////add(&Background(Color::Rgb(0,0,128)))?; ////}).layout(area)?,
//Ok(()) ////Some([1, 1, 5, 6]));
//})) ////let area: [u16;4] = [1, 1, 95, 100];
//})).layout(area)?, ////assert_eq!(Align::Center(Stack::down(|add|{
//Some([46, 48, 5, 6])); ////add(&Outset::XY(1, 1, "1"))?;
//Ok(()) ////add(&Outset::XY(1, 1, "333"))
//} ////})).layout(area)?,
////Some([46, 48, 5, 6]));
////assert_eq!(Align::Center(Stack::down(|add|{
////add(&Layers::new(|add|{
//////add(&Outset::XY(1, 1, Background(Color::Rgb(0,128,0))))?;
////add(&Outset::XY(1, 1, "1"))?;
////add(&Outset::XY(1, 1, "333"))?;
//////add(&Background(Color::Rgb(0,128,0)))?;
////Ok(())
////}))?;
////add(&Layers::new(|add|{
//////add(&Outset::XY(1, 1, Background(Color::Rgb(0,0,128))))?;
////add(&Outset::XY(1, 1, "555"))?;
////add(&Outset::XY(1, 1, "777777"))?;
//////add(&Background(Color::Rgb(0,0,128)))?;
////Ok(())
////}))
////})).layout(area)?,
////Some([46, 48, 5, 6]));
////Ok(())
////}

View file

@ -53,7 +53,7 @@ from!(|state:&SequencerTui|SequencerStatus = {
}); });
render!(<Tui>|self: SequencerStatus|Fixed::h(2, lay!([ render!(<Tui>|self: SequencerStatus|Fixed::h(2, lay!([
Self::help(), Self::help(),
Fill::wh(Align::se({Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats())})), Fill::wh(Align::se(Tui::fg_bg(TuiTheme::orange(), TuiTheme::g(25), self.stats()))),
]))); ])));
impl SequencerStatus { impl SequencerStatus {
fn help () -> impl Render<Tui> { fn help () -> impl Render<Tui> {