Jailson Brito
← All side projects

Tabfier

Transcribes guitar and bass recordings into playable tablature.

BetaSince July 2026
  • React
  • TypeScript
  • TensorFlow.js
  • Web Audio API

Transcribes a guitar or bass recording into playable, editable tablature, entirely in the browser — nothing is uploaded.

The problem

Transcribing your own guitar or bass playing into tab is normally manual, ear-by-ear work, or it means uploading a recording and waiting. Tabfier does it in the browser: record or import audio, get an editable tab out, nothing leaves the device.

The hard part isn’t detecting notes — it’s turning a detected pitch into a specific string and fret. The same note usually has several fingerings, and picking the wrong one produces a tab that’s technically correct and unplayable the way it’s written.

Tabfier's editor, showing a transcribed guitar riff as an editable tab staff, with instrument settings for fold octaves, positional fret assignment, and hand spanTabfier's editor, showing a transcribed guitar riff as an editable tab staff, with instrument settings for fold octaves, positional fret assignment, and hand span

Approach and methodology

Built measured rather than tuned by ear: the project keeps a mechanism doc, a ranked list of known accuracy problems, and a results doc with real F1 scores against real guitar recordings — not just synthetic test audio, which overstates accuracy considerably (see Results).

Fret assignment is treated as an optimisation problem: the constants weighing “prefer a lower hand position” against “prefer fewer position shifts” were fit and cross-validated against real players’ actual fingering choices. Negative results are kept in the docs too — two attempts to close a gap in open-string usage both measurably hurt accuracy and were reverted, recorded rather than deleted.

Built with Claude Code as the coding agent. Every UI element carries a test id specifically so a change can be verified against the real, running app in a browser rather than trusted on faith.

Architecture

Tabfier transcription pipelineAudio is decoded and resampled, then a pretrained pitch-detection model produces raw notes. Everything after that is deterministic — filtering, octave folding, and quantizing to a musical grid — before a dynamic-programming search assigns each note to a string and fret, and the tab is rendered and exported.

Audio input

Decode + resample
(mono, 22.05kHz)

basic-pitch model
(TensorFlow.js, Web Worker)

Filter + fold octaves + quantize
(pure, deterministic)

Fret assignment
(dynamic-programming search)

Render tab as SVG

Export MIDI / MusicXML

Tabfier transcription pipelineAudio is decoded and resampled, then a pretrained pitch-detection model produces raw notes. Everything after that is deterministic — filtering, octave folding, and quantizing to a musical grid — before a dynamic-programming search assigns each note to a string and fret, and the tab is rendered and exported.

Audio input

Decode + resample
(mono, 22.05kHz)

basic-pitch model
(TensorFlow.js, Web Worker)

Filter + fold octaves + quantize
(pure, deterministic)

Fret assignment
(dynamic-programming search)

Render tab as SVG

Export MIDI / MusicXML

One non-deterministic stage (the model), three deterministic stages after it — the codebase is structured around that split.

Nothing leaves the browser: transcription runs entirely client-side, and audio, notes, and edits are all stored locally. The only network request the app makes at all is fetching the model’s own weights from a CDN the first time it runs. Tab is drawn as hand-rolled SVG — no third-party notation engraver — and exports to a hand-written MIDI encoder and MusicXML.

The editor exposes real controls into that pipeline, not just a finished tab to look at: Simplify collapses a chord down to its lowest note; Fold octaves corrects octave-detection errors; Positional turns the hand-position-aware fret search on or off; Hand span sets how many frets that search will stretch across; Confidence and Min length filter out low-confidence or too-short detections before they ever reach the tab. Each one is a direct dial on a step of the pipeline above, not a separate feature bolted on afterward.

Results

The open question going in was how far a general-purpose, off-the-shelf pitch model could get on guitar specifically — an instrument where the same note usually has more than one right answer for where to play it.

Metric Synthetic audio Real audio (GuitarSet)
Overall F1 ~0.95 0.718
Fret-assignment accuracy 54.5% → 68.5% after two fixes
Bass F1 ~0.39 not yet measured

A specific, counterintuitive result is documented rather than glossed over: sustained single notes — bends, vibrato — fragment worse than fast chord strums, the opposite of what “more notes at once should be harder” would predict.

Limitations

  • Explicitly an experimental beta, with known accuracy problems.
  • Bass transcription is the weakest measured area and hasn’t been verified on real bass recordings at all — an open question, not just a rough edge.
  • The recording path has real, un-fixed accuracy costs: no input-level normalisation before the model’s fixed thresholds, and mic recording goes through a lossy codec then back.
  • Manual tempo entry is the default. Automatic detection exists and works from the notes alone, but can’t always tell a tempo from its double or half.
  • The model is several years old, general-purpose, and wasn’t built for guitar — weakest at exactly what guitar does a lot of: the same pitch on more than one string, bends, distortion.

Work in progress

Real-audio bass accuracy — currently a blind spot, not just a weak spot.

Raw audio capture (skipping the lossy codec round-trip) and input-level normalisation are both reasoned through, not yet built. Tap-tempo and audio-based tempo detection are on the list.

A guitar-specific model, or a simpler single-note pitch tracker for solo lines, is being considered as a way past the current model’s ceiling — not decided yet.

The tab renderer itself — drawing and editing a fretted-instrument staff from a plain list of notes — doesn’t depend on anything Tabfier-specific. Worth its own small library if a second use for it ever comes up.