mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
wip: refactor arranger to device
This commit is contained in:
parent
fa73821a0b
commit
89288f2920
40 changed files with 2015 additions and 1919 deletions
|
|
@ -1,94 +1,6 @@
|
|||
use crate::*;
|
||||
use super::*;
|
||||
|
||||
macro_rules! impl_port {
|
||||
($Name:ident : $Spec:ident -> $Pair:ident |$jack:ident, $name:ident|$port:expr) => {
|
||||
#[derive(Debug)] pub struct $Name {
|
||||
/// Handle to JACK client, for receiving reconnect events.
|
||||
jack: Jack,
|
||||
/// Port name
|
||||
name: Arc<str>,
|
||||
/// Port handle.
|
||||
port: Port<$Spec>,
|
||||
/// List of ports to connect to.
|
||||
conn: Vec<PortConnect>
|
||||
}
|
||||
impl AsRef<Port<$Spec>> for $Name { fn as_ref (&self) -> &Port<$Spec> { &self.port } }
|
||||
impl $Name {
|
||||
pub fn new ($jack: &Jack, name: impl AsRef<str>, connect: &[PortConnect])
|
||||
-> Usually<Self>
|
||||
{
|
||||
let $name = name.as_ref();
|
||||
let jack = $jack.clone();
|
||||
let port = $port?;
|
||||
let name = $name.into();
|
||||
let conn = connect.to_vec();
|
||||
let port = Self { jack, port, name, conn };
|
||||
port.connect_to_matching()?;
|
||||
Ok(port)
|
||||
}
|
||||
pub fn name (&self) -> &Arc<str> { &self.name }
|
||||
pub fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
pub fn port_mut (&mut self) -> &mut Port<$Spec> { &mut self.port }
|
||||
pub fn into_port (self) -> Port<$Spec> { self.port }
|
||||
pub fn close (self) -> Usually<()> {
|
||||
let Self { jack, port, .. } = self;
|
||||
Ok(jack.with_client(|client|client.unregister_port(port))?)
|
||||
}
|
||||
}
|
||||
impl HasJack for $Name { fn jack (&self) -> &Jack { &self.jack } }
|
||||
impl JackPort for $Name {
|
||||
type Port = $Spec;
|
||||
type Pair = $Pair;
|
||||
fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
}
|
||||
impl JackPortConnect<&str> for $Name {
|
||||
fn connect_to (&self, to: &str) -> Usually<PortConnectStatus> {
|
||||
self.with_client(|c|if let Some(ref port) = c.port_by_name(to.as_ref()) {
|
||||
self.connect_to(port)
|
||||
} else {
|
||||
Ok(Missing)
|
||||
})
|
||||
}
|
||||
}
|
||||
impl JackPortConnect<&Port<Unowned>> for $Name {
|
||||
fn connect_to (&self, port: &Port<Unowned>) -> Usually<PortConnectStatus> {
|
||||
self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
||||
Connected
|
||||
} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
||||
Connected
|
||||
} else {
|
||||
Mismatch
|
||||
}))
|
||||
}
|
||||
}
|
||||
impl JackPortConnect<&Port<$Pair>> for $Name {
|
||||
fn connect_to (&self, port: &Port<$Pair>) -> Usually<PortConnectStatus> {
|
||||
self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
||||
Connected
|
||||
} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
||||
Connected
|
||||
} else {
|
||||
Mismatch
|
||||
}))
|
||||
}
|
||||
}
|
||||
impl JackPortAutoconnect for $Name {
|
||||
fn conn (&self) -> &[PortConnect] {
|
||||
&self.conn
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_port!(JackAudioIn: AudioIn -> AudioOut |j, n|j.register_port::<AudioIn>(n));
|
||||
|
||||
impl_port!(JackAudioOut: AudioOut -> AudioIn |j, n|j.register_port::<AudioOut>(n));
|
||||
|
||||
impl_port!(JackMidiIn: MidiIn -> MidiOut |j, n|j.register_port::<MidiIn>(n));
|
||||
|
||||
impl_port!(JackMidiOut: MidiOut -> MidiIn |j, n|j.register_port::<MidiOut>(n));
|
||||
|
||||
pub trait JackPort: HasJack {
|
||||
type Port: PortSpec;
|
||||
type Pair: PortSpec;
|
||||
|
|
@ -235,3 +147,91 @@ impl PortConnect {
|
|||
format!(" ({}) {} {}", status, scope, name).into()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_port {
|
||||
($Name:ident : $Spec:ident -> $Pair:ident |$jack:ident, $name:ident|$port:expr) => {
|
||||
#[derive(Debug)] pub struct $Name {
|
||||
/// Handle to JACK client, for receiving reconnect events.
|
||||
jack: Jack,
|
||||
/// Port name
|
||||
name: Arc<str>,
|
||||
/// Port handle.
|
||||
port: Port<$Spec>,
|
||||
/// List of ports to connect to.
|
||||
conn: Vec<PortConnect>
|
||||
}
|
||||
impl AsRef<Port<$Spec>> for $Name { fn as_ref (&self) -> &Port<$Spec> { &self.port } }
|
||||
impl $Name {
|
||||
pub fn new ($jack: &Jack, name: impl AsRef<str>, connect: &[PortConnect])
|
||||
-> Usually<Self>
|
||||
{
|
||||
let $name = name.as_ref();
|
||||
let jack = $jack.clone();
|
||||
let port = $port?;
|
||||
let name = $name.into();
|
||||
let conn = connect.to_vec();
|
||||
let port = Self { jack, port, name, conn };
|
||||
port.connect_to_matching()?;
|
||||
Ok(port)
|
||||
}
|
||||
pub fn name (&self) -> &Arc<str> { &self.name }
|
||||
pub fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
pub fn port_mut (&mut self) -> &mut Port<$Spec> { &mut self.port }
|
||||
pub fn into_port (self) -> Port<$Spec> { self.port }
|
||||
pub fn close (self) -> Usually<()> {
|
||||
let Self { jack, port, .. } = self;
|
||||
Ok(jack.with_client(|client|client.unregister_port(port))?)
|
||||
}
|
||||
}
|
||||
impl HasJack for $Name { fn jack (&self) -> &Jack { &self.jack } }
|
||||
impl JackPort for $Name {
|
||||
type Port = $Spec;
|
||||
type Pair = $Pair;
|
||||
fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
}
|
||||
impl JackPortConnect<&str> for $Name {
|
||||
fn connect_to (&self, to: &str) -> Usually<PortConnectStatus> {
|
||||
self.with_client(|c|if let Some(ref port) = c.port_by_name(to.as_ref()) {
|
||||
self.connect_to(port)
|
||||
} else {
|
||||
Ok(Missing)
|
||||
})
|
||||
}
|
||||
}
|
||||
impl JackPortConnect<&Port<Unowned>> for $Name {
|
||||
fn connect_to (&self, port: &Port<Unowned>) -> Usually<PortConnectStatus> {
|
||||
self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
||||
Connected
|
||||
} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
||||
Connected
|
||||
} else {
|
||||
Mismatch
|
||||
}))
|
||||
}
|
||||
}
|
||||
impl JackPortConnect<&Port<$Pair>> for $Name {
|
||||
fn connect_to (&self, port: &Port<$Pair>) -> Usually<PortConnectStatus> {
|
||||
self.with_client(|c|Ok(if let Ok(_) = c.connect_ports(&self.port, port) {
|
||||
Connected
|
||||
} else if let Ok(_) = c.connect_ports(port, &self.port) {
|
||||
Connected
|
||||
} else {
|
||||
Mismatch
|
||||
}))
|
||||
}
|
||||
}
|
||||
impl JackPortAutoconnect for $Name {
|
||||
fn conn (&self) -> &[PortConnect] {
|
||||
&self.conn
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_port!(JackAudioIn: AudioIn -> AudioOut |j, n|j.register_port::<AudioIn>(n));
|
||||
|
||||
impl_port!(JackAudioOut: AudioOut -> AudioIn |j, n|j.register_port::<AudioOut>(n));
|
||||
|
||||
impl_port!(JackMidiIn: MidiIn -> MidiOut |j, n|j.register_port::<MidiIn>(n));
|
||||
|
||||
impl_port!(JackMidiOut: MidiOut -> MidiIn |j, n|j.register_port::<MidiOut>(n));
|
||||
|
|
|
|||
|
|
@ -9,10 +9,29 @@ pub(crate) use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering::Rela
|
|||
pub(crate) use std::fmt::Debug;
|
||||
pub(crate) use std::ops::{Add, Sub, Mul, Div, Rem};
|
||||
|
||||
pub(crate) use ::tengri::{Usually, tui::*};
|
||||
pub(crate) use ::tengri::{from, Usually, tui::*};
|
||||
|
||||
pub use ::atomic_float; pub(crate) use atomic_float::*;
|
||||
|
||||
pub trait Has<T>: Send + Sync {
|
||||
fn get (&self) -> &T;
|
||||
fn get_mut (&mut self) -> &mut T;
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! has {
|
||||
($T:ty: |$self:ident : $S:ty| $x:expr) => {
|
||||
impl Has<$T> for $S {
|
||||
fn get (&$self) -> &$T { &$x }
|
||||
fn get_mut (&mut $self) -> &mut $T { &mut $x }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub trait HasN<T>: Send + Sync {
|
||||
fn get_nth (&self, key: usize) -> &T;
|
||||
fn get_nth_mut (&mut self, key: usize) -> &mut T;
|
||||
}
|
||||
|
||||
pub trait Gettable<T> {
|
||||
/// Returns current value
|
||||
fn get (&self) -> T;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ pub use ::midly::{
|
|||
live::*,
|
||||
};
|
||||
|
||||
mod midi_in; pub use self::midi_in::*;
|
||||
mod midi_out; pub use self::midi_out::*;
|
||||
|
||||
/// Update notes_in array
|
||||
pub fn update_keys (keys: &mut[bool;128], message: &MidiMessage) {
|
||||
match message {
|
||||
|
|
@ -35,28 +38,3 @@ pub fn all_notes_off (output: &mut [Vec<Vec<u8>>]) {
|
|||
evt.write(&mut buf).unwrap();
|
||||
output[0].push(buf);
|
||||
}
|
||||
|
||||
/// Trait for thing that may receive MIDI.
|
||||
pub trait HasMidiIns {
|
||||
fn midi_ins (&self) -> &Vec<JackMidiIn>;
|
||||
|
||||
fn midi_ins_mut (&mut self) -> &mut Vec<JackMidiIn>;
|
||||
|
||||
fn has_midi_ins (&self) -> bool {
|
||||
!self.midi_ins().is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for thing that may output MIDI.
|
||||
pub trait HasMidiOuts {
|
||||
fn midi_outs (&self) -> &Vec<JackMidiOut>;
|
||||
|
||||
fn midi_outs_mut (&mut self) -> &mut Vec<JackMidiOut>;
|
||||
|
||||
fn has_midi_outs (&self) -> bool {
|
||||
!self.midi_outs().is_empty()
|
||||
}
|
||||
|
||||
/// Buffer for serializing a MIDI event. FIXME rename
|
||||
fn midi_note (&mut self) -> &mut Vec<u8>;
|
||||
}
|
||||
|
|
|
|||
42
crates/engine/src/midi/midi_in.rs
Normal file
42
crates/engine/src/midi/midi_in.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use crate::*;
|
||||
|
||||
impl<T: Has<Vec<JackMidiIn>>> HasMidiIns for T {
|
||||
fn midi_ins (&self) -> &Vec<JackMidiIn> {
|
||||
self.get()
|
||||
}
|
||||
fn midi_ins_mut (&mut self) -> &mut Vec<JackMidiIn> {
|
||||
self.get_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for thing that may receive MIDI.
|
||||
pub trait HasMidiIns {
|
||||
fn midi_ins (&self) -> &Vec<JackMidiIn>;
|
||||
fn midi_ins_mut (&mut self) -> &mut Vec<JackMidiIn>;
|
||||
/// Collect MIDI input from app ports (TODO preallocate large buffers)
|
||||
fn midi_input_collect <'a> (&'a self, scope: &'a ProcessScope) -> CollectedMidiInput<'a> {
|
||||
self.midi_ins().iter()
|
||||
.map(|port|port.port().iter(scope)
|
||||
.map(|RawMidi { time, bytes }|(time, LiveEvent::parse(bytes)))
|
||||
.collect::<Vec<_>>())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
fn midi_ins_with_sizes <'a> (&'a self) ->
|
||||
impl Iterator<Item=(usize, &Arc<str>, &[PortConnect], usize, usize)> + Send + Sync + 'a
|
||||
{
|
||||
let mut y = 0;
|
||||
self.midi_ins().iter().enumerate().map(move|(i, input)|{
|
||||
let height = 1 + input.conn().len();
|
||||
let data = (i, input.name(), input.conn(), y, y + height);
|
||||
y += height;
|
||||
data
|
||||
})
|
||||
}
|
||||
fn midi_in_add (&mut self, jack: &Jack) -> Usually<()> {
|
||||
let index = self.midi_ins().len();
|
||||
self.midi_ins_mut().push(JackMidiIn::new(jack, &format!("M/{index}"), &[])?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub type CollectedMidiInput<'a> = Vec<Vec<(u32, Result<LiveEvent<'a>, MidiError>)>>;
|
||||
33
crates/engine/src/midi/midi_out.rs
Normal file
33
crates/engine/src/midi/midi_out.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use crate::*;
|
||||
|
||||
impl<T: Has<Vec<JackMidiOut>>> HasMidiOuts for T {
|
||||
fn midi_outs (&self) -> &Vec<JackMidiOut> {
|
||||
self.get()
|
||||
}
|
||||
fn midi_outs_mut (&mut self) -> &mut Vec<JackMidiOut> {
|
||||
self.get_mut()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Trait for thing that may output MIDI.
|
||||
pub trait HasMidiOuts {
|
||||
fn midi_outs (&self) -> &Vec<JackMidiOut>;
|
||||
fn midi_outs_mut (&mut self) -> &mut Vec<JackMidiOut>;
|
||||
fn midi_outs_with_sizes <'a> (&'a self) ->
|
||||
impl Iterator<Item=(usize, &Arc<str>, &[PortConnect], usize, usize)> + Send + Sync + 'a
|
||||
{
|
||||
let mut y = 0;
|
||||
self.midi_outs().iter().enumerate().map(move|(i, output)|{
|
||||
let height = 1 + output.conn().len();
|
||||
let data = (i, output.name(), output.conn(), y, y + height);
|
||||
y += height;
|
||||
data
|
||||
})
|
||||
}
|
||||
fn midi_out_add (&mut self, jack: &Jack) -> Usually<()> {
|
||||
let index = self.midi_outs().len();
|
||||
self.midi_outs_mut().push(JackMidiOut::new(&jack, &format!("{index}/M"), &[])?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue