Make the biquads SIMD capable
This commit is contained in:
parent
8c30eccb27
commit
935d952d81
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -276,6 +276,7 @@ name = "diopser"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nih_plug",
|
||||
"packed_simd_2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -448,6 +449,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.6"
|
||||
|
@ -619,6 +626,16 @@ dependencies = [
|
|||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packed_simd_2"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defdcfef86dcc44ad208f71d9ff4ce28df6537a4e0d6b0e8e845cb8ca10059a6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.0"
|
||||
|
|
|
@ -10,3 +10,5 @@ crate-type = ["cdylib"]
|
|||
|
||||
[dependencies]
|
||||
nih_plug = { path = "../../", features = ["assert_process_allocs"] }
|
||||
|
||||
packed_simd = { version = "0.3.6", package = "packed_simd_2" }
|
||||
|
|
|
@ -14,43 +14,56 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use packed_simd::f32x2;
|
||||
use std::f32::consts;
|
||||
use std::ops::{Add, Mul, Sub};
|
||||
|
||||
/// A simple biquad filter with functions for generating coefficients for an all-pass filter.
|
||||
///
|
||||
/// Based on <https://en.wikipedia.org/wiki/Digital_biquad_filter#Transposed_direct_forms>.
|
||||
///
|
||||
/// The type parameter T should be either an `f32` or a SIMD type.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Biquad {
|
||||
pub coefficients: BiquadCoefficients,
|
||||
s1: f32,
|
||||
s2: f32,
|
||||
pub struct Biquad<T> {
|
||||
pub coefficients: BiquadCoefficients<T>,
|
||||
s1: T,
|
||||
s2: T,
|
||||
}
|
||||
|
||||
/// The coefficients `[b0, b1, b2, a1, a2]` for [Biquad]. These coefficients are all prenormalized,
|
||||
/// i.e. they have been divided by `a0`.
|
||||
///
|
||||
/// The type parameter T should be either an `f32` or a SIMD type.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BiquadCoefficients {
|
||||
b0: f32,
|
||||
b1: f32,
|
||||
b2: f32,
|
||||
a1: f32,
|
||||
a2: f32,
|
||||
pub struct BiquadCoefficients<T> {
|
||||
b0: T,
|
||||
b1: T,
|
||||
b2: T,
|
||||
a1: T,
|
||||
a2: T,
|
||||
}
|
||||
|
||||
impl Default for Biquad {
|
||||
/// Either an `f32` or some SIMD vector type of `f32`s that can be used iwth our biquads.
|
||||
pub trait SimdType:
|
||||
Mul<Output = Self> + Sub<Output = Self> + Add<Output = Self> + Copy + Sized
|
||||
{
|
||||
fn from_f32(value: f32) -> Self;
|
||||
}
|
||||
|
||||
impl<T: SimdType> Default for Biquad<T> {
|
||||
/// Before setting constants the filter should just act as an identity function.
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
coefficients: BiquadCoefficients::identity(),
|
||||
s1: 0.0,
|
||||
s2: 0.0,
|
||||
s1: T::from_f32(0.0),
|
||||
s2: T::from_f32(0.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Biquad {
|
||||
impl<T: SimdType> Biquad<T> {
|
||||
/// Process a single sample.
|
||||
pub fn process(&mut self, sample: f32) -> f32 {
|
||||
pub fn process(&mut self, sample: T) -> T {
|
||||
let result = self.coefficients.b0 * sample + self.s1;
|
||||
|
||||
self.s1 = self.coefficients.b1 * sample - self.coefficients.a1 * result + self.s2;
|
||||
|
@ -60,16 +73,27 @@ impl Biquad {
|
|||
}
|
||||
}
|
||||
|
||||
impl BiquadCoefficients {
|
||||
impl<T: SimdType> BiquadCoefficients<T> {
|
||||
/// Convert scalar coefficients into the correct vector type.
|
||||
pub fn from_f32s(scalar: BiquadCoefficients<f32>) -> Self {
|
||||
Self {
|
||||
b0: T::from_f32(scalar.b0),
|
||||
b1: T::from_f32(scalar.b1),
|
||||
b2: T::from_f32(scalar.b2),
|
||||
a1: T::from_f32(scalar.a1),
|
||||
a2: T::from_f32(scalar.a2),
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter coefficients that would cause the sound to be passed through as is.
|
||||
pub fn identity() -> Self {
|
||||
Self {
|
||||
Self::from_f32s(BiquadCoefficients {
|
||||
b0: 1.0,
|
||||
b1: 0.0,
|
||||
b2: 0.0,
|
||||
a1: 0.0,
|
||||
a2: 0.0,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute the coefficients for an all-pass filter.
|
||||
|
@ -93,6 +117,18 @@ impl BiquadCoefficients {
|
|||
let a1 = (-2.0 * cos_omega0) / a0;
|
||||
let a2 = (1.0 - alpha) / a0;
|
||||
|
||||
Self { b0, b1, b2, a1, a2 }
|
||||
Self::from_f32s(BiquadCoefficients { b0, b1, b2, a1, a2 })
|
||||
}
|
||||
}
|
||||
|
||||
impl SimdType for f32 {
|
||||
fn from_f32(value: f32) -> Self {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
impl SimdType for f32x2 {
|
||||
fn from_f32(value: f32) -> Self {
|
||||
f32x2::splat(value)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue