Web-native signal processing framework inspired by GNU Radio. Build real-time DSP flowgraphs that run entirely in the browser, with optional WebGPU and WASM acceleration.
Live demo: https://webgr.roman01la.workers.dev
- Visual flowgraph editor — drag-to-connect block-based DSP pipeline editor (Canvas 2D)
- Real-time scheduler —
MessageChannel-driven loop with pre-allocated scratch buffers, error boundaries, and topological execution - Lock-free buffers —
SharedArrayBuffer-backed circular buffers for cross-thread data flow - 30+ DSP blocks — sources, sinks, math, filters (FIR/IIR), demodulators (FM/AM/NBFM), resampling, transforms (FFT, Hilbert, rotator), AGC, PLL
- WebGPU FFT — Stockham radix-2 FFT compute pipeline with double-buffered readback
- WASM kernels — zero-copy SIMD-accelerated FFT, FIR, FM demod via Emscripten/AssemblyScript
- Audio output —
AudioWorkletsink fed by a SAB ring buffer - Spectrum & waterfall displays — Canvas 2D real-time visualization
- Persistence — save/load flowgraphs to localStorage and shareable URLs
packages/
core/ Scheduler, Flowgraph, CircularBuffer, Block base class
blocks/ DSP block implementations (FIR, FFT, FM demod, resampler, ...)
gpu/ WebGPU FFT and spectrum pipeline
dsp-wasm/ WASM kernel wrappers (zero-copy)
ui/ Flowgraph editor, spectrum/waterfall displays, controls
apps/
app/ Full-featured editor application (deployed)
demo/ FM receiver and signal generator demos
bench/ Benchmark suite (JS vs WASM vs GPU)
pnpm install
pnpm dev # run the editor app at localhost:5173
pnpm dev:demo # run the demo app
pnpm test:run # run all tests
pnpm build # build all packagesA flowgraph is a directed graph of blocks connected through circular buffers. Each block declares typed input and output ports (f32 for real samples, cf32 for complex I/Q). The scheduler topologically sorts blocks, then in each iteration calls each block's work() method with input/output buffer views, advancing read/write pointers based on the items consumed and produced.
Variable-rate blocks (decimators, interpolators, resamplers) report their actual itemsConsumed/itemsProduced so the scheduler advances buffer pointers correctly.
The scheduler uses MessageChannel for sub-millisecond scheduling (vs. setTimeout(0)'s ~4ms clamp), pre-allocated scratch buffers to eliminate per-iteration GC pressure, and per-block try/catch error boundaries.
DSP blocks have JS reference implementations and can be accelerated through opt-in injection:
import { FIRFilter, FMDemod } from '@webgr/blocks';
import {
loadNativeKernels, nativeFIRInit, nativeFIRFilter, nativeFIRReset, nativeFMDemod,
} from '@webgr/dsp-wasm';
await loadNativeKernels();
FIRFilter.enableWasm({ init: nativeFIRInit, filter: nativeFIRFilter, reset: nativeFIRReset });
FMDemod.enableWasm({ demod: nativeFMDemod });For GPU spectrum analysis, use GPUSpectrumPipeline from @webgr/gpu directly — it runs window → FFT → magnitude → power dB entirely on the GPU.
SharedArrayBuffer requires the page to be cross-origin isolated. The deployed Cloudflare Worker sets:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corpCross-Origin-Resource-Policy: same-origin
When self-hosting, ensure your server emits the same headers.