mod handle; mod jack; mod render; pub use self::handle::*; pub use self::jack::*; pub use self::render::*; use crate::prelude::*; // TODO: // - Meters: propagate clipping: // - If one stage clips, all stages after it are marked red // - If one track clips, all tracks that feed from it are marked red? pub const ACTIONS: [(&'static str, &'static str);2] = [ ("+/-", "Adjust"), ("Ins/Del", "Add/remove track"), ]; pub struct Mixer { exited: bool, jack: Jack, tracks: Vec, selected_track: usize, selected_column: usize, } pub struct Track { name: String, channels: u8, input_ports: Vec>, pre_gain_meter: f64, gain: f64, insert_ports: Vec>, return_ports: Vec>, post_gain_meter: f64, post_insert_meter: f64, level: f64, pan: f64, output_ports: Vec>, post_fader_meter: f64, route: String, } impl Mixer { pub fn new () -> Result> { let (client, status) = Client::new( "bloop-mixer", ClientOptions::NO_START_SERVER )?; let jack = client.activate_async( Notifications, ClosureProcessHandler::new(Box::new( move |_: &Client, _: &ProcessScope| -> Control { Control::Continue }) as BoxControl + Send> ) )?; Ok(Self { exited: false, selected_column: 0, selected_track: 1, tracks: vec![ Track::new(&jack.as_client(), 1, "Kick")?, Track::new(&jack.as_client(), 1, "Snare")?, Track::new(&jack.as_client(), 2, "Hihats")?, Track::new(&jack.as_client(), 2, "Sample")?, Track::new(&jack.as_client(), 2, "Bus 1")?, Track::new(&jack.as_client(), 2, "Bus 2")?, Track::new(&jack.as_client(), 2, "Mix")?, ], jack, }) } } impl Track { pub fn new (jack: &Client, channels: u8, name: &str) -> Result> { let mut input_ports = vec![]; let mut insert_ports = vec![]; let mut return_ports = vec![]; let mut output_ports = vec![]; for channel in 1..=channels { input_ports.push(jack.register_port(&format!("{name} [input {channel}]"), AudioIn::default())?); output_ports.push(jack.register_port(&format!("{name} [out {channel}]"), AudioOut::default())?); let insert_port = jack.register_port(&format!("{name} [pre {channel}]"), AudioOut::default())?; let return_port = jack.register_port(&format!("{name} [insert {channel}]"), AudioIn::default())?; jack.connect_ports(&insert_port, &return_port)?; insert_ports.push(insert_port); return_ports.push(return_port); } Ok(Self { name: name.into(), channels, input_ports, pre_gain_meter: 0.0, gain: 0.0, post_gain_meter: 0.0, insert_ports, return_ports, post_insert_meter: 0.0, level: 0.0, pan: 0.0, post_fader_meter: 0.0, route: "---".into(), output_ports, }) } } impl Exitable for Mixer { fn exit (&mut self) { self.exited = true } fn exited (&self) -> bool { self.exited } }