Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions BUILD-OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@ alone. MSVC flags and `Release` builds are unaffected.

| Option | Default | Purpose and prerequisites |
|---|---|---|
| `ENABLE_DEEPFIST_EXPERIMENT` | OFF | Build the experimental DeepFist CW receive decoder. Requires ONNX Runtime at configure time (configuration fails without it) and a separate verified model bundle at runtime; see below. |
| `ENABLE_RTL` | ON | Build the experimental receive-only RTL-SDR USB backend when both `librtlsdr` and single-precision FFTW (`fftw3f`) are found. Missing either disables the backend unless `REQUIRE_RTL=ON`. |
| `AETHER_HL2_TX_TXA` | ON | Select WDSP's TXA chain as the Hermes-Lite 2 transmit modulator: SSB, AM, DSB and FM. OFF builds the in-tree phasing modulator, which is SSB only; AM, DSB and FM then stay receive-only. This choice has no runtime toggle. |

**DeepFist:** enabling `-DENABLE_DEEPFIST_EXPERIMENT=ON` alone does not supply its
model. The configured model-download URL defaults to empty. For developer
qualification, the runtime environment variable `AETHER_DEEPFIST_MODEL_DIR`
can point to the exact verified bundle; it is not a CMake switch. The required
assets and distribution prerequisite are described in
**Neural CW decoders:** DeepFist and DeepCW build whenever ONNX Runtime is
found at configure time (Apple Silicon macOS, Linux and Windows; the pinned
runtime has no Intel-macOS build), with no separate option. Neither model is
bundled: each downloads on first use from its upstream source at a pinned size
and SHA-256. For developer qualification, the runtime environment variables
`AETHER_DEEPFIST_MODEL_DIR` and `AETHER_DEEPCW_MODEL_DIR` point at a local
copy instead; they are not CMake switches. See
[the DeepFist guide](docs/deepfist-cw-backend.md). ggmorse remains the default
CW receive decoder.

Expand Down Expand Up @@ -149,7 +150,7 @@ the ASR library (`aetherasr`) sees.
| `HAVE_NVIDIA_AFX` | `ENABLE_NVIDIA_AFX` on x86-64 Linux or Windows. |
| `HAVE_MQTT` | `ENABLE_MQTT`. |
| `HAVE_MQTT_TLS` | `MQTT_TLS`, and for the bundled library OpenSSL is found. |
| `HAVE_DEEPFIST` | `ENABLE_DEEPFIST_EXPERIMENT`. |
| `HAVE_DEEPFIST`, `HAVE_DEEPCW`, `HAVE_CW_RX_BACKENDS` | ONNX Runtime is found. |
| `HAVE_MIDI` | Always; RtMidi is bundled. |
| `HAVE_SERIALPORT`, `HAVE_WEBSOCKETS`, `HAVE_KEYCHAIN` | The Qt SerialPort, Qt WebSockets or QtKeychain package is found. |
| `HAVE_DBUS` | Qt DBus is found on Linux or another non-Apple Unix; it is never looked for on macOS or Windows. |
Expand Down Expand Up @@ -178,7 +179,7 @@ Additional cache values accept a value rather than ON/OFF:
| Setting | Default | Values and purpose |
|---|---|---|
| `AETHERSDR_SANITIZER` | `none` | `none`, `address`, `undefined`, `address,undefined`, or `thread`. Instruments the main CMake tree with a GNU-driver GCC/Clang build; MSVC and clang-cl are rejected, and so is combining `address` with `thread`. Adds `-g3 -fno-omit-frame-pointer` to every configuration, Release included. ExternalProject children need separate sanitizer flags. |
| `DEEPFIST_MODEL_BASE_URL` | Empty | Published, versioned HTTPS directory for the exact DeepFist assets. See the distribution prerequisite in [the DeepFist guide](docs/deepfist-cw-backend.md). |
| `DEEPFIST_MODEL_BASE_URL` | Empty (N9BC's `exp27_bt-champion` release) | Replaces the HTTPS directory holding the exact DeepFist model assets; empty uses the published release. The LICENSE asset carries its own pinned source. See [the DeepFist guide](docs/deepfist-cw-backend.md). |
| `RADE_TAP_DIR` | `<build-directory>/rade_taps` | Directory for RADE WAV diagnostics; available when RADE and its taps are enabled. |
| `AETHER_TEST_FFTW_TIMELIMIT` | `0.001` | Seconds FFTW may spend measuring each plan under test; an empty value allows unbounded measurement. |
| `AETHER_SANITIZER_TIMEOUT_SCALE` | `4` | Positive integer. Multiplier applied to every test `TIMEOUT` when the build is sanitizer-instrumented (`AETHERSDR_SANITIZER` set, or `-fsanitize=` in the global C/C++ flags or in any configuration's `CMAKE_<LANG>_FLAGS_<CONFIG>`). An uninstrumented build keeps every limit exactly as written. |
Expand Down
47 changes: 33 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3173,27 +3173,36 @@ endif()

target_sources(aethercore PRIVATE src/models/CwRxModel.cpp src/models/CwRxModel.h)

option(ENABLE_DEEPFIST_EXPERIMENT "Build the local DeepFist CW prototype" OFF)
set(DEEPFIST_MODEL_BASE_URL "" CACHE STRING "Published, versioned HTTPS DeepFist asset directory (empty before publication)")
if(ENABLE_DEEPFIST_EXPERIMENT)
if(NOT ORT_FOUND)
message(FATAL_ERROR "The DeepFist prototype requires the packaged ONNX Runtime")
endif()
target_compile_definitions(aethercore PUBLIC HAVE_DEEPFIST)
target_compile_definitions(aethercore PRIVATE DEEPFIST_MODEL_BASE_URL="${DEEPFIST_MODEL_BASE_URL}")
# Neural CW receive decoders (RFC #4817): built wherever ONNX Runtime is found
# (Apple Silicon, Linux, Windows; the pinned runtime has no Intel-macOS build).
# Their models are never shipped: each downloads on first use from its upstream
# release at a pinned size and SHA-256.
# Empty selects the published release; a value replaces it. Not a cache default,
# so build directories configured before the release keep downloading.
set(DEEPFIST_MODEL_BASE_URL "" CACHE STRING "DeepFist asset directory override (empty = the published release)")
set(_deepfist_model_url "https://github.com/n9bc/DeepFist/releases/download/exp27_bt-champion/")
if(DEEPFIST_MODEL_BASE_URL)
set(_deepfist_model_url "${DEEPFIST_MODEL_BASE_URL}")
endif()
target_compile_definitions(aethercore PRIVATE DEEPFIST_MODEL_BASE_URL="${_deepfist_model_url}")

if(ORT_FOUND)
target_compile_definitions(aethercore PUBLIC HAVE_ONNX)
# Every CW receive backend beyond ggmorse needs ONNX Runtime, so this one
# gate decides whether the CW panel offers a decoder selector (RFC #4817).
target_compile_definitions(aethercore PUBLIC HAVE_DEEPFIST HAVE_DEEPCW HAVE_CW_RX_BACKENDS)
target_sources(aethercore PRIVATE
src/models/DeepFistCwModel.cpp src/models/DeepFistCwModel.h
src/core/deepfist/DeepFistStream.cpp
src/core/deepfist/DeepFistModelAssets.cpp src/core/deepfist/DeepFistModelAssets.h
third_party/deepfist/DeepFistConditioner.cpp
third_party/deepfist/DeepFistSpectrogram.cpp
third_party/deepfist/DeepFistCtc.cpp
third_party/deepfist/DeepFistModel.cpp)
third_party/deepfist/DeepFistModel.cpp
src/core/DeepCwEngine.cpp src/core/DeepCwEngine.h
src/core/DeepCwCommitter.cpp src/core/DeepCwCommitter.h
src/models/DeepCwRxBackend.cpp src/models/DeepCwRxBackend.h
src/core/CwModelAssets.cpp src/core/CwModelAssets.h)
target_include_directories(aethercore PRIVATE "${CMAKE_SOURCE_DIR}/third_party/deepfist")
endif()

if(ORT_FOUND)
target_compile_definitions(aethercore PUBLIC HAVE_ONNX)
# PUBLIC include dir: core/SignalClassifier.h includes onnxruntime under
# HAVE_ONNX (PUBLIC) and is pulled in by gui/MainWindow.h. Same transitive
# leak as FFTW3 above. Library link stays PRIVATE (transitive via the lib).
Expand Down Expand Up @@ -3540,6 +3549,16 @@ endforeach()
# it keep resolving against the repository root. The header of that file explains
# why that matters and why it should not be "tidied up" into a subdirectory.
enable_testing()
# DeepCW offline replay harness (RFC #4817 regression take): not built by default.
if(ORT_FOUND)
add_executable(deepcw_replay EXCLUDE_FROM_ALL
tools/deepcw_replay.cpp src/core/DeepCwEngine.cpp src/core/DeepCwCommitter.cpp
src/core/Resampler.cpp)
target_compile_definitions(deepcw_replay PRIVATE HAVE_ONNX)
target_include_directories(deepcw_replay PRIVATE src
${CMAKE_SOURCE_DIR}/third_party/r8brain ${ORT_INCLUDE_DIRS})
target_link_libraries(deepcw_replay PRIVATE Qt6::Widgets ${ORT_LIBRARIES})
endif()
include(tests/tests.cmake)


Expand Down
48 changes: 46 additions & 2 deletions THIRD_PARTY_LICENSES
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,8 @@ report PortAudio/portaudio#1176.
Source: https://github.com/PortAudio/portaudio (tag v19.7.0, sha256
5af29ba58bbdbb7bbcefaaecc77ec8fc413f0db6f4c4e286c40c3e1b83174fa0)

DeepFist native helpers (experimental)
--------------------------------------
DeepFist native helpers
-----------------------
MIT License

Copyright (c) 2026 Brent Crier
Expand Down Expand Up @@ -766,3 +766,47 @@ license text is in third_party/littlefs/LICENSE.md.
Copyright (c) 2017, Arm Limited.
License: BSD-3-Clause
Source: https://github.com/littlefs-project/littlefs


32. DeepCW — Neural CW Decoder (ported code in-binary + model download-on-demand)
---------------------------------------------------------------------------------
The optional neural CW decode backend (DeepCwEngine, RFC #4817). Unlike the
download-only ASR entries above, this has TWO distinct AGPL-3.0 obligations:

a) Ported code (compiled into the binary). src/core/DeepCwEngine.{h,cpp} is a
C++ port of decode_morse.py from e04/deepcw-engine — the spectrogram build
(256-pt FFT, hop 48, periodic Hann, 400-1200 Hz -> 65 bins, log1p) and the
greedy-CTC decode. A faithful port of AGPL-3.0 source is a derivative of it,
so this code ships AGPL-3.0 in every binary regardless of whether a user
ever downloads the weights. AetherSDR is GPL-3.0-or-later; GPLv3 §13
permits the combination (its only added obligation, AGPL's network clause,
affects hosting the combined work as a network service — desktop use is
unaffected, and AetherSDR source is already public).

b) Model weights (NOT bundled). Downloaded on first enable of the DeepCW
backend (source: the e04/deepcw-engine repository), SHA-256-verified,
cached under the user's data dir. Run by ONNX Runtime (entry 11).

Attribution: "deepcw-engine" by e04.
License: AGPL-3.0-or-later (both the ported code and the model)
Source: https://github.com/e04/deepcw-engine


33. DeepFist — CW model weights (download-on-demand)
-------------------------------------------------------------------------------
The exp27_bt-champion model (deepfist.onnx and deepfist.onnx.json) is downloaded
on first selection, never bundled or mirrored by AetherSDR. Size and SHA-256
are pinned in src/core/CwModelAssets.cpp. The accompanying LICENSE is fetched
from the release tag's resolved source revision, not a historical MIT revision.
The native helpers' separate historical MIT notice above remains in effect.

Copyright: Copyright (C) 2026 Brent Crier (N9BC)
License understanding: GPL-3.0-or-later, following the published release's
LICENSE and README; accepted for this pinned download by the
operator on 2026-10-17. This is not a separate upstream ruling on
the older checkpoint. See docs/deepfist-cw-backend.md.
Release: https://github.com/n9bc/DeepFist/releases/tag/exp27_bt-champion
Source: https://github.com/n9bc/DeepFist/tree/930bd3cea7d9bf19fd45413acc9064b54c722871
License: https://raw.githubusercontent.com/n9bc/DeepFist/930bd3cea7d9bf19fd45413acc9064b54c722871/LICENSE
LICENSE: 35927 bytes; SHA-256
d8dcabd2c59c9e96be89f094a94474685e3fcd5ee8c4304ae7fbbf6c722df6ab
65 changes: 37 additions & 28 deletions docs/deepfist-cw-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
This implementation supplies a shared `CwRxModel` receive-backend interface and
an optional DeepFist backend. ggmorse remains the default receive decoder and
continues to decode transmit sidetone. Only the selected receive backend runs.
The RFC is #4817; DeepCW remains outside this change. The operator authorized
preparing this PR before DeepCW, overriding the earlier implementation order.
The RFC is #4817. DeepCW is the third backend, behind the same interface.

DeepFist consumes selected-slice pre-monitor PCM through `PcmFrame`, resamples
on its worker, and uses the pinned native Lyra frontend. Source changes, discontinuities,
Expand All @@ -25,26 +24,23 @@ DeepFist output does not feed automatic callsign spotting. Other monitored
slices and speaker gain/mute do not alter the selected decoder input. This is
an audio slice tap, not an RF separation claim.

## Distribution prerequisite
## Distribution

**Not ready for general release:** no upstream standalone download directory
has been established for this exact model bundle. As checked during PR
preparation, n9bc/DeepFist publishes no release assets or committed weights;
Lyra's releases expose Windows installers, not the three standalone files.
The application must not download or execute an installer to obtain a model.

`ENABLE_DEEPFIST_EXPERIMENT` is therefore default OFF and requires ONNX Runtime
when enabled. `DEEPFIST_MODEL_BASE_URL` remains empty. A missing model produces
an unavailable status, not a request to an invented endpoint. A developer can
point `AETHER_DEEPFIST_MODEL_DIR` at the exact verified bundle for qualification.
This override is not the intended end-user installation workflow.

Before enabling the feature in released builds, the upstream author must
publish the exact assets at a versioned HTTPS directory and confirm model
redistribution provenance. Then configure that directory, exercise the real
public download, and test fresh-cache, cancellation, retry and offline reuse
on each supported platform. The RFC's upstream-only hosting decision remains
in effect; this change does not publish an AetherSDR mirror.
DeepFist builds whenever ONNX Runtime is found (Apple Silicon macOS, Linux and
Windows); there is no separate option. The model is never bundled with the
application. It downloads from N9BC's versioned `exp27_bt-champion` release
(`https://github.com/n9bc/DeepFist/releases/download/exp27_bt-champion/`), whose
`deepfist.onnx` and `deepfist.onnx.json` match the pinned lengths and hashes
below; a non-empty `DEEPFIST_MODEL_BASE_URL` replaces that directory.
The release has no separate LICENSE asset. The manifest downloads its license
from the release tag's resolved commit,
[`930bd3cea7d9bf19fd45413acc9064b54c722871`](https://github.com/n9bc/DeepFist/tree/930bd3cea7d9bf19fd45413acc9064b54c722871),
using a commit-pinned HTTPS URL and the exact size/hash below. The shared
`CwModelAssets` downloader serves each decoder's own catalog. The RFC's
upstream-only hosting decision remains in effect; there is no AetherSDR mirror.
A developer can point `AETHER_DEEPFIST_MODEL_DIR` at a local verified bundle.
An older cache keeps its model and metadata; its historical LICENSE is
re-verified and replaced from the pinned source before the bundle is ready.

The downloader verifies exact lengths and SHA-256 hashes, takes a cache lock,
uses atomic file replacement, and checks the complete bundle before loading.
Expand All @@ -56,13 +52,26 @@ removed asset available to new installations.
|---|---:|---|
| deepfist.onnx | 13051998 | 6d2d4e3d66f9001d15e21a1b38b79150eae19ead86a310202900ee69d672b94d |
| deepfist.onnx.json | 1257 | 840ceb8dba9d46d04495547a8a3789968b1acd2f8ac3a3a5c631f84008ac2217 |
| LICENSE | 1068 | 9ad70a9ed30d58502e29f9e691a008ee7bccb6eba49d4384f2b7e675d68dc4f3 |
| LICENSE | 35927 | d8dcabd2c59c9e96be89f094a94474685e3fcd5ee8c4304ae7fbbf6c722df6ab |

### License understanding

For the `exp27_bt-champion` download, AetherSDR follows the upstream release
revision's [GPL-3.0-or-later license](https://github.com/n9bc/DeepFist/blob/930bd3cea7d9bf19fd45413acc9064b54c722871/LICENSE)
and [README license notice](https://github.com/n9bc/DeepFist/blob/930bd3cea7d9bf19fd45413acc9064b54c722871/README.md#license).
The model predates upstream's MIT-to-GPL change; that history does not create
an incompatibility with AetherSDR's GPLv3 licensing. MIT is also
[GPL-compatible](https://www.gnu.org/licenses/license-list.html#Expat), with
its notices preserved. The operator accepted using the published release's
GPL terms for this pinned download on 2026-10-17. This records the project's
current understanding, rather than claiming a separate upstream clarification
of the historical checkpoint's license. Future model revisions need their own
provenance and pins.

The original PR's qualification used a bundle extracted from the Lyra 0.24.0
installer as an archive. It is not committed or bundled into AetherSDR. Native helpers retain
their pinned historical MIT license and attribution under
`third_party/deepfist`; later upstream licensing does not identify the license
of a different checkpoint or future update.
The native helpers under `third_party/deepfist` retain their pinned historical
MIT license and attribution. The model is downloaded directly from upstream;
it is neither committed nor bundled into AetherSDR. Its attribution and pinned
license source are also recorded in `THIRD_PARTY_LICENSES`.

## Validation contract

Expand All @@ -72,7 +81,7 @@ is disabled. The committer and injected model-assets tests also run in the
default build, without ONNX Runtime or weights. Optional worker tests use
injected PCM and download replies. Real inference tests require the pinned local
bundle and return skip code 77 when absent; a skipped test is not model proof.
Tests behind the default-OFF option do not run in the default CI graph.
Tests that need ONNX Runtime do not run in the default CI graph, which installs none.

Synthetic replay has shown useful gains from normalization and emission
protection. Those measurements are not an accuracy estimate for arbitrary
Expand Down
Loading
Loading