Expand description
IIR and FIR filter library for audio processing.
This crate provides digital filter implementations for audio signal processing, including biquad IIR filters and FIR filters. The filters are designed for parametric equalization and audio processing applications.
§Features
- Biquad IIR filters: Peak, Lowpass, Highpass, Lowshelf, Highshelf, Bandpass, Notch
- FIR filters: Windowed sinc filters with various window types
- Frequency response computation: For both IIR and FIR filters
- Multiple output formats: APO, RME, AU Preset
§Example
use math_audio_iir_fir::{Biquad, BiquadFilterType, SRATE};
// Create a peak filter at 1kHz with Q=2 and +3dB gain
let filter = Biquad::new(BiquadFilterType::Peak, 1000.0, SRATE, 2.0, 3.0);
// Get the frequency response at 1kHz (in dB)
let response_db = filter.log_result(1000.0);
assert!((response_db - 3.0).abs() < 0.1);§IIR & FIR Filters
This crate provides IIR (Infinite Impulse Response) filter implementations for audio equalization.
§Features
- Biquad Filters: Implementation of common biquad filter types
- Low-pass filters
- High-pass filters
- Peak/notch filters
- Low/high shelf filters
- Band-pass filters
- PEQ (Parametric Equalizer): Multi-band parametric equalization with advanced features
- SPL response computation
- Preamp gain calculation
- EqualizerAPO format export
- PEQ comparison and manipulation
- Filter Design: Specialized filter design algorithms
- Butterworth filters (lowpass/highpass)
- Linkwitz-Riley filters (lowpass/highpass)
- Response Computation: Calculate frequency and phase response
- Filter Conversion: Convert between different filter representations
§Filter Types
§Biquad Filter Types
BiquadFilterType::Lowpass: Low-pass filterBiquadFilterType::Highpass: High-pass filterBiquadFilterType::HighpassVariableQ: High-pass filter with variable QBiquadFilterType::Bandpass: Band-pass filterBiquadFilterType::Peak: Peak/parametric filterBiquadFilterType::Notch: Notch filterBiquadFilterType::Lowshelf: Low-shelf filterBiquadFilterType::Highshelf: High-shelf filter
§Usage Examples
§Basic Biquad Filter
use math_audio_iir_fir::{Biquad, BiquadFilterType};
// Create a peak filter at 1kHz with Q=1.0 and 3dB gain
let filter = Biquad::new(
BiquadFilterType::Peak,
1000.0, // frequency
48000.0, // sample rate
1.0, // Q factor
3.0 // gain in dB
);
// Apply filter to audio samples (requires mut for state updates)
// let mut filter = Biquad::new(...); // <- use mut if processing samples
// let output = filter.process(input_sample);
// Calculate frequency response at 1kHz
let response_db = filter.log_result(1000.0);
print!("Response at 1kHz: {:.2} dB", response_db);§Parametric EQ (PEQ)
use math_audio_iir_fir::{Biquad, BiquadFilterType, Peq, peq_spl, peq_preamp_gain, peq_format_apo};
use ndarray::Array1;
// Create a multi-band EQ
let mut peq: Peq = Vec::new();
// Add a high-pass filter at 80Hz
let hp = Biquad::new(BiquadFilterType::Highpass, 80.0, 48000.0, 0.707, 0.0);
peq.push((1.0, hp));
// Add a peak filter to boost mids at 1kHz
let peak = Biquad::new(BiquadFilterType::Peak, 1000.0, 48000.0, 1.5, 4.0);
peq.push((1.0, peak));
// Add a high-shelf to roll off highs
let hs = Biquad::new(BiquadFilterType::Highshelf, 8000.0, 48000.0, 0.8, -2.0);
peq.push((1.0, hs));
// Calculate frequency response
let freqs = Array1::logspace(10.0, 20.0_f64.log10(), 20000.0_f64.log10(), 1000);
let response = peq_spl(&freqs, &peq);
// Calculate preamp gain to prevent clipping
let preamp = peq_preamp_gain(&peq);
print!("Recommended preamp: {:.1} dB", preamp);
// Export to EqualizerAPO format
let apo_config = peq_format_apo("My Custom EQ", &peq);
print!("{}", apo_config);§Filter Design
use math_audio_iir_fir::{peq_butterworth_lowpass, peq_linkwitzriley_highpass};
// Create a 4th-order Butterworth lowpass at 2kHz
let lp_filter = peq_butterworth_lowpass(4, 2000.0, 48000.0);
print!("Butterworth LP has {} sections", lp_filter.len());
// Create a 4th-order Linkwitz-Riley highpass at 2kHz
let hp_filter = peq_linkwitzriley_highpass(4, 2000.0, 48000.0);
print!("LR HP has {} sections", hp_filter.len());
// These can be used for crossover design§PEQ Functions Reference
§Core PEQ Operations
peq_spl(freq, peq): Calculate SPL response across frequenciespeq_equal(left, right): Compare two PEQs for equalitypeq_preamp_gain(peq): Calculate recommended preamp gainpeq_preamp_gain_max(peq): Calculate conservative preamp gain with safety marginpeq_format_apo(comment, peq): Export PEQ to EqualizerAPO format
§Filter Design Functions
peq_butterworth_q(order): Calculate Q values for Butterworth filterspeq_butterworth_lowpass(order, freq, srate): Create Butterworth lowpass filterpeq_butterworth_highpass(order, freq, srate): Create Butterworth highpass filterpeq_linkwitzriley_q(order): Calculate Q values for Linkwitz-Riley filterspeq_linkwitzriley_lowpass(order, freq, srate): Create Linkwitz-Riley lowpass filterpeq_linkwitzriley_highpass(order, freq, srate): Create Linkwitz-Riley highpass filter
§Utility Functions
bw2q(bw): Convert bandwidth in octaves to Q factorq2bw(q): Convert Q factor to bandwidth in octaves
§Advanced Example: Building a Complete Audio Processor
use math_audio_iir_fir::*;
use ndarray::Array1;
fn create_studio_eq() -> Peq {
let mut peq = Vec::new();
// High-pass filter to remove subsonic content
let hp = peq_butterworth_highpass(2, 20.0, 48000.0);
peq.extend(hp);
// Presence boost
let presence = Biquad::new(BiquadFilterType::Peak, 3000.0, 48000.0, 1.2, 2.5);
peq.push((1.0, presence));
// Air band enhancement
let air = Biquad::new(BiquadFilterType::Highshelf, 10000.0, 48000.0, 0.9, 1.5);
peq.push((1.0, air));
peq
}
fn analyze_eq(peq: &Peq) {
// Generate frequency sweep
let freqs = Array1::logspace(10.0, 20.0_f64.log10(), 20000.0_f64.log10(), 200);
// Calculate response
let response = peq_spl(&freqs, peq);
// Find peak response
let max_gain = response.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
let min_gain = response.iter().fold(f64::INFINITY, |a, &b| a.min(b));
println!("EQ Analysis:");
println!(" Peak gain: {:.2} dB", max_gain);
println!(" Min gain: {:.2} dB", min_gain);
println!(" Dynamic range: {:.2} dB", max_gain - min_gain);
println!(" Recommended preamp: {:.2} dB", peq_preamp_gain(peq));
}
fn main() {
let studio_eq = create_studio_eq();
analyze_eq(&studio_eq);
// Export for use in EqualizerAPO
let config = peq_format_apo("Studio EQ v1.0", &studio_eq);
println!("\nEqualizerAPO Configuration:");
println!("{}", config);
}§Key Concepts
§PEQ Type
The Peq type is defined as Vec<(f64, Biquad)> where:
- The
f64is the weight/amplitude multiplier for each filter - The
Biquadis the individual filter definition - This allows for flexible filter chaining and weighting
§Filter Order vs. Sections
- Butterworth filters: An Nth-order filter uses N/2 biquad sections (rounded up)
- Linkwitz-Riley filters: Special case of Butterworth designed for crossovers
- Higher orders provide steeper rolloff but more computational cost
§Q Factor Guidelines
- Q < 0.5: Wide, gentle curves
- Q = 0.707: Butterworth response (maximally flat)
- Q = 1.0: Good compromise for most applications
- Q > 5: Very narrow, surgical corrections
- Q > 10: Extreme precision, potential ringing
§Fast PEQ Loudness Compensation
§Overview
When applying parametric EQ (PEQ) to audio, the spectral balance and perceived loudness changes. This document describes how to use the fast loudness compensation feature to maintain similar loudness without running full Replay Gain analysis.
§The Problem
Traditional approach (slow):
- Apply PEQ filters to audio
- Run full Replay Gain analysis (EBU R128)
- Decode entire audio file
- Process all samples through loudness meter
- Takes seconds for each file
§The Solution
Fast analytical approach (microseconds):
- Analyze PEQ frequency response
- Apply perceptual weighting (K-weighting or A-weighting)
- Compute loudness change analytically
- Takes microseconds, no audio processing needed
§API Usage
§Basic Example
use math_audio_iir_fir::{Biquad, BiquadFilterType, Peq, peq_loudness_gain, peq_preamp_gain};
// Create your PEQ filters
let bass_boost = Biquad::new(BiquadFilterType::Peak, 100.0, 48000.0, 1.0, 6.0);
let peq: Peq = vec![(1.0, bass_boost)];
// Get gain adjustments
let anti_clip = peq_preamp_gain(&peq); // Prevents clipping: -6.00 dB
let loudness_k = peq_loudness_gain(&peq, "k"); // K-weighted: -1.40 dB
let loudness_a = peq_loudness_gain(&peq, "a"); // A-weighted: -0.06 dB
// Apply to your audio pipeline:
// total_gain = anti_clip + loudness_k // or use loudness_a§Choosing Weighting Method
K-weighting ("k"):
- Based on EBU R128 standard
- Similar to how Replay Gain works
- Better for general music playback
- Recommended for most use cases
A-weighting ("a"):
- Classic loudness measurement
- Emphasizes mid-range, de-emphasizes bass
- Better for voice/speech content
- More tolerant of bass boost
§Real-World Examples
From the test output:
-
Mid-range boost (+6 dB at 1 kHz):
- K-weighted: -1.55 dB (compensate by reducing 1.55 dB)
- A-weighted: -1.36 dB
- Effect: Similar compensation since 1kHz is important in both curves
-
Bass boost (+6 dB at 100 Hz):
- K-weighted: -1.40 dB
- A-weighted: -0.06 dB
- Effect: A-weighting barely compensates (bass less important perceptually)
-
Treble boost (+6 dB at 8 kHz):
- K-weighted: -2.40 dB
- A-weighted: -0.99 dB
- Effect: K-weighting has high-frequency boost, so more compensation needed
-
V-shaped EQ (bass+4dB, mid-3dB, treble+3dB):
- K-weighted: -1.76 dB
- A-weighted: +0.14 dB (slight boost!)
- Effect: A-weighting sees net reduction in important frequencies
§Integration with Audio Pipeline
§Option 1: Combine with Anti-Clipping
// Safest: prevent clipping AND maintain loudness
let total_gain = peq_preamp_gain(&peq) + peq_loudness_gain(&peq, "k");
// Apply PEQ filters + total_gain to audio§Option 2: Loudness Compensation Only
// If you know your PEQ won't clip (e.g., cuts only)
let total_gain = peq_loudness_gain(&peq, "k");
// Apply PEQ filters + total_gain to audio§Option 3: Use with CamillaDSP
# In your CamillaDSP config:
filters:
peq_with_compensation:
type: Conv
parameters:
# ... your PEQ biquads ...
- type: Gain
parameters:
gain: -1.55 # from peq_loudness_gain()§Performance Comparison
| Method | Time per file | Requires audio? | Accuracy |
|---|---|---|---|
| Replay Gain (EBU R128) | 1-10 seconds | Yes | 100% (reference) |
| peq_loudness_gain() | < 1 millisecond | No | ~90-95% |
The analytical method is 1000x faster while providing good perceptual accuracy.
§When to Use Each Method
§Use peq_loudness_gain() when:
- Real-time EQ adjustment
- Previewing EQ changes
- Batch processing many files
- Interactive audio applications
- You want instant results
§Use full Replay Gain when:
- Normalizing existing audio files
- Maximum accuracy required
- One-time analysis acceptable
- Working with non-EQ’d audio
§Technical Details
§How It Works
- Generate 500 logarithmically-spaced frequency points (20 Hz - 20 kHz)
- Compute PEQ frequency response at each point
- Apply perceptual weighting curve (K or A)
- Integrate weighted energy change
- Convert to dB gain compensation
§Weighting Curves
K-weighting approximation:
- High-pass: 4th order Butterworth at 38 Hz
- High-shelf: +4 dB above 1500 Hz
A-weighting (IEC 61672-1):
- Follows standard A-weighting formula
- Peak sensitivity ~4 kHz
- -19 dB at 100 Hz, -9 dB at 500 Hz
§Limitations
- Assumes broadband audio: Works best with music/speech, not pure tones
- Ignores phase: Only analyzes magnitude response
- Approximation: Not identical to sample-by-sample EBU R128
- No masking effects: Doesn’t model psychoacoustic masking
Despite these limitations, the method provides good perceptual accuracy for practical use.
§Future Improvements
Potential enhancements:
- More accurate K-weighting filter implementation
- Support for custom weighting curves
- Integration with audio file metadata
- Automatic weighting selection based on content type
§See Also
src-iir/src/mod.rs: Implementationsrc-audio/src/replaygain.rs: Full Replay Gain implementation- EBU R128 standard: https://tech.ebu.ch/docs/r/r128.pdf
- A-weighting standard: IEC 61672-1
§License
GPL-3.0-or-later
Modules§
- denormals
- Utilities for handling floating-point denormals (subnormals).
Structs§
- Biquad
- Represents a single biquad IIR filter.
- Filter
Row - Represents a single filter in a parametric equalizer.
- Fir
- Represents a single FIR filter.
- FirDesign
Config - Configuration for FIR filter generation
Enums§
- Biquad
Filter Type - Filter types for biquad filters
- FirFilter
Type - FIR filter types
- FirPhase
- Phase type for FIR generation
- IirError
- Errors that can occur during IIR filter operations.
- Window
Type - Window function types for FIR filter design
Constants§
- DEFAULT_
Q_ HIGH_ LOW_ PASS - Default Q factor for high/low pass filters
- DEFAULT_
Q_ HIGH_ LOW_ SHELF - Default Q factor for high/low shelf filters
- SRATE
- Sample rate constant (matching Python SRATE)
Functions§
- bw2q
- Converts bandwidth in octaves to a Q factor.
- compute_
fir_ bank_ response - Compute the combined FIR bank response (in dB) on a given frequency grid.
- compute_
peq_ response - Compute the combined PEQ response (in dB) on a given frequency grid for a Peq.
- fir_
bank_ preamp_ gain - Calculate the recommended preamp gain to avoid clipping for a FIR bank.
- fir_
bank_ spl - Compute the FIR bank SPL response at given frequencies.
- generate_
fir_ from_ response - Generate an FIR filter to match a target frequency response
- generate_
kirkeby_ correction - Generate Kirkeby regularized FIR correction filter
- generate_
window - Generates a window function for FIR filter design.
- interpolate_
phase_ complex - Interpolate phase in the complex domain to avoid wrap artifacts
- peq_
butterworth_ highpass - Create Butterworth highpass filter
- peq_
butterworth_ lowpass - Create Butterworth lowpass filter
- peq_
butterworth_ q - Compute Q values for Butterworth filters
- peq_
equal - Check if two PEQs are equal
- peq_
format_ apo - Format PEQ as APO configuration string
- peq_
format_ aupreset - Format PEQ as Apple AUNBandEQ preset (aupreset) plist XML
- peq_
format_ rme_ channel - Format PEQ as RME TotalMix channel preset XML
- peq_
format_ rme_ room - Format PEQ as RME TotalMix room EQ preset XML (dual channel)
- peq_
linkwitzriley_ highpass - Create Linkwitz-Riley highpass filter
- peq_
linkwitzriley_ lowpass - Create Linkwitz-Riley lowpass filter
- peq_
linkwitzriley_ q - Compute Q values for Linkwitz-Riley filters
- peq_
loudness_ gain - Compute loudness-weighted gain adjustment for PEQ to maintain spectral balance
- peq_
preamp_ gain - Compute preamp gain for a PEQ: well adapted to computers
- peq_
preamp_ gain_ max - Compute preamp gain for a PEQ and look at the worst case
- peq_
print - Print a formatted table of the parametric EQ filters from a Peq.
- peq_spl
- Compute SPL for each frequency given a PEQ
- q2bw
- Converts a Q factor to bandwidth in octaves.
- save_
fir_ to_ wav - Save FIR coefficients to a WAV file (32-bit float mono)
- smooth_
phase_ via_ group_ delay - Smooth phase via group delay smoothing
- unwrap_
phase - Unwrap phase by removing 2π discontinuities