Skip to main content

sample/
window.rs

1//! Module for windowing over a batch of Frames. Includes default Hanning and Rectangle window
2//! types.
3
4use {FloatSample, Sample};
5use core;
6use core::marker::PhantomData;
7use frame::Frame;
8use signal::{self, Signal};
9
10/// The window function used within a `Window`.
11pub trait Type {
12    /// Returns the amplitude for the given phase, given as some `Sample` type.
13    fn at_phase<S: Sample>(phase: S) -> S;
14}
15
16/// A type of window function, also known as the "raised cosine window".
17///
18/// [Wiki entry](https://en.wikipedia.org/wiki/Window_function#Hann_.28Hanning.29_window).
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub struct Hanning;
21
22/// The simplest window type, equivalent to replacing all but *N* values of data sequence by
23/// zeroes, making it appear as though the waveform suddenly turns on and off.
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub struct Rectangle;
26
27/// A `Signal` type that for every yielded `phase`, yields the amplitude across the `window::Type`
28/// for that phase.
29#[derive(Clone)]
30pub struct Window<F, W>
31where
32    F: Frame,
33    W: Type,
34{
35    /// Yields phase stepped at a constant rate to be passed to the window function `W`.
36    pub phase: signal::Phase<signal::ConstHz>,
37    marker: PhantomData<(F, W)>,
38}
39
40/// Takes a long slice of frames and yields `Windowed` chunks of size `bin` once every `hop` frames.
41#[derive(Clone)]
42pub struct Windower<'a, F, W>
43where
44    F: 'a + Frame,
45    W: Type,
46{
47    /// The size of each `Windowed` chunk to be yielded.
48    pub bin: usize,
49    /// The step size over `frames` for the start of each new `Windowed` chunk.
50    pub hop: usize,
51    /// The beginning of the remaining slice to be yielded by the `Windower`.
52    pub frames: &'a [F],
53    wttype: PhantomData<W>,
54}
55
56/// An Iterator that multiplies a Signal with a Window.
57///
58/// Returns `None` once the `Window` has been exhausted.
59#[derive(Clone)]
60pub struct Windowed<S, W>
61where
62    S: Signal,
63    W: Type,
64{
65    signal: S,
66    window: Window<<S::Frame as Frame>::Float, W>,
67}
68
69
70impl Type for Hanning {
71    fn at_phase<S: Sample>(phase: S) -> S {
72        const PI_2: f64 = core::f64::consts::PI * 2.0;
73        let v = phase.to_float_sample().to_sample() * PI_2;
74        (0.5 * (1.0 - super::ops::f64::cos(v)))
75            .to_sample::<S::Float>()
76            .to_sample::<S>()
77    }
78}
79
80impl Type for Rectangle {
81    fn at_phase<S: Sample>(_phase: S) -> S {
82        <S::Float as FloatSample>::identity().to_sample::<S>()
83    }
84}
85
86
87impl<F, W> Window<F, W>
88where
89    F: Frame,
90    W: Type,
91{
92    /// Construct a new `Window` with the given length as a number of frames.
93    pub fn new(len: usize) -> Self {
94        let step = signal::rate(len as f64 - 1.0).const_hz(1.0);
95        Window {
96            phase: signal::phase(step),
97            marker: PhantomData,
98        }
99    }
100}
101
102
103impl<'a, F, W> Windower<'a, F, W>
104where
105    F: 'a + Frame,
106    W: Type,
107{
108    /// Constructor for a new `Windower` iterator.
109    pub fn new(frames: &'a [F], bin: usize, hop: usize) -> Self {
110        Windower {
111            bin: bin,
112            hop: hop,
113            frames: frames,
114            wttype: PhantomData,
115        }
116    }
117}
118
119impl<'a, F> Windower<'a, F, Rectangle>
120where
121    F: 'a + Frame,
122{
123    /// Constructor for a `Windower` using the `Rectangle` window function.
124    pub fn rectangle(frames: &'a [F], bin: usize, hop: usize) -> Self {
125        Windower::new(frames, bin, hop)
126    }
127}
128
129impl<'a, F> Windower<'a, F, Hanning>
130where
131    F: 'a + Frame,
132{
133    /// Constructor for a `Windower` using the `Hanning` window function.
134    pub fn hanning(frames: &'a [F], bin: usize, hop: usize) -> Self {
135        Windower::new(frames, bin, hop)
136    }
137}
138
139
140impl<F, W> Iterator for Window<F, W>
141where
142    F: Frame,
143    W: Type,
144{
145    type Item = F;
146
147    fn next(&mut self) -> Option<Self::Item> {
148        let v = W::at_phase(self.phase.next_phase());
149        let v_f: <F::Sample as Sample>::Float = v.to_sample();
150        Some(F::from_fn(|_| v_f.to_sample::<F::Sample>()))
151    }
152}
153
154impl<'a, F, W> Iterator for Windower<'a, F, W>
155where
156    F: 'a + Frame,
157    W: Type,
158{
159    type Item = Windowed<signal::FromIterator<core::iter::Cloned<core::slice::Iter<'a, F>>>, W>;
160
161    fn next(&mut self) -> Option<Self::Item> {
162        let num_frames = self.frames.len();
163        if self.bin <= num_frames {
164            let frames = &self.frames[..self.bin];
165            let window = Window::new(self.bin);
166            self.frames = if self.hop < num_frames {
167                &self.frames[self.hop..]
168            } else {
169                &[]
170            };
171            Some(Windowed {
172                signal: signal::from_iter(frames.iter().cloned()),
173                window: window,
174            })
175        } else {
176            None
177        }
178    }
179
180    fn size_hint(&self) -> (usize, Option<usize>) {
181        let num_frames = self.frames.len();
182        // Must have at least `bin` number of frames left to iterate at all.
183        if self.bin < num_frames {
184            // If the hop size is 0, we'll iterate forever.
185            if self.hop == 0 {
186                return (core::usize::MAX, None);
187            }
188            // Otherwise we can determine exactly how many iterations remain.
189            let remaining_hop_frames = self.frames.len() - self.bin;
190            let remaining_iterations = remaining_hop_frames / self.hop;
191            (remaining_iterations, Some(remaining_iterations))
192        } else {
193            (0, Some(0))
194        }
195    }
196}
197
198impl<S, W> Iterator for Windowed<S, W>
199where
200    S: Signal,
201    W: Type,
202{
203    type Item = S::Frame;
204    fn next(&mut self) -> Option<Self::Item> {
205        self.window.next().map(|w_f| {
206            let s_f = self.signal.next();
207            s_f.mul_amp(w_f)
208        })
209    }
210}
211
212/// A helper function for constructing a `Window` that uses a `Hanning` `Type` function.
213pub fn hanning<F>(num_frames: usize) -> Window<F, Hanning>
214where
215    F: Frame,
216{
217    Window::new(num_frames)
218}
219
220/// A helper function for constructing a `Window` that uses a `Rectangle` `Type` function.
221pub fn rectangle<F>(num_frames: usize) -> Window<F, Rectangle>
222where
223    F: Frame,
224{
225    Window::new(num_frames)
226}