use crate::*; /// Stores and displays time-related state. pub struct TransportToolbar { /// Enable metronome? pub metronome: bool, /// Current sample rate, tempo, and PPQ. pub timebase: Arc, /// JACK client handle (needs to not be dropped for standalone mode to work). pub jack: Option, /// JACK transport handle. pub transport: Option, /// Quantization factor /// Global frame and usec at which playback started pub started: Option<(usize, usize)>, pub focused: bool, pub focus: usize, pub playing: TransportPlayPauseButton, pub bpm: TransportBPM, pub quant: TransportQuantize, pub sync: TransportSync, pub clock: TransportClock, } impl TransportToolbar { pub fn standalone () -> Usually>> { let mut transport = Self::new(None); transport.focused = true; let jack = JackClient::Inactive( Client::new("tek_transport", ClientOptions::NO_START_SERVER)?.0 ); transport.transport = Some(jack.transport()); let transport = Arc::new(RwLock::new(transport)); transport.write().unwrap().jack = Some( jack.activate( &transport.clone(), |state, client, scope| { state.write().unwrap().process(client, scope) } )? ); Ok(transport) } pub fn new (transport: Option) -> Self { let timebase = Arc::new(Timebase::default()); Self { focused: false, focus: 0, playing: TransportPlayPauseButton { value: Some(TransportState::Stopped), focused: true }, bpm: TransportBPM { value: timebase.bpm(), focused: false }, quant: TransportQuantize { value: 24, focused: false }, sync: TransportSync { value: timebase.ppq() as usize * 4, focused: false }, clock: TransportClock { frame: 0, pulse: 0, ppq: 0, usecs: 0, focused: false }, transport, timebase, metronome: false, started: None, jack: None, } } pub fn toggle_play (&mut self) -> Usually<()> { let transport = self.transport.as_ref().unwrap(); self.playing.value = match self.playing.value.expect("1st frame has not been processed yet") { TransportState::Stopped => { transport.start()?; Some(TransportState::Starting) }, _ => { transport.stop()?; transport.locate(0)?; Some(TransportState::Stopped) }, }; Ok(()) } pub fn update (&mut self, scope: &ProcessScope) -> (bool, usize, usize, usize, usize, f64) { let CycleTimes { current_frames, current_usecs, next_usecs, period_usecs } = scope.cycle_times().unwrap(); let chunk_size = scope.n_frames() as usize; let transport = self.transport.as_ref().unwrap().query().unwrap(); self.clock.frame = transport.pos.frame() as usize; let mut reset = false; if self.playing.value != Some(transport.state) { match transport.state { TransportState::Rolling => { self.started = Some(( current_frames as usize, current_usecs as usize, )); }, TransportState::Stopped => { self.started = None; reset = true; }, _ => {} } } self.playing.value = Some(transport.state); ( reset, current_frames as usize, chunk_size as usize, current_usecs as usize, next_usecs as usize, period_usecs as f64 ) } pub fn bpm (&self) -> usize { self.timebase.bpm() as usize } pub fn ppq (&self) -> usize { self.timebase.ppq() as usize } pub fn pulse (&self) -> usize { self.timebase.frame_to_pulse(self.clock.frame as f64) as usize } pub fn usecs (&self) -> usize { self.timebase.frame_to_usec(self.clock.frame as f64) as usize } } impl<'a> Focus<5, TuiOutput<'a>, Rect> for TransportToolbar { fn focus (&self) -> usize { self.focus } fn focus_mut (&mut self) -> &mut usize { &mut self.focus } fn focusable (&self) -> [&dyn Focusable, Rect>;5] { [ &self.playing as &dyn Focusable, Rect>, &self.bpm as &dyn Focusable, Rect>, &self.quant as &dyn Focusable, Rect>, &self.sync as &dyn Focusable, Rect>, &self.clock as &dyn Focusable, Rect>, ] } fn focusable_mut (&mut self) -> [&mut dyn Focusable, Rect>;5] { [ &mut self.playing as &mut dyn Focusable, Rect>, &mut self.bpm as &mut dyn Focusable, Rect>, &mut self.quant as &mut dyn Focusable, Rect>, &mut self.sync as &mut dyn Focusable, Rect>, &mut self.clock as &mut dyn Focusable, Rect>, ] } } impl<'a> Focusable, Rect> for TransportToolbar { fn is_focused (&self) -> bool { self.focused } fn set_focused (&mut self, focused: bool) { self.focused = focused } } process!(TransportToolbar |self, _client, scope| { self.update(&scope); Control::Continue }); pub struct TransportPlayPauseButton { pub value: Option, pub focused: bool } impl<'a> Focusable, Rect> for TransportPlayPauseButton { fn is_focused (&self) -> bool { self.focused } fn set_focused (&mut self, focused: bool) { self.focused = focused } } pub struct TransportBPM { pub value: f64, pub focused: bool } impl<'a> Focusable, Rect> for TransportBPM { fn is_focused (&self) -> bool { self.focused } fn set_focused (&mut self, focused: bool) { self.focused = focused } } pub struct TransportQuantize { pub value: usize, pub focused: bool } impl<'a> Focusable, Rect> for TransportQuantize { fn is_focused (&self) -> bool { self.focused } fn set_focused (&mut self, focused: bool) { self.focused = focused } } pub struct TransportSync { pub value: usize, pub focused: bool } impl<'a> Focusable, Rect> for TransportSync { fn is_focused (&self) -> bool { self.focused } fn set_focused (&mut self, focused: bool) { self.focused = focused } } pub struct TransportClock { pub frame: usize, pub pulse: usize, pub ppq: usize, pub usecs: usize, pub focused: bool, } impl<'a> Focusable, Rect> for TransportClock { fn is_focused (&self) -> bool { self.focused } fn set_focused (&mut self, focused: bool) { self.focused = focused } }