
Low end · 7 October 2026 · 8 min
Rumble you can’t hear is eating your limiter
Subsonic rumble and DC offset barely register on a LUFS meter, but they still count toward your peaks, so the limiter works harder for loudness you can’t hear. Check what lives under 20–30 Hz, filter it gently before the limiter, and you get headroom back without changing the song.
Here’s the session. The mix sounds clean. The meter says the master is sitting where you want it. But the limiter is pumping more than it should for how loud the record actually feels, and every time you push for another dB the kick gets smaller. You solo things, you check the vocal, you blame the 808. Nothing sounds wrong.
That’s the tell. When the limiter is busy and your ears can’t find the reason, the reason is often below where your ears and most speakers go. A mic stand getting bumped. HVAC in the vocal booth. A sample pulled off vinyl with the turntable wobble still in it. A plugin that leaves a little DC offset behind. You can’t hear 9 Hz, and the loudness meter mostly ignores it too, because K-weighting rolls off the deep lows. Your peak meter counts every bit of it.
Why the meter and the limiter disagree
Integrated LUFS is built to track how loud something feels, so it rolls off the low end on purpose. A peak limiter doesn’t care how anything feels. It sees a sample value and turns the whole mix down when that value crosses the ceiling. So a slow swell riding under the beat lifts every transient on top of it closer to the ceiling. The limiter hits harder on the hits that ride that swell, and you pay for it in punch.
DC offset is the same problem in its simplest form. If the whole waveform sits a little above zero, the positive peaks reach the ceiling early. It’s a few tenths of a dB on a mild case and more on a bad one, and you get nothing musical in return.
A quick check before you blame the mix
This script reads a bounce and tells you the DC offset, how much of the file’s energy sits under 20 Hz and under your cutoff, and what a gentle 25 Hz high-pass would do to peaks and loudness. It only reports. It doesn’t change your file.
#!/usr/bin/env python3
"""rumble_check.py: find the low end you can't hear but your limiter can.
Usage: python3 rumble_check.py mix.wav [cutoff_hz]
Needs: numpy + ffmpeg on PATH.
Prints DC offset, how much of the file's energy sits under 20 Hz and
under the cutoff, and how much peak headroom a gentle high-pass gives
back while integrated loudness barely moves."""
import re, subprocess, sys
import numpy as np
SR = 48000
path = sys.argv[1]
cut = float(sys.argv[2]) if len(sys.argv) > 2 else 25.0
HPF = f"highpass=f={cut}:poles=2,highpass=f={cut}:poles=2" # ~24 dB/oct, removes DC too
def decode(af=None):
cmd = ["ffmpeg", "-v", "error", "-i", path, "-ac", "2", "-ar", str(SR)]
if af:
cmd += ["-af", af]
raw = subprocess.run(cmd + ["-f", "f32le", "-"], capture_output=True, check=True).stdout
return np.frombuffer(raw, dtype=np.float32).reshape(-1, 2)
def lufs(af=None):
chain = (af + "," if af else "") + "ebur128=peak=true:framelog=quiet"
err = subprocess.run(["ffmpeg", "-nostats", "-hide_banner", "-i", path, "-af", chain,
"-f", "null", "-"], capture_output=True, text=True).stderr
summ = err[err.rfind("Summary:"):]
i = float(re.search(r"I:\s+(-?[\d.]+) LUFS", summ).group(1))
tp = float(re.search(r"Peak:\s+(-?[\d.]+) dBFS", summ).group(1))
return i, tp
db = lambda v: 20 * np.log10(max(v, 1e-12))
x = decode()
dc = x.mean(axis=0)
mono = x.mean(axis=1) - x.mean()
spec = np.abs(np.fft.rfft(mono)) ** 2
freqs = np.fft.rfftfreq(len(mono), 1 / SR)
total = spec[1:].sum() + 1e-20
share20 = spec[(freqs > 0) & (freqs < 20)].sum() / total
sharecut = spec[(freqs > 0) & (freqs < cut)].sum() / total
y = decode(HPF)
pk_in, pk_out = np.abs(x).max(), np.abs(y).max()
i_in, tp_in = lufs()
i_out, tp_out = lufs(HPF)
print(f"file : {path}")
print(f"DC offset L/R : {dc[0]:+.4f} / {dc[1]:+.4f} ({db(abs(dc).max()):.1f} dBFS)")
print(f"energy < 20 Hz : {100 * share20:.1f}% of the file")
print(f"energy < {cut:g} Hz : {100 * sharecut:.1f}%")
print(f"sample peak : {db(pk_in):+.2f} dBFS -> {db(pk_out):+.2f} dBFS after {cut:g} Hz HPF")
print(f"true peak : {tp_in:+.1f} dBTP -> {tp_out:+.1f} dBTP")
print(f"integrated : {i_in:.1f} LUFS -> {i_out:.1f} LUFS")
print(f"headroom returned : {db(pk_in) - db(pk_out):+.2f} dB of peak for {i_in - i_out:+.1f} LU of loudness")
if abs(dc).max() > 0.001 or sharecut > 0.02:
print("verdict : low end you can't hear is spending headroom. Filter before the limiter.")
else:
print("verdict : sub-audio looks clean. Leave the low end alone.")
What it found on test signals
These are synthetic WAVs built on the box, labeled that way on purpose so nobody mistakes them for a real record. The base is a 140 BPM trap-style loop with a kick, a 49 Hz 808, a snare, and hats. The second version is the same loop with a 9 Hz swell, a few 18 Hz mic-stand bumps, and a small DC offset added.
| Measurement | Clean loop | Loop + rumble |
|---|---|---|
| Integrated loudness | −23.3 LUFS | −23.2 LUFS |
| Sample peak | −6.9 dBFS | −4.1 dBFS |
| True peak | −6.9 dBTP | −3.4 dBTP |
| DC offset | −66 dBFS | −30 dBFS |
| Energy under 20 Hz | 0.2% | 76% |
Read that again. The loudness meter says the two files are the same, within a tenth of a LU. The peak meter says the rumble version has 3.5 dB less true-peak headroom. Three quarters of the file’s energy is something nobody will ever hear.
Then we pushed both into the same limiter: +12 dB of drive into a −2.0 dBFS sample-peak ceiling. The rumble version came out at −14.1 LUFS with about 1.7 dB of average gain reduction. The same file with a 20 Hz high-pass first came out at −13.1 LUFS with about 0.7 dB of average gain reduction. Same drive and same ceiling, but a full LU louder, and the limiter worked less than half as hard. The clean loop, for reference, landed at −12.9.
One honest footnote. The limiter in that test held a sample-peak ceiling, and the synthetic hats still pushed true peak over it. That’s a separate fight, and it’s covered in True peak is what codecs clip. Rumble doesn’t cause it, but it does eat the margin you’d otherwise have for it.
The catch: filtering isn’t free
On the clean loop, the same 25 Hz filter raised the peak by about 1 dB. Nothing was wrong down there to remove. All the filter did was shift the phase of the 49 Hz 808 and kick, and the waveform stacked a little differently. That’s why the script gives a verdict instead of telling you to always filter.
- If there’s real sub-audio junk (DC, energy under 20 Hz above a couple of percent, a peak that drops when you filter), filter it.
- If the low end is already clean, leave it alone. A reflexive 30 Hz cut on every master can cost a little weight and a little headroom for nothing.
- Mind your fundamentals. A tuned 808 can go down to E1 (41 Hz) or lower. Keep the cutoff well below the lowest note. Around 18–25 Hz is a safe start for most hip-hop and electronic records. Acoustic and orchestral sessions can usually sit a bit higher, around 25–30 Hz.
Where to fix it, in order
- At the source. Put a high-pass on the vocal, the acoustic guitar, the room mics, and any sample you lifted from vinyl. They have no business under 40–80 Hz anyway. That’s where most rumble comes from.
- On the mix bus, gently. A 12–24 dB/oct high-pass around 20 Hz cleans up whatever is left without touching the 808. Linear-phase is an option if you hear the low end shift, but listen for pre-ringing on the kick.
- Then the limiter. Re-check peak headroom and gain reduction. If the limiter suddenly relaxes, you just found free loudness.
- Re-measure after any slow or screwed version. Slowing a track down moves everything lower, including rumble that used to sit at 25 Hz and is now down at 17. Check the ScrewAI render separately instead of trusting the full-speed numbers.
When the master is printed, dropping it into CoProducer is a good last look. It looks for DC and rumble evidence next to the true-peak and loudness readings, and only suggests a cautious high-pass when that evidence is strong, so you can see whether the limiter was fighting the song or the floor.
- Should I always high-pass my master at 30 Hz?
- No. Filter when there’s measurable DC or sub-audio energy. On a clean mix a high-pass can shift low-end phase and even raise peaks slightly. Measure first.
- Will a high-pass make my 808 weaker?
- Not if the cutoff sits well below the 808’s lowest note. Around 18–25 Hz with a gentle slope leaves a tuned 808 alone and removes rumble under it.
- Does DC offset really matter?
- It shifts the whole waveform off center, so one side of it reaches the ceiling sooner. It’s small, but it’s headroom you get back for free.