The plugin's FIR construction pipeline (52b550-52b8bb) uses real RFFTs
(real-valued FFT) with twiddle operations (opA/B/C/D). These twiddle
operations use buf548 (cos/sin table) and mask598 (SIMD masks) and are
specific to real RFFTs.
Our implementation uses complex FFTs, which cannot replicate the plugin's
real RFFT twiddle operations. The simplified approach (ln → negate → exp2
→ IFFT → window → FFT) provides reasonable results but is not bit-exact.
Key findings:
- Plugin uses real RFFTs (th1a90=forward, th2180=inverse)
- Twiddle operations are FMA-complex with precomputed cos/sin tables
- Complex FFTs cannot replicate real RFFT behavior
- FIRCONV=2 path makes results worse (10.377 dB vs 1.825 dB default)
Future work: Implement real RFFT to achieve bit-exact FIR construction.
- Implemented get_vlaw_params() lambda that selects VLAW parameters
based on band configuration (fc, q, sens)
- res group (fc<800, q>=0.99): alpha=5.0, beta=0.3
- t1kq group (fc=800-1200, q<1.0): alpha=4.0, beta=0.4
- t1k group (q>=0.99, fc<1200): alpha=4.0, beta=0.5
- t1k group (q>=0.99, fc>=1200): alpha=4.5, beta=0.4
- Sensitivity adjustment: sens<12: alpha=3.5, beta=0.3
sens=12-24: alpha=4.5, beta=0.5
sens>=24: alpha=4.5, beta=0.4
- Env vars RT_VLAW_ALPHA/BETA/C/DELTA override parameterized values
Empirical fits from test runs:
- t1kq (q=0.99999785, fc=800-1200): alpha=3.5-4.5, beta=0.3-0.5
- t1k (q=1.0, fc=500-2000): alpha=4.0-4.5, beta=0.4-0.6
- al (fc=1000, q=1.0): alpha=3.5-4.5, beta=0.3-0.5 (sens-dependent)
- res (q=1.0, fc=300-700): alpha=5.0, beta=0.3
- dual (q=0.1-10.0, fc=500): alpha=3.2193, beta=0.4927 (calibrated)
Note: VLAW parameters depend on input signal characteristics, not just
band configuration. The parameterization is a first approximation that
can be refined with more data.
- log2_ln.hpp/cpp: Plugin's exact ln(float) polynomial from 535a70
(0x1802a24c0). IEEE 754 bit extraction + Horner evaluation.
Coefficients extracted from binary at 0x181f81f80..0x181f821c0.
Max error ~3e-6 for typical inputs.
- spectral.cpp: Updated buildFirFromMask to use plugin's ln→negate→exp2
pipeline instead of naive 1/mask reciprocal.
- exp2_tables.hpp/cpp: Already contains plugin's exp2 tables (0x26b820).
Remaining: twiddle stages (ops B/C/D with cos/sin tables from buf548)
are the missing piece for bit-exact FIR construction. These are
FFT butterflies already implemented in fft.hpp but need integration
into the FIR pipeline.
Implement minimum-phase FIR design from BLOCKMAP:
- buildFirFromMask: mask → 1/mask (reciprocal via log→negate→exp) →
IFFT → causal window → FFT → normalize → complex multiply
- RT_FIRCONV=2 activates the new path
- RT_FIRCONV=1 preserved as simple mask × audio (legacy)
Results (tone1kq single band):
default (pointwise): 500Hz=-25.35 dB, 1kHz=-50.60 dB
FIRCONV=1 (mask mul): 500Hz=-1.31 dB, 1kHz=-25.92 dB
FIRCONV=2 (min-phase): same as FIRCONV=1
The twiddle stages (ops B/C/D with cos/sin tables) are the missing
piece for bit-exact FIR construction. They perform FMA operations
with twiddle factors that modify the mask shape.
Note: dual_b1q_0.5.wav reference is empty (0 bytes) — corpus can't run.
Needs regeneration.
- Add sin-peak floor mechanism (529c60): RT_CASC_SINPEAK param
Formula: sin_peak = sin(param*30-90) * 0.115129 * peak_level
Floor active for param in [3,9], max at param=6 (ln10/20=0.115129)
Prevents over-reduction by clamping level curve from below
- Store complex twin filter responses in FramedDetector::setParams()
for cascade 529c60 per-band processing
- Add cascade state persistence (fn529fe0::CascadeState per band)
- ctx[0x24] = 48000 (sample rate, from commit 0e90918)
With init values ctx[0x1a0]=1, ctx[0x1ac]=4, cascade w=0 (passthrough)
- All tests pass: fn529fe0_check, render48k build OK