use super::source::SourceImpl;
use crate::{config::*, PoleOrZero, SeriesBiquad, TransferFunction, ZPKModel};
use rand::{rngs::SmallRng, Rng, SeedableRng};
use rand_distr::StandardNormal;
const PINKNOISE_ANALOG_ORDER: usize = 10;
#[derive(Clone, Debug)]
pub struct WhiteNoise {
rng: SmallRng,
interrupt_state: Option<InterruptState>,
}
impl WhiteNoise {
pub fn new(fs: Flt, interrupt_period: Option<Flt>) -> Self {
let interrupt_state = if let Some(period) = interrupt_period {
if period > 0. {
Some(InterruptState {
period,
cur_idx: 0,
max_idx: (period * fs) as usize,
silence: false,
})
} else {
None
}
} else {
None
};
WhiteNoise {
rng: SmallRng::from_entropy(),
interrupt_state,
}
}
}
impl SourceImpl for WhiteNoise {
fn genSignal_unscaled(&mut self, sig: &mut dyn ExactSizeIterator<Item = &mut Flt>) {
let mut output = true;
if let Some(InterruptState {
cur_idx,
max_idx,
silence,
..
}) = &mut self.interrupt_state
{
if cur_idx > max_idx {
*cur_idx = 0;
*silence = !*silence;
}
output = !*silence;
*cur_idx += sig.len();
}
if output {
sig.for_each(|s| {
*s = self.rng.sample(StandardNormal);
});
} else {
sig.for_each(|s| {
*s = 0.;
});
}
}
fn reset(&mut self, fs: Flt) {
if let Some(state) = &mut self.interrupt_state {
state.silence = false;
state.cur_idx = 0;
state.max_idx = (state.period * fs) as usize;
}
}
fn clone_dyn(&self) -> Box<dyn SourceImpl> {
Box::new(self.clone())
}
}
#[derive(Debug, Clone)]
pub struct ColoredNoise {
wn: WhiteNoise,
tmp: Vec<Flt>,
analogue_blueprint: ZPKModel,
filter: SeriesBiquad,
}
impl ColoredNoise {
pub fn newPinkNoise(fs: Flt, interrupt_period: Option<Flt>) -> Self {
let twopi = 2. * pi;
let fl = 10.;
let fu = 20e3;
let fpoles_real: Vec<Flt> = (0..PINKNOISE_ANALOG_ORDER)
.map(|i| fl * (fu / fl).powf((i as Flt) / (PINKNOISE_ANALOG_ORDER as Flt - 1.)))
.collect();
let fzeros_real: Vec<Flt> = (0..PINKNOISE_ANALOG_ORDER - 1)
.map(|i| (fpoles_real[i] * fpoles_real[i + 1]).sqrt())
.collect();
let poles: Vec<PoleOrZero> = fpoles_real
.into_iter()
.map(|f| PoleOrZero::Real1(-twopi * f))
.collect();
let zeros: Vec<PoleOrZero> = fzeros_real
.into_iter()
.map(|f| PoleOrZero::Real1(-twopi * f))
.collect();
let gain = 1.;
let analogue_blueprint = ZPKModel::new(zeros, poles, gain);
let filter = analogue_blueprint.bilinear(480000.);
Self {
wn: WhiteNoise::new(fs, interrupt_period),
tmp: vec![],
analogue_blueprint,
filter,
}
}
}
impl SourceImpl for ColoredNoise {
fn genSignal_unscaled(&mut self, sig: &mut dyn ExactSizeIterator<Item = &mut Flt>) {
self.tmp.resize(sig.len(), 0.);
self.wn.genSignal_unscaled(&mut self.tmp.iter_mut());
self.filter.filter_inout(&mut self.tmp);
sig.zip(&self.tmp).for_each(|(sig, src)| {
*sig = *src;
});
}
fn reset(&mut self, fs: Flt) {
self.filter = self.analogue_blueprint.bilinear(fs);
let fnyq = fs / 2.;
let N = 2400;
let freq = Array1::linspace(20., fnyq, 2000);
let tf_power_sum = self
.filter
.tf(fs, freq.view())
.mapv(|t| t.abs().powi(2))
.sum();
let gain = ((N as Flt) / tf_power_sum).sqrt();
self.filter.setGain(gain);
}
fn clone_dyn(&self) -> Box<dyn SourceImpl> {
Box::new(self.clone())
}
}
#[derive(Clone, Copy, Debug)]
struct InterruptState {
period: Flt,
cur_idx: usize,
max_idx: usize,
silence: bool,
}