Fix pre-existing compilation failures in four test call sites that were
missing the wfm_denoise: bool argument added to ChannelDsp::new() and
SdrPipeline::start().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
- Raise audio LPF cutoff from 15 kHz to 17 kHz to pass full FM stereo
audio bandwidth without excessive HF rolloff
- Replace 2-point linear interpolation resampler with 4-point Hermite
cubic spline for a much flatter passband up to 17 kHz
- Add FM discriminator gain normalization (fm_gain = fs / 150000) so
±75 kHz deviation maps to ±1.0 regardless of composite sample rate,
stabilizing stereo carrier amplitude reconstruction
- Double pilot PLL proportional (0.0015→0.003) and integral
(0.00002→0.00005) gains for faster lock and better tracking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
The 19 kHz pilot notch was applied only to the L+R sum path, introducing
~22° of phase shift at 15 kHz relative to the L-R diff path. This phase
mismatch caused interchannel crosstalk (≈ −14 dB separation at 15 kHz).
Fix: remove the notch from the sum processing chain so both sum and diff
pass through identical 4th-order Butterworth LPFs, giving phase-coherent
demodulation across the full audio band. The notch is relocated to the
mono output branch where phase alignment with the diff channel is not
required. Pilot rejection on the stereo L/R outputs is still adequate
(~28 dB) from the combined LPF + deemphasis response at 19 kHz.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Add a server-side toggle for the multiband stereo denoiser so it can be
enabled or disabled at runtime without restarting the server.
Backend (trx-backend-soapysdr):
- Add `denoise_enabled: bool` to `WfmStereoDecoder`; gate multiband
blend behind it (falls back to uniform single-band blend when off)
- Add `set_denoise_enabled()` method on `WfmStereoDecoder`
- Propagate `wfm_denoise: bool` through `ChannelDsp`, `SdrPipeline`,
and `SoapySdrRig`; add `set_wfm_denoise()` at each layer
- Include `wfm_denoise` in `filter_state()` so it flows into snapshots
Protocol / core (trx-core, trx-protocol, trx-server):
- Add `SetWfmDenoise(bool)` to `RigCommand` and `ClientCommand`
- Add default `set_wfm_denoise()` trait method to `RigCat`
- Handle `SetWfmDenoise` in `rig_task.rs` and update `RigFilterState`
- Add `wfm_denoise: bool` (default `true`) to `RigFilterState`
Frontend (trx-frontend-http):
- Add `POST /toggle_wfm_denoise` endpoint
- Add "Denoise On/Off" button next to the stereo/mono audio picker
- Sync button state from SSE filter snapshot (`update.filter.wfm_denoise`)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Split the L-R diff channel into three frequency bands at audio rate and
apply SNR-weighted blending per band driven by pilot magnitude:
- 0–2 kHz: blend¹ (most stereo — low frequencies have best SNR)
- 2–8 kHz: blend² (moderate noise reduction)
- 8–15 kHz: blend⁴ (aggressive noise reduction — hiss-prone range)
Move blend from composite rate to audio rate so the crossover filters
(2nd-order Butterworth at 2 kHz and 8 kHz) operate at 48 kHz and the
pilot blend is linearly interpolated per audio sample for smooth
transitions. Unblended diff is now stored in prev_diff; prev_blend
tracks the blend value for the same interpolation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>