1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use cursive_core::{
    Printer, Vec2, View,
    theme::{Color, ColorStyle}
};
use rand::{
    Rng, thread_rng,
    prelude::SliceRandom as _
};
use audiovis::RawVisualizer;
use mlounge_core::library::Song;

/// An audio visualizer that visualizes the audio as a waveform
pub struct WaveVisualizer {
    wave: RawVisualizer,
    latest_data: Vec<f32>,
    art_path: String,
    colors: Vec<Color>,
    width: usize
}

impl WaveVisualizer {
    /// Create a new `WaveVisualizer`
    pub fn new() -> WaveVisualizer {
        WaveVisualizer {
            wave: RawVisualizer::new(),
            latest_data: vec![],
            art_path: String::new(),
            colors: vec![],
            width: 0
        }
    }

    /// Update the audio visualizer with the specified song
    pub fn update(&mut self, song: &Song) {
        if self.width == 0 { return; }
        let mut rand = thread_rng();
        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 = rand.gen_range(5..20);
                self.colors = colors.choose_multiple(&mut rand, num_colors).copied().collect();
            }
        }
    }
}

impl View for WaveVisualizer {
    fn draw(&self, printer: &Printer) {
        if self.colors.is_empty() { return; }
        let width = printer.size.x;
        let height = printer.size.y;
        let mut latest_data = self.latest_data.clone();
        latest_data.resize(width / 2, 0.);
        let mut wave = latest_data.clone();
        wave.reverse();
        wave.extend_from_slice(&latest_data);
        let mut color_i = 0;
        let color_m = width / self.colors.len();
        for (i, level) in wave.iter().enumerate() {
            let style = ColorStyle::new(self.colors[color_i], Color::TerminalDefault);
            let int_level = (level * height as f32) as usize / 3;
            printer.with_color(style, |printer| {
                printer.print_vline((i, height - int_level), int_level, "█");
                printer.print((i, height - 1), "█");
            });
            if i % color_m == 0 && i > 0 && i < width { color_i += 1; }
            if color_i >= self.colors.len() { color_i = 0; }
        }
    }

    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
        self.width = constraint.x;
        constraint
    }
}

impl Default for WaveVisualizer {
    fn default() -> Self { Self::new() }
}