An always-on-top overlay that transcribes speech and shows the translation in the corner of the screen. Written for Counter-Strike 2 voice chat but it does not know or care what game is running.
Speech recognition runs locally with faster-whisper. Nothing about the audio leaves the machine unless you use the Google translation backend, which only ever sees the transcribed text.
Push-to-translate (the default). Press F, say something in Turkish, press
F again. The overlay shows it in English and Russian so you can paste it into
text chat or just read it out. It is a toggle, not a hold, which sounds wrong
until you try to hold a key down and talk while also playing.
Listen mode. Set PUSH_TO_TRANSLATE_ENABLED=false and it captures system
audio through WASAPI loopback instead, segments it, and translates whatever your
teammates are saying into Turkish. This one is more experimental. It works, but
game audio and voice chat come down the same loopback stream, so gunfire ends up
in the recogniser too.
Audio arrives as 16 kHz mono float blocks of 100 ms. An energy VAD accumulates them: RMS above the threshold means speech, and a segment is emitted once there has been 300 ms of trailing silence and the segment is at least 350 ms long, or once it hits the 3 second cap. That segment goes to whisper, the text goes to deep-translator, and the result is pushed to the Qt overlay through a signal.
The VAD is deliberately dumb. A neural VAD is more accurate but adds latency to
every block, and at 100 ms blocks the RMS check is essentially free. If it
misses quiet speech, drop VAD_ENERGY_THRESHOLD. If a noisy room keeps
triggering it, raise it. 0.015 is a reasonable starting point.
condition_on_previous_text=False on the whisper call matters more than it
looks. With it on, whisper carries context between segments and starts
hallucinating continuations during silence.
No kernel driver, no DLL injection, no reading or writing game memory, no touching game files. It opens an audio device and draws a window. That is the whole footprint.
The overlay is a separate top-most click-through window, so the game has to run in borderless or windowed fullscreen for it to be visible. Exclusive fullscreen will cover it.
Game and platform terms of service still apply to you, not to me.
setup.batCreates a venv, installs the package with pip install -e . and copies
.env.example to .env. There is also python launcher.py if you would rather
click through a GUI installer.
Then:
run.batFirst run downloads the whisper weights, about 75 MB for base. On CPU,
base with int8 keeps up fine. small is noticeably better on accented
speech and roughly twice as slow. medium and up want a GPU.
Everything lives in .env, parsed by config.py. The knobs you will actually
touch:
| Variable | Default | Notes |
|---|---|---|
STT_MODEL_SIZE |
base |
tiny, base, small, medium, large-v3 |
STT_DEVICE |
cpu |
cuda if you have the CUDA runtime |
STT_COMPUTE_TYPE |
int8 |
float16 on GPU |
PUSH_TO_TRANSLATE_HOTKEY |
f |
single char or a pynput key name |
PUSH_TO_TRANSLATE_OUTPUT_LANGUAGE |
ru |
second output language |
VAD_ENERGY_THRESHOLD |
0.015 |
see above |
OVERLAY_X / OVERLAY_Y |
16 |
top-left corner in pixels |
TRANSLATOR_PROVIDER |
google |
or libretranslate with a URL |
Point LIBRETRANSLATE_URL at your own instance if you do not want text going to
Google.
src/cs2_voice_translator/
audio_capture.py WASAPI loopback via soundcard
mic_capture.py microphone, used by push-to-translate
vad.py energy segmenter
stt.py faster-whisper wrapper
translator.py deep-translator / LibreTranslate
overlay.py PySide6 top-most window
app.py listen mode worker
push_to_translate.py hotkey mode worker
config.py .env parsing
main.py wiring
Windows 10/11, Python 3.10+. A microphone for push-to-translate, any output device for listen mode.
MIT, see LICENSE.