arancormonk/dsd-neo
A modern, modular, and performance enhanced C/C++ decoder for digital voice. DMR, P25, NXDN, YSF, and more.
DSD-neo
A modular and performance‑enhanced version of the well-known Digital Speech Decoder (DSD) with a modern CMake build, split into focused libraries (runtime, platform, dsp, io, engine, fec, crypto, protocol, core, ui) and a thin CLI.
Project homepage: https://github.com/arancormonk/dsd-neo
Downloads
- Stable releases: see GitHub Releases
- Linux AppImage (x86_64):
dsd-neo-linux-x86_64-portable-<version>.AppImage - Linux AppImage (aarch64):
dsd-neo-linux-aarch64-portable-<version>.AppImage - macOS DMG (arm64):
dsd-neo-macos-arm64-portable-<version>.dmg - Windows native ZIP (MSVC x86_64, recommended):
dsd-neo-msvc-x86_64-native-<version>.zip - Windows native ZIP (MinGW x86_64, alternative):
dsd-neo-mingw-x86_64-native-<version>.zip
- Linux AppImage (x86_64):
- Nightly builds:
- Linux AppImage (x86_64): dsd-neo-linux-x86_64-portable-nightly.AppImage
- Linux AppImage (aarch64): dsd-neo-linux-aarch64-portable-nightly.AppImage
- macOS DMG (arm64): dsd-neo-macos-arm64-portable-nightly.dmg
- Windows native ZIP (MSVC x86_64, recommended): dsd-neo-msvc-x86_64-native-nightly.zip
- Windows native ZIP (MinGW x86_64, alternative): dsd-neo-mingw-x86_64-native-nightly.zip
- Arch Linux (AUR): dsd-neo-git
On Windows, the native MSVC ZIP is the preferred download for best integration with the Windows console and audio stack. The MinGW ZIP is a fully native alternative.
Project Status
This project is an active work in progress as we decouple from the upstream fork and continue modularization. Expect breaking changes to build presets, options, CLI flags, and internal library boundaries while this stabilization work proceeds. The main branch may be volatile; for deployments, prefer building a known commit. Issues and PRs are welcome—please include logs and reproduction details when reporting regressions.
Overview
- A performance‑enhanced fork of lwvmobile/dsd-fme, which is a fork of szechyjs/dsd
- Modularized fork with clear boundaries:
runtime,platform,dsp,io,engine,fec,crypto,protocol,core, plusuiand a CLI app. - Protocol coverage: DMR, dPMR, D‑STAR, NXDN, P25 Phase 1/2, X2‑TDMA, EDACS, ProVoice, M17, YSF.
- Requires arancormonk/mbelib-neo for IMBE/AMBE vocoder primitives.
- Public headers live under
include/dsd-neo/...and are included as#include <dsd-neo/<module>/<header>>.
How DSD‑neo Is Different
-
More input and streaming options
- Direct RTL‑SDR USB, plus RTL‑TCP (
-i rtltcp[:host:port]) and SoapySDR (-i soapy[:args]) for non-RTL radios (for example Airspy/SDRplay/HackRF/LimeSDR). - Generic TCP PCM16LE input (
-i tcp[:host:port], SDR++/GRC 7355 audio streams). - UDP audio in/out: receive PCM16LE over UDP as an input, and send decoded audio to UDP sinks for easy piping to other apps or hosts (decoded voice is typically 8 kHz; see
docs/network-audio.md). - M17 UDP/IP in/out: dedicated M17 frame input/output over UDP (
-i m17udp[:bind:17000],-o m17udp[:host:17000]).
- Direct RTL‑SDR USB, plus RTL‑TCP (
-
Built‑in trunking workflow
- Follow P25 and DMR trunked voice automatically using channel maps and group lists (
-C ...csv,-G group.csv,-T,-N). - On‑the‑fly retune control via rigctl (
-U) for external SDR front-ends (e.g., SDR++). For RTL/RTL‑TCP input, DSD-neo retunes directly (optional external UDP retune control can be enabled with--rtl-udp-control <port>; seedocs/udp-control.md).
- Follow P25 and DMR trunked voice automatically using channel maps and group lists (
-
RTL‑SDR quality‑of‑life features
- Bias‑tee control (when supported by your librtlsdr), manual or auto gain, power squelch, adjustable tuner bandwidth, and per‑run PPM correction.
- Optional spectrum‑based auto‑PPM drift correction with SNR/power gating and short training/lock, for long unattended runs.
- rtl_tcp niceties: configurable prebuffering to reduce dropouts and settings tuned for stable network use.
-
RTL‑SDR optimizations and diagnostics
- Real‑time visual aids in the terminal for faster setup and troubleshooting:
- Constellation view with adjustable gating and normalization.
- Eye diagram (Unicode/ASCII, optional color) with adaptive scales and level guides.
- Spectrum analyzer with adjustable FFT size.
- FSK 4‑level histogram and live per‑modulation SNR readouts.
- Heavily optimized RTL path for smoother audio and fewer dropouts:
- One‑pass byte→I/Q widening with optional 90° rotation and DC‑spur fs/4 capture shift (configurable).
- Cascaded decimation and an optional rational resampler to keep processing efficient and responsive.
- Optional auto‑PPM correction from the timing error detector for long unattended runs.
- Device control from the UI: toggle bias‑tee, switch AGC/manual gain, adjust bandwidth and squelch, and retune quickly.
- Real‑time visual aids in the terminal for faster setup and troubleshooting:
-
M17 encode tooling
- Generate M17 signals for test/airgap workflows: stream voice (
-fZ), packet (-fP), and BERT (-fB) encoders.
- Generate M17 signals for test/airgap workflows: stream voice (
-
Expanded DSP controls for power users
- Changes apply instantly from the UI and persist across retunes.
- See docs/cli.md for environment variable reference.
-
Portable, ready‑to‑run builds
- Linux AppImage, macOS DMG, and Windows portable ZIP releases.
How this compares at a glance
- Versus DSD‑FME: similar protocol coverage and UI heritage, but DSD‑neo adds network‑friendly I/O (UDP audio in), refined RTL‑TCP handling (prebuffer, tuned defaults), optional auto‑PPM, and packaged cross‑platform binaries.
- Versus the original DSD: more protocols (notably P25 Phase 2, M17, YSF, EDACS), built‑in trunking, network inputs, device control, and an interactive UI.
Build From Source
Requirements
- C compiler with C11 and C++ compiler with C++14 support.
- CMake ≥ 3.20.
- Dependencies:
- Required: libsndfile; a curses backend (ncursesw/PDCurses); and an audio backend (PulseAudio by default, PortAudio on Windows).
- Optional: librtlsdr (RTL‑SDR support), SoapySDR (non‑RTL SDR backends), Codec2 (additional vocoder paths), libcurl (rdio API uploads), help2man (man page generation).
- Vocoder: mbelib-neo (
mbe-neoCMake package) is required.
OS package hints
- Ubuntu/Debian (apt):
sudo apt-get update && sudo apt-get install -y build-essential cmake ninja-build libsndfile1-dev libpulse-dev libncurses-dev librtlsdr-dev libsoapysdr-dev
- macOS (Homebrew):
brew install cmake ninja libsndfile ncurses pulseaudio librtlsdr soapysdr codec2
- Windows:
- Preferred binary: the native MSVC ZIP. The MinGW ZIP is an alternative native build.
- Source builds use CMake presets with vcpkg; set
VCPKG_ROOTand usewin-msvc-*orwin-mingw-*presets inCMakePresets.json.
MBE vocoder dependency (mbelib-neo)
DSD‑neo requires the mbe-neo CMake package (from mbelib-neo). If CMake fails with “could not find mbe-neo”, install it and re-run configure.
Example (Linux/macOS):
# Build and install mbelib-neo (once)
git clone https://github.com/arancormonk/mbelib-neo
cmake -S mbelib-neo -B mbelib-neo/build -DCMAKE_BUILD_TYPE=Release
cmake --build mbelib-neo/build -j
cmake --install mbelib-neo/build --prefix "$HOME/.local"
# Then configure dsd-neo (point CMake to the install prefix)
cmake --preset dev-release -DCMAKE_PREFIX_PATH="$HOME/.local"Build recipes (copy/paste)
Linux/macOS — release build (preset dev-release, recommended)
# From the repository root.
#
# OS deps (examples):
# - Ubuntu/Debian: sudo apt-get update && sudo apt-get install -y build-essential cmake ninja-build libsndfile1-dev libpulse-dev libncurses-dev librtlsdr-dev libsoapysdr-dev
# - macOS: brew install cmake ninja libsndfile ncurses pulseaudio librtlsdr soapysdr codec2
#
# Install is optional; you can run directly from the build tree.
cmake --preset dev-release
cmake --build --preset dev-release -j
# Run (no install required)
build/dev-release/apps/dsd-cli/dsd-neo -h
# Install (optional; pick one)
cmake --install build/dev-release --prefix "$HOME/.local"
# sudo cmake --install build/dev-releaseLinux/macOS — debug build + tests (preset dev-debug)
# OS deps (examples):
# - Ubuntu/Debian: sudo apt-get update && sudo apt-get install -y build-essential cmake ninja-build libsndfile1-dev libpulse-dev libncurses-dev librtlsdr-dev libsoapysdr-dev
# - macOS: brew install cmake ninja libsndfile ncurses pulseaudio librtlsdr soapysdr codec2
cmake --preset dev-debug
cmake --build --preset dev-debug -j
ctest --preset dev-debug -V
# Run (no install required)
build/dev-debug/apps/dsd-cli/dsd-neo -hManual configure/build (no presets)
# Use a build directory that isn't a preset (so you don't expect build/dev-release to exist).
cmake -S . -B build/manual -DCMAKE_BUILD_TYPE=Release
cmake --build build/manual -j
# Run (no install required)
build/manual/apps/dsd-cli/dsd-neo -h
# Install (optional; pick one)
cmake --install build/manual --prefix "$HOME/.local"
# sudo cmake --install build/manualCoverage (optional)
tools/coverage.sh # generates build/coverage-debug/coverage_htmlNotes
- Presets live in
CMakePresets.json. - Presets create out‑of‑source builds under
build/<preset>/. Run from the repo root. - The CLI binary outputs to
build/<preset>/apps/dsd-cli/dsd-neo. cmake --install <build_dir>only works if you configured that build directory. If you're inside the build directory, usecmake --install ..- If
cmake --install build/dev-releasefails andbuild/dev-release/doesn't exist, you likely did a manual build (install from your actual build dir).
Install / Uninstall
# Preset builds (recommended)
# Single-config generators (Unix Makefiles/Ninja):
cmake --install build/dev-release --prefix "$HOME/.local"
# Multi-config generators (Visual Studio/Xcode):
cmake --install build/dev-release --config Release --prefix "$HOME/.local"
# Manual build directory (example above uses `build/manual/`):
cmake --install build/manual --prefix "$HOME/.local"
# cmake --install build --prefix "$HOME/.local" # if you configured into `build/`
# Uninstall from the same build directory
cmake --build build/dev-release --target uninstall # preset build
cmake --build build/manual --target uninstall # manual build directory
# cmake --build build --target uninstall # if you configured into `build/`Build Options
These are CMake cache options (set at configure time via -D...).
- Build hygiene and optimization:
-DDSD_ENABLE_WARNINGS=ON— Enable common warnings (default ON).-DDSD_WARNINGS_AS_ERRORS=ON— Treat warnings as errors.-DDSD_ENABLE_FAST_MATH=ON— Enable fast‑math (-ffast-math//fp:fast) across targets.-DDSD_ENABLE_LTO=ON— Enable IPO/LTO in Release builds (when supported).-DDSD_ENABLE_NATIVE=ON— Enable-march=native -mtune=native(non‑portable binaries).-DDSD_ENABLE_ASAN=ON— AddressSanitizer in Debug builds.-DDSD_ENABLE_UBSAN=ON— UndefinedBehaviorSanitizer in Debug builds.
- Audio backend selection:
-DDSD_USE_PORTAUDIO=ON— Use PortAudio instead of PulseAudio (default on Windows).
- Radio backend selection:
-DDSD_ENABLE_RTLSDR=ON|OFF— Enable/disable RTL-SDR backend discovery.-DDSD_ENABLE_SOAPYSDR=ON|OFF— Enable/disable SoapySDR backend discovery.-DDSD_REQUIRE_RTLSDR=ON|OFF— Fail configure when RTL-SDR is enabled but unavailable.-DDSD_REQUIRE_SOAPYSDR=ON|OFF— Fail configure when SoapySDR is enabled but unavailable.
- UI and behavior toggles:
-DCOLORS=OFF— Disable ncurses color output.-DCOLORSLOGS=OFF— Disable colored terminal/log output.
- Protocol and feature knobs:
-DPVC=ON— Enable ProVoice Conventional Frame Sync.-DLZ=ON— Enable LimaZulu‑requested NXDN tweaks.-DSID=ON— Enable experimental P25p1 Soft ID decoding.
- Optional features (auto‑detected):
- RTL‑SDR support is enabled when
librtlsdris found. - SoapySDR support is enabled when SoapySDR is found.
- Codec2 support is enabled when
codec2is found.
- RTL‑SDR support is enabled when
CI Backend Policy
- CI treats backend availability as a build contract, not a best-effort option.
- Linux CI runs a backend matrix for
both,soapy_only,rtl_only, andneither. - Release/packaging/static-analysis jobs that are expected to exercise radio backends configure with:
-DDSD_REQUIRE_RTLSDR=ON-DDSD_REQUIRE_SOAPYSDR=ON
- If either required backend is missing, configure fails fast.
Backend Matrix Reproduction (Local)
Run from repo root after installing deps (librtlsdr and SoapySDR when required):
# both backends required
cmake --preset dev-debug \
-DDSD_ENABLE_RTLSDR=ON -DDSD_REQUIRE_RTLSDR=ON \
-DDSD_ENABLE_SOAPYSDR=ON -DDSD_REQUIRE_SOAPYSDR=ON
cmake --build --preset dev-debug -j
# soapy_only
cmake --preset dev-debug \
-DDSD_ENABLE_RTLSDR=OFF \
-DDSD_ENABLE_SOAPYSDR=ON -DDSD_REQUIRE_SOAPYSDR=ON
cmake --build --preset dev-debug -j
# rtl_only
cmake --preset dev-debug \
-DDSD_ENABLE_RTLSDR=ON -DDSD_REQUIRE_RTLSDR=ON \
-DDSD_ENABLE_SOAPYSDR=OFF
cmake --build --preset dev-debug -j
# neither
cmake --preset dev-debug \
-DDSD_ENABLE_RTLSDR=OFF \
-DDSD_ENABLE_SOAPYSDR=OFF
cmake --build --preset dev-debug -jCI-like strict scan-build run:
tools/scan_build.sh --strict \
--cmake-arg -DDSD_REQUIRE_RTLSDR=ON \
--cmake-arg -DDSD_REQUIRE_SOAPYSDR=ONRuntime Tuning
Most users can run with defaults. For advanced tuning, see docs/cli.md.
Common options:
- Auto‑PPM drift correction (RTL‑SDR):
--auto-ppm - RTL‑TCP adaptive buffering:
--rtltcp-autotune - Rig control (SDR++):
-U 4532(default port),-B <Hz>(bandwidth)
SoapySDR Quickstart
- Use SoapySDR when your hardware is not accessed through
librtlsdrdirectly. - Build with Soapy enabled (
-DDSD_ENABLE_SOAPYSDR=ON) and optionally require it (-DDSD_REQUIRE_SOAPYSDR=ON). - Install SoapySDR tools and the Soapy module for your radio; verify with
SoapySDRUtil --infoand discover args with
SoapySDRUtil --find. - Run with
-i soapy[:args]. Thesoapy:string selects backend/device only; set tuning viartl_*keys (at minimum
rtl_freq; easiest via config). See the guide for a minimal config snippet. - Full guide:
docs/soapysdr.md.
Using The CLI
- See the friendly CLI guide: docs/cli.md
- Or run
dsd-neo -hfor quick usage in your terminal. - Digital/analog output gain:
-g <float>(digital;0= auto,1≈ 2%,50= 100%) and-n <float>(analog 0–100%). - DMR mono helpers:
- Modern form:
-fs -nm(DMR BS/MS simplex + mono audio). - Legacy alias:
-fr(kept as a shorthand for the same DMR‑mono profile).
- Modern form:
- CSV formats (channel maps, group lists, key lists):
docs/csv-formats.md(examples inexamples/)
- Or run
Quick examples
- UDP in → Pulse out with UI:
dsd-neo -i udp -o pulse -N - DMR trunking from TCP PCM input (with rigctl):
dsd-neo -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N
Configuration
- INI‑style user config is implemented for stable defaults (input/output/mode/trunking); see
docs/config-system.md. - Config loading is opt-in: use
--configto enable (optionally with a path), setDSD_NEO_CONFIG=<path>, or pass a single positional*.inipath (treated as--config <path>). - Default path (when
--configis passed without a path):${XDG_CONFIG_HOME:-$HOME/.config}/dsd-neo/config.ini. --interactive-setupforces the bootstrap wizard even when a config exists;--print-configdumps the effective config as INI.- When config is enabled, the final settings are autosaved on exit.
Tests
- Run all tests:
ctest --preset dev-debug -V(orctest --test-dir build/dev-debug -V). - Scope: unit tests cover runtime config parsing/validation, DSP primitives (filters/resampler/demod helpers), and FEC/crypto helpers.
Documentation
- CLI usage and options:
docs/cli.md - SoapySDR non-RTL setup and usage:
docs/soapysdr.md - User config system (INI):
docs/config-system.md - Trunking CSV formats:
docs/csv-formats.md(examples inexamples/) - Network audio I/O details (TCP/UDP/stdin/stdout):
docs/network-audio.md - Terminal UI hotkeys and menus:
docs/ui-terminal.md - RTL UDP retune control protocol:
docs/udp-control.md - Module overview and build targets:
docs/code_map.md
Project Layout
- Apps:
apps/dsd-cli— CLI entrypoint, targetdsd-neo. - Core:
src/core, headers<dsd-neo/core/...>— glue (audio, vocoder, frame dispatch, GPS, file import). - Engine:
src/engine, headers<dsd-neo/engine/...>— top-level decode/encode runner and lifecycle. - Platform:
src/platform, headers<dsd-neo/platform/...>— cross-platform primitives (audio backend, sockets, threading, timing, curses). - Runtime:
src/runtime, headers<dsd-neo/runtime/...>— config, logging, aligned memory, rings, worker pool, RT scheduling, git version. - DSP:
src/dsp, headers<dsd-neo/dsp/...>— demod pipeline, resampler, filters, FLL/TED, SIMD helpers. - IO:
src/io, headers<dsd-neo/io/...>— radio (RTL‑SDR, RTL‑TCP, SoapySDR), audio (PulseAudio/PortAudio + UDP PCM input/output), control (UDP/rigctl/serial). - FEC:
src/fec, headers<dsd-neo/fec/...>— BCH, Golay, Hamming, RS, BPTC, CRC/FCS. - Crypto:
src/crypto, headers<dsd-neo/crypto/...>— RC2/RC4/DES/AES and helpers. - Protocols:
src/protocol/<name>, headers<dsd-neo/protocol/<name>/...>— DMR, dPMR, D‑STAR, NXDN, P25, X2‑TDMA, EDACS, ProVoice, M17, YSF. - Third‑party:
src/third_party/ezpwd(INTERFACE targetdsd-neo_ezpwd),src/third_party/pffft(FFT helper).
Tooling
- Format:
tools/format.sh(requiresclang-format; see.clang-format). - Static analysis:
tools/clang_tidy.sh(use--strictfor extra checks).tools/cppcheck.sh(use--strictfor broader checks).tools/iwyu.sh(include hygiene via include-what-you-use; excludessrc/third_party).tools/gcc_fanalyzer.sh(GCC-fanalyzerpath-sensitive diagnostics; excludessrc/third_party).tools/scan_build.sh(Clang Static Analyzer viascan-build, heavier full-build pass; excludessrc/third_party; supports repeatable--cmake-argpassthrough).tools/semgrep.sh(additional SAST rules; use--strictto fail on findings; excludessrc/third_party).
- Git hooks:
tools/install-git-hooks.shenables auto‑format on commit and a CI-aligned pre-push analysis pass (clang-format, clang-tidy, cppcheck, IWYU, GCC fanalyzer, Semgrep) on changed paths. - Optional full scan-build pre-push/preflight pass: set
DSD_HOOK_RUN_SCAN_BUILD=1. - Manual preflight runner:
tools/preflight_ci.shruns the same CI-aligned checks aspre-pushwithout pushing.
Contributing
- Languages: C (C11) and C++ (C++14). Indent width 4 spaces; no tabs; brace all control statements; line length ≤ 120.
- Use project‑prefixed includes only:
#include <dsd-neo/...>. - Prefer small, testable helpers and add focused tests under
tests/<area>. - Before sending changes: build presets you touched, run
tools/format.sh, address feasible clang‑tidy and cppcheck warnings.
License
- Project license: GPL‑3.0‑or‑later (see
LICENSE). - Portions remain under ISC per the original DSD author (see
COPYRIGHT). - Third-party notices live in
THIRD_PARTY.md(installed license texts:share/doc/dsd-neo/licenses/). - Project-authored source files carry SPDX identifiers reflecting their license; vendored third-party files retain upstream license headers.
