Test tool for the reverse-engineered Fairbuds GATT protocol.
At least subjectively, the expanded EQ capabilities significantly improve the sound compared to what's possible with the app itself, especially in the high end.
Now available as a web app (thanks @zyberspace).
- Set EQ presets (Main, Bass, Flat, Studio)
- More EQ control
- −12 to +13.5 dB per band (vs. app limited ±10 dB)
- Customisable Q-factor (vs. app hardcoded 0.7)
- Load parametric EQ files generated by AutoEQ
- Battery level monitoring
- Interactive CLI with command history
git clone --recurse-submodules https://github.com/user/fairbuds.git
cd fairbudsIf you already cloned without --recurse-submodules:
git submodule update --init --recursiveThis project uses the uv Python package manager. To install it, run:
# Linux/macOS
curl -LsSf https://astral.sh/uv/install.sh | sh
# macOS with brew
brew install uv
# Or with pipx
pipx install uvThen install the dependencies:
uv syncThe BLE address might be different to the audio (BR/EDR) address shown in Bluetooth settings.
# Start BLE scan
uv run fairbuds --scan
# Look for your Fairbuds in the list, e.g.:
# 00:11:22:33:44:55 -96 dBm Fairbuds
# macOS:
# A1F7C2D9-4B8E-9A3F-16D2-7C5B8E0F4A12 ?? dBm Fairbudsuv run fairbuds 00:11:22:33:44:55 # Replace with your Fairbuds BLE addressType help in the interactive CLI for more details on available commands. If you just want to try the best preset, type:
load rtings_treble
uv run fairbuds --help # Show help
uv run fairbuds --version # Show version
uv run fairbuds --scan # Scan and list BLE devices
uv run fairbuds --list-presets # List available AutoEQ presetsAutoEq/– AutoEQ (submodule)pex/– Parametric EQ configs for AutoEQfairbuds.yaml– uses the full EQ capabilitiesfairbuds-app.yaml– equivalent to the official app
presets/– Parametric EQ presetspresets_app/– App-compatible versions of the presetsmeasurements/– Useful Fairbuds response curve measurementssrc/– Source code for this project
Please keep in mind that this project is a quick-and-dirty experiment and most of the Python code was vibe-coded. There is not much point in making it more robust; it served only to test the protocol before attempting Gadgetbridge support.
Don't read too much into the code. The AI reads a bit too much into instructions and is very eager to change them into code with even more helpful comments. But the core implementation (EQ switching, custom EQ's battery info) should be correct.
RTINGS (studio eq, ANC Off).csv contains RTINGS measurement of the “Main” preset on the 5128. This seems to be the best base for experimentation. Use the “JM-1 with Harman filters” target for best results.
The rest are from DHRME on the 711 for use with the “AutoEq in-ear” target. I had mixed results even though they also measured the “Studio” EQ, possibly due to differences in the firmware.
Some of these measurements are from AutoEq's database, the missing ones I preprocessed myself from the raw CSV files.
See comments in each preset. Unfortunately we currently do not have enough data for a definitive preset. My favourite so far is rtings_treble.txt, but its construction is a bit fishy.
It's created by simply adding the gains from main-ish.txt – my by-ear approximation of the “Main” preset – to the EQ generated by AutoEq (see generate.sh), which uses measurements by RTINGS on the “Main” preset.
This is of course speculative at best. main-ish does not match “Main” perfectly and rtings_treble also uses variable Q-factors. But as an approximation it works well enough.
The Q-values in the app are hardcoded to 7.
The actual interpretation is undocumented (if any calculations were present, they were most likely optimised out). This tool assumes the final Q-value is n/10.
This would mean the default is 0.7 with a range of 0.1–25.5, which is reasonable. It would also match the Fairbuds XL's 2023 default value (which is directly visible in the decompiled code).
Changing this value manually seems to affect the sound seemingly linearly, with the full range affecting the sound, and seems to match a software emulation with the same settings. But ultimately, it results in a meaningful improvement to the sound, so for now it's good enough.
It is worth mentioning though that manually calculating the value for the given bands would bring it closer to 1.2.
Follow the setup in the AutoEq README. Then use the parametric equalizer presets in pex/.
cd AutoEq
uv pip install -U -e .
. .venv/bin/activate
python -m autoeq \
--input-file="../measurements/RTINGS (main eq, ANC Off).csv" \
--output-dir="../results" \
--target="targets/JM-1 with Harman filters.csv" \
--max-gain=8 \
--parametric-eq \
--parametric-eq-config=../pex/fairbuds.yaml \
--fs=48000 \
--bass-boost=6.5 \
--preamp=-4For bass boost, I use the default on the AutoEq web app for the given target – 6.5 dB for the JM-1 target and 8 dB for the AutoEq in-ear target.
The max gain and preamp settings significantly affect the output of the optimiser, but are a bit trial and error. I got best results by settings the max gain to make it not clip under 10KHz (8 dB should be enough). Since the range of the EQ is quite limited even with the extended range, this gives the optimiser a better chance to tune the midrange, where hearing is most sensitive.
I then manually tune the preamp to find a value where the optimiser does not misbehave at the lowest or highest points. If not given enough room, it tends to create small spikes to get at least some benefit, which is usually not what we want. If multiple values give usable results, choose as low a preamp as possible to prevent clipping.
This is much less important when generating app-compatible presets, where the Q-values are fixed.
sh generate.sh
sh generate_app.shTBD