AGM Studios Alexander G. Myers

Lab · audio

Sound, tuned by measurement

I made the sounds on this site and a music pipeline in code, then checked them with an open-source listening tool instead of leaving them to taste.

Ears are easy to fool, so every sound here goes through the same loop: I make it in code, render it offline, measure it, describe it, change one thing, and repeat. The listening tool is Earshot, an open-source tool that gives an AI ears: it listens to a sound and reports what it hears, with exact meters (loudness, true peak, attack, decay) and a confidence score for what the sound resembles.

How the pieces fit

  1. Tone.js builds the sound. One function, build(), defines the synths, filters and levels. The site and the test renderer both call it, so I measure exactly what ships.
  2. An offline render makes a file. Tone.Offline plays each cue into a buffer at 48 kHz without a speaker, and writes the buffer as a WAV.
  3. Earshot measures and describes it. The meters give me numbers to compare between versions. The description says whether a “click” actually reads as a click.
  4. One change per round. I keep a version only if the reading moved the right way.
// From the shipped ui-sound.js (shared by the site and the renderer):
// a filtered-noise click and a soft FM bell.
export function build(T, dest) {
  const out = new T.Volume(-14).connect(dest);
  const band = new T.Filter({ type: "bandpass", frequency: 2400, Q: 1.4 }).connect(out);
  const click = new T.NoiseSynth({ envelope: { attack: 0.0005, decay: 0.018 } }).connect(band);
  const bell = new T.PolySynth(T.FMSynth, { harmonicity: 3, modulationIndex: 1.2,
    envelope: { attack: 0.002, decay: 0.32, sustain: 0, release: 0.25 } }).connect(out);
  // …levels, then play(kind, at) picks the click or the bell for each cue
}

Interface sounds: four rounds

The six interface sounds, as shipped

Press one to hear it. Sound loads only when you press; it never plays on its own.

CuePlayTrue peakLoudnessAttackDecayBrightness
err-24.2 dBTP-38.6 LUFS5 ms170 ms862 Hz
nav-15.8 dBTP-38.1 LUFS2 ms13 ms6800 Hz
ok-21.7 dBTP-33.3 LUFS6 ms167 ms1343 Hz
on-21.5 dBTP-33.5 LUFS54 ms216 ms1009 Hz
press-15.6 dBTP-39 LUFS2 ms12 ms5867 Hz
toggle-21.5 dBTP-32.1 LUFS5 ms174 ms1930 Hz
VersionChangeWhat Earshot heard
v1sine chord + triangle pluck, -22 dB'a water drop / liquid bloop' (z +3.6); -34.5 / -42.8 LUFS
v2octave up, triangle chord, -16 dBchord: 'interface click' (z +3.1) but 'cheap synthesized beep' (z +3.97); press still 'water drop'
v3band-passed noise click; soft FM bellchord: 'a success chime' (z +3.84, strong); press: 'scroll wheel tick / key press'; too quiet
v4levels: click +10 dB, bell +6 dBpeaks -15.6 to -24.2 dBFS, no clipping, cues within ~7 LU

The first version sounded fine to me. Earshot said it sounded like “a water drop”. Two rounds later, the confirmation chord read as “a success chime” and the click as “a key press”. I have not tested those descriptions with visitors yet.

A music pipeline, measured

I used the same loop to tune a breakbeat engine written in Python that renders tracks from recorded loops and stems. Earshot read three versions of one track for spectrogram, sections, events and loudness:

Earshot sheet of version 1: spectrogram with gaps in the drum breaks, loudness curve averaging -16.1 LUFS.
Version 1. The breaks had holes (the dark vertical gaps), and loops sat at different levels.
made with Earshot sheet last committed 2026-10-22
Earshot sheet of version 2: denser, even breaks.
Version 2. Stems summed into the breaks and loops level-matched: the crest factor rose from about 10 dB to 14.7 dB at the same loudness, so the drums hit harder without the track getting louder.
made with Earshot sheet last committed 2026-10-22
Earshot sheet of version 3: an ambient intro section before the breaks, -16.5 LUFS.
Version 3. A new intro built from melodic loops. Earshot’s genre match for the body rose from z +3.1 to z +4.7, and the two tracks’ intros stopped sounding alike (similarity 0.39, from near-identical).
made with Earshot sheet last committed 2026-10-23
Twenty seconds of version 3.
made with a Python breakbeat engine, own loops and stemsmeasured with Earshot

Why it matters at work

The same habit applies to anything that is easy to judge by feel and hard to argue about: check it with an instrument, change one thing, keep the record. I used it to check course decks at real screen sizes, and to keep the search benchmark honest.