1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::{AvxSample, NeonSample, SseSample};

/// The trait governing a single sample.
///
/// There are two types which implements this trait so far:
/// * [f32]
/// * [f64]
pub trait Sample
where
    Self: Copy
        + CoerceFrom<usize>
        + CoerceFrom<f64>
        + CoerceFrom<f32>
        + realfft::FftNum
        + std::ops::Mul
        + std::ops::Div
        + std::ops::Add
        + std::ops::Sub
        + std::ops::MulAssign
        + std::ops::RemAssign
        + std::ops::DivAssign
        + std::ops::SubAssign
        + std::ops::AddAssign
        + AvxSample
        + SseSample
        + NeonSample,
{
    const PI: Self;

    /// Calculate the sine of `self`.
    fn sin(self) -> Self;

    /// Calculate the cosine of `self`.
    fn cos(self) -> Self;

    /// Coerce `value` into the current type.
    ///
    /// Coercions are governed through the private `CoerceFrom` trait.
    fn coerce<T>(value: T) -> Self
    where
        Self: CoerceFrom<T>,
    {
        Self::coerce_from(value)
    }
}

impl Sample for f32 {
    const PI: Self = std::f32::consts::PI;

    fn sin(self) -> Self {
        f32::sin(self)
    }

    fn cos(self) -> Self {
        f32::cos(self)
    }
}

impl Sample for f64 {
    const PI: Self = std::f64::consts::PI;

    fn sin(self) -> Self {
        f64::sin(self)
    }

    fn cos(self) -> Self {
        f64::cos(self)
    }
}

/// The trait used to coerce a value infallibly from one type to another.
///
/// This is similar to doing `value as T` where `T` is a floating point type.
/// Loss of precision may happen during coercions if the coerced from value
/// doesn't fit fully within the target type.
pub trait CoerceFrom<T> {
    /// Perform a coercion from `value` into the current type.
    fn coerce_from(value: T) -> Self;
}

impl CoerceFrom<usize> for f32 {
    fn coerce_from(value: usize) -> Self {
        value as f32
    }
}

impl CoerceFrom<usize> for f64 {
    fn coerce_from(value: usize) -> Self {
        value as f64
    }
}

impl CoerceFrom<f64> for f32 {
    fn coerce_from(value: f64) -> Self {
        value as f32
    }
}

impl CoerceFrom<f64> for f64 {
    fn coerce_from(value: f64) -> Self {
        value as f64
    }
}

impl CoerceFrom<f32> for f32 {
    fn coerce_from(value: f32) -> Self {
        value as f32
    }
}

impl CoerceFrom<f32> for f64 {
    fn coerce_from(value: f32) -> Self {
        value as f64
    }
}