use {FloatSample, Sample};
use core;
use core::marker::PhantomData;
use frame::Frame;
use signal::{self, Signal};
pub trait Type {
fn at_phase<S: Sample>(phase: S) -> S;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Hanning;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Rectangle;
#[derive(Clone)]
pub struct Window<F, W>
where F: Frame,
W: Type,
{
pub phase: signal::Phase<signal::ConstHz>,
marker: PhantomData<(F, W)>,
}
#[derive(Clone)]
pub struct Windower<'a, F, W>
where F: 'a + Frame,
W: Type,
{
pub bin: usize,
pub hop: usize,
pub frames: &'a [F],
wttype: PhantomData<W>
}
impl Type for Hanning {
fn at_phase<S: Sample>(phase: S) -> S {
const PI_2: f64 = core::f64::consts::PI * 2.0;
let v = phase.to_float_sample().to_sample() * PI_2;
(0.5 * (1.0 - super::ops::f64::cos(v)))
.to_sample::<S::Float>()
.to_sample::<S>()
}
}
impl Type for Rectangle {
fn at_phase<S: Sample>(_phase: S) -> S {
<S::Float as FloatSample>::identity().to_sample::<S>()
}
}
impl<F, W> Window<F, W>
where F: Frame,
W: Type
{
pub fn new(len: usize) -> Self {
let step = signal::rate(len as f64 - 1.0).const_hz(1.0);
Window {
phase: signal::phase(step),
marker: PhantomData,
}
}
}
impl<'a, F, W> Windower<'a, F, W>
where F: 'a + Frame,
W: Type
{
pub fn new(frames: &'a [F], bin: usize, hop: usize) -> Self {
Windower {
bin: bin,
hop: hop,
frames: frames,
wttype: PhantomData
}
}
}
impl<'a, F> Windower<'a, F, Rectangle>
where F: 'a + Frame,
{
pub fn rectangle(frames: &'a [F], bin: usize, hop: usize) -> Self {
Windower::new(frames, bin, hop)
}
}
impl<'a, F> Windower<'a, F, Hanning>
where F: 'a + Frame,
{
pub fn hanning(frames: &'a [F], bin: usize, hop: usize) -> Self {
Windower::new(frames, bin, hop)
}
}
impl<F, W> Iterator for Window<F, W>
where F: Frame,
W: Type
{
type Item = F;
fn next(&mut self) -> Option<Self::Item> {
let v = W::at_phase(self.phase.next_phase());
let v_f: <F::Sample as Sample>::Float = v.to_sample();
Some(F::from_fn(|_| v_f.to_sample::<F::Sample>()))
}
}
impl<'a, F, W> Iterator for Windower<'a, F, W>
where F: 'a + Frame,
W: Type
{
type Item = signal::MulAmp<core::iter::Cloned<core::slice::Iter<'a, F>>, Window<F::Float, W>>;
fn next(&mut self) -> Option<Self::Item> {
let num_frames = self.frames.len();
if self.bin <= num_frames {
let frames = &self.frames[..self.bin];
let window = Window::new(self.bin);
self.frames = if self.hop < num_frames { &self.frames[self.hop..] } else { &[] };
Some(frames.iter().cloned().mul_amp(window))
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let num_frames = self.frames.len();
if self.bin < num_frames {
if self.hop == 0 {
return (core::usize::MAX, None);
}
let remaining_hop_frames = self.frames.len() - self.bin;
let remaining_iterations = remaining_hop_frames / self.hop;
(remaining_iterations, Some(remaining_iterations))
} else {
(0, Some(0))
}
}
}
pub fn hanning<F>(num_frames: usize) -> Window<F, Hanning>
where F: Frame,
{
Window::new(num_frames)
}
pub fn rectangle<F>(num_frames: usize) -> Window<F, Rectangle>
where F: Frame,
{
Window::new(num_frames)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_window_size() {
let v = [[1f32; 1]; 16];
let windows: Vec<Vec<[f32; 1]>> = Windower::hanning(&v[..], 8, 4).map(|i| i.collect::<Vec<[f32; 1]>>()).collect();
assert_eq!(windows.len(), 3);
}
}