implement ConnectPort

This commit is contained in:
🪞👃🪞 2025-01-09 18:48:39 +01:00
parent 0cca06e054
commit 9e4406c66a
4 changed files with 77 additions and 64 deletions

View file

@ -82,6 +82,67 @@ impl RegisterPort for Arc<RwLock<JackConnection>> {
} }
} }
pub trait ConnectPort {
fn port_by_name (&self, name: impl AsRef<str>) -> Option<Port<Unowned>>;
fn connect_ports <A: PortSpec, B: PortSpec> (&self, source: &Port<A>, target: &Port<B>)
-> Usually<()>;
fn connect_midi_from (&self, input: &Port<MidiIn>, ports: &[impl AsRef<str>]) -> Usually<()> {
for port in ports.iter() {
let port = port.as_ref();
if let Some(port) = self.port_by_name(port).as_ref() {
self.connect_ports(port, input)?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_midi_to (&self, output: &Port<MidiOut>, ports: &[impl AsRef<str>]) -> Usually<()> {
for port in ports.iter() {
let port = port.as_ref();
if let Some(port) = self.port_by_name(port).as_ref() {
self.connect_ports(output, port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_audio_from (&self, input: &Port<AudioIn>, ports: &[impl AsRef<str>]) -> Usually<()> {
for port in ports.iter() {
let port = port.as_ref();
if let Some(port) = self.port_by_name(port).as_ref() {
self.connect_ports(port, input)?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
fn connect_audio_to (&self, output: &Port<AudioOut>, ports: &[impl AsRef<str>]) -> Usually<()> {
for port in ports.iter() {
let port = port.as_ref();
if let Some(port) = self.port_by_name(port).as_ref() {
self.connect_ports(output, port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
}
impl ConnectPort for Arc<RwLock<JackConnection>> {
fn port_by_name (&self, name: impl AsRef<str>) -> Option<Port<Unowned>> {
self.read().unwrap().client().port_by_name(name.as_ref())
}
fn connect_ports <A: PortSpec, B: PortSpec> (&self, source: &Port<A>, target: &Port<B>)
-> Usually<()>
{
Ok(self.read().unwrap().client().connect_ports(source, target)?)
}
}
///// Collection of JACK ports as [AudioIn]/[AudioOut]/[MidiIn]/[MidiOut]. ///// Collection of JACK ports as [AudioIn]/[AudioOut]/[MidiIn]/[MidiOut].
//#[derive(Default, Debug)] //#[derive(Default, Debug)]
//pub struct JackPorts { //pub struct JackPorts {

View file

@ -49,15 +49,19 @@ impl MidiPlayer {
pub fn new ( pub fn new (
jack: &Arc<RwLock<JackConnection>>, jack: &Arc<RwLock<JackConnection>>,
name: impl AsRef<str>, name: impl AsRef<str>,
clip: Option<&Arc<RwLock<MidiClip>>>,
midi_from: &[impl AsRef<str>], midi_from: &[impl AsRef<str>],
midi_to: &[impl AsRef<str>], midi_to: &[impl AsRef<str>],
) -> Usually<Self> { ) -> Usually<Self> {
let name = name.as_ref(); let name = name.as_ref();
let midi_in = jack.midi_in(&format!("M/{name}"), midi_from)?; let midi_in = jack.midi_in(&format!("M/{name}"), midi_from)?;
jack.connect_midi_from(&midi_in, midi_from)?;
let midi_out = jack.midi_out(&format!("{name}/M"), midi_to)?; let midi_out = jack.midi_out(&format!("{name}/M"), midi_to)?;
jack.connect_midi_to(&midi_out, midi_to)?;
let clock = Clock::from(jack);
Ok(Self { Ok(Self {
clock: Clock::from(jack), play_phrase: Some((Moment::zero(&clock.timebase), clip.cloned())),
play_phrase: None,
next_phrase: None, next_phrase: None,
recording: false, recording: false,
monitoring: false, monitoring: false,
@ -67,9 +71,10 @@ impl MidiPlayer {
midi_ins: vec![midi_in], midi_ins: vec![midi_in],
midi_outs: vec![midi_out], midi_outs: vec![midi_out],
notes_out: RwLock::new([false;128]).into(), notes_out: RwLock::new([false;128]).into(),
note_buf: vec![0;8],
reset: true, reset: true,
note_buf: vec![0;8], clock,
}) })
} }
pub fn play_status (&self) -> impl Content<TuiOut> { pub fn play_status (&self) -> impl Content<TuiOut> {

View file

@ -105,23 +105,20 @@ pub fn main () -> Usually<()> {
}))?)?, }))?)?,
TekMode::Sequencer { TekMode::Sequencer {
midi_from, midi_from, midi_to, ..
midi_to, ..
} => engine.run(&jack.activate_with(|jack|Ok({ } => engine.run(&jack.activate_with(|jack|Ok({
let clock = Clock::from(jack); let clock = Clock::from(jack);
let phrase = Arc::new(RwLock::new(MidiClip::new( let clip = Arc::new(RwLock::new(MidiClip::new(
"Clip", true, 4 * clock.timebase.ppq.get() as usize, "Clip", true, 4 * clock.timebase.ppq.get() as usize,
None, Some(ItemColor::random().into()) None, Some(ItemColor::random().into())
))); )));
let midi_in = jack.read().unwrap().register_port("i", MidiIn::default())?; let player = MidiPlayer::new(&jack, name, Some(&clip), &midi_from, &midi_to)?;
connect_from(jack, &midi_in, &midi_from)?;
let midi_out = jack.read().unwrap().register_port("o", MidiOut::default())?;
connect_to(jack, &midi_out, &midi_to)?;
Sequencer { Sequencer {
_jack: jack.clone(), _jack: jack.clone(),
pool: PoolModel::from(&phrase), clock: player.clock.clone(),
editor: MidiEditor::from(&phrase), player,
player: MidiPlayer::new(&clock, &phrase, &[midi_in], &[midi_out])?, editor: MidiEditor::from(&clip),
pool: PoolModel::from(&clip),
compact: true, compact: true,
transport: true, transport: true,
selectors: true, selectors: true,
@ -130,7 +127,6 @@ pub fn main () -> Usually<()> {
note_buf: vec![], note_buf: vec![],
perf: PerfModel::default(), perf: PerfModel::default(),
status: true, status: true,
clock,
} }
}))?)?, }))?)?,
@ -224,55 +220,6 @@ pub fn main () -> Usually<()> {
}) })
} }
#[allow(unused)]
fn connect_from (jack: &JackConnection, input: &Port<MidiIn>, ports: &[String]) -> Usually<()> {
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(port, input)?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
#[allow(unused)]
fn connect_to (jack: &JackConnection, output: &Port<MidiOut>, ports: &[String]) -> Usually<()> {
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(output, port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
#[allow(unused)]
fn connect_audio_from (jack: &JackConnection, input: &Port<AudioIn>, ports: &[String]) -> Usually<()> {
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(port, input)?;
} else {
panic!("Missing MIDI output: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
#[allow(unused)]
fn connect_audio_to (jack: &JackConnection, output: &Port<AudioOut>, ports: &[String]) -> Usually<()> {
for port in ports.iter() {
if let Some(port) = jack.port_by_name(port).as_ref() {
jack.client().connect_ports(output, port)?;
} else {
panic!("Missing MIDI input: {port}. Use jack_lsp to list all port names.");
}
}
Ok(())
}
#[test] fn verify_cli () { #[test] fn verify_cli () {
use clap::CommandFactory; use clap::CommandFactory;
TekCli::command().debug_assert(); TekCli::command().debug_assert();

View file

@ -10,7 +10,7 @@ use MidiEditCommand::*;
use MidiPoolCommand::*; use MidiPoolCommand::*;
pub struct Groovebox { pub struct Groovebox {
_jack: Arc<RwLock<JackConnection>>, pub _jack: Arc<RwLock<JackConnection>>,
pub player: MidiPlayer, pub player: MidiPlayer,
pub pool: PoolModel, pub pool: PoolModel,
pub editor: MidiEditor, pub editor: MidiEditor,