Skip to content

feat: add 16-band graphic EQ stage#209

Merged
OpenSauce merged 4 commits intomainfrom
feat/graphic-eq
Mar 1, 2026
Merged

feat: add 16-band graphic EQ stage#209
OpenSauce merged 4 commits intomainfrom
feat/graphic-eq

Conversation

@OpenSauce
Copy link
Owner

@OpenSauce OpenSauce commented Mar 1, 2026

Summary

  • Adds a 16-band graphic equalizer (25 Hz – 20 kHz) as an Effect stage
  • Uses cascaded biquad peaking filters (Direct Form 1) with Audio EQ Cookbook coefficients
  • f64 internal precision prevents numerical instability at low frequencies under high oversampling
  • New labeled_vertical_slider reusable widget for the 16-fader UI
  • 12 unit tests covering stability, correctness, and edge cases (extreme gain + 16x oversampling)

Closes #112

Test plan

  • make lint passes (clippy pedantic + nursery, formatting)
  • make test passes (82 unit + 6 integration tests)
  • Manual: add Graphic EQ from Effects tab, adjust all 16 faders, verify audio
  • Manual: set 25 Hz band to -12 dB with oversampling enabled, verify no rumbling/crash
  • Manual: save/load preset with EQ settings, verify persistence

16-band graphic equalizer (25 Hz – 20 kHz) using cascaded biquad peaking
filters with Audio EQ Cookbook coefficients. Uses f64 internal precision
for numerical stability at low frequencies under high oversampling rates.

DSP:
- Direct Form 1 biquads with f64 coefficients and state
- Fixed Q derived from bandwidth (10 octaves / 16 bands ≈ 2.28)
- Nyquist guard, denormal flushing, unity passthrough optimization
- 12 unit tests including stability at extreme gain + 16x oversampling

GUI:
- New labeled_vertical_slider reusable widget
- 16 vertical faders with frequency labels and dB readout
- Full-width centered layout
- i18n: EN "Graphic EQ", ZH_CN "图形均衡器"
- Registered as Effect in stage registry, minimap abbreviation "EQ"
Copilot AI review requested due to automatic review settings March 1, 2026 20:03
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new 16-band Graphic EQ “Effect” stage (DSP + GUI) and wires it into the existing stage registry, minimap, and i18n system.

Changes:

  • Introduces EqStage DSP implementation using cascaded peaking biquads plus unit tests.
  • Adds a new EQ stage UI with 16 vertical faders and a reusable labeled_vertical_slider widget.
  • Registers/translates the new stage (registry entry, minimap abbreviation, EN/ZH_CN strings).

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/amp/stages/eq.rs New DSP EQ stage (biquad cascade) + extensive unit tests
src/amp/stages/mod.rs Exposes the new eq stage module
src/gui/stages/eq.rs New GUI stage view/config/message for the EQ (16 faders)
src/gui/stages/mod.rs Registers the new EQ stage via stage_registry!
src/gui/components/widgets/common.rs Adds reusable labeled_vertical_slider widget
src/gui/components/minimap.rs Adds “EQ” abbreviation for the new stage
src/i18n/mod.rs Adds stage_eq translation key + EN/ZH_CN strings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…r strings

- Use the Audio EQ Cookbook BW-in-octaves alpha formula:
  alpha = sin(w0) * sinh(ln(2)/2 * BW * w0/sin(w0))
  This maintains constant-octave bandwidth for all bands regardless of
  their position relative to Nyquist, fixing the 20 kHz band narrowing
  at 44.1/48 kHz sample rates.
- Export MIN_GAIN_DB/MAX_GAIN_DB from DSP module; GUI uses them for
  slider range and config clamping instead of duplicated literals.
- Fix ambiguous error messages: "0..15" → "0..=15" to clearly
  communicate inclusive bounds.
Reset x1/x2/y1/y2 when entering or leaving unity passthrough mode.
State from a previous filter shape is meaningless to the passthrough
(and vice versa), so retaining it would cause a brief transient click
on the next coefficient change.

For gain-to-gain changes (e.g. +6 dB → +12 dB), state is preserved —
DF1's state variables hold actual signal values that remain meaningful
across coefficient updates, which is why DF1 was chosen over DF2T.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@OpenSauce OpenSauce merged commit 0fa08e8 into main Mar 1, 2026
7 checks passed
@OpenSauce OpenSauce deleted the feat/graphic-eq branch March 1, 2026 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Filter Stage: TPT One Pole Filter & Biquad Filtering

2 participants