A C library and set of tools implementing RADE V1 and V2. It was derived from the reference Python implementation with the assistance of Claude Code, reviewed and tested by the FreeDV team. It passes the same suite of automated tests as the Python version.
Built and tested on Linux-x86, Windows (via wine), and macOS. Linux-x86 (native, gcc) is the reference build where the majority of tests are run.
Due to resource limitations of the core team, we will decline support of additional OSes, instead encouraging the use of externally-maintained fork or patch sets. These patches/forks should be tested using a loss-based test -- examples can be found in this repo's GitHub workflows and the verification section of drowe67/radae.
RADE V2 is under active development. The waveform, model weights, and API are subject to change without notice, and future versions will not be backwards compatible with the current implementation.
Known issues are under investigation. On-air use is not recommended at this stage, and the FreeDV team is not able to provide support for pre-release V2 deployments. Any on-air V2 signals should be considered premature use of the development waveform and are not part of official FreeDV development activity.
The official V2 status will be announced on the FreeDV blog.
RADE (Radio AutoEncoder) is a neural codec for transmitting speech over HF radio channels. Speech is converted to feature vectors by the FARGAN vocoder (built as part of Opus), encoded by a neural encoder, modulated onto an OFDM waveform, and transmitted as IQ samples. The receive path reverses this: IQ samples are demodulated, decoded by a neural decoder, and synthesised back to speech by FARGAN.
Transmit:
speech WAV ──► lpcnet_demo ──► features ──► radae_tx ──► IQ @ 8 kHz ──► radio
(16 kHz) (radio interface)
Receive:
speech WAV ◄── lpcnet_demo ◄── features ◄── radae_rx ◄── IQ @ 8 kHz ◄── radio
(16 kHz) (radio interface)
The convenience tools rade_tx_wav and rade_rx_wav wrap this entire pipeline
in a single command (WAV in, WAV out). For integration into SDR applications,
the rade_api.h C API gives direct access to each stage; see
RadeAPIUse.md for details.
cd rade_c
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc) # or -j$(sysctl -n hw.logicalcpu) on macOS
Native build using the system Clang/Xcode toolchain -- no cross-compilation
needed. Requires CMake and the autotools Opus's own build uses
(autogen.sh/configure), which aren't part of the Xcode Command Line
Tools by default:
brew install cmake autoconf automake libtool sox
Then build as above (cmake .. && make -j$(sysctl -n hw.logicalcpu)).
The rade library and its WAV convenience tools (rade_tx_wav/rade_rx_wav) can be
cross-compiled for Windows from Linux using MinGW-w64. This is the reference cross-compile
setup used to validate the Windows build.
Install the MinGW-w64 toolchain and Wine (Wine is only needed to run/test the result on Linux, not to build it):
sudo apt install mingw-w64 wine
Build using the provided toolchain file:
cd rade_c
mkdir build-win
cd build-win
cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-mingw64.cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
This produces librade.dll/librade.dll.a (the shared library and its import library) plus
rade_tx_wav.exe/rade_rx_wav.exe, radae_tx.exe/radae_rx.exe, real2iq.exe,
rade_v2_text_test.exe, and lpcnet_demo.exe. The remaining CLI test tools
(rade_bpf_test, rade_ber_test, rade_v1_text_test, rade_dec_v2_test,
rade_enc_v2_test) reference internal (non rade_api.h) symbols and don't currently build
on Windows.
Running an .exe under Wine needs libssp-0.dll (MinGW's _FORTIFY_SOURCE runtime support
library) alongside it, since it isn't on Wine's default search path:
Assuming you are in build-win just after make:
cp $(x86_64-w64-mingw32-gcc -print-file-name=libssp-0.dll) src/
cd src && wine ./rade_tx_wav.exe --help
Troubleshooting:
- Don't reuse a build directory across a native/cross-compile switch -- CMake caches
CMAKE_TOOLCHAIN_FILEon first configure and won't pick up a later change, silently producing a native build. Use a fresh directory (e.g.build-win, kept separate frombuild) when cross-compiling. - If the Opus
ExternalProject_Adddownload step fails with a checksum mismatch, delete the corrupted download (build_opus-prefix/src/build_opus/opus_data-*.tar.gzunder your build directory) and rerun. Generic download flakiness, not specific to cross-compiling.
test/win_loss_check.sh automates a sanity check that this cross-compiled build is
numerically equivalent to the native Linux build -- (re)builds both the native Linux and
Windows cross-compiled rade_tx_wav/rade_rx_wav (no separate build step needed first),
runs both through the same TX/RX round trip (the Windows build under Wine), and compares
loss (via radae's loss.py) and the feature files
against a tolerance. This is what CI runs on every push as the Windows check (see
Supported Platforms above); it can also be run manually:
cd ~/rade_c
./test/win_loss_check.sh ~/radae
The primary interface is a streaming IQ pipeline using radae_tx and radae_rx.
The radio interface — IQ samples produced by radae_tx and consumed by radae_rx — is
complex float32 (interleaved I,Q) at 8000 Hz. Speech I/O runs at 16000 Hz.
sox ../input_sample.wav -r 16000 -t .s16 -c 1 - | \
./src/lpcnet_demo -features /dev/stdin - | \
./src/radae_tx > tx1.iq
cat tx1.iq | \
./src/radae_rx | \
./src/lpcnet_demo -fargan-synthesis /dev/stdin - | \
sox -t .s16 -r 16000 -c 1 - decoded1.wav
sox ../input_sample.wav -r 16000 -t .s16 -c 1 - | \
./src/lpcnet_demo -features /dev/stdin - | \
./src/radae_tx --v2 > tx2.iq
cat tx2.iq | \
./src/radae_rx --v2 | \
./src/lpcnet_demo -fargan-synthesis /dev/stdin - | \
sox -t .s16 -r 16000 -c 1 - decoded2.wav
These tools wrap the full pipeline for simple WAV-in, WAV-out use, handling the real→IQ conversion internally. Useful for quick tests with off-air recordings.
The simplest way to try RADE is with the WAV convenience tools. From the build directory:
# RADE V1
./src/rade_tx_wav ../input_sample.wav tx_rade1.wav
./src/rade_rx_wav tx_rade1.wav decoded_rade1.wav
# RADE V2
./src/rade_tx_wav --v2 ../input_sample.wav tx_rade2.wav
./src/rade_rx_wav --v2 tx_rade2.wav decoded_rade2.wav
This encodes input_sample.wav to a RADE waveform and decodes it back to speech —
no additional tools required.
rade_rx_wav accepts a real-valued 8 kHz WAV file directly — for example,
audio recorded from a conventional SSB receiver or a KiwiSDR. Use sox to
resample to 8 kHz first if needed:
sox offair.wav -r 8000 -c 1 offair_8k.wav
./src/rade_rx_wav --v2 offair_8k.wav decoded.wav
If integrating at the API level, note that real-valued input requires a
different scaling factor than complex IQ — see RADE_INT16_SCALE in
rade_api.h for the full rationale, and src/rade_rx_wav.c for a
worked example.
rade_tx_wav [--v2] [-v 0|1] <input.wav> <output.wav>
rade_rx_wav [--v2] [-v 0|1|2|3] <input.wav> <output.wav>
| File | Purpose |
|---|---|
src/rade_api.h |
Public API |
src/rade_api.c |
API implementation (V1/V2 dispatch) |
src/radae_tx.c |
Standalone transmitter executable |
src/radae_rx.c |
Standalone receiver executable |
src/lpcnet_demo.c |
Feature extraction / vocoder synthesis |
src/real2iq.c |
Real baseband → complex IQ converter |
src/rade_dsp.h/c |
Complex math utilities, constants, pilot generation |
src/rade_bpf.h/c |
Complex bandpass filter |
| File | Purpose |
|---|---|
src/rade_ofdm.h/c |
OFDM modulation/demodulation |
src/rade_acq.h/c |
Acquisition and pilot detection |
src/rade_tx.h/c |
Transmitter internals |
src/rade_rx.h/c |
Receiver with sync state machine |
src/rade_enc.h/c |
Neural encoder |
src/rade_dec.h/c |
Neural decoder |
src/rade_enc_data.c |
Encoder weights |
src/rade_dec_data.c |
Decoder weights |
| File | Purpose |
|---|---|
src/rade_v2_ofdm.h/c |
OFDM modulation/demodulation |
src/rade_tx_v2.h/c |
Transmitter internals |
src/rade_rx_v2.h/c |
Receiver with sync state machine |
src/rade_enc_v2.h/c |
Neural encoder |
src/rade_dec_v2.h/c |
Neural decoder |
src/rade_sync.h/c |
Frame synchronisation |
src/rade_enc_v2_data.c |
Encoder weights |
src/rade_dec_v2_data.c |
Decoder weights |
src/rade_sync_data.c |
Sync weights |
Verification of your RADE integration is essential before any on-air use. A loss test confirms that feature vectors are passing correctly through your encode/decode pipeline, catching issues such as dropped sample buffers or signal processing errors before they manifest as degraded audio on air.
Before testing a hardware or software integration, establish a software-only loss baseline using the C port. This is the C port equivalent of the reference Python verification in the radae repo.
Run from rade_c/build (requires the radae Python repo at ~/radae for loss.py):
cd rade_c/build
./src/lpcnet_demo -features ../wav/all.wav features_in.f32
cat features_in.f32 | ./src/radae_tx --v2 > tx_c.f32
cat tx_c.f32 | ./src/radae_rx --v2 -v 0 > features_rx_c.f32
PYTHONPATH=~/radae python3 ~/radae/loss.py features_in.f32 features_rx_c.f32 --clip_start 100 --clip_end 300
Expected output (software-only reference, wav/all.wav, model 250725):
loss: 0.080 start: 224 acq_time: 1.24 s
This matches the Python reference result (loss: 0.081) to within ±10%. When testing a real integration, a loss within ±10% of this figure is considered a pass.
A suite of ctests runs automatically on every GitHub push (Linux x86 and ARM). The tests cover V1 and V2 encode/decode pipelines, channel conditions (AWGN, MPP, MPG, MPD), acquisition, SNR estimation, EOO detection, BER, and the WAV convenience tools.
To run the tests locally, the radae Python reference repo is required:
cd ~
git clone https://github.com/drowe67/radae.git
cd radae && mkdir build && cd build
cmake -DRADE_C_BUILD_DIR=~/rade_c/build ..
ctest -R rade_c
rade_c/
├── CMakeLists.txt
├── cmake/
│ └── BuildOpus.cmake
└── src/
├── CMakeLists.txt
├── rade_api.h # Public API
├── rade_api.c # API implementation
├── radae_tx.c # Transmitter executable
├── radae_rx.c # Receiver executable
├── lpcnet_demo.c # Feature extraction / vocoder synthesis
├── real2iq.c # Real → IQ converter
├── rade_dsp.h/c # DSP primitives
├── rade_bpf.h/c # Bandpass filter
├── rade_ofdm.h/c # V1 OFDM mod/demod
├── rade_acq.h/c # V1 acquisition
├── rade_tx.h/c # V1 transmitter internals
├── rade_rx.h/c # V1 receiver internals
├── rade_enc.h/c # V1 neural encoder
├── rade_dec.h/c # V1 neural decoder
├── rade_enc_data.c # V1 encoder weights
├── rade_dec_data.c # V1 decoder weights
├── rade_v2_ofdm.h/c # V2 OFDM mod/demod
├── rade_tx_v2.h/c # V2 transmitter internals
├── rade_rx_v2.h/c # V2 receiver internals
├── rade_enc_v2.h/c # V2 neural encoder
├── rade_dec_v2.h/c # V2 neural decoder
├── rade_sync.h/c # V2 frame sync
├── rade_enc_v2_data.c # V2 encoder weights
├── rade_dec_v2_data.c # V2 decoder weights
└── rade_sync_data.c # V2 sync weights