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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use std::collections::HashMap;
use std::error::Error;

use super::misc::*;
use super::error::*;
use super::binned::BinnedWaveformRenderer;

/// A renderer that contains multiple `BinnedWaveformRenderer`s
/// with different bin sizes.
///
/// It will automatically choose an apropriate bin size each time
/// it renders.
pub struct MultiWaveformRenderer<T: Sample> {
    pub binned: HashMap<usize, BinnedWaveformRenderer<T>>,
    sample_rate: f64,
}

impl<T: Sample> MultiWaveformRenderer<T> {
    /// The constructor.
    ///
    /// # Arguments
    ///
    /// * `samples` - The samples that will be used to calculate binned min / max values.
    ///               It must also contain the sample rate that is used by
    ///               `BinnedWaveformRenderer` to render images when given a
    ///               `TimeRange::Seconds`.
    /// * `bin_sizes` - The sizes of the bins which the min / max values will be binned
    ///                into.
    /// * `config` - See `WaveformConfig`.
    pub fn new(samples: &SampleSequence<T>, bin_sizes: &[usize], config: WaveformConfig) -> Result<Self, Box<Error>> {
        let mut r = MultiWaveformRenderer {
            binned: HashMap::new(),
            sample_rate: samples.sample_rate,
        };
        let mut bss = Vec::with_capacity(bin_sizes.len());
        for bs in bin_sizes {
            bss.push(*bs);
        }
        bss.sort();

        // TODO: This is obviously improvable if we use the 
        // result for smaller bin sizes for calculating the
        // larger bin sizes.
        for bs in bss.iter() {
            r.binned
                .insert(*bs, try!(BinnedWaveformRenderer::new(samples, *bs, config)));
        }

        Ok(r)
    }

    fn get_optimal_bin_size(&self, samples_per_pixel: f64) -> Option<usize> {

        let mut bin_sizes: Vec<usize> = self.binned.keys().map(|x| *x).collect();
        if bin_sizes.len() == 0 {
            return None;
        }

        bin_sizes.sort();
        let mut bin_size = bin_sizes[0];
        for bs in bin_sizes.iter() {
            if (*bs as f64) <= samples_per_pixel {
                bin_size = *bs;
            } else {
                break;
            }
        }

        Some(bin_size)
    }

    /// Renders an image as a `Vec<u8>`.
    ///
    /// `None` will be returned if the area of the specified `shape` is equal to zero.
    ///
    /// # Arguments
    ///
    /// * `range` - The samples within this `TimeRange` will be rendered.
    /// * `shape` - The `(width, height)` of the resulting image in pixels.
    pub fn render_vec(&mut self, range: TimeRange, shape: (usize, usize)) -> Option<Vec<u8>> {
        let (w, h) = shape;
        if w == 0 || h == 0 {
            return None;
        }

        let (begin, end) = range.to_sample_tuple(self.sample_rate);

        let samples_per_pixel = ((end - begin) as f64) / (w as f64);

        if let Some(bin_size) = self.get_optimal_bin_size(samples_per_pixel) {
            return self.binned
                .get_mut(&bin_size)
                .unwrap()
                .render_vec(range, shape);
        }else{
            return None;
        }
    }


    /// Writes the image into a mutable reference to a slice.
    ///
    /// It will raise an error if
    ///
    /// * the area of the specified `shape` is equal to zero.
    /// * either the width or height of the `shape` exceeds that of the `full_shape`
    ///   of `img`.
    /// * the length of `img` is not long enough to contain the result.
    ///   `(offsets.0 + shape.0) * (offsets.1 + shape.1) * (Bytes per pixel) <= img.len()`
    ///   must be satisfied.
    ///
    /// # Arguments
    ///
    /// * `range` - The samples within this `TimeRange` will be rendered.
    /// * `offsets` - The `(x-offset, y-offset)` of the part of the `img` that is
    ///               going to be overwritten in in pixels.
    ///               Specifies the starting position to write into `img`.
    /// * `shape` - The `(width, height)` of the part of the `img` that is going 
    ///             to be overwritten in pixels.
    /// * `img`   - A mutable reference to the slice to write the result into.
    /// * `full_shape` - The `(width, height)` of the whole `img` in pixels.
    ///
    pub fn render_write(&mut self, range: TimeRange, offsets: (usize, usize), shape: (usize, usize), img: &mut [u8], full_shape: (usize, usize)) -> Result<(), Box<Error>> {
        let (begin, end) = range.to_sample_tuple(self.sample_rate);

        let samples_per_pixel = ((end - begin) as f64) / (shape.0 as f64);

        if let Some(bin_size) = self.get_optimal_bin_size(samples_per_pixel) {
            return self.binned
                .get_mut(&bin_size)
                .unwrap()
                .render_write(range, offsets, shape, img, full_shape);
        }else{
            return Err(Box::new(InvalidSizeError{var_name: "bin sizes".to_string()}));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::MultiWaveformRenderer;
    use misc::*;

    #[test]
    fn multi() {
        let data = vec![0f64; 50000];
        let sample_rate = 44100f64;
        let ss = SampleSequence {
            data: &data[..],
            sample_rate,
        };
        let foreground = Color::Vector4(255, 0, 0, 255);
        let background = Color::Vector4(0, 0, 0, 0);
        let config = WaveformConfig::new(-100f64, 100f64, foreground, background).unwrap();
        let bss = vec![10, 50, 100];
        let mut mwr = MultiWaveformRenderer::new(&ss, &bss, config).unwrap();

        for bs in bss.iter() {
            assert_eq!(mwr.binned.get(bs).unwrap().get_bin_size(), *bs);
            assert_eq!(mwr.binned.get(bs).unwrap().get_sample_rate(), sample_rate);
        }

        mwr.render_vec(TimeRange::Seconds(0f64, 1f64), (1000, 100))
            .unwrap();
    }

    #[test]
    fn markers() {
        let c = Color::Scalar(0);
        let config = WaveformConfig::new(-1f64, 1f64, c, c).unwrap();
        let wfr = MultiWaveformRenderer::new(
            &SampleSequence {
                data: &vec![0f64; 100],
                sample_rate: 44100f64,
            },
            &vec![10usize], config
        ).unwrap();
        let _test: &(Sync+Send) = &wfr;
    }
}