PitchHut logo
High-performance DSP library for real-time signal processing.
Pitch

dspx is a production-ready digital signal processing library that harnesses native C++ acceleration and Redis state persistence. Designed for Node.js backends, it excels in processing real-time biosignals, audio streams, and sensor data with speed and efficiency, offering a comprehensive suite of features for modern applications.

Description

I built dspx after hitting a wall with real-time EMG processing in Node.js.

The problem: 2000 Hz streams × 8 channels → filters → decimation → FFT

  • Pure JS: too slow
  • Python sidecar: deployment complexity
  • WASM: no native threading

The solution: Native C++ DSP with Redis-persisted state. Workers can process a chunk, save state, die, and resume elsewhere — serverless DSP without losing filter history.

Repo: https://github.com/a-kgeorge/dspx Benchmarks: https://github.com/a-kgeorge/dspx-benchmark npm: https://www.npmjs.com/package/dspx


Why Redis for DSP?

Traditional DSP assumes persistent processes. But serverless / Kubernetes deployments scale to zero, killing your filter state.

dspx serializes:

  • filter coefficients
  • FFT buffers
  • convolution history

to Redis in ~1–2 ms. New workers restore state + resume mid-stream.


Use cases

  • IoT gateways with intermittent workloads
  • Audio pipelines that need fault tolerance
  • Multi-tenant DSP where each user’s state persists independently
  • EMG/EEG/ECG processing with bursty traffic

Features

DSP primitives

  • STFT, Mel-spectrogram, MFCC (speech/audio)
  • FIR/IIR filtering (Butterworth, Chebyshev, Parks-McClellan)
  • Convolution (time-domain + FFT-based)
  • Moving stats, rectification, decimation, resampling
  • Hilbert transform, wavelet decomposition

Infrastructure

  • Multi-channel streaming (audio, biosignals, IoT sensors)
  • Redis state persistence (survives restarts, migrates across workers)
  • TypeScript-first API with full type safety
  • SIMD where available (AVX2 / SSE2 / NEON)

Performance

Environment: Intel i5-12600T • Node v22.21.1 • 16 GB RAM

Full benchmarks: https://github.com/a-kgeorge/dspx-benchmark

Throughput scaling

  • 1 pipeline: ~34M samples/sec
  • 32 pipelines: ~101M samples/sec (near-linear scaling)

Latency

  • Small inputs: sub-ms p50
  • Large inputs + Redis persistence: ~31 ms p50 / ~39 ms p99

Memory

Zero leaks observed across 10,000+ Redis save/restore cycles (C++ + JS GC verified clean)

ARM

Stable on Pixel 9 Pro XL under production-like loads (NEON tuning would improve further)


Why not WASM?

WASM was considered, but N-API fit better:

  • Native threading without SharedArrayBuffer hacks
  • Platform-specific SIMD (AVX2/SSE2/NEON)
  • Zero-copy Redis via raw buffer access
  • Clean integration with Node streams/Buffers

Example

const pipeline = await createDspPipeline({
  redisHost: "localhost",
  redisPort: 6379,
  stateKey: "dsp:user:ch1",
});

pipeline
  .filter({
    type: "butterworth",
    mode: "bandpass",
    lowCutoffFrequency: 20,
    highCutoffFrequency: 450
  })
  .stft({ windowSize: 512, hopSize: 160 })
  .melSpectrogram({ numMelBands: 26 })
  .mfcc({ numCoefficients: 13 });

await pipeline.process(audioData, { sampleRate: 16000 });

// Save state to Redis (1–2 ms)
const state = await pipeline.saveState();

// Worker can die here...

// New worker restores + resumes
await pipeline.loadState(state);
await pipeline.process(nextChunk);

Platform support

x64 + ARM Tested on Pixel 9 Pro XL — stable under large streams (even without NEON tuning)

Node 18 / 20 / 22 N-API v8 (single prebuild works across versions)

Prebuilt binaries

  • Linux / macOS / Windows (x64)
  • ARM users compile once; then behaves like a normal Node module

Stateful Serverless DSP

Because dspx serializes state + Redis is low-latency, workers can:

  1. Process segment N
  2. Save state to Redis
  3. Scale down / terminate
  4. Another worker resumes at N+1

Benefits

  • Fault tolerance (worker crash ≠ lost filter state)
  • Elastic scaling (scale to zero when idle)
  • Workload migration (e.g., multi-region)
  • Lower cost vs. always-on DSP instances

Help wanted

ARM NEON optimization

Seeking contributors for portable NEON paths (generic ARM) — especially convolution/FFT hot loops.

Production war stories

Where have you hit limits with DSP in Node? What primitives/patterns are missing?

Kafka integration

Exploring clean patterns to pipe Kafka topics into dspx pipelines (backpressure, batching, checkpoints). Feedback welcome.


Who is it for?

✅ Good fit

  • Node backends doing streaming sensor/audio DSP
  • Systems needing stateful pipelines + fault tolerance
  • Teams wanting DSP without separate Python/C++ services
  • IoT gateways with intermittent workloads

❌ Not ideal for

  • Browser-only DSP (use Web Audio API)
  • Hard real-time embedded audio (<1 ms latency)

Status

✅ STFT / Mel / MFCC ✅ Convolution + FFT (native C/C++) ✅ Redis state persistence ✅ ARM functional (not yet optimized) ✅ 891 tests passing (including chaining tests) 🔄 Kafka integration — seeking input


Feedback welcome — especially around:

  • Kafka / message queue patterns
  • NEON portability
  • Deployment models (Kubernetes operators?)
  • Real-world workloads

Repo: https://github.com/a-kgeorge/dspx

Benchmarks: https://github.com/a-kgeorge/dspx-benchmark

Thanks!

0 comments

No comments yet.

Sign in to be the first to comment.