use cursive_core::{
Printer, Vec2, View,
theme::{Color, ColorStyle}
};
use rand::{
Rng, thread_rng,
prelude::SliceRandom as _,
rngs::ThreadRng
};
use audiovis::RawVisualizer;
use mlounge_core::library::Song;
pub struct WaveVisualizer {
rand: ThreadRng,
wave: RawVisualizer,
latest_data: Vec<f32>,
art_path: String,
colors: Vec<Color>,
width: usize
}
impl WaveVisualizer {
pub fn new() -> WaveVisualizer {
WaveVisualizer {
rand: thread_rng(),
wave: RawVisualizer::new(),
latest_data: vec![],
art_path: String::new(),
colors: vec![],
width: 0
}
}
pub fn update(&mut self, song: &Song) {
if self.width == 0 { return; }
self.latest_data = self.wave.get_wave_data(self.width / 2);
if self.latest_data.len() < 4 { return; }
if let Some(path) = song.get_art_path() {
if self.art_path != path || self.latest_data[3] >= 0.25 {
self.colors.clear();
self.art_path = path;
let colors = song.cursive_album_colors();
let num_colors = self.rand.gen_range(5..20);
self.colors = colors.choose_multiple(&mut self.rand, num_colors).copied().collect();
}
}
}
fn draw_multicolored_line(&self, printer: &Printer, x: usize, line_height: usize, max_height: usize) {
let height = printer.size.y;
let color_height = max_height / self.colors.len();
let mut color_index = 0;
let real_height =
if line_height % 2 == 0 {
line_height / 2
}
else {
(line_height + 1) / 2
}
.clamp(2, max_height);
let mut height_idx = 0;
for y in 0..real_height {
let color1 = if height_idx <= 3 {
self.colors[0]
}
else { self.colors[color_index] };
if color_height > 0 {
if height_idx % color_height == 0 && height_idx > 0 && height_idx < line_height { color_index += 1; }
if color_index >= self.colors.len() { color_index = 0; }
}
height_idx += 1;
let color2 = self.colors[color_index];
if color_height > 0 {
if height_idx % color_height == 0 && height_idx > 0 && height_idx < line_height { color_index += 1; }
if color_index >= self.colors.len() { color_index = 0; }
}
height_idx += 1;
let style = if height_idx >= line_height {
ColorStyle::new(color1, Color::TerminalDefault)
}
else { ColorStyle::new(color1, color2) };
printer.with_color(style, |printer| printer.print((x, height - y), "▄"));
}
}
}
impl View for WaveVisualizer {
fn draw(&self, printer: &Printer) {
if self.colors.is_empty() { return; }
let height = printer.size.y;
let max_height = height / 3;
for (x, freq) in self.latest_data.iter().rev().chain(&self.latest_data).enumerate() {
self.draw_multicolored_line(printer, x, (*freq * 10. * max_height as f32) as usize, max_height);
}
}
fn required_size(&mut self, constraint: Vec2) -> Vec2 {
self.width = constraint.x;
constraint
}
}
impl Default for WaveVisualizer {
fn default() -> Self { Self::new() }
}