mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
wip: refactor pt.41 (52e)
This commit is contained in:
parent
8856353eab
commit
79895fe3f6
4 changed files with 133 additions and 80 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue