use crate::*; impl Sampler { pub fn view_grid (&self) -> impl Content + 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 + 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 + '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>> = &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 + 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 { draw_status(self.mapped[index].as_ref()) } } fn draw_list_item (sample: &Option>>) -> 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>>) -> impl Content + 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) = 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>>) -> impl Content { 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 { 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) }