diff --git a/README.md b/README.md index 1f3090f..9b2868f 100644 --- a/README.md +++ b/README.md @@ -734,8 +734,14 @@ Due to nonlinearity, we do not attempt to calculate frequency responses for thes | Opcode | Type | Parameters | Family | Notes | | ------------ | ---------------------- | ------------ | ------------ | --------- | | `bandrez` | bandpass (2nd order) | frequency, Q | nested 1st order | | -| `dresonator` | bandpass (2nd order) | frequency, Q | dirty biquad | Stable when the feedback mapping is nonexpansive. | -| `fresonator` | bandpass (2nd order) | frequency, Q | feedback biquad | -..- | +| `dbell` | peaking (2nd order) | frequency, Q, gain | dirty biquad | Biquad with nonlinear state shaping and adjustable amplitude gain. | +| `dhighpass` | highpass (2nd order) | frequency, Q | dirty biquad | | +| `dlowpass` | lowpass (2nd order) | frequency, Q | dirty biquad | | +| `dresonator` | bandpass (2nd order) | frequency, Q | dirty biquad | | +| `fbell` | peaking (2nd order) | frequency, Q, gain | feedback biquad | Biquad with nonlinear feedback and adjustable amplitude gain. | +| `fhighpass` | highpass (2nd order) | frequency, Q | feedback biquad | | +| `flowpass` | lowpass (2nd order) | frequency, Q | feedback biquad | | +| `fresonator` | bandpass (2nd order) | frequency, Q | feedback biquad | | | `lowrez` | lowpass (2nd order) | frequency, Q | nested 1st order | | | `moog` | lowpass (4th order) | frequency, Q | Moog ladder | | @@ -899,11 +905,17 @@ The following table summarizes the available settings. | `biquad` | `biquad` to set biquad coefficients | | `butterpass_hz` | `center` | | `constant` | `value` to set scalar value on all channels | +| `dbell_hz` | `center_q_gain` | | `dc` | `value` to set scalar value on all channels | | `dcblock_hz` | `center` | +| `dhighpass_hz` | `center_q` | +| `dlowpass_hz` | `center_q` | | `dresonator_hz` | `center_q` | | `dsf_saw_r` | `roughness` in 0...1 | | `dsf_square_r` | `roughness` in 0...1 | +| `fbell_hz` | `center_q_gain` | +| `fhighpass_hz` | `center_q` | +| `flowpass_hz` | `center_q` | | `follow` | `time` to set follow time in seconds | | `fresonator_hz` | `center_q` | | `highpass_hz` | `center_q` | @@ -1073,13 +1085,19 @@ The type parameters in the table refer to the hacker preludes. | `clip()` | 1 | 1 | Clip signal to -1...1. | | `clip_to(min, max)` | 1 | 1 | Clip signal to min...max. | | `constant(x)` | - | `x` | Constant signal `x`. Synonymous with `dc`. | +| `dbell(shape)` | 4 (audio, frequency, Q, gain) | 1 | Dirty biquad bell equalizer (2nd order) with feedback `shape`, for example, `Tanh(1.0)`. | +| `dbell_hz(shape, f, q, gain)` | 1 | 1 | Dirty biquad bell equalizer (2nd order) with feedback `shape`, center `f` Hz, Q value `q` and amplitude gain `gain`. | | `dc(x)` | - | `x` | Constant signal `x`. Synonymous with `constant`. | | `dcblock()` | 1 | 1 | Zero center signal with cutoff frequency 10 Hz. | | `dcblock_hz(f)` | 1 | 1 | Zero center signal with cutoff frequency `f`. | | `declick()` | 1 | 1 | Apply 10 ms of fade-in to signal. | | `declick_s(t)` | 1 | 1 | Apply `t` seconds of fade-in to signal. | | `delay(t)` | 1 | 1 | Delay of `t` seconds. Delay time is rounded to the nearest sample. | -| `dresonator(shape)` | 3 (audio, frequency, bandwidth) | 1 | Dirty biquad resonator (2nd order) with feedback `shape`, for example, `Tanh(1.0)`. | +| `dhighpass(shape)` | 3 (audio, frequency, Q) | 1 | Dirty biquad highpass (2nd order) with feedback `shape`, for example, `Tanh(1.0)`. | +| `dhighpass_hz(shape, f, q)` | 1 | 1 | Dirty biquad highpass (2nd order) with feedback `shape`, center `f` Hz and Q `q`. | +| `dlowpass(shape)` | 3 (audio, frequency, Q) | 1 | Dirty biquad lowpass (2nd order) with feedback `shape`, for example, `Tanh(1.0)`. | +| `dlowpass_hz(shape, f, q)` | 1 | 1 | Dirty biquad lowpass (2nd order) with feedback `shape`, center `f` Hz and Q `q`. | +| `dresonator(shape)` | 3 (audio, frequency, Q) | 1 | Dirty biquad resonator (2nd order) with feedback `shape`, for example, `Tanh(1.0)`. | | `dresonator_hz(shape, f, q)` | 1 | 1 | Dirty biquad resonator (2nd order) with feedback `shape`, center `f` Hz and Q `q`. | | `dsf_saw()` | 2 (frequency, roughness) | 1 | Saw-like discrete summation formula oscillator. | | `dsf_saw_r(r)` | 1 (frequency) | 1 | Saw-like discrete summation formula oscillator with roughness `r` in 0...1. | @@ -1089,6 +1107,8 @@ The type parameters in the table refer to the hacker preludes. | `envelope2(f)` | 1 (x) | `f` | Time-varying, input dependent control `f` with scalar or tuple output, e.g., `\|t, x\| exp(-t * x)`. Synonymous with `lfo2`. | | `envelope3(f)` | 2 (x, y) | `f` | Time-varying, input dependent control `f` with scalar or tuple output, e.g., `\|t, x, y\| y * exp(-t * x)`. Synonymous with `lfo3`. | | `envelope_in(f)` | `f` | `f` | Time-varying, input dependent control `f` with scalar or tuple output, e.g., `\|t, i: &Frame\| exp(-t * i[0])`. Synonymous with `lfo_in`. | +| `fbell(shape)` | 4 (audio, frequency, Q, gain) | 1 | Feedback biquad bell equalizer (2nd order) with feedback `shape`, for example, `Tanh(1.0)`. | +| `fbell_hz(shape, f, q, gain)` | 1 | 1 | Feedback biquad bell equalizer (2nd order) with feedback `shape`, center `f` Hz, Q value `q` and amplitude gain `gain`. | | `fdn(x)` | `x` | `x` | Feedback Delay Network: enclose feedback circuit `x` (with equal number of inputs and outputs) using diffusive [Hadamard](https://en.wikipedia.org/wiki/Hadamard_matrix) feedback. | | `fdn2(x, y)` | `x`, `y`| `x`, `y`| Feedback Delay Network: enclose feedback circuit `x` (with equal number of inputs and outputs) using diffusive Hadamard feedback, with extra feedback loop processing `y`. The feedforward path does not include `y`. | | `feedback(x)` | `x` | `x` | Enclose (single sample) feedback circuit `x` (with equal number of inputs and outputs). | @@ -1096,8 +1116,12 @@ The type parameters in the table refer to the hacker preludes. | `fir(weights)` | 1 | 1 | FIR filter with the specified weights, for example, `fir((0.5, 0.5))`. | | `fir3(gain)` | 1 | 1 | Symmetric 3-point FIR calculated from desired `gain` at the Nyquist frequency. | | `flanger(fb, min_d, max_d, f)`| 1| 1 | Flanger effect with feedback amount `fb`, minimum delay `min_d` seconds, maximum delay `max_d` seconds and delay function `f`, e.g., `\|t\| lerp11(0.01, 0.02, sin_hz(0.1, t))`. | +| `fhighpass(shape)` | 3 (audio, frequency, Q) | 1 | Feedback biquad highpass (2nd order) with feedback `shape`, for example, `Softsign(1.0)`. | +| `fhighpass_hz(shape, f, q)` | 1 | 1 | Feedback biquad highpass (2nd order) with feedback `shape`, center `f` Hz and Q `q`. | +| `flowpass(shape)` | 3 (audio, frequency, Q) | 1 | Feedback biquad lowpass (2nd order) with feedback `shape`, for example, `Softsign(1.0)`. | +| `flowpass_hz(shape, f, q)` | 1 | 1 | Feedback biquad lowpass (2nd order) with feedback `shape`, center `f` Hz and Q `q`. | | `follow(t)` | 1 | 1 | Smoothing filter with halfway response time `t` seconds. | -| `fresonator(shape)` | 3 (audio, frequency, bandwidth) | 1 | Feedback biquad resonator (2nd order) with feedback `shape`, for example, `Softsign(1.0)`. | +| `fresonator(shape)` | 3 (audio, frequency, Q) | 1 | Feedback biquad resonator (2nd order) with feedback `shape`, for example, `Softsign(1.0)`. | | `fresonator_hz(shape, f, q)` | 1 | 1 | Feedback biquad resonator (2nd order) with feedback `shape`, center `f` Hz and Q `q`. | | `hammond()` | 1 (frequency) | 1 | Bandlimited Hammond oscillator. Emphasizes first three partials. | | `hammond_hz(f)` | - | 1 | Bandlimited Hammond oscillator at `f` Hz. Emphasizes first three partials. | diff --git a/examples/keys.rs b/examples/keys.rs index 02dcdb0..1858a23 100644 --- a/examples/keys.rs +++ b/examples/keys.rs @@ -29,6 +29,7 @@ enum Filter { Butterworth, Bandpass, Peak, + DirtyBiquad, FeedbackBiquad, } @@ -285,6 +286,7 @@ impl eframe::App for State { }); ui.horizontal(|ui| { ui.selectable_value(&mut self.filter, Filter::Peak, "Peak"); + ui.selectable_value(&mut self.filter, Filter::DirtyBiquad, "Dirty Biquad"); ui.selectable_value(&mut self.filter, Filter::FeedbackBiquad, "Feedback Biquad"); }); ui.separator(); @@ -496,10 +498,14 @@ impl eframe::App for State { (pass() | lfo(move |t| (xerp11(200.0, 10000.0, sin_hz(0.2, t)), 2.0))) >> peak(), )), + Filter::DirtyBiquad => Net::wrap(Box::new( + (pass() | lfo(move |t| (max(400.0, 20000.0 * exp(-t * 8.0)), 2.0))) + >> dlowpass(Tanh(1.0)), + )), Filter::FeedbackBiquad => Net::wrap(Box::new( - (mul(5.0) + (mul(2.0) | lfo(move |t| (xerp11(200.0, 10000.0, sin_hz(0.2, t)), 5.0))) - >> fresonator(Softsign(1.0)), + >> fresonator(Softsign(1.01)), )), }; let mut note = Box::new(waveform >> filter); diff --git a/src/biquad.rs b/src/biquad.rs index 94acfcc..ab3083a 100644 --- a/src/biquad.rs +++ b/src/biquad.rs @@ -1,4 +1,4 @@ -//! Biquad filters with nonlinearities. +//! Biquad filters with optional nonlinearities. use super::audionode::*; use super::math::*; @@ -9,6 +9,7 @@ use super::*; use core::marker::PhantomData; use numeric_array::typenum::*; +/// Biquad coefficients in normalized form. #[derive(Copy, Clone, Debug, Default)] pub struct BiquadCoefs { pub a1: F, @@ -20,7 +21,9 @@ pub struct BiquadCoefs { impl BiquadCoefs { /// Return settings for a Butterworth lowpass filter. + /// Sample rate is in Hz. /// Cutoff is the -3 dB point of the filter in Hz. + #[inline] pub fn butter_lowpass(sample_rate: F, cutoff: F) -> Self { let c = F::from_f64; let f: F = tan(cutoff * F::PI / sample_rate); @@ -34,8 +37,9 @@ impl BiquadCoefs { } /// Return settings for a constant-gain bandpass resonator. - /// The center frequency is given in Hz. + /// Sample rate and center frequency are in Hz. /// The overall gain of the filter is independent of bandwidth. + #[inline] pub fn resonator(sample_rate: F, center: F, q: F) -> Self { let c = F::from_f64; let r: F = exp(-F::PI * center / (q * sample_rate)); @@ -47,7 +51,61 @@ impl BiquadCoefs { Self { a1, a2, b0, b1, b2 } } + /// Return settings for a lowpass filter. + /// Sample rate and cutoff frequency are in Hz. + #[inline] + pub fn lowpass(sample_rate: F, cutoff: F, q: F) -> Self { + let c = F::from_f64; + let omega = F::TAU * cutoff / sample_rate; + let alpha = sin(omega) / (c(2.0) * q); + let beta = cos(omega); + let a0r = c(1.0) / (c(1.0) + alpha); + let a1 = c(-2.0) * beta * a0r; + let a2 = (c(1.0) - alpha) * a0r; + let b1 = (c(1.0) - beta) * a0r; + let b0 = b1 * c(0.5); + let b2 = b0; + Self { a1, a2, b0, b1, b2 } + } + + /// Return settings for a highpass filter. + /// Sample rate and cutoff frequency are in Hz. + #[inline] + pub fn highpass(sample_rate: F, cutoff: F, q: F) -> Self { + let c = F::from_f64; + let omega = F::TAU * cutoff / sample_rate; + let alpha = sin(omega) / (c(2.0) * q); + let beta = cos(omega); + let a0r = c(1.0) / (c(1.0) + alpha); + let a1 = c(-2.0) * beta * a0r; + let a2 = (c(1.0) - alpha) * a0r; + let b0 = (c(1.0) + beta) * c(0.5) * a0r; + let b1 = (c(-1.0) - beta) * a0r; + let b2 = b0; + Self { a1, a2, b0, b1, b2 } + } + + /// Return settings for a bell equalizer filter. + /// Sample rate and center frequencies are in Hz. + /// Gain is amplitude gain (`gain` > 0). + #[inline] + pub fn bell(sample_rate: F, center: F, q: F, gain: F) -> Self { + let c = F::from_f64; + let omega = F::TAU * center / sample_rate; + let alpha = sin(omega) / (c(2.0) * q); + let beta = cos(omega); + let a = sqrt(gain); + let a0r = c(1.0) / (c(1.0) + alpha / a); + let a1 = c(-2.0) * beta * a0r; + let a2 = (c(1.0) - alpha / a) * a0r; + let b0 = (c(1.0) + alpha * a) * a0r; + let b1 = a1; + let b2 = (c(1.0) - alpha * a) * a0r; + Self { a1, a2, b0, b1, b2 } + } + /// Arbitrary biquad. + #[inline] pub fn arbitrary(a1: F, a2: F, b0: F, b1: F, b2: F) -> Self { Self { a1, a2, b0, b1, b2 } } @@ -346,6 +404,7 @@ pub trait BiquadMode: Clone + Default + Sync + Send { fn update(&mut self, params: &BiquadParams, coefs: &mut BiquadCoefs); } +/// Resonator biquad mode. #[derive(Clone, Default)] pub struct ResonatorBiquad { _marker: PhantomData, @@ -359,11 +418,72 @@ impl ResonatorBiquad { impl BiquadMode for ResonatorBiquad { type Inputs = U3; + #[inline] fn update(&mut self, params: &BiquadParams, coefs: &mut BiquadCoefs) { *coefs = BiquadCoefs::resonator(params.sample_rate, params.center, params.q); } } +/// Lowpass biquad mode. +#[derive(Clone, Default)] +pub struct LowpassBiquad { + _marker: PhantomData, +} + +impl LowpassBiquad { + pub fn new() -> Self { + Self::default() + } +} + +impl BiquadMode for LowpassBiquad { + type Inputs = U3; + #[inline] + fn update(&mut self, params: &BiquadParams, coefs: &mut BiquadCoefs) { + *coefs = BiquadCoefs::lowpass(params.sample_rate, params.center, params.q); + } +} + +/// Highpass biquad mode. +#[derive(Clone, Default)] +pub struct HighpassBiquad { + _marker: PhantomData, +} + +impl HighpassBiquad { + pub fn new() -> Self { + Self::default() + } +} + +impl BiquadMode for HighpassBiquad { + type Inputs = U3; + #[inline] + fn update(&mut self, params: &BiquadParams, coefs: &mut BiquadCoefs) { + *coefs = BiquadCoefs::highpass(params.sample_rate, params.center, params.q); + } +} + +/// Bell biquad mode. +#[derive(Clone, Default)] +pub struct BellBiquad { + _marker: PhantomData, +} + +impl BellBiquad { + pub fn new() -> Self { + Self::default() + } +} + +impl BiquadMode for BellBiquad { + type Inputs = U4; + #[inline] + fn update(&mut self, params: &BiquadParams, coefs: &mut BiquadCoefs) { + *coefs = BiquadCoefs::bell(params.sample_rate, params.center, params.q, params.gain); + } +} + #[derive(Clone)] /// Biquad in transposed direct form II with nonlinear feedback. pub struct FbBiquad, S: Shape> { diff --git a/src/hacker.rs b/src/hacker.rs index 2d71354..326ae7a 100644 --- a/src/hacker.rs +++ b/src/hacker.rs @@ -2419,11 +2419,161 @@ pub fn unit, O: Size>(unit: Box) -> An(shape: S) -> An, S>> { + An(DirtyBiquad::new(BellBiquad::new(), shape)) +} + +/// Biquad bell equalizer with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// Filter `center` is in Hz and `gain` is amplitude gain. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dbell_hz( + shape: S, + center: f32, + q: f32, + gain: f32, +) -> An, S>> { + super::prelude::dbell_hz(shape, center as f64, q as f64, gain as f64) +} + +/// Biquad bell equalizer with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Input 3: amplitude gain +/// - Output 0: filtered audio +pub fn fbell(shape: S) -> An, S>> { + An(FbBiquad::new(BellBiquad::new(), shape)) +} + +/// Biquad bell equalizer with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// Filter `center` is in Hz and `gain` is amplitude gain. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn fbell_hz( + shape: S, + center: f32, + q: f32, + gain: f32, +) -> An, S>> { + super::prelude::fbell_hz(shape, center as f64, q as f64, gain as f64) +} + +/// Biquad highpass with nonlinear state shaping using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn dhighpass(shape: S) -> An, S>> { + An(DirtyBiquad::new(HighpassBiquad::new(), shape)) +} + +/// Biquad highpass with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dhighpass_hz( + shape: S, + cutoff: f32, + q: f32, +) -> An, S>> { + super::prelude::dhighpass_hz(shape, cutoff as f64, q as f64) +} + +/// Biquad highpass with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn fhighpass(shape: S) -> An, S>> { + An(FbBiquad::new(HighpassBiquad::new(), shape)) +} + +/// Biquad highpass with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn fhighpass_hz( + shape: S, + cutoff: f32, + q: f32, +) -> An, S>> { + super::prelude::fhighpass_hz(shape, cutoff as f64, q as f64) +} + +/// Biquad lowpass with nonlinear state shaping using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn dlowpass(shape: S) -> An, S>> { + An(DirtyBiquad::new(LowpassBiquad::new(), shape)) +} + +/// Biquad lowpass with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dlowpass_hz( + shape: S, + cutoff: f32, + q: f32, +) -> An, S>> { + super::prelude::dlowpass_hz(shape, cutoff as f64, q as f64) +} + +/// Biquad lowpass with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn flowpass(shape: S) -> An, S>> { + An(FbBiquad::new(LowpassBiquad::new(), shape)) +} + +/// Biquad lowpass with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn flowpass_hz( + shape: S, + cutoff: f32, + q: f32, +) -> An, S>> { + super::prelude::flowpass_hz(shape, cutoff as f64, q as f64) +} + /// Biquad resonator with nonlinear state shaping using waveshaper `shape`. /// The filter is stable when `shape` is nonexpansive. /// (The usual waveshapes are nonexpansive up to hardness 1.0). /// - Input 0: audio -/// - Input 1: center frequency +/// - Input 1: center frequency (Hz) /// - Input 2: Q /// - Output 0: filtered audio /// @@ -2453,7 +2603,7 @@ pub fn dresonator_hz( /// The filter is stable when `shape` is nonexpansive. /// (The usual waveshapes are nonexpansive up to hardness 1.0). /// - Input 0: audio -/// - Input 1: center frequency +/// - Input 1: center frequency (Hz) /// - Input 2: Q /// - Output 0: filtered audio /// diff --git a/src/hacker32.rs b/src/hacker32.rs index 9748e2c..a8d0f8c 100644 --- a/src/hacker32.rs +++ b/src/hacker32.rs @@ -2419,11 +2419,161 @@ pub fn unit, O: Size>(unit: Box) -> An(shape: S) -> An, S>> { + An(DirtyBiquad::new(BellBiquad::new(), shape)) +} + +/// Biquad bell equalizer with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// Filter `center` is in Hz and `gain` is amplitude gain. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dbell_hz( + shape: S, + center: f32, + q: f32, + gain: f32, +) -> An, S>> { + super::prelude::dbell_hz(shape, center, q, gain) +} + +/// Biquad bell equalizer with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Input 3: amplitude gain +/// - Output 0: filtered audio +pub fn fbell(shape: S) -> An, S>> { + An(FbBiquad::new(BellBiquad::new(), shape)) +} + +/// Biquad bell equalizer with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// Filter `center` is in Hz and `gain` is amplitude gain. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn fbell_hz( + shape: S, + center: f32, + q: f32, + gain: f32, +) -> An, S>> { + super::prelude::fbell_hz(shape, center, q, gain) +} + +/// Biquad highpass with nonlinear state shaping using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn dhighpass(shape: S) -> An, S>> { + An(DirtyBiquad::new(HighpassBiquad::new(), shape)) +} + +/// Biquad highpass with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dhighpass_hz( + shape: S, + cutoff: f32, + q: f32, +) -> An, S>> { + super::prelude::dhighpass_hz(shape, cutoff, q) +} + +/// Biquad highpass with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn fhighpass(shape: S) -> An, S>> { + An(FbBiquad::new(HighpassBiquad::new(), shape)) +} + +/// Biquad highpass with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn fhighpass_hz( + shape: S, + cutoff: f32, + q: f32, +) -> An, S>> { + super::prelude::fhighpass_hz(shape, cutoff, q) +} + +/// Biquad lowpass with nonlinear state shaping using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn dlowpass(shape: S) -> An, S>> { + An(DirtyBiquad::new(LowpassBiquad::new(), shape)) +} + +/// Biquad lowpass with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dlowpass_hz( + shape: S, + cutoff: f32, + q: f32, +) -> An, S>> { + super::prelude::dlowpass_hz(shape, cutoff, q) +} + +/// Biquad lowpass with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn flowpass(shape: S) -> An, S>> { + An(FbBiquad::new(LowpassBiquad::new(), shape)) +} + +/// Biquad lowpass with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn flowpass_hz( + shape: S, + cutoff: f32, + q: f32, +) -> An, S>> { + super::prelude::flowpass_hz(shape, cutoff, q) +} + /// Biquad resonator with nonlinear state shaping using waveshaper `shape`. /// The filter is stable when `shape` is nonexpansive. /// (The usual waveshapes are nonexpansive up to hardness 1.0). /// - Input 0: audio -/// - Input 1: center frequency +/// - Input 1: center frequency (Hz) /// - Input 2: Q /// - Output 0: filtered audio /// @@ -2453,7 +2603,7 @@ pub fn dresonator_hz( /// The filter is stable when `shape` is nonexpansive. /// (The usual waveshapes are nonexpansive up to hardness 1.0). /// - Input 0: audio -/// - Input 1: center frequency +/// - Input 1: center frequency (Hz) /// - Input 2: Q /// - Output 0: filtered audio /// diff --git a/src/prelude.rs b/src/prelude.rs index 316980e..52f49b9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2863,11 +2863,173 @@ pub fn unit, O: Size>(unit: Box) -> An(shape: S) -> An, S>> { + An(DirtyBiquad::new(BellBiquad::new(), shape)) +} + +/// Biquad bell equalizer with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// Filter `center` is in Hz and `gain` is amplitude gain. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dbell_hz( + shape: S, + center: F, + q: F, + gain: F, +) -> An, S>> { + let mut filter = FixedDirtyBiquad::new(BellBiquad::new(), shape); + filter.set_center_q_gain(center, q, gain); + An(filter) +} + +/// Biquad bell equalizer with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Input 3: amplitude gain +/// - Output 0: filtered audio +pub fn fbell(shape: S) -> An, S>> { + An(FbBiquad::new(BellBiquad::new(), shape)) +} + +/// Biquad bell equalizer with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// Filter `center` is in Hz and `gain` is amplitude gain. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn fbell_hz( + shape: S, + center: F, + q: F, + gain: F, +) -> An, S>> { + let mut filter = FixedFbBiquad::new(BellBiquad::new(), shape); + filter.set_center_q_gain(center, q, gain); + An(filter) +} + +/// Biquad highpass with nonlinear state shaping using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn dhighpass(shape: S) -> An, S>> { + An(DirtyBiquad::new(HighpassBiquad::new(), shape)) +} + +/// Biquad highpass with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dhighpass_hz( + shape: S, + cutoff: F, + q: F, +) -> An, S>> { + let mut filter = FixedDirtyBiquad::new(HighpassBiquad::new(), shape); + filter.set_center_q(cutoff, q); + An(filter) +} + +/// Biquad highpass with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn fhighpass(shape: S) -> An, S>> { + An(FbBiquad::new(HighpassBiquad::new(), shape)) +} + +/// Biquad highpass with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn fhighpass_hz( + shape: S, + cutoff: F, + q: F, +) -> An, S>> { + let mut filter = FixedFbBiquad::new(HighpassBiquad::new(), shape); + filter.set_center_q(cutoff, q); + An(filter) +} + +/// Biquad lowpass with nonlinear state shaping using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn dlowpass(shape: S) -> An, S>> { + An(DirtyBiquad::new(LowpassBiquad::new(), shape)) +} + +/// Biquad lowpass with nonlinear state shaping with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn dlowpass_hz( + shape: S, + cutoff: F, + q: F, +) -> An, S>> { + let mut filter = FixedDirtyBiquad::new(LowpassBiquad::new(), shape); + filter.set_center_q(cutoff, q); + An(filter) +} + +/// Biquad lowpass with nonlinear feedback using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Input 1: cutoff frequency (Hz) +/// - Input 2: Q +/// - Output 0: filtered audio +pub fn flowpass(shape: S) -> An, S>> { + An(FbBiquad::new(LowpassBiquad::new(), shape)) +} + +/// Biquad lowpass with nonlinear feedback with fixed parameters, using waveshaper `shape`. +/// The filter is stable when `shape` is nonexpansive. +/// (The usual waveshapes are nonexpansive up to hardness 1.0). +/// - Input 0: audio +/// - Output 0: filtered audio +pub fn flowpass_hz( + shape: S, + cutoff: F, + q: F, +) -> An, S>> { + let mut filter = FixedFbBiquad::new(LowpassBiquad::new(), shape); + filter.set_center_q(cutoff, q); + An(filter) +} + /// Biquad resonator with nonlinear state shaping using waveshaper `shape`. /// The filter is stable when `shape` is nonexpansive. /// (The usual waveshapes are nonexpansive up to hardness 1.0). /// - Input 0: audio -/// - Input 1: center frequency +/// - Input 1: center frequency (Hz) /// - Input 2: Q /// - Output 0: filtered audio pub fn dresonator(shape: S) -> An, S>> { @@ -2893,7 +3055,7 @@ pub fn dresonator_hz( /// The filter is stable when `shape` is nonexpansive. /// (The usual waveshapes are nonexpansive up to hardness 1.0). /// - Input 0: audio -/// - Input 1: center frequency +/// - Input 1: center frequency (Hz) /// - Input 2: Q /// - Output 0: filtered audio pub fn fresonator(shape: S) -> An, S>> {