pub extern crate jack; pub extern crate midly; pub extern crate tengri; mod engine_structs; pub use self::engine_structs::*; mod engine_traits; pub use self::engine_traits::*; mod engine_impls; mod jack_structs; pub use self::jack_structs::*; mod jack_traits; pub use self::jack_traits::*; mod jack_types; pub use self::jack_types::*; mod jack_impls; pub(crate) use ::{ tengri::{Usually, from, output::PerfModel}, atomic_float::AtomicF64, std::{ fmt::Debug, ops::{Add, Sub, Mul, Div, Rem}, sync::{Arc, RwLock, atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed}}, }, }; pub use ::{ jack::{*, contrib::{*, ClosureProcessHandler}}, midly::{Smf, TrackEventKind, MidiMessage, Error as MidiError, num::*, live::*,} }; pub const DEFAULT_PPQ: f64 = 96.0; /// FIXME: remove this and use PPQ from timebase everywhere: pub const PPQ: usize = 96; /// (pulses, name), assuming 96 PPQ pub const NOTE_DURATIONS: [(usize, &str);26] = [ (1, "1/384"), (2, "1/192"), (3, "1/128"), (4, "1/96"), (6, "1/64"), (8, "1/48"), (12, "1/32"), (16, "1/24"), (24, "1/16"), (32, "1/12"), (48, "1/8"), (64, "1/6"), (96, "1/4"), (128, "1/3"), (192, "1/2"), (256, "2/3"), (384, "1/1"), (512, "4/3"), (576, "3/2"), (768, "2/1"), (1152, "3/1"), (1536, "4/1"), (2304, "6/1"), (3072, "8/1"), (3456, "9/1"), (6144, "16/1"), ]; pub const NOTE_NAMES: [&str; 128] = [ "C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0", "C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1", "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5", "C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", "C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7", "C8", "C#8", "D8", "D#8", "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8", "C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", "G#9", "A9", "A#9", "B9", "C10", "C#10", "D10", "D#10", "E10", "F10", "F#10", "G10", ]; /// Return boxed iterator of MIDI events pub fn parse_midi_input <'a> (input: ::jack::MidiIter<'a>) -> Box, &'a [u8])> + 'a> { Box::new(input.map(|::jack::RawMidi { time, bytes }|( time as usize, LiveEvent::parse(bytes).unwrap(), bytes ))) } /// Add "all notes off" to the start of a buffer. pub fn all_notes_off (output: &mut [Vec>]) { let mut buf = vec![]; let msg = MidiMessage::Controller { controller: 123.into(), value: 0.into() }; let evt = LiveEvent::Midi { channel: 0.into(), message: msg }; evt.write(&mut buf).unwrap(); output[0].push(buf); } /// 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; }, _ => {} } } /// Returns the next shorter length pub fn note_duration_prev (pulses: usize) -> usize { for (length, _) in NOTE_DURATIONS.iter().rev() { if *length < pulses { return *length } } pulses } /// Returns the next longer length pub fn note_duration_next (pulses: usize) -> usize { for (length, _) in NOTE_DURATIONS.iter() { if *length > pulses { return *length } } pulses } pub fn note_duration_to_name (pulses: usize) -> &'static str { for (length, name) in NOTE_DURATIONS.iter() { if *length == pulses { return name } } "" } pub fn note_pitch_to_name (n: usize) -> &'static str { if n > 127 { panic!("to_note_name({n}): must be 0-127"); } NOTE_NAMES[n] } //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<'static>, ///// Port name //name: Arc, ///// Port handle. //port: Port<$Spec>, ///// List of ports to connect to. //conn: Vec //} //impl AsRef> for $Name { //fn as_ref (&self) -> &Port<$Spec> { &self.port } //} //impl $Name { //pub fn new ($jack: &Jack, name: impl AsRef, connect: &[PortConnect]) //-> Usually //{ //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 { &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<'static> for $Name { //fn jack (&self) -> &'static Jack<'static> { &self.jack } //} //impl JackPort<'static> for $Name { //type Port = $Spec; //type Pair = $Pair; //fn port (&self) -> &Port<$Spec> { &self.port } //} //impl ConnectTo<'static, &str> for $Name { //fn connect_to (&self, to: &str) -> Usually { //self.with_client(|c|if let Some(ref port) = c.port_by_name(to.as_ref()) { //self.connect_to(port) //} else { //Ok(Missing) //}) //} //} //impl ConnectTo<'static, &Port> for $Name { //fn connect_to (&self, port: &Port) -> Usually { //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 ConnectTo<'static, &Port<$Pair>> for $Name { //fn connect_to (&self, port: &Port<$Pair>) -> Usually { //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 ConnectAuto<'static> for $Name { //fn connections (&self) -> &[PortConnect] { //&self.conn //} //} //}; //}