diff --git a/crates/tek_sequencer/src/arranger.rs b/crates/tek_sequencer/src/arranger.rs index 8ef229af..b2c8c6db 100644 --- a/crates/tek_sequencer/src/arranger.rs +++ b/crates/tek_sequencer/src/arranger.rs @@ -2,6 +2,8 @@ use crate::*; /// Root level object for standalone `tek_arranger` pub struct Arranger { + /// JACK client handle (needs to not be dropped for standalone mode to work). + pub jack: Option>, /// Which view is focused pub focus_cursor: (usize, usize), /// Controls the JACK transport. @@ -121,7 +123,8 @@ impl Arranger { phrases: Arc>>, ) -> Self { let mut app = Self { - focus_cursor: (0, 1), + jack: None, + focus_cursor: (0, 1), phrases_split: 20, arrangement_split: 21, editor: PhraseEditor::new(), diff --git a/crates/tek_sequencer/src/arranger_cli.rs b/crates/tek_sequencer/src/arranger_cli.rs index 2703fc6b..f3ac2798 100644 --- a/crates/tek_sequencer/src/arranger_cli.rs +++ b/crates/tek_sequencer/src/arranger_cli.rs @@ -44,19 +44,26 @@ impl ArrangerCli { Some(okhsl_to_rgb(scene_color_1.mix(scene_color_2, i as f32 / self.scenes as f32))) )?; } - transport.write().unwrap().jack = Some( - jack.activate( - &transport.clone(), - |state: &Arc>>, client, scope| { - state.write().unwrap().process(client, scope) - } - )?.into() - ); - Tui::run(Arc::new(RwLock::new(Arranger::new( + let arranger = Arc::new(RwLock::new(Arranger::new( self.transport.then_some(transport), arrangement, phrases, - ))))?; + ))); + let jack = jack.activate(&arranger.clone(), arranger_jack_callback)?; + let jack = Some(jack.into()); + if let Some(ref transport) = arranger.read().unwrap().transport { + transport.write().unwrap().jack = jack.clone(); + } + arranger.write().unwrap().jack = jack.clone(); + Tui::run(arranger)?; Ok(()) } } + +fn arranger_jack_callback ( + state: &Arc>>, + client: &Client, + scope: &ProcessScope, +) -> Control { + state.write().unwrap().process(client, scope) +} diff --git a/crates/tek_sequencer/src/arranger_snd.rs b/crates/tek_sequencer/src/arranger_snd.rs new file mode 100644 index 00000000..c5ba2457 --- /dev/null +++ b/crates/tek_sequencer/src/arranger_snd.rs @@ -0,0 +1,9 @@ +use crate::*; +impl Audio for Arranger { + fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { + if let Some(ref transport) = self.transport { + transport.write().unwrap().process(client, scope); + } + todo!("arranger process") + } +} diff --git a/crates/tek_sequencer/src/lib.rs b/crates/tek_sequencer/src/lib.rs index 8f000956..ccbc4007 100644 --- a/crates/tek_sequencer/src/lib.rs +++ b/crates/tek_sequencer/src/lib.rs @@ -10,7 +10,7 @@ pub(crate) use palette::{*, convert::*, okhsl::*}; use rand::distributions::uniform::UniformSampler; submod! { - arranger arranger_cmd arranger_tui + arranger arranger_cmd arranger_tui arranger_snd sequencer sequencer_cmd sequencer_tui sequencer_snd transport transport_cmd transport_tui transport_snd } diff --git a/crates/tek_sequencer/src/sequencer.rs b/crates/tek_sequencer/src/sequencer.rs index b678fe38..fe2bbba7 100644 --- a/crates/tek_sequencer/src/sequencer.rs +++ b/crates/tek_sequencer/src/sequencer.rs @@ -7,6 +7,8 @@ pub type PhraseMessage = Vec; pub type PhraseChunk = [Vec]; /// Root level object for standalone `tek_sequencer` pub struct Sequencer { + /// JACK client handle (needs to not be dropped for standalone mode to work). + pub jack: Option>, /// Which view is focused pub focus_cursor: (usize, usize), /// Controls the JACK transport. diff --git a/crates/tek_sequencer/src/sequencer_cli.rs b/crates/tek_sequencer/src/sequencer_cli.rs index 53b31058..45f47ea3 100644 --- a/crates/tek_sequencer/src/sequencer_cli.rs +++ b/crates/tek_sequencer/src/sequencer_cli.rs @@ -18,34 +18,41 @@ pub struct SequencerCli { impl SequencerCli { fn run (&self) -> Usually<()> { - let jack = Client::new("tek_arranger", ClientOptions::NO_START_SERVER)?.0; - let jack = JackClient::Inactive(jack); + let jack = Client::new("tek_arranger", ClientOptions::NO_START_SERVER)?.0; + let jack = JackClient::Inactive(jack); let transport = Arc::new(RwLock::new(TransportToolbar::new(None, Some(jack.transport())))); - transport.write().unwrap().jack = Some( - jack.activate( - &transport.clone(), - |state: &Arc>>, client, scope| { - state.write().unwrap().process(client, scope) - } - )?.into() - ); let focus_cursor = (1, 1); let clock = transport.read().unwrap().clock.clone(); let transport = self.transport.then_some(transport); let editor = PhraseEditor::new(); let phrases = Arc::new(RwLock::new(PhrasePool::new())); - let seq = Sequencer { focus_cursor, clock, transport, editor, phrases }; + let sequencer = Sequencer { jack: None, focus_cursor, clock, transport, editor, phrases }; if let Some(_) = self.name.as_ref() { - // TODO: seq.name = Arc::new(RwLock::new(name.clone())); + // TODO: sequencer.name = Arc::new(RwLock::new(name.clone())); } if let Some(_) = self.ppq { - // TODO: seq.ppq = ppq; + // TODO: sequencer.ppq = ppq; } if let Some(_) = self.length { - // TODO: if let Some(phrase) = seq.phrase.as_mut() { + // TODO: if let Some(phrase) = sequencer.phrase.as_mut() { //phrase.write().unwrap().length = length; //} } - Tui::run(Arc::new(RwLock::new(seq))).map(|_|()) + let sequencer = Arc::new(RwLock::new(sequencer)); + let jack = jack.activate(&sequencer.clone(), sequencer_jack_callback)?; + let jack = Some(jack.into()); + if let Some(ref transport) = sequencer.read().unwrap().transport { + transport.write().unwrap().jack = jack.clone(); + } + sequencer.write().unwrap().jack = jack.clone(); + Tui::run(sequencer).map(|_|()) } } + +fn sequencer_jack_callback ( + state: &Arc>>, + client: &Client, + scope: &ProcessScope, +) -> Control { + state.write().unwrap().process(client, scope) +} diff --git a/crates/tek_sequencer/src/sequencer_snd.rs b/crates/tek_sequencer/src/sequencer_snd.rs index 3253acd7..1c790c65 100644 --- a/crates/tek_sequencer/src/sequencer_snd.rs +++ b/crates/tek_sequencer/src/sequencer_snd.rs @@ -1,4 +1,13 @@ use crate::*; +impl Audio for Sequencer { + fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { + if let Some(ref transport) = self.transport { + transport.write().unwrap().process(client, scope); + } + todo!("sequencer process") + } +} + impl Phrase { /// Write a chunk of MIDI events to an output port. pub fn process_out ( diff --git a/crates/tek_sequencer/src/transport_cli.rs b/crates/tek_sequencer/src/transport_cli.rs index 739ddce9..15db296d 100644 --- a/crates/tek_sequencer/src/transport_cli.rs +++ b/crates/tek_sequencer/src/transport_cli.rs @@ -7,14 +7,16 @@ pub fn main () -> Usually<()> { let mut transport = TransportToolbar::new(None, Some(jack.transport())); transport.focused = true; let transport = Arc::new(RwLock::new(transport)); - transport.write().unwrap().jack = Some( - jack.activate( - &transport.clone(), - |state: &Arc>>, client, scope| { - state.write().unwrap().process(client, scope) - } - )?.into() - ); + let jack = jack.activate(&transport.clone(), transport_jack_callback)?; + transport.write().unwrap().jack = Some(jack.into()); Tui::run(transport)?; Ok(()) } + +fn transport_jack_callback ( + state: &Arc>>, + client: &Client, + scope: &ProcessScope, +) -> Control { + state.write().unwrap().process(client, scope) +}