Skip to content

Avoid NR2 wisdom generation on audio thread#2275

Merged
ten9876 merged 1 commit intoten9876:mainfrom
jensenpat:aether/nr2-macos-diagnosis
May 2, 2026
Merged

Avoid NR2 wisdom generation on audio thread#2275
ten9876 merged 1 commit intoten9876:mainfrom
jensenpat:aether/nr2-macos-diagnosis

Conversation

@jensenpat
Copy link
Copy Markdown
Collaborator

Summary

Fixes a macOS NR2 stall where enabling NR2 could freeze RX audio and the WAVE scope for minutes when the local FFTW wisdom file existed but could not be imported by the current FFTW runtime.

Root Cause

AudioEngine::needsWisdomGeneration() only checked whether aethersdr_fftw_wisdom existed. If the file was stale or incompatible, setNr2Enabled() still called SpectralNR::generateWisdom() on the audio worker thread. generateWisdom() then failed to import the file and started full FFTW wisdom generation, which can run for several minutes and blocks the audio thread. That explains the observed audio stop, WAVE hang, and later recovery.

On the affected macOS machine, the local wisdom file was present and had a fftw-3.3.10 header, while the current build uses FFTW 3.3.11; fftw-wisdom rejected it with an import error.

Changes

  • Add SpectralNR::loadWisdom() so Aether can validate/import wisdom without triggering full generation.
  • Make AudioEngine::needsWisdomGeneration() return true when the wisdom file exists but cannot be imported.
  • Prevent AudioEngine::setNr2Enabled() from ever running full FFTW wisdom generation on the audio worker thread.
  • Keep fallback FFT builds from showing bogus wisdom-generation behavior.

Impact

When wisdom is missing or stale, NR2 enable now routes through the existing background progress dialog path instead of blocking audio playback. If wisdom import unexpectedly fails at enable time, NR2 proceeds with runtime FFTW_MEASURE plans rather than hanging RX audio.

Validation

  • cmake --build build --parallel 10
  • ctest --test-dir build --output-on-failure
  • Confirmed the local stale wisdom file reproduced the import failure with fftw-wisdom -w /Users/patj/.config/AetherSDR/AetherSDR/aethersdr_fftw_wisdom.

👨🏼‍💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat

@jensenpat jensenpat marked this pull request as ready for review May 2, 2026 05:49
@jensenpat jensenpat requested a review from ten9876 as a code owner May 2, 2026 05:49
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.

Thanks @jensenpat — well-diagnosed fix. The root-cause analysis (stale fftw-3.3.10 wisdom rejected by 3.3.11) matches the symptom (audio worker thread blocked in FFTW_PATIENT plan creation), and the change correctly splits import (fast, safe on the audio thread) from generation (slow, must run on the background dialog thread).

A few small observations:

Minor / non-blocking

  1. AudioEngine::needsWisdomGeneration() now has an observable side effect — it imports wisdom into FFTW global state via SpectralNR::loadWisdom(). The name still reads as a pure query. This is harmless in practice (the only caller is MainWindow::enableNr2WithWisdom() on the UI thread, and the import is fast), but consider renaming to something like ensureWisdomReady() or adding a one-line comment noting the side effect. Not a blocker.

  2. When needsWisdomGeneration() returns true because the file existed but failed to import, the subsequent background path calls SpectralNR::generateWisdom() which begins by attempting loadWisdom() again — a second guaranteed-failed import on the same stale file before it falls through to full generation. Minor redundancy, no correctness issue.

  3. Lock order looks fine: setNr2Enabled holds m_dspMutex (recursive) and then briefly takes s_fftwMutex inside loadWisdom. There is no other path that takes them in the reverse order, so no ABBA risk.

  4. qCWarning(lcDsp) is already established in this file (line 90), so the new export-failure log fits convention.

The HAVE_FFTW3 guards in both needsWisdomGeneration() and setNr2Enabled() are good — fallback FFT builds will no longer claim wisdom is needed and won't attempt imports.

LGTM as a targeted bug fix. The validation steps (build + ctest + reproducing the import failure with fftw-wisdom) are appropriate for this change.

@ten9876 ten9876 merged commit 1667c41 into ten9876:main May 2, 2026
5 checks passed
ten9876 added a commit that referenced this pull request May 2, 2026
The v0.9.5.1 entry was originally cut for just the TCI TX hotfix
(#2285), but six additional fixes had already landed in main between
the v0.9.5 tag and v0.9.5.1:

- #2275 NR2 wisdom generation off the audio thread
- #2278 SmartLink disconnect teardown
- #2279 Reset RX slice tabs on disconnect (#2254)
- #2280 macOS panadapter pop-out refresh + multi-pan dock layout
- #2282 SmartLink reconnect after WAN drop
- #2284 Qt log handler serialization fixes macOS tune-time crash

CHANGELOG.md gets a per-fix entry with root cause + behavior change.
WhatsNewData.cpp regenerated via scripts/gen_whatsnew.py so the
in-app What's New dialog reflects the full v0.9.5.1 contents.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
ten9876 added a commit that referenced this pull request May 2, 2026
Match the v0.9.5 `(#NNNN, contributor)` heading style and call out
@rfoust and @jensenpat in the summary for the bulk of this release.

Authors per PR:
- @rfoust: #2278, #2279, #2280, #2282 (SmartLink + macOS popout)
- @jensenpat: #2275, #2284 (NR2 wisdom + Qt log serialization)

WhatsNewData.cpp regenerated.

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
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.

NR2 causes loss of audio, Wave meter freeze and cannot exit AetherSDR without using Force Quit NR2 Stopped audio when activated

2 participants