tek/tek/device/sampler/sampler_view.rs
2025-09-08 00:00:33 +03:00

283 lines
10 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::*;
impl Sampler {
pub fn view_grid (&self) -> impl Draw<TuiOut> + Layout<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
//Thunk::new(|to: &mut TuiOut|{
//})
"TODO"
}
pub fn view_grid_cell <'a> (
&'a self, name: &'a str, x: u16, y: u16, w: u16, h: u16
) -> impl Draw<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, T: NotePoint + NoteRange> (
&'a self, compact: bool, editor: &T
) -> impl Draw<TuiOut> + 'a {
let note_lo = editor.get_note_lo();
let note_pt = editor.get_note_pos();
let note_hi = editor.get_note_hi();
Fixed::x(if compact { 4 } else { 12 }, Map::south(
1,
move||(note_lo..=note_hi).rev(),
move|note, _index| {
//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);
if let Some(mapped) = &self.mapped[note] {
let sample = mapped.read().unwrap();
fg = if note == note_pt {
sample.color.lightest.rgb
} else {
Tui::g(224)
};
bg = if note == note_pt {
sample.color.light.rgb
} else {
sample.color.base.rgb
};
}
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 Draw<TuiOut> + use<'_> {
Outer(true, Style::default().fg(Tui::g(96)))
.enclose(Fill::xy(draw_viewer(if let Some((_, Some(sample))) = &self.recording {
Some(sample)
} else if let Some(sample) = &self.mapped[note_pt] {
Some(sample)
} else {
None
})))
}
pub fn view_sample_info (&self, note_pt: usize) -> impl Draw<TuiOut> + use<'_> {
Fill::x(Fixed::y(1, draw_info(if let Some((_, Some(sample))) = &self.recording {
Some(sample)
} else if let Some(sample) = &self.mapped[note_pt] {
Some(sample)
} else {
None
})))
}
pub fn view_sample_status (&self, note_pt: usize) -> impl Draw<TuiOut> + use<'_> {
Fixed::x(20, draw_info_v(if let Some((_, Some(sample))) = &self.recording {
Some(sample)
} else if let Some(sample) = &self.mapped[note_pt] {
Some(sample)
} else {
None
}))
}
pub fn view_status (&self, index: usize) -> impl Draw<TuiOut> {
draw_status(self.mapped[index].as_ref())
}
pub fn view_meters_input (&self) -> impl Draw<TuiOut> + use<'_> {
draw_meters(&self.input_meters)
}
pub fn view_meters_output (&self) -> impl Draw<TuiOut> + use<'_> {
draw_meters(&self.output_meters)
}
}
fn draw_meters (meters: &[f32]) -> impl Draw<TuiOut> + use<'_> {
Tui::bg(Black, Fixed::x(2, Map::east(1, ||meters.iter(), |value, _index|{
Fill::y(RmsMeter(*value))
})))
}
fn draw_list_item (sample: &Option<Arc<RwLock<Sample>>>) -> String {
if let Some(sample) = sample {
let sample = sample.read().unwrap();
format!("{:8}", sample.name)
//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 Draw<TuiOut> + Layout<TuiOut> + use<'_> {
let min_db = -64.0;
Thunk::new(move|to: &mut TuiOut|{
let [x, y, width, height] = to.area();
let area = Rect { x, y, width, height };
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.;
}
Canvas::default()
.x_bounds([sample.start as f64, sample.end as f64])
.y_bounds([min_db, 0.])
.paint(|ctx| {
for line in lines.iter() {
ctx.draw(line);
}
//FIXME: proportions
//let text = "press record to finish sampling";
//ctx.print(
//(width - text.len() as u16) as f64 / 2.0,
//height as f64 / 2.0,
//text.red()
//);
}).render(area, &mut to.buffer);
} else {
Canvas::default()
.x_bounds([0.0, width as f64])
.y_bounds([0.0, height as f64])
.paint(|_ctx| {
//let text = "press record to begin sampling";
//ctx.print(
//(width - text.len() as u16) as f64 / 2.0,
//height as f64 / 2.0,
//text.red()
//);
})
.render(area, &mut to.buffer);
}
})
}
fn draw_info (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<TuiOut> + Layout<TuiOut> + use<'_> {
When(sample.is_some(), Thunk::new(move|to: &mut TuiOut|{
let sample = sample.unwrap().read().unwrap();
let theme = sample.color;
to.place(&row!(
FieldH(theme, "Name", format!("{:<10}", sample.name.clone())),
FieldH(theme, "Length", format!("{:<8}", sample.channels[0].len())),
FieldH(theme, "Start", format!("{:<8}", sample.start)),
FieldH(theme, "End", format!("{:<8}", sample.end)),
FieldH(theme, "Trans", "0"),
FieldH(theme, "Gain", format!("{}", sample.gain)),
))
}))
}
fn draw_info_v (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<TuiOut> + Layout<TuiOut> + use<'_> {
Either::new(sample.is_some(), Thunk::new(move|to: &mut TuiOut|{
let sample = sample.unwrap().read().unwrap();
let theme = sample.color;
to.place(&Fixed::x(20, col!(
Fill::x(Align::w(FieldH(theme, "Name ", format!("{:<10}", sample.name.clone())))),
Fill::x(Align::w(FieldH(theme, "Length", format!("{:<8}", sample.channels[0].len())))),
Fill::x(Align::w(FieldH(theme, "Start ", format!("{:<8}", sample.start)))),
Fill::x(Align::w(FieldH(theme, "End ", format!("{:<8}", sample.end)))),
Fill::x(Align::w(FieldH(theme, "Trans ", "0"))),
Fill::x(Align::w(FieldH(theme, "Gain ", format!("{}", sample.gain)))),
)))
}), Thunk::new(|to: &mut TuiOut|to.place(&Tui::fg(Red, col!(
Tui::bold(true, "× No sample."),
"[r] record",
"[Shift-F9] import",
)))))
}
fn draw_status (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<TuiOut> + Layout<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)
}