From 2d9bc2bec5b1d2adbce1ecae202c62f8b2965922 Mon Sep 17 00:00:00 2001 From: Wouter Ensink <46427708+w-ensink@users.noreply.github.com> Date: Tue, 20 Dec 2022 18:21:13 +0100 Subject: [PATCH] added frequency unit (#2) --- src/biquad.rs | 29 ++++++++----- src/units/frequency.rs | 88 ++++++++++++++++++++++++++++++++++++++++ src/units/mod.rs | 2 + src/units/sample_rate.rs | 60 +++++++++++++++++---------- 4 files changed, 148 insertions(+), 31 deletions(-) create mode 100644 src/units/frequency.rs diff --git a/src/biquad.rs b/src/biquad.rs index 61b18a0..6eb9518 100644 --- a/src/biquad.rs +++ b/src/biquad.rs @@ -4,9 +4,10 @@ //! Example of a low pass filter: //! ```rust //! use rabu::biquad::{BiquadFilter, low_pass_coefficients}; +//! use rabu::units::{Frequency, SampleRate}; //! -//! let sample_rate = 44100.0; -//! let cutoff = 1000.0; +//! let sample_rate = SampleRate::from(44100); +//! let cutoff = Frequency::from(1000.0); //! let coefficients = low_pass_coefficients(sample_rate, cutoff); //! //! let mut filter = BiquadFilter::new(coefficients); @@ -15,6 +16,8 @@ //! let output_sample = filter.process(input_sample); //! ``` +use crate::units::{Frequency, SampleRate}; + /// The coefficients for a `BiquadFilter`. pub struct BiquadCoefficients { pub a1: f64, @@ -67,8 +70,11 @@ impl BiquadFilter { /// Creates the biquad coefficients for a low pass filter, /// given a sample rate and a cutoff frequency. -pub fn low_pass_coefficients(sample_rate: f64, cutoff_frequency: f64) -> BiquadCoefficients { - let w0 = 2.0 * std::f64::consts::PI * cutoff_frequency / sample_rate; +pub fn low_pass_coefficients( + sample_rate: SampleRate, + cutoff_frequency: Frequency, +) -> BiquadCoefficients { + let w0 = 2.0 * std::f64::consts::PI * cutoff_frequency.as_f64() / sample_rate.as_f64(); let cos_w0 = w0.cos(); let sin_w0 = w0.sin(); let alpha = sin_w0 / (2.0 * 0.5); @@ -92,14 +98,14 @@ pub fn low_pass_coefficients(sample_rate: f64, cutoff_frequency: f64) -> BiquadC /// Creates the biquad coefficients for a band pass filter, /// given a sample rate and a cutoff frequency. pub fn band_pass_coefficients( - sample_rate: f64, - center_frequency: f64, + sample_rate: SampleRate, + center_frequency: Frequency, bandwidth: f64, ) -> BiquadCoefficients { - let w0 = 2.0 * std::f64::consts::PI * center_frequency / sample_rate; + let w0 = 2.0 * std::f64::consts::PI * center_frequency.as_f64() / sample_rate.as_f64(); let cos_w0 = w0.cos(); let sin_w0 = w0.sin(); - let alpha = sin_w0 * std::f64::consts::SQRT_2 / 2.0 * bandwidth / center_frequency; + let alpha = sin_w0 * std::f64::consts::SQRT_2 / 2.0 * bandwidth / center_frequency.as_f64(); let b0 = sin_w0 / 2.0; let b1 = 0.0; @@ -119,8 +125,11 @@ pub fn band_pass_coefficients( /// Creates the biquad coefficients for a high pass filter, /// given a sample rate and a cutoff frequency. -pub fn high_pass_coefficients(sample_rate: f64, cutoff_frequency: f64) -> BiquadCoefficients { - let w0 = 2.0 * std::f64::consts::PI * cutoff_frequency / sample_rate; +pub fn high_pass_coefficients( + sample_rate: SampleRate, + cutoff_frequency: Frequency, +) -> BiquadCoefficients { + let w0 = 2.0 * std::f64::consts::PI * cutoff_frequency.as_f64() / sample_rate.as_f64(); let cos_w0 = w0.cos(); let sin_w0 = w0.sin(); let alpha = sin_w0 / (2.0 * 0.5); diff --git a/src/units/frequency.rs b/src/units/frequency.rs new file mode 100644 index 0000000..f619ff7 --- /dev/null +++ b/src/units/frequency.rs @@ -0,0 +1,88 @@ +use crate::units::{Duration, Seconds}; +use derive_more::{Add, AddAssign, Sub, SubAssign}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// Represent a frequency in Hz. +#[derive(Copy, Clone, Debug, PartialEq, Add, Sub, AddAssign, SubAssign, PartialOrd)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Frequency(f64); + +impl Frequency { + /// Gets the raw value of the frequency as `f64`. + pub fn as_f64(&self) -> f64 { + self.0 + } + + /// Gets the raw value of the frequency as `f64`. + pub fn as_f32(&self) -> f64 { + self.as_f64() + } + + /// Gets the period of the frequency (cycle duration): + /// ``` + /// use rabu::units::{Duration, Frequency}; + /// + /// let frequency = Frequency::from(20.0); + /// let period = frequency.period(); + /// + /// assert_eq!(period, Duration::from_secs_f64(0.05)); + /// ``` + pub fn period(&self) -> Duration { + Duration::from_secs_f64(1.0 / self.as_f64()) + } + + /// Gets the period of the frequency (cycle duration): + /// ``` + /// use rabu::units::{Duration, Frequency, Seconds}; + /// + /// let frequency = Frequency::from(20.0); + /// let period = frequency.period_seconds(); + /// + /// assert_eq!(period, Seconds::from(0.05)); + /// ``` + pub fn period_seconds(&self) -> Seconds { + (1.0 / self.as_f64()).into() + } +} + +macro_rules! impl_float_conversions { + ($float_type: ty) => { + impl From<$float_type> for Frequency { + fn from(value: $float_type) -> Self { + Self(value as _) + } + } + + impl From for $float_type { + fn from(value: Frequency) -> Self { + value.0 as _ + } + } + }; +} + +impl_float_conversions!(f32); +impl_float_conversions!(f64); + +macro_rules! impl_from_int_type { + ($int_type: ty) => { + impl From<$int_type> for Frequency { + fn from(value: $int_type) -> Self { + Self(value as _) + } + } + }; +} + +impl_from_int_type!(u64); +impl_from_int_type!(u32); +impl_from_int_type!(u16); +impl_from_int_type!(u8); +impl_from_int_type!(usize); + +impl_from_int_type!(i64); +impl_from_int_type!(i32); +impl_from_int_type!(i16); +impl_from_int_type!(i8); +impl_from_int_type!(isize); diff --git a/src/units/mod.rs b/src/units/mod.rs index 8680409..6bbb78a 100644 --- a/src/units/mod.rs +++ b/src/units/mod.rs @@ -1,6 +1,7 @@ pub use bit_depth::BitDepth; pub use channels::Channels; pub use duration::Duration; +pub use frequency::Frequency; pub use latency::Latency; pub use percentage::Percentage; pub use sample_rate::SampleRate; @@ -12,6 +13,7 @@ pub use time_section::TimeSection; mod bit_depth; mod channels; mod duration; +mod frequency; mod latency; mod percentage; mod sample_rate; diff --git a/src/units/sample_rate.rs b/src/units/sample_rate.rs index 860599e..151820f 100644 --- a/src/units/sample_rate.rs +++ b/src/units/sample_rate.rs @@ -1,31 +1,36 @@ -use crate::units::{Duration, Seconds}; +use crate::units::{Duration, Frequency, Seconds}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; /// Represents a sample rate (in Hz.). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct SampleRate(u32); +pub struct SampleRate(Frequency); impl SampleRate { + /// Gives the sample rate as a `Frequency`. + pub fn as_frequency(&self) -> Frequency { + self.0 + } + /// Gives back the raw value as a `u32`. pub fn as_u32(&self) -> u32 { - self.0 + self.as_f64() as _ } /// Gives back the raw value as a `usize`. pub fn as_usize(&self) -> usize { - self.as_u32() as usize + self.as_f64() as usize } /// Gives back the raw value as a `f64`. pub fn as_f64(&self) -> f64 { - self.as_u32() as f64 + self.0.as_f64() } /// Gives back the raw value as a `u64`. pub fn as_u64(&self) -> u64 { - self.as_u32() as u64 + self.as_f64() as u64 } /// Gets the duration between two consecutive samples: @@ -56,30 +61,43 @@ impl SampleRate { } } -macro_rules! impl_int_conversions { +macro_rules! impl_from_int_type { ($int_type: ty) => { impl From<$int_type> for SampleRate { fn from(value: $int_type) -> Self { - Self(value as _) + Self(Frequency::from(value)) + } + } + }; +} + +impl_from_int_type!(u64); +impl_from_int_type!(u32); +impl_from_int_type!(u16); +impl_from_int_type!(u8); +impl_from_int_type!(usize); + +impl_from_int_type!(i64); +impl_from_int_type!(i32); +impl_from_int_type!(i16); +impl_from_int_type!(i8); +impl_from_int_type!(isize); + +macro_rules! impl_float_conversions { + ($int_type: ty) => { + impl From<$int_type> for SampleRate { + fn from(value: $int_type) -> Self { + Self(Frequency::from(value)) } } impl From for $int_type { fn from(value: SampleRate) -> Self { - value.0 as _ + value.as_f64() as _ } } }; } -impl_int_conversions!(u64); -impl_int_conversions!(u32); -impl_int_conversions!(u16); -impl_int_conversions!(u8); -impl_int_conversions!(usize); - -impl_int_conversions!(i64); -impl_int_conversions!(i32); -impl_int_conversions!(i16); -impl_int_conversions!(i8); -impl_int_conversions!(isize); +impl_float_conversions!(f64); +impl_float_conversions!(f32);