DenoiseStream removes background noise from a live microphone in real time. A mic-side client streams 20 ms audio chunks to a server; the server suppresses noise and streams the cleaned audio back — low enough latency to monitor while you speak, with optional before/after recording.
The denoising backend is pluggable. A dependency-free spectral-gate runs on any CPU, and an optional DeepFilterNet backend plugs in for learned, GPU-accelerated suppression — without changing the client, protocol, or endpoints.
Heavy denoising wants a capable (or GPU) machine, while the microphone lives on a laptop. DenoiseStream splits the two and connects them over a small, explicit binary protocol, so the same client can drive a local CPU server for development and a remote GPU server in production.
┌──────────────┐ 20 ms float32 chunks ┌─────────────────────┐
mic ─▶ │ client │ ──────────────────────────▶ │ server │
│ capture & │ WebSocket · HTTP │ denoise (CPU/GPU) │
out ◀─ │ playback │ ◀────────────────────────── │ spectral-gate or │
└──────────────┘ cleaned chunks back │ DeepFilterNet │
└─────────────────────┘
| Capability | Detail |
|---|---|
| Pluggable backends | numpy spectral-gate (no GPU) or DeepFilterNet (GPU), selected with --enhancer |
| Low-latency streaming | full-duplex WebSocket, 20 ms (320-sample) frames at 16 kHz |
| Batch enhancement | one-shot POST /api/enhance: raw PCM in, denoised WAV out |
| Real DSP | decision-directed (Ephraim–Malah) Wiener filter on a streaming overlap-add STFT |
| Bring your own server | client talks to any server that implements the documented protocol |
| Light core | depends only on numpy; the server and learned backend are optional extras |
pip install -e ".[dev]"
python scripts/demo.pyThe demo synthesizes a noisy clip, runs the spectral-gate enhancer offline, writes
samples/before.wav and samples/after.wav, and reports the measured reduction:
backend : spectral-gate
clip : 4.0s @ 16000 Hz
noise floor : 0.0598 -> 0.0226 rms
noise reduction : 8.4 dB
pip install -e ".[server,client]"
# terminal 1 — start the server (GPU-free spectral-gate backend)
denoisestream-server --enhancer spectral-gate
# terminal 2 — stream mic -> denoise -> speakers
denoisestream-client --url http://127.0.0.1:8765 stream --play
# capture before/after WAVs while streaming (Ctrl+C to stop)
denoisestream-client stream --record --before before.wav --after after.wavRecord a fixed segment, enhance it in one request, then save or play it back:
denoisestream-client --url http://127.0.0.1:8765 batch --seconds 3 --playpip install -e ".[server,deepfilternet]" # adds torch (large)
denoisestream-server --enhancer deepfilternetDeepFilterNet is a learned model that handles non-stationary noise — other voices, keyboard, traffic — that a stationary spectral gate cannot. The client, protocol, and endpoints are unchanged.
The bundled server is a reference default, not a requirement. The client and
server are fully decoupled: the client speaks a small, documented protocol
(docs/protocol.md) and will talk to any server that
implements it — for example a GPU box already running DeepFilterNet, RNNoise, or
a custom model.
Install only the client and point it at your host:
pip install -e ".[client]" # installs the mic client only — no aiohttp, no server
denoisestream-client --url http://YOUR-SERVER:PORT stream --playA compatible server only needs to honor the contract:
| Endpoint | Purpose |
|---|---|
GET /health |
report sample_rate_hz and chunk_samples |
GET /ws/stream |
JSON handshake, then binary float32 chunk in, denoised chunk out |
POST /api/enhance |
raw float32 PCM in, denoised WAV out (batch) |
The default backend is a numpy-only speech enhancer on a streaming overlap-add STFT (50% overlap, Hann window):
- Frame the audio into overlapping windows.
- Estimate the noise spectrum with minima-controlled recursive averaging and a speech-presence guard, so sustained speech is not absorbed into the noise floor.
- Apply a gain mask from a decision-directed (Ephraim–Malah) Wiener filter: bins dominated by noise are attenuated toward a floor; bins above it pass through.
- Reconstruct with weighted overlap-add, dividing out the window energy so a unity mask reproduces the input exactly. Algorithmic latency is one hop (20 ms).
- Streaming — a WebSocket duplex. A JSON handshake negotiates the chunk size, then the client sends raw float32 chunks and the server returns one denoised chunk for each.
- Batch —
POST /api/enhancewith raw float32 PCM returns a denoised WAV. - Raw-TCP framing — a self-contained length-prefixed format (magic header,
uint32length, payload,0for end-of-stream) for the low-level transport.
See docs/architecture.md and docs/protocol.md for the full design.
The client runs three cooperating threads — a mic-input callback, a network worker, and a speaker-output callback — bridged by two queues. In live mode it drops the oldest chunk under backpressure to stay low-latency; in record mode it keeps every chunk so the saved file is complete.
--enhancer |
Dependencies | Removes | Notes |
|---|---|---|---|
spectral-gate |
numpy | stationary noise (hiss, fans, hum) | default, GPU-free |
deepfilternet |
torch + model | non-stationary noise too | learned, GPU-friendly |
passthrough |
numpy | nothing (identity) | baseline / transport testing |
Add your own by implementing the Enhancer interface
(src/denoisestream/enhancers/base.py) and registering it in the factory.
src/denoisestream/
config.py client/server contract (sample rate, chunk size, routes)
protocol.py length-prefixed binary framing
audio_io.py WAV encode/decode
dsp.py streaming STFT + spectral-gate Wiener filter
enhancers/ pluggable backends and factory
server/ aiohttp app: WebSocket stream, HTTP batch, health
client/ streaming and batch clients, CLI
tests/ protocol, DSP, enhancers, end-to-end server
scripts/demo.py offline before/after demo
docs/ architecture and protocol specs
pip install -e ".[dev]"
pytestThe suite exercises the binary framing, WAV I/O, the STFT/Wiener DSP, and an end-to-end round-trip against the live aiohttp server.
- The spectral gate targets stationary noise; use the DeepFilterNet backend for non-stationary sources.
- The DeepFilterNet streaming path runs per chunk; a frame-synchronous integration would lower its latency further.
- The server has no authentication or TLS — run it on a trusted network or behind a reverse proxy.
Released under the MIT License.