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.
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:
- Process segment N
- Save state to Redis
- Scale down / terminate
- 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!
No comments yet.
Sign in to be the first to comment.