A native macOS app that generates Line 6 Helix guitar
presets from a plain-English request — "Metallica Black Album rhythm, tight and
scooped" — and writes a .hlx file the hardware loads directly.
Inference runs locally: Llama 3.1 8B via llama.cpp on Metal. No cloud, no API
key, no subscription.
Status: archived. It worked, it was verified on real hardware, and then I sold the Helix and went back to analog. The code is here as a record of how it was built rather than as something maintained.
An 8B model will confidently tell you a Marshall JCM-800 is the amp for Metallica's "Nothing Else Matters" clean. It is a Roland JC-120, in all 18 Metallica presets a professional built. The model is unreliable at recalling which amp makes a sound and quite good at knowing which artists belong to the same scene — so nearly all of this project is about supplying the first from data and letting the model do the second.
Three generated sources feed the prompt, and none of them is hand-written:
| Source | What it answers |
|---|---|
ModelCatalog.swift |
Which models exist and what parameters each one really has |
FW380.swift |
What Line 6's official FW 3.80 document says exists, per device |
ArtistConventions.swift |
What professionals actually used, per artist and per role |
ArtistConventions is mined from 1,913 real presets: which amp, cab, drive and
EQ each artist's clean, crunch and high-gain tones use. Only aggregate
statistics — counts and medians grouped by label. No preset content is
reproduced anywhere in this repo.
Most of what follows was discovered by measuring the corpus rather than by reasoning about it, usually after the reasoning had been wrong for a while.
A median over a control that does not exist is measuring a constant.
Master came out at 1.0 on every Fender in the corpus. That looked like sampling
bias for a day. It is not: a Fender Deluxe Reverb has no Master knob, so the
device pins it at 100% — and 47 of the 112 amps are in that position. Line 6's
own summary says so in a footnote.
The snapshot controller ID is per device, and inferring it from four files got it wrong on all four. Snapshots are how one preset covers a verse and a solo. Counting 2,452 parameters that genuinely differ between scenes across 891 presets gives Helix Floor 19, LT 19, HX Stomp 9, Stomp XL 12. The value that had been recorded as fact appears twice in the entire corpus. Getting it wrong fails silently in the worst way: the file loads, the snapshots appear with their names, and every one plays the base setting.
A length distribution that stops dead is a hardware limit. Snapshot names cap at 10 characters and preset names at 16. Over the cap the device keeps the preset and discards the name, so it presents as "snapshots work but have no labels" — a symptom that points nowhere near its cause. Both were found by plotting name lengths across the corpus and noticing the cliff.
The example in a prompt sets the shape, including how much to generate. An example showing an amp and a cab produced two-block presets for a tone that is mostly delay and reverb, with ten blocks free. An example whose lead scene dropped the volume produced solos quieter than the rhythm. Both times the prose said the opposite of the example, and the example won.
What you remove from a prompt matters as much as what stays. Trimming a 59-artist table to the 8 relevant ones cut the prompt 42% — and changed the answer, because the measured rows were byte-identical but the company they kept had changed. A thrash request padded with Queen and Pink Floyd returns a crunch tone; padded with Metal and Iron Maiden it returns the mined high-gain row. Two A/B checks against the untrimmed prompt are written into the repo for this reason; they caught three regressions that the test suite did not.
The prompt is advice; the reconciliation layer is the guarantee. Rules the model ignores often enough to matter are enforced in code afterwards — no cab block into a real cabinet, no amp block into an amp's front, no solo quieter than the rhythm it rises out of, no parameter that the chosen model does not have.
Sources/ToneArchitect/
Services/PromptBuilder.swift prompt assembly, per device and rig
Services/LlamaService.swift inference + the reconciliation layer
Services/HelixService.swift .hlx generation
Generated/ committed, never hand-edited
scripts/
mine-conventions.py corpus -> artist/role conventions
gen-fw380.py Line 6's FW 3.80 PDF -> machine-readable
gen-catalog.py HX Edit's catalog -> Swift
claude-compare.py same prompt against a frontier model
MEMORY.md is the working log kept across sessions: what was measured, what was
verified on hardware, and a running list of the traps that cost real time. It is
candid about the mistakes, several of which are mine and several of which are
the model's.
swift build
./make-app.sh release # -> build/ToneArchitect.app
./.build/debug/ToneArchitect --selftestThe generated Swift is committed, so the build needs neither the preset corpus nor HX Edit installed. Regenerating it does — see the header of each script.
No licence granted. Published as a portfolio reference, not for reuse. Line 6, Helix and HX are trademarks of Yamaha Guitar Group. This project is not affiliated with or endorsed by them.