use std::f64::consts::PI; use std::ops::Neg; use crate::map; /// Represents a digital, sampled frequency /// as radians per samples in [0; 2*pi[ range /// mapped to the whole [0; usize::MAX] range #[derive(Clone, Copy, PartialEq, PartialOrd)] pub struct DigitalFrequency(pub usize); /// Represents an absolute phase offset /// as radians in [0; 2*pi[ range /// mapped to the whole [0; usize::MAX] range #[derive(Clone, Copy, PartialEq, PartialOrd)] pub struct Phase(pub DigitalFrequency); impl DigitalFrequency { /// Creates a DigitalFrequency from rads per samples pub fn from_rad(radians_per_sample: f64) -> Self { // Frequnecy wraps arround : Going at 2 pi radians per second // Is like not oscillating at all let f = radians_per_sample.rem_euclid(2. * PI); // Then we map the [0, 2*PI] range into the 0 to usize range DigitalFrequency(map(f, 0., 2. * PI, 0., usize::MAX as f64).floor() as usize) } /// Creates a DigitalFrequency from a frequency given in hertz (s^(-1)) /// in the context of a sample rate also given in hertz pub fn from_time_frequency(hertz: f64, sample_rate: f64) -> Self { Self::from_rad(map(hertz, 0., sample_rate, 0., 2. * PI)) } /// Gets the frequency as radians per sample pub fn as_rad(&self) -> f64 { map(self.0 as f64, 0., usize::MAX as f64, 0., 2. * PI) } /// Gets the frequency as hertz in the context of a sample rate /// also given in hert pub fn as_time_frequency(&self, sample_rate: f64) -> f64 { map(self.0 as f64, 0., usize::MAX as f64, 0., sample_rate) } } impl Neg for DigitalFrequency { type Output = Self; /// Returns the "negative frequency" fn neg(self) -> Self::Output { DigitalFrequency(usize::MAX - self.0) } }