use super::siggenchannel::SiggenChannelConfig;
use super::source::{self, *};
use super::sweep::SweepType;
use super::SiggenCommand;
use crate::config::*;
use crate::filter::Filter;
use anyhow::{bail, Result};
use dasp_sample::{FromSample, Sample};
use rayon::prelude::*;
use std::fmt::Debug;
use std::iter::ExactSizeIterator;
use std::slice::IterMut;
pub const DUMMY_SAMPLING_FREQ: Flt = 48000.;
#[derive(Clone, Debug)]
#[cfg_attr(feature = "python-bindings", pyclass)]
pub struct Siggen {
fs: Option<Flt>,
source: Source,
channels: Vec<SiggenChannelConfig>,
source_buf: Vec<Flt>,
chout_buf: Vec<Vec<Flt>>,
}
#[cfg(feature = "python-bindings")]
#[cfg_attr(feature = "python-bindings", pymethods)]
impl Siggen {
#[new]
fn new_py() -> Self {
Siggen::new(1, Source::newSilence())
}
}
impl Siggen {
pub fn new(nchannels: usize, source: Source) -> Siggen {
Siggen {
fs: None,
source,
channels: vec![SiggenChannelConfig::new(); nchannels],
source_buf: vec![],
chout_buf: vec![],
}
}
pub fn newSweep(
fs: Flt,
nchannels: usize,
fl: Flt,
fu: Flt,
sweep_time: Flt,
quiet_time: Flt,
sweep_type: SweepType,
) -> Result<Self> {
let source = Source::newSweep(fs, fl, fu, sweep_time, quiet_time, sweep_type)?;
Ok(Self::new(nchannels, source))
}
pub fn newSine(fs: Flt, nchannels: usize, freq: Flt) -> Result<Siggen> {
Ok(Siggen::new(nchannels, Source::newSine(fs, freq)?))
}
pub fn newSilence(_fs: Flt, nchannels: usize) -> Siggen {
Siggen::new(nchannels, Source::newSilence())
}
pub fn newWhiteNoise(fs: Flt, nchannels: usize, interrupt_period: Option<Flt>) -> Siggen {
Siggen::new(nchannels, Source::newWhiteNoise(fs, interrupt_period))
}
pub fn nchannels(&self) -> usize {
self.channels.len()
}
pub fn applyCommand(&mut self, msg: SiggenCommand) -> Result<()> {
match msg {
SiggenCommand::ChangeSource { src } => {
self.source = src;
self.reset(self.fs.unwrap_or(48e3));
Ok(())
}
SiggenCommand::ResetSiggen { fs } => {
self.reset(fs);
Ok(())
}
SiggenCommand::SetMuteAllChannels { mute } => {
self.setAllMute(mute);
Ok(())
}
SiggenCommand::SetMuteChannel { ch, mute } => {
if ch > self.channels.len() {
bail!("Invalid channel index: {ch}");
}
self.channels[ch].setMute(mute);
Ok(())
}
SiggenCommand::SetAllGains { g } => {
self.setAllGains(g);
Ok(())
}
}
}
pub fn setAllGains(&mut self, g: Flt) {
self.channels.iter_mut().for_each(|set| set.setGain(g))
}
pub fn setNChannels(&mut self, nch: usize) {
self.channels.truncate(nch);
while self.channels.len() < nch {
self.channels.push(SiggenChannelConfig::new());
}
}
pub fn setDCOffset(&mut self, dc: &[Flt]) {
self.channels.iter_mut().zip(dc).for_each(|(ch, dc)| {
ch.DCOffset = *dc;
});
}
pub fn genSignal<T>(&mut self, out: &mut [T])
where
T: Sample + FromSample<Flt> + Debug,
Flt: Sample,
{
let nch = self.nchannels();
let nsamples: usize = out.len() / nch;
assert!(out.len() % self.nchannels() == 0);
self.source_buf.resize(nsamples, 0.0);
self.source
.genSignal_unscaled(&mut self.source_buf.iter_mut());
self.chout_buf.resize(nch, vec![]);
for (channelno, (channel, chout)) in self
.channels
.iter_mut()
.zip(self.chout_buf.iter_mut())
.enumerate()
{
chout.resize(nsamples, 0.0);
channel.genSignal(&self.source_buf, chout);
let out_iterator = out.iter_mut().skip(channelno).step_by(nch);
out_iterator.zip(chout).for_each(|(out, chin)| {
*out = chin.to_sample();
});
}
}
pub fn reset(&mut self, fs: Flt) {
self.fs = Some(fs);
self.source.reset(fs);
self.channels.iter_mut().for_each(|x| x.reset(fs))
}
pub fn setAllMute(&mut self, mute: bool) {
self.channels.iter_mut().for_each(|s| {
s.setMute(mute);
});
}
pub fn setMute(&mut self, mute: &[bool]) {
assert!(mute.len() == self.nchannels());
self.channels.iter_mut().zip(mute).for_each(|(s, m)| {
s.setMute(*m);
});
}
}
#[cfg(test)]
mod test {
use approx::assert_abs_diff_eq;
use super::*;
use crate::Flt;
#[test]
fn test_whitenoise() {
let mut t = [0.0; 10];
Siggen::newWhiteNoise(1., 1, None).genSignal(&mut t);
}
#[test]
fn test_sine() {
const N: usize = 10000;
let mut s1 = [0.0; N];
let mut s2 = [0.0; N];
let mut siggen = Siggen::newSine(10., 1, 1.0).unwrap();
siggen.reset(10.0);
siggen.setAllMute(false);
siggen.genSignal(&mut s1);
siggen.reset(10.0);
siggen.genSignal(&mut s2);
let absdiff = s1
.iter()
.zip(s2.iter())
.map(|(s1, s2)| Flt::abs(*s1 - *s2))
.sum::<Flt>();
assert_abs_diff_eq!(absdiff, 0., epsilon = Flt::EPSILON * 100.);
}
#[test]
fn test_sine2() {
const fs: Flt = 10.0;
const Nframes: usize = 10000;
const Nch: usize = 2;
let mut signal = [0.0; Nch * Nframes];
let mut siggen = Siggen::newSine(fs, Nch, 1.0).unwrap();
siggen.reset(fs);
siggen.setMute(&[false, true]);
siggen.genSignal(&mut signal[..Nframes / 2]);
siggen.genSignal(&mut signal[Nframes / 2..]);
let ms1 = signal.iter().step_by(2).map(|s1| *s1 * *s1).sum::<Flt>() / (Nframes as Flt);
println!("ms1: {}", ms1);
let ms2 = signal
.iter()
.skip(1)
.step_by(2)
.map(|s1| *s1 * *s1)
.sum::<Flt>()
/ (Nframes as Flt);
assert_abs_diff_eq!(Flt::abs(ms1 - 0.5), 0., epsilon = Flt::EPSILON * 1e3);
assert_eq!(ms2, 0.0);
}
#[test]
fn test_sample() {
assert_eq!((0.5f32).to_sample::<i8>(), 64);
assert_eq!((1.0f32).to_sample::<i8>(), 127);
assert_eq!(-(1.0f32).to_sample::<i8>(), -127);
assert_eq!((1.0f32).to_sample::<i16>(), i16::MAX);
}
}