Andrew Shiau

readings

Type
Web instrument
Reads
Every 33 ms, measured — not chosen
Microphone
Read in the page and discarded. Nothing is recorded or sent.

Hold a note, or play a phrase. The line is your pitch in cents against the note you are nearest; the datum is dead centre. Each note that ends prints its own panel below, with the offset you actually held.

Open the instrument. Nothing is recorded and nothing leaves the page — the microphone signal is read in the browser and thrown away. The practice room has the tuner, metronome and drone.

The axis is discontinuous, and it draws a lie

A tuner reads cents off the nearest note, which is the right axis for one held note and the wrong one for a phrase. Move from A4 to B4 and the reading wraps from +49¢ to −49¢ without passing through zero. Drawn as one line that is a full-height vertical stroke through the middle of a clean slur — the same picture a catastrophic intonation error would draw.

So something has to decide when the note changed, and every possible answer is wrong in some case. Round every frame to the nearest note and a wide vibrato renames the note at every peak: a singer's reaches ±123 cents, so the peaks cross the halfway line twice a cycle. Wait for agreement instead and a grace note shorter than the window disappears — worse, its frames get charged to the note you were holding, which then reports an error you did not make. Lock the note at the attack and a slur measures the second note against the first, pinning the reading off scale.

There is no default that is right for every instrument, so the decision is a registry of eight named mechanisms rather than a constant, each with its parameters and its cost written down. A bench scores them against contours whose truth is known by construction. The trace picks one; changing it is one string.

The most relevant precedent was written by the same person

The detector here is the McLeod pitch method, and Philip McLeod also wrote Tartini — a violin intonation trainer solving this exact problem. Same detector, same question, and his answer is not a constant: the tolerance is base + √(local variance) × stretch, so vibrato raises the variance, which widens the band, which suppresses the note change. Nothing detects vibrato. On his own numbers that is about 12 cents on a steady tone and 113 under a wide vibrato, from one formula.

It is implemented, benched, and not what ships — it swallows a semitone trill whole, one note found where twelve were played, because the band it opens is wider than the trill's own interval. Every window and every threshold was swept; the behaviour is invariant, so that is the mechanism and not a tuning miss. It stays in the registry for the idea.

Reading faster does not help, and the measurement says why

The obvious fix for a ragged vibrato is to read more often. It does not work, and the reason is the analyser window: 2048 samples is 46 ms of audio, so every read is already an estimate fitted to that whole span. Measured in a real browser with the real detector, it returns the same ±52¢ of a real ±58¢ at every cadence from 66 ms down to 5 ms. The peak it misses is the window averaging, and no hop recovers it. At a 16 ms hop each read shares 66% of its samples with the one before; at 5 ms, 89%. That redundancy is what "smoother" turned out to mean.

What halving the cadence to 33 ms actually buys is that the drawing stops lying. The trace joins samples with straight lines, and at 66 ms a 6 Hz vibrato gets 2.5 samples per cycle — a worst-phase peak is drawn up to 22 cents from where it happened, which is larger than the errors the page exists to show. At 33 ms that is 3 cents. Going further costs real money for one: 8 ms is 81% of a core, and 5 ms needs 130% and cannot hold its own schedule.

One number for a phrase is the wrong answer

The test phrase holds four notes at +20, −18, +12 and −6 cents. They average to about +1, so any single figure for the take reports a player who is in tune and is wrong about every note in it. That is why each finished note prints its own panel, with its own datum and its own offset engraved on it — and why the panels are the half of this that is conventional. In a survey of nine tuners, five practice platforms and six audio editors, per-note cards were the only place real intonation statistics lived.

Each panel's offset is weighted toward the middle of the note rather than averaged flat, because a real attack overshoots — this phrase starts 40 cents sharp before settling, and a flat mean would call that note sharp when the player merely started sharp. Melodyne computes its own figure the same way, on the stated grounds that the central part of a note decides what a listener hears it as.

The suite that passed and proved nothing

The first harness drove the page with a fake microphone playing that four-note phrase, and ten tests passed on the first run. Then the segmenter was swapped for the wrong mechanism — lock-at-the-attack, which cannot handle a phrase — and all ten passed again. Every note in that fixture has a rest around it, and a rest is precisely where even the wrong mechanism is right.

So there is a second fixture: a slurred A4 to B4 with no rest, phase integrated across the glide so there is no click for an onset detector to lean on. With the wrong mechanism it now reports "only heard: A4" and panel offsets of 91.7 cents — off a ±50 scale. A suite that cannot tell the right mechanism from the wrong one is not testing the mechanism, however green it is.

And four bugs that no assertion could have caught, all one cause: Astro scopes CSS by stamping an attribute on the elements it compiles, and every mark in both figures is drawn at runtime. So every scoped rule missed them — the traces computed to no stroke, the fills fell back to black, and the figure rendered as a solid black slab with the numbers correct underneath. One screenshot found what ten passing tests could not.