Remove voices from videos locally on your Mac while preserving the original video stream.
100% local processing. Your video and audio stay on your Mac. The app does not upload media to a cloud processing service.
Internet access is only needed during installation/update and when the Demucs model must be downloaded.
So don't expect quality code here.
Open Terminal in this project folder and run:
./setup.sh && ./start.shThat's it. The first command installs and verifies everything. If setup succeeds, the second command immediately starts Local Voice Remover.
setup.sh automatically handles:
- Apple Command Line Tools check
- Homebrew installation if needed
- nvm
- the project's tested Node.js version
- the project's pinned pnpm version
- FFmpeg and ffprobe
- uv
- the project's pinned Python runtime
- the repository-local Python environment
- NumPy
- PyTorch
- Demucs
- JavaScript dependencies
- final environment verification
You do not need to install Demucs globally, activate Python manually, run pnpm setup, or configure Node by hand.
If macOS says the scripts are not executable after downloading/unzipping:
chmod +x setup.sh start.sh
./setup.sh && ./start.shThe full setup only needs to be run the first time.
After that, whenever you want to use Local Voice Remover, open Terminal in the project folder and run:
./start.shstart.sh loads the project's Node environment, verifies the local processing stack, and starts both the UI and local API.
Open the local URL shown in Terminal, normally:
http://localhost:5173
If that port is occupied, Vite may use the next available port.
Run the installer again:
./setup.shThe setup script is designed to be rerun. It repairs/checks the local toolchain and dependencies, then runs the environment verification.
After it completes:
./start.shUses the Foreground Voice Range control to remove the more prominent portion of the separated vocal signal while retaining quieter vocal material where possible.
The threshold adapts to each recording's vocal levels. Once a prominent phrase is detected, suppression includes its onset, quiet syllables, brief pauses, and tail so parts of nearby speech do not leak back in. The processed timeline measures the vocal audio retained in the mix using the original timeline's scale.
The slider starts at 75%, the suggested starting point for voices that are very loud or close to the camera. Adjust up if the voice you want to remove remains, or down if voices you want to keep are being removed.
Your last dial setting is remembered in this browser. The selected range stays visible in the applied settings summary during processing and on the finished result.
The processed timeline defaults to the remaining detected voice waveform at the same scale as the original. Switch to Removed voice to see the difference, or enable Overlay original for a faint outline comparison. The colored strip below the waveform marks removed intervals; it does not represent voice still present. Region counts refer to audio above the detection threshold, so quiet residual voice can still exist when the count is zero.
The control estimates voice prominence, not literal physical distance from the camera. A single mixed microphone recording cannot reliably determine that a speaker is a specific number of feet away.
Uses the full Demucs no_vocals stem to remove detected vocal content as aggressively as possible.
Both modes also reduce little camera handling clicks by repairing short audio impulses from neighboring samples. This targets brief clicks while preserving continuous high-pitched sounds.
Turn Wind detection & removal to On before processing to look for sustained, irregular low-frequency energy typical of microphone wind noise. Click anywhere on the wind settings card to toggle it; its switch and On/Off label show the selected state. When detected, the app reduces the band below 180 Hz in those sections and reports how much likely rumble it found. The option is off by default.
This is a heuristic and can also identify other rumble. It reduces wind noise rather than guaranteeing full removal, and cannot recover audio obscured by severe wind or microphone distortion. Knowles' microphone wind noise note explains why low-frequency filtering can help and the tradeoff in audio bandwidth.
The video stream is copied instead of re-encoded where the output container supports it. This preserves the source video codec, resolution, frame rate, HDR/color information, and encoded video quality.
Audio is processed separately.
The app also creates a smaller H.264/AAC preview of the original video for browser playback. If the browser stalls on a large or unsupported MOV, it switches to that preview when ready. The final download still uses the original video stream.
For MOV input, the app keeps MOV output and uses lossless PCM audio. Other supported containers use an appropriate audio codec for that container.
Videos, uploaded source copies, and processing files are stored in the current user's Downloads folder. Finished videos are saved automatically to:
~/Downloads/chatter-cut/processed-videos/
The app resolves your own home directory and creates this folder if needed; no username is hardcoded. Finished videos keep the source name with a job ID prefix and a -no-voice suffix. The Download button is also available in the app; your browser controls where that additional copy is saved.
Videos created before this change remain in .local-voice-remover/outputs/, and their existing playback and download links continue to work. New finished videos are saved to ~/Downloads/chatter-cut/processed-videos/.
Restart the app after updating so the server uses the new save location.
Large videos can require substantial temporary disk space because the app creates uncompressed audio and AI separation files.
Before AI separation, the app estimates the required working space and checks available disk space for both temporary files and the finished video.
Uploaded source copies and temporary audio/AI processing files are stored in subfolders of the same Downloads folder:
~/Downloads/chatter-cut/uploads/
~/Downloads/chatter-cut/work/
~/Downloads/chatter-cut/previews/
Uploaded source copies are deleted after processing and preview creation finish. Processing files remain in work/, and browser previews remain in previews/. New jobs do not create files in .local-voice-remover/ inside the project.
If you run out of disk space, delete finished videos you no longer need from ~/Downloads/chatter-cut/processed-videos/. The app does not automatically delete them. You can also delete temporary files in ~/Downloads/chatter-cut/work/ when no videos are being processed.
Normally you do not need to run this manually because setup.sh and start.sh handle it.
For troubleshooting:
pnpm doctorIt checks:
Node
pnpm
FFmpeg
ffprobe
uv
Python
NumPy
PyTorch
Demucs
The server uses the repository-owned AI environment through:
uv run demucsIt does not use an arbitrary globally installed Demucs.
AI/audio applications are more reliable when the complete toolchain is tested together.
This project therefore controls its runtime instead of automatically using whatever happens to be newest on the Mac:
.nvmrccontrols the Node major version.package.jsoncontrols pnpm compatibility..python-versioncontrols Python.pyproject.tomlcontrols the Python AI dependencies.pnpm-lock.yamlcontrols JavaScript dependency resolution when present.uv.lockcontrols Python dependency resolution when present.
This avoids a system Python, global Demucs installation, or unrelated package update silently changing the processing environment.
Every push to main runs the tests and production build, then publishes a GitHub release with a vMAJOR.MINOR.PATCH tag and notes listing the pushed changes. The badge at the top of this README shows the latest published version and links to its release.
The first release uses the initial version in package.json (1.1.0). After that, Git tags are the source of truth for application release versions; the private package version remains the initial baseline.
| Commit message | Version change | Example |
|---|---|---|
feat: ... or feat(scope): ... |
Minor | v1.1.0 → v1.2.0 |
feat!: ..., fix(scope)!: ..., or a BREAKING CHANGE: footer |
Major | v1.2.0 → v2.0.0 |
| All other changes, including fixes and documentation | Patch | v1.1.0 → v1.1.1 |
When a push contains several commits, the largest required bump wins. Feature branches do not publish releases until their changes reach main. Releases are queued to avoid conflicting version numbers. Rerunning a completed release workflow reuses its existing tag.
Run pnpm release:version to preview the next release tag without publishing. If a release fails, fix the failing test/build or rerun the Release workflow in GitHub Actions. Publishing uses GitHub's built-in token; no extra release secret is required.
Complete Apple's installer and then run:
./setup.shagain.
Run:
./setup.shDo not start by globally reinstalling Demucs or PyTorch.
Repair the project-owned Python environment:
rm -rf .venv
./setup.shchmod +x setup.sh start.shThen:
./setup.shnode -v
pnpm -v
ffmpeg -version
ffprobe -version
uv --version
uv run python --version
uv run python -c 'import numpy, torch, demucs; print("AI imports OK")'
uv run demucs --help
pnpm doctorFirst time:
./setup.sh && ./start.shEvery time after that:
./start.sh