From 935d952d8135d294caead67f3879d318ef23f760 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 15 Feb 2022 18:00:01 +0100 Subject: [PATCH] Make the biquads SIMD capable --- Cargo.lock | 17 ++++++++ plugins/diopser/Cargo.toml | 2 + plugins/diopser/src/filter.rs | 74 ++++++++++++++++++++++++++--------- 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b75e3d4..6a128dde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/plugins/diopser/Cargo.toml b/plugins/diopser/Cargo.toml index e05975ac..3dfd78ea 100644 --- a/plugins/diopser/Cargo.toml +++ b/plugins/diopser/Cargo.toml @@ -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" } diff --git a/plugins/diopser/src/filter.rs b/plugins/diopser/src/filter.rs index 63ae52e9..173216bf 100644 --- a/plugins/diopser/src/filter.rs +++ b/plugins/diopser/src/filter.rs @@ -14,43 +14,56 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +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 . +/// +/// 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 { + pub coefficients: BiquadCoefficients, + 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 { + 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 + Sub + Add + Copy + Sized +{ + fn from_f32(value: f32) -> Self; +} + +impl Default for Biquad { /// 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 Biquad { /// 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 BiquadCoefficients { + /// Convert scalar coefficients into the correct vector type. + pub fn from_f32s(scalar: BiquadCoefficients) -> 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) } }