Originally from: https://github.com/peterbmarks/radae_decoder
Based on code from: https://github.com/drowe67/radae
A real-time RADAE (Radio Autoencoder) encoder and decoder for Linux. In receive (RX) mode it captures RADAE modem audio from an audio input device, decodes it using a neural OFDM demodulator and FARGAN vocoder, and plays the decoded speech on an audio output device. In transmit (TX) mode it captures speech from a microphone, extracts LPCNet features, encodes them with the RADE neural encoder, and outputs the OFDM modem signal to a radio. Includes a GTK3 UI with level meters, spectrum/waterfall displays, sync status, SNR, and a TX output level slider.
Note that this version of the FreeDV RADEV1 software started as an experiment to find out if Claude Code could help with the work of porting the current Python implementation over to C.
It's not a supported product of the project and hasn't been fully tested or code reviewed.
If it works for you, great, if not I advise using the supported FreeDV app you can download here.
Unlike the official FreeDV app, this program uses an experimental C port of the python code and does not require python to run. It's (currently) a statically linked single binary of just 16MB compared to 600MB. (But, of course, it does far far less).
- Real-time RADAE decoding — Full receive pipeline: Hilbert transform, OFDM demodulation, neural decoder, FARGAN speech synthesis
- Dual device selection — Pick any capture device (modem input) and playback device (decoded speech output)
- Automatic signal acquisition — Searches for RADAE signal, locks on when found, re-acquires after signal loss
- Live status display — Shows sync state, SNR (dB), and frequency offset (Hz) while decoding
- Open WAV file recording — Decodes and plays a WAV file recording such as those from the FreeDV app
- Real-time RADAE encoding — Full transmit pipeline: microphone capture, LPCNet feature extraction, neural RADE encoder, OFDM modulation
- Dual device selection — Pick any capture device (microphone) and playback device (radio transmit audio)
- TX output level slider — Adjustable output level (0–100%) to set the drive level to the radio; saved across sessions
- TX bandpass filter — Switchable 700–2300 Hz bandpass filter on the TX output, applied just before the audio is sent to the radio. Uses a 101-tap FIR filter at 8 kHz to sharply limit the transmitted bandwidth. Toggled via the BPF switch in the main window; setting is saved across sessions
- End-of-over signalling — Automatically sends an EOO frame when transmission stops
- Input & output level meters — Calibrated dB scale (-60 to 0 dB) with peak hold
- Spectrum display — Shows 4 kHz of audio spectrum. With a RADAE signal you should see energy concentrated in the OFDM band around 1.3 kHz
- Waterfall display — Same as the spectrum but with vertical history
- Sample rate flexibility — The audio backend handles sample rate conversion where supported; internally works at 8 kHz modem and 16 kHz speech rates
- Settings persistence — Device selections and TX level are saved to
~/.config/radae-decoder.conf
Audio Input (8 kHz mono)
-> Hilbert transform (127-tap FIR) -> complex IQ
-> RADE receiver (pilot acquisition, OFDM demod, neural decoder)
-> FARGAN vocoder -> 16 kHz mono speech
-> Audio Output
Mic Input (16 kHz mono)
-> LPCNet feature extraction (36 features per 10 ms frame)
-> Accumulate 12 feature frames (120 ms)
-> RADE transmitter (neural encoder, OFDM modulation)
-> 960 complex IQ samples @ 8 kHz
-> [Optional] 700–2300 Hz bandpass filter (101-tap FIR, toggled by BPF switch)
-> Take real part, scale by TX output level
-> Radio Audio Output
The RADAE codec uses a 30-carrier OFDM waveform in ~1.3 kHz bandwidth. Each 120 ms modem frame produces 12 speech frames (10 ms each) via the neural decoder and FARGAN vocoder. Pilot symbols enable automatic frequency and timing synchronization.
- Linux (tested on Ubuntu 24.04 / Linux Mint)
- GTK 3.24+
- ALSA runtime libraries (
libasound2) — default audio backend- PulseAudio (
libpulse0) if built with-DAUDIO_BACKEND=PULSE - PortAudio if built with
-DAUDIO_BACKEND=PORTAUDIO
- PulseAudio (
- hamlib
- X11 or Wayland display server
- CMake 3.16+
- C++17 compiler (GCC 7+, Clang 5+)
- C11 compiler
- Internet connection (first build downloads and compiles Opus with FARGAN/LPCNet support)
- Autotools (
autoconf,automake,libtool) for building Opus - Development headers:
libgtk-3-devlibasound2-dev(if using-DAUDIO_BACKEND=ALSA)libpulse-dev(if using-DAUDIO_BACKEND=PULSEdefault on Linux)libhamlib-dev(GUI only)libcairo2-dev(usually pulled in by GTK3)
# Default
sudo apt-get install build-essential cmake \
libgtk-3-dev libasound2-dev pkg-config \
autoconf automake libtool libpulse-dev libhamlib-dev
# Tools-only (no GUI build, no GTK/Hamlib needed)
sudo apt-get install build-essential cmake \
libasound2-dev pkg-config \
autoconf automake libtool libpulse-dev
# Optional: PulseAudio backend
sudo apt-get install libpulse-devYou will need Xcode command line tools and homebrew.
brew install automake libtool git sox cmake wget pkgconf \
gtk+3 hamlib portaudio
cd radae_decoderPrepare the make file:
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
Tools-only build (skip RADAE_Gui and GUI deps)
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF ..
First build downloads Opus (~175 MB) and compiles everything. The NN weight files (rade_enc_data.c, rade_dec_data.c) are ~47 MB and take a while to compile.
make -j$(nproc)
Binary is now at: build/RADAE_Gui Tools are at: build/tools/
The audio backend is selected at configure time via -DAUDIO_BACKEND=:
| Value | Default on | Library needed |
|---|---|---|
ALSA |
- | libasound2-dev |
PULSE |
Linux | libpulse-dev |
PORTAUDIO |
macOS | portaudio19-dev |
# Linux default (PULSE)
cmake -DCMAKE_BUILD_TYPE=Release ..
# Explicitly choose PulseAudio (default on Linux)
cmake -DCMAKE_BUILD_TYPE=Release -DAUDIO_BACKEND=PULSE ..
# Explicitly choose ALSA on Linux
cmake -DCMAKE_BUILD_TYPE=Release -DAUDIO_BACKEND=ALSA ..
# PortAudio (macOS default, also available on Linux)
cmake -DCMAKE_BUILD_TYPE=Release -DAUDIO_BACKEND=PORTAUDIO ..The selected backend is printed during configuration:
-- Audio backend: PULSE
Note when using ALSA you should choose devices with plughw: prefix so they can do their own sample rate conversion.
Note: once a build directory has been configured, CMake caches AUDIO_BACKEND. Delete CMakeCache.txt or the build directory before switching backends.
On some systems, pkg-config can't find .pc files in /usr/lib/x86_64-linux-gnu/pkgconfig. The CMakeLists.txt handles this automatically, but if you encounter issues:
export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig
cmake ..webrx_rade_decode can be packaged as a self-contained Debian .deb for easy installation on Debian/Ubuntu systems. All dependencies (Opus, RADE library, neural network weights) are statically linked into the binary, so the only runtime requirement is libc6.
# Install build dependencies
sudo apt-get install build-essential cmake autoconf automake libtool pkg-config \
libgtk-3-dev libhamlib-dev libpulse-dev
# Build and package (downloads Opus from GitHub on first run; cached afterwards)
./package-deb.sh
# Install
sudo dpkg -i webrx-rade-decode_0.1.0-1_amd64.debIf build/tools/webrx_rade_decode already exists from a previous cmake build:
./package-deb.sh --skip-buildsudo apt install debhelper-compatA debian/ directory is provided for use with standard Debian tooling:
# (run this from the top level directory)
# Full package (default behavior): CLI and GUI
dpkg-buildpackage -us -uc -b
# Minimal package (CLI tools only): webrx-rade-decode-minimal
dpkg-buildpackage -us -uc -b -Ppkg.minimalNote: the build fetches Opus source from GitHub the first time it runs. This requires internet access during the configure step, which is non-standard for Debian policy. Use
package-deb.shfor straightforward local builds.
./build/RADAE_Gui- Input dropdown -- Select the capture device receiving the RADAE modem signal (e.g. a sound card connected to a radio receiver).
- Output dropdown -- Select the playback device for decoded speech (e.g. speakers or headphones).
- Start button -- Click to begin decoding. The button turns red and changes to "Stop".
- Status bar -- Shows "Searching for signal..." until a RADAE signal is detected, then displays "Synced -- SNR: X dB Freq: +Y Hz".
- Meter display -- Shows decoded output audio levels in real-time once synced.
- Refresh button -- Re-scan for devices if you plug in new hardware.
The chosen input and output audio device names are saved and loaded on launch. If both are found decoding will automatically start.
- Toggle the TX switch to enable transmit mode. The settings dialog gains TX-specific device selectors.
- TX Input -- Select the microphone capture device.
- TX Output -- Select the playback device connected to the radio transmitter.
- TX level slider -- Adjust the output drive level (right side of window). The setting is saved across sessions.
- BPF switch -- Toggle the 700–2300 Hz bandpass filter on the TX output. This limits the transmitted bandwidth to the SSB passband. The setting is saved across sessions.
- Click Start to begin transmitting. The status bar shows "Transmitting..." and the meters show mic input and modem output levels.
- Click Stop to end the transmission; an end-of-over (EOO) frame is sent automatically.
If you see "Failed to open audio devices":
- ALSA: Ensure your user is in the
audiogroup (sudo usermod -aG audio $USER, then log out and back in). - PulseAudio: Ensure PulseAudio is running (
pulseaudio --checkorpactl info).
radae_headless is a command-line tool that runs the full RADAE encode/decode pipeline without a graphical interface. It is useful for headless servers, automation, or embedded deployments where a display is unavailable.
./build/radae_headless [options]| Option | Description |
|---|---|
-h, --help |
Show help and exit |
-d, --devices |
List available audio devices and exit |
-c FILE |
Config file path (default: radae_headless.conf) |
-t |
Transmit mode (default is receive mode) |
--fromradio DEVICE |
Audio input device receiving the RADAE modem signal (RX) |
--tospeaker DEVICE |
Audio output device for decoded speech (RX) |
--frommic DEVICE |
Audio input device for the microphone (TX) |
--toradio DEVICE |
Audio output device connected to the radio transmitter (TX) |
--call CALLSIGN |
Your callsign (e.g. VK3TPM) — saved to the config file |
Receive (RX) — default mode. Requires --fromradio and --tospeaker:
./build/radae_headless --fromradio alsa_input.usb-radio --tospeaker alsa_output.pci-speakersTransmit (TX) — enabled with -t. Requires --frommic and --toradio:
./build/radae_headless -t --frommic alsa_input.pci-mic --toradio alsa_output.usb-radioUse --devices to discover the correct device names for your system:
./build/radae_headless --devicesSettings are persisted to radae_headless.conf (or the file given with -c). If the config file does not exist and device options are supplied on the command line, the file is created automatically.
The config file format is key=value, one per line; lines beginning with # are comments:
# radae_headless configuration
fromradio=alsa_input.usb-radio
tospeaker=alsa_output.pci-speakers
frommic=alsa_input.pci-mic
toradio=alsa_output.usb-radio
call=VK3TPMCommand-line options always override values in the config file.
While running, the tool prints a live status line to stderr every second:
SYNC SNR: 12.3 dB Freq: +1.5 Hz In: 0.45 Out: 0.62
SYNC becomes ---- when the receiver has not yet locked on to a signal. Press Ctrl+C to stop cleanly (an EOO frame is sent automatically in TX mode).
| Module | Responsibility |
|---|---|
| rade_decoder | Complete real-time decode pipeline: audio capture (8 kHz), Hilbert transform (real to IQ), RADE receiver, FARGAN vocoder synthesis, audio playback (16 kHz). Runs on a dedicated thread with atomic status variables. |
| rade_encoder | Complete real-time encode pipeline: mic capture (16 kHz), LPCNet feature extraction, RADE transmitter (neural encoder + OFDM mod), audio playback to radio (8 kHz). Runs on a dedicated thread; TX output level controlled via atomic. |
| audio_stream | Backend-neutral AudioStream class. Compiled against one of: audio_stream_alsa.cpp, audio_stream_pulse.cpp, or audio_stream_portaudio.cpp depending on AUDIO_BACKEND. |
| audio_input | Device enumeration wrapper used by the UI dropdowns |
| meter_widget | Custom GtkDrawingArea widget; redraws at ~30 fps using Cairo; converts linear RMS to logarithmic dB; green-to-red gradient fill; peak-hold with decay |
| main | GTK application shell; connects signals; manages device combo boxes and TX level slider; starts/stops decoder/encoder; updates meters and status via GLib timer |
| radae_nopy (librade) | RADAE codec C library: OFDM mod/demod, pilot acquisition, neural encoder/decoder (GRU+Conv), bandpass filter. Neural network weights compiled directly into the binary (~47 MB). |
Audio Input (8 kHz mono)
| AudioStream::read() -- blocking read, S16_LE mono
v
Hilbert transform (127-tap Hamming-windowed FIR)
-> RADE_COMP (complex IQ samples)
v
rade_rx() -- pilot acquisition, OFDM demod, neural decoder
-> 36-float feature vectors (12 per modem frame, when synced)
v
FARGAN vocoder (fargan_synthesize)
-> 160 float samples per frame @ 16 kHz (10 ms)
v
AudioStream::write() -- audio playback, S16_LE mono
Mic Input (16 kHz mono)
| AudioStream::read() -- blocking read, S16_LE mono
v
lpcnet_compute_single_frame_features()
-> 36-float feature vector per 160 samples (10 ms)
v
Accumulate 12 feature frames (432 floats, 120 ms)
v
rade_tx() -- neural encoder, OFDM modulation
-> 960 RADE_COMP samples @ 8 kHz (120 ms)
v
[Optional] rade_bpf_process() -- 700-2300 Hz BPF (101-tap FIR, toggled by BPF switch)
v
Take real part, scale by TX level slider
v
AudioStream::write() -- audio playback to radio, S16_LE mono
The RADE receiver has three states:
- SEARCH -- Correlates incoming signal against pilot patterns across 40 frequency bins (+-100 Hz range, 2.5 Hz steps)
- CANDIDATE -- Validates detected signal over multiple frames, refines timing and frequency
- SYNC -- Locked and demodulating. Continuously tracks pilots. Loses sync if pilots fail for 3 seconds.
When sync is lost, the FARGAN vocoder is re-initialized so it can warm up cleanly when the next signal is acquired (5-frame warm-up via fargan_cont()).
- RX processing thread (RadaeDecoder): Runs the entire capture-decode-playback loop
- TX processing thread (RadaeEncoder): Runs the entire mic-capture-encode-playback loop
- GTK main thread: Reads atomic status variables at 30 Hz, updates meters, status label, and writes TX scale from the slider
- Synchronization:
std::atomic<float>/std::atomic<bool>with relaxed ordering (lock-free)
Your pkg-config search path is missing the multiarch directory:
export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig- List available capture devices:
arecord -L - List available playback devices:
aplay -L - Ensure your user is in the
audiogroup:groups $USER - Try the
defaultdevice, or a specifichw:X,Yorplughw:X,Yidentifier fromarecord -l.
- Ensure PulseAudio is running:
pulseaudio --checkorpactl info. - Verify devices exist:
pactl list sources short(capture) andpactl list sinks short(playback). - Try different devices from the dropdowns.
- Ensure the input device is actually receiving a RADAE modem signal at the expected bandwidth (~1.3 kHz around baseband).
- Check that the input level is reasonable (not clipping, not too quiet).
- The signal must contain RADAE OFDM pilots for the receiver to lock on.
The first build downloads Opus source from GitHub (~175 MB). Ensure you have an internet connection. If behind a proxy, set http_proxy/https_proxy environment variables.
The neural network weight files (rade_enc_data.c, rade_dec_data.c) are ~24 MB and ~23 MB respectively. Compiling these takes significant time and memory. Use make -j$(nproc) for parallel builds.
- Sample rate: 8000 Hz (modem), 16000 Hz (speech)
- OFDM carriers: 30
- Bandwidth: ~1.3 kHz
- Modem frame: 960 samples @ 8 kHz (120 ms)
- Latent dimension: 80 (neural autoencoder bottleneck)
- Feature frames per modem frame: 12 (3 latent vectors x 4 encoder stride)
- Speech frame: 160 samples @ 16 kHz (10 ms)
| Backend | API | Format | Notes |
|---|---|---|---|
| ALSA | snd_pcm_readi / snd_pcm_writei |
SND_PCM_FORMAT_S16_LE |
Linux default; direct hardware access, low latency |
| PulseAudio | pa_simple_read / pa_simple_write |
PA_SAMPLE_S16LE |
Server-managed; handles rate conversion automatically |
| PortAudio | Pa_ReadStream / Pa_WriteStream |
paInt16 |
macOS default; cross-platform |
All three backends present the same AudioStream interface to the rest of the application.
Take a wav file off air and produce a demodulated wav file
Usage:
rade_demod [-v 0|1|2] <input.wav> <output.wav>
Take a wav file with speech in it and produce a RADE OFDM encoded output wav file ready for transmission.
Usage:
rade_modulate [-v 0|1|2] <intput.wav> <output.wav>
./tools/rade_modulate ../voice.wav rade.wav
./tools/rade_demod rade.wav decoded.wav
play decoded.wav
sox ../voice.wav -r 16000 -t .s16 -c 1 - | \
./tools/lpcnet_demo -features /dev/stdin - | \
./tools/radae_tx > tx.iq
cat tx.iq | \
./tools/radae_rx | \
./tools/lpcnet_demo -fargan-synthesis /dev/stdin - | \
sox -t .s16 -r 16000 -c 1 - decoded.wav
usage: radae_rx [options]
-h, --help Show this help
--model_name FILE Path to model (ignored, uses built-in weights)
-v LEVEL Verbosity level (0, 1, or 2)
--no-unsync Disable automatic unsync
sox ../FDV_offair.wav -r 8000 -e float -b 32 -c 1 -t raw - | \
./tools/real2iq | \
./tools/radae_rx > features.f32
./tools/lpcnet_demo -fargan-synthesis features.f32 - | \
sox -t .s16 -r 16000 -c 1 - decoded.wav
play decoded.wav
./webrx_rade_decode -h
usage: webrx_rade_decode [options]
Reads 16-bit signed mono audio at 8000 Hz from stdin,
decodes RADAE, and writes 16-bit signed mono audio
at 8000 Hz to stdout.
options:
-h, --help Show this help
-v LEVEL Verbosity: 0=quiet 1=normal (default) 2=verbose
Test:
sox FDV_offair.wav \
-t raw -b 16 -r 8000 -e signed-integer - | \
./webrx_rade_decode |sox -t raw -r 8000 -b 16 -e signed-integer -c 1 - output.wav
Prints information to stderr for OpenWebRx+ to display to the user like this:
Status=Searching
Status=Sync,SNR=20dB,FreqOffset=1.0 Hz
Status=End-of-over at modem frame 38
Status=Searching
Status=Sync,SNR=22dB,FreqOffset=0.0 Hz
Status=Sync,SNR=34dB,FreqOffset=0.0 Hz
Status=Sync,SNR=35dB,FreqOffset=0.0 Hz
Status=Sync,SNR=36dB,FreqOffset=0.0 Hz
Status=Sync,SNR=36dB,FreqOffset=0.0 Hz
Status=Sync,SNR=36dB,FreqOffset=0.0 Hz
Status=Sync,SNR=36dB,FreqOffset=0.0 Hz
Status=Sync,SNR=35dB,FreqOffset=0.0 Hz
Status=Sync,SNR=36dB,FreqOffset=0.0 Hz
Status=Sync,SNR=36dB,FreqOffset=0.0 Hz
Status=Sync,SNR=36dB,FreqOffset=0.0 Hz
Status=Sync,SNR=35dB,FreqOffset=0.0 Hz
Status=Sync,SNR=35dB,FreqOffset=0.0 Hz
Status=Sync,SNR=36dB,FreqOffset=0.0 Hz
Status=End-of-over at modem frame 334
Status=Searching
Status=Sync,SNR=20dB,FreqOffset=1.0 Hz
src/
├── radae/ Core RADAE C library
│ ├── rade_api.h / .c Public API: rade_open, rade_rx, rade_tx, rade_close
│ ├── rade_ofdm.h / .c OFDM mod/demod: DFT/IDFT, pilot insertion, cyclic prefix, equalization
│ ├── rade_rx.h / .c RADAE receiver: pilot acquisition, OFDM demod, neural decode, sync state machine
│ ├── rade_tx.h / .c RADAE transmitter: neural encode, OFDM modulation
│ ├── rade_acq.h / .c Pilot-based signal acquisition and frequency/timing synchronisation
│ ├── rade_bpf.h / .c 700–2300 Hz bandpass FIR filter applied to TX output
│ ├── rade_dsp.h / .c DSP primitives: complex arithmetic, Hilbert transform, FFT helpers
│ ├── rade_enc.h / .c Neural encoder (GRU + convolution layers)
│ ├── rade_enc_data.h / .c Pre-trained encoder network weights (~24 MB, compiled into binary)
│ ├── rade_dec.h / .c Neural decoder (GRU + convolution layers)
│ └── rade_dec_data.h / .c Pre-trained decoder network weights (~23 MB, compiled into binary)
│
├── radae_top/ C++ wrappers around the RADAE C library
│ ├── rade_core.h Shared types and constants
│ ├── rade_constants.h Auto-generated neural network dimensions (latent size, frame count, etc.)
│ ├── rade_decoder.h / .cpp RadaeDecoder: RX pipeline thread (capture → Hilbert → RADE Rx → FARGAN → playback)
│ ├── rade_encoder.h / .cpp RadaeEncoder: TX pipeline thread (mic → LPCNet features → RADE Tx → radio out)
│ └── audio_passthrough.h / .cpp AudioPassthrough: raw audio loopback with RMS/FFT metering for passthrough mode
│
├── audio/ Platform-neutral audio I/O abstraction
│ ├── audio_stream.h AudioStream base class (read / write / list devices interface)
│ ├── audio_input.h / .cpp AudioInput: background capture thread with per-channel level metering
│ ├── audio_stream_alsa.cpp ALSA backend (Linux)
│ ├── audio_stream_pulse.cpp PulseAudio backend (Linux default)
│ └── audio_stream_portaudio.cpp PortAudio backend (macOS default; also available on Linux)
│
├── gui/ GTK3 graphical user interface
│ ├── main.cpp Program entry point; creates GTK application, initialises globals
│ ├── gui_activate.h / .cpp GTK "activate" handler: builds window, widgets, and layout from code
│ ├── gui_app_state.h Declarations of all shared UI/state globals (decoder, encoder, widgets, etc.)
│ ├── gui_callbacks.h / .cpp GTK signal handlers: button clicks, device selection, mode toggles, window close
│ ├── gui_controls.h / .cpp Higher-level helpers: start/stop decoder/encoder, refresh status, update rig
│ ├── gui_config.h / .cpp Settings load/save to ~/.config/radae-decoder.conf
│ ├── meter_widget.h / .cpp Custom GtkDrawingArea bar-meter: logarithmic dB scale, peak-hold with decay
│ ├── spectrum_widget.h / .cpp Custom GtkDrawingArea spectrum display (0–4 kHz, frequency labels)
│ ├── waterfall_widget.h / .cpp Custom GtkDrawingArea waterfall: scrolling spectrogram history
│ └── rig_control.h / .cpp Hamlib wrapper: enumerates rig models and serial ports, sends frequency commands
│
├── network/ FreeDV Reporter integration
│ ├── socket_io.h / .cpp Minimal Socket.IO v4 client over IXWebSocket (Engine.IO handshake, event routing)
│ └── freedv_reporter.h / .cpp FreeDVReporter: connects to FreeDV Reporter server, tracks remote stations, handles QSY requests
│
├── eoo/ End-of-over callsign codec
│ └── EooCallsignCodec.h / .cpp Encodes/decodes operator callsign in the RADE EOO frame using LDPC + CRC
│
├── wav/ WAV file recording
│ └── wav_recorder.h / .cpp WavRecorder: thread-safe PCM S16 WAV writer with correct header management
│
├── tools/ Command-line utilities
│ ├── rade_demod.cpp File tool: WAV RADAE audio in → decoded speech WAV out
│ ├── rade_modulate.cpp File tool: speech WAV in → RADAE OFDM WAV out
│ ├── radae_headless.cpp Headless transceiver: full RX or TX pipeline with no GUI, config-file driven
│ ├── radae_rx.c Streaming receiver: IQ float32 on stdin → LPCNet features on stdout
│ ├── radae_tx.c Streaming transmitter: LPCNet features on stdin → IQ float32 on stdout
│ ├── real2iq.c Converts real baseband float32 to complex IQ via Hilbert transform
│ ├── webrx_rade_decode.c OpenWebRX plugin: S16 8 kHz mono in → decoded S16 8 kHz mono out
│ └── lpcnet_demo.c LPCNet vocoder demo (feature extraction and FARGAN synthesis, Mozilla code)
│
└── yyjson/ Embedded JSON library (MIT licence)
└── yyjson.h / .c Fast JSON parser and serialiser used for FreeDV Reporter event handling
- RADAE codec by David Rowe (github.com/drowe67)
- Opus/LPCNet/FARGAN by Xiph.Org / Amazon (opus-codec.org)
- Built with GTK 3 (gtk.org)
- Audio I/O via ALSA / PulseAudio / PortAudio (selectable at build time)
- Thanks David Rowe for help and encouragement.
- Thanks Stanislav Lechev [0xAF] for contributing the debian .deb package build
Platform: Linux (Ubuntu 24.04 / Linux Mint)
MacMini M4
No compiler optimisation:
marksp@Peters-M4-Mini build % time ./rade_demod ~/Desktop/FDV_VK3SRC_EOO.wav out.wav
Input: /Users/marksp/Desktop/FDV_VK3SRC_EOO.wav 48000 Hz 1 ch 16-bit int
Modem input: 433920 samples @ 8000 Hz (54.2 s)
rade_open: model_file=model19_check3/checkpoints/checkpoint_epoch_100.pth (ignored, using built-in weights)
rade_open: n_features_in=432 Nmf=960 Neoo=1152 n_eoo_bits=180
Callsign = 'VK3SRC'
End-of-over at modem frame 447
Modem frames: 452 valid: 443
Output: out.wav 53.1 s (1699520 bytes)
./rade_demod ~/Desktop/FDV_VK3SRC_EOO.wav out.wav 11.39s user 0.05s system 99% cpu 11.457 total
Built with:
cmake -DCMAKE_BUILD_TYPE=Release ..
Makes almost no difference:
marksp@Peters-M4-Mini build % time ./rade_demod ~/Desktop/FDV_VK3SRC_EOO.wav out.wav
Input: /Users/marksp/Desktop/FDV_VK3SRC_EOO.wav 48000 Hz 1 ch 16-bit int
Modem input: 433920 samples @ 8000 Hz (54.2 s)
rade_open: model_file=model19_check3/checkpoints/checkpoint_epoch_100.pth (ignored, using built-in weights)
rade_open: n_features_in=432 Nmf=960 Neoo=1152 n_eoo_bits=180
Callsign = 'VK3SRC'
End-of-over at modem frame 447
Modem frames: 452 valid: 443
Output: out.wav 53.1 s (1699520 bytes)
./rade_demod ~/Desktop/FDV_VK3SRC_EOO.wav out.wav 11.26s user 0.02s system 99% cpu 11.290 total
The bottleneck might be file i/o.


