HapticSync is a small Windows Python script that turns audio volume into vibration on an XInput-compatible controller. It measures the audio's root mean square (RMS) level and sends the same vibration strength to both controller motors.
- Windows with
xinput1_4.dllorxinput1_3.dllavailable. - Python 3 with pip.
- An XInput-compatible controller with vibration support, connected as controller index
0. - An audio input accessible through SoundCard, ideally a loopback input for your playback device.
- The Python packages
soundcardandnumpy.
The script uses Windows XInput through ctypes.windll, so it does not run unchanged on macOS or Linux.
Clone this repository, or download and extract it from GitHub. If you use Git:
git clone https://github.com/aaka3h/HapticSync.git
cd HapticSyncIn PowerShell, from the project folder, create a virtual environment and install the dependencies:
py -m venv .venv
.\.venv\Scripts\python.exe -m pip install soundcard numpyIf the py launcher is unavailable, use python -m venv .venv instead.
-
Connect your controller and choose the Windows playback device you want to monitor.
-
Start the script:
.\.venv\Scripts\python.exe HapticSync.py -
Check the printed
Targeting SpeakerandListening todevice names, then play audio. -
Press Ctrl+C to stop. The script sends a zero-vibration command when interrupted inside its recording loop.
The script searches for a loopback input whose name contains the default speaker's name. If it cannot find a match, it uses the first input returned by SoundCard. That fallback may be a microphone rather than a loopback input, so check the Listening to line before relying on the result.
The current settings are in HapticSync.py; there are no command-line options.
| Setting | Current value | Effect |
|---|---|---|
| Sample rate | 44100 Hz |
Requested recording rate |
| Frames per read | 512 |
Number of audio frames processed per iteration |
multiplier |
600000 |
Scales RMS audio level into motor strength |
| Noise cutoff | 3000 |
Scaled motor values below this become zero |
| Maximum motor value | 65535 |
Caps the vibration command |
| Controller index | 0 |
Chooses the first XInput controller slot |
Increase multiplier for stronger vibration or decrease it for weaker vibration. This responds to overall audio level; it does not isolate bass, detect beats, or control the two motors independently.
- No vibration: Confirm the controller supports XInput vibration and occupies index
0. The script does not check XInput return codes, so a missing controller may produce no error. - Wrong sound triggers vibration: Check the selected input name. The fallback can select a microphone; review
get_loopback()if you need a specific input. - No input found: Check that Windows exposes your playback device and an appropriate recording or loopback input.
- XInput DLL error: The script tries
xinput1_4first and thenxinput1_3; one must be available on your Windows installation. - Recording error: Check the selected audio device and whether it accepts the requested sample rate.