mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
283 lines
10 KiB
Rust
283 lines
10 KiB
Rust
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)
|
||
}
|