use crate::*; pub type SequencerApp = AppContainer< Tui, SequencerModel, SequencerView, SequencerViewCommand, SequencerAudio, SequencerStatusBar >; impl TryFrom<&Arc>> for SequencerApp { type Error = Box; fn try_from (jack: &Arc>) -> Usually { let clock = Arc::new(Clock::from(Instant::default())); let transport = Arc::new(RwLock::new(tek_api::Transport { metronome: false, transport: jack.read().unwrap().transport(), jack: jack.clone(), clock: clock.clone() })); let phrases = Arc::new(RwLock::new(PhrasePool { phrases: vec![] // FIXME })); let player = Arc::new(RwLock::new(MIDIPlayer::new(jack, &clock, "preview")?)); let model = Arc::new(RwLock::new(SequencerModel { transport: transport.clone(), phrases: phrases.clone(), player: player.clone() })); Ok(Self::new( &model, SequencerView::from(&model), SequencerAudio(transport.clone(), player.clone()), None, None, )) } } pub struct SequencerModel { /// State of the JACK transport. pub transport: Arc>, /// State of the phrase pool. pub phrases: Arc>, /// State of the phrase player. pub player: Arc>, } impl From<&Arc>> for SequencerView { fn from (model: &Arc>) -> Self { Self { split: 20, transport: TransportView::from(&model.read().unwrap().transport), phrases: PhrasePoolView::from(&model.read().unwrap().phrases), editor: PhraseEditor::new(), model: model.clone(), } } } /// Root level object for standalone `tek_sequencer`. /// Also embeddable, in which case the `player` is used for preview. pub struct SequencerView { pub model: Arc>, /// Displays the JACK transport. pub transport: TransportView, /// Displays the phrase pool pub phrases: PhrasePoolView, /// Displays the phrase editor pub editor: PhraseEditor, /// Width of phrase pool pub split: u16, } impl Content for SequencerView { type Engine = Tui; fn content (&self) -> impl Widget { col!( self.transport, Split::right(20, widget(&self.phrases), widget(&self.editor)).min_y(20) ) } }