pub struct FrameIter<'a> {
data: &'a [f64],
frame_length: usize,
hop_length: usize,
current: usize,
n_frames: usize,
}
impl<'a> FrameIter<'a> {
pub fn new(data: &'a [f64], frame_length: usize, hop_length: usize) -> Self {
let n_frames = if data.len() >= frame_length {
1 + (data.len() - frame_length) / hop_length
} else {
0
};
Self {
data,
frame_length,
hop_length,
current: 0,
n_frames,
}
}
pub fn n_frames(&self) -> usize {
self.n_frames
}
pub fn frame(&self, i: usize) -> &[f64] {
assert!(
i < self.n_frames,
"frame index {} out of bounds for {} frames",
i,
self.n_frames
);
let start = i * self.hop_length;
&self.data[start..start + self.frame_length]
}
}
impl<'a> Iterator for FrameIter<'a> {
type Item = &'a [f64];
fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.n_frames {
return None;
}
let start = self.current * self.hop_length;
self.current += 1;
Some(&self.data[start..start + self.frame_length])
}
fn size_hint(&self) -> (usize, Option<usize>) {
let rem = self.n_frames - self.current;
(rem, Some(rem))
}
}
impl ExactSizeIterator for FrameIter<'_> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_framing() {
let data: Vec<f64> = (0..10).map(|i| i as f64).collect();
let iter = FrameIter::new(&data, 4, 2);
assert_eq!(iter.n_frames(), 4);
let frames: Vec<&[f64]> = iter.collect();
assert_eq!(frames.len(), 4);
assert_eq!(frames[0], &[0.0, 1.0, 2.0, 3.0]);
assert_eq!(frames[1], &[2.0, 3.0, 4.0, 5.0]);
assert_eq!(frames[2], &[4.0, 5.0, 6.0, 7.0]);
assert_eq!(frames[3], &[6.0, 7.0, 8.0, 9.0]);
}
#[test]
fn test_frame_equals_data_length() {
let data = vec![1.0, 2.0, 3.0, 4.0];
let iter = FrameIter::new(&data, 4, 1);
assert_eq!(iter.n_frames(), 1);
let frames: Vec<&[f64]> = iter.collect();
assert_eq!(frames[0], &[1.0, 2.0, 3.0, 4.0]);
}
#[test]
fn test_data_shorter_than_frame() {
let data = vec![1.0, 2.0];
let iter = FrameIter::new(&data, 4, 1);
assert_eq!(iter.n_frames(), 0);
assert_eq!(iter.count(), 0);
}
#[test]
fn test_hop_length_one() {
let data: Vec<f64> = (0..6).map(|i| i as f64).collect();
let iter = FrameIter::new(&data, 3, 1);
assert_eq!(iter.n_frames(), 4);
}
#[test]
fn test_iterator_count_matches_n_frames() {
let data: Vec<f64> = (0..20).map(|i| i as f64).collect();
let iter = FrameIter::new(&data, 5, 3);
let n = iter.n_frames();
assert_eq!(iter.count(), n);
}
#[test]
fn test_random_access_matches_sequential() {
let data: Vec<f64> = (0..15).map(|i| i as f64).collect();
let iter = FrameIter::new(&data, 4, 2);
let n = iter.n_frames();
let sequential: Vec<Vec<f64>> = FrameIter::new(&data, 4, 2).map(|f| f.to_vec()).collect();
for i in 0..n {
let random = iter.frame(i);
assert_eq!(random, sequential[i].as_slice());
}
}
#[test]
fn test_size_hint_exact() {
let data: Vec<f64> = (0..10).map(|i| i as f64).collect();
let mut iter = FrameIter::new(&data, 4, 2);
assert_eq!(iter.len(), 4);
iter.next();
assert_eq!(iter.len(), 3);
iter.next();
assert_eq!(iter.len(), 2);
}
}