Skip to content

fix: remove stale RADE DSP guards that silenced NR4/NR2/etc. on unrelated pans#2025

Merged
ten9876 merged 1 commit intoten9876:mainfrom
NF0T:fix/rade-dsp-multipan-guards
Apr 26, 2026
Merged

fix: remove stale RADE DSP guards that silenced NR4/NR2/etc. on unrelated pans#2025
ten9876 merged 1 commit intoten9876:mainfrom
NF0T:fix/rade-dsp-multipan-guards

Conversation

@NF0T
Copy link
Copy Markdown
Contributor

@NF0T NF0T commented Apr 26, 2026

Background

This fix was identified during post-merge testing of PR #1953 (dual-buffer RADE
RX architecture). After #1953 landed, multi-pan testing revealed that
client-side DSP (NR4, NR2, RN2, BNR, DFNR, MNR) was completely silenced on any
non-RADE pan while RADE was active — a regression introduced by guards that were
correct before #1953 but became harmful once the dual-buffer design separated
RADE decoded audio from the DSP pipeline entirely.

Problem

In a two-pan setup (Pan A = RADE/FreeDV, Pan B = SSB/CW), engaging NR4 or any
client-side DSP on Pan B had no effect. The UI buttons illuminated correctly,
but the audio pipeline was untouched.

Root Cause

AudioEngine had if (m_radeMode) return; guards at the top of every DSP
setter (setNr4Enabled, setNr2Enabled, setRn2Enabled, setBnrEnabled,
setDfnrEnabled, setMnrEnabled) and a teardown loop in setRadeMode(on=true)
that forcibly disabled all DSP.

These guards were appropriate when RADE decoded audio flowed through the same
m_rxBuffer / DSP pipeline as regular audio — running NR on decoded speech
would have degraded it. They are no longer correct after PR #1953: decoded
speech now flows exclusively through m_radeRxBuffer and is mixed in the drain
timer after the DSP stage. The DSP pipeline only ever touches m_rxBuffer;
RADE audio never enters it.

Fix

  • Remove if (m_radeMode) return; from all six client-side DSP setters
  • Remove the DSP teardown loop from setRadeMode(on=true)
  • Correct updateRxBufferStats() to sum both buffers for accurate diagnostics
  • Correct the drain timer mix to apply the final std::clamp in a single pass
    over the full output block (was only clamping the RADE portion)

Testing

Tested on FLEX-8400, firmware v4.1.5.39794, two-panadapter layout:

  • Pan A: Slice 0 in RADE/FreeDV mode, RADE active, receiving decoded speech
  • Pan B: Slice 1 in USB — NR4/NR2 engaged → audio processing confirmed active
  • No regressions on single-pan operation or non-RADE modes
  • RADE decoded audio quality unaffected (DSP path is upstream of the mix)

🤖 Generated with Claude Code

@NF0T NF0T requested a review from ten9876 as a code owner April 26, 2026 14:32
Copy link
Copy Markdown
Contributor

@aethersdr-agent aethersdr-agent Bot left a comment

Choose a reason for hiding this comment

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

Clean, well-scoped fix. CI is green (build, CodeQL, analyze all pass). One file changed, all four changes are consistent with the dual-buffer architecture from #1953.

Guard removal (6 DSP setters + setRadeMode teardown): Correct. Post-#1953, RADE decoded audio flows through m_radeRxBuffer and is mixed in the drain timer after the DSP stage — the DSP pipeline only touches m_rxBuffer, so the guards were silencing DSP on pans that never see RADE audio. Good catch.

updateRxBufferStats(): Summing both buffers gives an accurate picture of total buffered audio for diagnostics. Fine.

Drain timer clamp: Moving from a per-sample clamp inside the RADE mix loop to a single pass over the full output block is the right call. One minor observation: before this PR, the non-RADE path (out[i] += rx[i]) never clamped at all — the new code now clamps unconditionally, which is actually a small improvement (prevents out-of-range samples reaching the DAC even in non-RADE scenarios). The cost of iterating len/floatBytes samples for a clamp is negligible at audio sample rates.

No issues found — scope is tight, no convention violations, no null-pointer risks, no resource leaks. Excellent PR description too.

Thanks for the thorough multi-pan testing on the 8400, @NF0T.

…n another pan

With ten9876#1953, decoded RADE speech writes to m_radeRxBuffer and bypasses the
DSP chain entirely. DSP (NR2/NR4/RN2/BNR/DFNR) runs only on m_rxBuffer,
which carries SSB/CW audio from all non-RADE slices. The original guards
that prevented DSP while m_radeMode was set were motivated by the old single-
buffer design, where decoded speech flowed through feedAudioData() → DSP.

With the dual-buffer architecture those guards are wrong:

  - In multi-pan (RADE on Pan A, SSB on Pan B) the guards silently discarded
    any attempt to enable NR4/etc. on Pan B. The button illuminated but no
    processing occurred — confirmed by user testing (NF0T, FLEX-8400 v4.1.5).
  - setRadeMode(true) tore down any already-active DSP on entry, killing
    noise reduction on a concurrently listening SSB pan.

Decoded speech in m_radeRxBuffer is never touched by DSP regardless; removing
the guards cannot affect RADE speech quality.

Also address two minor issues noted in the ten9876#1953 review (aethersdr-agent):

  - updateRxBufferStats() now sums m_rxBuffer + m_radeRxBuffer so the buffer
    diagnostics UI (rxBufferBytes / rxBufferPeakBytes) reflects total buffered
    audio rather than omitting the RADE speech contribution.

  - Drain-timer mix clamp: both source loops now use plain += and a single
    std::clamp pass runs over the full output array after both sources are
    mixed. Previously the clamp was applied only to the RADE addition, which
    was functionally correct (RADE ran last) but fragile and unclear in intent.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@NF0T NF0T force-pushed the fix/rade-dsp-multipan-guards branch from ad7e82c to e1c6a08 Compare April 26, 2026 18:54
@ten9876 ten9876 merged commit e1fd45c into ten9876:main Apr 26, 2026
5 checks passed
@NF0T NF0T deleted the fix/rade-dsp-multipan-guards branch April 26, 2026 23:36
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.

2 participants