Skip to content

About

Free offline guitar tuner with the largest open song→tuning catalog: 27,800+ songs by 857 artists across 573 tunings and 18 scenes worldwide — including the Russian alt scene no other database covers. Target-constrained pitch detection, physically modelled reference tones. No signup, no ads.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Guitar Tuner

A fast, free guitar tuner that knows what tuning the song is actually in: 27,801 songs across 857 artists and 573 tunings, six to eight strings. Scenes other tuning databases skip are in here song by song — the Russian and Finnish alternative scenes, Japanese visual kei, Taiwanese and Filipino metal, Latin America.

Live → marr59.github.io/guitar-tuner

Pick a song, see the tuning it was recorded in, retune, play. No account, no signup, no paywall, no ads. Installs to your home screen and works with no signal.

Tuner screen: E Standard selected, waveform display, string selector and Manual/Auto switch    Search by Song: Slipknot's Vermilion Pt. 2 shown in B F# B E G# C# with a verified badge


What it does

  • Accurate pitch detection down to low B and F#, reading out in cents
  • Tuning library — 27,801 songs across 857 artists and 573 tunings, searchable offline
  • Alternate tunings only — songs in plain E standard are deliberately not catalogued
  • Multiple readings per song where transcriptions genuinely disagree — 1,314 songs carry an alternate tuning alongside the primary one rather than a chosen winner
  • Experimental tunings preserved — Soundgarden's six-strings-of-E "Mind Riot", Sonic Youth's unison and out-of-order sets, Joni Mitchell's open tunings
  • Russian alt scene — Психея, [AMATORY], Stigmata, Lumen, Jane Air and others, largely undocumented in English-language sources
  • Nordic metal in depth — Stam1na and Mokoma on seven-string A D A D G B E, Turmion Kätilöt, Kalmah, Insomnium, Before the Dawn and the rest of the Finnish catalogue, song by song rather than band by band
  • Real guitar reference tones — tap a string to hear its target pitch, played by a sampled steel-string acoustic and corrected to the exact frequency
  • Auto-advance — tune a string and it moves to the next, in whichever direction you're working
  • Any string count — 4 to 8 strings; the library holds 409 six-string, 130 seven-string and 33 eight-string sets
  • Custom tunings you can build, name, rename and delete
  • A4 calibration from 432 to 444 Hz for old recordings and ensemble playing
  • Three themes, including a warm dark one for stage and dim rooms
  • Offline via service worker, with JSON export/import of your library

Why it exists

Most tuners handle E standard and a handful of drop tunings. The annoying part of playing metal isn't the tuning itself, it's finding out which tuning a song uses, which usually means digging through tab sites and forum threads that contradict each other.

Slipknot's "Vermilion Pt. 2" is the example that started this project. Most published tabs are written in E standard because it reads more easily that way. The record is in Drop B. Trust the tabs and you learn the song in the wrong key.

So the app pairs an accurate tuner with a curated database of alternate tunings, tied to specific songs and albums. Songs that are just plain E standard are left out on purpose: their absence is itself useful information.


Engineering notes

No frameworks, no build step, no backend. One HTML file, one JSON catalogue, a service worker. That constraint was worth keeping: deploying is a git push and it runs on a phone in a rehearsal room with no signal.

Pitch detection is target-constrained

The obvious design — detect whatever note is playing, then work out which string it is — turns out to be the wrong one. In low tunings like Drop B the strings sit close together and are rich in harmonics, so the detector regularly locks onto a neighbouring string or an octave partial.

Instead the player picks the string first. Because the target frequency is then known, the detector only has to answer "how far is this from that note", and it can restrict its period search to ±700 cents around the expected one. Octave errors and neighbour-string confusion stop being possible, rather than being fought with heuristics.

The detector is a YIN-style cumulative difference function with a coarse pass, a fine pass, and parabolic interpolation of the minimum. Measured against synthetic plucked-string signals: better than 0.15 cents across F#1 to E4, including strings detuned by up to 180 cents.

The needle holds instead of guessing

The difference function also yields an aperiodicity figure, which becomes a confidence score. On a cleanly plucked string it sits around 0.98; on a noisy but valid signal 0.82; on room noise 0.10; on silence 0.00.

Below a threshold of 0.55 the reading is discarded and the needle holds its last position rather than darting around. Combined with a median filter over recent readings and an exponential glide rendered at 60fps independently of the analysis rate, that is what makes the display feel calm instead of nervous.

Reference tones are a real guitar, corrected to pitch

Tapping a string plays its target pitch. Three generations of this: a stack of sine partials (sounded like a whistle), then a Karplus-Strong plucked string — a filtered noise burst in a fractional delay line, comb-filtered at the pick position, voiced through a light body EQ, zero bytes of audio assets. That version is still in the code as the offline fallback.

The current voice is a sampled steel-string acoustic (FluidR3 General MIDI soundfont, CC-BY 3.0, 16 notes every three semitones from E1 to D♭5, ~300 KB, cached by the service worker). The nearest sample plays at the exact ratio target/nominal, so timbre never shifts by more than 1.5 semitones. An A/B against the synthesis was not close.

The catch, and it is the same catch as before: a reference tone that is off by a few cents makes you tune your guitar to a lie. A sampled string is not in tune with itself — the attack sits 10–16 cents sharp and the note settles over about two seconds, which is physics, not a defect. So samples/index.json carries each sample's drift track, measured every 25 ms with the app's own detector, and the player cancels it point by point with a playbackRate curve. The result is checked by simulating that playback and measuring it with the same detector (node tools/verify_samples.cjs): across F♯1–C5, including drop tunings, the tone stays within a cent of target for its whole length, attack included.

Auto-advance follows the player

After a string settles in tune, the app waits briefly and moves to the next one. Direction is inferred rather than assumed: starting at the 6th string walks toward the 1st, starting at the 1st walks toward the 6th, and switching strings mid-session re-reads the direction from that move.

The first implementation only advanced if the string stayed inside ±4 cents continuously for the whole delay. A decaying note almost always wobbles out of that band for a moment, which silently cancelled the transition — so it appeared to work once and then never again. The timer now runs independently of the signal and is only abandoned if the reading moves more than 15 cents, i.e. when the player has clearly gone back to the tuning peg.

The catalogue was quietly ASCII-only

Importing the Russian scene surfaced a bug that would have destroyed the data without raising a single error. Deduplication and slug generation both normalised titles with [^a-z0-9] — which, applied to Cyrillic, returns an empty string. Every song by a Russian band would have collapsed onto the same key and the same blank id, silently reducing fifty songs to one.

The fix is Unicode-aware keys (/[^\p{L}\p{N}]/gu) plus transliteration for slugs, with the song id appended when two slugs still collide. But the interesting part is what remained afterwards, because Russian titles vary in ways an English-only importer never has to think about:

  • ё vs е — "Он Не Придет" and "Он не придёт" are the same song, and they arrived with two different tunings
  • script variance — "Осколки"/"Oskolki", "Сид Spears"/"Sid Spears"
  • inconsistent transliteration — "12 Секунд" vs "12 Secund", where a strict transliterator produces sekund and secund

Eight duplicate pairs survived the automated pass and were caught by comparing aggressively-normalised keys with k/c and y/i folded together. Two of the eight disagreed on the tuning, so they became conflict entries rather than being silently merged.

Low is not the same as wrong

The same import produced a batch of unusually low tunings, and the temptation was to treat low as suspect. Some were genuinely broken: an entry whose lowest strings were E1 and A1 — bass guitar range — turned out to be a bass track that slipped past the guitar filter. A title with a transcriber's credit baked into it ("… by Music Master Тула") carried a tuning that was just standard with one string wrong. A Nirvana cover was filed under the covering band's own catalogue.

But [AMATORY]'s six-string Drop G, tuned down to G1 at 49 Hz, is real — five songs, all consistent — and so is Stigmata's seven-string Drop G. The distinguishing signal was not the pitch but the consistency: a real band tuning recurs across songs, while an artefact appears once. This is the same lesson as the unison heuristic above, arriving from the opposite direction.

Data honesty over false precision

Tuning information on the internet contradicts itself constantly, so every catalogue entry carries a confidence level and its sources. high means cross-checked across multiple independent sources and shown with a verified badge in the UI. Entries without that badge are omitted from the display to avoid labelling 99% of the library as unverified noise.

Where sources genuinely disagree, both readings ship as selectable variants instead of one being silently chosen. Metallica's "The Thing That Should Not Be" is transcribed as D standard, as Drop D, and Kirk Hammett has been quoted saying C#. The same mechanism covers songs with legitimately different studio and live tunings, such as Nirvana's "Come As You Are" — D standard on the record, E♭ live.

One further signal is recorded rather than hidden. When every transcription of a band's catalogue reports an identical tuning with no variation at all, that is as likely to mean transcribers copied the value forward as it is to mean the band never retuned. Those entries carry a note saying so. It is a weaker claim than the data appears to make, and saying so is more useful than sounding certain.

Data model

A tuning is an ordered array of scientific-pitch note names, low to high, of any length:

{
  "id": "drop-b",
  "name": "Drop B",
  "strings": ["B1", "F#2", "B2", "E3", "G#3", "C#4"]
}

Nothing in the detector, the UI or the storage layer assumes six strings. Seven- and eight-string guitars, bass and ukulele work without schema changes, and the custom tuning builder already offers 4 through 8. The catalogue exercises this today: the Rolling Stones' "Honky Tonk Women" is genuinely five strings — the five-string Open G Keith Richards gets by removing the sixth.

Songs don't repeat the note array — they reference a tuning by id:

{
  "song": "Vermilion Pt. 2",
  "artist": "Slipknot",
  "t": "drop-b"
}

When sources genuinely disagree, the primary tuning stays in t and the competing readings ride alongside it in alts, with a note recording the conflict instead of silently picking a winner:

{
  "song": "The Thing That Should Not Be",
  "artist": "Metallica",
  "t": "std-d",
  "alts": ["drop-d"],
  "note": "Sources disagree: many transcriptions say D standard, older ones say Drop D, and Kirk Hammett has been quoted saying C#."
}

That normalisation matters at this scale. 27,801 songs reference a shared set of 573 tunings, and roughly half of the original file was repeated boilerplate prose and reconstructible URLs. Collapsing both took the catalogue from 300 KB to 84 KB before the bulk import, and the finished file is 3.6 MB raw but 590 KB gzipped — small enough to ship whole, so search stays instant and the entire library works offline.

Splitting the catalogue into per-artist chunks was considered and rejected: searching for a song requires an index of every title anyway, and chunking would break offline use for anything not already downloaded. Extrapolated, one normalised file holds 27,801 songs in about 590 KB gzipped.

Stack

Audio Web Audio API — AnalyserNode, custom DSP in plain JS
Rendering Canvas 2D, spring-smoothed at 60fps
Offline Service worker, network-first with cache fallback
Storage localStorage, with JSON export/import as a backup path
Data Static tunings.json, 27,801 songs in 590 KB gzipped
Deploy GitHub Pages

Network-first caching is deliberate: a cache-first shell would pin installed users to a stale build. On GitHub Pages there are no cache headers to tune, so bumping the service worker version each deploy is the only lever that matters.

About the data

A tuning is a fact about a recording: which pitch each string is set to. The catalogue collects those facts from publicly available information and records how much each one should be trusted.

  • verified — cross-checked against multiple independent sources, shown with a badge
  • unmarked — commonly reported, but not independently confirmed
  • c — sources genuinely disagree; both readings are kept and the UI says so
  • unusual — the tuning really is strange, deliberately so, and is not a data error

No tab, notation or lyric content is stored or reproduced anywhere in this project — only the tuning itself, which is a measurable property of the recording rather than a creative work.

Errors do exist. Transcriptions get copied forward, bass tracks occasionally masquerade as guitar parts, and a tuning that suits a transcriber's reading may not be the one on the record. Corrections are welcome.

Running locally

git clone https://github.com/marr59/guitar-tuner.git
cd guitar-tuner
python3 -m http.server 8000

Then open http://localhost:8000. Microphone access needs a secure context, so localhost works but a bare LAN IP will not — use HTTPS to test from a phone.

Contributing a tuning

Entries live in tunings.json. Include the strings low to high, the source you checked, and an honest confidence level. If a song is played in plain E standard, it doesn't need an entry.

License

MIT — see LICENSE.

Reference-tone samples in samples/ are rendered from the FluidR3_GM soundfont (acoustic_guitar_steel) via gleitz/midi-js-soundfonts, licensed CC-BY 3.0.

About

Free offline guitar tuner with the largest open song→tuning catalog: 27,800+ songs by 857 artists across 573 tunings and 18 scenes worldwide — including the Russian alt scene no other database covers. Target-constrained pitch detection, physically modelled reference tones. No signup, no ads.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages