a patch is just a data structure
I downloaded VCV Rack to steal a Buchla patch from a YouTube video, and ended up spending two days reading a binary instead.
The patch wouldn't make any sound. While I was poking at it I noticed the obvious thing: it's a file. Files are usually readable if you're stubborn. So we opened it.
A .vcv turns out to be Zstandard compression wrapped around a tar archive wrapped around JSON. Three ordinary layers. Inside there are two lists — what's on the rails, and what's plugged into what. That's a whole modular rack, and it's about as mysterious as a spreadsheet.
the half that's missing
Reading one is easy. Writing one that means anything is not.
Every param and every port in that file is a bare integer. Nothing says output 0 is the sine and input 3 is the audio in. The file records positions in a list, and the meaning of those positions lives in the plugin's C++ source, which the file doesn't ship.
So we went and got the source. Most Rack plugins publish a link to their repo right in their manifest, and every module declares its controls twice — an enum whose order defines the indices, and config calls that give each one a label and a range. Parse both and you get a dictionary: "Cutoff frequency" is param 0, range 0.007 to 0.993. Ten plugins went through that same pass.
the one that had no source
Then there was a plugin with 149 modules and no code anywhere. Its repository is screenshots and a changelog. That's a third of my library.
Two things got us most of the way. The first is almost embarrassing: Rack writes out every param of every module when you save. So I dropped all 149 modules into an empty rack, hit save, and read the file back. Three thousand three hundred params, for free.
The second is less embarrassing. Every Rack module has to call config(params, inputs, outputs, lights) when it starts up, and those four numbers end up sitting in the compiled binary as literal values. Disassemble it, find the call sites, read the numbers. 153 of them.
Tying those to actual module names was the fiddly part, because the class names in the code aren't the names on the panel. DueMani is the module called 4Hands. OctoAD is 8AttackDecay. Matching them up took the param counts from the save as a cross-check, and it got 107 of the 149. The other 42 are still unidentified and I'd rather leave them that way than guess.
the reason any of this mattered
I assumed knowing how many ports a module has was a convenience. It isn't.
Rack looks up a cable's port by index with no bounds check, and then writes to it. A cable pointing at a port that doesn't exist isn't an error or a dropped connection — it reads past the end of an array and writes into whatever's there. One of our earlier ideas was to discover port counts by cabling every index and seeing which ones survived. That would have corrupted memory a few thousand times.
So now nothing gets written to disk unless it validates first: every param inside its real range, every cable inside a real port count. If it can't be verified it doesn't get saved.
the part I actually cared about
Out of all that came two patches. One is five steps against a four-four kick, sharing a clock, so the line only lands on the downbeat every fifth bar. The pitches are deliberately between the keys — a semitone is a twelfth of a volt and none of the values are a multiple of it.
The other is a drone. No clock, no gates, nothing to start. Sines tuned close enough to beat against each other, drifting on modulators whose cycles never line up, with the effects quietly re-rolling themselves every four minutes.
I took the drone and rebuilt half of it. Swapped two oscillators for additive ones so I could pull individual harmonics, set an LFO to 1024 Hz so it stopped being an LFO and became an FM source, dropped an oscillator to 11.6 Hz so it stopped being audible and became a modulator.
And when we read my version back, it found something I hadn't heard: I'd run a stereo signal into a mono input. Two cables into one port. The right channel was silent and which one you were hearing depended on the order the engine happened to process them.
That's the split, and it's a clean one. Structure is checkable — port counts, ranges, duplicate inputs, dangling cables — and none of that needs ears. Whether the thing is any good isn't checkable at all.
Full write-up, including the disassembly and both patches: Generating VCV Rack Patches.