You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(audio): v26.5.3 — PAPR processor, split-band de-esser, peak hold (aethersdr#3024)
## Summary
Three threads landed together. The de-esser fix is the
**release-critical** part (multiple operators reporting RMS /
forward-power loss vs SmartSDR — root-caused to this stage). The PAPR
processor (aethersdr#2887) and the meter-UI polish came along for the ride during
the same bench session.
Bumps version to **26.5.3**.
## The de-esser bug (release-critical)
`ClientDeEss::process()` was applying its sidechain-derived gain
reduction to the **full signal** every time HF energy crossed threshold:
```cpp
// OLD — broadband attenuation when sibilance triggers:
l *= gainLin;
r *= gainLin;
```
So every S / T / F phoneme pulled lows and mids down alongside the
highs, crashing RMS. SmartSDR doesn't have this stage at all, which is
why operators saw lower average power on AetherSDR than SmartSDR at the
same drive setting (Antonio D'Arpino's report on the AetherSDR Users
Group, plus matching symptoms from others).
**Fix**: split-band topology — `output = full + bandpass × (gain − 1)`.
The bandpass acts as both the sidechain detector and the slice to
attenuate; lows and mids pass through unchanged.
Also adds:
- **Cascaded biquads** (1–4 stages) so the user can dial slope from 12 →
24 → 36 → 48 dB/oct via a new toggle in the de-esser panel. Default 24
dB/oct (2 stages). Narrower notch = less mid-band collateral on
Ess-heavy phrases.
- AppSettings persistence: `ClientDeEssTxSlopeStages` /
`ClientDeEssRxSlopeStages`.
## PAPR processor (aethersdr#2887)
New **ClientPhaseRotator** module — cascade of all-pass biquads that
symmetrizes asymmetric voice peaks before downstream
compression/limiting, so the clipping work produces primarily odd-order
(musical) harmonics instead of even-order (buzzy) ones.
Embedded inside **ClientComp** as a private member, exposed via two new
controls in the comp panel:
- **Drive** (0..18 dB) — pre-gain into the comp threshold. Pushes more
material across the curve so the comp engages harder, lifting RMS.
- **Phase** (0..6 stages) — pre-comp rotator stage count.
The per-sample gain auto-tracks Drive (`gainLin = curve × makeup ×
driveLin`), so Drive doesn't fight the comp's natural GR response — same
model as broadcast Optimod. Drive and Phase apply regardless of the
comp's chain-bypass state.
Bench result: with Drive +9 dB / Phase 4 stg, CRST drops from ~12 dB to
~8 dB cleanly, peaks pegged at the limiter ceiling, no audible squash.
## UI polish
- **Comp GR + Out meters** — now render THRESH-style tick columns
(Left/Right) and a right-anchored dB-value footer, so all three vertical
meters in the comp editor read with one visual vocabulary.
- **Final Output Stage peak-hold toggle** — latches PK/RMS/GR
worst-case-since-engaged for capturing burst maxima. CRST always tracks
live so adjustments visibly land in real time.
- **10 Hz numeric-readout throttle** — new shared
`kMeterReadoutUpdateMs` constant in `MeterSmoother.h`. Applied to Final
Output Stage, comp GR/Out meters, Tube OUT meter, and RX chain output
stage. Bars still animate at 125 Hz, only text setText is gated to 10 Hz
so digits are readable.
## Stats
- 22 files changed, +898 / −50
- 2 new source files (`ClientPhaseRotator.{h,cpp}`)
- DSP changes covered by manual hardware test (Jeremy KK7GWY's bench)
- No new tests added for the new DSPs — should follow up in a Phase 2 PR
## Test plan
- [x] Clean build, 0 errors
- [x] Manual: Drive 0..+18 dB lifts RMS as expected, GR meter responds
- [x] Manual: Phase toggle audibly clean under heavy Drive
- [x] Manual: De-esser no longer crashes RMS on sibilant phrases
- [x] Manual: Slope toggle cycles 12 → 24 → 36 → 48 dB/oct
- [x] Manual: Peak hold latches worst-case; CRST tracks live
- [x] Manual: Meter readouts readable at 10 Hz, bars smooth at 125 Hz
- [ ] CI: build, check-paths, check-windows green before merge
## Operator workaround for pre-v26.5.3 builds
For anyone on v26.5.2 hitting the de-esser bug: **disable the DESS
card** in the channel strip CHAIN row (single click to bypass). Forward
power should recover immediately. v26.5.3 makes the fix permanent.
Closesaethersdr#2887.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments