LUFS Normalize

Every platform’s version of one master

Drop one master. Get every platform’s version. Nothing leaves your browser.

It measures to ITU-R BS.1770, the same standard the platforms measure with, using the same meter as headless-daw, the engine this was built from. The loudness it reads, the peak it reads and the volume change it plans are the ones that engine gets.

How it measures headless-daw’s own meter, BS.1770-4, in WebAssembly

This is the same meter headless-daw uses when it measures a mix offline, compiled to run in your browser instead. It is not a second implementation that has to be kept in step; it is that engine's own, and it is checked against it. headless-daw (hdaw.app) is the DAW engine this tool was built from.

Nothing is uploaded. Every byte stays in this tab.
01

The file

WAV · FLAC · OGG
Drop a file, or click to choose WAV · FLAC · Ogg Vorbis
File details
Channel layout

Channel layout

02

What it measures

The full measurement

Measured once. A gain is a scalar, so every delivery target is one multiply away from the same measurement — the file is not read again per target.

03

Where it goes

Delivery target

More options A target of your own, every target at once, 24-bit or float.

Or a target of your own

LUFS
dBTP

Every target at once

What it writes

04

The result

In headless-daw, this is one line

This page is the browser end of a normaliser that already exists. headless-daw (hdaw.app) takes the same delivery targets on its own render call, against a whole session rather than a finished master.

{"method": "render", "params": {
  "out_path": "master.wav",
  "normalize": {"preset": "spotify"}
}}

Or a target of your own, in place of a preset:

{"method": "render", "params": {
  "out_path": "master.wav",
  "normalize": {"target_lufs": -14.0, "true_peak_ceiling_db": -1.0}
}}

Shown without the JSON-RPC envelope and session setup your client adds.

The same 6 files, one call each, from a session rather than a master, and every one of them is deterministic: the same session renders byte-identical audio, every time. The reply carries what this page’s report card carries: the measured loudness, the gain applied, whether the ceiling capped it, and the loudness the file actually reached.

What it reads, and what it writes

In. Multichannel WAV, 8 to 32-bit integer or 32/64-bit float, WAVE_FORMAT_EXTENSIBLE included. FLAC, to the format’s own eight-channel ceiling. Ogg Vorbis at any channel count.

Out. 24-bit PCM WAV by default, or 32-bit float, at whatever rate went in. Nothing is resampled and nothing is dithered.

Any sample rate. 44.1, 48, 88.2, 96, 176.4 and 192 kHz all work, and so does anything else your file states: the meter works out its filter from the file’s own rate rather than assuming one. Whatever goes in comes back at the same rate.

Not compressed output. A FLAC or an Ogg goes in; a WAV comes out. Re-encoding it here would mean shipping an encoder to undo a decode, and the file you want next is almost always the uncompressed one.

What the numbers mean

Integrated loudness, in LUFS, is the whole file’s loudness under ITU-R BS.1770’s K-weighting and its two gates: an absolute one at −70 LUFS, and a relative one 10 LU below the ungated mean. Quiet passages are excluded, which is why a sparse file reads louder than its average would suggest.

True peak, in dBTP, is the peak of the waveform between the samples, recovered by oversampling. It is what a converter will actually have to reproduce, and it can sit several dB above the highest sample in the file.

Both are checked against reference tones from EBU Tech 3341, the document that exists so two meters can be asked whether they agree. How closely they are held, and what that does and does not prove, is written up in the repository rather than here.

Delivery targets

The gain is one number, and it is min(target − measured, ceiling − true peak). So the ceiling caps the gain rather than reshaping the audio: nothing is limited, nothing is compressed, and if the ceiling stopped the file short of its target the page says so and says what loudness it reached instead.

When every target clamps. A master whose true peak already sits at −0.2 dBTP has nowhere to go: the platforms here cap at −1.0 or −2.0 dBTP, so the honest answer is a file quieter than the platform asked for. Normalising louder would mean limiting, and this tool will not limit behind your back. Neither will headless-daw: its own normalise call is this same one scalar gain. The engine has limiters, and they are things you reach for on purpose, upstream of a delivery target.

Where these numbers come from. Spotify publishes both its target and the standard it measures with: −14 dB LUFS, according to the ITU 1770 standard. The broadcast row is the published standard itself, EBU R 128. The rest are industry-reported: those platforms do not publish a figure, and the values here are the ones the industry works to. Any of them can be overruled with a loudness and a ceiling of your own.

Delivery targets, and the true-peak ceiling each one asks for
PlatformsTargetCeiling
spotify, youtube, tidal, streaming-14 LUFS-1 dBTP
apple-music, podcast-16 LUFS-1 dBTP
amazon-music-14 LUFS-2 dBTP
deezer-15 LUFS-1 dBTP
broadcast-ebu-23 LUFS-1 dBTP
broadcast-atsc-24 LUFS-2 dBTP

Channels, and what each one is worth

BS.1770 weighs a main channel at 1.0, a surround channel at 1.41 and an LFE at 0.0. So the measurement depends on knowing which channel is which, and a channel count does not say: six channels is 5.1 nearly always and something else occasionally.

A WAV can carry a speaker mask, and where it does the page reads it and says so. Where it does not, the page guesses from the channel count and says that. Either way the chooser is there to be overruled — an LFE weighed 1.0 by mistake makes a bass-heavy master read loud and normalise too quiet.

Nothing is uploaded

There is no server to upload to. Audio is never transmitted or stored, and nobody else sees it. There is no account. Nothing has to fit through a request either, so the size limit is a question about the machine, not the tool.

In Chrome, Edge and the other Chromium browsers the file is streamed: the page reads a block, applies the gain, and writes it straight to the file you chose, so your disk sets the ceiling and nothing but a block is ever held. That is true of a FLAC and an Ogg as well as a WAV — the output stream does not care what went in, though a compressed file is still decoded whole first, and the page says what that will cost before it does it.

Firefox and Safari cannot hand a page a file handle at all, and neither can any browser on an iPhone — they are all WebKit underneath. There the file is held in memory and handed back as a download instead, which costs the finished file’s own size twice over while it is built. The page says how much before you press, and refuses rather than letting the tab run out of room. Everything above the write is identical either way.

The batch works the same way round. Where the browser will hand over a folder, each target is streamed straight into it. Where it will not, the files come back as one ZIP built in this tab — entry by entry, with each entry’s length and checksum written after its audio rather than before, so no file is ever held to be measured.

Questions

Which target should I pick?
The one you are delivering to. Press its row and the file is written for it. Where several platforms ask for the same numbers they share a row, because they want the same file and writing it twice would suggest otherwise.
If you do not know yet, write every delivery target at once. One press does the lot, each file named after what it is for, and you can pick the one you need when you find out.
Do I have to upload anything?
No, and there is nowhere to upload it to. This page is a static file with no server behind it. Your mix is read, measured and written inside your own browser, and it never leaves the machine you are sitting at.
Will this change my mix?
It changes the volume and nothing else. Every sample is multiplied by the same number, so the balance you mixed is the balance you get. There is no limiter, no compressor and no EQ anywhere in the path.
Why is my file quieter than the number I asked for?
Because the peaks ran out of room before the loudness did. Every platform asks for two things: a loudness, and a peak ceiling it will not have you cross. Turning your mix up far enough to reach the loudness would have pushed the peaks past the ceiling.
Getting there anyway would mean squashing the loudest moments, and this will not do that behind your back. So it stops at the ceiling and tells you the loudness it actually reached. If you want it louder than that, it is a mastering decision and it belongs upstream of here.
What if my track is already at the right level?
Then almost nothing happens: the change comes out near zero and you get your file back as it was. Most masters go down rather than up, because most delivery targets are quieter than a modern master.
Does it work on my phone?
Yes. On a phone, and in Firefox and Safari on a desktop, the finished file comes back as a download instead of being written straight into a folder you chose. That is the only difference, and everything before it is the same. Very long files are the one thing to watch on that path, because the whole file has to be held in memory, and the page tells you what that will cost before you press anything.
Where does this come from?
It is part of headless-daw, the DAW engine it was built from, compiled to run in your browser. The meter is that engine's own rather than a second one written for the web, so the loudness you read here is the same measurement as the engine's. headless-daw is at hdaw.app.
What about a surround mix?
It handles one. Surround channels count for more than the front ones and the LFE counts for nothing at all, which is what BS.1770 asks for. Getting that wrong is what makes a bass-heavy mix read louder than it really is and come back too quiet.
A WAV can state which channel is which, and where it does the page uses that and says so. A FLAC or an Ogg cannot state it, so the page works it out from the channel count and says that instead. If it has guessed wrong, the channel layout control in step 01 is there to correct it.