waveform/
multi.rs

1use std::collections::HashMap;
2use std::error::Error;
3
4use super::misc::*;
5use super::error::*;
6use super::binned::BinnedWaveformRenderer;
7
8/// A renderer that contains multiple `BinnedWaveformRenderer`s
9/// with different bin sizes.
10///
11/// It will automatically choose an apropriate bin size each time
12/// it renders.
13pub struct MultiWaveformRenderer<T: Sample> {
14    pub binned: HashMap<usize, BinnedWaveformRenderer<T>>,
15    sample_rate: f64,
16}
17
18impl<T: Sample> MultiWaveformRenderer<T> {
19    /// The constructor.
20    ///
21    /// # Arguments
22    ///
23    /// * `samples` - The samples that will be used to calculate binned min / max values.
24    ///               It must also contain the sample rate that is used by
25    ///               `BinnedWaveformRenderer` to render images when given a
26    ///               `TimeRange::Seconds`.
27    /// * `bin_sizes` - The sizes of the bins which the min / max values will be binned
28    ///                into.
29    /// * `config` - See `WaveformConfig`.
30    pub fn new(samples: &SampleSequence<T>, bin_sizes: &[usize], config: WaveformConfig) -> Result<Self, Box<Error>> {
31        let mut r = MultiWaveformRenderer {
32            binned: HashMap::new(),
33            sample_rate: samples.sample_rate,
34        };
35        let mut bss = Vec::with_capacity(bin_sizes.len());
36        for bs in bin_sizes {
37            bss.push(*bs);
38        }
39        bss.sort();
40
41        // TODO: This is obviously improvable if we use the 
42        // result for smaller bin sizes for calculating the
43        // larger bin sizes.
44        for bs in bss.iter() {
45            r.binned
46                .insert(*bs, try!(BinnedWaveformRenderer::new(samples, *bs, config)));
47        }
48
49        Ok(r)
50    }
51
52    fn get_optimal_bin_size(&self, samples_per_pixel: f64) -> Option<usize> {
53
54        let mut bin_sizes: Vec<usize> = self.binned.keys().map(|x| *x).collect();
55        if bin_sizes.len() == 0 {
56            return None;
57        }
58
59        bin_sizes.sort();
60        let mut bin_size = bin_sizes[0];
61        for bs in bin_sizes.iter() {
62            if (*bs as f64) <= samples_per_pixel {
63                bin_size = *bs;
64            } else {
65                break;
66            }
67        }
68
69        Some(bin_size)
70    }
71
72    /// Renders an image as a `Vec<u8>`.
73    ///
74    /// `None` will be returned if the area of the specified `shape` is equal to zero.
75    ///
76    /// # Arguments
77    ///
78    /// * `range` - The samples within this `TimeRange` will be rendered.
79    /// * `shape` - The `(width, height)` of the resulting image in pixels.
80    pub fn render_vec(&mut self, range: TimeRange, shape: (usize, usize)) -> Option<Vec<u8>> {
81        let (w, h) = shape;
82        if w == 0 || h == 0 {
83            return None;
84        }
85
86        let (begin, end) = range.to_sample_tuple(self.sample_rate);
87
88        let samples_per_pixel = ((end - begin) as f64) / (w as f64);
89
90        if let Some(bin_size) = self.get_optimal_bin_size(samples_per_pixel) {
91            return self.binned
92                .get_mut(&bin_size)
93                .unwrap()
94                .render_vec(range, shape);
95        }else{
96            return None;
97        }
98    }
99
100
101    /// Writes the image into a mutable reference to a slice.
102    ///
103    /// It will raise an error if
104    ///
105    /// * the area of the specified `shape` is equal to zero.
106    /// * either the width or height of the `shape` exceeds that of the `full_shape`
107    ///   of `img`.
108    /// * the length of `img` is not long enough to contain the result.
109    ///   `(offsets.0 + shape.0) * (offsets.1 + shape.1) * (Bytes per pixel) <= img.len()`
110    ///   must be satisfied.
111    ///
112    /// # Arguments
113    ///
114    /// * `range` - The samples within this `TimeRange` will be rendered.
115    /// * `offsets` - The `(x-offset, y-offset)` of the part of the `img` that is
116    ///               going to be overwritten in in pixels.
117    ///               Specifies the starting position to write into `img`.
118    /// * `shape` - The `(width, height)` of the part of the `img` that is going 
119    ///             to be overwritten in pixels.
120    /// * `img`   - A mutable reference to the slice to write the result into.
121    /// * `full_shape` - The `(width, height)` of the whole `img` in pixels.
122    ///
123    pub fn render_write(&mut self, range: TimeRange, offsets: (usize, usize), shape: (usize, usize), img: &mut [u8], full_shape: (usize, usize)) -> Result<(), Box<Error>> {
124        let (begin, end) = range.to_sample_tuple(self.sample_rate);
125
126        let samples_per_pixel = ((end - begin) as f64) / (shape.0 as f64);
127
128        if let Some(bin_size) = self.get_optimal_bin_size(samples_per_pixel) {
129            return self.binned
130                .get_mut(&bin_size)
131                .unwrap()
132                .render_write(range, offsets, shape, img, full_shape);
133        }else{
134            return Err(Box::new(InvalidSizeError{var_name: "bin sizes".to_string()}));
135        }
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::MultiWaveformRenderer;
142    use misc::*;
143
144    #[test]
145    fn multi() {
146        let data = vec![0f64; 50000];
147        let sample_rate = 44100f64;
148        let ss = SampleSequence {
149            data: &data[..],
150            sample_rate,
151        };
152        let foreground = Color::Vector4(255, 0, 0, 255);
153        let background = Color::Vector4(0, 0, 0, 0);
154        let config = WaveformConfig::new(-100f64, 100f64, foreground, background).unwrap();
155        let bss = vec![10, 50, 100];
156        let mut mwr = MultiWaveformRenderer::new(&ss, &bss, config).unwrap();
157
158        for bs in bss.iter() {
159            assert_eq!(mwr.binned.get(bs).unwrap().get_bin_size(), *bs);
160            assert_eq!(mwr.binned.get(bs).unwrap().get_sample_rate(), sample_rate);
161        }
162
163        mwr.render_vec(TimeRange::Seconds(0f64, 1f64), (1000, 100))
164            .unwrap();
165    }
166
167    #[test]
168    fn markers() {
169        let c = Color::Scalar(0);
170        let config = WaveformConfig::new(-1f64, 1f64, c, c).unwrap();
171        let wfr = MultiWaveformRenderer::new(
172            &SampleSequence {
173                data: &vec![0f64; 100],
174                sample_rate: 44100f64,
175            },
176            &vec![10usize], config
177        ).unwrap();
178        let _test: &(Sync+Send) = &wfr;
179    }
180}