Real-time AI voice changer web application.
Route a microphone through ONNX or RVC models with a low-latency WebSocket audio pipeline.
Quick Start • Model Support • API • Configuration • 한국어 • 日本語
- Real-time voice conversion with binary WebSocket streaming and AudioWorklet
- ONNX and RVC model support, plus a model-free DSP mode (pitch shifting and effects with no checkpoint loaded)
- Live pitch and formant shifting, F0 method selection (PM / Harvest / Crepe / RMVPE / FCPE), and RVC advanced controls (index rate, RMS mix, protect)
- 12-effect server-side DSP rack: noise gate, robot, whisper, telephone, distortion, bitcrush, chorus, echo, reverb, tone EQ, compressor, output gain — all streaming-safe with per-connection state
- 16 built-in voice presets (Chipmunk, Deep Voice, Robot, Ghost, Telephone, Stadium, …) plus custom presets that save the complete Voice Lab state
- Silence Saver pauses expensive model inference after quiet input while keeping DSP tails alive, then resumes on the first audible chunk
- Measured performance profiles (Responsive / Balanced / Stable) recommend a chunk size from recent p95 round-trip and server processing time
- Real-time spectrum visualizer, VU meters with peak hold, latency sparkline, server timing breakdown (model / DSP / network), and live inference duty monitoring
- Output recorder — capture the converted voice and download it as WAV
- Upload a whole audio file (wav / mp3 / flac / ogg / m4a) and render it through the active model + current Voice Lab settings + effect chain to a downloadable WAV
- Drag-and-drop model upload (
.pth/.pt/.onnx+ companion.indexfiles), one active model at a time - Model metadata badges: RVC version, target sample rate, F0 support, index presence, device
- Session settings for light/dark theme, transport profiles, Silence Saver, and ONNX / PyTorch / GPU / CUDA runtime visibility
- Consistent Lucide controls with keyboard-visible focus states, plus an explicit GitHub Star action with a normal repository-link fallback
The realtime workspace: live spectrum, device routing, output recorder, VU meters with a model / DSP / network latency breakdown, and pitch, formant, and F0 method controls.
16 one-click voice presets and the 12-effect server-side DSP chain. Custom presets also remember F0, retrieval, filter, RMS, and protect controls. Everything here works with or without a voice model — enable an effect and it applies to the live stream instantly.
Drag-and-drop upload for RVC / ONNX checkpoints and companion .index files, with metadata
badges and one-click activation.
Render whole audio files through the active model and effect chain, then download the result as WAV. RVC renders process the complete file and honor the current Index Rate, Filter Radius, RMS Mix, and Protect values rather than using the realtime stream's short context window.
Light/dark theme, transport profiles, a measured recommendation, Silence Saver controls, and a live view of what the backend sees: ONNX provider, PyTorch device, GPU, and CUDA.
The commands below assume Windows PowerShell in the repository root.
git clone https://github.com/sioaeko/OpenVoiceChanger.git
cd OpenVoiceChangerpython -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r backend/requirements.txt
pip install --no-deps git+https://github.com/RVC-Project/Retrieval-based-Voice-ConversionCPU ONNX works with the default requirements. If you want ONNX to use CUDA locally, replace the CPU package with the GPU package:
pip uninstall -y onnxruntime
pip install onnxruntime-gpu==1.23.2cd frontend
npm install
npm run build
cd ..RVC .pth / .pt models need a HuBERT content encoder file.
New-Item -ItemType Directory -Force models\assets | Out-NullPlace the file here:
models/assets/hubert_base.pt
You can override that path with OVC_HUBERT_PATH.
.venv\Scripts\python.exe -m uvicorn backend.main:app --host 127.0.0.1 --port 8000Open:
http://127.0.0.1:8000
Terminal 1:
.venv\Scripts\python.exe -m uvicorn backend.main:app --reload --host 127.0.0.1 --port 8000Terminal 2:
cd frontend
npm run devThen open http://127.0.0.1:5173.
| Format | Engine | Notes |
|---|---|---|
.onnx |
ONNX Runtime | CPU by default, CUDA if onnxruntime-gpu is installed |
.pth / .pt |
PyTorch | RVC v1/v2 models, requires hubert_base.pt |
- Open the app in your browser.
- (Optional) Upload and activate a model in the
Modelstab — without one, the studio runs in pure DSP mode. - Open Settings to choose a performance profile and tune Silence Saver if needed.
- Pick your input and output devices in the
Studiotab. - Click
Start Voice Changer. - Shape the voice live: pitch, formant, F0 method, effect rack, or a one-click preset.
- Press B (or the
A/B Monitortoggle) to compare the converted voice against your raw input without stopping the stream. - Record the output, or render whole files in the
Convertertab.
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/api/config |
Stream defaults, Silence Saver defaults, ONNX runtime info, PyTorch runtime info |
GET |
/api/github/star |
Check the active GitHub CLI account's star state |
POST |
/api/github/star |
Star this repository after an explicit same-device browser action |
GET |
/api/models/ |
List uploaded models |
POST |
/api/models/upload |
Upload a model file |
DELETE |
/api/models/{name} |
Delete a model |
POST |
/api/models/{name}/activate |
Activate a model |
POST |
/api/models/deactivate |
Deactivate the current model |
GET |
/api/models/active |
Get the active model |
GET |
/api/presets/ |
List built-in and user voice presets |
POST |
/api/presets/ |
Save a user preset |
DELETE |
/api/presets/{id} |
Delete a user preset |
POST |
/api/convert/ |
Offline file conversion (multipart upload → WAV) |
WS |
/ws/audio |
Real-time audio streaming |
Interactive docs are available at /docs while the backend is running.
- Connect to
/ws/audio. Browser clients must connect from an allowed origin (see Network access); non-browser clients send noOriginheader and are accepted. - Send JSON config:
{"sample_rate": 48000, "chunk_size": 4096}. Send the rate yourAudioContextactually runs at (audioContext.sampleRate), not the rate you requested — the browser is free to ignore the request, and the server processes and resamples using whatever you report here. - Send binary audio frames:
[uint32 seq_num][uint32 reserved][float32[] PCM samples] - Receive processed audio frames in the same format — the response
reservedfield carries the server processing time in hundredths of a millisecond - Send settings updates such as
{"pitch_shift": 3.0, "formant_shift": -2.0, "f0_method": "rmvpe", "filter_radius": 3, "silence_saver": true, "silence_threshold_db": -52, "effects": {"reverb": {"enabled": true, "size": 0.6, "mix": 0.4}}} - Receive periodic status JSON:
{"type": "status", "latency_ms": …, "model_ms": …, "dsp_ms": …, "mode": "rvc|onnx|dsp|bypass", "bypass": false, "inference_sleeping": false, "inference_duty_percent": 100.0, "effects_active": …}
All settings fields are optional and unknown fields are ignored, so older and newer clients interoperate with either side of this release.
{"bypass": true} returns the input signal untouched: no noise gate, no model,
no pitch or formant shift, no effect rack. The microphone, the WebSocket and the
output routing all keep running, so it is a true A/B against the converted
signal rather than a stop. Press B in the UI to toggle it.
This is deliberately different from the effect rack's Bypass all button, which only clears the effects and leaves model conversion running.
Bypass is not persisted between sessions, and no artificial delay is added to match converted-path latency — the architecture has no timing primitive that would make such compensation reliable, so the raw path is simply faster.
The Settings modal maps Responsive, Balanced, and Stable to 2048, 4096, and 8192-sample chunks. After at least eight live samples, the UI uses the recent p95 round-trip latency and model + DSP processing time to recommend the smallest profile with processing headroom. A profile selected while routing is queued for the next session; manual sample-rate and chunk-size fields remain locked until routing stops.
Silence Saver is enabled by default at -52 dB and can be tuned from -80 to
-20 dB. When a model is active and input stays below the threshold for 180 ms,
the server releases that stream's model context and skips inference. It still
runs the post-effect stage with silence so echo and reverb tails decay normally,
then wakes on the first audible chunk. The monitor exposes the current Saver
state and the percentage of model-eligible frames that actually ran inference as
Duty. DSP-only mode is never put to sleep.
The header control performs one transparent action for this fixed repository.
From a loopback browser, an explicit click can use the active, authenticated
GitHub CLI (gh) account to star sioaeko/OpenVoiceChanger; the credential never
enters the frontend. If gh is missing, unauthenticated, unreachable, or the UI
is opened from another device, the control becomes a normal link to the GitHub
repository so the user can decide there.
Environment variables use the OVC_ prefix.
| Variable | Default | Description |
|---|---|---|
OVC_MODELS_DIR |
models |
Model directory |
OVC_HOST |
127.0.0.1 |
Backend bind address — loopback only by default |
OVC_PORT |
8000 |
Backend port |
OVC_SAMPLE_RATE |
40000 |
Sample rate suggested to the client (the browser reports the rate it actually uses) |
OVC_CHUNK_SIZE |
4096 |
Default chunk size |
OVC_CORS_ORIGINS |
["http://localhost:5173", "http://127.0.0.1:5173", "http://localhost:8000", "http://127.0.0.1:8000"] |
Cross-origin allowlist for HTTP and the audio WebSocket |
OVC_ALLOW_ANY_ORIGIN |
false |
Disable origin checks entirely (trusted networks only) |
OVC_LOG_LEVEL |
info |
Log level |
OVC_HUBERT_PATH |
models/assets/hubert_base.pt |
HuBERT path for RVC |
OVC_RMVPE_ROOT |
models/assets/rmvpe |
Optional RMVPE assets directory |
OVC_RVC_STREAM_CONTEXT_SECONDS |
0.14 |
Rolling 16 kHz history each stream re-runs inference over |
OVC_RVC_INDEX_RATE |
0.75 |
Retrieval mix when a matching .index exists |
OVC_RVC_FILTER_RADIUS |
3 |
Harvest median filter radius (values below 3 disable smoothing) |
OVC_RVC_RMS_MIX_RATE |
0.25 |
RMS envelope blend |
OVC_RVC_PROTECT |
0.33 |
Consonant protection |
OVC_RVC_ALLOW_UNSAFE_CHECKPOINTS |
false |
Permit unpickling checkpoints that fail safe loading (see Security) |
OVC_PRESETS_PATH |
data/presets.json |
User preset storage file |
OVC_MAX_CONVERT_SECONDS |
600 |
Max audio length for offline conversion |
OVC_RVC_STREAM_CONTEXT_SECONDS is a latency/quality trade-off, not a buffer
size: every chunk is inferred against this entire window, so raising it improves
continuity but multiplies per-chunk inference cost. 0.14 keeps realtime
headroom at the default 4096-sample chunk.
The studio can upload and execute model checkpoints and open your microphone, so the defaults assume a single-user machine.
- Bind address.
OVC_HOSTdefaults to127.0.0.1; nothing outside the machine can reach the API unless you change it. - Origins. Cross-origin HTTP requests and WebSocket handshakes are checked
against
OVC_CORS_ORIGINS. Requests carrying noOriginheader (curl, native clients, tests) are allowed; the opaquenullorigin is rejected. - Same-origin is always allowed. A page served by this backend passes the check on any address, so the frontend keeps working when you move it to a LAN host without touching the allowlist. A hostile third-party page cannot satisfy it, because the browser sends that page's own origin.
The WebSocket needs this check because browsers do not apply the same-origin policy to WebSocket connections — without it, any website you visited could open your microphone stream through this backend.
To use the studio from another device on your network:
OVC_HOST=0.0.0.0 python -m uvicorn backend.main:app --host 0.0.0.0 --port 8000Serving the built frontend from that same backend needs no further configuration. Only if you run the Vite dev server on a different host must you add its origin:
export OVC_CORS_ORIGINS='["http://192.168.1.50:5173"]'Note that browsers only expose microphone capture on secure origins: over plain
HTTP, getUserMedia is unavailable on anything except localhost. Reach a LAN
deployment over HTTPS, or use it from the host machine.
RVC .pth files are Python pickles, so loading one with PyTorch's legacy
weights_only=False executes whatever code the file's author put in it. Since
checkpoints arrive through the web upload endpoint, the backend loads them in
PyTorch's safe weights-only mode (extended with data-only numpy symbols so
checkpoints storing numpy values still load).
If a checkpoint genuinely cannot be loaded that way, activation fails with an explanatory error instead of silently unpickling it. To load such a file you must opt in per-deployment, and only for a checkpoint you trust:
OVC_RVC_ALLOW_UNSAFE_CHECKPOINTS=true python -m uvicorn backend.main:appThe backend logs a warning naming the file each time that path is taken.
pip install -r backend/requirements-test.txt
python -m pytest # backend
cd frontend && npm install
npm test # frontend
npm run buildbackend/requirements-test.txt is intentionally lighter than
backend/requirements.txt — the tests cover the transport, DSP chain, origin
validation and checkpoint loading, none of which need the full RVC inference
stack. CI runs both suites plus the frontend build (.github/workflows/ci.yml).
OpenVoiceChanger/
├── backend/
│ ├── main.py
│ ├── config.py
│ ├── security.py
│ ├── routers/
│ └── services/
├── frontend/
│ ├── public/
│ └── src/
├── tests/
├── models/
├── .github/workflows/
├── README.md
├── README_KR.md
├── README_JP.md
└── Makefile
The included Makefile is a convenience for POSIX shells or WSL.
| Command | Description |
|---|---|
make install |
Install backend and frontend dependencies |
make install-test |
Install backend test dependencies |
make dev |
Run backend and frontend dev servers |
make dev-backend |
Run backend only |
make dev-frontend |
Run frontend only |
make test |
Run backend and frontend tests |
make test-backend |
Run backend tests only |
make test-frontend |
Run frontend tests only |
make build |
Build the frontend |
make clean |
Remove build artifacts |
- Python 3.10+
- Node.js 18+
- npm




