# QuietMic

A small **Windows desktop app** that removes background noise from your
microphone in real time — café chatter, keyboard clatter, fans, street noise —
before your voice reaches Zoom / Teams / Meet or any other app.

It captures your mic, runs each 10 ms frame through a neural denoiser, and sends
the cleaned audio to an output device you choose. Point that output at a **virtual
audio cable** and every meeting app hears the denoised signal.

Two denoising engines, switchable live:

| Engine | Model | Best for | Latency |
| ------ | ----- | -------- | ------- |
| **RNNoise** | [`nnnoiseless`](https://crates.io/crates/nnnoiseless) | steady noise (fans, hiss, street); lowest latency | ~10 ms |
| **DeepFilterNet** | [DeepFilterNet3](https://github.com/Rikorose/DeepFilterNet) via pure-Rust `tract` | café *chatter* / non-stationary noise; best quality | ~40 ms |

`QuietMic.exe` is a self-contained native GUI app (~33 MB — it embeds the
DeepFilterNet3 model). It uses only Windows system libraries — copy it anywhere on
Windows 10/11 and double-click. No install, no console window, no runtime download.

---

## Using it

**Launch:** double-click **`QuietMic.exe`** (or run `.\run.ps1`). A window opens:

```
┌──────────────────────────────┐
│           QuietMic           │
│  Real-time noise reducer     │
│                              │
│        ▶  Start              │   ← big Start / Stop button
│         ○ Off                │
│  ──────────────────────────  │
│  Microphone  [ your mic  ▾]  │
│  Output      [ CABLE ...  ▾] │
│  ⟳ Refresh                   │
│  Engine  (•)RNNoise ( )DFN   │   ← switch denoiser live
│  ──────────────────────────  │
│  ☐ Compare — bypass filter   │   ← A/B raw vs denoised
│  Strength  [======●===] 100% │
│                              │
│  Input level  [######....]   │
│  Output level [###.......]   │
└──────────────────────────────┘
```

### Try it (hear the difference)
1. Set **Output** to your **headphones** (using speakers would feed back into the mic).
2. Press **Start**.
3. Talk, tap the desk, let noise in — then tick **“Compare — bypass filter”**
   on and off to hear exactly what QuietMic removes. Switch **Engine** between
   RNNoise and DeepFilterNet to compare them. **Strength** dials the effect from
   subtle to full.

### Use it in real meetings
1. Install [VB-Audio Virtual Cable](https://vb-audio.com/Cable/) (free). It adds
   `CABLE Input` (a playback device) and `CABLE Output` (a recording device).
2. In QuietMic, set **Output** to **`CABLE Input`** and press **Start**.
   (QuietMic auto-selects a CABLE output if it finds one.)
3. In Zoom/Teams/Meet, choose **`CABLE Output`** as your microphone.

Flow: real mic → QuietMic denoises → `CABLE Input` → `CABLE Output` → meeting app.

**Which engine?** For café chatter, **DeepFilterNet** is noticeably cleaner. If you
need the lowest possible latency (e.g. monitoring your own voice live) or you're on
a very weak CPU, use **RNNoise**. Switching restarts the audio automatically.

**Runs in the tray.** Closing the window (X) hides QuietMic to the system tray so it
keeps cleaning your mic in the background — click the tray icon to bring it back, or
right-click it for **Quit**. A global hotkey, **Ctrl + Alt + Q**, toggles bypass from
anywhere — even when the window is hidden or another app has focus (handy mid-meeting).

---

## Building from source

Requires the Rust **GNU** toolchain (`stable-x86_64-pc-windows-gnu`) and the MinGW
paths configured in [`.cargo/config.toml`](.cargo/config.toml).

```powershell
cargo build --release                       # full app (RNNoise + DeepFilterNet)
cargo build --release --no-default-features  # lean RNNoise-only build (~4 MB)
```

- **DeepFilterNet** is vendored under [`vendor/deepfilternet/`](vendor/deepfilternet)
  (from Rikorose/DeepFilterNet @ `d375b2d`), with `crate-type` trimmed to `rlib`
  (upstream's cdylib overflows MinGW's linker export table) and `tract` pinned to
  `=0.21.4` (the exact version it was written against — `^0.21.4` drifts to an
  incompatible API). The DFN3 model is embedded via `include_bytes!`.
- The toolchain paths (`linker`, `-Cdlltool`, and `CC`/`AR` for tract's SIMD
  kernels) are pinned in `.cargo/config.toml`, so a plain `cargo build` works from
  any terminal. If you relocate MinGW-w64, update those paths.
- `quietmic --selftest` loads each engine and processes a frame (a quick sanity check).

## How it works

```
 mic ─▶ WASAPI capture (cpal, f32/48kHz) ─▶ downmix to mono ─▶ input ring buffer
                                                                     │
                                        denoise worker thread ◀──────┘
                                        480-sample frames → RNNoise | DeepFilterNet
                                        (+ bypass / wet-dry mix)
                                                                     │
                                            output ring buffer ◀─────┘
                                                     │
                                   WASAPI playback (cpal) ─▶ chosen output device
```

Denoising runs on a **dedicated worker thread**, never in the cpal callbacks — both
because DeepFilterNet's `tract` runtime is single-thread-bound and because heavy
inference must never block real-time audio. The callbacks only touch lock-free ring
buffers; the UI communicates through lock-free atomics, so controls and meters never
stutter the audio.

GUI is [egui/eframe](https://github.com/emilk/egui) (glow/OpenGL). Source:
[`src/main.rs`](src/main.rs) (GUI) · [`src/audio.rs`](src/audio.rs) (engine).
Third-party licenses: [`THIRD-PARTY-LICENSES.md`](THIRD-PARTY-LICENSES.md).

## Known limitations / roadmap

- **Clock drift** between the mic and output clocks is compensated by a linear
  resampler with a control loop on the output-ring fill (holds it at its setpoint,
  so no accumulating under/overrun). Correction is a sub-1% ratio nudge — an
  inaudible pitch shift for speech.
- DeepFilterNet adds ~40 ms latency (2-frame lookahead). A `default-model-ll`
  low-latency DFN3 variant exists (~0 lookahead) at a larger model size — a possible
  future option.
- The global hotkey (Ctrl+Alt+Q) is fixed; making it user-configurable is a nice-to-have.
- Before building your own, check whether your meeting app's built-in noise
  suppression (or NVIDIA Broadcast, if you have an NVIDIA GPU) already suffices.
