Uladzimir KarpenkaandClaude Opus 4.8 65cb3c386e wfm: add a wideband FM modulator and demodulator
Model the pair on fmd.c / fmmod.c, but with the parts that a 75 kHz
deviation forces:

  - the demodulator discriminates with arg(x[n] * conj(x[n-1])) rather
    than a PLL; an omegaN in the tens of kHz cannot track 75 kHz.
  - emphasis is a one-pole RC (tau 75 us) on both ends, not fmd's 1/f
    fc_impulse FIR.  A 1/f FIR from f_low = 20 Hz would sit ~+57 dB at
    20 Hz, where broadcast FM specifies flat below the corner.
  - TXA_WFM leaves the shared preemph block off; wfmmod carries its own.
  - wfmmod clamps bp_fc = deviation + f_high to 0.45 * samplerate, since
    +/-90 kHz exceeds Nyquist at the rates the narrowband modes use.

Scope is mono: no 19 kHz pilot, no 38 kHz stereo subcarrier, no RDS.

Both mode enums are appended to so the ABI stays stable for clients.
The JNI bindings are deliberately left alone.

Verified against a wfmmod -> wfmd loopback: the discriminator is exact,
the dc-removal one-pole tracks |H_lp(f)| * ain * sdelta to ratio 1.000,
and a 700 + 1900 Hz two-tone comes back with THD+N ~ 3e-5 % at +/-37.5
kHz deviation.  Note the demodulator aliases unless samplerate exceeds
2 * deviation * |aud|max, so 192 kHz is the practical floor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 07:43:07 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00
2026-06-01 15:58:45 +03:00

WDSP

DSP library for SDR (Software Defined Radio) applications.

Originally written for Windows by Warren Pratt, NR0V. Ported to Linux and Android by John Melton G0ORX/N6LYT.

Project structure

wdsp/
├── *.c / *.h                    — WDSP library sources
├── org_openhpsdr_dsp_Wdsp.c/.h  — JNI bridge
├── Makefile                     — host build (Linux / macOS)
├── Makefile.android             — Android cross-build
├── java/
│   └── org/openhpsdr/dsp/Wdsp.java
├── third_party/
│   ├── fftw/              — FFTW source (download manually, see below)
│   ├── rnnoise/           — RNNoise noise suppression
│   └── libspecbleach/     — spectral noise reduction
├── obj/                   — object files (generated)
└── lib/                   — built libraries (generated)

Host build (Linux / macOS)

Dependencies

Linux:

sudo apt install build-essential libfftw3-dev pkg-config default-jdk

macOS:

brew install fftw pkg-config

Build

# Full build: static + shared + JNI library + Java classes
make

# Individual targets
make static        # lib/libwdsp.a
make shared        # lib/libwdsp.so  (or .dylib on macOS)
make java          # lib/libwdspj.so + java/build/

Install

sudo make install                    # installs to /usr/local/lib and /usr/local/include
sudo make PREFIX=/opt/wdsp install   # custom prefix
sudo make install_java               # install libwdspj alongside libwdsp

Options

Variable Default Description
PREFIX /usr/local Install prefix
NR34LIB off Set to ON to skip bundled rnnoise/libspecbleach
CC gcc C compiler
CFLAGS -pthread -O3 ... Compiler flags
make NR34LIB=ON    # build without NR3/NR4 noise reduction
make CC=clang

Clean

make clean

Android build

Prerequisites

  1. Android NDK r23 or newer
  2. FFTW source — download and extract into third_party/fftw/:
wget https://www.fftw.org/fftw-3.3.10.tar.gz
tar xf fftw-3.3.10.tar.gz
mv fftw-3.3.10 third_party/fftw
  1. Java compiler — for building the .class file (Android Studio's JBR or any JDK)

Build

make android
# or directly
make -f Makefile.android

Output is placed into:

lib/android/
├── arm64-v8a/
│   ├── libfftw3.so
│   ├── libfftw3f.so
│   ├── libwdsp.so
│   └── libwdspj.so
├── armeabi-v7a/
│   └── ...
├── x86_64/
│   └── ...
└── java/
    └── org/openhpsdr/dsp/Wdsp.class

libwdsp.so has FFTW linked statically — no separate FFTW dependency at runtime on the device.

Options

Variable Default Description
ANDROID_NDK /home/vladimir/Android/Sdk/ndk/29.0.14206865 Path to Android NDK
ANDROID_API 24 Minimum API level
ANDROID_ABIS arm64-v8a armeabi-v7a x86_64 Target ABIs
ANDROID_HOST_TAG auto-detected Host platform (linux-x86_64, darwin-x86_64, etc.)
FFTW_SRC third_party/fftw Path to FFTW source
JAVAC /opt/android-studio/jbr/bin/javac Java compiler
make -f Makefile.android \
    ANDROID_NDK=~/Android/Sdk/ndk/26.3.11579264 \
    ANDROID_API=26 \
    ANDROID_ABIS=arm64-v8a

Clean

make -f Makefile.android clean
# removes obj/android/ and lib/android/

Using in an Android project

Copy lib/android/{abi}/ into your Android project's jniLibs:

app/src/main/jniLibs/
├── arm64-v8a/
│   ├── libwdsp.so
│   └── libwdspj.so
├── armeabi-v7a/
│   └── ...
└── x86_64/
    └── ...

Add Wdsp.java to your source tree and load the libraries at startup:

System.loadLibrary("wdsp");
System.loadLibrary("wdspj");

Or use the singleton:

Wdsp wdsp = Wdsp.getInstance();
S
Description
No description provided
Readme
63 MiB
Languages
C 99.9%
Java 0.1%