diff --git a/README.md b/README.md index 07432587..8b6a709c 100644 --- a/README.md +++ b/README.md @@ -50,38 +50,39 @@ let bar: [u8; 2] = foo.map(Sample::to_sample); assert_eq!(bar, [128u8, 128]); ``` -Use the **Signal** trait for working with `Iterator`s that yield `Frame`s. -To complement the `Iterator` trait, **Signal** provides methods for adding, -scaling, offsetting, multiplying, clipping and generating frame iterators and -more. Working with **Signal**s allows for easy, readable creation of rich and -complex DSP graphs with a simple and familiar API. +Use the **Signal** trait for working with infinite-iterator-like types that +yield `Frame`s. **Signal** provides methods for adding, scaling, offsetting, +multiplying, clipping and generating streams of `Frame`s. Working with +**Signal**s allows for easy, readable creation of rich and complex DSP graphs +with a simple and familiar API. ```rust // Clip to an amplitude of 0.9. let frames = [[1.2, 0.8], [-0.7, -1.4]]; -let clipped: Vec<_> = frames.iter().cloned().clip_amp(0.9).collect(); +let clipped: Vec<_> = signal::from_slice(&frames).clip_amp(0.9).take(2).collect(); assert_eq!(clipped, vec![[0.9, 0.8], [-0.7, -0.9]]); // Add `a` with `b` and yield the result. let a = [[0.2], [-0.6], [0.5]]; let b = [[0.2], [0.1], [-0.8]]; -let a_signal = a.iter().cloned(); -let b_signal = b.iter().cloned(); -let added: Vec<[f32; 1]> = a_signal.add_amp(b_signal).collect(); +let a_signal = signal::from_slice(&a); +let b_signal = signal::from_slice(&b); +let added: Vec<[f32; 1]> = a_signal.add_amp(b_signal).take(3).collect(); assert_eq!(added, vec![[0.4], [-0.5], [-0.3]]); // Scale the playback rate by `0.5`. let foo = [[0.0], [1.0], [0.0], [-1.0]]; -let mut source = foo.iter().cloned(); -let interp = Linear::from_source(&mut source).unwrap(); -let frames: Vec<_> = source.scale_hz(interp, 0.5).collect(); +let mut source = signal::from_slice(&foo); +let interp = Linear::from_source(&mut source); +let frames: Vec<_> = source.scale_hz(interp, 0.5).take(8).collect(); assert_eq!(&frames[..], &[[0.0], [0.5], [1.0], [0.5], [0.0], [-0.5], [-1.0], [-0.5]][..]); ``` The **signal** module also provides a series of **Signal** source types, including: -- `FromInterleavedSamples` +- `FromIterator` +- `FromInterleavedSamplesIterator` - `Equilibrium` (silent signal) - `Phase` - `Sine` diff --git a/examples/resample.rs b/examples/resample.rs index 20b6f675..be463817 100644 --- a/examples/resample.rs +++ b/examples/resample.rs @@ -4,7 +4,7 @@ extern crate sample; use hound::{WavReader, WavSpec, WavWriter}; use sample::interpolate::{Sinc, Converter}; -use sample::Sample; +use sample::{signal, Sample, Signal}; fn main() { let assets = find_folder::Search::ParentsThenKids(5, 5).for_folder("assets").unwrap(); @@ -12,11 +12,13 @@ fn main() { let samples: Vec<[f64; 1]> = reader.samples::() .map(|s| [s.unwrap().to_sample()]) .collect(); + let len = samples.len(); + let signal = signal::from_slice(&samples[..]); let sample_rate = reader.spec().sample_rate as f64; let new_sample_rate = 10_000.0; let sinc = Sinc::zero_padded(50); - let conv = Converter::from_hz_to_hz(samples.iter().cloned(), sinc, sample_rate, new_sample_rate); + let conv = Converter::from_hz_to_hz(signal, sinc, sample_rate, new_sample_rate); let spec = WavSpec { channels: 1, @@ -26,7 +28,8 @@ fn main() { }; let mut writer = WavWriter::create(assets.join("two_vowels_10k.wav"), spec).unwrap(); - for f in conv { + let len = (len as f64 * new_sample_rate / sample_rate) as usize; + for f in conv.take(len) { writer.write_sample((f[0].to_sample::())).unwrap(); } } diff --git a/examples/synth.rs b/examples/synth.rs index 0efce67a..c541fb2a 100644 --- a/examples/synth.rs +++ b/examples/synth.rs @@ -1,8 +1,7 @@ extern crate portaudio as pa; extern crate sample; -use sample::{Frame, Sample, Signal, ToFrameSliceMut}; -use sample::signal; +use sample::{signal, Frame, Sample, Signal, ToFrameSliceMut}; const FRAMES_PER_BUFFER: u32 = 512; const NUM_CHANNELS: i32 = 1; @@ -17,13 +16,12 @@ fn run() -> Result<(), pa::Error> { // Create a signal chain to play back 1 second of each oscillator at A4. let hz = signal::rate(SAMPLE_RATE).const_hz(440.0); let one_sec = SAMPLE_RATE as usize; - let mut signal = hz.clone().sine().take(one_sec) + let mut waves = hz.clone().sine().take(one_sec) .chain(hz.clone().saw().take(one_sec)) .chain(hz.clone().square().take(one_sec)) .chain(hz.clone().noise_simplex().take(one_sec)) .chain(signal::noise(0).take(one_sec)) - .map(|f| f.map(|s| s.to_sample::())) - .scale_amp(0.2); + .map(|f| f.map(|s| s.to_sample::() * 0.2)); // Initialise PortAudio. let pa = try!(pa::PortAudio::new()); @@ -35,7 +33,7 @@ fn run() -> Result<(), pa::Error> { let callback = move |pa::OutputStreamCallbackArgs { buffer, .. }| { let buffer: &mut [[f32; 1]] = buffer.to_frame_slice_mut().unwrap(); for out_frame in buffer { - match signal.next() { + match waves.next() { Some(frame) => *out_frame = frame, None => return pa::Complete, } diff --git a/examples/wav.rs b/examples/wav.rs index 5d738620..f3ecdd94 100644 --- a/examples/wav.rs +++ b/examples/wav.rs @@ -63,9 +63,12 @@ fn frames(file_name: &'static str) -> Vec { let sample_file = assets.join(file_name); let mut reader = hound::WavReader::open(&sample_file).unwrap(); let spec = reader.spec(); + let duration = reader.duration(); + let new_duration = (duration as f64 * (SAMPLE_RATE as f64 / spec.sample_rate as f64)) as usize; let samples = reader.samples().map(|s| s.unwrap()); - let mut signal = signal::from_interleaved_samples::<_, wav::Frame>(samples); - let interp = Linear::from_source(&mut signal).unwrap(); + let mut signal = signal::from_interleaved_samples_iter::<_, wav::Frame>(samples); + let interp = Linear::from_source(&mut signal); signal.from_hz_to_hz(interp, spec.sample_rate as f64, SAMPLE_RATE as f64) + .take(new_duration) .collect() } diff --git a/src/interpolate.rs b/src/interpolate.rs index fd62f250..235f0224 100644 --- a/src/interpolate.rs +++ b/src/interpolate.rs @@ -1,6 +1,6 @@ //! The Interpolate module allows for conversion between various sample rates. -use {Duplex, Frame, Sample, VecDeque}; +use {Duplex, Frame, Sample, Signal, VecDeque}; use core::f64::consts::PI; use ops::f64::{sin, cos}; @@ -15,10 +15,11 @@ use ops::f64::{sin, cos}; /// - Sample decimator /// #[derive(Clone)] -pub struct Converter - where ::Item: Frame +pub struct Converter + where S: Signal, + I: Interpolator, { - source: T, + source: S, interpolator: I, interpolation_value: f64, source_to_target_ratio: f64 @@ -28,15 +29,13 @@ pub struct Converter pub struct Floor { left: F, - exhausted: bool } /// Interpolator that interpolates linearly between the previous value and the next value pub struct Linear { left: F, - right: Option, - exhausted: bool + right: F, } /// Interpolator for sinc interpolation. Generally accepted as one of the better sample rate @@ -48,31 +47,29 @@ pub struct Sinc depth: usize, } -/// Trait for all things that can interpolate between two values. Implementations should keep track -/// of the necessary data both before and after the current frame. -pub trait Interpolator -{ +/// Types that can interpolate between two values. +/// +/// Implementations should keep track of the necessary data both before and after the current +/// frame. +pub trait Interpolator { type Frame: Frame; - /// Given a distance between [0. and 1.) to the following sample, return the interpolated value + /// Given a distance between [0.0 and 1.0) to the following sample, return the interpolated + /// value. fn interpolate(&self, x: f64) -> Self::Frame; - /// Called whenever the Interpolator value is over 1. - fn next_source_frame(&mut self, source_frame: Option); - - /// Should indicate whether the Interpolator is out of values. - fn is_exhausted(&self) -> bool; + /// Called whenever the Interpolator value steps passed 1.0. + fn next_source_frame(&mut self, source_frame: Self::Frame); } -impl Converter - where T: Iterator, - ::Item: Frame, +impl Converter + where S: Signal, I: Interpolator { /// Construct a new `Converter` from the source frames and the source and target sample rates /// (in Hz). #[inline] - pub fn from_hz_to_hz(source: T, interpolator: I, source_hz: f64, target_hz: f64) -> Self { + pub fn from_hz_to_hz(source: S, interpolator: I, source_hz: f64, target_hz: f64) -> Self { Self::scale_playback_hz(source, interpolator, source_hz / target_hz) } @@ -83,7 +80,7 @@ impl Converter /// For example, if our `source_frames` is a sine wave oscillating at a frequency of 2hz and /// we wanted to convert it to a frequency of 3hz, the given `scale` should be `1.5`. #[inline] - pub fn scale_playback_hz(source: T, interpolator: I, scale: f64) -> Self { + pub fn scale_playback_hz(source: S, interpolator: I, scale: f64) -> Self { assert!(scale > 0.0, "We can't yield any frames at 0 times a second!"); Converter { source: source, @@ -102,7 +99,7 @@ impl Converter /// /// This is the same as calling `Converter::scale_playback_hz(source_frames, 1.0 / scale)`. #[inline] - pub fn scale_sample_hz(source: T, interpolator: I, scale: f64) -> Self { + pub fn scale_sample_hz(source: S, interpolator: I, scale: f64) -> Self { Self::scale_playback_hz(source, interpolator, 1.0 / scale) } @@ -132,33 +129,32 @@ impl Converter /// Borrow the `source_frames` Interpolator from the `Converter`. #[inline] - pub fn source(&self) -> &T { + pub fn source(&self) -> &S { &self.source } /// Mutably borrow the `source_frames` Iterator from the `Converter`. #[inline] - pub fn source_mut(&mut self) -> &mut T { + pub fn source_mut(&mut self) -> &mut S { &mut self.source } /// Drop `self` and return the internal `source_frames` Iterator. #[inline] - pub fn into_source(self) -> T { + pub fn into_source(self) -> S { self.source } } -impl Iterator for Converter - where T: Iterator, - ::Item: Frame, - I: Interpolator::Item> +impl Signal for Converter + where S: Signal, + I: Interpolator { - type Item = ::Item; + type Frame = S::Frame; - fn next(&mut self) -> Option { + fn next(&mut self) -> Self::Frame { let Converter { - ref mut source, + ref mut source, ref mut interpolator, ref mut interpolation_value, source_to_target_ratio @@ -170,56 +166,36 @@ impl Iterator for Converter *interpolation_value -= 1.0; } - if interpolator.is_exhausted() { - None - } else { - let out = interpolator.interpolate(*interpolation_value); - *interpolation_value += source_to_target_ratio; - Some(out) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len_multiplier = self.source_to_target_ratio / 1.0; - let (source_lower, source_upper) = self.source.size_hint(); - let lower = (source_lower as f64 * len_multiplier) as usize; - let upper = source_upper.map(|upper| (upper as f64 * len_multiplier) as usize); - (lower, upper) + let out = interpolator.interpolate(*interpolation_value); + *interpolation_value += source_to_target_ratio; + out } } impl Floor { - /// Create a new Floor Interpolator. + /// Create a new Floor Interpolator. pub fn new(left: F) -> Floor { - Floor { - left: left, - exhausted: false - } + Floor { left: left } } /// Consumes the first value from a given source in order to initialize itself. If the source /// has no values at all, this will return None. - pub fn from_source(source: &mut I) -> Option> - where I: Iterator + pub fn from_source(source: &mut S) -> Floor + where F: Frame, + S: Signal { - source.by_ref().next().map(|left| Floor { - left: left, - exhausted: false - }) + let left = source.next(); + Floor { left: left } } } impl Linear { - /// Create a new Linear Interpolator. - pub fn new(left: F, right: T) -> Linear - where Option: From + /// Create a new Linear Interpolator. + pub fn new(left: F, right: F) -> Linear { - let right = Option::::from(right); Linear { - exhausted: right.is_none(), left: left, right: right } @@ -227,28 +203,28 @@ impl Linear /// Consumes the first value from a given source to initialize itself. If the source has no /// values, this will return None. - pub fn from_source(source: &mut I) -> Option> - where I: Iterator + pub fn from_source(source: &mut S) -> Linear + where F: Frame, + S: Signal, { - source.by_ref().next().map(|left| { - let right = source.by_ref().next(); - Linear { - exhausted: right.is_none(), - left: left, - right: right - } - }) + let left = source.next(); + let right = source.next(); + Linear { + left: left, + right: right + } } } impl Sinc { - /// Create a new Sinc interpolater whose inner queue will be padded with the ghiven frames. - pub fn new(depth: usize, padding: I) -> Self - where I: IntoIterator, + /// Create a new Sinc interpolater whose inner queue will be padded with the given signal. + pub fn new(depth: usize, padding: S) -> Self + where F: Frame, + S: Signal, { let mut queue = VecDeque::with_capacity(depth * 2 + 1); - for v in padding.into_iter().take(depth) { + for v in padding.take(depth) { queue.push_back(v); } @@ -290,15 +266,8 @@ impl Interpolator for Floor self.left } - fn next_source_frame(&mut self, source_frame: Option) { - match source_frame { - Some(f) => { self.left = f; }, - None => { self.exhausted = true; } - } - } - - fn is_exhausted(&self) -> bool { - self.exhausted + fn next_source_frame(&mut self, source_frame: Self::Frame) { + self.left = source_frame; } } @@ -312,7 +281,7 @@ impl Interpolator for Linear /// possible, although not advisable, to provide an x > 1.0 or < 0.0, but this will just /// continue to be a linear ramp in one direction or another. fn interpolate(&self, x: f64) -> Self::Frame { - self.left.zip_map(self.right.unwrap_or(Self::Frame::equilibrium()), |l, r| { + self.left.zip_map(self.right, |l, r| { let l_f = l.to_sample::(); let r_f = r.to_sample::(); let diff = r_f - l_f; @@ -320,17 +289,10 @@ impl Interpolator for Linear }) } - fn next_source_frame(&mut self, source_frame: Option) { - match self.right { - Some(f) => { self.left = f; }, - None => { self.exhausted = true; } - } + fn next_source_frame(&mut self, source_frame: Self::Frame) { + self.left = self.right; self.right = source_frame; } - - fn is_exhausted(&self) -> bool { - self.exhausted - } } impl Interpolator for Sinc @@ -349,7 +311,7 @@ impl Interpolator for Sinc let rightmost = nl + self.depth; let leftmost = nr as isize - self.depth as isize; let max_depth = if rightmost >= self.frames.len() { - self.frames.len() - self.depth + self.frames.len() - self.depth } else if leftmost < 0 { (self.depth as isize + leftmost) as usize } else { @@ -379,26 +341,16 @@ impl Interpolator for Sinc }) } - fn next_source_frame(&mut self, source_frame: Option) { - match source_frame { - Some(f) => { - if self.frames.len() == self.max_n() { - // make room if necessary - self.frames.pop_front(); - } - - self.frames.push_back(f); - if self.idx < self.depth { - self.idx += 1; - } - }, - None => { self.frames.pop_front(); }, + fn next_source_frame(&mut self, source_frame: F) { + if self.frames.len() == self.max_n() { + // make room if necessary + self.frames.pop_front(); } - } - fn is_exhausted(&self) -> bool { - self.frames.len() <= (self.depth + 1) - && self.idx == self.depth + self.frames.push_back(source_frame); + if self.idx < self.depth { + self.idx += 1; + } } } diff --git a/src/signal.rs b/src/signal.rs index fdb7505c..8cbdca18 100644 --- a/src/signal.rs +++ b/src/signal.rs @@ -13,8 +13,10 @@ //! - [noise_simplex](./fn.noise_simplex.html) for generating a 1D simplex noise waveform. //! - [gen](./fn.gen.html) for generating frames of type F from some `Fn() -> F`. //! - [gen_mut](./fn.gen_mut.html) for generating frames of type F from some `FnMut() -> F`. -//! - [from_interleaved_samples](./fn.from_interleaved_samples.html) for converting an iterator yielding samples to an -//! iterator yielding frames. +//! - [from_iter](./fn.from_iter.html) for converting an iterator yielding frames to a signal. +//! - [from_slice](./fn.from_slice.html) for converting a slice of frames into a signal. +//! - [from_interleaved_samples_iter](./fn.from_interleaved_samples_iter.html) for converting an +//! iterator yielding interleaved samples to a signal. //! //! Working with **Signal**s allows for easy, readable creation of rich and complex DSP graphs with //! a simple and familiar API. @@ -24,19 +26,32 @@ use interpolate::{Converter, Interpolator}; use core; -/// Implement `Signal` for all `Iterator`s that yield `Frame`s. -impl Signal for I where I: Iterator, I::Item: Frame {} - -/// A trait that allows us to treat `Iterator`s that yield `Frame`s as a multi-channel PCM signal. +/// Types that yield `Frame`s as a multi-channel PCM signal. /// /// For example, `Signal` allows us to add two signals, modulate a signal's amplitude by another /// signal, scale a signals amplitude and much more. -/// -/// `Signal` has a blanket implementation for all `Iterator`s whose `Item` associated types -/// implement `Frame`. -pub trait Signal: Iterator + Sized - where Self::Item: Frame, -{ +pub trait Signal { + /// The `Frame` type returned by the `Signal`. + type Frame: Frame; + + /// Yield the next `Frame` in the `Signal`. + /// + /// # Example + /// + /// ```rust + /// extern crate sample; + /// + /// use sample::{signal, Signal}; + /// + /// fn main() { + /// let frames = [[0.2], [-0.6], [0.4]]; + /// let mut signal = signal::from_slice(&frames); + /// assert_eq!(signal.next(), [0.2]); + /// assert_eq!(signal.next(), [-0.6]); + /// assert_eq!(signal.next(), [0.4]); + /// } + /// ``` + fn next(&mut self) -> Self::Frame; /// Provides an iterator that yields the sum of the frames yielded by both `other` and `self` /// in lock-step. @@ -46,22 +61,23 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { - /// let a = [[0.2], [-0.6], [0.5]]; + /// let a = [[0.2], [-0.6], [0.4]]; /// let b = [[0.2], [0.1], [-0.8]]; - /// let a_signal = a.iter().cloned(); - /// let b_signal = b.iter().cloned(); - /// let added: Vec<[f32; 1]> = a_signal.add_amp(b_signal).collect(); - /// assert_eq!(added, vec![[0.4], [-0.5], [-0.3]]); + /// let a_signal = signal::from_slice(&a); + /// let b_signal = signal::from_slice(&b); + /// let added: Vec<_> = a_signal.add_amp(b_signal).take(3).collect(); + /// assert_eq!(added, vec![[0.4], [-0.5], [-0.4]]); /// } /// ``` #[inline] fn add_amp(self, other: S) -> AddAmp - where S: Signal, - S::Item: Frame::Sample as Sample>::Signed, - NumChannels=::NumChannels>, + where Self: Sized, + S: Signal, + S::Frame: Frame::Sample as Sample>::Signed, + NumChannels=::NumChannels>, { AddAmp { a: self, @@ -77,22 +93,23 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let a = [[0.25], [-0.8], [-0.5]]; /// let b = [[0.2], [0.5], [0.8]]; - /// let a_signal = a.iter().cloned(); - /// let b_signal = b.iter().cloned(); - /// let added: Vec<_> = a_signal.mul_amp(b_signal).collect(); + /// let a_signal = signal::from_slice(&a); + /// let b_signal = signal::from_slice(&b); + /// let added: Vec<_> = a_signal.mul_amp(b_signal).take(3).collect(); /// assert_eq!(added, vec![[0.05], [-0.4], [-0.4]]); /// } /// ``` #[inline] fn mul_amp(self, other: S) -> MulAmp - where S: Signal, - S::Item: Frame::Sample as Sample>::Float, - NumChannels=::NumChannels>, + where Self: Sized, + S: Signal, + S::Frame: Frame::Sample as Sample>::Float, + NumChannels=::NumChannels>, { MulAmp { a: self, @@ -108,18 +125,19 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[0.25, 0.4], [-0.2, -0.5]]; - /// let signal = frames.iter().cloned(); - /// let offset: Vec<[f32; 2]> = signal.offset_amp(0.5).collect(); + /// let signal = signal::from_slice(&frames); + /// let offset: Vec<_> = signal.offset_amp(0.5).take(2).collect(); /// assert_eq!(offset, vec![[0.75, 0.9], [0.3, 0.0]]); /// } /// ``` #[inline] - fn offset_amp(self, offset: <::Sample as Sample>::Signed) + fn offset_amp(self, offset: <::Sample as Sample>::Signed) -> OffsetAmp + where Self: Sized, { OffsetAmp { signal: self, @@ -135,24 +153,26 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[0.2], [-0.5], [-0.4], [0.3]]; - /// let signal = frames.iter().cloned(); - /// let scaled: Vec<[f32; 1]> = signal.scale_amp(2.0).collect(); + /// let signal = signal::from_slice(&frames); + /// let scaled: Vec<_> = signal.scale_amp(2.0).take(4).collect(); /// assert_eq!(scaled, vec![[0.4], [-1.0], [-0.8], [0.6]]); /// } /// ``` #[inline] - fn scale_amp(self, amp: <::Sample as Sample>::Float) -> ScaleAmp { + fn scale_amp(self, amp: <::Sample as Sample>::Float) -> ScaleAmp + where Self: Sized, + { ScaleAmp { signal: self, amp: amp, } } - /// Produces an `Iterator` that offsets the amplitude of every `Frame` in `self` by the + /// Produces a new `Signal` that offsets the amplitude of every `Frame` in `self` by the /// respective amplitudes in each channel of the given `amp_frame`. /// /// # Example @@ -160,19 +180,20 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[0.5, 0.3], [-0.25, 0.9]]; - /// let mut signal = frames.iter().cloned().offset_amp_per_channel([0.25, -0.5]); - /// assert_eq!(signal.next().unwrap(), [0.75, -0.2]); - /// assert_eq!(signal.next().unwrap(), [0.0, 0.4]); + /// let signal = signal::from_slice(&frames); + /// let offset: Vec<_> = signal.offset_amp_per_channel([0.25, -0.5]).take(2).collect(); + /// assert_eq!(offset, vec![[0.75, -0.2], [0.0, 0.4]]); /// } /// ``` #[inline] fn offset_amp_per_channel(self, amp_frame: F) -> OffsetAmpPerChannel - where F: Frame::Sample as Sample>::Signed, - NumChannels=::NumChannels>, + where Self: Sized, + F: Frame::Sample as Sample>::Signed, + NumChannels=::NumChannels>, { OffsetAmpPerChannel { signal: self, @@ -180,7 +201,7 @@ pub trait Signal: Iterator + Sized } } - /// Produces an `Iterator` that scales the amplitude of every `Frame` in `self` by the + /// Produces a new `Signal` that scales the amplitude of every `Frame` in `self` by the /// respective amplitudes in each channel of the given `amp_frame`. /// /// # Example @@ -188,19 +209,20 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[0.2, -0.5], [-0.4, 0.3]]; - /// let mut signal = frames.iter().cloned().scale_amp_per_channel([0.5, 2.0]); - /// assert_eq!(signal.next().unwrap(), [0.1, -1.0]); - /// assert_eq!(signal.next().unwrap(), [-0.2, 0.6]); + /// let signal = signal::from_slice(&frames); + /// let scaled: Vec<_> = signal.scale_amp_per_channel([0.5, 2.0]).take(2).collect(); + /// assert_eq!(scaled, vec![[0.1, -1.0], [-0.2, 0.6]]); /// } /// ``` #[inline] fn scale_amp_per_channel(self, amp_frame: F) -> ScaleAmpPerChannel - where F: Frame::Sample as Sample>::Float, - NumChannels=::NumChannels>, + where Self: Sized, + F: Frame::Sample as Sample>::Float, + NumChannels=::NumChannels>, { ScaleAmpPerChannel { signal: self, @@ -211,27 +233,28 @@ pub trait Signal: Iterator + Sized /// Multiplies the rate at which frames of `self` are yielded by the given `signal`. /// /// This happens by wrapping `self` in a `rate::Converter` and calling `set_playback_hz_scale` - /// with the value yielded by `signal` + /// with each value yielded by `signal` /// /// # Example /// /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// use sample::interpolate::Linear; /// /// fn main() { /// let foo = [[0.0], [1.0], [0.0], [-1.0]]; - /// let mul = [1.0, 1.0, 0.5, 0.5, 0.5, 0.5]; - /// let mut source = foo.iter().cloned(); - /// let interp = Linear::from_source(&mut source).unwrap(); - /// let frames: Vec<_> = source.mul_hz(interp, mul.iter().cloned()).collect(); + /// let mul = [[1.0], [1.0], [0.5], [0.5], [0.5], [0.5]]; + /// let mut source = signal::from_slice(&foo); + /// let interp = Linear::from_source(&mut source); + /// let frames: Vec<_> = source.mul_hz(interp, signal::from_slice(&mul)).take(6).collect(); /// assert_eq!(&frames[..], &[[0.0], [1.0], [0.0], [-0.5], [-1.0], [-0.5]][..]); /// } /// ``` fn mul_hz(self, interpolator: I, mul_per_frame: M) -> MulHz - where M: Iterator, + where Self: Sized, + M: Signal, I: Interpolator, { MulHz { @@ -247,19 +270,20 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// use sample::interpolate::Linear; /// /// fn main() { /// let foo = [[0.0], [1.0], [0.0], [-1.0]]; - /// let mut source = foo.iter().cloned(); - /// let interp = Linear::from_source(&mut source).unwrap(); - /// let frames: Vec<_> = source.from_hz_to_hz(interp, 1.0, 2.0).collect(); + /// let mut source = signal::from_slice(&foo); + /// let interp = Linear::from_source(&mut source); + /// let frames: Vec<_> = source.from_hz_to_hz(interp, 1.0, 2.0).take(8).collect(); /// assert_eq!(&frames[..], &[[0.0], [0.5], [1.0], [0.5], [0.0], [-0.5], [-1.0], [-0.5]][..]); /// } /// ``` fn from_hz_to_hz(self, interpolator: I, source_hz: f64, target_hz: f64) -> Converter - where I: Interpolator, + where Self: Sized, + I: Interpolator, { Converter::from_hz_to_hz(self, interpolator, source_hz, target_hz) } @@ -271,19 +295,20 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// use sample::interpolate::Linear; /// /// fn main() { /// let foo = [[0.0], [1.0], [0.0], [-1.0]]; - /// let mut source = foo.iter().cloned(); - /// let interp = Linear::from_source(&mut source).unwrap(); - /// let frames: Vec<_> = source.scale_hz(interp, 0.5).collect(); + /// let mut source = signal::from_slice(&foo); + /// let interp = Linear::from_source(&mut source); + /// let frames: Vec<_> = source.scale_hz(interp, 0.5).take(8).collect(); /// assert_eq!(&frames[..], &[[0.0], [0.5], [1.0], [0.5], [0.0], [-0.5], [-1.0], [-0.5]][..]); /// } /// ``` fn scale_hz(self, interpolator: I, multi: f64) -> Converter - where I: Interpolator, + where Self: Sized, + I: Interpolator, { Converter::scale_playback_hz(self, interpolator, multi) } @@ -298,40 +323,48 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[0.2], [0.4]]; - /// let delayed: Vec<_> = frames.iter().cloned().delay(2).collect(); + /// let signal = signal::from_slice(&frames); + /// let delayed: Vec<_> = signal.delay(2).take(4).collect(); /// assert_eq!(delayed, vec![[0.0], [0.0], [0.2], [0.4]]); /// } /// ``` - fn delay(self, n_frames: usize) -> Delay { + fn delay(self, n_frames: usize) -> Delay + where Self: Sized, + { Delay { signal: self, n_frames: n_frames, } } - /// Converts a `Iterator` yielding `Frame`s into an `Iterator` yielding `Sample`s. + /// Converts a `Signal` into a type that yields the interleaved `Sample`s. /// /// # Example /// /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[0.1, 0.2], [0.3, 0.4]]; - /// let samples: Vec<_> = frames.iter().cloned().to_samples().collect(); + /// let signal = signal::from_iter(frames.iter().cloned()); + /// let samples = signal.into_interleaved_samples(); + /// let samples: Vec<_> = samples.into_iter().take(4).collect(); /// assert_eq!(samples, vec![0.1, 0.2, 0.3, 0.4]); /// } /// ``` - fn to_samples(self) -> ToSamples { - ToSamples { + fn into_interleaved_samples(mut self) -> IntoInterleavedSamples + where Self: Sized, + { + let first = self.next().channels(); + IntoInterleavedSamples { signal: self, - current_frame: None, + current_frame: first, } } @@ -343,15 +376,18 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[1.2, 0.8], [-0.7, -1.4]]; - /// let clipped: Vec<_> = frames.iter().cloned().clip_amp(0.9).collect(); + /// let signal = signal::from_slice(&frames); + /// let clipped: Vec<_> = signal.clip_amp(0.9).take(2).collect(); /// assert_eq!(clipped, vec![[0.9, 0.8], [-0.7, -0.9]]); /// } /// ``` - fn clip_amp(self, thresh: <::Sample as Sample>::Signed) -> ClipAmp { + fn clip_amp(self, thresh: <::Sample as Sample>::Signed) -> ClipAmp + where Self: Sized, + { ClipAmp { signal: self, thresh: thresh, @@ -367,7 +403,7 @@ pub trait Signal: Iterator + Sized /// /// Note: When using multiple `Output`s in this fashion, you will need to be sure to pull the /// frames from each `Output` in sync (whether per frame or per buffer). This is because when - /// output A requests `Frame`s before output B, those frames mjust remain available for output + /// output A requests `Frame`s before output B, those frames must remain available for output /// B and in turn must be stored in an intermediary ring buffer. /// /// # Example @@ -375,18 +411,21 @@ pub trait Signal: Iterator + Sized /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[0.1], [0.2], [0.3]]; - /// let bus = frames.iter().cloned().bus(); + /// let signal = signal::from_slice(&frames); + /// let bus = signal.bus(); /// let mut a = bus.send(); /// let mut b = bus.send(); - /// assert_eq!(a.collect::>(), vec![[0.1], [0.2], [0.3]]); - /// assert_eq!(b.collect::>(), vec![[0.1], [0.2], [0.3]]); + /// assert_eq!(a.take(3).collect::>(), vec![[0.1], [0.2], [0.3]]); + /// assert_eq!(b.take(3).collect::>(), vec![[0.1], [0.2], [0.3]]); /// } /// ``` - fn bus(self) -> Bus { + fn bus(self) -> Bus + where Self: Sized, + { Bus { node: Rc::new(core::cell::RefCell::new(SharedNode { signal: self, @@ -395,32 +434,67 @@ pub trait Signal: Iterator + Sized } } - /// Pads the `Signal` with the given `frame`. - /// - /// Calling this will return a new `Iterator` that never yields `None`, instead yielding the - /// given `frame` whenever `Self` would return `None`. + /// Converts the `Signal` into an `Iterator` that will yield the given number for `Frame`s + /// before returning `None`. /// /// # Example /// /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { - /// let arr = [[0.25], [0.75], [0.25], [-0.25]]; - /// let signal = arr.iter().cloned(); - /// let padded: Vec<_> = signal.pad_with([0.0]).take(6).collect(); - /// assert_eq!(padded, vec![[0.25], [0.75], [0.25], [-0.25], [0.0], [0.0]]); + /// let frames = [[0.1], [0.2], [0.3], [0.4]]; + /// let mut signal = signal::from_slice(&frames).take(2); + /// assert_eq!(signal.next(), Some([0.1])); + /// assert_eq!(signal.next(), Some([0.2])); + /// assert_eq!(signal.next(), None); /// } /// ``` - fn pad_with(self, frame: Self::Item) -> PadWith { - PadWith { + fn take(self, n: usize) -> Take + where Self: Sized, + { + Take { signal: self, - frame: frame, + n: n, } } + /// Borrows a Signal rather than consuming it. + /// + /// This is useful to allow applying signal adaptors while still retaining ownership of the + /// original signal. + /// + /// # Example + /// + /// ```rust + /// extern crate sample; + /// + /// use sample::{signal, Signal}; + /// + /// fn main() { + /// let frames = [[0], [1], [2], [3], [4]]; + /// let mut signal = signal::from_slice(&frames); + /// assert_eq!(signal.next(), [0]); + /// assert_eq!(signal.by_ref().take(2).collect::>(), vec![[1], [2]]); + /// assert_eq!(signal.next(), [3]); + /// assert_eq!(signal.next(), [4]); + /// } + /// ``` + fn by_ref(&mut self) -> &mut Self { + self + } +} + + +impl<'a, S> Signal for &'a mut S + where S: Signal, +{ + type Frame = S::Frame; + fn next(&mut self) -> Self::Frame { + (**self).next() + } } @@ -447,9 +521,15 @@ pub struct GenMut { frame: core::marker::PhantomData, } +/// A type that wraps an Iterator and provides a `Signal` implementation for it. +#[derive(Clone)] +pub struct FromIterator { + iter: I, +} + /// An iterator that converts an iterator of `Sample`s to an iterator of `Frame`s. #[derive(Clone)] -pub struct FromInterleavedSamples +pub struct FromInterleavedSamplesIterator where I: Iterator, I::Item: Sample, F: Frame, @@ -536,10 +616,9 @@ pub struct MulAmp { #[derive(Clone)] pub struct OffsetAmp where S: Signal, - S::Item: Frame, { signal: S, - offset: <::Sample as Sample>::Signed, + offset: <::Sample as Sample>::Signed, } /// An `Iterator` that scales the amplitude of the sample of each channel in every `Frame` yielded @@ -547,10 +626,9 @@ pub struct OffsetAmp #[derive(Clone)] pub struct ScaleAmp where S: Signal, - S::Item: Frame, { signal: S, - amp: <::Sample as Sample>::Float, + amp: <::Sample as Sample>::Float, } /// An `Iterator` that scales the amplitude of every `Frame` in `self` by the respective amplitudes @@ -576,7 +654,6 @@ pub struct ScaleAmpPerChannel { #[derive(Clone)] pub struct MulHz where S: Signal, - S::Item: Frame, I: Interpolator, { signal: Converter, @@ -593,33 +670,28 @@ pub struct Delay { n_frames: usize, } -/// Converts a `Signal` to an `Iterator` yielding `Sample`s of the signal. -pub struct ToSamples +/// Converts a `Signal` to a type that yields the individual interleaved samples. +pub struct IntoInterleavedSamples where S: Signal, - S::Item: Frame, { signal: S, - current_frame: Option<::Channels>, + current_frame: ::Channels, } -/// Clips samples in each frame yielded by `signal` to the given threshhold amplitude. -#[derive(Clone)] -pub struct ClipAmp +/// Converts the `IntoInterleavedSamples` into an `Iterator` that always returns `Some`. +pub struct IntoInterleavedSamplesIterator where S: Signal, - S::Item: Frame, { - signal: S, - thresh: <::Sample as Sample>::Signed, + samples: IntoInterleavedSamples, } -/// Pads the inner `signal` with the given `frame` instead of returning `None`. +/// Clips samples in each frame yielded by `signal` to the given threshhold amplitude. #[derive(Clone)] -pub struct PadWith +pub struct ClipAmp where S: Signal, - S::Item: Frame, { signal: S, - frame: S::Item, + thresh: <::Sample as Sample>::Signed, } /// A type which allows for `send`ing a single `Signal` to multiple outputs. @@ -627,7 +699,6 @@ pub struct PadWith /// This type manages pub struct Bus where S: Signal, - S::Item: Frame, { node: Rc>>, } @@ -635,10 +706,9 @@ pub struct Bus /// The data shared between each `Output`. struct SharedNode where S: Signal, - S::Item: Frame, { signal: S, - buffers: Vec>, + buffers: Vec>, } /// An output node to which some signal `S` is `Output`ing its frames. @@ -646,12 +716,20 @@ struct SharedNode /// It may be more accurate to say that the `Output` "pull"s frames from the signal. pub struct Output where S: Signal, - S::Item: Frame, { idx: usize, node: Rc>>, } +/// An iterator that yields `n` number of `Frame`s from the inner `signal`. +#[derive(Clone)] +pub struct Take + where S: Signal, +{ + signal: S, + n: usize, +} + ///// Signal Constructors @@ -687,10 +765,13 @@ pub fn equilibrium() -> Equilibrium /// ```rust /// extern crate sample; /// +/// use sample::{signal, Signal}; +/// /// fn main() { -/// let mut frames = sample::signal::gen(|| [0.5]); -/// assert_eq!(frames.next(), Some([0.5])); -/// assert_eq!(frames.next(), Some([0.5])); +/// let mut frames = signal::gen(|| [0.5]); +/// assert_eq!(frames.next(), [0.5]); +/// assert_eq!(frames.next(), [0.5]); +/// assert_eq!(frames.next(), [0.5]); /// } /// ``` pub fn gen(gen: G) -> Gen @@ -711,16 +792,18 @@ pub fn gen(gen: G) -> Gen /// ```rust /// extern crate sample; /// +/// use sample::{signal, Signal}; +/// /// fn main() { /// let mut f = [0.0]; -/// let mut frames = sample::signal::gen_mut(|| { +/// let mut signal = signal::gen_mut(|| { /// let r = f; /// f[0] += 0.1; /// r /// }); -/// assert_eq!(frames.next(), Some([0.0])); -/// assert_eq!(frames.next(), Some([0.1])); -/// assert_eq!(frames.next(), Some([0.2])); +/// assert_eq!(signal.next(), [0.0]); +/// assert_eq!(signal.next(), [0.1]); +/// assert_eq!(signal.next(), [0.2]); /// } /// ``` pub fn gen_mut(gen_mut: G) -> GenMut @@ -734,36 +817,98 @@ pub fn gen_mut(gen_mut: G) -> GenMut } -/// An iterator that converts the given `Iterator` yielding `Sample`s to a `Signal` yielding frames -/// of type `F`. +/// Create a new `Signal` from the given `Frame`-yielding `Iterator`. +/// +/// When the `Iterator` is exhausted, the new `Signal` will yield `F::equilibrium`. +/// +/// # Example +/// +/// ```rust +/// extern crate sample; +/// +/// use sample::{signal, Signal}; +/// +/// fn main() { +/// let frames = [[1], [-3], [5], [6]]; +/// let mut signal = signal::from_iter(frames.iter().cloned()); +/// assert_eq!(signal.next(), [1]); +/// assert_eq!(signal.next(), [-3]); +/// assert_eq!(signal.next(), [5]); +/// assert_eq!(signal.next(), [6]); +/// assert_eq!(signal.next(), [0]); +/// } +/// ``` +pub fn from_iter(frames: I) -> FromIterator + where I: IntoIterator, + I::Item: Frame, +{ + FromIterator { + iter: frames.into_iter(), + } +} + + +/// Create a new `Signal` from the given slice of `Frame`s. +/// +/// When the given slice is exhausted, the new `Signal` will yield `F::equilibrium`. +/// +/// # Example +/// +/// ```rust +/// extern crate sample; +/// +/// use sample::{signal, Signal}; +/// +/// fn main() { +/// let frames = [[1], [-3], [5], [6]]; +/// let mut signal = signal::from_slice(&frames); +/// assert_eq!(signal.next(), [1]); +/// assert_eq!(signal.next(), [-3]); +/// assert_eq!(signal.next(), [5]); +/// assert_eq!(signal.next(), [6]); +/// assert_eq!(signal.next(), [0]); +/// } +/// ``` +pub fn from_slice(frames: &[F]) -> FromIterator>> + where F: Frame, +{ + FromIterator { + iter: frames.iter().cloned(), + } +} + + +/// Create a new `Signal` from the given `Frame`-yielding `Iterator`. +/// +/// When the `Iterator` is exhausted, the new `Signal` will yield `F::equilibrium`. /// /// # Example /// /// ```rust /// extern crate sample; /// -/// use sample::signal; +/// use sample::{signal, Signal}; /// /// fn main() { /// let foo = [0, 1, 2, 3]; -/// let mut signal = signal::from_interleaved_samples::<_, [i32; 2]>(foo.iter().cloned()); -/// assert_eq!(signal.next(), Some([0, 1])); -/// assert_eq!(signal.next(), Some([2, 3])); -/// assert_eq!(signal.next(), None); +/// let mut signal = signal::from_interleaved_samples_iter::<_, [i32; 2]>(foo.iter().cloned()); +/// assert_eq!(signal.next(), [0, 1]); +/// assert_eq!(signal.next(), [2, 3]); +/// assert_eq!(signal.next(), [0, 0]); /// /// let bar = [0, 1, 2]; -/// let mut signal = signal::from_interleaved_samples::<_, [i32; 2]>(bar.iter().cloned()); -/// assert_eq!(signal.next(), Some([0, 1])); -/// assert_eq!(signal.next(), None); +/// let mut signal = signal::from_interleaved_samples_iter::<_, [i32; 2]>(bar.iter().cloned()); +/// assert_eq!(signal.next(), [0, 1]); +/// assert_eq!(signal.next(), [0, 0]); /// } /// ``` -pub fn from_interleaved_samples(samples: I) -> FromInterleavedSamples - where I: Iterator, +pub fn from_interleaved_samples_iter(samples: I) -> FromInterleavedSamplesIterator + where I: IntoIterator, I::Item: Sample, F: Frame, { - FromInterleavedSamples { - samples: samples, + FromInterleavedSamplesIterator { + samples: samples.into_iter(), frame: core::marker::PhantomData, } } @@ -776,18 +921,18 @@ pub fn from_interleaved_samples(samples: I) -> FromInterleavedSamples(step: S) -> Phase @@ -805,7 +950,6 @@ pub fn phase(step: S) -> Phase /// /// This is necessary for composing `Hz` or `ConstHz`, both of which may be used to step forward /// the `Phase` for some kind of oscillator (i.e. `Sine`, `Saw`, `Square` or `NoiseSimplex`). -/// ``` pub fn rate(hz: f64) -> Rate { Rate { hz: hz } } @@ -818,15 +962,15 @@ pub fn rate(hz: f64) -> Rate { /// ```rust /// extern crate sample; /// -/// use sample::signal; +/// use sample::{signal, Signal}; /// /// fn main() { /// // Generates a sine wave signal at 1hz to be sampled 4 times per second. /// let mut signal = signal::rate(4.0).const_hz(1.0).sine(); -/// assert_eq!(signal.next(), Some([0.0])); -/// assert_eq!(signal.next(), Some([1.0])); +/// assert_eq!(signal.next(), [0.0]); +/// assert_eq!(signal.next(), [1.0]); /// signal.next(); -/// assert_eq!(signal.next(), Some([-1.0])); +/// assert_eq!(signal.next(), [-1.0]); /// } /// ``` pub fn sine(phase: Phase) -> Sine { @@ -840,15 +984,15 @@ pub fn sine(phase: Phase) -> Sine { /// ```rust /// extern crate sample; /// -/// use sample::signal; +/// use sample::{signal, Signal}; /// /// fn main() { /// // Generates a saw wave signal at 1hz to be sampled 4 times per second. /// let mut signal = signal::rate(4.0).const_hz(1.0).saw(); -/// assert_eq!(signal.next(), Some([1.0])); -/// assert_eq!(signal.next(), Some([0.5])); -/// assert_eq!(signal.next(), Some([0.0])); -/// assert_eq!(signal.next(), Some([-0.5])); +/// assert_eq!(signal.next(), [1.0]); +/// assert_eq!(signal.next(), [0.5]); +/// assert_eq!(signal.next(), [0.0]); +/// assert_eq!(signal.next(), [-0.5]); /// } /// ``` pub fn saw(phase: Phase) -> Saw { @@ -862,15 +1006,15 @@ pub fn saw(phase: Phase) -> Saw { /// ```rust /// extern crate sample; /// -/// use sample::signal; +/// use sample::{signal, Signal}; /// /// fn main() { /// // Generates a square wave signal at 1hz to be sampled 4 times per second. /// let mut signal = signal::rate(4.0).const_hz(1.0).square(); -/// assert_eq!(signal.next(), Some([1.0])); -/// assert_eq!(signal.next(), Some([1.0])); -/// assert_eq!(signal.next(), Some([-1.0])); -/// assert_eq!(signal.next(), Some([-1.0])); +/// assert_eq!(signal.next(), [1.0]); +/// assert_eq!(signal.next(), [1.0]); +/// assert_eq!(signal.next(), [-1.0]); +/// assert_eq!(signal.next(), [-1.0]); /// } /// ``` pub fn square(phase: Phase) -> Square { @@ -884,6 +1028,8 @@ pub fn square(phase: Phase) -> Square { /// ```rust /// extern crate sample; /// +/// use sample::{signal, Signal}; +/// /// fn main() { /// let mut noise = sample::signal::noise(0); /// for n in noise.take(1_000_000) { @@ -904,7 +1050,7 @@ pub fn noise(seed: u64) -> Noise { /// ```rust /// extern crate sample; /// -/// use sample::signal; +/// use sample::{signal, Signal}; /// /// fn main() { /// // Creates a simplex noise signal oscillating at 440hz sampled 44_100 times per second. @@ -922,63 +1068,138 @@ pub fn noise_simplex(phase: Phase) -> NoiseSimplex { //// Trait Implementations for Signal Types. -impl Iterator for Equilibrium - where F: Frame, +impl Signal for FromIterator + where I: Iterator, + I::Item: Frame, { - type Item = F; + type Frame = I::Item; #[inline] - fn next(&mut self) -> Option { - Some(F::equilibrium()) + fn next(&mut self) -> Self::Frame { + match self.iter.next() { + Some(frame) => frame, + None => Self::Frame::equilibrium(), + } } } -impl DoubleEndedIterator for Equilibrium + +impl Signal for FromInterleavedSamplesIterator + where I: Iterator, + I::Item: Sample, + F: Frame, +{ + type Frame = F; + #[inline] + fn next(&mut self) -> Self::Frame { + F::from_samples(&mut self.samples).unwrap_or(F::equilibrium()) + } +} + + +impl Signal for Equilibrium where F: Frame, { + type Frame = F; #[inline] - fn next_back(&mut self) -> Option { - Some(F::equilibrium()) + fn next(&mut self) -> Self::Frame { + F::equilibrium() } } -impl Iterator for Gen +impl Signal for Gen where G: Fn() -> F, + F: Frame, { - type Item = F; + type Frame = F; #[inline] - fn next(&mut self) -> Option { - Some((self.gen)()) + fn next(&mut self) -> Self::Frame { + (self.gen)() } } -impl Iterator for GenMut +impl Signal for GenMut where G: FnMut() -> F, + F: Frame, { - type Item = F; + type Frame = F; #[inline] - fn next(&mut self) -> Option { - Some((self.gen_mut)()) + fn next(&mut self) -> Self::Frame { + (self.gen_mut)() } } -impl Iterator for FromInterleavedSamples - where I: Iterator, - I::Item: Sample, - F: Frame, +impl Signal for Hz + where S: Signal, { - type Item = F; + type Frame = [f64; 1]; #[inline] - fn next(&mut self) -> Option { - F::from_samples(&mut self.samples) + fn next(&mut self) -> Self::Frame { + [self.step()] } } -impl Rate { +impl Signal for ConstHz { + type Frame = [f64; 1]; + #[inline] + fn next(&mut self) -> Self::Frame { + [self.step()] + } +} + + +impl Signal for Phase + where S: Step, +{ + type Frame = [f64; 1]; + #[inline] + fn next(&mut self) -> Self::Frame { + [self.next_phase()] + } +} + +impl Signal for Sine + where S: Step, +{ + type Frame = [f64; 1]; + #[inline] + fn next(&mut self) -> Self::Frame { + const PI_2: f64 = core::f64::consts::PI * 2.0; + let phase = self.phase.next_phase(); + [super::ops::f64::sin(PI_2 * phase)] + } +} + + +impl Signal for Saw + where S: Step, +{ + type Frame = [f64; 1]; + #[inline] + fn next(&mut self) -> Self::Frame { + let phase = self.phase.next_phase(); + [phase * -2.0 + 1.0] + } +} + + +impl Signal for Square + where S: Step, +{ + type Frame = [f64; 1]; + #[inline] + fn next(&mut self) -> Self::Frame { + let phase = self.phase.next_phase(); + [if phase < 0.5 { 1.0 } else { -1.0 }] + } +} + + +impl Rate { /// Create a `ConstHz` iterator which consistently yields "hz / rate". pub fn const_hz(self, hz: f64) -> ConstHz { ConstHz { step: hz / self.hz } @@ -996,13 +1217,11 @@ impl Rate { rate: self, } } - } -impl Hz - where I: Iterator, +impl Hz + where S: Signal, { - /// Construct a `Phase` iterator that, for every `hz` yielded by `self`, yields a phase that is /// stepped by `hz / self.rate.hz`. #[inline] @@ -1033,11 +1252,9 @@ impl Hz pub fn noise_simplex(self) -> NoiseSimplex { self.phase().noise_simplex() } - } impl ConstHz { - /// Construct a `Phase` iterator that is incremented via the constant step size, `self.step`. #[inline] pub fn phase(self) -> Phase { @@ -1067,7 +1284,6 @@ impl ConstHz { pub fn noise_simplex(self) -> NoiseSimplex { self.phase().noise_simplex() } - } /// Types that may be used to give a phase step size based on some `hz / sample rate`. @@ -1090,18 +1306,14 @@ impl Step for ConstHz { } } -impl Step for Hz - where I: Iterator, +impl Step for Hz + where S: Signal, { #[inline] fn step(&mut self) -> f64 { - match self.hz.next() { - Some(hz) => { - self.last_step_size = hz / self.rate.hz; - hz - }, - None => self.last_step_size, - } + let hz = self.hz.next()[0]; + self.last_step_size = hz / self.rate.hz; + hz } } @@ -1109,7 +1321,6 @@ impl Step for Hz impl Phase where S: Step, { - /// Before yielding the current phase, the internal phase is stepped forward and wrapped via /// the given value. #[inline] @@ -1148,75 +1359,6 @@ impl Phase pub fn noise_simplex(self) -> NoiseSimplex { noise_simplex(self) } - -} - - -impl Iterator for Hz - where I: Iterator, -{ - type Item = f64; - #[inline] - fn next(&mut self) -> Option { - Some(self.step()) - } -} - - -impl Iterator for ConstHz { - type Item = f64; - #[inline] - fn next(&mut self) -> Option { - Some(self.step()) - } -} - - -impl Iterator for Phase - where S: Step, -{ - type Item = [f64; 1]; - #[inline] - fn next(&mut self) -> Option { - Some([self.next_phase()]) - } -} - - -impl Iterator for Sine - where S: Step, -{ - type Item = [f64; 1]; - #[inline] - fn next(&mut self) -> Option { - const PI_2: f64 = core::f64::consts::PI * 2.0; - let phase = self.phase.next_phase(); - Some([super::ops::f64::sin(PI_2 * phase)]) - } -} - - -impl Iterator for Saw - where S: Step, -{ - type Item = [f64; 1]; - #[inline] - fn next(&mut self) -> Option { - let phase = self.phase.next_phase(); - Some([phase * -2.0 + 1.0]) - } -} - - -impl Iterator for Square - where S: Step, -{ - type Item = [f64; 1]; - #[inline] - fn next(&mut self) -> Option { - let phase = self.phase.next_phase(); - Some([if phase < 0.5 { 1.0 } else { -1.0 }]) - } } @@ -1245,11 +1387,11 @@ impl Noise { } } -impl Iterator for Noise { - type Item = [f64; 1]; +impl Signal for Noise { + type Frame = [f64; 1]; #[inline] - fn next(&mut self) -> Option { - Some([self.next_sample()]) + fn next(&mut self) -> Self::Frame { + [self.next_sample()] } } @@ -1340,355 +1482,202 @@ impl NoiseSimplex } } -impl Iterator for NoiseSimplex +impl Signal for NoiseSimplex where S: Step, { - type Item = [f64; 1]; + type Frame = [f64; 1]; #[inline] - fn next(&mut self) -> Option { - Some([self.next_sample()]) + fn next(&mut self) -> Self::Frame { + [self.next_sample()] } } -#[inline] -fn zipped_size_hint(a: &A, b: &B) -> (usize, Option) - where A: Iterator, - B: Iterator, -{ - let (a_lower, a_upper) = a.size_hint(); - let (b_lower, b_upper) = b.size_hint(); - let lower = core::cmp::min(a_lower, b_lower); - let upper = match (a_upper, b_upper) { - (Some(a), Some(b)) => Some(core::cmp::min(a, b)), - (Some(a), None) => Some(a), - (None, Some(b)) => Some(b), - (None, None) => None, - }; - (lower, upper) -} - - -impl Iterator for AddAmp +impl Signal for AddAmp where A: Signal, B: Signal, - A::Item: Frame, - B::Item: Frame::Sample as Sample>::Signed, - NumChannels=::NumChannels>, + B::Frame: Frame::Sample as Sample>::Signed, + NumChannels=::NumChannels>, { - type Item = A::Item; + type Frame = A::Frame; #[inline] - fn next(&mut self) -> Option { - self.a.next().and_then(|a_f| self.b.next().map(|b_f| a_f.add_amp(b_f))) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - zipped_size_hint(&self.a, &self.b) + fn next(&mut self) -> Self::Frame { + self.a.next().add_amp(self.b.next()) } } -impl ExactSizeIterator for AddAmp - where AddAmp: Iterator, - A: ExactSizeIterator, - B: ExactSizeIterator, -{ - #[inline] - fn len(&self) -> usize { - core::cmp::min(self.a.len(), self.b.len()) - } -} - -impl Iterator for MulAmp +impl Signal for MulAmp where A: Signal, B: Signal, - A::Item: Frame, - B::Item: Frame::Sample as Sample>::Float, - NumChannels=::NumChannels>, -{ - type Item = A::Item; - #[inline] - fn next(&mut self) -> Option { - self.a.next().and_then(|a_f| self.b.next().map(|b_f| a_f.mul_amp(b_f))) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - zipped_size_hint(&self.a, &self.b) - } -} - -impl ExactSizeIterator for MulAmp - where MulAmp: Iterator, - A: ExactSizeIterator, - B: ExactSizeIterator, + B::Frame: Frame::Sample as Sample>::Float, + NumChannels=::NumChannels>, { + type Frame = A::Frame; #[inline] - fn len(&self) -> usize { - core::cmp::min(self.a.len(), self.b.len()) + fn next(&mut self) -> Self::Frame { + self.a.next().mul_amp(self.b.next()) } } -impl Iterator for ScaleAmp +impl Signal for ScaleAmp where S: Signal, - S::Item: Frame, { - type Item = S::Item; + type Frame = S::Frame; #[inline] - fn next(&mut self) -> Option { - self.signal.next().map(|f| f.scale_amp(self.amp)) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.signal.size_hint() - } -} - -impl ExactSizeIterator for ScaleAmp - where S: Signal + ExactSizeIterator, - S::Item: Frame, -{ - #[inline] - fn len(&self) -> usize { - self.signal.len() + fn next(&mut self) -> Self::Frame { + self.signal.next().scale_amp(self.amp) } } -impl Iterator for ScaleAmpPerChannel +impl Signal for ScaleAmpPerChannel where S: Signal, - S::Item: Frame, - F: Frame::Sample as Sample>::Float, - NumChannels=::NumChannels>, + F: Frame::Sample as Sample>::Float, + NumChannels=::NumChannels>, { - type Item = S::Item; - #[inline] - fn next(&mut self) -> Option { - self.signal.next().map(|f| f.mul_amp(self.amp_frame)) - } + type Frame = S::Frame; #[inline] - fn size_hint(&self) -> (usize, Option) { - self.signal.size_hint() - } -} - -impl ExactSizeIterator for ScaleAmpPerChannel - where ScaleAmpPerChannel: Iterator, - S: ExactSizeIterator, -{ - #[inline] - fn len(&self) -> usize { - self.signal.len() + fn next(&mut self) -> Self::Frame { + self.signal.next().mul_amp(self.amp_frame) } } -impl Iterator for OffsetAmp +impl Signal for OffsetAmp where S: Signal, - S::Item: Frame, { - type Item = S::Item; + type Frame = S::Frame; #[inline] - fn next(&mut self) -> Option { - self.signal.next().map(|f| f.offset_amp(self.offset)) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.signal.size_hint() - } -} - -impl ExactSizeIterator for OffsetAmp - where S: Signal + ExactSizeIterator, - S::Item: Frame, -{ - #[inline] - fn len(&self) -> usize { - self.signal.len() + fn next(&mut self) -> Self::Frame { + self.signal.next().offset_amp(self.offset) } } -impl Iterator for OffsetAmpPerChannel +impl Signal for OffsetAmpPerChannel where S: Signal, - S::Item: Frame, - F: Frame::Sample as Sample>::Signed, - NumChannels=::NumChannels>, -{ - type Item = S::Item; - #[inline] - fn next(&mut self) -> Option { - self.signal.next().map(|f| f.add_amp(self.amp_frame)) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.signal.size_hint() - } -} - -impl ExactSizeIterator for OffsetAmpPerChannel - where OffsetAmpPerChannel: Iterator, - S: ExactSizeIterator, + F: Frame::Sample as Sample>::Signed, + NumChannels=::NumChannels>, { + type Frame = S::Frame; #[inline] - fn len(&self) -> usize { - self.signal.len() + fn next(&mut self) -> Self::Frame { + self.signal.next().add_amp(self.amp_frame) } } -impl Iterator for MulHz +impl Signal for MulHz where S: Signal, - S::Item: Frame, - ::Sample: Duplex, - M: Iterator, - I: Interpolator::Item>, + ::Sample: Duplex, + M: Signal, + I: Interpolator, { - type Item = S::Item; + type Frame = S::Frame; #[inline] - fn next(&mut self) -> Option { - self.mul_per_frame.next().and_then(|mul| { - self.signal.set_playback_hz_scale(mul); - self.signal.next() - }) - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - // We can't make any guarantees about size here as the rate may change dramatically at any - // point. - (1, None) + fn next(&mut self) -> Self::Frame { + let mul = self.mul_per_frame.next()[0]; + self.signal.set_playback_hz_scale(mul); + self.signal.next() } } -impl Iterator for Delay +impl Signal for Delay where S: Signal, - S::Item: Frame, { - type Item = S::Item; + type Frame = S::Frame; #[inline] - fn next(&mut self) -> Option { + fn next(&mut self) -> Self::Frame { if self.n_frames > 0 { self.n_frames -= 1; - Some(Frame::equilibrium()) + Self::Frame::equilibrium() } else { self.signal.next() } } - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.signal.size_hint(); - (lower + self.n_frames, upper.map(|n| n + self.n_frames)) - } } -impl ExactSizeIterator for Delay - where Delay: Iterator, - S: ExactSizeIterator, + +impl IntoInterleavedSamples + where S: Signal, { + /// Yield the next interleaved sample from the inner `Signal`. #[inline] - fn len(&self) -> usize { - self.signal.len() + self.n_frames + pub fn next_sample(&mut self) -> ::Sample { + loop { + match self.current_frame.next() { + Some(channel) => return channel, + None => self.current_frame = self.signal.next().channels(), + } + } } -} + /// Convert the `ToInterleavedSamples` into an `Iterator`. + #[inline] + pub fn into_iter(self) -> IntoInterleavedSamplesIterator { + IntoInterleavedSamplesIterator { + samples: self, + } + } +} -impl Iterator for ToSamples +impl Iterator for IntoInterleavedSamplesIterator where S: Signal, - S::Item: Frame, { - type Item = ::Sample; + type Item = ::Sample; #[inline] fn next(&mut self) -> Option { - loop { - if let Some(ref mut frame) = self.current_frame { - if let Some(channel) = frame.next() { - return Some(channel); - } - } - self.current_frame = match self.signal.next() { - Some(frame) => Some(frame.channels()), - None => return None, - }; - } + Some(self.samples.next_sample()) } - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.signal.size_hint(); - let current_frame = self.current_frame.as_ref().map(|chans| chans.size_hint()); - let n_channels = ::n_channels(); - let lower = lower * n_channels + current_frame.map(|sh| sh.0).unwrap_or(0); - let upper = upper.and_then(|upper| { - let current_upper = match current_frame.map(|sh| sh.1) { - None => 0, - Some(None) => return None, - Some(Some(n)) => n, - }; - Some(upper * n_channels + current_upper) - }); - (lower, upper) - } -} - -impl Clone for ToSamples +} + +impl Clone for IntoInterleavedSamples where S: Signal + Clone, - S::Item: Frame, - ::Channels: Clone, + ::Channels: Clone, { #[inline] fn clone(&self) -> Self { - ToSamples { + IntoInterleavedSamples { signal: self.signal.clone(), current_frame: self.current_frame.clone(), } } } -impl ExactSizeIterator for ToSamples - where ToSamples: Iterator, - S: ExactSizeIterator, - S::Item: Frame, - ::Channels: ExactSizeIterator, +impl Clone for IntoInterleavedSamplesIterator + where S: Signal, + IntoInterleavedSamples: Clone, { #[inline] - fn len(&self) -> usize { - self.signal.len() * ::n_channels() - + self.current_frame.as_ref().map(|f| f.len()).unwrap_or(0) + fn clone(&self) -> Self { + IntoInterleavedSamplesIterator { + samples: self.samples.clone(), + } } } -impl Iterator for ClipAmp +impl Signal for ClipAmp where S: Signal, - S::Item: Frame, { - type Item = S::Item; + type Frame = S::Frame; #[inline] - fn next(&mut self) -> Option { - self.signal.next().map(|f| f.map(|s| { - let s: <::Sample as Sample>::Signed = s.to_sample(); + fn next(&mut self) -> Self::Frame { + let f = self.signal.next(); + f.map(|s| { + let s: <::Sample as Sample>::Signed = s.to_sample(); if s > self.thresh { self.thresh } else if s < -self.thresh { -self.thresh } else { s } .to_sample() - })) - } -} - - -impl Iterator for PadWith - where S: Signal, - S::Item: Frame, -{ - type Item = S::Item; - #[inline] - fn next(&mut self) -> Option { - Some(self.signal.next().unwrap_or(self.frame)) + }) } } impl Bus where S: Signal, - S::Item: Frame, { /// Produce a new Output node to which the signal `S` will output its frames. #[inline] @@ -1704,25 +1693,21 @@ impl Bus impl SharedNode where S: Signal, - S::Item: Frame, { - /// Requests the next frame for the `Output` whose ring buffer lies at the given index. /// /// If there are no frames waiting in the front of the ring buffer, a new frame will be /// requested from the `signal` and appended to the back of each ring buffer. #[inline] - fn next_frame(&mut self, idx: usize) -> Option { + fn next_frame(&mut self, idx: usize) -> S::Frame { loop { match self.buffers[idx].pop_front() { - Some(frame) => return Some(frame), - None => match self.signal.next() { - Some(frame) => { - for buffer in self.buffers.iter_mut() { - buffer.push_back(frame); - } - }, - None => return None, + Some(frame) => return frame, + None => { + let frame = self.signal.next(); + for buffer in self.buffers.iter_mut() { + buffer.push_back(frame); + } } } } @@ -1732,12 +1717,10 @@ impl SharedNode fn pending_frames(&self, idx: usize) -> usize { self.buffers[idx].len() } - } impl Output where S: Signal, - S::Item: Frame, { /// The number of frames that have been requested from the `Signal` `S` by some other `Output` /// that have not yet been requested by this `Output`. @@ -1750,16 +1733,16 @@ impl Output /// ```rust /// extern crate sample; /// - /// use sample::Signal; + /// use sample::{signal, Signal}; /// /// fn main() { /// let frames = [[0.1], [0.2], [0.3]]; - /// let bus = frames.iter().cloned().bus(); + /// let bus = signal::from_slice(&frames).bus(); /// let mut signal = bus.send(); /// let mut monitor = bus.send(); - /// assert_eq!(signal.collect::>(), vec![[0.1], [0.2], [0.3]]); + /// assert_eq!(signal.take(3).collect::>(), vec![[0.1], [0.2], [0.3]]); /// assert_eq!(monitor.pending_frames(), 3); - /// assert_eq!(monitor.next(), Some([0.1])); + /// assert_eq!(monitor.next(), [0.1]); /// assert_eq!(monitor.pending_frames(), 2); /// } /// ``` @@ -1769,20 +1752,39 @@ impl Output } } -impl Iterator for Output +impl Signal for Output where S: Signal, - S::Item: Frame, { - type Item = S::Item; + type Frame = S::Frame; #[inline] - fn next(&mut self) -> Option { + fn next(&mut self) -> Self::Frame { self.node.borrow_mut().next_frame(self.idx) } +} + + +impl Iterator for Take + where S: Signal, +{ + type Item = S::Frame; #[inline] + fn next(&mut self) -> Option { + if self.n == 0 { + return None; + } + self.n -= 1; + Some(self.signal.next()) + } fn size_hint(&self) -> (usize, Option) { - let node = self.node.borrow(); - let (lower, upper) = node.signal.size_hint(); - let n = node.buffers[self.idx].len(); - (lower + n, upper.map(|upper| upper + n)) + (self.n, Some(self.n)) + } +} + +impl ExactSizeIterator for Take + where S: Signal, +{ + #[inline] + fn len(&self) -> usize { + self.n } } diff --git a/src/window.rs b/src/window.rs index 6a1a850f..7fbe430d 100644 --- a/src/window.rs +++ b/src/window.rs @@ -53,6 +53,18 @@ pub struct Windower<'a, F, W> wttype: PhantomData } +/// An Iterator that multiplies a Signal with a Window. +/// +/// Returns `None` once the `Window` has been exhausted. +#[derive(Clone)] +pub struct Windowed + where S: Signal, + W: Type, +{ + signal: S, + window: Window<::Float, W>, +} + impl Type for Hanning { fn at_phase(phase: S) -> S { @@ -137,7 +149,7 @@ impl<'a, F, W> Iterator for Windower<'a, F, W> where F: 'a + Frame, W: Type { - type Item = signal::MulAmp>, Window>; + type Item = Windowed>>, W>; fn next(&mut self) -> Option { let num_frames = self.frames.len(); @@ -145,7 +157,10 @@ impl<'a, F, W> Iterator for Windower<'a, F, W> 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)) + Some(Windowed { + signal: signal::from_slice(frames), + window: window, + }) } else { None } @@ -169,6 +184,18 @@ impl<'a, F, W> Iterator for Windower<'a, F, W> } } +impl Iterator for Windowed + where S: Signal, + W: Type, +{ + type Item = S::Frame; + fn next(&mut self) -> Option { + self.window.next().map(|w_f| { + let s_f = self.signal.next(); + s_f.mul_amp(w_f) + }) + } +} /// A helper function for constructing a `Window` that uses a `Hanning` `Type` function. pub fn hanning(num_frames: usize) -> Window @@ -183,15 +210,3 @@ pub fn rectangle(num_frames: usize) -> Window { Window::new(num_frames) } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_window_size() { - let v = [[1f32; 1]; 16]; - let windows: Vec> = Windower::hanning(&v[..], 8, 4).map(|i| i.collect::>()).collect(); - assert_eq!(windows.len(), 3); - } -} diff --git a/tests/interpolate.rs b/tests/interpolate.rs index fc374bf8..a5f1602d 100644 --- a/tests/interpolate.rs +++ b/tests/interpolate.rs @@ -3,52 +3,50 @@ extern crate sample; use sample::interpolate::{Converter, Floor, Linear}; -use sample::Signal; +use sample::{signal, Signal}; #[test] fn test_floor_converter() { let frames: [[f64; 1]; 3] = [[0.0], [1.0], [2.0]]; - let mut source = frames.iter().cloned(); - let interp = Floor::from_source(&mut source).unwrap(); + let mut source = signal::from_slice(&frames); + let interp = Floor::from_source(&mut source); let mut conv = Converter::scale_playback_hz(source, interp, 0.5); - assert_eq!(conv.next(), Some([0.0])); - assert_eq!(conv.next(), Some([0.0])); - assert_eq!(conv.next(), Some([1.0])); - assert_eq!(conv.next(), Some([1.0])); + assert_eq!(conv.next(), [0.0]); + assert_eq!(conv.next(), [0.0]); + assert_eq!(conv.next(), [1.0]); + assert_eq!(conv.next(), [1.0]); // It may seem odd that we are emitting two values, but consider this: no matter what the next // value would be, Floor would always yield the same frame until we hit an interpolation_value // of 1.0 and had to advance the frame. We don't know what the future holds, so we should // continue yielding frames. - assert_eq!(conv.next(), Some([2.0])); - assert_eq!(conv.next(), Some([2.0])); - assert_eq!(conv.next(), None); + assert_eq!(conv.next(), [2.0]); + assert_eq!(conv.next(), [2.0]); } #[test] fn test_linear_converter() { let frames: [[f64; 1]; 3] = [[0.0], [1.0], [2.0]]; - let mut source = frames.iter().cloned(); - let interp = Linear::from_source(&mut source).unwrap(); + let mut source = signal::from_slice(&frames); + let interp = Linear::from_source(&mut source); let mut conv = Converter::scale_playback_hz(source, interp, 0.5); - assert_eq!(conv.next(), Some([0.0])); - assert_eq!(conv.next(), Some([0.5])); - assert_eq!(conv.next(), Some([1.0])); - assert_eq!(conv.next(), Some([1.5])); - assert_eq!(conv.next(), Some([2.0])); + assert_eq!(conv.next(), [0.0]); + assert_eq!(conv.next(), [0.5]); + assert_eq!(conv.next(), [1.0]); + assert_eq!(conv.next(), [1.5]); + assert_eq!(conv.next(), [2.0]); // There's nothing else here to interpolate toward, but we do want to ensure that we're // emitting the correct number of frames. - assert_eq!(conv.next(), Some([1.0])); - assert_eq!(conv.next(), None); + assert_eq!(conv.next(), [1.0]); } #[test] fn test_scale_playback_rate() { // Scale the playback rate by `0.5` let foo = [[0.0], [1.0], [0.0], [-1.0]]; - let mut source = foo.iter().cloned(); - let interp = Linear::from_source(&mut source).unwrap(); - let frames: Vec<_> = source.scale_hz(interp, 0.5).collect(); + let mut source = signal::from_slice(&foo); + let interp = Linear::from_source(&mut source); + let frames: Vec<_> = source.scale_hz(interp, 0.5).take(8).collect(); assert_eq!(&frames[..], &[[0.0], [0.5], [1.0], [0.5], [0.0], [-0.5], [-1.0], [-0.5]][..]); } diff --git a/tests/signal.rs b/tests/signal.rs index 8710fe23..a632b381 100644 --- a/tests/signal.rs +++ b/tests/signal.rs @@ -2,7 +2,7 @@ extern crate sample; -use sample::Signal; +use sample::{signal, Signal}; #[test] fn test_equilibrium() { @@ -14,7 +14,7 @@ fn test_equilibrium() { fn test_scale_amp() { let foo = [[0.5], [0.8], [-0.4], [-0.2]]; let amp = 0.5; - let amp_scaled: Vec<_> = foo.iter().cloned().scale_amp(amp).collect(); + let amp_scaled: Vec<_> = signal::from_slice(&foo).scale_amp(amp).take(4).collect(); assert_eq!(amp_scaled, vec![[0.25], [0.4], [-0.2], [-0.1]]); } @@ -22,6 +22,6 @@ fn test_scale_amp() { fn test_offset_amp() { let foo = [[0.5], [0.9], [-0.4], [-0.2]]; let amp = -0.5; - let amp_offset: Vec<_> = foo.iter().cloned().offset_amp(amp).collect(); + let amp_offset: Vec<_> = signal::from_slice(&foo).offset_amp(amp).take(4).collect(); assert_eq!(amp_offset, vec![[0.0], [0.4], [-0.9], [-0.7]]); } diff --git a/tests/window.rs b/tests/window.rs index 7f2932dc..29129c0c 100644 --- a/tests/window.rs +++ b/tests/window.rs @@ -7,7 +7,7 @@ use sample::window::Windower; fn test_window_at_phase() { let window = sample::window::hanning::<[f64; 1]>(9); let expected = [0.0, 0.1464, 0.5000, 0.8536, 1., 0.8536, 0.5000, 0.1464, 0., 0.1464]; - for (r, e) in window.zip(expected.iter()) { + for (r, e) in window.zip(&expected) { println!("Expected: {}\t\tFound: {}", e, r[0]); assert!((r[0] - e).abs() < 0.001); } @@ -18,9 +18,8 @@ fn test_windower() { let data = [[0.1f64], [0.1], [0.2], [0.2], [0.3], [0.3], [0.4], [0.4]]; let expected = [[[0.1], [0.1]], [[0.1], [0.2]], [[0.2], [0.2]], [[0.2], [0.3]], [[0.3], [0.3]], [[0.3], [0.4]], [[0.4], [0.4]]]; - let windower = Windower::rectangle(&data, 2, 1); - for (chunk, expected_chunk) in windower.zip(expected.iter()) { + for (chunk, expected_chunk) in windower.zip(&expected) { for (r, e) in chunk.zip(expected_chunk.iter()) { for (r_chan, e_chan) in r.channels().zip(e.channels()) { println!("Expected: {}\t\tFound: {}", e_chan, r_chan); @@ -29,3 +28,13 @@ fn test_windower() { } } } + +#[test] +fn test_window_size() { + let v = [[1f32; 1]; 16]; + let windows: Vec> = Windower::hanning(&v, 8, 4) + .map(|i| i.take(8).collect::>()) + .take(3) + .collect(); + assert_eq!(windows.len(), 3); +}