nsys-signal-utils 0.0.3

Signal processing utilities
Documentation
//! Signal generators
// TODO: use signal generators from dasp crate?

use rand;
use rand_xorshift::XorShiftRng;
use derive_more::{From, TryInto};

#[derive(Clone, Debug)]
pub struct Generator {
  pub freq : f64,
  pub kind : Kind,
  pub rng  : XorShiftRng
}

pub trait Generate {
  fn generate (&mut self,
    rng     : &mut XorShiftRng,
    samples : &mut [i16],
    freq    : f64);
}

#[derive(Clone, Debug, PartialEq, From, TryInto)]
pub enum Kind {
  Wave  (Wave),
  Noise (Noise)
}

#[derive(Clone, Debug, PartialEq)]
pub enum Wave {
  Sin,
  Tri,
  Saw,
  Square {
    width : u32
  }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Noise {
  White,
  Brown { intensity : i16 },
  Pink
}

impl Generator {
  #[inline]
  pub fn new (kind : Kind, freq : f64) -> Self {
    use rand::SeedableRng;
    // TODO: seed rng
    let rng = XorShiftRng::seed_from_u64 (0);
    Generator { kind, freq, rng }
  }
  #[inline]
  pub fn generate (&mut self, samples : &mut [i16]) {
    self.kind.generate (&mut self.rng, samples, self.freq)
  }
}

impl Generate for Kind {
  fn generate (&mut self,
    rng     : &mut XorShiftRng,
    samples : &mut [i16],
    freq    : f64
  ) {
    match self {
      Kind::Wave  (wave)  => wave.generate  (rng, samples, freq),
      Kind::Noise (noise) => noise.generate (rng, samples, freq)
    }
  }
}

impl Generate for Wave {
  fn generate (&mut self,
    _rng     : &mut XorShiftRng,
    _samples : &mut [i16],
    _freq    : f64
  ) {
    unimplemented!("TODO")
  }
}

impl Generate for Noise {
  fn generate (&mut self,
    rng     : &mut XorShiftRng,
    samples : &mut [i16],
    _freq   : f64
  ) {
    use rand::Rng;
    match self {
      Noise::White => {
        for sample in samples.iter_mut() {
          *sample = rng.random();
        }
      },
      Noise::Brown { intensity } => {
        let mut level = 0i16;
        for sample in samples.iter_mut() {
          *sample = level;
          let delta = rng.random_range(-(intensity.abs())..intensity.abs());
          level = level.saturating_add (delta);
        }
        // TODO: amplitude
        //pcm::normalize (samples, std::i16::MAX - 1000);
      },
      _ => unimplemented!("TODO")
    }
  }
}