The one idea that makes it all work: you can’t delete a concept by deleting the pieces that contain it. A dominant seventh appears in 1,272 of MAESTRO’s 1,276 pieces, so filtering would delete the corpus.
Instead, transform, don’t filter: edit the concept out note by note and keep every piece, changing only the one thing under study. A detector — hand-validated by ear before it’s ever trusted — does the surgery, and the same detector scores the result. Its biases sit symmetrically on both sides of the model, and after three rounds of blind ear-checks, they’re known.
The pipeline, stage by stage
MIDI corpus → the detector labels windows → a transform writes an edited MIDI mirror (control is the corpus as-is) → REMI tokens → a from-scratch GPT → three consumers: a sampler, a likelihood probe, and an ONNX export for the browser. Crucially, the detector also scores the sampler’s output, closing the loop.
What a piece looks like to the model
Four tokens per note — pitch, velocity, duration — with a bar token at each bar line and a position token for where in the bar it falls. No tempo or time-signature tokens. Vocabulary 268 for the tonal models, 271 for the multi-instrument one. The whole idea of reconstructing one instrument from another rests on the ordering within each beat: guitar, then bass, then drums.
The cloud bit
RunPod as a bare machine — no serverless, no notebooks. Create a pod, copy code and tokens up over SSH, launch detached, poll a status file, copy the checkpoint back, delete the pod. Most runs are eighteen minutes on a rented RTX 4090 at 440,000 tokens a second. The whole study — around forty models across three corpora — came to under thirty dollars.
- Detector defaults. 0.5 s window and hop, tone threshold 0.06, core threshold 0.12 for root/third/seventh, max-outside 0.10, min-inside 0.80, a 0.01 s simultaneity grid. Larger template wins, ties by inside mass. Key by Krumhansl-Kessler correlation on mass-weighted chroma. The config is serialized into every stats file.
- Tokenizer config. pitch range (21, 109), beat resolution 8 then 4, 16 velocity bins, chords/rests/tempos/time-signatures off; the multi-instrument variant turns programs on and restricts them to guitar / bass / drums.
- Model configs. Workhorse d512 / 8 layers / 8 heads, 25.5M params. Full-band d512 / 8L at context 2048, 26.4M. Blues d256 / 6L with 12-key transposition augmentation. Browser-playground models d384 / 6L, exported to int8.
- Probes. Note times reconstructed from the bar/position stream so detector labels align to token positions; chunked teacher forcing with left context; paired differences reported with piece-clustered standard errors.
- What’s tested. The detector, the KV cache, and the token walker carry ~29 synthetic unit tests. The training and sampling paths are validated by their own artifacts rather than unit tests.
Corpora & provenance
Weimar Jazz Database (jazz solos with ground-truth chords), MAESTRO v3 (classical piano), and a public Kaggle metal-MIDI dump (PDDL). The trained checkpoints are headed for a public HuggingFace repo.