Real-time streaming noise cancellation with DeepFilterNet3 on ONNX Runtime
Project description
deepfilter-stream
Real-time streaming noise cancellation with DeepFilterNet3 on ONNX Runtime.
deepfilter-stream wraps the DeepFilterNet3
model (arXiv:2110.05588) in a minimal, dependency-light Python API. It ships the model as an
ONNX graph so that inference runs entirely on CPU via ONNX Runtime — no PyTorch required.
The library is designed for low-latency, real-time pipelines: a single stream runs at roughly
7x faster than real-time on a modern CPU core, measured end-to-end algorithmic latency is
~32 ms, and a single machine can run 16+ concurrent real-time streams on a typical CPU.
Installation
pip install deepfilter-stream
The ONNX model (~13 MB) downloads automatically on first use and is cached in the user's platform cache directory. See Model download below.
Quickstart
Library API
from deepfilter_stream import DeepFilterModel, Denoiser
# Option A: shared model, one stream per thread
model = DeepFilterModel()
stream = model.new_stream(atten_lim_db=None) # or atten_lim_db=20.0 to blend in dry signal
# Feed arbitrary-length chunks at any sample rate; returns enhanced float32 mono
import numpy as np
noisy = np.random.randn(9600).astype(np.float32) # 0.2 s at 48 kHz
enhanced = stream.process(noisy, sr=48000)
# Flush any buffered tail at end of file
tail = stream.flush()
# Reset stream state without reloading the model (e.g. next utterance)
stream.reset()
# Option B: standalone Denoiser (loads its own model internally)
denoiser = Denoiser()
enhanced = denoiser.process(noisy, sr=48000)
Frame-by-frame API (lowest latency)
model = DeepFilterModel()
stream = model.new_stream()
frame_size = stream.frame_size # 512 samples at 48 kHz
frame = np.zeros(frame_size, dtype=np.float32)
enhanced_frame = stream.process_frame(frame)
Live demo (mic -> denoise -> speakers)
Warning: wear headphones to avoid feedback when using the live demo.
deepfilter-stream # use default mic/speakers
deepfilter-stream --list-devices # list audio devices
deepfilter-stream --input-device 2 --output-device 4
deepfilter-stream --atten-lim-db 20 # blend 20 dB noise reduction with dry signal
API reference
| Symbol | Description |
|---|---|
DeepFilterModel(model_path=None, providers=None, intra_op_num_threads=None, inter_op_num_threads=None) |
Loads the ONNX session. Thread-safe; share across threads. |
model.new_stream(atten_lim_db=None) |
Returns a new Denoiser stream bound to this model. |
stream.process(samples, sr) |
Process a chunk of audio (any length, any sample rate). Returns float32 mono at sr. |
stream.flush() |
Drain buffered tail; call at end of file/clip. |
stream.process_frame(frame) |
Process exactly one 512-sample frame at 48 kHz. |
stream.reset() |
Reset stream state (GRU hidden states + buffers). |
stream.sample_rate |
48000 |
stream.frame_size |
512 |
stream.latency_ms |
Per-frame STFT minimum (~10.7 ms for 512 samples at 48 kHz). |
Latency
- Hop size: 512 samples @ 48 kHz = 10.67 ms per frame.
latency_msproperty: reports the per-frame STFT minimum (~10.7 ms), which is the minimum algorithmic offset introduced by framing alone.- Measured end-to-end algorithmic latency: ~32 ms (≈ 3 hops), measured via impulse benchmark. This reflects the actual signal delay through the STFT/iSTFT and GRU pipeline.
- Real-world latency adds device/buffer round-trip time on top of the algorithmic offset.
Performance
Measured on a single CPU core (no GPU required):
| Metric | Value |
|---|---|
| Single-stream RTF | ~0.145 (~7x faster than real-time) |
| End-to-end algorithmic latency | ~32 ms (impulse benchmark, ~3 hops) |
| Concurrent real-time streams | 16+ on a typical CPU |
| Hop duration | 10.67 ms (512 samples @ 48 kHz) |
Concurrency
The DeepFilterModel session is thread-safe and shareable. Each Denoiser stream holds
its own GRU hidden state and is not thread-safe — use one stream per thread.
from deepfilter_stream import DeepFilterModel
# For servers with many concurrent streams, limit ONNX intra-op threads
# so that thread contention across streams does not reduce throughput:
model = DeepFilterModel(intra_op_num_threads=1)
# Each worker thread gets its own stream; model is shared
def worker():
stream = model.new_stream()
# ... process audio
Model download
The ONNX model is downloaded automatically on first use and cached under the platform cache
directory (e.g. ~/.cache/deepfilter-stream/dfn3-512-v1/ on Linux).
To use a local copy, set the environment variable:
export DEEPFILTER_STREAM_MODEL_DIR=/path/to/folder
# folder must contain: denoiser_model.onnx, initial_states.npz, meta.json
Attribution
deepfilter-stream bundles the DeepFilterNet3 model weights. The original work:
- Repository: https://github.com/Rikorose/DeepFilterNet
- Paper: arXiv:2110.05588 — "DeepFilterNet: A Low Complexity Speech Enhancement Framework for Full-Band Audio based on Deep Filtering"
Dual-licensed under MIT and Apache 2.0 (your choice). See LICENSE and NOTICE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file deepfilter_stream-0.1.0.tar.gz.
File metadata
- Download URL: deepfilter_stream-0.1.0.tar.gz
- Upload date:
- Size: 348.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62078455b3700deaae9e1b1455e18170f218d1d6fae9e7d9e2aa7360379a9984
|
|
| MD5 |
d77a6bb81ea953fc267466e7f1b566c3
|
|
| BLAKE2b-256 |
1b36e5520bff51cf7b8067df420f5c3511993e21f1bb704344aaf17cded48b4e
|
File details
Details for the file deepfilter_stream-0.1.0-py3-none-any.whl.
File metadata
- Download URL: deepfilter_stream-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34e351a744451dd6fe9ffad4cce67953d5db55c9b5de40d475080a538728ac89
|
|
| MD5 |
05bb8fa8f3fc24a1e7ad6a9c38835e06
|
|
| BLAKE2b-256 |
c0ce0f182aa9bed2b473d398aca8afe0cab352c849f3b4402cd099a9e4a78122
|