CrossoverFilter
Tier: Core (Internal Utility) | No ComponentType | No Parameters
Linkwitz-Riley 4th-order (LR4) crossover filter using two cascaded Butterworth 2nd-order biquad sections per output.
Overview
CrossoverFilter splits an input signal into complementary low-frequency and high-frequency bands that sum back to the original signal with flat magnitude response. This is the fundamental building block of the BandSplitter, which chains multiple CrossoverFilters to create multiband processing paths.
The design uses the Linkwitz-Riley 4th-order topology: two cascaded 2nd-order Butterworth filters per output. The Butterworth sections each have \(Q = 1/\sqrt{2} \approx 0.707\), and cascading two of them produces a 4th-order (24 dB/octave) slope with the critical property that \(|H_\text{LP}|^2 + |H_\text{HP}|^2 = 1\) --- the low and high outputs sum to unity power at all frequencies, with no coloration or phase anomalies at the crossover point.
This is an internal utility with no ComponentType, no parameter interface, no snapshot, and no bridge class. It is configured and driven entirely by BandSplitter.
File Locations
| Path | |
|---|---|
| Header | Sources/FolioDSP/include/FolioDSP/Core/CrossoverFilter.h |
| Implementation | Sources/FolioDSP/src/Core/CrossoverFilter.cpp |
| Tests | Tests/FolioDSPTests/CrossoverFilterTests.swift |
API / Interface
namespace folio::dsp {
class CrossoverFilter {
public:
CrossoverFilter() = default;
/// Configure crossover frequency. Must be called before process().
void setCrossoverFrequency(float freq, float sampleRate);
/// Process one sample. Splits input into low and high outputs.
void process(float input, float& lowOut, float& highOut);
/// Reset all internal filter states.
void reset();
private:
Biquad lowpass1_, lowpass2_; // Cascaded for low output
Biquad highpass1_, highpass2_; // Cascaded for high output
};
}
Algorithm
1. Butterworth Biquad Configuration
When setCrossoverFrequency(freq, sampleRate) is called, all four internal Biquad filters are configured at the same frequency with Butterworth Q:
lowpass1_andlowpass2_: both set to Lowpass type at frequency \(f_c\) with \(Q = Q_\text{BW}\)highpass1_andhighpass2_: both set to Highpass type at frequency \(f_c\) with \(Q = Q_\text{BW}\)
Each Biquad implements the Audio EQ Cookbook lowpass/highpass using Direct Form II Transposed. The Butterworth Q produces a maximally-flat passband (no resonance peak).
2. Signal Processing
For each input sample, two cascaded filter chains produce the split outputs:
Each individual Biquad provides a 2nd-order (12 dB/octave) slope. Cascading two produces a 4th-order (24 dB/octave) slope.
3. Linkwitz-Riley Properties
The LR4 crossover has three essential properties:
Unity magnitude sum. At all frequencies:
This means the recombined signal \(y_\text{low} + y_\text{high}\) has perfectly flat magnitude response. No frequency is boosted or attenuated by the splitting process.
-6 dB at crossover. At the crossover frequency \(f_c\):
Each band is at half amplitude at crossover. When summed, the total is 0 dB (not +3 dB as with a Butterworth crossover, which would produce a bump).
In-phase at crossover. Both outputs are in-phase at \(f_c\), so the summation is coherent. The LR4 topology produces an allpass phase response when the two outputs are summed:
where \(A(z)\) is a 4th-order allpass function. The magnitude is exactly 1 at all frequencies; only the phase varies (which is inaudible for a single crossover).
4. Why LR4 (Not Butterworth or Bessel)
| Property | Butterworth Crossover | LR4 Crossover |
|---|---|---|
| Magnitude at \(f_c\) | -3 dB each, +3 dB summed | -6 dB each, 0 dB summed |
| Sum flatness | +3 dB bump at crossover | Perfectly flat |
| Slope | 12 dB/oct (2nd order) | 24 dB/oct (4th order) |
| Phase at crossover | 90 degree offset | In-phase |
The LR4 is the standard for multiband audio processing because it is the lowest-order topology that sums to unity with no magnitude ripple.
5. Transfer Function
A single 2nd-order Butterworth lowpass has the transfer function:
The LR4 low output is the square of this:
Similarly for highpass:
The key identity is:
where \(A(s)\) is a 4th-order allpass.
Implementation Notes
- Depends on Biquad: CrossoverFilter includes
Biquad.hand uses four Biquad instances internally. The Biquad class provides the Audio EQ Cookbook coefficient computation and Direct Form II Transposed processing. - Real-time safe:
process()is four biquad filter operations (8 multiplies, 8 adds, 4 state updates). No allocations, no branches beyond the biquad coefficient computation (which happens only insetCrossoverFrequency, not per-sample). - No interpolation on frequency changes: When
setCrossoverFrequencyis called, all four biquads update their coefficients immediately. BandSplitter is responsible for smoothing crossover frequency changes if needed. - Reset: Clears the internal state of all four biquads, producing silence on both outputs until new input arrives.
- Frequency range: The crossover frequency should be between approximately 20 Hz and \(f_s/2\). The Biquad coefficient computation handles edge cases, but extreme values near Nyquist may produce numerical artifacts.
Used By
| Component | Usage |
|---|---|
| BandSplitter | Chains \(N-1\) CrossoverFilters to split a signal into \(N\) frequency bands (up to 8 bands, 7 crossovers) |