Last active
May 1, 2025 05:19
-
-
Save sletz/70d4a6b54e7c3336c3c207184d9fcdbe to your computer and use it in GitHub Desktop.
Decramped peak filter algorithm in Faust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import("stdfaust.lib"); | |
| // ============================================================================= | |
| // Decramped Peaking EQ Filter (Second Order Biquad) | |
| // Based on the Audio EQ Cookbook by Robert Bristow-Johnson | |
| // https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html | |
| // | |
| // This implementation uses the standard RBJ formulas which inherently | |
| // account for frequency warping (i.e., they are "decramped"). | |
| // ============================================================================= | |
| peak_eq_decramped(fc, gain_db, q) = filter with { | |
| // Filter parameters and intermediate variables | |
| // Intermediate calculations based on RBJ formulas | |
| A = pow(10.0, gain_db / 40.0); // Amplitude ratio from dB gain | |
| // Note: /40 for peaking EQ, /20 for shelving | |
| omega = 2.0 * ma.PI * fc / ma.SR; // Angular frequency (radians/sample) | |
| // Pre-warping is implicitly handled by using tan() in alpha calc via sin/cos | |
| // Alpha determines the filter bandwidth/Q shape | |
| alpha = sin(omega) / (2.0 * q); | |
| // --- Calculate Filter Coefficients --- | |
| // Coefficients derived from RBJ's Peaking EQ formulas | |
| // Numerator coefficients (b) | |
| b0 = 1.0 + alpha * A; | |
| b1 = -2.0 * cos(omega); | |
| b2 = 1.0 - alpha * A; | |
| // Denominator coefficients (a) | |
| // a0 is the normalization factor | |
| a0 = 1.0 + alpha / A; | |
| a1 = -2.0 * cos(omega); // Same as b1 | |
| a2 = 1.0 - alpha / A; | |
| // --- Normalization --- | |
| // Divide all coefficients by a0 to get the standard biquad form | |
| // where the coefficient for y[n] is 1. | |
| // Add small epsilon to prevent division by zero if A is extremely small (large cut) | |
| // or if alpha is zero (fc=0 or fc=SR/2). | |
| a0_safe = max(ma.EPSILON, a0); // Use machine epsilon as the floor | |
| norm_b0 = b0 / a0_safe; | |
| norm_b1 = b1 / a0_safe; | |
| norm_b2 = b2 / a0_safe; | |
| norm_a1 = a1 / a0_safe; // Note: tf2 expects the negated coefficients a1, a2 | |
| // but the RBJ formulas directly give these negated versions | |
| // for the y[n-1], y[n-2] terms. | |
| norm_a2 = a2 / a0_safe; // So we use them directly here. | |
| // --- Filter Implementation --- | |
| // Use Faust's built-in second-order IIR filter (biquad) function | |
| // tf2(b0, b1, b2, a1, a2) implements: | |
| // y(n) = b0*x(n) + b1*x(n-1) + b2*x(n-2) - a1*y(n-1) - a2*y(n-2) | |
| filter = fi.tf2(norm_b0, norm_b1, norm_b2, norm_a1, norm_a2); | |
| }; | |
| // ============================================================================= | |
| // User Interface and Processing Block | |
| // ============================================================================= | |
| // --- UI Controls --- | |
| freq = hslider("peakF [unit:Hz] [style:log]", 1000, 20, 20000, 1) : si.smoo; | |
| gain_db = hslider("peakGain [unit:dB]", 0, -24, 24, 0.1) : si.smoo; | |
| q = hslider("peakQ [style:log]", 1.0, 0.1, 18, 0.01) : si.smoo; | |
| // --- Processing --- | |
| // Apply the decramped peak EQ filter to the stereo input signal | |
| process = peak_eq_decramped(freq, gain_db, q); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment