Skip to content

Releases: ten9876/AetherSDR

AetherSDR v0.9.7 — CW keying overhaul + reliability sweep

06 May 04:47
v0.9.7
c8ef1bc

Choose a tag to compare

CW keying overhaul + reliability sweep

A focused follow-up to v0.9.6 with two themes: a substantial CW operator
upgrade — keyboard and MIDI-mapped straight key + iambic paddles, full
break-in / QSK respect on both paths, netCW timing fixes, and Apollo-era
Quindar tones on PTT engage/disengage — and a reliability sweep covering
SpotHub auto-reconnect, a TCI crash on quit, the long-standing waterfall
TX trail, hardware PTT regressions, and DAX RX latency.

Big thanks to @jensenpat (CW keyboard / MIDI controls, compression
meter gating, Windows MSVC runtime), @M7HNF-Ian (Spot Lines,
HiDPI gauge clipping, TCI crash on quit, SpotHub auto-reconnect),
@filemakers (connect-to-last-radio opt-out checkbox), @NF0T
(RADE TX policy naming + tests), @chibondking (live voltage gauge),
plus issue reporters @vu2cpl (TCI crash with full call stack),
@luigiverdicchio1-prog (SpotHub failed-reconnect repro), @LU5DX
and @rnash2 (spectrum amplitude scale issue — under investigation).

New features

CW keyboard + MIDI controls (#2361, #2391, jensenpat)

  • Three new shared shortcut + MIDI actions: Trigger straight key,
    Trigger CW Left Paddle, Trigger CW Right Paddle. Same action IDs
    and display names for keyboard shortcuts and MIDI mappings (cwkey /
    cwdit / cwdah); MidiSettings migrates legacy dotted IDs
    (cw.key / cw.dit / cw.dah) on read.
  • Straight key is a true momentary control: keyboard press + MIDI gate-on
    assert the netCW key path, release + gate-off release it. Paddles feed
    the local iambic keyer when running so sidetone and on-air timing stay
    aligned with WPM; falls back to a held-key path otherwise.
  • Both paths now honor the radio's break_in setting fully — with
    break_in=1 (QSK), key edges trigger TX and break_in_delay holds
    the relay between elements; with break_in=0, keys are queued and the
    operator engages PTT manually (Space PTT, MOX, hardware PTT). The
    previous auto-PTT envelope masked break-in OFF and killed QSK hang
    time on release.
  • New clickable red TX status badge in the status bar acts as an
    emergency transmit cancel — checks Multi-Flex ownership, clears all
    local CW state, forces sidetone key-up, and sends cw key 0 /
    cw ptt 0 / transmit tune 0 / xmit 0.
  • Slider focus lease no longer blocks momentary CW shortcuts or Space
    PTT — clicking the CW delay slider previously froze J/K/L paddle
    keying and Space PTT for 2+ seconds while the lease's arrow-key
    capture timer expired.
  • Pre-existing typo fix: J tile in the on-screen keyboard widget was
    bound to Qt::Key_I, so binding a shortcut to J in the editor
    selected I.

Quindar tones — Apollo-era K/BK on PTT (#2334, fixes #2262)

  • Optional 2525 Hz "K" / 2475 Hz "BK" tones on PTT engage / disengage,
    modeled after Apollo CapCom audio. Lock-free DSP module wired between
    PC mic gain and the final TX limiter so tones are mixed into the
    outgoing audio. Local sidetone via a dedicated 48 kHz QAudioSink
    (mutually exclusive with CW mode at the mode level — Quindar and CW
    share the same sidetone bus).
  • Added as the QUIN chip in the Final Output Stage panel of the
    Aetherial Audio Channel Strip with a frameless editor dialog
    (test-tone buttons + Done in the same row as the title bar).
  • Disabled by default; opt-in via the chip toggle.

netCW keying fix + trace logging (#2336, fixes a long-tail of issues)

  • Fixes netCW timing for both straight-key and iambic CW. Adds detailed
    aether.cw trace category logging across MIDI / keyboard input,
    netCW UDP scheduling, VITA stream/index details, and TCP fallback /
    backstop paths so future timing regressions are diagnosable from logs.

Spot Lines toggle in SpotHub (#2349, M7HNF-Ian)

  • New "Spot Lines" toggle in the SpotHub Display settings draws vertical
    lines from the spectrum up to each spot label. Off during contests to
    reduce visual clutter; on for casual ops to keep label-to-frequency
    mapping legible at a glance.

Network Diagnostics live logs tab (#2333)

  • New tab in the Network Diagnostics dialog with live tail of the same
    logs the diagnostics report references, scoped to the diagnostic
    categories (aether.connection, aether.dxcluster, aether.cw,
    etc.). Lets users diff what they're seeing against what was logged
    without leaving the dialog.

Connect-to-last-radio opt-out checkbox (#2390, filemakers)

  • New "Connect to last radio on start up" checkbox on the connection
    dialog; defaults to ON so existing users keep current behavior. When
    unchecked, AetherSDR no longer auto-connects on startup, on
    broadcast-discovery, or on routed-radio probe — useful for operators
    who want to pick a radio manually each session. The dialog
    auto-launches at startup when opt-out is enabled so the user has a
    clear path to pick a radio.

Bug fixes

SpotHub auto-reconnect after failed connection attempt (#2394, M7HNF-Ian, fixes #2380)

  • SpotHub (DX cluster / RBN) didn't automatically reconnect after a
    Wi-Fi drop or any failed connection attempt — Qt's QAbstractSocket
    only emits disconnected() on Connected → Unconnected transitions,
    so when the socket failed during ConnectingState (host blocked,
    refused, or timed out), the reconnect timer was never armed. Extracts
    a scheduleReconnect() helper called from all three failure paths
    (live drop, socket error, connect timeout) with guards against
    double-scheduling. A per-call epoch counter prevents stale timeouts
    from a previous attempt aborting a later successful one. Backoff
    sequence unchanged: 5 s → 10 s → 20 s → 40 s → 60 s.

TCI crash on quit when TciServer outlives RadioModel (#2386, M7HNF-Ian, fixes #2385)

  • TciServer was constructed as a QObject child of MainWindow, so
    Qt deleted it during ~QWidget::deleteChildren() — which runs after
    MainWindow's value members (including m_radioModel) have already
    destructed. ~TciServer()stop()releaseDaxForTci() then
    dereferenced freed memory. EXC_BAD_ACCESS @ 0x38, 100% reproducible
    on quit when a radio was connected. Reported by VU2CPL with full call
    stack. Fixed by explicitly tearing down m_tciServer in
    ~MainWindow() after the audio thread is stopped but while
    m_radioModel is still alive, plus a belt-and-braces
    QPointer<RadioModel> so the existing null guards in
    releaseDaxForTci() catch any future regression automatically.

Waterfall unfreezes on radio interlock state, not MOX edge (#2368, fixes #1927)

  • Waterfall freeze/unfreeze previously gated on the local MOX edge,
    which fired the instant the user released PTT — the radio kept
    streaming TX-contaminated tiles for the UNKEY_REQUESTED window, and
    those rows then took 10–23 s to scroll off the visible waterfall.
    Now driven by RadioModel::radioTransmittingChanged (interlock
    state=TRANSMITTING), so the freeze is held until the radio
    actually leaves TX. Multi-Flex bonus: any client TXing now triggers
    the freeze, not just our client.

Honor cw break_in for keyboard CW keying (#2391)

  • RadioModel::sendCwKey and the iambic keyer's onPaddleEvent both
    unconditionally wrapped each key/squeeze in a cw ptt 1...cw ptt 0
    envelope. Made break-in OFF a no-op (auto-PTT forced TX anyway) and
    killed the radio's break_in_delay hang time with break-in ON
    (force-dropped PTT after every element). Stripped the auto-PTT in
    both paths so the radio's break-in setting decides TX behavior,
    matching SmartSDR semantics.

Spot list double-click switches mode (#2372, fixes #2298)

  • Double-clicking a spot in the Spot List now switches the radio's
    mode along with the frequency. Previously only the frequency moved,
    leaving the user in the wrong mode for the spotted signal.

Spot trigger includes pan= for external CAT clients (#2369, fixes #2366)

  • The spot click protocol now includes pan=<panId> so external CAT
    clients (N1MM Logger, etc.) consuming AetherSDR's spot triggers can
    route the click to the correct panadapter in multi-pan setups.

Compression meter gates on radio TX state (#2363, jensenpat)

  • The TX compression meter now displays only while the radio reports
    state=TRANSMITTING. Previously it could read live during RX from
    stale interlock state, confusing operators about what compression
    was actually applied to their signal.

Voltage gauge label shows live radio voltage (#2362, chibondking)

  • The voltage gauge label now reflects the live voltage value reported
    by the radio instead of the static "VOLTS" placeholder.

Minimal mode revert on macOS when entered while maximized (#2367, fixes #2365)

  • Entering minimal mode while the window was already maximized on
    macOS would revert to a non-minimal layout immediately on toggle.
    Layout / state ordering corrected so the entry sticks regardless of
    the prior maximized state.

MidiControlManager: drop dead paramAction signal (#2370)

  • Cleanup follow-up after #2336 introduced paramActionTrace
    paramAction was still emitted but had zero connectors. Removed
    the orphan signal + matching declaration.

Infrastructure

DAX RX native pw_stream source on Linux (#2312, fixes #1008)

  • DAX RX latency on Linux drops from ~400 ms → ~200 ms via a native
    PipeWire pw_stream source path, replacing the previous PulseAudio
    client. Brings DAX RX latency in line with macOS / Windows.

RADE TX policy naming + tests (#2353, NF0T, fixes #2343)

  • Renames the RADE TX policy enum to align with the issue tracking
    language (HostedDaxBridge etc.) and adds unit tests covering each
    (reason, platform, mode) → (allowed, note) decision row.

HiDPI gauge clipping (#2346, M7HNF-Ian)

  • HGauge tick labels and TxApplet value labels were clipping on HiDPI
    displays. Layout / paint regions updated to honor device-pixel ratio.

Windows portable ZIP includes MSVC runtime (#2364, jensenpat)

  • Windows portable ZIP now bun...
Read more

v0.9.6 — Aetherial Audio Channel Strip + AetherSweep Phase 2

04 May 01:14
v0.9.6
eed1b7d

Choose a tag to compare

Aetherial Audio Channel Strip + AetherSweep Phase 2

Headline additions: a unified Aetherial Audio Channel Strip that brings
every TX DSP stage (gate, EQ, compressor, de-esser, tube, AetherVoice,
reverb, and a brand-new Final Output Stage with brickwall limiter) into a
single editable window with a savable preset library — and AetherSweep
Phase 2
, a polish pass on the in-panadapter SWR analyzer with log scale,
threshold-band shading, interpolated bandwidth at SWR ≤ 1.5 / 2.0, a
resonance caret, and band-change-aware auto-stop. Network Diagnostics
gained trend graphs and per-series gutter hints. RADE finally ships in
the official Windows installer.

Big thanks to @jensenpat (oscillator reference fix, AetherSweep
Phase 2, Connect-by-IP recents, minimal mode polish, Windows installer
packaging), @NF0T (RADE on Windows CI/installer, RADE mic meter
fix), @rfoust (Network Diagnostics trend graphs), and
@AetherClaude (stderr non-draining-pipe deadlock) for landing the
bulk of this release.

New features

Aetherial Audio Channel Strip (#2307, #2326)

  • New unified TX DSP window covering every stage in the chain: gate, EQ,
    compressor, de-esser, tube, AetherVoice (the exciter formerly known as
    PooDoo), Freeverb, plus a brand-new Final Output Stage with brickwall
    limiter, output trim, DC block, and a 1 kHz test tone.
  • Savable preset library at ~/.config/AetherSDR/ChannelStrip.settings
    (separate from AetherSDR.settings). Captures every TX DSP knob, the
    user's chain order, and final-limiter parameters. Save / Delete /
    Export Preset / Export Library buttons in the strip's preset row.
  • Master/Aux BYPASS button stays in lock-step between the docked Chain
    applet and the strip via a shared engine-level snapshot — flipping it
    in either place updates both.
  • Two new 4th-row panels: Aetherial Waveform — TX (1–20 s scope window
    with SCOPE/ENVELOPE/HISTORY modes) and Final Output Stage (peak-hold
    meter with GR overlay + draggable amber ceiling triangle, mouse-wheel
    ±0.1 dB).
  • Logo / title rebrand: PooDoo™ exciter → AetherVoice™ "Aetherial
    Voice Processor" with Body / Clarity emphasis controls. Docked tile
    (PUDU) renamed to EVO on the chain widget; container button
    renamed VUDU.
  • Double-click any TX chain tile launches the Channel Strip — replaces
    the legacy easter-egg launch nub on the Chain applet and the
    per-stage TX floating editors (ClientDeEssEditor,
    ClientReverbEditor, etc.).
  • FreeVerb tile in the docked applet panel now shows the same
    decay-tail viz as the Channel Strip's reverb panel, signal-driven by
    a new AudioEngine::clientReverbStateChanged signal (no polling).

AetherSweep Phase 2 (#2320, jensenpat)

  • Logarithmic SWR scale for cleaner low-ratio detail; threshold-band
    shading for SWR 1.0–1.5 (green), 1.5–2.0 (amber), and >2.0 (red).
  • Resonance caret + dot at the best measured SWR point; visual
    start/end notches mark sweep endpoints.
  • Interpolated bandwidth brackets at SWR ≤ 1.5 and ≤ 2.0, with a
    concise BW readout in the corner label.
  • Resonant frequency display trimmed to kHz precision; corner readout
    switched from "latest sample" to best SWR + resonance frequency.
  • Cleared sweep plots when the swept TX slice changes bands; if a band
    change happens while a sweep is running, the sweep stops and clears
    without restoring the old freq/pan range so cleanup doesn't fight
    the user's new band.

Network Diagnostics trend graphs (#2309, rfoust; #2316)

  • Per-metric trend plots with Timeframe selector (1 min / 5 min /
    15 min / 1 h / 1 d / 1 w).
  • Logarithmic Y-axis on the Rates tab — 0 / 1 / 10 / 100 / 1k kbps
    decades all visible at once instead of being squashed at the
    baseline.
  • Per-series last-sample hints in the left gutter — small
    color-coded values that always show the latest reading for each
    visible stream, with a 6 px-tall solid centerline alpha gradient
    to keep the labels legible against the trace.
  • Frameless chrome with draggable title bar + 8-axis resize matching
    the rest of AetherSDR's floating windows.

RADE in the official Windows installer (#2324, NF0T)

  • ENABLE_RADE=ON for both the Windows CI job and the official
    installer workflow. Vendored RADE-prepared Opus + neural-net
    weights are statically linked, so no new DLLs ship — AetherSDR.exe
    grows ~8–12 MB to match the AppImage.
  • New Build Opus (RADE dependency) CI step provides clean failure
    attribution and matches the AppImage workflow's pattern. Closes
    reports of "RADE absent from Windows installer".

Connect by IP recents dropdown (#2296, jensenpat)

  • Connect-by-IP field is now a combo box pre-populated with the last
    five addresses (stored as RecentDirectIpAddresses). Successful
    connect promotes the address to the top of the list.

Black slider auto-offset (#2328)

  • Spectrum Overlay menu's Black slider now drives a noise-floor target
    offset while AUTO is engaged: 50 = at the noise floor (today's
    behaviour); lower = darker (push threshold above the floor); higher
    = lighter. Manual mode keeps existing semantics. Both stored
    values persist independently so toggling AUTO swaps the slider
    position without losing either preference.

Minimal mode polish (#2290, jensenpat; #2299)

  • Title bar drag now reaches the gutter and other previously-dead
    zones via sub-pixel hit testing. Exit paths from minimal mode
    consolidated; layout stops fighting on toggle.

Aetherial Noise Reduction docked applet (#2297)

  • Client-side NR controls live in their own docked applet under
    PooDoo Audio (RX); the redundant DSP sub-panel was removed from
    the Spectrum Overlay menu for a cleaner DSP surface.

Bug fixes

Oscillator reference status no longer goes stale (#2329, jensenpat)

  • New RadioModel::oscillatorChanged() signal drives the status-bar
    reference label and Radio Setup combo immediately from oscillator
    state, instead of relying on event ordering with GPS status.
    Eliminates the case where the status bar got stuck on the previous
    reference if a GPS update never arrived after the oscillator
    transition.
  • Radio Setup dropdown preserves currently-selected/actual options
    during presence transitions, so transient flag blips no longer
    drop the active option from the combo. Renamed External
    External 10 MHz to match the FlexLib API description.
  • Status-bar tooltips now show desired setting, actual source, lock
    state, and GPS/external details.

RADE mic level meter + gain slider (#2292, NF0T)

  • The RADE TX mic level meter now updates while the modem is active,
    and the gain slider is enabled instead of stuck at zero. Fixes
    "no apparent way to set RADE mic level" reports.

Stderr non-draining pipe deadlock (#2300, AetherClaude)

  • When stdout/stderr was redirected to a pipe with no reader, the
    audio worker thread could deadlock writing log lines. Replaced
    blocking writes with a non-blocking path that drops on the floor
    rather than stalling the thread.

Windows installer runtime packaging (#2303, jensenpat)

  • Tightened Windows runtime-DLL bundling for a smaller installer and
    fewer "missing DLL" reports on first launch.

Infrastructure

v0.9.5.1 release-notes expansion (#2288, #2289)

  • The CHANGELOG entry for v0.9.5.1 was expanded post-release to
    cover all post-v0.9.5 fixes (#2113 reachability sweep, the four
    rfoust polish PRs, NR2 audio-thread + Qt-log hotfixes) with full
    contributor shoutouts.

v0.9.5.1 — Stability & polish hotfix sweep

02 May 17:52
v0.9.5.1
88fdb6b

Choose a tag to compare

Stability & polish hotfix sweep

A focused follow-up release that lands the TCI TX policy hotfix plus six
post-v0.9.5 fixes already in main: SmartLink WAN reconnect after radio
drops, sequenced WAN disconnect teardown, RX slice-tab reset between
radios with different slice counts, macOS panadapter pop-out live
updates and dock-splitter layout, NR2 wisdom-generation safety on the
audio thread, and a Qt log-handler serialization fix that resolves a
macOS tune-time crash.

Big thanks to @rfoust (four SmartLink / disconnect / macOS polish
fixes) and @jensenpat (NR2 audio-thread safety + Qt log
serialization) for landing the bulk of this release.

Bug fixes

TCI TX silent on Windows / Linux non-PipeWire (#2276)

  • evaluateDaxTxPolicy() now always allows DaxTxRequestReason::TciTxAudio
    regardless of platform / hosted-DAX availability. TCI receives audio
    over WebSocket and feeds it into a dedicated dax_tx stream that's
    independent of SmartSDR DAX2 (which owns the Windows DAX audio
    devices
    , not the radio's dax_tx stream slot — multiple GUI clients
    can each register their own).
  • Test assertions in tests/radio_status_ownership_test.cpp flipped to
    match the corrected policy and a new Linux-non-PipeWire test case
    added.

SmartLink reconnect after WAN drop (#2282, rfoust)

  • MainWindow now owns a WAN reconnect timer that re-requests a
    SmartLink radio connection using the last selected WAN radio when
    RadioModel reports an unexpected WAN disconnect, instead of
    leaving the app stuck on the "Radio disconnected — waiting for
    reconnect" popup.
  • SmartLinkClient::reconnect() refreshes Auth0 credentials via the
    saved refresh token before reconnecting, avoiding reuse of an
    expired id_token. Auth-refresh failure stops the retry loop and
    shows a sign-in-required status instead of retrying forever.
  • RadioModel::forceDisconnect() now handles WAN connections so
    missed pings transition the app to disconnected/reconnecting
    promptly. Ping watchdog logs and forces disconnect once per outage
    rather than every second.
  • PanadapterStack::prepareShutdown() releases QRhi GPU resources
    before main-window teardown to avoid the macOS Metal teardown crash
    that could fire after a stale-state Disconnect.

SmartLink disconnect teardown (#2278, rfoust)

  • WAN disconnect previously closed the WAN socket after disconnecting
    RadioModel's signals and nulled m_wanConn directly, skipping
    RadioModel::onDisconnected() cleanup entirely. Panadapters,
    slices, meters, and streams stayed alive in the model after the user
    clicked Disconnect.
  • Now runs the normal model teardown path on intentional WAN
    disconnect, so WAN sessions emit connectionStateChanged(false) and
    clear model state the same way LAN disconnects do.

Reset RX slice tabs on disconnect between radios with different slice counts (#2254, rfoust)

  • RxApplet::clearSliceButtons() tears down generated slice tab buttons
    and restores the static slice badge on disconnect. Stale A–H buttons
    no longer linger after switching from a high-slice radio to a
    smaller one.
  • MainWindow's infoChanged initializer is now per-connection rather
    than one-shot, so each radio rebuilds its slice row from its own
    maxSlices. Slice button click connections are guarded against
    duplicate signal handlers across reconnects.

Qt log handler serialization fixes macOS tune-time crash (#2284, jensenpat)

  • The global qInstallMessageHandler callback wrote through a single
    QFile* without synchronization, and concurrent qCInfo/qDebug
    output from main + worker threads corrupted Qt's internal file
    write-buffer state. The tune-policy diagnostic line happened to be
    the log call that exposed the corruption — the failing object was
    the logging sink, not the Flex tune command path.
  • Now serializes the handler with an intentionally leaked mutex
    (mirroring the existing shutdown-safe treatment of the redaction
    regexes) and replaces per-message QTextStream wrapping with a
    direct UTF-8 QFile::write()/flush() path. No change to radio
    command ordering or panadapter policy.

macOS panadapter pop-out refresh + multi-pan dock layout (#2280, rfoust)

  • Detached panadapter windows on macOS no longer show a static/stale
    spectrum image. Cross-window reparenting now resets the native
    QRhi/Metal surface and re-requests pan dimensions from the radio
    after every float/dock cycle.
  • Saved floating-window state is no longer restored after later
    user-added pans, so adding a second panadapter does not spawn an
    unwanted blank floating window.
  • rebuildDockedSplitter() keeps the main-window splitter compact
    when multiple pans float/dock — no more empty placeholder slots.

NR2 wisdom generation no longer freezes the audio thread (#2275, jensenpat)

  • AudioEngine::needsWisdomGeneration() previously only checked
    whether aethersdr_fftw_wisdom existed. If the file was stale or
    incompatible (e.g. fftw-3.3.10 header on a build that uses FFTW
    3.3.11), setNr2Enabled() ran full FFTW wisdom generation on the
    audio worker thread, blocking RX audio and the WAVE scope for
    several minutes.
  • Adds SpectralNR::loadWisdom() for import-only validation, makes
    needsWisdomGeneration() return true when the file exists but
    cannot be imported, and routes generation through the existing
    background progress dialog instead of the audio thread. If wisdom
    import fails at enable time, NR2 falls back to runtime
    FFTW_MEASURE plans rather than hanging audio.

v0.9.5 — Reliability sweep + DAX2 coexistence overhaul

02 May 05:14
v0.9.5
0344533

Choose a tag to compare

[v0.9.5] — 2026-05-02

Reliability sweep + DAX2 coexistence overhaul

A focused stability release. Headline is DAX2 coexistence policy
(jensenpat)
— a centralized decision table that makes AetherSDR's
behaviour next to SmartSDR DAX, hosted DAX (macOS / PipeWire), and
external Flex tooling explicit, testable, and consistently logged.
Plus substantial improvements to disconnect teardown (sequenced
stream remove with response wait — fixes the Flex-6300 unreachable-
after-reconnect bug), worker-thread shutdown (no more killTimer
warnings on app exit), panadapter zoom (no spectrum flash), and
multi-flex spot/ATU handling (DXCluster spot trigger_action removal,
ATU per-frequency toggle).

A two-PR issue triage cleanup closed 12 long-standing issues across
small UI bugs, contrast, indicator routing, click-to-tune behaviour,
and visible regressions from recent feature work.

Features

Aetherial Parametric EQ Smoothing combo (#2236)

  • New Smoothing combo on the EQ analyzer with 1/24, 1/12, 1/6, 1/3,
    1/1 octave fractional smoothing options (linear-power averaging).
    Persists via EqAnalyzerSmoothing; defaults to 1/12 octave.
  • Audio-domain band-plan strip on the EQ canvas + dashed yellow filter
    cutoff guides for both TX and RX. Cutoff guides are draggable to
    retune filter edges with mode-aware USB/LSB/AM/FM offset conversion.
  • Phone applet Low/High Cut buttons snap to nearest 50 Hz.
  • ~30 % faster smoothing inner loop after replacing
    std::pow(10, x/10) with std::exp(x * ln(10)/10) (#2239).

Custom filter edges with persistence (#2272)

  • Right-click a filter button → Set Custom Edges... opens a
    2-spinbox dialog. Asymmetric lo:hi pairs persist in
    FilterPresets_<mode> via a new mixed width / lo:hi storage
    format (backward compat preserved for existing width-only entries).
  • Reset to Default is now per-slot.
  • FilterPassbandWidget shows signed lo/hi/center values so LSB/CW
    filters reveal sideband.
  • Filter-edge grab zone in the spectrum bumped from 5px to 8px so
    edges sitting near the VFO line are easier to grab.

Spot click client-side mode mapping (#2272)

  • All client-ingested spots (DXCluster, RBN, POTA, SpotCollector,
    FreeDV, WSJT-X, manual) now ship with trigger_action=none. The
    radio no longer auto-acts on stored mode strings (which mishandled
    "SSB" and similar non-Flex tokens, falling back to CW).
  • AetherSDR's auto-mode mapping handles tune+mode client-side.
    Default flipped to enabled.
  • FreeDV-source spots activate the RADE engine via activateRADE()
    (sets DIGU/DIGL plus the OFDM modem) instead of just landing on a
    plain digital mode.

ATU per-frequency toggle (#2272)

  • ATU button now mirrors SmartSDR's behaviour: first click on a
    frequency tunes; second click at the same frequency bypasses; freq
    change resets the toggle so the next click tunes again.

Bug fixes

DAX2 coexistence policy (#2271, jensenpat)

  • New DaxTxPolicy.h decision table: (reason, platform, mode) → (allowed, note). Centralizes platform-aware DAX TX decisions with
    explicit reasons (HostedDaxBridge, TciTxAudio, ExternalDaxRouteOnly,
    GenericAudioRecreate) and consistent log notes at every branch.
  • Lazy dax_tx stream creation via RadioModel::ensureDaxTxStream()
    — eager creation at GUI attach is removed so SmartSDR DAX can own
    the Windows route.
  • daxTxStatusCanUpdateLocalState() anti-stomp: foreign DAX TX
    status can no longer accidentally adopt our tracked stream slot.
  • LAN VITA UDP rebind path: on Flex's 0x500000A9 "Port/IP pair
    already in use" error, AetherSDR rebinds to an OS-assigned ephemeral
    port and retries client udpport. WAN/SmartLink already used
    ephemeral ports and is correctly excluded from the rebind path.
  • Dead-orphan DAX RX detection: client_handle=0 ip=0.0.0.0 entries
    are ignored as not-our-stream rather than treated as legacy-compat.
  • External DAX TX/RX visibility: separate seen-once log lines so the
    radio's external streams are visible in diagnostic logs without
    polluting our local state.
  • 24 + test assertions across testStreamStatusOwnershipCompatibility,
    testDaxTxStatusOwnership, testDaxTxPolicy, and
    testUdpRegistrationPolicy.
  • Linux non-PipeWire builds correctly skip both setDax(1) and DAX
    stream creation, so digital TX falls back to the physical mic input
    rather than going silent (#2273).

Sequenced radio disconnect teardown (#2247, jensenpat)

  • Fixes Flex-6300 / 6400 unreachability after reconnect (#2113, #2218).
  • Disconnect now sends stream remove 0x<id> and waits up to 2 s for
    the radio's response before closing TCP. Without this, fire-and-
    forget teardown left stale Flex sessions that refused subsequent
    connects until reboot.
  • Drops the rejected client disconnect <self_handle> send — verified
    against FlexLib's own self-disconnect path, which uses the 0x04
    "dying gasp" byte before TCP close. AetherSDR now does the same.
  • Defensive auto-reconnect arms on refused-connect paths that don't
    emit a disconnected signal.

Worker object shutdown thread affinity (#2248, rfoust)

  • Eliminates QObject::killTimer: Timers cannot be stopped from another thread, QObject::moveToThread: Current thread is not the object thread, and ~QObject warnings on app exit.
  • Worker-thread QObjects (audio engine, spot clients, ext controllers,
    radio connection, panadapter stream) are now destroyed via
    deleteLater() on their owning threads before each thread quits.

Panadapter zoom keeps spectrum visible (#2246, rfoust)

  • New reprojectSpectrum() mirrors the existing waterfall reprojection.
    Zoom changes that overlap with the previous range now interpolate
    existing FFT bins forward instead of clearing them, eliminating the
    spectrum flash/blank during pinch / wheel / drag zoom.

TGXL detected via direct TCP only (#2250, chrisb1964)

  • TUN applet now appears for TGXLs that don't report through the
    amplifier API (Flex-8600 fw 4.2.18). New m_directPresence fallback
    in TunerModel; isPresent() returns true via either path.
  • Handles bare amplifier <handle> removed form correctly via a new
    ampRemovedRe regex (matches FlexLib's s.Contains("removed")
    semantics for both bare-flag and kvs-form removals).

RX slice tab capacity initialization (#2243, chibondking)

  • RX slice tab capacity is now seeded from the radio model on connect
    rather than left at the default — fixes empty tabs when reconnecting
    to a different radio model.

Radio model label refresh (#2244, jensenpat)

  • Radio model label refreshes on info command response, so
    reconnecting to a different model immediately reflects the new
    identity in the UI.

FreeDV Reporter OS string (#2269, tmiw)

  • OS field lowercased to match the official FreeDV client convention.
    Previously AetherSDR users showed as "other" in monthly platform
    reports. Thanks Mooneer.

FreeDV Reporter checkbox visibility (#2268, NF0T)

  • Three checkboxes in the FreeDV Reporter tab were rendering with no
    visible borders against the dark background. Applied the standard
    ConnectionPanel checkbox style.

AppletPanel scrollbar (#2257, Chaosuk97)

  • AppletPanel scrollbar widened from 6 px to 12 px with a dim handle
    at rest that brightens to #4a6880 on hover or drag. 500 ms
    delay before dimming back so quick scroll gestures don't flicker.
    Always-visible track to match the rest of the app.

Sweep 1 — 7 small UI / contrast fixes (#2270)

  • AetherSDR vX.Y.Z shown again in the in-app title bar — restored
    after the frameless-window mode regression (#2027).
  • FlexControl knob press tokens are bare S / C / L, not
    X4S / X4C / X4L. Captured against LB2EG's hardware (#2263).
  • Å Morse sequence corrected to 01101 (·−−·−) per ITU-R M.1677-1
    (#2264, LB2EG).
  • Single-click-to-tune suppressed across the entire K / SFI / WNB /
    RF Gain / WIDE indicator strip in the top-right of the spectrum,
    not just the propagation text (#1564).
  • Slice record (⏺) and play (▶) indicator alpha values doubled for
    legibility against the dark spectrum background (#1576).
  • Status indicators (TNF / CWX / DVK / FDX) unified to cyan
    (#00b4d8) for active and dark grey (#404858) for off; TNF init
    colour bug fixed (was semi-transparent white) (#1581).
  • Status bar time stack: removed grid-square label; date + UTC time
    use the same 2-row layout as every other telemetry stack (#1583).

Sweep 2 — 5 small bug fixes (#2272)

  • Double-clicking an off-screen slice indicator (<A / A>) recenters
    cleanly without retuning to a wrong frequency (#2237). Qt's
    press → release → double-click → release sequence was leaving
    m_spotClickConsumed=false on the trailing release, so the
    single-click-to-tune path fired against the new center.
  • HAVE_RADE without HAVE_WEBSOCKETS compile error (#2204) —
    startFreeDvReporting / stopFreeDvReporting now wrap their
    bodies with #ifndef HAVE_WEBSOCKETS no-op fallback.
  • (See "Features" above for #1846 spot mode, #1993 ATU toggle, #2259
    custom filter edges.)

v0.9.4 — AetherSweep, ShackSwitch, and multi-client startup hardening

01 May 04:56
v0.9.4
678ede8

Choose a tag to compare

[v0.9.4] — 2026-05-01

AetherSweep, ShackSwitch, and multi-client startup hardening

A heavy community-contribution release. Headline feature is AetherSweep
(jensenpat) — an in-panadapter SWR sweep analyzer that walks the current TX
band, plots SWR live on the spectrum surface, and handles TGXL bypass +
PGXL checks. ShackSwitch support (nigelfenton) lands as a
new Peripherals tab + dedicated applet, integrating any builder's open-source
Arduino antenna switch over the Antenna Genius protocol.

A trio of substantial reliability fixes from jensenpat addresses long-standing
multi-client startup issues — when SmartSDR or DAX is already connected,
AetherSDR's panadapter creation, slice ownership, and PC audio stream
acquisition now all hold up under the racey status interleavings the
ShackSwitch and DAX users were hitting. Plus a focused mix of platform
fixes: macOS DMG dark-theme on pop-out windows (Chaosuk97), Windows
without-Qt6::SerialPort build (NF0T), NRL gating correctness on 6000-series
radios.

Features

AetherSweep — in-panadapter SWR analyzer (#2202, #2220, #2230, jensenpat)

  • New Start/Clear Sweep buttons under the ANT slice menu, plus a 1-10 W
    sweep-power slider with cross-panel sync. Persisted as
    SwrSweepPowerWatts and defaults to 1 W.
  • Walks the current TX band stepping a tune carrier in 20 kHz increments
    with edge guards, sampling fresh SWR + forward-power meter data per step,
    and overlays the curve on the panadapter directly under the slice flag.
  • Per-band-edge guard, max-260-points cap, and 60 m channelized-band
    refusal. Refuses to start when split is active, when transmitting,
    when the band is wider than the radio's max pan width, or when a PGXL
    amplifier is in OPERATE mode (forces user to STANDBY first).
  • ⚠️ Third-party amplifiers are not auto-detected. AetherSweep
    only checks for Power Genius XL status — it has no way
    to talk to ACOM, SPE, Elecraft KPA, OM Power, or other linear amps.
    If you have a non-PGXL amplifier, manually place it in BYPASS or
    STANDBY before starting an SWR sweep.
    The sweep will run a tune
    carrier through whatever path the radio sees, and a non-bypassed
    external linear will amplify that carrier into your antenna.
  • Full TGXL handling: snapshots OPERATE/BYPASS state, places TGXL into
    BYPASS to read raw antenna SWR, restores original state on completion
    or abort. Reads radio-side SWR while TGXL is bypassed (TGXL stops
    emitting RL meter packets in bypass — #2229).
  • 5-phase state machine with explicit timeouts: WaitingForTgxlBypass,
    TgxlBypassSettle, Sweeping, StoppingTune, RestoringTgxl.
  • Esc to abort. Inputs locked during sweep so the user can't accidentally
    retune mid-pass. Disconnect mid-sweep cleanly stops the carrier and
    releases TGXL.
  • Optimistic setTunePower() update so the sweep's chosen power lands
    immediately rather than racing the radio's status echo.
  • Sweep result label shows source — RADIO for direct measurement,
    TGXL BYPASS for tuner-bypassed measurement.

ShackSwitch antenna switch integration (#2214, #2227, nigelfenton)

  • New Peripherals tab in Radio Setup with auto-discovery and manual-IP
    connect for ShackSwitch devices via the Antenna Genius (AG) UDP/TCP
    protocol on port 9007.
  • New ShackSwitchApplet — compact panel with up to 8 labelled
    antenna-port buttons, click-to-switch, active-port highlight. SO2R
    dual-radio mode shows Input A / Input B side-by-side with conflict
    detection. Single-radio mode (4-port R4 hardware) hides Input B
    automatically.
  • Dummy-load / deselect (clicking the active port deselects it) and
    per-port labels driven by the device's own configuration.
  • Integration is invisible to users without ShackSwitch hardware —
    detected by the name="ShackSwitch" field in the AG broadcast beacon.
  • Web UI launcher button opens the device's local web interface.
  • Reference hardware: ShackSwitch v2.0 (Arduino Uno Q, SO2R, 8-port) and
    ShackSwitch R4 (Arduino Uno R4 WiFi, single-radio, 4-port).

Bug fixes

Multi-client startup panadapter creation (#2222, jensenpat)

  • AetherSDR's startup pan creation now holds up cleanly when SmartSDR,
    DAX, or another GUI/audio client is already connected. The radio
    replays status for all current pans/slices/streams on connect; without
    this fix, AetherSDR could correctly reject other clients' objects but
    then fail to instantiate its own PanadapterModel if ownership status
    arrived out of order.
  • Adds display panafall create x=100 y=100 (FlexLib v4.2.18 syntax)
    with capability-based fallback to legacy panadapter create.
  • New ensureOwnedPanadapter() factory; deferred-status replay queue
    for display pan frames that arrive without client_handle; waterfall
    ordering recovery via panadapter=... parent ID lookup.
  • Routes failure cases through the existing panadapterLimitReached /
    sliceCreateFailed status-bar signals so radio resource exhaustion
    is visible instead of looking like a startup hang.

PC audio remote stream ownership (#2226, jensenpat)

  • Fixes PC Audio failure when SmartSDR / DAX is already running — the
    shared remote_audio_rx pipe was being silently removed because
    AetherSDR was parsing the stream create response body as decimal
    instead of hex. "4000009" (no 0x prefix) was becoming
    0x003D0F09 instead of 0x04000009, so the create-response stream
    didn't match the status-reported stream and AetherSDR removed the
    real one.
  • Extracts a new RadioStatusOwnership helper (header-only, fully
    unit-tested) that handles ownership decisions for both panadapters
    and remote audio streams — defer when no client_handle, claim
    when ours, ignore when another client's.
  • Stream-acquisition state machine now tracks create-pending,
    remove-requested, and adopted-from-status separately so toggling
    PC Audio doesn't race the create response.
  • Adds radio_status_ownership_test with 25 assertions covering all
    the ownership decisions and the headline parse bug.
  • Fixes #2037, #1418, #1473.

TGXL meter goes silent during bypass (#2229, #2230)

  • AetherSweep aborted with "no fresh TGXL SWR meter data" whenever the
    TGXL was in OPERATE before sweep start. The TGXL stops emitting RL
    (return-loss) meter packets while in BYPASS — bypass relays are
    passive wire-through, no measurement engine.
  • Switches the meter source to RADIO while the TGXL is bypassed; the
    radio's own SWR coupler measures the same physical signal through
    the bypassed relays. UI label still shows TGXL BYPASS since
    that's what describes the configuration.

Pop-out applet panel white background on macOS (#2190, Chaosuk97)

  • macOS DMG builds rendered floating windows with a white background
    even though the dark-theme stylesheet was applied — the CI-built
    libqcocoa.dylib enforced Qt::WA_StyledBackground more strictly
    than Homebrew's Qt 6.11.0 build.
  • Adds setAttribute(Qt::WA_StyledBackground, true) on all three
    floating-window classes (FloatingContainerWindow, PanFloatingWindow,
    MainWindow::floatAppletPanel). Cross-platform safe: the attribute
    is harmless on Linux/Windows where it was a no-op, and now the
    pop-out applet panel correctly themed on every platform (was
    defaulting to system theme on Linux/Windows too — latent bug fixed
    as a side effect).

Windows build without Qt6::SerialPort (#2195, NF0T)

  • Compile error introduced by #2147: the <QElapsedTimer> include was
    guarded by #ifdef HAVE_SERIALPORT while m_debounceTimer is declared
    under #if defined(HAVE_SERIALPORT) || defined(Q_OS_WIN). Mismatch
    broke the Windows-without-SerialPort build configuration. Widens the
    include guard to match.

NRL DSP filter visible on 6000-series radios (#2219)

  • Fixes regression from #2184 where NRL was incorrectly grouped with
    the 8000-series-only firmware DSP filters (NRS, RNN, NRF). NRL is
    available on 6000-series too — only NRS/RNN/NRF require BigBend /
    DragonFire hardware. Fixes #2198.

Acknowledgements

Massive contributor batch this cycle:

  • jensenpat — AetherSweep (3 PRs: feature + power-control polish + TGXL
    meter fix), multi-client panadapter startup, PC audio ownership. This
    release wouldn't be the leap it is without his work.
  • nigelfenton — ShackSwitch integration (3 PRs across the cycle:
    protocol fix, full integration, callsign-detection cleanup).
  • NF0T — Windows build fix.
  • Chaosuk97 — macOS DMG dark-theme fix.

v0.9.3 — External APD, FreeDV Reporter, Slice Colors, and v4.2 firmware updater

30 Apr 06:29
v0.9.3
716ee11

Choose a tag to compare

[v0.9.3] — 2026-04-30

External APD, FreeDV Reporter, Slice Colors, and v4.2 firmware updater

A broad release. Headline feature is External APD support for
SmartSDR firmware 4.2.18, which lets the radio sample its outgoing
RF from a coupled feedback path on one of the RX/XVTR inputs so the
predistortion engine trains against the actual transmitted signal —
required when a FLEX-8x00 drives an external linear amplifier.
FreeDV Reporter station reporting (NF0T) lands the long-requested
RADE-integrated reporting flow. chibondking ships customizable
slice colors plus two serial / pop-out fixes. AetherSDR's firmware
updater is rewritten to extract .ssdr files natively from
FlexRadio's v4.2+ MSI installer (no bundled tools needed), and the
NAVTEX data-layer plumbing lands ahead of the upcoming applet.

A long tail of UI polish and Windows-platform fixes also lands —
TX→RX waterfall continuity, scroll-wheel debounce, 48 kHz audio
sink on Windows, applet pop-out persistence, and floating-window
dark theming.

Features

External APD (#2187)

  • New "APD" tab in Radio Setup with per-TX-antenna external sampler
    selection (ANT1 / ANT2 / XVTA / XVTB → INTERNAL / RX_A / RX_B /
    XVTA / XVTB). Tab is hidden unless the radio reports apd configurable=1, so it stays invisible on 6000-series radios and
    pre-4.2.18 firmware.
  • Equalizer Reset button issues apd reset to clear all per-antenna
    training data.
  • Protocol additions: apd sampler sub-object parsing (with
    fallback-to-INTERNAL for invalid selected_sampler), bare
    equalizer_reset flag handling, and the matching setApdSamplerPort
    command path on TransmitModel.
  • Cross-checked against Flex.Smoothlake.FlexLib v4.2.18 source.

FreeDV Reporter station reporting with RADE integration (#2173, NF0T)

  • Adds FreeDV Reporter (https://qso.freedv.org) station-reporting
    support driven by the RADE modem's sync / SNR / freq-offset events.
  • New connection toggle in the DX Cluster dialog plus per-slice
    reporting toggle that mirrors RADE engine state to the Reporter
    WebSocket session.
  • Builds opportunistically — without Qt6::WebSockets or librade,
    the toggles silently become no-ops.

Customizable slice colors (#2155, chibondking)

  • Per-slice color selection through a new SliceColorManager
    singleton. Color assignments persist across sessions and are
    visible in VFO widgets, panadapter overlays, and meter strips.

Native MSI firmware installer support (#2169)

  • The firmware updater can now extract .ssdr files directly from
    FlexRadio's v4.2.18+ MSI installer (which switched from PE/COFF
    self-extracting .exe to WiX 6 MSI). Vendored libmspack
    (LGPL-2.1) handles LZX-compressed CABs; a small OLE Compound File
    reader pulls the embedded CAB from the MSI envelope.
  • "Browse .ssdr" → "Select Installer..." now accepts .msi, .exe,
    and .ssdr. No external tools required (no 7z, no MSI runtime).
  • Format auto-detection on the first 8 bytes (OLE magic vs. PE/COFF MZ).

NAVTEX data-layer plumbing (#2186)

  • New NavtexModel covers the SmartSDR navtex waveform protocol —
    per-message Pending → Queued → Sent / Error state, status parsing
    for navtex and navtex sent, and a navtex send command path
    with proper quote/backslash escaping for msg_text.
  • Foundation for the upcoming NAVTEX applet UI; data layer ships
    first so other clients (TCI, scripting) can already publish NAVTEX
    traffic.
  • 21-assertion unit test covers escaping, idempotency, error paths.

CWX active tracking (#2181)

  • RadioModel tracks CWX send state so the audio gate stays open
    during long character sends.

Floating-window dark theme (#2096, AetherClaude)

  • Pop-out panadapter and floating-container windows now inherit the
    full dark theme via a new Theme.h shared stylesheet, eliminating
    flash-of-light-theme on window construction.

Center active VFO when zooming in from keyboard (#2183, jensenpat)

  • The keyboard zoom-in shortcut now centers the active VFO in the
    viewport (matches the mouse-wheel zoom behavior).

Bug fixes

TX→RX waterfall continuity (#2171, #2182)

  • Force FFT-fallback rendering on TX→RX transition to prevent a
    visible gap in the waterfall (#2171).
  • Blank waterfall rows for 400 ms after TX ends so any residual
    hardware tail doesn't paint over the noise floor (#2182).

Hide 8000-series DSP filters on 6000-series radios (#2184)

  • NRL, NRS, RNN, NRF filters are FLEX-8x00-only. 6000-series
    radios no longer show greyed-out controls for filters they can't
    use.

Stream-status helper consolidation (#2145)

  • Deduplicates the per-stream-type status helpers. Annotates
    m_daxTxClientHandle and documents the TCI receiver-index policy
    for future contributors.

TCP close handshake before socket destroy (#2113)

  • Wait for disconnected() before tearing down the QTcpSocket on
    user-initiated disconnect. Fixes occasional "connection reset"
    reports on the radio side.

rigctld short-form split direction (#2111)

  • S (set split) and s (get split) were transposed in the rigctld
    mapping table, so external loggers couldn't read or set split.

CW sidetone on Windows (#2105)

  • startSidetoneStream() was never called on Windows because the
    audio backend init order put it after the first key event. CW
    sidetone now starts immediately on connect.

48 kHz RX audio sink on Windows (#2123)

  • Prefer 48 kHz over 24 kHz on Windows where WASAPI's resampler
    introduces audible high-frequency artifacts at 24 kHz.

Scrollbar styling on applet panels (#2088)

  • The applet-panel scroll area was inheriting Qt's default thin grey
    scrollbar; restyles to the dark-theme bar.

USB mic level gauge on connect (#2086)

  • The USB mic-level gauge wasn't drawn when connecting with mic source = PC; gauge now appears immediately.

VOX phoneStateChanged on keyboard shortcut (#2084)

  • VOX setters didn't emit phoneStateChanged(), so the UI didn't
    refresh when VOX was toggled via keyboard shortcut.

Scroll-wheel debounce (#2151)

  • Debounces high-frequency pixelDelta scroll events from
    precision-scroll mice in VfoWidget and SpectrumWidget.

Marker-width settings cleanup (#2156, mvanhorn)

  • Slice<N>_MarkerThin setting key is now removed after migration
    to Slice<N>_MarkerWidth instead of being left in place.

Serial PTT — Win32 WaitCommEvent path (#2147, chibondking)

  • FTDI VCP drivers only refresh DSR/CTS in the completion of a
    WaitCommEvent call; AetherSDR's polling-based detection missed
    edges on Windows. Adds a Win32 native event-wait path on top of
    Qt's serial port for DSR detection.

Applet pop-out persistence race (#2154, chibondking)

  • Floating applet windows were sometimes restored at the wrong
    position because the geometry-save signal raced the close event.
    Systemic fix wires save before destruction.

Windows build guard for FreeDV Reporter (#2186)

  • The FreeDV Reporter freedvReportingToggled connect-lambda used
    RADE-guarded symbols inside an #ifdef HAVE_WEBSOCKETS block.
    Windows has WebSockets but no RADE → undefined-identifier compile
    errors. Added the missing HAVE_RADE inner guard.

Docs

  • Data-modes help refresh (#1939) — replaces lingering "DIGI
    applet" references with the current independent-tile UI vocabulary.
  • DIGI applet scrub (#2179) — sweeps the remaining stale
    references in tooltips and dialog text.

Acknowledgements

Thanks to NF0T for the FreeDV Reporter station-reporting
integration; chibondking for slice colors, the serial PTT
WaitCommEvent fix, and the applet pop-out race; jensenpat for
the keyboard zoom-center shortcut; mvanhorn for the marker-key
cleanup; and AetherClaude for the bulk of the long-tail bug
fixes.

v0.9.2.1 — TGXL TUNE for firmware 4.2 hotfix

29 Apr 15:10
v0.9.2.1
49f1df7

Choose a tag to compare

[v0.9.2.1] — 2026-04-29

TGXL direct autotune for firmware 4.2 compatibility

Hotfix release. After upgrading to SmartSDR firmware 4.2, multiple
users on both AetherSDR and SmartSDR report the TUNE button no longer
works on the 4O3A Tuner Genius XL. The radio's tgxl autotune command
path was reworked in 4.2 firmware and broke for many configurations.

This release routes the TUNE button through the TGXL's native
port-9010 channel when a direct TGXL connection is configured,
bypassing the affected firmware path. Users without a direct TGXL
connection are unaffected by this change and should still configure
direct connection in Radio Setup → Tuner to recover TUNE.

Bug Fixes

TGXL TUNE works again on firmware 4.2 (#2163)

  • When a direct TGXL connection (port 9010) is configured, the TUNE
    button now sends the native autotune command directly to the TGXL
    instead of routing tgxl autotune handle=<H> through the radio's
    command channel. Falls back to the radio path when no direct
    connection is available.
  • The TGXL drives radio PTT via its hardware interlock cable when it
    receives the native autotune command, so client-side keying is
    not required. Existing tuning state and SWR readout in the Tuner
    applet are unchanged.

Log redaction no longer mangles 4-component version strings

  • The PII redactor's IPv4 regex matched anything that looked like
    four dot-separated 1-3-digit numbers, so the application's own
    version string 0.9.2.1 was being redacted to *.*.*. 1 in
    logs and support bundles. Negative lookbehind/lookahead now skip
    quoted ("0.9.2.1") and v-prefixed (v0.9.2.1) version forms
    while still redacting bare IPs in log output.

v0.9.2 — WAVE Phase 2, v4.2.18 firmware support, and community polish

29 Apr 05:24
dc3d886

Choose a tag to compare

[v0.9.2] — 2026-04-28

WAVE Phase 2, v4.2.18 firmware support, and community polish

A focused community-driven release. Major work from jensenpat lands
the WAVE Phase 2 applet (four visualizations, settings drawer), proper
TCXO frequency-offset calibration, and the DAX/TCI multi-stream routing
needed for FlexRadio firmware 4.2.18. chibondking and NF0T
ship a serial PTT fix and an r8b heap-corruption crash fix. The VFO
DSP panel gets a UX pass (collapsed Marker + Filter Edge buttons), and
the v4.2.18 discovery beacon is parsed.

Features

WAVE Phase 2 — applet visualization controls (#2124, jensenpat)

  • Double-click the WAVE waveform to open a settings drawer (replaces
    the prior clear-on-double-click behavior). Drawer is open by default
    on first launch for discoverability.
  • New compact View dropdown with four visualizations:
    Scope (the original waveform trace), Envelope (filled RMS with peak
    outline), History (side-scrolling activity bars), Bands (vertical
    EQ-style frequency bands).
  • Persisted Zoom and FPS controls in the drawer. Zoom is amplitude
    gain across all views, not a time-window preference.
  • Drawer participates in the applet size hint when expanded so the
    applet stays compact when collapsed.

DAX-aware TCI multi-stream routing (#2140, jensenpat)

  • Adapts the DAX/TCI audio path for FlexRadio firmware 4.2.18's
    explicit stream-ownership reporting. Filters DAX RX/IQ stream
    status by client_handle so we don't accidentally register another
    client's stream, while accepting ownership-less status from older
    firmware.
  • Advertises TCI receivers as contiguous owned-slice indexes
    (0..N-1) rather than raw Flex slice IDs. Fixes WSJT-X TCI1/TCI2
    multi-slice operation when this client owns slice 1 but another
    client owns slice 0.
  • Honors per-client audio_start:<receiver> so multi-slice WSJT-X
    receives only the intended audio.
  • Stream-removal handling: unregisters DAX/IQ streams and clears TCI
    DAX placeholders on removed status.
  • Adds focused diagnostics for first DAX VITA packets, TCI receiver
    maps, DAX RX delivery, and DAX TX route selection — gated behind
    lcDax / lcCat categories so default users see no extra noise.

TCXO frequency-offset calibration (#2119, jensenpat)

  • Replaces the unsupported radio calibrate command (firmware
    v4.1.5 returns 0x50000016 "unknown command") with the documented
    SmartSDR / FlexLib sequence: radio set cal_freq=, radio set freq_error_ppb=0, radio pll_start.
  • Watches pll_done status for completion with run-specific guards
    against stale events from a prior calibration firing during a new
    run.
  • Cross-checked against FlexLib v2.10.1 source. Fixes #1237, #2095.

VFO marker controls — tri-state Marker, single Filter Edge (#2141)

  • The four-button row (Thin / Thick / Edges / Hide) collapses to two:
    • Marker cycles Off → 1 px → 3 px on click. Off skips both
      the center line and the top triangle, leaving only the passband
      bracket.
    • Filter Edge is a checkable on/off — checked = edges shown.
  • New Slice<N>_MarkerWidth int settings key with one-shot migration
    from the old Slice<N>_MarkerThin bool (True → 1, False → 3).

v4.2.18 discovery beacon parsing (#2138, AetherClaude)

  • Parses two new fields from the FlexLib v4.2.18 discovery packet:
    is_system_model (flags bench / system-build radios) and
    turf_region (turf region indicator distinct from the existing
    region field). turf_region is shown in the connect dialog
    detail line.

Other

  • ATU start added to the keyboard shortcut actions list.
  • Clear action added to the CW decode window context menu (#2116).

Bug fixes

Resampler heap corruption (#2114, NF0T)

  • r8b::CDSPResampler24::process() doesn't bounds-check its l
    parameter; passing a block larger than the constructor's
    aMaxInLen silently overflows internal filter buffers. Bug
    manifested as a crash when the Qt event loop stalled long enough
    for QAudioSource::readAll() to return more than 4096 frames in
    one call (typical during DX-cluster spot bursts or heavy UI
    redraws). Fix: chunk-and-recurse on each process*() path so each
    call stays within the configured limit.

Serial PTT input non-functional (#2125, chibondking)

  • Three layered bugs blocked the serial-PTT path:
    1. No way to open the port without restarting AetherSDR — the
      Serial tab had no Open / Close buttons and the auto-open label
      implied a restart was required.
    2. loadSettings() defaulted CTS / DSR polarity to ActiveLow
      while the dialog combo defaulted to "Active High". Users who
      left polarity at the displayed default got silently inverted
      logic — footswitch press read as inactive, PTT never fired.
    3. updatePolling() was missed when the port was opened, so the
      polling loop didn't pick up the configured input function.
  • Adds Open / Close buttons to the Serial tab, fixes the polarity
    default mismatch, and tracks the explicit Open state separately
    from auto-open via a new SerialPortOpen setting.

Slice audio loss after band changes (#2128, jensenpat)

  • After display pan set band=, the radio sometimes stops mixing
    slice audio without echoing audio_mute=1, leaving the model in a
    "unmuted but silent" state. Fix: 300 ms after the band-change
    command, reassert slice set <N> audio_mute=0 for any unmuted
    slice on that pan.

CWX Live toggle and Send action (#2122, jensenpat)

  • Live button is now a true toggle so operators can turn live
    keying back off (was force-on only).
  • Send button now submits the current input when Live is off
    (matching Enter-key behavior).
  • Setup exits Live cleanly without duplicate-sending text already
    keyed character-by-character.
  • Adds cwx_panel_test covering Live toggling, Send-click
    submission, Enter submission, and Live exit safety.

Connect-radio dialog grouping polish (#2121, jensenpat)

  • Scopes the QFrame callout stylesheet so child labels and
    checkboxes don't inherit the panel border / background, fixing
    nested-bordered-box rendering on macOS, Windows, and Linux.
  • Tightens the SmartLink Remote radio list height and moves the
    Connect Remote button outside the Remote group.

Internal

  • bool m_markerThinint m_markerWidth (0 / 1 / 3) propagated
    through VfoWidget, SpectrumWidget::SliceOverlay, and the
    markerStyleChanged signal. Render path skips both the center
    line and the top triangle when markerWidth == 0.

Acknowledgements

Thanks to jensenpat for the WAVE Phase 2, DAX/TCI, calibration,
band-change, CWX, and dialog polish work; chibondking for the
serial PTT triple-fix; and NF0T for catching the r8b heap-
corruption bug.

v0.9.1 — Local iambic CW keyer + CW transmit reliability

27 Apr 08:08
52bb95b

Choose a tag to compare

[v0.9.1] — 2026-04-27

Local iambic CW keyer, unified sidetone controls, and CW transmit reliability

A focused follow-up to v0.9.0. The headline feature is a software
iambic keyer that turns any MIDI / serial paddle into a sub-5 ms
sidetone source via the new PortAudio backend (issue #2079) — the
radio still produces the on-air signal, but the local sidetone
gate fires the moment the paddle moves instead of waiting for the
radio's keyed-back signal. Three latent bugs in the netcw protocol
path that prevented CW from ever transmitting on FLEX-8600 v4.1.5
firmware are also fixed. Plus the CW panel collapses three sidetone
widget groups into one set of controls and finally wires up the L/R
pan slider that's been a placeholder since the panel was first added.

Features

Local iambic keyer for sub-5 ms paddle sidetone (#2079)

  • Software iambic state machine that runs alongside the radio's RF
    iambic engine. Both engines see the same paddle inputs at the same
    WPM and produce identical Morse timing — but the local keyer drives
    the sidetone gate directly, avoiding the 50–200 ms round-trip
    through the radio's keyed-back signal.
  • Modes A and B implemented (Ultimatic / Bug / Straight follow in a
    later phase). Hooked into both MIDI Gate params (cw.dit,
    cw.dah) and serial paddle paths (DTR/CTS via SerialPortController).
  • Driven by the existing radio Iambic toggle — no new UI clutter.
    The keyer mirrors the radio's iambic state, mode, and WPM via the
    TransmitModel phoneStateChanged signal.
  • Dedicated worker thread with std::chrono::steady_clock timing
    and a lock-free atomic key gate on the audio side. 9 unit tests
    covering single dit/dah timing, squeeze alternation, inter-element
    gap, mode A release behaviour, WPM scaling, paddle swap, idempotent
    start, and idle behaviour.

Sidetone controls unified (#2079)

  • The CW panel previously had three separate sidetone widget groups:
    the radio's "Sidetone" toggle/volume, a "Local STn" toggle/volume
    for the local PortAudio sidetone, and a "Follow" pitch row with a
    manual override slider. All three are now collapsed into the
    single existing Sidetone button, which drives both engines in
    lockstep. The volume slider drives mon_gain_cw on the radio and
    the local sidetone identically. Pitch always follows the radio's
    cw_pitch.

CW pan slider wired up (#2079)

  • The L/R pan slider in the CW panel was a dead UI element with a
    TODO comment. Now drives both the radio's mon_pan_cw (radio-side
    sidetone pan within the RX audio stream) and the local sidetone
    with constant-power pan law (cosine/sine for equal-loudness sweep,
    no center dip). Double-click on the slider recenters to 50.

Slice capacity notification (#48)

  • Status-bar warning when adding another panadapter would exceed the
    radio's slice limit. Three guard points cover the pre-flight check
    in the layout dialog, the runtime check in applyPanLayout, and
    the async fallback when the radio rejects a panafall create.
    Includes the radio model name and slice count in the message.

PortAudio sidetone via JACK on Linux (#2075 follow-up)

  • The PortAudio sidetone backend (introduced in v0.9.0) now prefers
    the JACK host API on Linux when available, with paFramesPerBuffer = 128 + suggestedLatency = 0 for sub-5 ms quantum. PipeWire's
    ALSA shim silently breaks callback-mode streams on some setups
    (Pa_StartStream returns success but the audio thread never
    schedules the callback); pipewire-jack delivers reliable callbacks
    at the device's native sample rate. 48 kHz is now the universal
    preference, with Pa_IsFormatSupported guarding fallback.

Bug fixes

CW transmit: invalid paddle command form

  • RadioModel::sendCwPaddle was emitting cw key 1 0 (a 2-arg paddle
    form) which the radio's protocol does not accept — FlexLib only
    ever sends single-state cw key 1 or cw key 0 and expects the
    client to do iambic timing locally. The 2-arg form was silently
    dropped, so paddle keying produced no RF. Now collapses to a
    straight-key form when the local iambic keyer isn't running, or
    routes through the new sendCwKeyEdge + sendCwPtt primitives
    when it is.

CW transmit: lowercase hex in netcw payload

  • FlexLib formats time=0x... and client_handle=0x... with C#
    ToString("X") (uppercase), and the radio's status messages do
    too (e.g. S23A59BDF|...). Firmware v4.1.5's netcw parser is
    case-sensitive on these fields and silently dropped lowercase
    packets. Now formatted explicitly uppercase.

CW transmit: dead TCP fallback

  • The post-UDP TCP fallback was sending the netcw-decorated form
    (cw key 1 time=0x... index=... client_handle=0x...) which the
    radio rejects with 0x50001000 ("command syntax error") on TCP.
    Removed when the netcw stream is up; the no-netcw fallback (for
    firmware that doesn't support netcw stream creation) is preserved
    separately.

Optimistic updates for CW model setters

  • setCwIambic, setCwIambicMode, setCwSpeed, and setCwPitch
    on TransmitModel previously sent the command to the radio
    without updating local state, on the assumption that the radio
    would echo the new value back. Firmware v1.4.0.0 doesn't reliably
    echo iambic flags, WPM, or pitch in transmit status messages, so
    any code reading these properties after a UI toggle saw stale
    values until the next periodic transmit status arrived (or never).
    Now follow the same optimistic-update pattern as setCwBreakIn.

Block on graceful disconnect (#1996, openstreem)

  • RadioModel::disconnectFromRadio now uses Qt::BlockingQueued Connection for both the gracefulDisconnect lambda and the
    fallback disconnectFromRadio call, matching the destructor's
    pattern. Without this, the queued work could be cancelled before
    it ran during app teardown — leaving the radio with a stale
    session that required a power cycle.

Memory recall: restore repeater offset and tone (#1871, #1965, jensenpat)

  • Recalled FM repeater memories properly restore repeater_offset_dir,
    fm_repeater_offset_freq, derived tx_offset_freq, and CTCSS tone
    state. Previously, switching from a repeater memory to simplex
    could leave stale TX offset state on the slice.

m_activeTxSlice initializer mismatch (#2076)

  • Default-init was 0 but clear() sets to -1. Now both default
    to -1 so a fresh MeterModel and a cleared one have identical
    activeTxSlice() state.

Per-slice compression meter resolution (#2073)

  • TX-chain COMPPEAK, AFTEREQ, and SC_MIC meters are now
    resolved per active slice instead of last-match-wins, fixing
    Multi-Flex setups where the wrong slice's compression value was
    surfaced in the UI.

ContainerWidget restoreState displaces children

  • restoreState re-inserted children at indices 0..N–1 even when
    they were already in the layout, displacing non-saved children
    like the CHAIN widget. insertChildWidget is now a no-op when
    the child is already present.

Build and CI

  • M_PI_2 replaced with a local kPiOver2 constexpr in
    CwSidetoneGenerator.cpp so the Windows MSVC build doesn't
    fail (<cmath> doesn't define M_PI_2 without _USE_MATH_DEFINES).

Acknowledgements

Thanks to the operators who tested CW workflows on real hardware
and surfaced the netcw protocol issues that had been silent since
the netcw backend landed, and to jensenpat and openstreem
for the community fixes bundled in.

v0.9.0

26 Apr 05:26
v0.9.0
1fa55e3

Choose a tag to compare

Aetherial Audio RX, frameless UI, and local CW sidetone

A milestone release. The Aetherial Audio suite — Parametric EQ, AGC-T
gate, AGC-C compressor, Tube saturator, and PUDU exciter — now runs
on both RX and TX with fully independent settings, drag-to-reorder
on each path, and matching frameless editor windows. The whole UI
goes frameless: the main window plus every applet pop-out and editor
gets a Discord-style minimise / maximise / close trio with title-bar
drag. CW operators get a dedicated low-latency local sidetone sink
that survives CWX too. Plus community fixes for the FLEX-6000
compression meter, RTTY mark-default reset, RADE decoded audio, and
the usual stack of UX polish.

New to the Aetherial Audio chain? See the Aetherial Audio wiki page for the full guide, including the new RX-chain section.

Features

Aetherial Audio RX chain (#1998)

  • Reuses the existing TX DSP modules (Parametric EQ, gate/expander,
    compressor, tube saturator, PUDU exciter) on the RX path with
    fully independent state from TX. Each stage is a tile in the
    CHAIN widget on the RX side: single-click toggles bypass,
    double-click opens the floating editor. RX chain order is
    drag-to-reorder. RADIO and SPEAK status tiles bookend the chain;
    the DSP tile shows whichever client-side noise reducer is active
    (NR2 / NR4 / BNR).
  • All applet titles rebrand to Aetherial: Parametric EQ,
    AGC-T (gate), AGC-C (compressor), Tube, PUDU.

Frameless main window with custom title bar (#1926)

  • Main window now uses Qt::FramelessWindowHint with a custom
    20 px title bar carrying drag-to-move via startSystemMove,
    double-click maximise, and a Discord-style minimise / maximise /
    close trio. Resize via standard window-edge grip.

Frameless pop-out windows for applets and panadapters (#1922)

  • Every floating applet and panadapter pop-out gains the same
    frameless title bar with the trio. Single-click trio actions,
    drag the bar to move, double-click to maximise.

Frameless editor windows for the entire Aetherial chain (#1998)

  • Aetherial Parametric EQ, AGC-T, AGC-C, Tube, PUDU, and Reverb
    editors all use the same shared title-bar widget with drag and
    trio. Title text reads "Aetherial <Stage> — <Side>" so the
    TX vs RX instance is identifiable at a glance.

Polish frameless title bar (#1931)

  • Title-bar trio refined to a Discord-style sequence; dropped the
    lightbulb icon in favour of a minimal arrow accent so the trio
    sits flush against the right edge.

Local CW sidetone with low-latency sink + CWX support (#1969)

  • Dedicated low-latency local sidetone path that bypasses the
    protocol-level monitor for keying feedback that doesn't fight
    network jitter. Works for paddle, straight key, and CWX
    generated transmissions. Pitch and gain follow the existing
    pitch / mon_gain_cw controls.

Two-Tone Tune shortcut (#1995, jensenpat)

  • New unassigned Two-Tone Tune keyboard action under the TX
    shortcut category. Sends transmit set tune_mode=two_tone
    before starting Tune, toggles off on a second press, and
    restores tune_mode=single_tone on stop so the regular TUNE
    press isn't surprised by sticky two-tone state.

XVTR diagnostic logging (#1964)

  • New xvtr logging category captures status messages, RF↔IF
    frequency translation, and pan-bandwidth conversions so XVTR
    setup issues can be diagnosed from log bundles instead of pcap.

XVTR policy regression tests (#1960)

  • Test harness covers transverter active/inactive state, RF↔IF
    conversion, and the family of pan-recenter cases that used to
    drop the waterfall when crossing IF/RF boundaries.

Bug fixes

Flex compression meter derivation across radio families (#1992, jensenpat)

  • FLEX-8000 series exposes TX/AFTEREQ at 20 fps as the post-EQ
    reference for compression display; FLEX-6000 captures don't
    expose AFTEREQ, so the best matching reference is TX/SC_MIC
    at 10 fps with TX/COMPPEAK still at 20 fps. Mixed cadence is
    guarded by a freshness check so a fresh COMPPEAK isn't compared
    against a stale SC_MIC sample. When AFTEREQ is present it
    takes precedence over SC_MIC.

Preserve rtty_mark_default when radio resets mark on band change (#1968, chibondking)

  • The radio resets slice rtty_mark to 2125 in the status broadcast
    that follows a band change, regardless of the configured
    rtty_mark_default. SliceModel::applyStatus() was accepting
    the 2125 value blindly, overwriting the user's configured mark.
    Now tracks m_rttyMarkDefault (seeded from RadioModel) and a
    user-override flag so the correct default is pushed back when
    the radio resets, without fighting an intentional 2125 selection.

Fix choppy/harsh RADE decoded audio: dedicated buffer + sample-wise mix (#1953, NF0T)

  • RADE decoded audio was sharing the SSB output buffer, producing
    glitches and harsh artefacts on decoded voice. Split into a
    dedicated buffer with per-sample mixing into the speaker output
    so RADE and SSB don't fight for the same write window.

Fix CoreMIDI init crash during MIDI auto-connect (#1949, jensenpat)

  • macOS CoreMIDI initialisation could crash on launch when
    auto-connect ran before the MIDI client was fully constructed.
    Init order tightened so the client is ready before any
    auto-connect attempt.

Restore shortcuts after slider nudges (#1952, jensenpat)

  • Shortcut bindings could go stale after the user nudged a slider
    with the keyboard, because focus stayed on the slider and ate
    subsequent shortcut keystrokes. Focus now returns to the main
    window after a slider nudge.

Preserve MIDI bindings when saving device settings (#1951, jensenpat)

  • Saving MIDI device settings was overwriting bindings with an
    empty map because the save path read from the wrong source.
    Now the existing binding map is merged into the saved settings.

Cancel frequency entry with Escape (#1954, jensenpat)

  • The numeric frequency-entry buffer didn't honour Escape, so a
    user who started typing a frequency had to clear the buffer
    manually. Escape now cancels the entry cleanly.

Gate XVTR waterfall tile shifts (#1925, jensenpat)

  • Waterfall tile-shift logic continued to fire on XVTR pans even
    when the IF↔RF frequency relationship made the shift meaningless,
    producing visual tearing. Shifts are now gated on transverter
    state.

Close all floating windows when main window closes (#1920, chibondking)

  • Floating applet pop-outs and panadapter pop-outs were left as
    orphaned top-level windows when the main window was closed,
    forcing the user to close each one individually. All
    floating children now close together with the main window.

Build and CI

cmake: declare Qt 6.2 minimum (#1962)

  • startSystemMove is gated behind Qt 6.2; the build now declares
    the minimum explicitly so older systems get a clean configure
    error rather than a confusing link failure. Matches Ubuntu
    22.04 LTS shipped Qt.

ci(windows): switch to Ninja so sccache actually wraps cl.exe (#1963)

  • The Windows CI job was using MSBuild, which sccache can't wrap
    for compilation caching. Moved to Ninja so the sccache layer
    established in #1913 actually has effect, cutting Windows build
    times further.

ci: speed up Windows build with sccache + Qt/FFTW caching (#1913)

  • Adds sccache for compiler caching plus GitHub Actions cache
    layers for Qt and FFTW dependencies. First-run pulls populate
    the cache; subsequent CI runs reuse compiled objects and prebuilt
    third-party artefacts.

Add /bigobj to MSVC compile options (#1910#1911)

  • The compilation unit hit the C1128 section count limit on
    MSVC. /bigobj raises the limit so the unit compiles cleanly
    without splitting the file.

Dependencies

  • Bump mozilla-actions/sccache-action from 0.0.6 to 0.0.10 (#1941)
  • Bump actions/cache from 4 to 5 (#1942)

Acknowledgements

Massive cycle. jensenpat delivered eight PRs this release —
including the FLEX-6000 compression meter derivation, two-tone
Tune shortcut, XVTR diagnostic logging and regression tests, and
four crash/UX fixes (CoreMIDI init, MIDI binding persistence,
slider-nudge focus, frequency-entry Escape). chibondking
shipped two PRs (RTTY mark-default preservation and the
floating-window close cascade). Thanks also to NF0T for the
RADE decoded-audio dedicated-buffer fix.

73, Jeremy KK7GWY


Downloads

Platform Asset
Linux x86_64 AetherSDR-v0.9.0-x86_64.AppImage
Linux aarch64 (Raspberry Pi 5) AetherSDR-v0.9.0-aarch64.AppImage
macOS (Apple Silicon) AetherSDR-v0.9.0-macOS-apple-silicon.dmg
macOS (Intel) AetherSDR-v0.9.0-macOS-intel.dmg
Windows x64 (installer) AetherSDR-v0.9.0-Windows-x64-setup.exe
Windows x64 (portable) AetherSDR-v0.9.0-Windows-x64-portable.zip
Stream Deck plugin com.aethersdr.radio.streamDeckPlugin
StreamController plugin streamcontroller-aethersdr.zip

The git tag v0.9.0 is GPG-signed (key 01FBE34B4639247E); macOS bundles are Apple-signed and notarised.