The MIDI/Piano Generation Pipeline
The ask was precise and, at the time, appeared simple: take raw quantized MIDI — the kind with no rubato, no dynamics, no pedal, dead flat and metronomic — and make it sound as though a real pianist had played it. That became midi-transformer. The first two generations were disposable experiments, built to be thrown away and duly thrown away; gen-3, nicknamed PerformanceNet, was the one that worked — a ~10M-parameter model that learned expressive timing and dynamics well enough to serve as the project's baseline for months.
Then came the ambitious part. Gens 4 through 7 all tried to push past gen-3 — bigger models, up to ~90M params, bf16 autocast, gradient checkpointing, and a custom "velocity trajectory loss" aimed at the one thing gen-3 never nailed, velocity correlation. Almost none of it worked. The trajectory loss proved structurally incapable of improving velocity at all, which is a clean and genuinely useful negative result; it is also still a negative result. Rubato modeling failed less gracefully: what looked for a while like emergent expressive timing turned out, on a close inspection of the note counts, to be fully degenerate output — not subtle humanization but the model collapsing outright. A separate gen-7 attempt pretrained a GPT-style tokenized model on the ARIA-MIDI corpus, 80× larger than anything the project had used before, and got further than the rest; it banked roughly 5 hours of pretraining before hitting its time budget at about 11% of the planned run. Between the failed experiments and the half-finished pretrain, the file tree had become, in the phrase used at the time, "a complete mess."
The fix was to stop trying to salvage any of it in place. Gen-3 was declared the sole production model and the gen-4 through gen-7 checkpoints were deleted outright — deprecated rather than hoarded, on the theory that a checkpoint nobody will ever load again is simply a claim on disk. The one promising idea, the GPT-style humanizer, got a clean fork of its own in piano-humanizer, carrying over the model and runtime code and none of the wreckage. Partway into that rebuild a second realization arrived, and it was rather more inconvenient than the first: much of the crowdsourced, rough MIDI the humanizer was meant to run on was itself full of quantization noise, so the noise had to go before anything could be humanized at all. That spun off a third project, piano-normalizer — an ASAP-trained denoiser built around a deliberately constrained "anchored edit-transducer," which makes timing-only add/subtract edits, always preserves the input pitches, and is capped at one edit per bar. The constraint was the point; having already watched a free-form model degenerate into noise, I chose a narrow and interpretable edit space on purpose.
A fourth project, piano-generator, took a different branch entirely — a from-scratch generator that reuses neither the normalizer nor the humanizer, pretrained on ARIA performance data with its own tokenizer. Its first overnight baseline ran in June and promptly found the same ~28M-effective-capacity ceiling the earlier models had found: loss bouncing inside a tight band no matter how the architecture was tweaked, RoPE and form mixing included. Some limits are about capacity, not cleverness.
By the time four related projects existed, the housekeeping bill arrived: over 50GB combined, duplicate token caches, and a midi-transformer .git folder bloated to 2.22GB by an early accidental git add -A of the entire dataset. The bloat turned out to be 236,000 unreachable loose objects rather than real history, and the distinction mattered a great deal; it meant a single git gc --prune=now could bring the repository down to 13MB without disturbing the actual 7-commit history. The datasets were then consolidated into one canonical ~/midi-corpus, which the other three projects reach through directory junctions instead of copies: one source of truth, and no more silent duplication.