wip: refactor pt.14: 138 errors

This commit is contained in:
🪞👃🪞 2024-11-10 23:22:26 +01:00
parent fbf217e108
commit 8b68a993bc
9 changed files with 95 additions and 100 deletions

View file

@ -99,9 +99,11 @@ impl ArrangementScene {
}).collect()
}
}
pub fn longest_name (scenes: &[Self]) -> usize {
scenes.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max)
}
/// Returns the pulse length of the longest phrase in the scene
pub fn pulses (&self) -> usize {
self.clips.iter().fold(0, |a, p|{

View file

@ -872,6 +872,7 @@ impl<E: Engine, A: Widget<Engine = E>, B: Widget<Engine = E>> Widget for Split<E
}
/// A widget that tracks its render width and height
#[derive(Debug)]
pub struct Measure<E: Engine>(PhantomData<E>, AtomicUsize, AtomicUsize);
impl<E: Engine> Measure<E> {

View file

@ -1,5 +1,19 @@
use crate::*;
pub struct SequencerAudio {
transport: Arc<RwLock<Transport>>,
player: Arc<RwLock<MIDIPlayer>>,
}
/// JACK process callback for sequencer app
impl Audio for SequencerAudio {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
self.transport.write().unwrap().process(client, scope);
self.player.write().unwrap().process(client, scope);
Control::Continue
}
}
pub struct MIDIPlayerAudio {
model: Arc<RwLock<MIDIPlayer>>
}

View file

@ -1,7 +1,7 @@
use crate::*;
pub struct ArrangementEditor<E: Engine> {
pub state: Arrangement,
pub model: Arrangement,
/// Currently selected element.
pub selected: ArrangementEditorFocus,
/// Display mode of arranger
@ -39,12 +39,6 @@ impl ArrangementEditorMode {
}
}
impl<E: Engine> Audio for ArrangementEditor<E> {
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
self.state.process(client, scope)
}
}
impl Content for ArrangementEditor<Tui> {
type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> {
@ -61,9 +55,9 @@ impl Content for ArrangementEditor<Tui> {
}
impl<E: Engine> ArrangementEditor<E> {
pub fn new (state: Arrangement) -> Self {
pub fn new (model: Arrangement) -> Self {
Self {
state,
model,
selected: ArrangementEditorFocus::Clip(0, 0),
mode: ArrangementEditorMode::Vertical(2),
color: Color::Rgb(28, 35, 25).into(),
@ -76,30 +70,30 @@ impl<E: Engine> ArrangementEditor<E> {
impl<E: Engine> ArrangementEditor<E> {
pub fn track (&self) -> Option<&ArrangementTrack> {
self.selected.track().map(|t|self.state.tracks.get(t)).flatten()
self.selected.track().map(|t|self.model.tracks.get(t)).flatten()
}
pub fn track_mut (&mut self) -> Option<&mut ArrangementTrack> {
self.selected.track().map(|t|self.state.tracks.get_mut(t)).flatten()
self.selected.track().map(|t|self.model.tracks.get_mut(t)).flatten()
}
pub fn scene (&self) -> Option<&ArrangementScene> {
self.selected.scene().map(|s|self.state.scenes.get(s)).flatten()
self.selected.scene().map(|s|self.model.scenes.get(s)).flatten()
}
pub fn scene_mut (&mut self) -> Option<&mut ArrangementScene> {
self.selected.scene().map(|s|self.state.scenes.get_mut(s)).flatten()
self.selected.scene().map(|s|self.model.scenes.get_mut(s)).flatten()
}
pub fn phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
self.scene()?.clips.get(self.selected.track()?)?.clone()
}
pub fn track_del (&mut self) {
if let Some(index) = self.selected.track() { self.state.track_del(index); }
if let Some(index) = self.selected.track() { self.model.track_del(index); }
}
pub fn scene_del (&mut self) {
if let Some(index) = self.selected.scene() { self.state.scene_del(index); }
if let Some(index) = self.selected.scene() { self.model.scene_del(index); }
}
pub fn track_widths (&self) -> Vec<(usize, usize)> {
let mut widths = vec![];
let mut total = 0;
for track in self.tracks.iter() {
for track in self.model.tracks.iter() {
let width = track.width;
widths.push((width, total));
total += width;
@ -111,20 +105,22 @@ impl<E: Engine> ArrangementEditor<E> {
let track_index = self.selected.track();
let scene_index = self.selected.scene();
track_index
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
.and_then(|index|self.model.tracks.get_mut(index).map(|track|(index, track)))
.map(|(track_index, _)|scene_index
.and_then(|index|self.scenes.get_mut(index))
.and_then(|index|self.model.scenes.get_mut(index))
.map(|scene|scene.clips[track_index] = None));
}
pub fn phrase_put (&mut self) {
if let ArrangementEditorFocus::Clip(track, scene) = self.selected {
self.scenes[scene].clips[track] = Some(self.phrases.read().unwrap().phrase().clone());
self.model.scenes[scene].clips[track] = Some(
self.model.phrases.read().unwrap().phrase().clone()
);
}
}
pub fn phrase_get (&mut self) {
if let ArrangementEditorFocus::Clip(track, scene) = self.selected {
if let Some(phrase) = &self.scenes[scene].clips[track] {
let mut phrases = self.phrases.write().unwrap();
if let Some(phrase) = &self.model.scenes[scene].clips[track] {
let mut phrases = self.model.phrases.write().unwrap();
if let Some(index) = phrases.index_of(&*phrase.read().unwrap()) {
phrases.phrase = index;
}
@ -133,8 +129,8 @@ impl<E: Engine> ArrangementEditor<E> {
}
pub fn phrase_next (&mut self) {
if let ArrangementEditorFocus::Clip(track, scene) = self.selected {
if let Some(ref mut phrase) = self.scenes[scene].clips[track] {
let phrases = self.phrases.read().unwrap();
if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] {
let phrases = self.model.phrases.read().unwrap();
let index = phrases.index_of(&*phrase.read().unwrap());
if let Some(index) = index {
if index < phrases.phrases.len().saturating_sub(1) {
@ -146,8 +142,8 @@ impl<E: Engine> ArrangementEditor<E> {
}
pub fn phrase_prev (&mut self) {
if let ArrangementEditorFocus::Clip(track, scene) = self.selected {
if let Some(ref mut phrase) = self.scenes[scene].clips[track] {
let phrases = self.phrases.read().unwrap();
if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] {
let phrases = self.model.phrases.read().unwrap();
let index = phrases.index_of(&*phrase.read().unwrap());
if let Some(index) = index {
if index > 0 {

View file

@ -2,7 +2,7 @@ use crate::*;
pub struct PhrasePoolView<E: Engine> {
_engine: PhantomData<E>,
pub state: PhrasePool,
pub model: PhrasePool,
/// Selected phrase
pub phrase: usize,
/// Scroll offset
@ -24,7 +24,7 @@ pub enum PhrasePoolMode {
}
impl<E: Engine> PhrasePoolView<E> {
pub fn new (state: PhrasePool) -> Self {
pub fn new (model: PhrasePool) -> Self {
Self {
_engine: Default::default(),
scroll: 0,
@ -32,14 +32,14 @@ impl<E: Engine> PhrasePoolView<E> {
mode: None,
focused: false,
entered: false,
state,
model,
}
}
pub fn len (&self) -> usize {
self.state.phrases.len()
self.model.phrases.len()
}
pub fn phrase (&self) -> &Arc<RwLock<Phrase>> {
&self.state.phrases[self.phrase]
&self.model.phrases[self.phrase]
}
pub fn index_before (&self, index: usize) -> usize {
index.overflowing_sub(1).0.min(self.len() - 1)
@ -48,8 +48,8 @@ impl<E: Engine> PhrasePoolView<E> {
(index + 1) % self.len()
}
pub fn index_of (&self, phrase: &Phrase) -> Option<usize> {
for i in 0..self.state.phrases.len() {
if *self.state.phrases[i].read().unwrap() == *phrase { return Some(i) }
for i in 0..self.model.phrases.len() {
if *self.model.phrases[i].read().unwrap() == *phrase { return Some(i) }
}
return None
}
@ -60,46 +60,46 @@ impl<E: Engine> PhrasePoolView<E> {
}
pub fn delete_selected (&mut self) {
if self.phrase > 0 {
self.state.phrases.remove(self.phrase);
self.phrase = self.phrase.min(self.state.phrases.len().saturating_sub(1));
self.model.phrases.remove(self.phrase);
self.phrase = self.phrase.min(self.model.phrases.len().saturating_sub(1));
}
}
pub fn append_new (&mut self, name: Option<&str>, color: Option<ItemColorTriplet>) {
self.state.phrases.push(Self::new_phrase(name, color));
self.phrase = self.state.phrases.len() - 1;
self.model.phrases.push(Self::new_phrase(name, color));
self.phrase = self.model.phrases.len() - 1;
}
pub fn insert_new (&mut self, name: Option<&str>, color: Option<ItemColorTriplet>) {
self.state.phrases.insert(self.phrase + 1, Self::new_phrase(name, color));
self.model.phrases.insert(self.phrase + 1, Self::new_phrase(name, color));
self.phrase += 1;
}
pub fn insert_dup (&mut self) {
let mut phrase = self.state.phrases[self.phrase].read().unwrap().duplicate();
let mut phrase = self.model.phrases[self.phrase].read().unwrap().duplicate();
phrase.color = ItemColorTriplet::random_near(phrase.color, 0.25);
self.state.phrases.insert(self.phrase + 1, Arc::new(RwLock::new(phrase)));
self.model.phrases.insert(self.phrase + 1, Arc::new(RwLock::new(phrase)));
self.phrase += 1;
}
pub fn begin_rename (&mut self) {
self.mode = Some(PhrasePoolMode::Rename(
self.phrase,
self.state.phrases[self.phrase].read().unwrap().name.clone()
self.model.phrases[self.phrase].read().unwrap().name.clone()
));
}
pub fn begin_length (&mut self) {
self.mode = Some(PhrasePoolMode::Length(
self.phrase,
self.state.phrases[self.phrase].read().unwrap().length,
self.model.phrases[self.phrase].read().unwrap().length,
PhraseLengthFocus::Bar
));
}
pub fn move_up (&mut self) {
if self.phrase > 1 {
self.state.phrases.swap(self.phrase - 1, self.phrase);
self.model.phrases.swap(self.phrase - 1, self.phrase);
self.phrase -= 1;
}
}
pub fn move_down (&mut self) {
if self.phrase < self.state.phrases.len().saturating_sub(1) {
self.state.phrases.swap(self.phrase + 1, self.phrase);
if self.phrase < self.model.phrases.len().saturating_sub(1) {
self.model.phrases.swap(self.phrase + 1, self.phrase);
self.phrase += 1;
}
}
@ -109,9 +109,9 @@ impl<E: Engine> PhrasePoolView<E> {
impl Content for PhrasePoolView<Tui> {
type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> {
let Self { focused, state, mode, .. } = self;
let Self { focused, model, mode, .. } = self;
let content = col!(
(i, phrase) in state.iter().enumerate() => Layers::new(|add|{
(i, phrase) in model.phrases.iter().enumerate() => Layers::new(|add|{
let Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
let mut length = PhraseLength::new(length, None);
if let Some(PhrasePoolMode::Length(phrase, new_length, focus)) = mode {
@ -136,7 +136,7 @@ impl Content for PhrasePoolView<Tui> {
let content = content.fill_xy().bg(Color::Rgb(28, 35, 25)).border(border);
let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)};
let upper_left = format!("[{}] Phrases", if self.entered {""} else {" "});
let upper_right = format!("({})", state.len());
let upper_right = format!("({})", model.phrases.len());
lay!(
content,
TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(),

View file

@ -15,15 +15,6 @@ pub struct SequencerView<E: Engine> {
pub player: MIDIPlayer,
}
/// JACK process callback for sequencer app
impl<E: Engine> Audio for SequencerView<E> {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
self.transport.process(client, scope);
self.player.process(client, scope);
Control::Continue
}
}
impl Content for SequencerView<Tui> {
type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> {

View file

@ -14,10 +14,10 @@ use crate::*;
impl<E: Engine> FocusGrid for SequencerView<E> {
type Item = SequencerFocus;
fn cursor (&self) -> (usize, usize) {
self.focus_cursor
self.cursor
}
fn cursor_mut (&mut self) -> &mut (usize, usize) {
&mut self.focus_cursor
&mut self.cursor
}
fn layout (&self) -> &[&[SequencerFocus]] { &[
&[SequencerFocus::Transport],
@ -34,10 +34,8 @@ impl<E: Engine> FocusGrid for SequencerView<E> {
}
fn update_focus (&mut self) {
let focused = self.focused();
if let Some(transport) = self.transport.as_ref() {
transport.write().unwrap().focused = focused == SequencerFocus::Transport
}
self.phrases.write().unwrap().focused = focused == SequencerFocus::PhrasePool;
self.editor.focused = focused == SequencerFocus::PhraseEditor;
self.transport.focused = focused == SequencerFocus::Transport;
self.phrases.focused = focused == SequencerFocus::PhrasePool;
self.editor.focused = focused == SequencerFocus::PhraseEditor;
}
}

View file

@ -1,31 +1,24 @@
use crate::*;
use tek_api::Transport;
/// Stores and displays time-related state.
/// Stores and displays time-related info.
#[derive(Debug)]
pub struct TransportView<E: Engine> {
_engine: PhantomData<E>,
pub state: Transport,
pub model: Transport,
pub focus: TransportViewFocus,
pub focused: bool,
pub size: Measure<E>,
}
/// JACK process callback for transport app
impl<E: Engine> Audio for TransportView<E> {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
self.state.process(client, scope);
Control::Continue
}
}
impl<E: Engine> TransportView<E> {
pub fn new (jack: &Arc<RwLock<JackClient>>, clock: Option<&Arc<Clock>>) -> Self {
Self {
_engine: Default::default(),
focused: false,
focus: TransportViewFocus::PlayPause,
state: Transport {
size: Measure::new(),
model: Transport {
metronome: false,
transport: jack.read().unwrap().transport(),
jack: jack.clone(),
@ -53,7 +46,7 @@ impl Content for TransportView<Tui> {
lay!(
self.focus.wrap(self.focused, TransportViewFocus::PlayPause, &Styled(
None,
match *self.clock.playing.read().unwrap() {
match *self.model.clock.playing.read().unwrap() {
Some(TransportState::Rolling) => "▶ PLAYING",
Some(TransportState::Starting) => "READY ...",
Some(TransportState::Stopped) => "⏹ STOPPED",
@ -63,20 +56,20 @@ impl Content for TransportView<Tui> {
row!(
self.focus.wrap(self.focused, TransportViewFocus::Bpm, &Outset::X(1u16, {
let bpm = self.clock.timebase().bpm.get();
let bpm = self.model.clock.timebase().bpm.get();
row! { "BPM ", format!("{}.{:03}", bpm as usize, (bpm * 1000.0) % 1000.0) }
})),
//let quant = self.focus.wrap(self.focused, TransportViewFocus::Quant, &Outset::X(1u16, row! {
//"QUANT ", ppq_to_name(self.quant as usize)
//})),
self.focus.wrap(self.focused, TransportViewFocus::Sync, &Outset::X(1u16, row! {
"SYNC ", pulses_to_name(self.clock.sync.get() as usize)
"SYNC ", pulses_to_name(self.model.clock.sync.get() as usize)
}))
).align_w().fill_x(),
self.focus.wrap(self.focused, TransportViewFocus::Clock, &{
let time1 = self.clock.current.format_beat();
let time2 = self.clock.current.usec.format_msu();
let time1 = self.model.clock.current.format_beat();
let time2 = self.model.clock.current.usec.format_msu();
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
}).align_e().fill_x(),

View file

@ -13,7 +13,7 @@ impl Handle<Tui> for TransportView<Tui> {
}
impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand {
fn input_to_command (state: &TransportView<Tui>, input: &TuiInput) -> Option<Self> {
fn input_to_command (view: &TransportView<Tui>, input: &TuiInput) -> Option<Self> {
use TransportViewFocus as Focus;
use FocusCommand as FocusCmd;
use TransportCommand as Cmd;
@ -22,31 +22,31 @@ impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand {
key!(KeyCode::Left) => Self::Focus(FocusCmd::Prev),
key!(KeyCode::Right) => Self::Focus(FocusCmd::Next),
key!(KeyCode::Char('.')) => Self::Transport(match state.focus {
Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() + 1.0),
Focus::Quant => Cmd::SetQuant(next_note_length(state.state.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(next_note_length(state.state.clock.sync.get()as usize)as f64+1.),
key!(KeyCode::Char('.')) => Self::Transport(match view.focus {
Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() + 1.0),
Focus::Quant => Cmd::SetQuant(next_note_length(view.model.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(next_note_length(view.model.clock.sync.get()as usize)as f64+1.),
Focus::PlayPause => {todo!()},
Focus::Clock => {todo!()}
}),
key!(KeyCode::Char(',')) => Self::Transport(match state.focus {
Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() - 1.0),
Focus::Quant => Cmd::SetQuant(prev_note_length(state.state.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(prev_note_length(state.state.clock.sync.get()as usize)as f64+1.),
key!(KeyCode::Char(',')) => Self::Transport(match view.focus {
Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() - 1.0),
Focus::Quant => Cmd::SetQuant(prev_note_length(view.model.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(prev_note_length(view.model.clock.sync.get()as usize)as f64+1.),
Focus::PlayPause => {todo!()},
Focus::Clock => {todo!()}
}),
key!(KeyCode::Char('>')) => Self::Transport(match state.focus {
Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() + 0.001),
Focus::Quant => Cmd::SetQuant(next_note_length(state.state.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(next_note_length(state.state.clock.sync.get()as usize)as f64+1.),
key!(KeyCode::Char('>')) => Self::Transport(match view.focus {
Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() + 0.001),
Focus::Quant => Cmd::SetQuant(next_note_length(view.model.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(next_note_length(view.model.clock.sync.get()as usize)as f64+1.),
Focus::PlayPause => {todo!()},
Focus::Clock => {todo!()}
}),
key!(KeyCode::Char('<')) => Self::Transport(match state.focus {
Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() - 0.001),
Focus::Quant => Cmd::SetQuant(prev_note_length(state.state.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(prev_note_length(state.state.clock.sync.get()as usize)as f64+1.),
key!(KeyCode::Char('<')) => Self::Transport(match view.focus {
Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() - 0.001),
Focus::Quant => Cmd::SetQuant(prev_note_length(view.model.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(prev_note_length(view.model.clock.sync.get()as usize)as f64+1.),
Focus::PlayPause => {todo!()},
Focus::Clock => {todo!()}
}),
@ -57,7 +57,7 @@ impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand {
}
impl<E: Engine> Command<TransportView<E>> for TransportViewCommand {
fn execute (self, state: &mut TransportView<E>) -> Perhaps<Self> {
fn execute (self, view: &mut TransportView<E>) -> Perhaps<Self> {
Ok(Some(match self {
Self::Focus(command) => Self::Focus({
use FocusCommand::*;
@ -70,9 +70,9 @@ impl<E: Engine> Command<TransportView<E>> for TransportViewCommand {
Self::Transport(command) => Self::Transport({
use TransportCommand::*;
match command {
SetBpm(bpm) => SetBpm(state.state.clock.timebase().bpm.set(bpm)),
SetQuant(quant) => SetQuant(state.state.clock.quant.set(quant)),
SetSync(sync) => SetSync(state.state.clock.sync.set(sync)),
SetBpm(bpm) => SetBpm(view.model.clock.timebase().bpm.set(bpm)),
SetQuant(quant) => SetQuant(view.model.clock.quant.set(quant)),
SetSync(sync) => SetSync(view.model.clock.sync.set(sync)),
_ => { todo!() }
}
}),