wip: refactor pt.41 (52e)

This commit is contained in:
🪞👃🪞 2024-11-15 20:58:16 +01:00
parent 8856353eab
commit 79895fe3f6
4 changed files with 133 additions and 80 deletions

View file

@ -34,7 +34,7 @@ pub enum ArrangerSceneCommand {
//}
pub trait ArrangerSceneApi: Sized {
fn name (&self) -> Arc<RwLock<String>>;
fn name (&self) -> &Arc<RwLock<String>>;
fn clips (&self) -> &Vec<Option<Arc<RwLock<Phrase>>>>;
fn color (&self) -> ItemColor;

View file

@ -33,7 +33,7 @@ pub enum ArrangerTrackCommand {
pub trait ArrangerTrackApi: PlayerApi + Send + Sync + Sized {
/// Name of track
fn name (&self) -> Arc<RwLock<String>>;
fn name (&self) -> &Arc<RwLock<String>>;
/// Preferred width of track column
fn width (&self) -> usize;
/// Preferred width of track column

View file

@ -12,6 +12,14 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for ArrangerApp<Tui> {
transport: jack.read().unwrap().transport(),
clock: Arc::new(Clock::from(Instant::default())),
jack: jack.clone(),
sequencer: SequencerView::from(&model.sequencer),
split: 20,
selected: ArrangerSelection::Clip(0, 0),
mode: ArrangerMode::Vertical(2),
color: Color::Rgb(28, 35, 25).into(),
size: Measure::new(),
focused: false,
entered: false,
}.into(), None, None))
}
}
@ -40,6 +48,7 @@ pub type ArrangerAppCommand = AppViewCommand<ArrangerViewCommand>;
#[derive(Clone, Debug)]
pub enum ArrangerViewCommand {
Clear,
Scene(ArrangerSceneCommand),
Track(ArrangerTrackCommand),
Clip(ArrangerClipCommand),
@ -69,7 +78,7 @@ impl InputToCommand<Tui, ArrangerApp<Tui>> for ArrangerAppCommand {
key!(KeyCode::Enter) => Self::Focus(Enter),
key!(KeyCode::Esc) => Self::Focus(Exit),
key!(KeyCode::Char(' ')) => {
Self::App(Transport(TransportCommand::Play(None)))
Self::App(Playhead(PlayheadCommand::Play(None)))
},
_ => Self::App(match view.focused() {
Content(ArrangerViewFocus::Transport) => Transport(
@ -87,8 +96,7 @@ impl InputToCommand<Tui, ArrangerApp<Tui>> for ArrangerAppCommand {
)
},
Content(ArrangerViewFocus::Arranger) => {
use ArrangerSelection as Focus;
use ArrangerCommand as Model;
use ArrangerSelection as Select;
use ArrangerTrackCommand as Track;
use ArrangerClipCommand as Clip;
use ArrangerSceneCommand as Scene;
@ -100,31 +108,31 @@ impl InputToCommand<Tui, ArrangerApp<Tui>> for ArrangerAppCommand {
// FIXME: boundary conditions
key!(KeyCode::Up) => match view.selected {
ArrangerSelection::Mix => return None,
ArrangerSelection::Track(t) => return None,
ArrangerSelection::Scene(s) => Select(Focus::Scene(s - 1)),
ArrangerSelection::Clip(t, s) => Select(Focus::Clip(t, s - 1)),
Select::Mix => return None,
Select::Track(t) => return None,
Select::Scene(s) => Select(Select::Scene(s - 1)),
Select::Clip(t, s) => Select(Select::Clip(t, s - 1)),
},
key!(KeyCode::Down) => match view.selected {
ArrangerSelection::Mix => Select(Focus::Scene(0)),
ArrangerSelection::Track(t) => Select(Focus::Clip(t, 0)),
ArrangerSelection::Scene(s) => Select(Focus::Scene(s + 1)),
ArrangerSelection::Clip(t, s) => Select(Focus::Clip(t, s + 1)),
Select::Mix => Select(Select::Scene(0)),
Select::Track(t) => Select(Select::Clip(t, 0)),
Select::Scene(s) => Select(Select::Scene(s + 1)),
Select::Clip(t, s) => Select(Select::Clip(t, s + 1)),
},
key!(KeyCode::Left) => match view.selected {
ArrangerSelection::Mix => return None,
ArrangerSelection::Track(t) => Select(Focus::Track(t - 1)),
ArrangerSelection::Scene(s) => return None,
ArrangerSelection::Clip(t, s) => Select(Focus::Clip(t - 1, s)),
Select::Mix => return None,
Select::Track(t) => Select(Select::Track(t - 1)),
Select::Scene(s) => return None,
Select::Clip(t, s) => Select(Select::Clip(t - 1, s)),
},
key!(KeyCode::Right) => match view.selected {
ArrangerSelection::Mix => return None,
ArrangerSelection::Track(t) => Select(Focus::Track(t + 1)),
ArrangerSelection::Scene(s) => Select(Focus::Clip(0, s)),
ArrangerSelection::Clip(t, s) => Select(Focus::Clip(t, s - 1)),
Select::Mix => return None,
Select::Track(t) => Select(Select::Track(t + 1)),
Select::Scene(s) => Select(Select::Clip(0, s)),
Select::Clip(t, s) => Select(Select::Clip(t, s - 1)),
},
key!(KeyCode::Char('+')) => Zoom(0),
@ -138,56 +146,56 @@ impl InputToCommand<Tui, ArrangerApp<Tui>> for ArrangerAppCommand {
key!(KeyCode::Char('`')) => { todo!("toggle view mode") },
key!(KeyCode::Char(',')) => match view.selected {
ArrangerSelection::Mix => Zoom(0),
ArrangerSelection::Track(t) => Track(Track::Swap(t, t - 1)),
ArrangerSelection::Scene(s) => Scene(Scene::Swap(s, s - 1)),
ArrangerSelection::Clip(t, s) => Clip(Clip::Set(t, s, None)),
Select::Mix => Zoom(0),
Select::Track(t) => Track(Track::Swap(t, t - 1)),
Select::Scene(s) => Scene(Scene::Swap(s, s - 1)),
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
},
key!(KeyCode::Char('.')) => match view.selected {
ArrangerSelection::Mix => Zoom(0),
ArrangerSelection::Track(t) => Track(Track::Swap(t, t + 1)),
ArrangerSelection::Scene(s) => Scene(Scene::Swap(s, s + 1)),
ArrangerSelection::Clip(t, s) => Clip(Clip::Set(t, s, None)),
Select::Mix => Zoom(0),
Select::Track(t) => Track(Track::Swap(t, t + 1)),
Select::Scene(s) => Scene(Scene::Swap(s, s + 1)),
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
},
key!(KeyCode::Char('<')) => match view.selected {
ArrangerSelection::Mix => Zoom(0),
ArrangerSelection::Track(t) => Track(Track::Swap(t, t - 1)),
ArrangerSelection::Scene(s) => Scene(Scene::Swap(s, s - 1)),
ArrangerSelection::Clip(t, s) => Clip(Clip::Set(t, s, None)),
Select::Mix => Zoom(0),
Select::Track(t) => Track(Track::Swap(t, t - 1)),
Select::Scene(s) => Scene(Scene::Swap(s, s - 1)),
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
},
key!(KeyCode::Char('>')) => match view.selected {
ArrangerSelection::Mix => Zoom(0),
ArrangerSelection::Track(t) => Track(Track::Swap(t, t + 1)),
ArrangerSelection::Scene(s) => Scene(Scene::Swap(s, s + 1)),
ArrangerSelection::Clip(t, s) => Clip(Clip::Set(t, s, None)),
Select::Mix => Zoom(0),
Select::Track(t) => Track(Track::Swap(t, t + 1)),
Select::Scene(s) => Scene(Scene::Swap(s, s + 1)),
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
},
key!(KeyCode::Enter) => match view.selected {
ArrangerSelection::Mix => return None,
ArrangerSelection::Track(t) => return None,
ArrangerSelection::Scene(s) => Scene(Scene::Play(s)),
ArrangerSelection::Clip(t, s) => return None,
Select::Mix => return None,
Select::Track(t) => return None,
Select::Scene(s) => Scene(Scene::Play(s)),
Select::Clip(t, s) => return None,
},
key!(KeyCode::Delete) => match view.selected {
ArrangerSelection::Mix => Edit(Model::Clear),
ArrangerSelection::Track(t) => Track(Track::Delete(t)),
ArrangerSelection::Scene(s) => Scene(Scene::Delete(s)),
ArrangerSelection::Clip(t, s) => Clip(Clip::Set(t, s, None)),
Select::Mix => Clear,
Select::Track(t) => Track(Track::Delete(t)),
Select::Scene(s) => Scene(Scene::Delete(s)),
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
},
key!(KeyCode::Char('c')) => Clip(Clip::RandomColor),
key!(KeyCode::Char('s')) => match view.selected {
ArrangerSelection::Clip(t, s) => Clip(Clip::Set(t, s, None)),
Select::Clip(t, s) => Clip(Clip::Set(t, s, None)),
_ => return None,
},
key!(KeyCode::Char('g')) => match view.selected {
ArrangerSelection::Clip(t, s) => Clip(Clip::Get(t, s)),
Select::Clip(t, s) => Clip(Clip::Get(t, s)),
_ => return None,
},
@ -275,9 +283,15 @@ impl HasJack for ArrangerView<Tui> {
}
}
impl HasClock for ArrangerView<Tui> {
fn clock (&self) -> &Arc<Clock> {
&self.transport.clock()
impl ClockApi for ArrangerView<Tui> {
fn current (&self) -> &Instant {
&self.current
}
fn quant (&self) -> &Quantize {
&self.quant
}
fn sync (&self) -> &LaunchSync {
&self.sync
}
}
@ -302,10 +316,10 @@ impl HasTracks<ArrangerTrack> for ArrangerView<Tui> {
{
let name = name.map_or_else(||self.track_default_name(), |x|x.to_string());
let track = ArrangerTrack {
width: name.len() + 2,
color: color.unwrap_or_else(||ItemColor::random()),
player: MIDIPlayer::new(&self.jack(), &self.clock(), name.as_str())?,
name: Arc::new(name.into()),
color: color.unwrap_or_else(||ItemColor::random()),
width: name.len() + 2,
//player: MIDIPlayer::new(&self.jack(), &self.clock(), name.as_str())?,
};
self.tracks_mut().push(track);
let index = self.tracks().len() - 1;
@ -389,24 +403,6 @@ pub enum ArrangerStatusBar {
PhraseEdit,
}
impl<E: Engine> From<ArrangerModel> for ArrangerView<E> {
fn from (model: ArrangerModel) -> Self {
let mut view = Self {
model,
sequencer: SequencerView::from(&model.sequencer),
split: 20,
selected: ArrangerSelection::Clip(0, 0),
mode: ArrangerMode::Vertical(2),
color: Color::Rgb(28, 35, 25).into(),
size: Measure::new(),
focused: false,
entered: false,
};
//view.update_focus();
view
}
}
/// Arranger display mode can be cycled
impl ArrangerMode {
/// Cycle arranger display mode
@ -1380,7 +1376,17 @@ pub struct ArrangerScene {
pub color: ItemColor,
}
impl ArrangerSceneApi for ArrangerTrack {}
impl ArrangerSceneApi for ArrangerTrack {
fn name (&self) -> &Arc<RwLock<String>> {
&self.name
}
fn clips (&self) -> &Vec<Option<Arc<RwLock<Phrase>>>> {
&self.clips
}
fn color (&self) -> ItemColor {
self.color
}
}
#[derive(Debug)]
pub struct ArrangerTrack {
@ -1416,4 +1422,36 @@ pub struct ArrangerTrack {
notes_out: Arc<RwLock<[bool; 128]>>,
}
impl ArrangerTrackApi for ArrangerTrack {}
impl ArrangerTrackApi for ArrangerTrack {
/// Name of track
fn name (&self) -> &Arc<RwLock<String>> {
&self.name
}
/// Preferred width of track column
fn width (&self) -> usize {
self.width
}
/// Preferred width of track column
fn width_mut (&mut self) -> &mut usize {
&mut self.width
}
/// Identifying color of track
fn color (&self) -> ItemColor {
self.color
}
}
impl HasMidiBuffer for ArrangerTrack {
}
impl HasPhrase for ArrangerTrack {
}
impl MidiInputApi for ArrangerTrack {
}
impl MidiOutputApi for ArrangerTrack {
}
impl PlayerApi for ArrangerTrack {
}

View file

@ -58,7 +58,7 @@ impl InputToCommand<Tui, TransportApp<Tui>> for TransportCommand {
use AppViewFocus::Content;
use ClockCommand::{SetBpm, SetQuant, SetSync};
use TransportViewFocus::{Bpm, Quant, Sync, PlayPause, Clock};
let clock = app.app.model.clock();
let clock = app.app.clock();
Some(match input.event() {
key!(Char('.')) => match app.focused() {
Content(Bpm) => SetBpm(clock.timebase().bpm.get() + 1.0),
@ -120,7 +120,7 @@ impl Command<TransportApp<Tui>> for TransportAppCommand {
impl Command<TransportApp<Tui>> for TransportCommand {
fn execute (self, state: &mut TransportApp<Tui>) -> Perhaps<Self> {
use ClockCommand::{SetBpm, SetQuant, SetSync};
let clock = state.app.model.clock();
let clock = state.app.clock();
Ok(Some(match self {
SetBpm(bpm) => SetBpm(clock.timebase().bpm.set(bpm)),
SetQuant(quant) => SetQuant(clock.quant.set(quant)),
@ -154,6 +154,21 @@ pub struct TransportView<E: Engine> {
size: Measure<E>,
}
impl<E: Engine> ClockApi for TransportView<E> {
fn current (&self) -> &Instant {
&self.current
}
fn quant (&self) -> &Quantize {
&self.quant
}
fn sync (&self) -> &LaunchSync {
&self.sync
}
}
impl<E: Engine> PlayheadApi for TransportView<E> {
}
/// Which item of the transport toolbar is focused
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TransportViewFocus {
@ -202,7 +217,7 @@ impl Content for TransportView<Tui> {
lay!(
self.focus.wrap(self.focused, TransportViewFocus::PlayPause, &Styled(
None,
match *self.model.clock().playing.read().unwrap() {
match *self.playing().read().unwrap() {
Some(TransportState::Rolling) => "▶ PLAYING",
Some(TransportState::Starting) => "READY ...",
Some(TransportState::Stopped) => "⏹ STOPPED",
@ -212,20 +227,20 @@ impl Content for TransportView<Tui> {
row!(
self.focus.wrap(self.focused, TransportViewFocus::Bpm, &Outset::X(1u16, {
let bpm = self.model.clock().timebase().bpm.get();
let bpm = self.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.model.clock().sync.get() as usize)
"SYNC ", pulses_to_name(self.sync().get() as usize)
}))
).align_w().fill_x(),
self.focus.wrap(self.focused, TransportViewFocus::Clock, &{
let time1 = self.model.clock().current.format_beat();
let time2 = self.model.clock().current.usec.format_msu();
let time1 = self.current().format_beat();
let time2 = self.current().usec.format_msu();
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
}).align_e().fill_x(),