mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
wip: down to 13 errors
This commit is contained in:
parent
6ce83fb27a
commit
ebdb8881e9
19 changed files with 793 additions and 691 deletions
|
|
@ -189,7 +189,7 @@ macro_rules! impl_port {
|
|||
type Pair = $Pair;
|
||||
fn port (&self) -> &Port<$Spec> { &self.port }
|
||||
}
|
||||
impl JackPortConnect<&str> for $Name {
|
||||
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)
|
||||
|
|
@ -233,5 +233,3 @@ 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));
|
||||
|
|
|
|||
|
|
@ -18,6 +18,16 @@ pub trait Has<T>: Send + Sync {
|
|||
fn get_mut (&mut self) -> &mut T;
|
||||
}
|
||||
|
||||
pub trait MaybeHas<T>: Send + Sync {
|
||||
fn get (&self) -> Option<&T>;
|
||||
}
|
||||
|
||||
impl<T, U: Has<Option<T>>> MaybeHas<T> for U {
|
||||
fn get (&self) -> Option<&T> {
|
||||
Has::<Option<T>>::get(self).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! has {
|
||||
($T:ty: |$self:ident : $S:ty| $x:expr) => {
|
||||
impl Has<$T> for $S {
|
||||
|
|
|
|||
|
|
@ -9,17 +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 {
|
||||
MidiMessage::NoteOn { key, .. } => { keys[key.as_int() as usize] = true; }
|
||||
MidiMessage::NoteOff { key, .. } => { keys[key.as_int() as usize] = false; },
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
mod midi_in; pub use self::midi_in::*;
|
||||
mod midi_out; pub use self::midi_out::*;
|
||||
mod midi_hold; pub use self::midi_hold::*;
|
||||
|
||||
/// Return boxed iterator of MIDI events
|
||||
pub fn parse_midi_input <'a> (input: ::jack::MidiIter<'a>) -> Box<dyn Iterator<Item=(usize, LiveEvent<'a>, &'a [u8])> + 'a> {
|
||||
|
|
|
|||
10
crates/engine/src/midi/midi_hold.rs
Normal file
10
crates/engine/src/midi/midi_hold.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
use crate::*;
|
||||
|
||||
/// Update notes_in array
|
||||
pub fn update_keys (keys: &mut[bool;128], message: &MidiMessage) {
|
||||
match message {
|
||||
MidiMessage::NoteOn { key, .. } => { keys[key.as_int() as usize] = true; }
|
||||
MidiMessage::NoteOff { key, .. } => { keys[key.as_int() as usize] = false; },
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,11 @@
|
|||
use crate::*;
|
||||
|
||||
impl JackMidiIn {
|
||||
pub fn parsed <'a> (&'a self, scope: &'a ProcessScope) -> impl Iterator<Item=(usize, LiveEvent<'a>, &'a [u8])> {
|
||||
parse_midi_input(self.port().iter(scope))
|
||||
}
|
||||
}
|
||||
|
||||
#[tengri_proc::command(JackMidiIn)]
|
||||
impl MidiInputCommand {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,151 @@
|
|||
use crate::*;
|
||||
|
||||
#[derive(Debug)] pub struct JackMidiOut {
|
||||
/// Handle to JACK client, for receiving reconnect events.
|
||||
jack: Jack,
|
||||
/// Port name
|
||||
name: Arc<str>,
|
||||
/// Port handle.
|
||||
port: Port<MidiOut>,
|
||||
/// List of ports to connect to.
|
||||
conn: Vec<PortConnect>,
|
||||
/// List of currently held notes.
|
||||
held: Arc<RwLock<[bool;128]>>,
|
||||
/// Buffer
|
||||
note_buffer: Vec<u8>,
|
||||
/// Buffer
|
||||
output_buffer: Vec<Vec<Vec<u8>>>,
|
||||
}
|
||||
|
||||
has!(Jack: |self: JackMidiOut|self.jack);
|
||||
|
||||
impl JackMidiOut {
|
||||
pub fn new (jack: &Jack, name: impl AsRef<str>, connect: &[PortConnect])
|
||||
-> Usually<Self>
|
||||
{
|
||||
let jack = jack.clone();
|
||||
let port = jack.register_port::<MidiOut>(name.as_ref())?;
|
||||
let name = name.as_ref().into();
|
||||
let conn = connect.to_vec();
|
||||
let port = Self {
|
||||
jack,
|
||||
port,
|
||||
name,
|
||||
conn,
|
||||
held: Arc::new([false;128].into()),
|
||||
note_buffer: vec![0;8],
|
||||
output_buffer: vec![vec![];65536],
|
||||
};
|
||||
port.connect_to_matching()?;
|
||||
Ok(port)
|
||||
}
|
||||
pub fn name (&self) -> &Arc<str> {
|
||||
&self.name
|
||||
}
|
||||
pub fn port (&self) -> &Port<MidiOut> {
|
||||
&self.port
|
||||
}
|
||||
pub fn port_mut (&mut self) -> &mut Port<MidiOut> {
|
||||
&mut self.port
|
||||
}
|
||||
pub fn into_port (self) -> Port<MidiOut> {
|
||||
self.port
|
||||
}
|
||||
pub fn close (self) -> Usually<()> {
|
||||
let Self { jack, port, .. } = self;
|
||||
Ok(jack.with_client(|client|client.unregister_port(port))?)
|
||||
}
|
||||
/// Clear the section of the output buffer that we will be using,
|
||||
/// emitting "all notes off" at start of buffer if requested.
|
||||
pub fn buffer_clear (&mut self, scope: &ProcessScope, reset: bool) {
|
||||
let n_frames = (scope.n_frames() as usize).min(self.output_buffer.len());
|
||||
for frame in &mut self.output_buffer[0..n_frames] {
|
||||
frame.clear();
|
||||
}
|
||||
if reset {
|
||||
all_notes_off(&mut self.output_buffer);
|
||||
}
|
||||
}
|
||||
/// Write a note to the output buffer
|
||||
pub fn buffer_write <'a> (
|
||||
&'a mut self,
|
||||
sample: usize,
|
||||
event: LiveEvent,
|
||||
) {
|
||||
self.note_buffer.fill(0);
|
||||
event.write(&mut self.note_buffer).expect("failed to serialize MIDI event");
|
||||
self.output_buffer[sample].push(self.note_buffer.clone());
|
||||
// Update the list of currently held notes.
|
||||
if let LiveEvent::Midi { ref message, .. } = event {
|
||||
update_keys(&mut*self.held.write().unwrap(), message);
|
||||
}
|
||||
}
|
||||
/// Write a chunk of MIDI data from the output buffer to the output port.
|
||||
pub fn buffer_emit (&mut self, scope: &ProcessScope) {
|
||||
let samples = scope.n_frames() as usize;
|
||||
let mut writer = self.port.writer(scope);
|
||||
for (time, events) in self.output_buffer.iter().enumerate().take(samples) {
|
||||
for bytes in events.iter() {
|
||||
writer.write(&RawMidi { time: time as u32, bytes }).unwrap_or_else(|_|{
|
||||
panic!("Failed to write MIDI data: {bytes:?}");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Port<MidiOut>> for JackMidiOut {
|
||||
fn as_ref (&self) -> &Port<MidiOut> {
|
||||
&self.port
|
||||
}
|
||||
}
|
||||
|
||||
impl JackPort for JackMidiOut {
|
||||
type Port = MidiOut;
|
||||
type Pair = MidiIn;
|
||||
fn port (&self) -> &Port<MidiOut> { &self.port }
|
||||
}
|
||||
|
||||
impl JackPortConnect<&str> for JackMidiOut {
|
||||
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 JackMidiOut {
|
||||
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<MidiIn>> for JackMidiOut {
|
||||
fn connect_to (&self, port: &Port<MidiIn>) -> 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 JackMidiOut {
|
||||
fn conn (&self) -> &[PortConnect] {
|
||||
&self.conn
|
||||
}
|
||||
}
|
||||
|
||||
#[tengri_proc::command(JackMidiOut)]
|
||||
impl MidiOutputCommand {
|
||||
}
|
||||
|
|
@ -29,6 +175,11 @@ pub trait HasMidiOuts {
|
|||
data
|
||||
})
|
||||
}
|
||||
fn midi_outs_emit (&mut self, scope: &ProcessScope) {
|
||||
for port in self.midi_outs_mut().iter_mut() {
|
||||
port.buffer_emit(scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trail for thing that may gain new MIDI ports.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue