Skip to main content

Module naming

Module naming 

Source
Expand description

Musical names for patches, read off the measured features.

A patch’s topology signature (ssaw·lp·ladr, noiz) is precise and useless as a name: it describes the circuit, not the sound, and it collides constantly — a pool of prior draws produces six consecutive noiz rows, which is six rows the user cannot tell apart or refer to. Names are how people hold a bank of sounds in their head, and every synth that has ever shipped knows it: First Bass, Cathedral, Glass Pad.

So a name here is <character> <role> — read off the extracted features and the amp envelope, not off the module list. Bright Pluck is a claim about the render the user can check with their ears; it stays true if the same sound is reached by a different circuit, and it changes when the sound changes. The signature stays available as separate metadata for anyone who wants the circuit.

§Why the buckets are quantiles and not thresholds

The obvious implementation — a ladder of if tests against absolute feature values, first match wins — was measured in the running app and concentrated catastrophically: 13 of 40 bank rows came out Glass Pad, with numerals running to Glass Pad 12. Two independent causes, both structural rather than a matter of picking better constants:

  • The first test in the ladder claimed roughly half the pool by itself. Attack time is close to log-uniform over 1 ms–10 s, so any fixed attack threshold in the middle of that range splits the pool about evenly, and whichever branch is tested first swallows half the alphabet’s traffic.
  • The standard audition phrase deliberately changes register (C4→Eb4→C3), which moves the spectral centroid of almost any un-lowpassed patch by roughly the amount an early centroid_std test was keyed to. That test matched nearly everything, so every character below it was unreachable.

A nominal alphabet of ~110 names was delivering an effective 8–12. The fix is not better constants — any fixed constant is wrong for a pool that drifts as evolution concentrates it. Each axis is bucketed by terciles of the pool’s own distribution (NameScale), so a bucket is one third of whatever the pool happens to be and the marginals stay flat however the pool moves. Role and character are then a 3×3 grid each: 81 names with uniform marginals by construction, instead of a ladder whose branches race.

This makes a name relative to the bank it lives in — the same patch can be Bright Pluck in a dark bank and Warm Pluck in a bright one. That is the right trade: a name earns its keep by telling apart the patches in front of you, not by being a global coordinate. The topology signature is still there for anyone who wants an absolute one.

§Why quantiles alone would lie

Terciles put a third of the pool in each bucket whatever the pool is. That is the property that fixes the concentration bug, and it is also a way to lie: hand this scheme forty patches that genuinely all sound like the same pad and it will still deal out thirty distinct names and tell the user they are thirty different things. “Thirteen of these are the same kind of pad” was bad UI when the old thresholds said it by accident, but it may well have been true.

So each axis also carries a just-noticeable difference ([Jnd]): if the pool’s own tercile cuts fall closer together than a listener could plausibly hear, that axis collapses to a single bucket and stops contributing to the name. A genuinely varied bank gets its full alphabet; a genuinely uniform one gets Warm Pad, Warm Pad 2, Warm Pad 3, which is the honest report. The numeral then carries real information — it says these are variations of one thing, not the namer ran out of ideas.

These floors are the one place absolute constants belong here. They encode perception, which does not move when the pool does — unlike the thresholds this module started with, which were absolute claims about pool structure and were wrong the moment the pool drifted.

Structs§

NameScale
The naming scale: where this pool’s terciles actually fall.

Functions§

claim_name
Take base if free, else the first base N that is, recording the claim.