sequencer: despaghettify

This commit is contained in:
🪞👃🪞 2024-08-22 05:14:34 +03:00
parent 1dbe151ae6
commit 654aa0f041
7 changed files with 268 additions and 218 deletions

View file

@ -16,7 +16,6 @@ pub struct Arranger {
/// Display mode of arranger
pub mode: ArrangerViewMode,
pub focused: bool,
pub entered: bool,
pub focus_sequencer: bool,
@ -68,83 +67,6 @@ impl Arranger {
//self.sequencer.show(phrase)
Ok(())
}
pub fn phrase (&self) -> Option<&Arc<RwLock<Phrase>>> {
let track_id = self.selected.track()?;
self.tracks.get(track_id)?.phrases.get((*self.scene()?.clips.get(track_id)?)?)
}
pub fn phrase_next (&mut self) {
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(|(track_index, track)|{
let phrases = track.phrases.len();
scene_index
.and_then(|index|self.scenes.get_mut(index))
.and_then(|scene|{
if let Some(phrase_index) = scene.clips[track_index] {
if phrase_index >= phrases - 1 {
scene.clips[track_index] = None;
} else {
scene.clips[track_index] = Some(phrase_index + 1);
}
} else if phrases > 0 {
scene.clips[track_index] = Some(0);
}
Some(())
})
});
}
pub fn phrase_prev (&mut self) {
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(|(track_index, track)|{
let phrases = track.phrases.len();
scene_index
.and_then(|index|self.scenes.get_mut(index))
.and_then(|scene|{
if let Some(phrase_index) = scene.clips[track_index] {
scene.clips[track_index] = if phrase_index == 0 {
None
} else {
Some(phrase_index - 1)
};
} else if phrases > 0 {
scene.clips[track_index] = Some(phrases - 1);
}
Some(())
})
});
}
pub fn scene (&self) -> Option<&Scene> {
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
}
pub fn scene_mut (&mut self) -> Option<&mut Scene> {
self.selected.scene().map(|s|self.scenes.get_mut(s)).flatten()
}
pub fn scene_next (&mut self) {
self.selected.scene_next(self.scenes.len() - 1)
}
pub fn scene_prev (&mut self) {
self.selected.scene_prev()
}
pub fn scene_add (&mut self, name: Option<&str>) -> Usually<&mut Scene> {
let clips = vec![None;self.tracks.len()];
self.scenes.push(match name {
Some(name) => Scene::new(name, clips),
None => Scene::new(&self.scene_default_name(), clips),
});
let index = self.scenes.len() - 1;
Ok(&mut self.scenes[index])
}
pub fn scene_del (&mut self) {
unimplemented!("Arranger::scene_del");
}
pub fn scene_default_name (&self) -> String {
format!("Scene {}", self.scenes.len() + 1)
}
pub fn rename_selected (&mut self) {
self.modal = Some(Box::new(ArrangerRenameModal::new(
self.selected,

View file

@ -20,7 +20,7 @@ submod! {
sequencer
sequencer_cli
sequencer_handle
sequencer_render
sequencer_view
transport
transport_focus
transport_handle
@ -30,4 +30,6 @@ submod! {
pubmod! {
arranger_view_h
arranger_view_v
sequencer_view_h
sequencer_view_v
}

View file

@ -145,3 +145,56 @@ impl Phrase {
phrase
}}
}
impl Arranger {
pub fn phrase (&self) -> Option<&Arc<RwLock<Phrase>>> {
let track_id = self.selected.track()?;
self.tracks.get(track_id)?.phrases.get((*self.scene()?.clips.get(track_id)?)?)
}
pub fn phrase_next (&mut self) {
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(|(track_index, track)|{
let phrases = track.phrases.len();
scene_index
.and_then(|index|self.scenes.get_mut(index))
.and_then(|scene|{
if let Some(phrase_index) = scene.clips[track_index] {
if phrase_index >= phrases - 1 {
scene.clips[track_index] = None;
} else {
scene.clips[track_index] = Some(phrase_index + 1);
}
} else if phrases > 0 {
scene.clips[track_index] = Some(0);
}
Some(())
})
});
}
pub fn phrase_prev (&mut self) {
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(|(track_index, track)|{
let phrases = track.phrases.len();
scene_index
.and_then(|index|self.scenes.get_mut(index))
.and_then(|scene|{
if let Some(phrase_index) = scene.clips[track_index] {
scene.clips[track_index] = if phrase_index == 0 {
None
} else {
Some(phrase_index - 1)
};
} else if phrases > 0 {
scene.clips[track_index] = Some(phrases - 1);
}
Some(())
})
});
}
}

View file

@ -8,6 +8,29 @@ pub struct Scene {
}
impl Scene {
pub fn from_edn <'a, 'e> (args: &[Edn<'e>]) -> Usually<Self> {
let mut name = None;
let mut clips = vec![];
edn!(edn in args {
Edn::Map(map) => {
let key = map.get(&Edn::Key(":name"));
if let Some(Edn::Str(n)) = key {
name = Some(*n);
} else {
panic!("unexpected key in scene '{name:?}': {key:?}")
}
},
Edn::Symbol("_") => {
clips.push(None);
},
Edn::Int(i) => {
clips.push(Some(*i as usize));
},
_ => panic!("unexpected in scene '{name:?}': {edn:?}")
});
let scene = Self::new(name.unwrap_or(""), clips);
Ok(scene)
}
pub fn new (name: impl AsRef<str>, clips: impl AsRef<[Option<usize>]>) -> Self {
let name = name.as_ref().into();
let clips = clips.as_ref().iter().map(|x|x.clone()).collect();
@ -47,28 +70,32 @@ pub fn scene_ppqs (tracks: &[Sequencer], scenes: &[Scene]) -> Vec<(usize, usize)
scenes
}
impl Scene {
pub fn from_edn <'a, 'e> (args: &[Edn<'e>]) -> Usually<Self> {
let mut name = None;
let mut clips = vec![];
edn!(edn in args {
Edn::Map(map) => {
let key = map.get(&Edn::Key(":name"));
if let Some(Edn::Str(n)) = key {
name = Some(*n);
} else {
panic!("unexpected key in scene '{name:?}': {key:?}")
}
},
Edn::Symbol("_") => {
clips.push(None);
},
Edn::Int(i) => {
clips.push(Some(*i as usize));
},
_ => panic!("unexpected in scene '{name:?}': {edn:?}")
impl Arranger {
pub fn scene (&self) -> Option<&Scene> {
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
}
pub fn scene_mut (&mut self) -> Option<&mut Scene> {
self.selected.scene().map(|s|self.scenes.get_mut(s)).flatten()
}
pub fn scene_next (&mut self) {
self.selected.scene_next(self.scenes.len() - 1)
}
pub fn scene_prev (&mut self) {
self.selected.scene_prev()
}
pub fn scene_add (&mut self, name: Option<&str>) -> Usually<&mut Scene> {
let clips = vec![None;self.tracks.len()];
self.scenes.push(match name {
Some(name) => Scene::new(name, clips),
None => Scene::new(&self.scene_default_name(), clips),
});
let scene = Self::new(name.unwrap_or(""), clips);
Ok(scene)
let index = self.scenes.len() - 1;
Ok(&mut self.scenes[index])
}
pub fn scene_del (&mut self) {
unimplemented!("Arranger::scene_del");
}
pub fn scene_default_name (&self) -> String {
format!("Scene {}", self.scenes.len() + 1)
}
}

View file

@ -25,7 +25,7 @@ impl Sequencer {
Ok(())
}
fn style_focus (&self) -> Option<Style> {
pub(crate) fn style_focus (&self) -> Option<Style> {
Some(if self.focused {
Style::default().green().not_dim()
} else {
@ -33,7 +33,7 @@ impl Sequencer {
})
}
fn style_timer_step (now: usize, step: usize, next_step: usize) -> Style {
pub(crate) fn style_timer_step (now: usize, step: usize, next_step: usize) -> Style {
if step <= now && now < next_step {
Style::default().yellow().bold().not_dim()
} else {
@ -53,121 +53,6 @@ impl Sequencer {
default
}
}
const H_KEYS_OFFSET: usize = 5;
fn horizontal_draw (&self, buf: &mut Buffer, mut area: Rect) -> Usually<()> {
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, Rect {
x: area.x, y: area.y + 1, width: 15, height: 4
})?;
"Start 1.1.1".blit(buf, area.x + 1, area.y + 2, None)?;
"End 2.1.1".blit(buf, area.x + 1, area.y + 3, None)?;
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, Rect {
x: area.x, y: area.y + 5, width: 15, height: 5
})?;
"[ Loop off ] ".blit(buf, area.x + 1, area.y + 6, None)?;
"Loop 1.1.1".blit(buf, area.x + 1, area.y + 7, None)?;
"Length 1.0.0".blit(buf, area.x + 1, area.y + 8, None)?;
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, Rect {
x: area.x, y: area.y + 10, width: 15, height: 7
})?;
"Notes -------".blit(buf, area.x + 1, area.y + 11, None)?;
"[ /2 ] [ x2 ]".blit(buf, area.x + 1, area.y + 12, None)?;
"[ Reverse ]".blit(buf, area.x + 1, area.y + 13, None)?;
"[ Invert ]".blit(buf, area.x + 1, area.y + 14, None)?;
"[ Duplicate ]".blit(buf, area.x + 1, area.y + 15, None)?;
area.x = area.x + 15;
area.width = area.width.saturating_sub(12);
self.horizontal_keys(buf, area)?;
if let Some(ref phrase) = self.phrase {
self.horizontal_timer(buf, area, phrase)?;
}
self.horizontal_notes(buf, area)?;
self.horizontal_cursor(buf, area)?;
self.horizontal_quant(buf, area)?;
Ok(())
}
fn horizontal_notes (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
if area.height < 2 {
return Ok(area)
}
let area = Rect {
x: area.x + Self::H_KEYS_OFFSET as u16,
y: area.y + 1,
width: area.width - Self::H_KEYS_OFFSET as u16,
height: area.height - 2
};
buffer_update(buf, area, &move |cell, x, y|{
let src_x = ((x as usize + self.time_axis.start) * self.time_axis.scale) as usize;
let src_y = (y as usize + self.note_axis.start) as usize;
if src_x < self.buffer.width && src_y < self.buffer.height - 1 {
let src = self.buffer.get(src_x, self.buffer.height - src_y);
src.map(|src|{
cell.set_symbol(src.symbol());
cell.set_fg(src.fg);
});
}
});
Ok(area)
}
fn horizontal_keys (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
if area.height < 2 {
return Ok(area)
}
let area = Rect {
x: area.x,
y: area.y + 1,
width: 5,
height: area.height - 2
};
buffer_update(buf, area, &|cell, x, y|{
let y = y + self.note_axis.start as u16;
if x < self.keys.area.width && y < self.keys.area.height {
*cell = self.keys.get(x, y).clone()
}
});
Ok(area)
}
fn horizontal_quant (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let quant = ppq_to_name(self.time_axis.scale);
let quant_x = area.x + area.width - 1 - quant.len() as u16;
let quant_y = area.y + area.height - 2;
quant.blit(buf, quant_x, quant_y, self.style_focus())
}
fn horizontal_cursor (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
if let (Some(time), Some(note)) = (self.time_axis.point, self.note_axis.point) {
let x = area.x + Self::H_KEYS_OFFSET as u16 + time as u16;
let y = area.y + 1 + note as u16 / 2;
let c = if note % 2 == 0 { "" } else { "" };
c.blit(buf, x, y, self.style_focus())
} else {
Ok(Rect::default())
}
}
fn horizontal_timer (
&self, buf: &mut Buffer, area: Rect, phrase: &RwLock<Phrase>
) -> Usually<Rect> {
let phrase = phrase.read().unwrap();
let (time0, time_z, now) = (self.time_axis.start, self.time_axis.scale, self.now % phrase.length);
let Rect { x, width, .. } = area;
let x2 = x as usize + Self::H_KEYS_OFFSET;
let x3 = x as usize + width as usize;
for x in x2..x3 {
let step = (time0 + x2) * time_z;
let next_step = (time0 + x2 + 1) * time_z;
let style = Self::style_timer_step(now, step as usize, next_step as usize);
"-".blit(buf, x as u16, area.y, Some(style))?;
}
return Ok(Rect { x: area.x, y: area.y, width: area.width, height: 1 })
}
}
fn nth_octave (index: u16) -> &'static str {

View file

@ -0,0 +1,161 @@
use crate::*;
impl Sequencer {
const H_KEYS_OFFSET: usize = 5;
pub(crate) fn horizontal_draw (&self, buf: &mut Buffer, mut area: Rect) -> Usually<()> {
SequenceStartEnd.render(buf, area)?;
SequenceLoop.render(buf, area)?;
SequenceRange.render(buf, area)?;
area.x = area.x + 15;
area.width = area.width.saturating_sub(12);
SequenceKeys(&self).render(buf, area)?;
if let Some(ref phrase) = self.phrase {
SequenceTimer(&self, phrase).render(buf, area)?;
}
SequenceNotes(&self).render(buf, area)?;
SequenceCursor(&self).render(buf, area)?;
SequenceZoom(&self).render(buf, area)?;
Ok(())
}
}
struct SequenceStartEnd;
impl Render for SequenceStartEnd {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let frame = Rect { x: area.x, y: area.y, width: 15, height: 4 };
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, frame)?;
"Start 1.1.1".blit(buf, area.x + 1, area.y + 1, None)?;
"End 2.1.1".blit(buf, area.x + 1, area.y + 2, None)?;
Ok(frame)
}
}
struct SequenceLoop;
impl Render for SequenceLoop {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let range = Rect { x: area.x, y: area.y + 4, width: 15, height: 5 };
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, range)?;
"[ Loop off ] ".blit(buf, area.x + 1, area.y + 5, None)?;
"Loop 1.1.1".blit(buf, area.x + 1, area.y + 6, None)?;
"Length 1.0.0".blit(buf, area.x + 1, area.y + 7, None)?;
Ok(range)
}
}
struct SequenceRange;
impl Render for SequenceRange {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let range = Rect { x: area.x, y: area.y + 9, width: 15, height: 7 };
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, range)?;
"Notes -------".blit(buf, area.x + 1, area.y + 10, None)?;
"[ /2 ] [ x2 ]".blit(buf, area.x + 1, area.y + 11, None)?;
"[ Reverse ]".blit(buf, area.x + 1, area.y + 12, None)?;
"[ Invert ]".blit(buf, area.x + 1, area.y + 13, None)?;
"[ Duplicate ]".blit(buf, area.x + 1, area.y + 14, None)?;
Ok(area)
}
}
struct SequenceKeys<'a>(&'a Sequencer);
impl<'a> Render for SequenceKeys<'a> {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
if area.height < 2 {
return Ok(area)
}
let area = Rect {
x: area.x,
y: area.y + 1,
width: 5,
height: area.height - 2
};
buffer_update(buf, area, &|cell, x, y|{
let y = y + self.0.note_axis.start as u16;
if x < self.0.keys.area.width && y < self.0.keys.area.height {
*cell = self.0.keys.get(x, y).clone()
}
});
Ok(area)
}
}
struct SequenceNotes<'a>(&'a Sequencer);
impl<'a> Render for SequenceNotes<'a> {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
if area.height < 2 {
return Ok(area)
}
let area = Rect {
x: area.x + Sequencer::H_KEYS_OFFSET as u16,
y: area.y + 1,
width: area.width - Sequencer::H_KEYS_OFFSET as u16,
height: area.height - 2
};
buffer_update(buf, area, &move |cell, x, y|{
let src_x = ((x as usize + self.0.time_axis.start) * self.0.time_axis.scale) as usize;
let src_y = (y as usize + self.0.note_axis.start) as usize;
if src_x < self.0.buffer.width && src_y < self.0.buffer.height - 1 {
let src = self.0.buffer.get(src_x, self.0.buffer.height - src_y);
src.map(|src|{
cell.set_symbol(src.symbol());
cell.set_fg(src.fg);
});
}
});
Ok(area)
}
}
struct SequenceCursor<'a>(&'a Sequencer);
impl<'a> Render for SequenceCursor<'a> {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
if let (Some(time), Some(note)) = (self.0.time_axis.point, self.0.note_axis.point) {
let x = area.x + Sequencer::H_KEYS_OFFSET as u16 + time as u16;
let y = area.y + 1 + note as u16 / 2;
let c = if note % 2 == 0 { "" } else { "" };
c.blit(buf, x, y, self.0.style_focus())
} else {
Ok(Rect::default())
}
}
}
struct SequenceZoom<'a>(&'a Sequencer);
impl<'a> Render for SequenceZoom<'a> {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let quant = ppq_to_name(self.0.time_axis.scale);
let quant_x = area.x + area.width - 1 - quant.len() as u16;
let quant_y = area.y + area.height - 2;
quant.blit(buf, quant_x, quant_y, self.0.style_focus())
}
}
struct SequenceTimer<'a>(&'a Sequencer, &'a Arc<RwLock<Phrase>>);
impl<'a> Render for SequenceTimer<'a> {
fn render (&self, buf: &mut Buffer, area: Rect) -> Usually<Rect> {
let phrase = self.1.read().unwrap();
let (time0, time_z, now) = (
self.0.time_axis.start, self.0.time_axis.scale, self.0.now % phrase.length
);
let Rect { x, width, .. } = area;
let x2 = x as usize + Sequencer::H_KEYS_OFFSET;
let x3 = x as usize + width as usize;
for x in x2..x3 {
let step = (time0 + x2) * time_z;
let next_step = (time0 + x2 + 1) * time_z;
let style = Sequencer::style_timer_step(now, step as usize, next_step as usize);
"-".blit(buf, x as u16, area.y, Some(style))?;
}
return Ok(Rect { x: area.x, y: area.y, width: area.width, height: 1 })
}
}