use core::{
f32::consts::PI,
fmt,
iter::{IntoIterator, Iterator},
};
use libm::{asinf, copysignf, cosf, sinf};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum WaveFunc {
Sine,
Cosine,
Square,
Sawtooth,
Triangle,
}
impl fmt::Display for WaveFunc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Sine => "Sine",
Self::Cosine => "Cosine",
Self::Square => "Square",
Self::Sawtooth => "Sawtooth",
Self::Triangle => "Triangle",
}
)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Wave {
pub sample_rate: f32,
pub frequency: f32,
pub phase: f32,
pub amplitude: f32,
pub func: WaveFunc,
}
impl Wave {
pub fn iter(&self) -> WaveIterator {
self.into_iter()
}
}
impl<'a> IntoIterator for &'a Wave {
type Item = f32;
type IntoIter = WaveIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
WaveIterator {
inner: self,
index: 0.0,
}
}
}
impl Default for Wave {
fn default() -> Self {
Self {
sample_rate: 0.0,
frequency: 0.0,
phase: 0.0,
amplitude: 1.0,
func: WaveFunc::Sine,
}
}
}
impl fmt::Display for Wave {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"<Func: {}, Freq: {}Hz, Ampl: {}, Sampling Freq: {}Hz>",
self.func, self.frequency, self.amplitude, self.sample_rate
)
}
}
#[derive(Debug, Clone)]
pub struct WaveIterator<'a> {
inner: &'a Wave,
index: f32,
}
impl<'a> WaveIterator<'a> {
#[inline]
fn index_inc(&mut self) -> f32 {
let idx = self.index;
self.index = (self.index % self.inner.sample_rate) + 1.0;
idx
}
#[inline]
fn func(&self, x: f32) -> f32 {
match self.inner.func {
WaveFunc::Sine => sinf(x),
WaveFunc::Cosine => cosf(x),
WaveFunc::Square => copysignf(1.0, sinf(x)),
WaveFunc::Sawtooth => (x % (2.0 * PI)) / PI - 1.0,
WaveFunc::Triangle => 2.0 * asinf(sinf(x)) / PI,
}
}
}
impl<'a> Iterator for WaveIterator<'a> {
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
let t = self.index_inc() / self.inner.sample_rate;
Some(
self.inner.amplitude
* self.func(2.0 * PI * t * self.inner.frequency + self.inner.phase),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::format;
use alloc::vec::Vec;
#[test]
fn test_wave_default() {
let wave: Wave = Default::default();
assert_eq!(
wave,
Wave {
sample_rate: 0.0,
frequency: 0.0,
phase: 0.0,
amplitude: 1.0,
func: WaveFunc::Sine
}
);
}
#[test]
fn test_wave_iteration() {
let wave = Wave {
sample_rate: 500.0,
frequency: 130.0,
..Default::default()
};
let res: Vec<f32> = wave.iter().take(1001).collect();
assert_eq!(res[0], 0.0);
assert_eq!(&res[1..501], &res[501..]);
}
#[test]
fn test_wave_iteration_cosine() {
let wave = Wave {
sample_rate: 500.0,
frequency: 130.0,
func: WaveFunc::Cosine,
..Default::default()
};
let res: Vec<f32> = wave.iter().take(1001).collect();
assert_eq!(res[0], 1.0);
assert_eq!(&res[1..501], &res[501..]);
}
#[test]
fn test_wave_iteration_square() {
let wave = Wave {
sample_rate: 500.0,
frequency: 130.0,
func: WaveFunc::Square,
..Default::default()
};
let res: Vec<f32> = wave.iter().take(1001).collect();
assert_eq!(res[0], 1.0);
assert_eq!(res[1], 1.0);
assert_eq!(res[2], -1.0);
assert_eq!(res[3], -1.0);
assert_eq!(&res[1..501], &res[501..]);
}
#[test]
fn test_wave_iteration_sawtooth() {
let wave = Wave {
sample_rate: 500.0,
frequency: 130.0,
func: WaveFunc::Sawtooth,
..Default::default()
};
let res: Vec<f32> = wave.iter().take(1001).collect();
assert_eq!(res[0], -1.0);
assert_eq!(res[1], -0.47999996);
assert_eq!(res[2], 0.04000008);
assert_eq!(res[3], 0.5600002);
assert_eq!(res[4], -0.91999984);
assert_eq!(&res[1..501], &res[501..]);
}
#[test]
fn test_wave_iteration_triangle() {
let wave = Wave {
sample_rate: 500.0,
frequency: 130.0,
func: WaveFunc::Triangle,
..Default::default()
};
let res: Vec<f32> = wave.iter().take(1001).collect();
assert_eq!(res[0], 0.0);
assert_eq!(res[1], 0.96);
assert_eq!(res[2], -0.08000024);
assert_eq!(res[3], -0.8799997);
assert_eq!(res[4], 0.16000047);
assert_eq!(&res[1..501], &res[501..]);
}
#[test]
fn test_wave_phase_shift() {
let wave = Wave {
sample_rate: 500.0,
frequency: 120.0,
phase: PI / 2.0,
..Default::default()
};
let res: Vec<f32> = wave.iter().take(5).collect();
assert_eq!(res[0], 1.0);
}
#[test]
fn test_wave_function_formatting() {
assert_eq!(format!("{}", WaveFunc::Sine), "Sine");
assert_eq!(format!("{}", WaveFunc::Cosine), "Cosine");
assert_eq!(format!("{}", WaveFunc::Square), "Square");
assert_eq!(format!("{}", WaveFunc::Sawtooth), "Sawtooth");
assert_eq!(format!("{}", WaveFunc::Triangle), "Triangle");
}
#[test]
fn test_wave_formatting() {
let wave = Wave {
sample_rate: 500.0,
frequency: 120.0,
phase: PI / 2.0,
..Default::default()
};
let fmt_string = format!("{}", wave);
assert_eq!(
fmt_string,
"<Func: Sine, Freq: 120Hz, Ampl: 1, Sampling Freq: 500Hz>"
);
}
}