diff --git a/crates/tek_mixer/src/mixer.rs b/crates/tek_mixer/src/mixer.rs index 1c9db6e2..bcc02d0a 100644 --- a/crates/tek_mixer/src/mixer.rs +++ b/crates/tek_mixer/src/mixer.rs @@ -1,15 +1,17 @@ use crate::*; pub struct Mixer { + /// JACK client handle (needs to not be dropped for standalone mode to work). + pub jack: Arc>, pub name: String, pub tracks: Vec>, pub selected_track: usize, pub selected_column: usize, } impl Mixer { - pub fn new (name: &str) -> Usually { - let (client, _status) = Client::new(name, ClientOptions::NO_START_SERVER)?; + pub fn new (jack: &Arc>, name: &str) -> Usually { Ok(Self { + jack: jack.clone(), name: name.into(), selected_column: 0, selected_track: 1, diff --git a/crates/tek_mixer/src/mixer_cli.rs b/crates/tek_mixer/src/mixer_cli.rs index e69de29b..7af8bff5 100644 --- a/crates/tek_mixer/src/mixer_cli.rs +++ b/crates/tek_mixer/src/mixer_cli.rs @@ -0,0 +1,22 @@ +//! Multi-track mixer +include!("lib.rs"); +use tek_core::clap::{self, Parser}; +pub fn main () -> Usually<()> { MixerCli::parse().run() } +#[derive(Debug, Parser)] #[command(version, about, long_about = None)] pub struct MixerCli { + /// Name of JACK client + #[arg(short, long)] name: Option, + /// Number of tracks + #[arg(short, long)] channels: Option, +} +impl MixerCli { + fn run (&self) -> Usually<()> { + Tui::run(JackClient::new("tek_mixer")?.activate_with(|jack|{ + let mut mixer = Mixer::new(jack, self.name.as_ref().map(|x|x.as_str()).unwrap_or("mixer"))?; + for channel in 0..self.channels.unwrap_or(8) { + mixer.track_add(&format!("Track {}", channel + 1), 1)?; + } + Ok(mixer) + })?)?; + Ok(()) + } +} diff --git a/crates/tek_mixer/src/plugin.rs b/crates/tek_mixer/src/plugin.rs index b3b277c3..b10d4499 100644 --- a/crates/tek_mixer/src/plugin.rs +++ b/crates/tek_mixer/src/plugin.rs @@ -3,6 +3,8 @@ use crate::*; /// A plugin device. pub struct Plugin { _engine: PhantomData, + /// JACK client handle (needs to not be dropped for standalone mode to work). + pub jack: Arc>, pub name: String, pub path: Option, pub plugin: Option, @@ -13,9 +15,13 @@ pub struct Plugin { impl Plugin { /// Create a plugin host device. - pub fn new (name: &str) -> Usually { + pub fn new ( + jack: &Arc>, + name: &str, + ) -> Usually { Ok(Self { _engine: Default::default(), + jack: jack.clone(), name: name.into(), path: None, plugin: None, @@ -27,11 +33,16 @@ impl Plugin { } impl Plugin { - pub fn new_lv2 (name: &str, path: &str) -> Usually> { + pub fn new_lv2 ( + jack: &Arc>, + name: &str, + path: &str, + ) -> Usually> { let plugin = LV2Plugin::new(path)?; jack_from_lv2(name, &plugin.plugin)? .run(|ports|Box::new(Self { _engine: Default::default(), + jack: jack.clone(), name: name.into(), path: Some(String::from(path)), plugin: Some(PluginKind::LV2(plugin)), diff --git a/crates/tek_mixer/src/plugin_cli.rs b/crates/tek_mixer/src/plugin_cli.rs index 622db58b..1bd62ca5 100644 --- a/crates/tek_mixer/src/plugin_cli.rs +++ b/crates/tek_mixer/src/plugin_cli.rs @@ -1,6 +1,23 @@ //! Plugin host include!("lib.rs"); -pub fn main () -> Usually<()> { - Tui::run(Arc::new(RwLock::new(crate::Plugin::new("")?)))?; - Ok(()) +use tek_core::clap::{self, Parser}; +pub fn main () -> Usually<()> { PluginCli::parse().run() } +#[derive(Debug, Parser)] #[command(version, about, long_about = None)] pub struct PluginCli { + /// Name of JACK client + #[arg(short, long)] name: Option, + /// Path to plugin + #[arg(short, long)] path: Option, +} +impl PluginCli { + fn run (&self) -> Usually<()> { + Tui::run(JackClient::new("tek_plugin")?.activate_with(|jack|{ + let mut plugin = Plugin::new_lv2( + jack, + self.name.as_ref().map(|x|x.as_str()).unwrap_or("mixer"), + self.path.as_ref().expect("pass --path /to/lv2/plugin.so") + )?; + Ok(plugin) + })?)?; + Ok(()) + } } diff --git a/crates/tek_mixer/src/sampler.rs b/crates/tek_mixer/src/sampler.rs index 6a0879c9..05dfcce7 100644 --- a/crates/tek_mixer/src/sampler.rs +++ b/crates/tek_mixer/src/sampler.rs @@ -1,7 +1,9 @@ use crate::*; /// The sampler plugin plays sounds. -pub struct Sampler { +pub struct Sampler { + _engine: PhantomData, + pub jack: Arc>, pub name: String, pub cursor: (usize, usize), pub editing: Option>>, @@ -14,7 +16,7 @@ pub struct Sampler { pub output_gain: f32 } -impl Sampler { +impl Sampler { pub fn from_edn <'e> (args: &[Edn<'e>]) -> Usually> { let mut name = String::new(); let mut dir = String::new(); @@ -54,6 +56,7 @@ impl Sampler { .audio_out("outL") .audio_out("outR") .run(|ports|Box::new(Self { + _engine: Default::default(), name: name.into(), cursor: (0, 0), editing: None, @@ -135,7 +138,7 @@ impl Sampler { } } -impl Audio for Sampler { +impl Audio for Sampler { fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control { self.process_midi_in(scope); self.clear_output_buffer(); @@ -144,7 +147,7 @@ impl Audio for Sampler { Control::Continue } } -impl Handle for Sampler { +impl Handle for Sampler { fn handle (&mut self, from: &TuiInput) -> Perhaps { match from.event() { key!(KeyCode::Up) => { @@ -188,7 +191,7 @@ impl Handle for Sampler { } } -impl Widget for Sampler { +impl Widget for Sampler { type Engine = Tui; fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> { todo!() @@ -198,7 +201,7 @@ impl Widget for Sampler { } } -pub fn tui_render_sampler (sampler: &Sampler, to: &mut TuiOutput) -> Usually<()> { +pub fn tui_render_sampler (sampler: &Sampler, to: &mut TuiOutput) -> Usually<()> { let [x, y, _, height] = to.area(); let style = Style::default().gray(); let title = format!(" {} ({})", sampler.name, sampler.voices.read().unwrap().len()); diff --git a/crates/tek_mixer/src/sampler_cli.rs b/crates/tek_mixer/src/sampler_cli.rs index edcbe8c6..3b9f42fa 100644 --- a/crates/tek_mixer/src/sampler_cli.rs +++ b/crates/tek_mixer/src/sampler_cli.rs @@ -1,6 +1,22 @@ //! Sample player include!("lib.rs"); -pub fn main () -> Usually<()> { - Tui::run(Arc::new(RwLock::new(crate::Sampler::new("", None)?)))?; - Ok(()) +use tek_core::clap::{self, Parser}; +pub fn main () -> Usually<()> { SamplerCli::parse().run() } +#[derive(Debug, Parser)] #[command(version, about, long_about = None)] pub struct SamplerCli { + /// Name of JACK client + #[arg(short, long)] name: Option, + /// Path to plugin + #[arg(short, long)] path: Option, +} +impl SamplerCli { + fn run (&self) -> Usually<()> { + Tui::run(JackClient::new("tek_sampler")?.activate_with(|jack|{ + let mut plugin = Sampler::new( + jack, + self.name.as_ref().map(|x|x.as_str()).unwrap_or("mixer"), + )?; + Ok(plugin) + })?)?; + Ok(()) + } }