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
84
85
86
87
88
89
90
91
92
93
94
use misc::*;
#[derive(Copy, Clone)]
pub struct DirectWaveformRenderer {
pub sample_rate: f64,
pub config: WaveformConfig,
}
impl DirectWaveformRenderer {
/// Generates an image as a `Vec<u8>` directly from the given samples.
///
/// # Arguments
///
/// * `samples` - The `Sample`s that will be used to render the image.
/// * `shape` - The `(width, height)` of the resulting image.
pub fn render_vec<T: Sample>(&self, samples: &[T], shape: (usize, usize)) -> Option<Vec<u8>> {
let (w, h) = shape;
if w == 0 || h == 0 {
return None;
}
let mut img = vec![0u8; w * h * 4];
let nb_samples = samples.len();
let samples_per_pixel = nb_samples / w;
// Unlike BinnedWaveformRenderer, the minmax values corresponding to
// each horizontal pixel is calculated beforehand, for the same reasons
// discussed later in these comments.
let mut minmax = MinMaxPairSequence {
data: Vec::with_capacity(w),
};
for x in 0..w {
let mut min = samples[x * samples_per_pixel + 0];
let mut max = samples[x * samples_per_pixel + 0];
if samples_per_pixel > 1 {
for i in 1..samples_per_pixel {
let idx = x * samples_per_pixel + i;
if idx >= nb_samples {
break;
}
let s = samples[idx];
if s > max {
max = s;
}
if s < min {
min = s;
}
}
}
minmax.data.push(MinMaxPair { min: min, max: max });
}
// Unlike BinnedWaveformRenderer, the `match` is outside the `for`s
// because it's faster this way.
// I've also tried it in BinnedWaveformRenderer but it didn't make a
// significant improvement in speed, so it's left that way.
match (self.config.get_background(), self.config.get_foreground()) {
(Color::Scalar(ba), Color::Scalar(fa)) => for y in 0..h {
let y_translated = ((h - y) as f64) / (h as f64) * (self.config.amp_max - self.config.amp_min) + self.config.amp_min;
for x in 0..w {
if y_translated < minmax.data[x].min.into() || y_translated > minmax.data[x].max.into() {
img[1 * (y * w + x) + 0] = ba;
} else {
img[1 * (y * w + x) + 0] = fa;
}
}
},
(
Color::Vector4(br, bg, bb, ba),
Color::Vector4(fr, fg, fb, fa),
) => for y in 0..h {
let y_translated = ((h - y) as f64) / (h as f64) * (self.config.amp_max - self.config.amp_min) + self.config.amp_min;
for x in 0..w {
if y_translated < minmax.data[x].min.into() || y_translated > minmax.data[x].max.into() {
img[4 * (y * w + x) + 0] = br;
img[4 * (y * w + x) + 1] = bg;
img[4 * (y * w + x) + 2] = bb;
img[4 * (y * w + x) + 3] = ba;
} else {
img[4 * (y * w + x) + 0] = fr;
img[4 * (y * w + x) + 1] = fg;
img[4 * (y * w + x) + 2] = fb;
img[4 * (y * w + x) + 3] = fa;
}
}
},
_ => {
panic!("Color formats of background and foreground are inconsistent!");
}
}
Some(img)
}
}