The Jump-Up Bass
A Reese is two saws a few cents apart, so every harmonic is two lines with nothing at all between them: 84 dB of nothing at the sixth. Distortion doesn't add harmonics to it, the count is pinned at its ceiling before the first clipper even runs. What it does is put lines where there were none, and by the third nonlinearity the gap is within 17 dB of the lines either side of it. This one is also the first day where the sound isn't code: it's a patch, thirteen nodes of data, and the five steps you walk through are worked out from the signal path rather than written by hand.
What it is
A jump-up bass, and the first day here whose sound isn’t code.
The sound is patch.ts: thirteen nodes and twelve wires, all numbers. Two saws thirty-five cents
apart, an envelope, the sub taken out before the distortion so the drive works on mids only,
three different nonlinearities with an EQ between each deciding what the next one bites, and a
clean sine put back underneath at the end.
The five steps you step through are not written down anywhere. They are worked out from the signal path: sort the graph, and where thirteen nodes give thirteen steps, merge the ones that moved the sound least until five remain. Click a step, or press 1 to 5.
How it works
The thing worth measuring about a Reese is not how many harmonics it has. It is where they are.
Two saws thirty-five cents apart put two lines at every harmonic: one at k times the low voice,
one at k times the high one, and between them nothing, because every line in the sound is a
multiple of one voice or the other and the midpoint is a multiple of neither. So that’s where to
look. clusterFillDb probes exactly halfway between the pair and reports what it finds against
the line beside it.
Here is what the five steps do to that gap, at the sixth harmonic:
| step | between the lines |
|---|---|
| two saws | -84.3 dB |
| an envelope | -107.5 dB |
| the sub taken out | -110.4 dB |
| one soft clip | -27.5 dB |
| two more clippers, sub back under | -16.5 dB |
The harmonic count over the same run goes 31, 31, and then sits at 40, which is the ceiling I gave it, for the whole rest of the patch. It has nothing to say. The gap moves 94 dB.
That is what distortion does to a Reese. It is not making the sound richer in harmonics, it is
making the spectrum stop being harmonic: every sum and difference of the two voices appears, so
the span that held two lines fills with lines one detune apart instead of k of them.
There’s a control for it in the tests. A single saw driven exactly as hard keeps its gap empty, because a nonlinearity on one voice produces harmonics of that voice and nothing else. The fill needs the detune and the distortion together.
What surprised me
The gap was already full before any distortion touched it, and the reason was the probe. The first run reported the reese as filled in at step two, the envelope. That’s real: an exponential decay is amplitude modulation, and it smears every line in the spectrum far wider than the 1.7 Hz gap I was looking at. My scratch version had missed it because that was a six second drone with no envelope at all. The probe was releasing the note at 0.28 seconds and measuring from 0.3, so it was reading nothing but release tail. The amp module has a sustain level now and the probe holds the note.
Three voices cannot show this at all. I started with three saws, which is what most people mean by a detuned stack, and the midpoint of the outer pair is then the middle voice. There’s no empty gap to watch fill in. Worse, three voices make a nonlinearity produce lines 0.66 Hz apart, and no window short enough to be useful resolves that. Two voices, which is what a Reese actually is.
The harmonic count read 1 for a clean Reese. Not a rounding error, a category error: neither voice sits at the note you played. A detuned pair has no energy at its own nominal frequency at all, so counting harmonics of that frequency counts the gaps.
And the page rendered nothing, for ever, and said so. A patch day has no settings, so it passes
() => undefined, and JSON.stringify(undefined) returns undefined rather than a string. That
matched the rig’s initial state, so its “have the settings changed” check said no on the very first
call and never rendered. I had built that key-ownership into the rig specifically to stop a day
choosing a key that changes every frame, and walked straight into the mirror image.
What I would do next
The obvious one is the editor. The patch is data and the walkthrough is derived, so the piece still missing is letting somebody drag the nodes around themselves and watch their own sound get broken into steps. Everything under this page is already built for it.
The other is the measuring. Rendering a stage takes 15 milliseconds; measuring it takes 633. Nearly all of that’s computing the same harmonic levels four separate ways for four different readouts. That’s the whole of the five seconds this page takes to show you anything.