Skip to content

feat(audio): add post-processing noise reduction with RNNoise#374

Open
mehmetnadir wants to merge 1 commit intosiddharthvaddem:mainfrom
mehmetnadir:feat/audio-noise-reduction
Open

feat(audio): add post-processing noise reduction with RNNoise#374
mehmetnadir wants to merge 1 commit intosiddharthvaddem:mainfrom
mehmetnadir:feat/audio-noise-reduction

Conversation

@mehmetnadir
Copy link
Copy Markdown
Contributor

@mehmetnadir mehmetnadir commented Apr 7, 2026

Summary

  • Add AI-powered noise reduction for video playback in the editor using RNNoise (neural network, 5.5K+ stars) via WebAssembly
  • Post-processing approach: raw audio preserved during recording, noise reduction applied in editor — users can toggle on/off and adjust levels in real-time
  • Three configurable levels (Light / Moderate / Aggressive) with distinct filter chains:
    • 2-stage highpass + lowpass filters for steep frequency rolloff
    • RNNoise neural network for intelligent noise suppression
    • Noise gate to suppress residual noise below threshold
    • DynamicsCompressor for volume normalization
  • New "Audio" section in Settings panel with toggle + level selector
  • Smooth transitions when changing levels — no audio interruption
  • Fix: use "floating" alwaysOnTop level for HUD/source selector so macOS permission dialogs appear above the app
  • i18n: noise reduction labels added for en, es, zh-CN

New dependency

@sapphi-red/web-noise-suppressor — MIT license, ~674KB, zero dependencies

Test plan

  • Record a video with microphone audio (include background noise: fan, keyboard, desk taps)
  • Open in editor → Settings → Audio → Enable Noise Reduction
  • Play video and verify noise is reduced
  • Switch between Light / Moderate / Aggressive — verify audible difference
  • Toggle off → verify original audio returns
  • Change levels during playback — verify video does not pause or glitch
  • Verify macOS permission dialog appears above HUD overlay
  • Run npm run i18n:check — all locales should pass

🤖 Generated with Claude Code

Add AI-powered noise reduction that can be applied during video playback
in the editor. Uses RNNoise (xiph.org neural network) via WebAssembly for
real-time audio processing with three configurable levels.

Features:
- Post-processing approach: raw audio is preserved during recording,
  noise reduction is applied in the editor during playback
- Three levels: Light, Moderate, Aggressive with distinct filter chains
- 2-stage highpass + lowpass filters for steep frequency rolloff
- RNNoise neural network for intelligent noise suppression
- Noise gate to suppress residual noise below threshold
- DynamicsCompressor for volume normalization
- Settings panel toggle and level selector in editor
- Smooth transitions when changing levels (no audio interruption)
- Fix: use "floating" alwaysOnTop level for HUD/source selector
  so macOS permission dialogs appear above the app
- i18n: noise reduction labels in en, es, zh-CN

New dependency: @sapphi-red/web-noise-suppressor (MIT, ~674KB)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f12bcf5172

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +69 to +72
if (workletRegistered) return;

await audioContext.audioWorklet.addModule(rnnoiseWorkletPath);
workletRegistered = true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Register RNNoise worklet per AudioContext

registerRnnoiseWorklet is guarded by a single global workletRegistered flag, but AudioWorklet registrations are scoped to each AudioContext. After useAudioEnhancement closes a context and a new one is created (e.g., reopening/remounting editor playback), this guard skips addModule, so new RnnoiseWorkletNode(...) fails and the code falls back to the non-RNNoise path, silently disabling the AI denoiser for subsequent sessions.

Useful? React with 👍 / 👎.

Comment on lines +214 to +216
destroy: () => {
gate.destroy();
rnnoiseNode?.destroy();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Disconnect enhancement graph during teardown

destroy() only stops the gate loop and RNNoise node, but never disconnects the filter/compressor nodes that were connected to ctx.destination. Because useAudioEnhancement rebuilds the chain on toggles/level changes, old chains remain attached in the audio graph, which can accumulate nodes over time and increase memory/CPU usage in long editing sessions.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant