//! This module provide signal generators. //! //! # Examples //! //! ## Create some white noise and print it. //! //! ``` //! let mut wn = Siggen::newWhiteNoise(); //! wn.setGain(0.1); //! wn.setMute(false); //! let mut sig = [0. ; 1024]; //! wn.genSignal(&mut sig); //! println!("{:?}", &sig); //! //! ``` use super::config::*; use super::filter::Filter; use pyo3::prelude::*; use rand::prelude::*; use rand::rngs::ThreadRng; use rand_distr::StandardNormal; trait Source: Send { /// Generate the 'pure' source signal. Output is placed inside the `sig` argument. fn genSignal_unscaled(&mut self, sig: &mut [Flt]); /// Reset the source state, i.e. set phase to 0, etc fn reset(&mut self, fs: Flt); /// Used to make the Siggen struct cloneable fn clone_dyn(&self) -> Box; } impl Clone for Box { fn clone(&self) -> Self { self.clone_dyn() } } /// White noise source #[derive(Clone)] struct WhiteNoise {} impl WhiteNoise { /// Generate new WhiteNoise generator fn new() -> WhiteNoise { WhiteNoise {} } } impl Source for WhiteNoise { fn genSignal_unscaled(&mut self, sig: &mut [Flt]) { sig.iter_mut() .for_each(|s| *s = thread_rng().sample(StandardNormal)); } fn reset(&mut self, _fs: Flt) {} fn clone_dyn(&self) -> Box { Box::new(self.clone()) } } /// Sine wave, with configurable frequency #[derive(Clone)] struct Sine { // Sampling freq [Hz] fs: Flt, // current stored phase phase: Flt, // Signal frequency [rad/s] omg: Flt, } impl Sine { /// Create new sine source signal /// /// Args: /// /// * fs: Sampling freq [Hz] /// * fn new(freq: Flt) -> Sine { Sine { fs: -1., phase: 0., omg: 2. * pi * freq, } } } impl Source for Sine { fn genSignal_unscaled(&mut self, sig: &mut [Flt]) { if self.fs < 0. { sig.iter_mut().for_each(|s| { *s = 0.; }); return; } sig.iter_mut().for_each(|s| { *s = Flt::sin(self.phase); self.phase += self.omg / self.fs; }); while self.phase > 2. * pi { self.phase -= 2. * pi; } } fn reset(&mut self, fs: Flt) { self.fs = fs; self.phase = 0.; } fn clone_dyn(&self) -> Box { Box::new(self.clone()) } } /// Sweep signal #[derive(Clone)] /// Signal generator. Able to create acoustic output signals pub struct Siggen { // The source dynamic signal. Noise, a sine wave, sweep, etc source: Box, // Filter applied to the source signal prefilter: Option>, // If set, no dynamic signal source output is given muted: bool, gain: Flt, DCOffset: Flt, } /// A struct that implements the Siggen trait is able to generate a signal. impl Siggen { /// Set new pre-filter that filters the source signal pub fn setPreFilter(&mut self, pref: Option>) { self.prefilter = pref.clone(); } /// Set the gain applied to the source signal /// /// * g: Gain value. Can be any float. If set to 0.0, the source is effectively muted. Only /// using (setMute) is a more efficient way to do this. pub fn setGain(&mut self, g: Flt) { self.gain = g; } /// Create a white noise signal generator. pub fn newWhiteNoise() -> Siggen { Siggen::new(Box::new(WhiteNoise::new())) } /// Create a sine wave signal generator /// /// * freq: Frequency of the sine wave in [Hz] pub fn newSineWave(freq: Flt) -> Siggen { Siggen::new(Box::new(Sine::new(freq))) } /// Create a new signal generator wiht an arbitrary source. pub fn new(source: Box) -> Siggen { Siggen { source, prefilter: None, muted: false, gain: 1.0, DCOffset: 0.0, } } /// Generate new signal data. /// /// # Args /// /// sig: Reference of array of float values to be filled with signal data. /// /// # Details /// /// - When muted, the DC offset is still applied /// - The order of the generation is: /// - First, the source is generated. /// - If a prefilter is installed, this pre-filter is applied to the source signal. /// - Gain is applied. /// - Offset is applied (thus, no gain is applied to the DC offset). /// pub fn genSignal(&mut self, sig: &mut [Flt]) { if self.muted { sig.iter_mut().for_each(|x| { *x = 0.0; }); } else { self.source.genSignal_unscaled(sig); if let Some(f) = &mut self.prefilter { f.filter(sig); } } sig.iter_mut().for_each(|x| { // First apply gain, then offset *x *= self.gain; *x += self.DCOffset; }); } /// Reset signal generator. Applies any kind of cleanup necessary. /// /// Args /// /// * fs: (New) Sampling frequency [Hz] /// pub fn reset(&mut self, fs: Flt) { self.source.reset(fs); if let Some(f) = &mut self.prefilter { f.reset(); } } } #[cfg(test)] mod test { use super::*; #[test] fn test_whitenoise() { let mut t = &[0.; 10]; Siggen::newWiteNoise().genSignal(&mut t); println!("{:?}", &t); } }