mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 03:36:41 +01:00
193 lines
7 KiB
Rust
193 lines
7 KiB
Rust
use crate::*;
|
|
|
|
impl Sampler {
|
|
|
|
pub fn view_grid (&self) -> impl Content<TuiOut> + use<'_> {
|
|
let cells_x = 8u16;
|
|
let cells_y = 8u16;
|
|
let cell_width = 10u16;
|
|
let cell_height = 2u16;
|
|
let width = cells_x * cell_width;
|
|
let height = cells_y * cell_height;
|
|
let cols = Map::east(
|
|
cell_width,
|
|
move||0..cells_x,
|
|
move|x, _|Map::south(
|
|
cell_height,
|
|
move||0..cells_y,
|
|
move|y, _|self.view_grid_cell("........", x, y, cell_width, cell_height)
|
|
)
|
|
);
|
|
cols
|
|
}
|
|
|
|
pub fn view_grid_cell <'a> (
|
|
&'a self, name: &'a str, x: u16, y: u16, w: u16, h: u16
|
|
) -> impl Content<TuiOut> + use<'a> {
|
|
let cursor = self.cursor();
|
|
let hi_fg = Color::Rgb(64, 64, 64);
|
|
let hi_bg = if y == 0 { Color::Reset } else { Color::Rgb(64, 64, 64) /*prev*/ };
|
|
let tx_fg = if let Some((index, _)) = self.recording
|
|
&& index % 8 == x as usize
|
|
&& index / 8 == y as usize
|
|
{
|
|
Color::Rgb(255, 64, 0)
|
|
} else {
|
|
Color::Rgb(255, 255, 255)
|
|
};
|
|
let tx_bg = if x as usize == cursor.0 && y as usize == cursor.1 {
|
|
Color::Rgb(96, 96, 96)
|
|
} else {
|
|
Color::Rgb(64, 64, 64)
|
|
};
|
|
let lo_fg = Color::Rgb(64, 64, 64);
|
|
let lo_bg = if y == 7 { Color::Reset } else { tx_bg };
|
|
Fixed::xy(w, h, Bsp::s(
|
|
Fixed::y(1, Tui::fg_bg(hi_fg, hi_bg, RepeatH(Phat::<()>::LO))),
|
|
Bsp::n(
|
|
Fixed::y(1, Tui::fg_bg(lo_fg, lo_bg, RepeatH(Phat::<()>::HI))),
|
|
Fill::x(Fixed::y(1, Tui::fg_bg(tx_fg, tx_bg, name))),
|
|
),
|
|
))
|
|
}
|
|
|
|
const _EMPTY: &[(f64, f64)] = &[(0., 0.), (1., 1.), (2., 2.), (0., 2.), (2., 0.)];
|
|
|
|
pub fn view_list <'a> (
|
|
&'a self,
|
|
compact: bool,
|
|
editor: &MidiEditor
|
|
) -> impl Content<TuiOut> + 'a {
|
|
let note_lo = editor.note_lo().load(Relaxed);
|
|
let note_pt = editor.note_pos();
|
|
let note_hi = editor.note_hi();
|
|
Fixed::x(12, Map::south(
|
|
1,
|
|
move||(note_lo..=note_hi).rev(),
|
|
move|note, i| {
|
|
//let offset = |a|Push::y(i as u16, Align::n(Fixed::y(1, Fill::x(a))));
|
|
let mut bg = if note == note_pt { Tui::g(64) } else { Color::Reset };
|
|
let mut fg = Tui::g(160);
|
|
let mapped: &Option<Arc<RwLock<Sample>>> = &self.mapped[note];
|
|
if mapped.is_some() {
|
|
fg = Tui::g(224);
|
|
bg = Color::Rgb(0, if note == note_pt { 96 } else { 64 }, 0);
|
|
}
|
|
if let Some((index, _)) = self.recording {
|
|
if note == index {
|
|
bg = if note == note_pt { Color::Rgb(96,24,0) } else { Color::Rgb(64,16,0) };
|
|
fg = Color::Rgb(224,64,32)
|
|
}
|
|
}
|
|
Tui::fg_bg(fg, bg, format!("{note:3} {}", self.view_list_item(note, compact)))
|
|
}))
|
|
}
|
|
pub fn view_list_item (&self, note: usize, compact: bool) -> String {
|
|
if compact {
|
|
String::default()
|
|
} else {
|
|
draw_list_item(&self.mapped[note])
|
|
}
|
|
}
|
|
pub fn view_sample (&self, note_pt: usize) -> impl Content<TuiOut> + use<'_> {
|
|
Outer(true, Style::default().fg(Tui::g(96))).enclose(draw_viewer(if let Some((_, sample)) = &self.recording {
|
|
Some(sample)
|
|
} else if let Some(sample) = &self.mapped[note_pt] {
|
|
Some(sample)
|
|
} else {
|
|
None
|
|
}))
|
|
}
|
|
pub fn status (&self, index: usize) -> impl Content<TuiOut> {
|
|
draw_status(self.mapped[index].as_ref())
|
|
}
|
|
}
|
|
|
|
fn draw_list_item (sample: &Option<Arc<RwLock<Sample>>>) -> String {
|
|
if let Some(sample) = sample {
|
|
let sample = sample.read().unwrap();
|
|
format!("{:8} {:3} {:6}-{:6}/{:6}",
|
|
sample.name,
|
|
sample.gain,
|
|
sample.start,
|
|
sample.end,
|
|
sample.channels[0].len()
|
|
)
|
|
} else {
|
|
String::from("........")
|
|
}
|
|
}
|
|
|
|
fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Content<TuiOut> + use<'_> {
|
|
let min_db = -40.0;
|
|
ThunkRender::new(move|to: &mut TuiOut|{
|
|
let [x, y, width, height] = to.area();
|
|
let area = Rect { x, y, width, height };
|
|
let (x_bounds, y_bounds, lines): ([f64;2], [f64;2], Vec<Line>) =
|
|
if let Some(sample) = &sample {
|
|
let sample = sample.read().unwrap();
|
|
let start = sample.start as f64;
|
|
let end = sample.end as f64;
|
|
let length = end - start;
|
|
let step = length / width as f64;
|
|
let mut t = start;
|
|
let mut lines = vec![];
|
|
while t < end {
|
|
let chunk = &sample.channels[0][t as usize..((t + step) as usize).min(sample.end)];
|
|
let total: f32 = chunk.iter().map(|x|x.abs()).sum();
|
|
let count = chunk.len() as f32;
|
|
let meter = 10. * (total / count).log10();
|
|
let x = t as f64;
|
|
let y = meter as f64;
|
|
lines.push(Line::new(x, min_db, x, y, Color::Green));
|
|
t += step / 2.;
|
|
}
|
|
(
|
|
[sample.start as f64, sample.end as f64],
|
|
[min_db, 0.],
|
|
lines
|
|
)
|
|
} else {
|
|
(
|
|
[0.0, width as f64],
|
|
[0.0, height as f64],
|
|
vec![
|
|
Line::new(0.0, 0.0, width as f64, height as f64, Color::Red),
|
|
Line::new(width as f64, 0.0, 0.0, height as f64, Color::Red),
|
|
]
|
|
)
|
|
};
|
|
Canvas::default()
|
|
.x_bounds(x_bounds)
|
|
.y_bounds(y_bounds)
|
|
.paint(|ctx| { for line in lines.iter() { ctx.draw(line) } })
|
|
.render(area, &mut to.buffer);
|
|
})
|
|
}
|
|
|
|
fn draw_status (sample: Option<&Arc<RwLock<Sample>>>) -> impl Content<TuiOut> {
|
|
Tui::bold(true, Tui::fg(Tui::g(224), sample
|
|
.map(|sample|{
|
|
let sample = sample.read().unwrap();
|
|
format!("Sample {}-{}", sample.start, sample.end)
|
|
})
|
|
.unwrap_or_else(||"No sample".to_string())))
|
|
}
|
|
|
|
fn draw_sample (
|
|
to: &mut TuiOut, x: u16, y: u16, note: Option<&u7>, sample: &Sample, focus: bool
|
|
) -> Usually<usize> {
|
|
let style = if focus { Style::default().green() } else { Style::default() };
|
|
if focus {
|
|
to.blit(&"🬴", x+1, y, Some(style.bold()));
|
|
}
|
|
let label1 = format!("{:3} {:12}",
|
|
note.map(|n|n.to_string()).unwrap_or(String::default()),
|
|
sample.name);
|
|
let label2 = format!("{:>6} {:>6} +0.0",
|
|
sample.start,
|
|
sample.end);
|
|
to.blit(&label1, x+2, y, Some(style.bold()));
|
|
to.blit(&label2, x+3+label1.len()as u16, y, Some(style));
|
|
Ok(label1.len() + label2.len() + 4)
|
|
}
|