Skip to content

Commit

Permalink
added frequency unit (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
w-ensink committed Dec 20, 2022
1 parent 17cd70a commit 2d9bc2b
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 31 deletions.
29 changes: 19 additions & 10 deletions src/biquad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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);
Expand Down
88 changes: 88 additions & 0 deletions src/units/frequency.rs
Original file line number Diff line number Diff line change
@@ -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<Frequency> 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);
2 changes: 2 additions & 0 deletions src/units/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down
60 changes: 39 additions & 21 deletions src/units/sample_rate.rs
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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<SampleRate> 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);

0 comments on commit 2d9bc2b

Please sign in to comment.