1
0
Fork 0

Make the biquads SIMD capable

This commit is contained in:
Robbert van der Helm 2022-02-15 18:00:01 +01:00
parent 8c30eccb27
commit 935d952d81
3 changed files with 74 additions and 19 deletions

17
Cargo.lock generated
View file

@ -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"

View file

@ -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" }

View file

@ -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)
}
}