GUI Application for FreeDV – open source digital voice for HF radio
 
 
 
 
 
 
Go to file
Mooneer Salem 2c7aa5ff82
Windows CI: RADE loss testing + ASan/UBSan sanitizer coverage (#1487)
* CI (Windows): add RADE loss testing (prerequisite for sanitizer coverage)

Ports the RADE loss test infrastructure from the ms-rade-v2 branch
(as of commit f013450b there) so the Windows sanitizer jobs added in
the following commits have a RADE loss test to actually run:

- test/TestFreeDVRadeLoss.ps1: transmits a known corpus through FreeDV,
  records the result, plays it back through RX, and compares TX/RX RADE
  features via loss.py against a threshold.
- test/RadeVerificationReport.ps1: assembles the RADE integration
  verification report from a test run.
- cmake-windows.yml: adds the rade-loss-baseline job (computes the loss
  threshold from a software-only baseline on Linux, since rade_tx_wav/
  rade_rx_wav are excluded from the Windows build), wires RADE loss
  testing and verification-report generation into the `test` job, adds
  crash dump collection (WER LocalDumps) for post-mortem diagnosis, and
  switches audio-endpoint readiness waiting to Wait-AudioDevices.ps1 to
  avoid starting a test before a virtual cable is actually enumerable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* Windows CI: add UBSan/ASan sanitizer build+test jobs

llvm-mingw supports UBSan on every architecture it targets and ASan on
x86 only (confirmed against the toolchain's own release assets: only
x86_64/i386 ship a libclang_rt.asan_dynamic-*.dll, no aarch64 variant
exists). Adds build-sanitizer (mirrors build-pgo-inst minus PGO, one
variant per {UBSAN x86_64, UBSAN aarch64, ASAN x86_64}) and
test-sanitizer (mirrors test, pointed at the new artifacts).

No manual DLL copy step needed for ASan: cmake/GetDependencies.cmake.in
already walks freedv.exe's PE import table via objdump and derives the
toolchain's <arch>-w64-mingw32/bin/ directory as a search path when
FREEDV_USING_LLVM_MINGW is set -- the same mechanism that bundles every
other DLL dependency already picks up libclang_rt.asan_dynamic-*.dll
automatically once ENABLE_ASAN is on. This path was already prepared
for in a prior commit (73cd6f49, "Fix cross-compile definitions to
allow asan to be used in the first place") but never wired into CI.

Sanitizer test steps are continue-on-error, matching the existing
SANITIZERS_ENABLED leniency on macOS/Linux (ctest doesn't enforce the
PASS_REGULAR_EXPRESSION under sanitizers there either) -- a sanitizer
build is slower and less reliable for real-time audio, so what matters
here is whether a sanitizer catches a genuine memory-safety/UB bug
(an abort with a diagnostic in the log), not the loss threshold.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* Fix Windows sanitizer options: drive-letter colon breaks the parser

Every test-sanitizer run was failing at freedv.exe startup with
"AddressSanitizer: ERROR: expected '=' in ASAN_OPTIONS" (and the UBSan
equivalent), masked as job "success" by continue-on-error -- meaning
zero actual testing happened in the previous push.

ASAN_OPTIONS/UBSAN_OPTIONS are colon-separated key=value pairs. The
absolute path used for suppressions= started with a Windows drive
letter (D:\...), and the sanitizer's own option parser split on that
colon too: "suppressions=D" parsed as one pair, then "\...\foo.txt"
(no '=') aborted the parse before FreeDV ever started.

Fix: copy the suppression files next to freedv.exe (alongside the
existing test script copies) and reference them by bare relative
filename, which contains no colon to collide with.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* Suppress known wxWidgets MSW UBSan finding (null pointer in tooltip.cpp)

wxToolInfo's constructor does a member access through a null pointer of
type TTTOOLINFOW in wx's own MSW backend (tooltip.cpp:100), hit
consistently on both new Windows UBSAN test-sanitizer jobs
(windows-2022 and windows-11-arm). Third-party code, not ours -- same
treatment as the existing macOS vptr suppressions for wx's own latent
UB.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* Suppress libressl UBSan finding; make Windows sanitizer jobs actually fail

test/ubsan_suppressions.txt: add function:crypto/stack/stack.c for
"call to function local_sk_X509_NAME_ENTRY_pop_free through pointer to
incorrect function type" -- a well-known, benign pattern in OpenSSL/
LibreSSL's type-erased sk_TYPE_pop_free callback casting, not a real bug.

cmake-windows.yml: the three test-sanitizer test steps are
continue-on-error (needed so an ordinary loss-threshold miss under
instrumentation overhead doesn't stop the other tests, matching the
SANITIZERS_ENABLED leniency ctest already gives sanitizer builds on
macOS/Linux) -- but continue-on-error suppresses the job's conclusion,
not just the step's outcome, so a genuine sanitizer abort was *also*
being swallowed into job "success" with no fix. Added a "Check for
sanitizer errors" step (no continue-on-error) that scans every test's
captured output for an actual AddressSanitizer/UndefinedBehaviorSanitizer/
LeakSanitizer report and fails the job for real if one is found, while
a plain "Test failed" from a loss-threshold miss (no sanitizer report
in the output) still doesn't. Also wired Tee-Object logging into the
FullDuplex and Reporting test steps (RadeLoss already had it) so all
three are covered by the scan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* CI (Windows): drop RadeVerificationReport, fix missing hamlibserver.py

Remove RadeVerificationReport.ps1 and the workflow steps that generate/
upload the RADE verification report from the `test` job -- out of scope
for this PR (Windows ASan/UBSan CI + the RADE loss test infra it needs).

Separately: PR CI showed both `test` and `test-sanitizer (ASAN, ...)`
failing the RADE Reporting step with "python.exe: can't open file
'...\bin\hamlibserver.py'". TestFreeDVReporting.ps1 unconditionally
launches hamlibserver.py (a mock rigctld) as a subprocess before
starting FreeDV, but neither job's "Copy test scripts to install
folder" step actually copied it there -- only TestFreeDVReporting.ps1
itself and its conf template were copied. Added the missing Copy-Item
to both jobs.

(The consequent "Couldn't connect to Radio with hamlib" fatal error
also triggered an apparent AddressSanitizer heap-use-after-free in
wxMutexInternal::LockTimeout during the ASan job's abnormal shutdown --
very likely collateral damage from the broken test flow rather than a
real bug, but worth re-checking once this fix lands.)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* CI (Windows): actually commit the RadeVerificationReport/hamlib workflow changes

Follow-up to 54aa6988 -- that commit only picked up the file deletion;
the cmake-windows.yml edits (removing the report generation/upload
steps and the RadeVerificationReport.ps1 copy, adding the missing
hamlibserver.py copy to both the test and test-sanitizer jobs) didn't
get staged due to a failed `git add` on the already-removed path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* master still uses RADEV1, not V2.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:53:43 -07:00
.github Windows CI: RADE loss testing + ASan/UBSan sanitizer coverage (#1487) 2026-09-13 10:53:43 -07:00
appimage Fix TLS connection failures in AppImage. (#1427) 2026-07-06 14:23:53 -07:00
ci CI (Windows): make collect-pgo-profile wait for real audio endpoints (#1483) 2026-09-07 23:57:12 -07:00
cmake Fix compiler error with Hamlib 5.0. (#1477) 2026-09-02 21:46:35 -07:00
codec2-1.2.0 Further real-time code cleanup (#1039) 2025-10-05 21:21:46 -07:00
contrib Add green frequency indicator for RADE. (#1283) 2026-04-08 00:46:14 -07:00
cross-compile
doc
src Real-time audio thread timing: histogram logging, wake-up debt compensation, high-res Windows waits (#1488) 2026-09-13 09:09:03 -07:00
test Windows CI: RADE loss testing + ASan/UBSan sanitizer coverage (#1487) 2026-09-13 10:53:43 -07:00
wav
.clang-tidy Enable clang-tidy during CI process (#1086) 2025-11-08 15:20:57 -08:00
.gitignore
.wenv.json
CHANGELOG_OLD.md Release version 2.4.0. (#1471) 2026-08-24 21:34:09 -07:00
CMakeLists.txt Fix compiler error with Hamlib 5.0. (#1477) 2026-09-02 21:46:35 -07:00
CODE_SIGNING.md Enable use of remote USB token for signing automated Windows builds. (#1312) 2026-04-30 07:28:53 -07:00
COPYING Relicense radio integration code under BSD license. (#1255) 2026-03-18 14:06:44 -07:00
README.md Enable use of remote USB token for signing automated Windows builds. (#1312) 2026-04-30 07:28:53 -07:00
USER_MANUAL.html latest user manual PDF 2026-09-13 16:11:14 +00:00
USER_MANUAL.md Real-time audio thread timing: histogram logging, wake-up debt compensation, high-res Windows waits (#1488) 2026-09-13 09:09:03 -07:00
USER_MANUAL.pdf latest user manual PDF 2026-09-13 16:11:14 +00:00
add_debug_entitlement.h Debug and fixing of unit tests (#1023) 2025-09-14 00:52:50 -07:00
build_linux.sh Enable CCache to make CI builds run more quickly. (#1328) 2026-08-12 17:43:22 -07:00
build_macos_sound_drivers.sh Second pass at pipeline optimization. (#975) 2025-08-30 09:18:53 -07:00
build_osx.sh Enable CCache to make CI builds run more quickly. (#1328) 2026-08-12 17:43:22 -07:00
build_signed_windows_release.sh Reenable Windows on ARM builds for FreeDV. (#1297) 2026-04-20 22:23:19 -07:00
delocating.py.patched
disable_float.tex
fargan_config.h.in
fargan_config_integ.h.in Set thread names for additional threads in system. (#1103) 2025-11-24 14:55:13 -08:00
generate-univ-pkgs.sh Force numpy to 2.3.x due to illegal instruction errors. (#1230) 2026-02-15 13:53:45 -08:00

README.md

Building FreeDV GUI

This document describes how to build the FreeDV GUI program for various operating systems. FreeDV GUI is developed on Ubuntu Linux, and then cross compiled for Windows using Fedora Linux (Fedora has great cross compiling support) and Docker.

Further Reading

Installing prerequisites on Ubuntu Linux

$ sudo apt install libspeexdsp-dev sox git \
libwxgtk3.2-dev libhamlib-dev libasound2-dev libao-dev \
libgsm1-dev libsndfile1-dev cmake module-assistant build-essential \
autoconf automake libtool libebur128-dev
$ git clone https://github.com/drowe67/freedv-gui.git
$ cd freedv-gui

(if using pipewire/PulseAudio -- recommended and the default) 
$ sudo apt install libpulse-dev

(if using PortAudio)
$ sudo apt install portaudio19-dev

(Depending on release you may need to use libwxgtk3.0-gtk3-dev instead of libwxgtk3.2-dev.)

Installing prerequisites on Fedora Linux

$ sudo dnf groupinstall "Development Tools"
$ sudo dnf install cmake wxGTK3-devel \
  libsndfile-devel speexdsp-devel hamlib-devel alsa-lib-devel libao-devel \
  gsm-devel gcc-c++ sox autoconf automake libtool libebur128-devel
$ git clone https://github.com/drowe67/freedv-gui.git
$ cd freedv-gui

(if using pipewire/PulseAudio -- default and recommended)
$ sudo dnf install pulseaudio-libs-devel

(if using PortAudio)
$ sudo dnf install portaudio-devel

Running FreeDV on Linux

  1. Build FreeDV to make sure the correct dependencies are linked in:

    (rade-venv) $ pwd
    /home/<user>/freedv-gui
    (rade-venv) $ ./build_linux.sh
    
  2. Execute FreeDV:

    (rade-venv) $ pwd
    /home/<user>/freedv-gui/build_linux
    (rade-venv) $ export GDK_BACKEND=x11 # optional, see (*) below
    (rade-venv) $ src/freedv
    

(*) If your Linux distribution and/or desktop environment uses Wayland, FreeDV will always open in the middle of the screen, regardless of where you positioned it before. You can avoid this by having FreeDV run as an X11 application instead using XWayland (GDK_BACKEND=x11).

Alternatively, you can use this script developed by Barry Jackson G4MKT to automate the above steps. While the FreeDV project thanks him for his contribution to helping Linux users more easily get on the air with FreeDV, the FreeDV development team will not provide support. All support inquiries regarding this script should be directed to the linked repo.

Audio driver selection

By default, FreeDV uses the native audio APIs on certain platforms. These are as follows:

Platform Audio API
macOS Core Audio
Linux pipewire (via PulseAudio library)
Windows WASAPI

On platforms not listed above, PortAudio is used instead. PortAudio can also be explicitly selected by the user by defining the environment variable USE_NATIVE_AUDIO=0 before running the build_*.sh script (or specifying -DUSE_NATIVE_AUDIO=0 to cmake).

Installing on Linux

You need to install the codec2 shared libraries, and freedv-gui:

$ cd ~/freedv-gui/codec2/build_linux
$ sudo make install
$ cd ~/freedv-gui/build_linux
$ sudo make install
$ sudo ldconfig

Radio integrations

FreeDV supports direct integration with several different types of radios. Please see this README for more information.

Testing

The wav directory contains test files of modulated audio that you can use to test FreeDV (see the USER_MANUAL).

Building for Windows

Windows releases are built using the LLVM version of MinGW. This allows one to build FreeDV for ARM as well as for Intel Windows systems.

Prerequisites

  • CMake >= 3.25.0
  • Linux (tested on Ubuntu 22.04)
    • NOTE: This does not currently work on macOS due to CMake using incorrect library suffixes.
  • NSIS for generating the installer (for example, sudo apt install nsis on Ubuntu)

Instructions

  1. Download LLVM MinGW at https://github.com/mstorsjo/llvm-mingw/releases/.
  2. Decompress into your preferred location. For example: tar xvf llvm-mingw-20220906-ucrt-ubuntu-18.04-x86_64.tar.xz (The exact filename here will depend on the file downloaded in step (1). Note that for best results, you should use a build containing "ucrt" in the file name corresponding to the platform which you're building the Windows binary from.)
  3. Add LLVM MinGW to your PATH: export PATH=/path/to/llvm-mingw-20220906-ucrt-ubuntu-18.04-x86_64/bin:$PATH. (The folder containing the LLVM tools is typically named the same as the file downloaded in step (2) minus the extension.)
  4. Create a build folder inside freedv-gui: mkdir build_windows
  5. Run CMake to configure the FreeDV build: cd build_windows && cmake -DCMAKE_TOOLCHAIN_FILE=${PWD}/../cross-compile/freedv-mingw-llvm-[architecture].cmake ..
    • Valid architectures are: aarch64 (64 bit ARM), x86_64 (64 bit Intel/AMD)
  6. Build FreeDV as normal: make (You can also add -j[num] to the end of this command to use multiple cores and shorten the build time.)
  7. Create FreeDV installer: make package

Building and installing on macOS

Using MacPorts, most of the appropriate dependencies can be installed by:

$ sudo port install automake git libtool sox +universal cmake wget pkgconf

and on Homebrew:

$ brew install automake libtool git sox cmake wget pkgconf

Once the dependencies are installed, you can then run the build_osx.sh script inside the source tree to build FreeDV and associated libraries (codec2, hamlib). A FreeDV.app app bundle will be created inside the build_osx/src folder which can be copied to your system's Applications folder.

Note: for distribution, code signing is required. The following commands can be run to enable this:

CODESIGN_IDENTITY=[identity in your keychain] UNIV_BUILD=1 ./build_osx.sh
cd build_osx
make release

Building with Profile Guided Optimization (PGO)

Profile Guided Optimization is an optimization strategy supported by the Clang compiler that uses profiling data to govern optimization decisions. This can significantly improve the runtime performance of many applications, especially with higher optimization levels. In testing with FreeDV, the AppImages are able to use up to 25% less CPU using a combination of BUILD_TYPE=Release, link-time optimization (LTO) and PGO. Currently this is supported for macOS and Linux using the LLVM version of the Clang compiler (not the one Apple ships with Xcode).

To build with PGO enabled:

  1. Perform an initial instrumented build using the ./build_linux.sh (or ./build_osx.sh) script, making sure to overide the relevant environment variables to use the correct version of Clang. Example below with macOS and Homebrew:
$ BUILD_TYPE=Release UT_ENABLE=0 BUILD_DEPS=1 PGO_INSTRUMENT=1 CC=$(brew --prefix llvm@20)/bin/clang CXX=$(brew --prefix llvm@20)/bin/clang++ OBJCXX=$(brew --prefix llvm@20)/bin/clang ./build_osx.sh 
  1. Execute FreeDV and use normally to obtain sufficient profiling data. An automated script is available to do this:
cd build_osx
LLVM_PROFILE_FILE="code-%p.profraw" FREEDV_COMPUTER_TO_RADIO_DEVICE="VB-Cable" FREEDV_RADIO_TO_COMPUTER_DEVICE="VB-Cable" FREEDV_COMPUTER_TO_SPEAKER_DEVICE="BlackHole1 2ch" FREEDV_MICROPHONE_TO_COMPUTER_DEVICE="BlackHole2 2ch" ../test/generate_pgo_profiles.sh 2>&1
$(brew --prefix llvm@20)/bin/llvm-profdata merge -output $(pwd)/../code.profdata code-*.profraw

(FREEDV_COMPUTER_TO_RADIO_DEVICE, FREEDV_RADIO_TO_COMPUTER_DEVICE, FREEDV_COMPUTER_TO_SPEAKER_DEVICE and FREEDV_MICROPHONE_TO_COMPUTER_DEVICE are optional on Linux, where PulseAudio/pipewire null sink(s) will be created if these are not provided).

  1. Perform a final build with the collected profiling data:
rm -rf build_osx
BUILD_TYPE=Release UT_ENABLE=0 UNIV_BUILD=1 BUILD_DEPS=1 PGO_USE_PROFILE=$(pwd)/code.profdata CC=$(brew --prefix llvm@20)/bin/clang CXX=$(brew --prefix llvm@20)/bin/clang++ OBJCXX=$(brew --prefix llvm@20)/bin/clang  ./build_osx.sh

Limitations:

  1. The best results are obtained if having FreeDV build all required dependencies itself (BUILD_DEPS=1). The optimization process is unable to touch already-compiled dyanmic libraries, so performance gains will likely be less without this option.