GEQ Module Design (geq_v1)
概述
geq_v1 是多通道图形均衡器(Graphic/Parametric EQ),每通道最多 50 个 biquad 滤波器频段,支持实时频响曲线可视化和拖拽控制。
参数
| 参数 ID | 类型 | 范围 | 默认值 | 说明 |
|---|---|---|---|---|
enable |
bool | - | true | 模块启用/禁用 |
bandsPerChannel |
int | 1~50 | 5 | 每通道频段数 |
bandType#${b}#${ch} |
enum | LP/HP/PK/LSV/HSV | PK | 第b频段第ch通道的滤波器类型 |
bandFreq#${b}#${ch} |
float | 20~20000 Hz | 1000 Hz | 中心/截止频率 |
bandGain#${b}#${ch} |
float | -24~24 dB | 0 dB | 频段增益(LP/HP 无效) |
bandQ#${b}#${ch} |
float | 0.1~20 | 0.707 | 品质因数(带宽) |
滤波器类型
| 类型 | 说明 | Gain 有效 |
|---|---|---|
| LP | 低通滤波器 | 否 |
| HP | 高通滤波器 | 否 |
| PK | 峰值(Peaking EQ) | 是 |
| LSV | 低频搁架(Low Shelf) | 是 |
| HSV | 高频搁架(High Shelf) | 是 |
频率响应计算(Biquad)
基于 Audio EQ Cookbook(Robert Bristow-Johnson)的双二阶滤波器公式:
// 核心传递函数(z变换):
// H(z) = (b0 + b1*z^-1 + b2*z^-2) / (1 + a1*z^-1 + a2*z^-2)
// 频率响应幅度(dB):
// |H(e^jw)|_dB = 10 * log10(|numerator|^2 / |denominator|^2)
// 其中 e^jw = cos(w) + j*sin(w),w = 2π*f/fs
纯 JavaScript 计算(无需 AudioContext),可在任意环境运行。
Canvas 可视化
- 尺寸:640×220 px
- X 轴:20 Hz ~ 20 kHz(对数刻度)
- Y 轴:±30 dB(线性刻度)
- 频率采样点:512 个
- 总频响 = 所有 band dB 叠加
拖拽交互
| 操作 | 效果 |
|---|---|
| 点击 band 控制点 | 选中该 band(高亮显示) |
| 拖拽 X | 更新 bandFreq(对数映射) |
| 拖拽 Y(PK/LSV/HSV) | 更新 bandGain |
| 拖拽 Y(LP/HP) | 更新 bandQ(上方→大Q,下方→小Q) |
坐标映射
// 频率 → X 坐标(对数)
freqToX(f) = log10(f / 20) / log10(1000) * width
// X 坐标 → 频率
xToFreq(x) = 20 * 1000^(x / width)
// dB → Y 坐标
dbToY(db) = height - ((db - minDb) / (maxDb - minDb)) * height
// Y 坐标 → dB
yToDb(y) = minDb + (1 - y/height) * (maxDb - minDb)
通道联动(per-band)
linkedChannelsPerBand = Map<bandIdx, Set<chIdx>>- 修改 Band B 的参数时,自动同步到联动 Set 中的所有通道
- 每行右侧 [🔗N] 按钮点击打开通道选择 popover
- 视觉标记:按钮颜色高亮,显示联动通道数
UI 布局
[标题] [关闭]
[CH1 CH2 ... CH20 Tab] [Band 数: 5]
┌─────────────────────────────────────┐
│ Canvas 640×220 (频响曲线 + 控制点) │
├─────────────────────────────────────┤
│ Band │ 类型 │ 频率 │ 增益 │ Q值 │链路│
│ 1 │[PK▼] │[1000] │[ 0.0]│[0.71]│[🔗]│
│ 2 │[LP▼] │[8000] │[N/A ]│[0.71]│[🔗]│
└─────────────────────────────────────┘
持久化
linkStore.setParamValue(instanceId, `bandType#${b}#${ch}`, 'PK')
linkStore.setParamValue(instanceId, `bandFreq#${b}#${ch}`, 1000)
linkStore.setParamValue(instanceId, `bandGain#${b}#${ch}`, 0)
linkStore.setParamValue(instanceId, `bandQ#${b}#${ch}`, 0.707)
linkStore.setParamValue(instanceId, 'bandsPerChannel', 5)
DSP 内存布局
| Offset | Size | 说明 |
|---|---|---|
| 0 | 1 | enable |
| 1 | 4 | bandsPerChannel |
| 5 | 50×20×4×4 | band params (type, freq, gain, Q) × 20ch × 50bands |
Total: 16005 bytes(满配 50 bands × 20 ch)
实际用量 = bandsPerChannel × 20 × 16 bytes