Uladzimir KarpenkaandClaude Opus 4.8 9960a1d0e3 resample: vectorize the polyphase tap loop
The tap loop wrapped the ring with a test on every tap:

    if ((idx_out = idx_in + j) >= ringsize) idx_out -= ringsize;

which made the address non-affine and stopped the vectorizer. Split the
walk at the wrap point instead, so both halves are unit-stride, and split
the complex ring into separate I/Q arrays so the taps load contiguously
rather than through a de-interleaving ld2.

The dot product also could not be vectorized as written: reassociating an
fp reduction needs -ffast-math, which this library must not enable (it
relies on IEEE semantics for 0/0 = NaN and x/0 = Inf, see linux_port.h).
Carry four independent accumulator pairs instead, which both breaks the
FMA dependency chain and lets the vectorizer in on any compiler.

Measured on an Apple M1 Pro, 512-sample DSP buffers, best of 5:

  xresample, decimation to 48 kHz     before      after    speedup
    192k -> 48k  (561 taps)          342.0 us    84.2 us     4.06x
    384k -> 48k  (1121 taps)         708.9 us   175.1 us     4.05x
    576k -> 48k  (1681 taps)        1074.4 us   266.9 us     4.03x
    768k -> 48k  (2241 taps)        1438.9 us   360.0 us     4.00x

  full xrxa() chain, 576k input      1148.2 us   337.6 us     3.40x
                                     10.76%       3.16%   of one core

  xresampleF (float, host audio)                          2.6x - 3.4x

Summation order changes, so the double path is not bit-identical: over
400 buffers of the full RX chain the worst deviation is 1.1e-12, an SNR
of 251 dB. The float path is bit-identical, as the cast to float absorbs
the difference. With the resampler bypassed (48k in, 48k out) the chain
is unchanged bit-for-bit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 22:44:08 +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
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%