CoProducer Measure a mix
Two glowing drum-hit waveforms over black marble, a magenta copy sitting a hair behind a cyan one, with a soft-focus compressor and VU meter at right

Mix craft · 16 October 2026 · 8 min

Parallel compression sounds thin? Check the latency first

NoDAW Labs · Lacquer Vol. 05

If bringing up a parallel compressor makes the drums thinner, hollower or flammy instead of bigger, the parallel bus is usually arriving late: a few samples to a few milliseconds of uncompensated latency turns the blend into a comb filter. Null-test the two paths, measure the offset, and fix the timing before you touch the compressor.

You know the move. Drum bus feeding a parallel aux, a compressor on it slammed at 10:1 with fast attack, and you ease that fader up expecting the kit to get thick and loud. Instead the snare loses its middle, the cymbals turn a little swishy, and the kick somehow feels smaller. So you swap compressors. Then you try a different attack. Same thing.

More often than not, the compressor isn’t the problem. The parallel copy is landing a few samples after the dry one, and two copies of the same drums, slightly apart in time, don’t add up. They comb.

What a late copy does to the blend

Add a signal to a delayed copy of itself and some frequencies arrive in phase (louder) while others arrive opposite (cancelled). The cancellations fall at regular spacing, like the teeth of a comb. With a delay of N samples at sample rate fs, the first notch sits at fs / (2·N) and they repeat every fs / N above it.

With true parallel compression the copy isn’t identical (it’s squashed), so the notches aren’t bottomless. But their depth changes as the compressor breathes, because the level ratio between the two paths keeps moving. That’s the swishy, faintly flanged thing on cymbals and room mics. It’s not your compressor’s character. It’s timing.

Where the offset lands decides what you hear:

Offset at 48 kHzFirst notchWhat it usually sounds like
1–4 samples24–6 kHzTop end a little duller than solo; easy to blame the compressor’s tone
8–64 samples (0.2–1.3 ms)3 kHz–375 HzHollow snare, papery vocal, “phasey” overheads
128–512 samples (2.7–10.7 ms)188–47 HzSnare body and kick weight drop out; blend stops getting louder
1,000+ samples (20 ms+)under 25 HzA flam or slap: you hear two hits, not one thicker one

We measured it on a drum loop

To put numbers on it we built a synthetic drum loop (pitched-sine kick, noise-and-tone snare, hats, a small stereo room) at 48 kHz, ran a copy through a fast 10:1 compressor (about 9.4 dB of gain reduction on hits), matched its RMS to the dry loop, and blended it in at −4 dB. Then we slid the parallel path late by different amounts and compared each blend with the perfectly aligned one. Synthetic test signals, so read the shape rather than the decimals.

Parallel late byFirst notchKick 40–120Body 150–400Crack 1.2–4kAir 4–16kBlend addsL/R correlation
0 (aligned)—0.00.00.00.0+4.0 dB0.89
1 sample24 kHz0.00.0−0.1−1.9+3.4 dB0.88
8 samples (0.17 ms)3 kHz0.0+0.1−6.0−2.7+3.4 dB0.89
32 samples (0.67 ms)750 Hz−0.1−0.1−2.6−2.5+3.3 dB0.89
64 samples (1.33 ms)375 Hz−0.3−1.5−2.5−2.6+3.1 dB0.89
128 samples (2.67 ms)188 Hz−1.3−7.1−2.8−2.6+2.2 dB0.90
512 samples (10.7 ms)47 Hz−3.8−1.1−2.6−2.6+0.8 dB0.86
1,024 samples (21.3 ms)23 Hz−1.2−1.5−2.4−2.6+2.3 dB0.90

Band columns are dB relative to the aligned blend. Three things in there are worth carrying into your next session.

The last column matters too. Correlation barely moved (0.86–0.90 in every row) because both channels comb the same way. A correlation meter, CoProducer’s phase row included, will pass this mix, and that’s honest: it answers whether left and right will cancel in mono, not whether two busses inside the session line up. Different question, different test.

Where the latency sneaks in

Modern DAWs compensate plugin latency automatically, which is why this catches good engineers. It breaks in a handful of predictable places:

Find it in one minute: the null test

Don’t bypass anything for this. In some DAWs a bypassed plugin drops its latency, which hides exactly what you’re looking for.

  1. On the parallel bus, set the compressor so it does nothing: ratio 1:1 or threshold all the way up, make-up at 0 dB.
  2. Flip polarity on the parallel bus and set its fader so its level matches the dry path (unity if the send is post-fader at 0 dB).
  3. Play the drums. Aligned paths null to near silence. If you still hear a thin, fizzy version of the kit, the paths are apart.

On the loop above, aligned paths nulled to −175 dB (numerical floor). One sample of offset left a residual only 3.0 dB under the dry level, on this hat-heavy loop. Sixty-four samples left −0.8 dB, and 128 made the “null” 2.2 dB louder than the dry. There’s no such thing as nearly aligned. A miss is a miss.

If you’d rather have a number than a vibe, bounce the dry drums and the parallel bus soloed, same start point, and let this work out the lag. It cross-correlates the two files and tells you which path to delay:

#!/usr/bin/env python3
"""find_offset.py — how late is one bounce relative to another?
Bounce the dry track (or bus) soloed and the parallel bus soloed, same start point, then:
    python3 find_offset.py dry.wav parallel.wav
Prints the lag in samples and ms, the first comb notch it implies, and how well the two line up."""
import sys, subprocess, numpy as np

def load(path):   # any format ffmpeg reads -> mono float, plus its sample rate
    sr = int(subprocess.run(["ffprobe", "-v", "error", "-select_streams", "a:0", "-show_entries", "stream=sample_rate",
                             "-of", "csv=p=0", path], capture_output=True, text=True, check=True).stdout)
    raw = subprocess.run(["ffmpeg", "-v", "error", "-i", path, "-ac", "1", "-f", "f32le", "-"], capture_output=True, check=True).stdout
    return np.frombuffer(raw, np.float32).astype(np.float64), sr

a, sr = load(sys.argv[1]); b, sr_b = load(sys.argv[2])
assert sr == sr_b, "bounce both files at the same sample rate"
n = min(len(a), len(b), sr * 30)                  # 30 s is plenty
a, b = a[:n] - a[:n].mean(), b[:n] - b[:n].mean()
size = 1 << int(np.ceil(np.log2(2 * n)))
xc = np.fft.irfft(np.fft.rfft(b, size) * np.conj(np.fft.rfft(a, size)), size)
max_lag = sr // 10                                # search +/-100 ms
lags = np.r_[np.arange(0, max_lag), np.arange(-max_lag, 0)]
vals = np.r_[xc[:max_lag], xc[-max_lag:]]
k = int(np.argmax(np.abs(vals))); lag = int(lags[k])
score = abs(vals[k]) / np.sqrt(np.sum(a ** 2) * np.sum(b ** 2))
pol = "same" if vals[k] > 0 else "FLIPPED"
print(f"{sys.argv[2]} vs {sys.argv[1]}: {lag:+d} samples ({lag / sr * 1000:+.2f} ms) at {sr} Hz")
print(f"match {score:.2f} (1.00 = identical shape), polarity {pol}")
if lag:
    print(f"blending them comb-filters: first notch ~{sr / (2 * abs(lag)):.0f} Hz, then every {sr / abs(lag):.0f} Hz")
    print(f"fix: delay the {'dry path' if lag > 0 else 'parallel path'} by {abs(lag)} samples, or fix the plugin delay compensation")
else:
    print("aligned to the sample")

On our loop, with the parallel path deliberately 64 samples late:

wet_late.wav vs dry.wav: +64 samples (+1.33 ms) at 48000 Hz
match 0.86 (1.00 = identical shape), polarity same
blending them comb-filters: first notch ~375 Hz, then every 750 Hz
fix: delay the dry path by 64 samples, or fix the plugin delay compensation

A match score under 1.00 is expected here, since one side is compressed. The lag is what you came for.

Fix order

  1. Turn compensation back on fully and restart playback. That alone fixes most of these.
  2. Ping any hardware inserts.
  3. If the routing can’t be compensated, put the measured offset on the dry path’s track delay (most DAWs take it in samples or ms) and run the null test again until it disappears.
  4. Only now dial the compressor. You’ll probably need less of the parallel fader than before, because the blend is finally adding up.

Once it’s aligned, the genre moves behave the way the tutorials promise. Rock and pop drum busses take a fast, hard-ratio parallel tucked well under the dry and get density without losing the snare’s crack. On R&B and pop vocals, a parallel tucked a few dB under the lead thickens the low-level detail without that papery phasiness. On trap 808s with parallel saturation, alignment protects the fundamental. Remember the 512-sample row: it cost the kick 3.8 dB.

And if you want two hits, do it on purpose. A parallel slap delayed 20 ms or more is a legitimate effect. The trouble is the 0.1–10 ms zone nobody chose.

Why does parallel compression make my drums sound thin?
Usually because the parallel bus arrives a few samples to a few milliseconds after the dry signal. The two copies comb-filter, cancelling some frequencies and losing top-end coherence, so the blend gets hollower instead of bigger. Null-test the paths and fix the latency before changing compressor settings.
How much delay causes phasing in parallel compression?
Any. On our synthetic drum loop a single sample at 48 kHz cost about 2 dB in the 4–16 kHz band, 8 samples took 6 dB out of the 1.2–4 kHz crack, and 128 samples took 7 dB out of the snare body. The first notch sits at the sample rate divided by twice the offset.
Does a compressor’s mix knob avoid the latency problem?
Usually, yes. With a built-in dry/wet control both signals go through the same plugin latency, so they stay aligned. The problem shows up when the dry and compressed signals take different routes through the session.
Will a phase correlation meter catch a misaligned parallel bus?
No. Both channels comb-filter the same way, so left/right correlation barely moves. Our blends read 0.86–0.90 whether aligned or 1,024 samples late. Use a polarity-flip null test or cross-correlate soloed bounces instead.

A free one-pager

The checklist we run before every release.

Loudness, true peak, mono, tails, export settings and the metadata basics, on one page. Leave your email and it opens straight away, or read it here first. No email needed for that.