EV·ENGINESTART THE SIMULATOR

Matching loudness across twenty engines

Illustration of a VU meter needle centred on its scale, flanked by a large bass speaker cone and a small tweeter cone emitting matching sound waves

Before any correction, the loudest and quietest of EV·ENGINE's twenty engine presets measured 19 loudness units apart under ITU-R BS.1770 K-weighting, a gap wide enough to reach for the volume control on every switch. A per-preset gain trim, fitted from that same K-weighted measurement rather than from raw signal energy, closed the spread to half a loudness unit.

Two families of noise

Twenty presets split loosely into two families of sound. Machines like the steam locomotive and the big single lean on bass emphasis and sub-oscillator level that stretches well up the rev range before it fades, so most of the signal's energy sits at the low end. Machines like the V10 and the jet turbine lean the other way, built from brightness, the level of engine orders above the first, and comb feedback that shimmers rather than booms. Both are correct renderings of the machines they model. Neither was built with the other's loudness in mind.

That difference showed up the moment every preset was rendered and measured against the rest. Under ITU-R BS.1770 K-weighting, the standard used for loudness metering in broadcast and streaming, the loudest preset in the set and the quietest sat 19 loudness units apart. 19 of them is a substantial mismatch, the difference between a preset that fills the cabin unassisted and one that needs the volume pushed to be heard at all.

Listen to the locomotive and then the turbine back to back at the same player volume, and the gap is obvious rather than academic. One is a low chuff with weight behind it. The other is a thin, high whine, and at matched volume settings one of them was always going to disappear against whatever else the cabin happened to be playing.

Why not RMS

The obvious way to measure the loudness of twenty audio signals is to average the energy in each one, root mean square, and scale until the averages match. That is also the wrong way here. RMS treats a hertz of low bass the same as a hertz of upper harmonics, and nearly every preset in the set leans on bass emphasis and sub-oscillator level to some degree, because that is where a combustion engine's fundamental sits.

Ranking twenty bass-heavy signals by RMS would have rewarded exactly the wrong presets. The locomotive and the big single, carrying most of their energy at the bottom of the spectrum already, would have measured louder than they sound, and a trim fitted from that measurement would have turned them down further than the ear was asking for. The V10 and the jet turbine, carrying their energy in brightness and comb shimmer rather than sub content, would have measured quiet and been pushed louder than they needed to be.

BS.1770 avoids that by applying a K-weighting filter before any energy is summed, a shelf that reduces the low end of the measurement in roughly the way the ear discounts it in the room. It is the same standard broadcasters use so that an advert does not land louder than the programme either side of it, applied here to twenty engines instead of twenty adverts.

Fitting the trim

The correction lives in dev/offline/measureLoudness.ts. Each preset is rendered offline at 48 kHz, the sample rate the AudioWorklet runs at in the browser, and its integrated loudness is measured under BS.1770. From that measurement a single gain trim is fitted for each preset and baked into the code, so the adjustment happens once, offline, rather than being recalculated on a phone or a Tesla's centre screen every time an engine is selected.

The result is a spread of 0.5 loudness units across all twenty presets, down from 19: roughly a fortieth of the original gap. Switching from the big single to the V10 now changes what the cabin sounds like without changing how loud it feels, which is the point of matching loudness rather than matching signal level.

The trims are per-preset gains, not new synthesis parameters. Firing unevenness, brightness, comb feedback and everything else that gives an engine its character stays exactly as set; only the overall level moves. A preset that was designed to shout still shouts, it no longer shouts over everything else in the list.

What to listen for

The easiest way to hear the trim working is to switch between the two ends of the original spread and notice what does not change. Play the steam locomotive and the jet turbine one after the other. The locomotive still sounds like a slow, heavy chuff and the turbine still sounds like a thin spooling whine. What is gone is the reach for the volume control between them.

The same holds for a pair built the opposite way round, like the engine the boxer rumble post covers against a preset with almost none of that low-end character. A bass-heavy preset keeps its weight in the room; a bright one keeps its edge. Matching loudness only removes the one variable that had nothing to do with the engineering of either sound: how hard the code happened to be driving the output stage.

Twenty presets built for twenty different machines were never going to land at the same signal level by accident, and nobody mixed them by ear to force the point. The measurement did the ranking, and the code carries the result: nineteen loudness units at the start, half of one at the end, and one less reason to touch the volume knob between a steam locomotive and a jet turbine.

More notes

All notes