mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 12:46:42 +01:00
reorder transport
This commit is contained in:
parent
340919830a
commit
84d650adf2
8 changed files with 147 additions and 107 deletions
|
|
@ -48,4 +48,5 @@ pub struct ArrangerTui {
|
||||||
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||||
pub editor: PhraseEditorModel,
|
pub editor: PhraseEditorModel,
|
||||||
pub focus: FocusState<AppFocus<ArrangerFocus>>,
|
pub focus: FocusState<AppFocus<ArrangerFocus>>,
|
||||||
|
pub perf: PerfModel,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ impl<'a, T: TransportViewState> Content for TransportView<'a, T> {
|
||||||
fn content (&self) -> impl Widget<Engine = Tui> {
|
fn content (&self) -> impl Widget<Engine = Tui> {
|
||||||
let state = self.0;
|
let state = self.0;
|
||||||
let selected = state.transport_selected();
|
let selected = state.transport_selected();
|
||||||
lay!(
|
row!(
|
||||||
selected.wrap(TransportFocus::PlayPause, &Styled(
|
selected.wrap(TransportFocus::PlayPause, &Styled(
|
||||||
None,
|
None,
|
||||||
match *state.transport_state().read().unwrap() {
|
match *state.transport_state().read().unwrap() {
|
||||||
|
|
@ -14,9 +14,7 @@ impl<'a, T: TransportViewState> Content for TransportView<'a, T> {
|
||||||
Some(TransportState::Stopped) => "⏹ STOPPED",
|
Some(TransportState::Stopped) => "⏹ STOPPED",
|
||||||
_ => "???",
|
_ => "???",
|
||||||
}
|
}
|
||||||
).min_xy(11, 2).push_x(1)).align_x().fill_x(),
|
).min_xy(11, 2).push_x(1)),
|
||||||
|
|
||||||
row!(
|
|
||||||
selected.wrap(TransportFocus::Bpm, &Outset::X(1u16, {
|
selected.wrap(TransportFocus::Bpm, &Outset::X(1u16, {
|
||||||
let bpm = state.transport_bpm_value();
|
let bpm = state.transport_bpm_value();
|
||||||
row! { "BPM ", format!("{}.{:03}", bpm as usize, (bpm * 1000.0) % 1000.0) }
|
row! { "BPM ", format!("{}.{:03}", bpm as usize, (bpm * 1000.0) % 1000.0) }
|
||||||
|
|
@ -26,15 +24,12 @@ impl<'a, T: TransportViewState> Content for TransportView<'a, T> {
|
||||||
//})),
|
//})),
|
||||||
selected.wrap(TransportFocus::Sync, &Outset::X(1u16, row! {
|
selected.wrap(TransportFocus::Sync, &Outset::X(1u16, row! {
|
||||||
"SYNC ", pulses_to_name(state.transport_sync_value() as usize)
|
"SYNC ", pulses_to_name(state.transport_sync_value() as usize)
|
||||||
}))
|
})),
|
||||||
).align_w().fill_x(),
|
|
||||||
|
|
||||||
selected.wrap(TransportFocus::Clock, &{
|
selected.wrap(TransportFocus::Clock, &{
|
||||||
let time1 = state.transport_format_beat();
|
let time1 = state.transport_format_beat();
|
||||||
let time2 = state.transport_format_msu();
|
let time2 = state.transport_format_msu();
|
||||||
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
|
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
|
||||||
}).align_e().fill_x(),
|
}).align_e().fill_x(),
|
||||||
|
|
||||||
).fill_x().bg(Color::Rgb(40, 50, 30))
|
).fill_x().bg(Color::Rgb(40, 50, 30))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,13 @@ macro_rules! impl_focus {
|
||||||
|
|
||||||
impl_focus!(TransportTui TransportFocus [
|
impl_focus!(TransportTui TransportFocus [
|
||||||
//&[Menu],
|
//&[Menu],
|
||||||
&[Content(Bpm), Content(Sync), Content(PlayPause), Content(Clock), Content(Quant)],
|
&[
|
||||||
|
Content(PlayPause),
|
||||||
|
Content(Bpm),
|
||||||
|
Content(Sync),
|
||||||
|
Content(Clock),
|
||||||
|
Content(Quant)
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl_focus!(SequencerTui SequencerFocus [
|
impl_focus!(SequencerTui SequencerFocus [
|
||||||
|
|
@ -126,9 +132,9 @@ impl_focus!(SequencerTui SequencerFocus [
|
||||||
//Menu,
|
//Menu,
|
||||||
//],
|
//],
|
||||||
&[
|
&[
|
||||||
|
Content(Transport(TransportFocus::PlayPause)),
|
||||||
Content(Transport(TransportFocus::Bpm)),
|
Content(Transport(TransportFocus::Bpm)),
|
||||||
Content(Transport(TransportFocus::Sync)),
|
Content(Transport(TransportFocus::Sync)),
|
||||||
Content(Transport(TransportFocus::PlayPause)),
|
|
||||||
Content(Transport(TransportFocus::Clock)),
|
Content(Transport(TransportFocus::Clock)),
|
||||||
Content(Transport(TransportFocus::Quant))
|
Content(Transport(TransportFocus::Quant))
|
||||||
],
|
],
|
||||||
|
|
@ -150,9 +156,9 @@ impl_focus!(ArrangerTui ArrangerFocus [
|
||||||
//Menu,
|
//Menu,
|
||||||
//],
|
//],
|
||||||
&[
|
&[
|
||||||
|
Content(Transport(TransportFocus::PlayPause)),
|
||||||
Content(Transport(TransportFocus::Bpm)),
|
Content(Transport(TransportFocus::Bpm)),
|
||||||
Content(Transport(TransportFocus::Sync)),
|
Content(Transport(TransportFocus::Sync)),
|
||||||
Content(Transport(TransportFocus::PlayPause)),
|
|
||||||
Content(Transport(TransportFocus::Clock)),
|
Content(Transport(TransportFocus::Clock)),
|
||||||
Content(Transport(TransportFocus::Quant))
|
Content(Transport(TransportFocus::Quant))
|
||||||
], &[
|
], &[
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ macro_rules! impl_jack_api {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_clock_api {
|
macro_rules! impl_clock_api {
|
||||||
($Struct:ident $(:: $field:ident)*) => {
|
($Struct:ident $(:: $field:ident)*) => {
|
||||||
impl ClockApi for $Struct {
|
impl ClockApi for $Struct {
|
||||||
|
|
@ -34,7 +33,6 @@ macro_rules! impl_clock_api {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_has_phrases {
|
macro_rules! impl_has_phrases {
|
||||||
($Struct:ident $(:: $field:ident)*) => {
|
($Struct:ident $(:: $field:ident)*) => {
|
||||||
impl HasPhrases for $Struct {
|
impl HasPhrases for $Struct {
|
||||||
|
|
@ -47,7 +45,6 @@ macro_rules! impl_has_phrases {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_midi_player {
|
macro_rules! impl_midi_player {
|
||||||
($Struct:ident $(:: $field:ident)*) => {
|
($Struct:ident $(:: $field:ident)*) => {
|
||||||
impl HasPhrase for $Struct {
|
impl HasPhrase for $Struct {
|
||||||
|
|
@ -116,7 +113,6 @@ macro_rules! impl_midi_player {
|
||||||
impl MidiPlayerApi for $Struct {}
|
impl MidiPlayerApi for $Struct {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_phrases_control {
|
macro_rules! impl_phrases_control {
|
||||||
($Struct:ident $(:: $field:ident)*) => {
|
($Struct:ident $(:: $field:ident)*) => {
|
||||||
impl PhrasesControl for $Struct {
|
impl PhrasesControl for $Struct {
|
||||||
|
|
@ -135,7 +131,6 @@ macro_rules! impl_phrases_control {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_phrase_editor_control {
|
macro_rules! impl_phrase_editor_control {
|
||||||
(
|
(
|
||||||
$Struct:ident $(:: $field:ident)*
|
$Struct:ident $(:: $field:ident)*
|
||||||
|
|
@ -179,6 +174,68 @@ macro_rules! impl_phrase_editor_control {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
macro_rules! impl_phrases_view_state {
|
||||||
|
($Struct:ident $(:: $field:ident)* [$self1:ident: $focus:expr] [$self2:ident: $enter:expr]) => {
|
||||||
|
impl PhrasesViewState for $Struct {
|
||||||
|
fn phrases_focused (&$self1) -> bool {
|
||||||
|
$focus
|
||||||
|
}
|
||||||
|
fn phrases_entered (&$self2) -> bool {
|
||||||
|
$enter
|
||||||
|
}
|
||||||
|
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
|
||||||
|
&self$(.$field)*.phrases
|
||||||
|
}
|
||||||
|
fn phrase_index (&self) -> usize {
|
||||||
|
self$(.$field)*.phrase.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
||||||
|
&self$(.$field)*.mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
macro_rules! impl_phrase_view_state {
|
||||||
|
($Struct:ident $(:: $field:ident)* [$self1:ident : $focused:expr] [$self2:ident : $entered:expr]) => {
|
||||||
|
impl PhraseViewState for $Struct {
|
||||||
|
fn phrase_editing (&self) -> &Option<Arc<RwLock<Phrase>>> {
|
||||||
|
&self$(.$field)*.phrase
|
||||||
|
}
|
||||||
|
fn phrase_editor_focused (&$self1) -> bool {
|
||||||
|
$focused
|
||||||
|
//self$(.$field)*.focus.is_focused()
|
||||||
|
}
|
||||||
|
fn phrase_editor_entered (&$self2) -> bool {
|
||||||
|
$entered
|
||||||
|
//self$(.$field)*.focus.is_entered()
|
||||||
|
}
|
||||||
|
fn phrase_editor_size (&self) -> &Measure<Tui> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn keys (&self) -> &Buffer {
|
||||||
|
&self$(.$field)*.keys
|
||||||
|
}
|
||||||
|
fn buffer (&self) -> &BigBuffer {
|
||||||
|
&self$(.$field)*.buffer
|
||||||
|
}
|
||||||
|
fn note_len (&self) -> usize {
|
||||||
|
self$(.$field)*.note_len
|
||||||
|
}
|
||||||
|
fn note_axis (&self) -> &RwLock<FixedAxis<usize>> {
|
||||||
|
&self$(.$field)*.note_axis
|
||||||
|
}
|
||||||
|
fn time_axis (&self) -> &RwLock<ScaledAxis<usize>> {
|
||||||
|
&self$(.$field)*.time_axis
|
||||||
|
}
|
||||||
|
fn now (&self) -> &Arc<Pulse> {
|
||||||
|
&self$(.$field)*.now
|
||||||
|
}
|
||||||
|
fn size (&self) -> &Measure<Tui> {
|
||||||
|
&self$(.$field)*.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_jack_api!(TransportTui::jack);
|
impl_jack_api!(TransportTui::jack);
|
||||||
impl_jack_api!(SequencerTui::jack);
|
impl_jack_api!(SequencerTui::jack);
|
||||||
|
|
@ -211,3 +268,28 @@ impl_phrase_editor_control!(ArrangerTui
|
||||||
[self: todo!()]
|
[self: todo!()]
|
||||||
[self, phrase: todo!()]
|
[self, phrase: todo!()]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
impl_phrases_view_state!(PhrasesModel
|
||||||
|
[self: false]
|
||||||
|
[self: false]
|
||||||
|
);
|
||||||
|
impl_phrases_view_state!(SequencerTui::phrases
|
||||||
|
[self: self.focused() == AppFocus::Content(SequencerFocus::Phrases)]
|
||||||
|
[self: self.focused() == AppFocus::Content(SequencerFocus::Phrases)]
|
||||||
|
);
|
||||||
|
impl_phrases_view_state!(ArrangerTui::phrases
|
||||||
|
[self: self.focused() == AppFocus::Content(ArrangerFocus::Phrases)]
|
||||||
|
[self: self.focused() == AppFocus::Content(ArrangerFocus::Phrases)]
|
||||||
|
);
|
||||||
|
impl_phrase_view_state!(PhraseEditorModel
|
||||||
|
[self: true]
|
||||||
|
[self: true]
|
||||||
|
);
|
||||||
|
impl_phrase_view_state!(SequencerTui::editor
|
||||||
|
[self: self.focused() == AppFocus::Content(SequencerFocus::PhraseEditor)]
|
||||||
|
[self: self.entered() && self.focused() == AppFocus::Content(SequencerFocus::PhraseEditor)]
|
||||||
|
);
|
||||||
|
impl_phrase_view_state!(ArrangerTui::editor
|
||||||
|
[self: self.focused() == AppFocus::Content(ArrangerFocus::PhraseEditor)]
|
||||||
|
[self: self.entered() && self.focused() == AppFocus::Content(ArrangerFocus::PhraseEditor)])
|
||||||
|
;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,8 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for ArrangerTui {
|
||||||
status_bar: None,
|
status_bar: None,
|
||||||
midi_buf: vec![vec![];65536],
|
midi_buf: vec![vec![];65536],
|
||||||
note_buf: vec![],
|
note_buf: vec![],
|
||||||
focus: FocusState::Entered(AppFocus::Content(ArrangerFocus::Transport(TransportFocus::Bpm)))
|
focus: FocusState::Entered(AppFocus::Content(ArrangerFocus::Transport(TransportFocus::Bpm))),
|
||||||
|
perf: PerfModel::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,15 @@ impl Audio for TransportTui {
|
||||||
|
|
||||||
impl Audio for SequencerTui {
|
impl Audio for SequencerTui {
|
||||||
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
|
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
|
||||||
|
// Start profiling cycle
|
||||||
let t0 = self.perf.get_t0();
|
let t0 = self.perf.get_t0();
|
||||||
|
|
||||||
|
// Update transport clock
|
||||||
if ClockAudio(self).process(client, scope) == Control::Quit {
|
if ClockAudio(self).process(client, scope) == Control::Quit {
|
||||||
return Control::Quit
|
return Control::Quit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update MIDI sequencer
|
||||||
if PlayerAudio(
|
if PlayerAudio(
|
||||||
&mut self.player,
|
&mut self.player,
|
||||||
&mut self.note_buf,
|
&mut self.note_buf,
|
||||||
|
|
@ -19,13 +24,37 @@ impl Audio for SequencerTui {
|
||||||
).process(client, scope) == Control::Quit {
|
).process(client, scope) == Control::Quit {
|
||||||
return Control::Quit
|
return Control::Quit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update sequencer playhead indicator
|
||||||
|
//self.now().set(0.);
|
||||||
|
//if let Some((ref started_at, Some(ref playing))) = self.player.play_phrase {
|
||||||
|
//let phrase = phrase.read().unwrap();
|
||||||
|
//if *playing.read().unwrap() == *phrase {
|
||||||
|
//let pulse = self.current().pulse.get();
|
||||||
|
//let start = started_at.pulse.get();
|
||||||
|
//let now = (pulse - start) % phrase.length as f64;
|
||||||
|
//self.now().set(now);
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
// End profiling cycle
|
||||||
self.perf.update(t0, scope);
|
self.perf.update(t0, scope);
|
||||||
|
|
||||||
Control::Continue
|
Control::Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Audio for ArrangerTui {
|
impl Audio for ArrangerTui {
|
||||||
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
|
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
|
||||||
|
// Start profiling cycle
|
||||||
|
let t0 = self.perf.get_t0();
|
||||||
|
|
||||||
|
// Update transport clock
|
||||||
|
if ClockAudio(self).process(client, scope) == Control::Quit {
|
||||||
|
return Control::Quit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update MIDI sequencers
|
||||||
if TracksAudio(
|
if TracksAudio(
|
||||||
&mut self.tracks,
|
&mut self.tracks,
|
||||||
&mut self.note_buf,
|
&mut self.note_buf,
|
||||||
|
|
@ -34,7 +63,9 @@ impl Audio for ArrangerTui {
|
||||||
).process(client, scope) == Control::Quit {
|
).process(client, scope) == Control::Quit {
|
||||||
return Control::Quit
|
return Control::Quit
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: one of these per playing track
|
// FIXME: one of these per playing track
|
||||||
|
self.now().set(0.);
|
||||||
if let ArrangerSelection::Clip(t, s) = self.selected {
|
if let ArrangerSelection::Clip(t, s) = self.selected {
|
||||||
let phrase = self.scenes().get(s).map(|scene|scene.clips.get(t));
|
let phrase = self.scenes().get(s).map(|scene|scene.clips.get(t));
|
||||||
if let Some(Some(Some(phrase))) = phrase {
|
if let Some(Some(Some(phrase))) = phrase {
|
||||||
|
|
@ -46,13 +77,15 @@ impl Audio for ArrangerTui {
|
||||||
let start = started_at.pulse.get();
|
let start = started_at.pulse.get();
|
||||||
let now = (pulse - start) % phrase.length as f64;
|
let now = (pulse - start) % phrase.length as f64;
|
||||||
self.now().set(now);
|
self.now().set(now);
|
||||||
return Control::Continue
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.now().set(0.);
|
// End profiling cycle
|
||||||
|
self.perf.update(t0, scope);
|
||||||
|
|
||||||
return Control::Continue
|
return Control::Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,34 +68,6 @@ pub trait PhrasesViewState: Send + Sync {
|
||||||
fn phrase_index (&self) -> usize;
|
fn phrase_index (&self) -> usize;
|
||||||
fn phrases_mode (&self) -> &Option<PhrasesMode>;
|
fn phrases_mode (&self) -> &Option<PhrasesMode>;
|
||||||
}
|
}
|
||||||
macro_rules! impl_phrases_view_state {
|
|
||||||
($Struct:ident $(:: $field:ident)* [$self1:ident: $focus:expr] [$self2:ident: $enter:expr]) => {
|
|
||||||
impl PhrasesViewState for $Struct {
|
|
||||||
fn phrases_focused (&$self1) -> bool {
|
|
||||||
$focus
|
|
||||||
}
|
|
||||||
fn phrases_entered (&$self2) -> bool {
|
|
||||||
$enter
|
|
||||||
}
|
|
||||||
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
|
|
||||||
&self$(.$field)*.phrases
|
|
||||||
}
|
|
||||||
fn phrase_index (&self) -> usize {
|
|
||||||
self$(.$field)*.phrase.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
|
||||||
&self$(.$field)*.mode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl_phrases_view_state!(PhrasesModel [self: false] [self: false]);
|
|
||||||
impl_phrases_view_state!(SequencerTui::phrases
|
|
||||||
[self: self.focused() == AppFocus::Content(SequencerFocus::Phrases)]
|
|
||||||
[self: self.focused() == AppFocus::Content(SequencerFocus::Phrases)]);
|
|
||||||
impl_phrases_view_state!(ArrangerTui::phrases
|
|
||||||
[self: self.focused() == AppFocus::Content(ArrangerFocus::Phrases)]
|
|
||||||
[self: self.focused() == AppFocus::Content(ArrangerFocus::Phrases)]);
|
|
||||||
|
|
||||||
pub trait PhraseViewState: Send + Sync {
|
pub trait PhraseViewState: Send + Sync {
|
||||||
fn phrase_editing (&self) -> &Option<Arc<RwLock<Phrase>>>;
|
fn phrase_editing (&self) -> &Option<Arc<RwLock<Phrase>>>;
|
||||||
|
|
@ -110,56 +82,6 @@ pub trait PhraseViewState: Send + Sync {
|
||||||
fn now (&self) -> &Arc<Pulse>;
|
fn now (&self) -> &Arc<Pulse>;
|
||||||
fn size (&self) -> &Measure<Tui>;
|
fn size (&self) -> &Measure<Tui>;
|
||||||
}
|
}
|
||||||
macro_rules! impl_phrase_view_state {
|
|
||||||
($Struct:ident $(:: $field:ident)* [$self1:ident : $focused:expr] [$self2:ident : $entered:expr]) => {
|
|
||||||
impl PhraseViewState for $Struct {
|
|
||||||
fn phrase_editing (&self) -> &Option<Arc<RwLock<Phrase>>> {
|
|
||||||
&self$(.$field)*.phrase
|
|
||||||
}
|
|
||||||
fn phrase_editor_focused (&$self1) -> bool {
|
|
||||||
$focused
|
|
||||||
//self$(.$field)*.focus.is_focused()
|
|
||||||
}
|
|
||||||
fn phrase_editor_entered (&$self2) -> bool {
|
|
||||||
$entered
|
|
||||||
//self$(.$field)*.focus.is_entered()
|
|
||||||
}
|
|
||||||
fn phrase_editor_size (&self) -> &Measure<Tui> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
fn keys (&self) -> &Buffer {
|
|
||||||
&self$(.$field)*.keys
|
|
||||||
}
|
|
||||||
fn buffer (&self) -> &BigBuffer {
|
|
||||||
&self$(.$field)*.buffer
|
|
||||||
}
|
|
||||||
fn note_len (&self) -> usize {
|
|
||||||
self$(.$field)*.note_len
|
|
||||||
}
|
|
||||||
fn note_axis (&self) -> &RwLock<FixedAxis<usize>> {
|
|
||||||
&self$(.$field)*.note_axis
|
|
||||||
}
|
|
||||||
fn time_axis (&self) -> &RwLock<ScaledAxis<usize>> {
|
|
||||||
&self$(.$field)*.time_axis
|
|
||||||
}
|
|
||||||
fn now (&self) -> &Arc<Pulse> {
|
|
||||||
&self$(.$field)*.now
|
|
||||||
}
|
|
||||||
fn size (&self) -> &Measure<Tui> {
|
|
||||||
&self$(.$field)*.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl_phrase_view_state!(PhraseEditorModel
|
|
||||||
[self: true]
|
|
||||||
[self: true]);
|
|
||||||
impl_phrase_view_state!(SequencerTui::editor
|
|
||||||
[self: self.focused() == AppFocus::Content(SequencerFocus::PhraseEditor)]
|
|
||||||
[self: self.entered() && self.focused() == AppFocus::Content(SequencerFocus::PhraseEditor)]);
|
|
||||||
impl_phrase_view_state!(ArrangerTui::editor
|
|
||||||
[self: self.focused() == AppFocus::Content(ArrangerFocus::PhraseEditor)]
|
|
||||||
[self: self.entered() && self.focused() == AppFocus::Content(ArrangerFocus::PhraseEditor)]);
|
|
||||||
|
|
||||||
fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> {
|
fn track_widths (tracks: &[ArrangerTrack]) -> Vec<(usize, usize)> {
|
||||||
let mut widths = vec![];
|
let mut widths = vec![];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue