Skip to content

peterbmarks/radae_decoder

Repository files navigation

RADAE Gui

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.

Platform GTK3 ALSA RADAE

Not an official release

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.

Screenshots

Screenshot

Settings

Rig

Video demo

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).

Features

Receive (RX)

  • 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

Transmit (TX)

  • 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

Common

  • 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

How it works

RX (Decode)

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

TX (Encode)

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.

Requirements

Runtime

  • 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
  • hamlib
  • X11 or Wayland display server

Build-time

  • 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-dev
    • libasound2-dev (if using -DAUDIO_BACKEND=ALSA)
    • libpulse-dev (if using -DAUDIO_BACKEND=PULSE default on Linux)
    • libhamlib-dev (GUI only)
    • libcairo2-dev (usually pulled in by GTK3)

Install dependencies (Debian/Ubuntu)

# 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-dev

Install dependencies for macOS

You will need Xcode command line tools and homebrew.

brew install automake libtool git sox cmake wget pkgconf \
gtk+3 hamlib portaudio 

Build Instructions

cd radae_decoder

Prepare 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/

Audio backend selection

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.

Environment quirks

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 ..

Debian Package for webrx_rade_decode

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.

Quick build

# 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.deb

Skip rebuild

If build/tools/webrx_rade_decode already exists from a previous cmake build:

./package-deb.sh --skip-build

Using dpkg-buildpackage

sudo apt install debhelper-compat

A 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.minimal

Note: 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.sh for straightforward local builds.

Usage

./build/RADAE_Gui

First run (RX)

  1. Input dropdown -- Select the capture device receiving the RADAE modem signal (e.g. a sound card connected to a radio receiver).
  2. Output dropdown -- Select the playback device for decoded speech (e.g. speakers or headphones).
  3. Start button -- Click to begin decoding. The button turns red and changes to "Stop".
  4. Status bar -- Shows "Searching for signal..." until a RADAE signal is detected, then displays "Synced -- SNR: X dB Freq: +Y Hz".
  5. Meter display -- Shows decoded output audio levels in real-time once synced.
  6. 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.

Transmitting (TX)

  1. Toggle the TX switch to enable transmit mode. The settings dialog gains TX-specific device selectors.
  2. TX Input -- Select the microphone capture device.
  3. TX Output -- Select the playback device connected to the radio transmitter.
  4. TX level slider -- Adjust the output drive level (right side of window). The setting is saved across sessions.
  5. 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.
  6. Click Start to begin transmitting. The status bar shows "Transmitting..." and the meters show mic input and modem output levels.
  7. Click Stop to end the transmission; an end-of-over (EOO) frame is sent automatically.

Permissions

If you see "Failed to open audio devices":

  • ALSA: Ensure your user is in the audio group (sudo usermod -aG audio $USER, then log out and back in).
  • PulseAudio: Ensure PulseAudio is running (pulseaudio --check or pactl info).

radae_headless — Headless Transceiver

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]

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

Modes

Receive (RX) — default mode. Requires --fromradio and --tospeaker:

./build/radae_headless --fromradio alsa_input.usb-radio --tospeaker alsa_output.pci-speakers

Transmit (TX) — enabled with -t. Requires --frommic and --toradio:

./build/radae_headless -t --frommic alsa_input.pci-mic --toradio alsa_output.usb-radio

Use --devices to discover the correct device names for your system:

./build/radae_headless --devices

Configuration file

Settings 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=VK3TPM

Command-line options always override values in the config file.

Status output

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).

Architecture

Component overview

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).

Decode pipeline (RX)

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

Encode pipeline (TX)

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

Sync state machine

The RADE receiver has three states:

  1. SEARCH -- Correlates incoming signal against pilot patterns across 40 frequency bins (+-100 Hz range, 2.5 Hz steps)
  2. CANDIDATE -- Validates detected signal over multiple frames, refines timing and frequency
  3. 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()).

Thread model

  • 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)

Troubleshooting

"Package 'gtk+-3.0' not found"

Your pkg-config search path is missing the multiarch directory:

export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig

"Failed to open audio devices" (ALSA)

  • List available capture devices: arecord -L
  • List available playback devices: aplay -L
  • Ensure your user is in the audio group: groups $USER
  • Try the default device, or a specific hw:X,Y or plughw:X,Y identifier from arecord -l.

"Failed to open audio devices" (PulseAudio)

  • Ensure PulseAudio is running: pulseaudio --check or pactl info.
  • Verify devices exist: pactl list sources short (capture) and pactl list sinks short (playback).
  • Try different devices from the dropdowns.

No audio output / stuck on "Searching for signal..."

  • 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.

Build fails downloading Opus

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.

Build takes a long time

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.

Technical details

RADAE modem parameters

  • 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)

Audio backend configuration

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.

Demo tools

RADE Demod: WAV RADE → WAV Speech Audio

Take a wav file off air and produce a demodulated wav file

Usage:

rade_demod [-v 0|1|2] <input.wav> <output.wav>

RADE Modulate: WAV Speech Audio → WAV RADE

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>

Round trip test

./tools/rade_modulate ../voice.wav rade.wav
./tools/rade_demod rade.wav decoded.wav
play decoded.wav

Encode: WAV → IQ

sox ../voice.wav -r 16000 -t .s16 -c 1 - | \
  ./tools/lpcnet_demo -features /dev/stdin - | \
  ./tools/radae_tx > tx.iq

Decode: IQ → WAV

cat tx.iq | \
  ./tools/radae_rx | \
  ./tools/lpcnet_demo -fargan-synthesis /dev/stdin - | \
  sox -t .s16 -r 16000 -c 1 - decoded.wav

Decode: WAV RADE → WAV (multiple steps)

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

Decode 8kHz int-16 samples from stdin (for OpenWebRX)

./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

Source files

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

Credits

  • 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)

Performance notes

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.

About

An experimental FreeDV RADEV1 GUI client using the C port

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors