We usually think of a musical scale as a set of notes — seven of them for the major scale, twelve if you take all the semitones. But there’s another way to look at it that turns out to be much more generative: a scale is a monotonic curve through log-frequency space, and a curve like that is secretly a probability distribution over pitch.
This post lays out that idea from the ground up — the definitions, the curve-to-distribution connection, and a small browser sketch that makes both audible. There’s an interactive library of playable scales below, and a fully deterministic three-voice theremin piece whose voices, it turns out, arrange themselves around the density of the scale they share. You can also open the standalone version in its own tab.
The setting: log-frequency space
Everything here lives in log-frequency space — the y-axis is log2(f) for a frequency f in Hz. This is the natural space for pitch: octaves become equal-sized steps, because doubling a frequency adds exactly 1 to its log2. A perfect fifth is the same vertical distance whether you play it down low or up high.
The sketch uses pure sine waves only, with a touch of vibrato — no overtones. Timbre is deliberately removed so that the geometry of pitch is the only thing that varies.
The hierarchy of definitions
The whole project is derived from one definition and a handful of specializations.
Scale
A scale is a monotonically increasing trajectory through log-frequency space, parameterized by a position
tin note-space[0, 1].
Concretely, a scale is a function S : t → log2(f) with the single constraint that t1 < t2 ⟹ S(t1) ≤ S(t2). The rate of increase is unconstrained: a scale can crawl, sprint, or pause, as long as it never descends. In code, a scale is just a list of pieces, each piece a little function defined on a sub-interval of t.
Discrete scale
A discrete scale instantaneously switches between discrete levels and pauses on those frequencies.
This is the special case where S is piecewise constant — flat plateaus joined by instantaneous jumps. This is what we normally call “a scale.”
Periodic scale
A periodic scale repeats via some property — most often frequency-doubling, i.e. octaves.
Formally S(t + T) = S(t) + log2(r) for all t, with period T and ratio r. The familiar octave is just r = 2.
Discrete periodic scale
The intersection of the two: discrete steps that repeat at the octave. The major scale is the canonical example — seven steps [0, 2, 4, 5, 7, 9, 11] semitones, repeating every octave. 19-TET (nineteen equal divisions of the octave) is the same idea with a different step pattern.
Chords and arpeggios
A chord is a subset of a scale sounded simultaneously. A discrete arpeggio is that same subset played one note at a time.
Chord and arpeggio trajectories
A chord trajectory is several scale-positions moving together over time (e.g. LERPing between two places in the scale). An arpeggio trajectory is the sequential rendering of the same.
This is the key generalization for the piece below. Each “voice” of a chord is now a trajectory p(t) in note-space — a function of time. The sounding chord is { S(p₁(t)), S(p₂(t)), … }. Crucially, the voices do not have to be monotonic — a voice can wander up and down through note-space freely. Only the underlying scale S must be monotonic.
The encoding
Every scale is stored as an array of pieces:
{ tStart, tEnd, fn: (t) => logFreqOffset, kind }
where kind ∈ {"continuous", "discrete"} is purely informational — the math is identical either way (a discrete piece just has a constant fn). A periodic scale stores one { period, octaveRatio } and the lookup wraps t modulo the period, adding log2(octaveRatio) · floor(t / period) per cycle.
Voices are stored the same way, but in time-space instead of note-space:
{ t0, t1, p0, p1, shape }
Each gesture LERPs a voice’s note-space position from p0 to p1 between times t0 and t1, shaped by an easing function.
Play the scales
Here’s the library. Each card maps note-space t (horizontal) to frequency (vertical, log-scaled). Periodic scales repeat by frequency-doubling, discrete scales step, continuous scales bend. Hit Play to audition each one through the theremin synth.
The discrete-periodic ones (major, minor, chromatic, 19-TET) should sound familiar. The continuous-periodic ones bend smoothly within each octave instead of stepping. And the two aperiodic continuous scales at the end just keep climbing — they never repeat.
The punchline: a scale is an inverse-CDF
Here is the connection that reframes everything.
A monotonic map
t → log-frequencyis an inverse CDF.
If you treat t as a uniform draw from [0, 1], then S(t) is a sample from a probability distribution over log-frequency. That’s exactly what inverse transform sampling is: push a uniform random variable through an inverse cumulative distribution function and you get a draw from the corresponding density. The probability density at a given pitch is
p(log f) = 1 / S'(t) where t = S⁻¹(log f)
The slope of the scale is the reciprocal of the density. Where the scale rises slowly, density is high — lots of t-mass packed into a small range of pitches. Where it rises quickly, density is low — the scale flies through that pitch region, spending little t there.
That single fact reinterprets the entire hierarchy:
| Scale property | Distribution interpretation |
|---|---|
| Slow-rise segment | High-density region — “stable” pitches |
| Fast-rise segment | Low-density region — “transition” pitches |
| Plateau (discrete) | Delta spike — a point mass at one pitch |
| Periodic with octave ratio | Density is octave-equivalent (mod-1 on log-pitch) |
| Continuous aperiodic | An arbitrary continuous density over the chosen range |
| Major scale | Seven delta spikes, repeating every octave |
| Log-linear sweep | Uniform density over log-frequency |
A discrete scale is a sum of delta spikes. The major scale is seven spikes per octave. The “log-linear sweep” in the library above — the most boring case — is just a uniform distribution over log-frequency. Every scale you’ve ever played was a probability distribution in disguise.
This is the lens for designing scales. Instead of asking “what shape do I want for S?”, ask “what distribution over pitch do I want?”, then integrate the density to get the CDF, and let the scale be its inverse.
The trio
Three theremin voices share one continuous aperiodic scale. Each voice is a trajectory through note-space; played together they form a chord trajectory, with arpeggio passages where a single voice carries the line. The horizontal axis is time; the colored curves are the three voices draped over the scale, and the yellow line is the playhead.
The trio, decoded by density
The shared scale (TRIO_SCALE) is five segments spanning about three octaves:
| Segment | t range |
Octaves | Shape | Density character |
|---|---|---|---|---|
| 1 | 0.00 – 0.18 | 0.40 | linear | medium, even |
| 2 | 0.18 – 0.32 | 0.80 | quadratic accel. | medium → low |
| 3 | 0.32 – 0.50 | 0.30 | sqrt (decel.) | high — plateau |
| 4 | 0.50 – 0.72 | 0.70 | exponential climb | low |
| 5 | 0.72 – 1.00 | 0.80 | cubic burst | lowest — burst |
The three voices then sit in different density regions, and that — not any deliberate harmonic plan — is what gives each its character:
- Bass lives in
p ∈ [0.04, 0.40]— segments 1, 2, and the start of the sqrt plateau. Mostly high-density, which is why its long pedal tones read as a tonic: small movements inpbarely change pitch. - Mid roams
p ∈ [0.36, 0.72], straddling the plateau and the exponential climb. Its early arpeggios sit on the plateau (audibly stepped notes); its later LERPs ride the climb (audibly gliding). - Lead lives in
p ∈ [0.72, 1.00]— the exponential climb and the cubic burst, the lowest-density zone. Smallp-movements become wide pitch sweeps, so the lead reads as expressive even though its note-space gestures are simple LERPs.
This alignment of voice-role to density-region wasn’t planned. It fell out of nothing more than “bass low, lead high” — but it’s the reason the piece holds together. A voice that crosses a density boundary feels like it changes character even when its behavior in note-space is perfectly uniform.
It’s deterministic
The composition has no Math.random and no time-of-day input. The same source always produces the same piece — every voice is a fixed list of eased LERPs, every scale a fixed list of pieces. Playback is deterministic up to the browser’s setValueCurveAtTime interpolation; for a bit-exact artifact you could render it through an OfflineAudioContext to WAV.
Where this goes next
The inverse-CDF framing suggests a density-first scale builder: a makeScaleFromDensity(pdf, range) that integrates an arbitrary probability density over log-frequency to get a CDF, then inverts it to produce a scale. Composition then becomes choosing a prior over pitch and a trajectory through it:
- “Draw a pitch from the scale” becomes a one-liner — sample
t ~ Uniform(0, 1), look upS(t). - A Brownian random walk in note-space becomes a pitch random walk weighted by the density — a concrete, audible way to hear what a distribution over pitch sounds like.
That’s the natural sequel: stop drawing scale curves, start drawing the densities you want to hear, and let the math hand you the scale.