
Stems · 21 August 2026 · 7 min
Can stem separation fix a bad mix? Stems diagnose mixes, they don’t replace them
Stem separation won’t fix a bad mix, but it’s one of the fastest ways to find out what’s wrong with one. Pull the track apart, mute or turn down one part at a time, and re-measure. The part that moves the true peak or clears the mud is your suspect. Then go back to the session and fix it there. Separated stems carry bleed and artifacts, so they make a good flashlight and a poor replacement for the mix.
Here’s the situation it’s good for. A mix keeps slamming the limiter, or the vocal disappears in the hook, and you can’t tell why by ear any more because you’ve heard it 300 times. Maybe it’s a beat you bought as a two-track, or an old bounce whose session is gone. A separator gives you four handles on a file that used to have one. That’s really useful, as long as you’re clear about what those handles are.
What can stems actually tell me about my mix?
Two kinds of things: where the energy is, and what each part does to the whole.
- Collisions in level. Which parts peak at the same moment and use up the ceiling together. Kick and 808 are the classic pair.
- Collisions in frequency. Which parts pile into the same band. A chord pad and a vocal both living at 200–400 Hz is how a vocal goes muddy without being quiet.
- Whether a problem is level or tone. If soloing the drums shows clean hits and the clipping only shows up when the bass comes in, the fix is balance, not a new kick sample.
What stems can’t tell you is what the arrangement should have been. They show you what’s there. Deciding what goes is still your job.
How do I find which part is eating my headroom?
The test is simple: leave one out and measure again. Mute one stem, sum the others, read the true peak and loudness. Then try the same stem 3 dB down instead of muted, because that’s closer to a real mix move. If muting a part barely changes the true peak, that part isn’t your problem, however loud it sounds.
To show it working without anybody’s real song, we built a synthetic test: a generated 30-second beat at 140 BPM with four stems (drums, an 808, a synth “voice” lead and chords). We know exactly what went into it, so we can check whether the method finds the right answer. We summed them with one gain so the mix’s highest sample sat at −0.3 dBFS, which looks safe on a sample meter. Its true peak, measured to the ITU-R BS.1770 method with FFmpeg’s ebur128 filter, is 0.0 dBTP. That’s a full dB over the −1 dBTP that Spotify recommends for masters.
The script below does the leave-one-out test on any folder of stems. It needs Python 3, NumPy and FFmpeg, and it only reads your files.
#!/usr/bin/env python3
"""stem_check.py: use stems to find which part of a mix is causing a problem.
Usage: python3 stem_check.py FOLDER (FOLDER holds the stem WAVs, plus mix.wav if you have it)
For each stem it prints loudness and true peak (FFmpeg ebur128, ITU-R BS.1770), where its energy
sits (sub / bass / low-mid / mid / presence / high), and what the summed mix does to true peak
and loudness if that stem is muted or turned down 3 dB. Nothing is written over your files.
Needs: Python 3, NumPy, FFmpeg on PATH."""
import re, subprocess, sys, tempfile, os
from pathlib import Path
import numpy as np
BANDS = [("sub", 20, 60), ("bass", 60, 150), ("lowmid", 150, 400), ("mid", 400, 1200), ("pres", 1200, 4000), ("high", 4000, 18000)]
def read(path):
"""Decode any audio file to 48 kHz stereo float with FFmpeg."""
raw = subprocess.run(["ffmpeg", "-v", "error", "-i", str(path), "-f", "f32le", "-ac", "2", "-ar", "48000", "-"],
capture_output=True, check=True).stdout
return np.frombuffer(raw, np.float32).reshape(-1, 2).astype(np.float64)
def meter(x):
"""Integrated LUFS and true peak (dBTP) of a float array, measured by FFmpeg ebur128."""
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as fh: p = fh.name
subprocess.run(["ffmpeg", "-v", "error", "-y", "-f", "f32le", "-ar", "48000", "-ac", "2", "-i", "-", "-c:a", "pcm_f32le", p],
input=x.astype(np.float32).tobytes(), check=True)
err = subprocess.run(["ffmpeg", "-hide_banner", "-nostats", "-i", p, "-af", "ebur128=peak=true", "-f", "null", "-"],
capture_output=True, text=True).stderr
os.unlink(p)
lufs = float(re.findall(r"I:\s+(-?[\d.]+|-inf) LUFS", err)[-1])
tp = float(re.findall(r"Peak:\s+(-?[\d.]+|-inf) dBFS", err)[-1])
return lufs, tp
def bands(x):
"""Share of the stem's energy in each band, in percent."""
m = x.mean(1); P = np.abs(np.fft.rfft(m)) ** 2; f = np.fft.rfftfreq(len(m), 1 / 48000)
tot = P[(f >= 20) & (f < 18000)].sum() or 1.0
return [100 * P[(f >= lo) & (f < hi)].sum() / tot for _, lo, hi in BANDS]
def main(folder):
folder = Path(folder)
files = sorted(p for p in folder.iterdir() if p.suffix.lower() in (".wav", ".flac", ".aif", ".aiff") and p.stem != "mix")
stems = {p.stem: read(p) for p in files}
n = min(len(x) for x in stems.values()); stems = {k: x[:n] for k, x in stems.items()}
total = sum(stems.values())
if (folder / "mix.wav").exists():
mix = read(folder / "mix.wav")[:n]
res = 20 * np.log10(np.sqrt(np.mean((mix - total) ** 2)) / np.sqrt(np.mean(mix ** 2)) + 1e-12)
print(f"stems vs mix.wav: residual {res:.1f} dB (below -60 dB means the stems add back up to the mix)")
L, T = meter(total)
print(f"summed mix: {L:.1f} LUFS, true peak {T:+.1f} dBTP\n")
print(f"{'stem':8} {'LUFS':>6} {'TP dBTP':>8} | " + " ".join(f"{b:>6}" for b, _, _ in BANDS) + " | mute: TP / LUFS | -3 dB: TP / LUFS")
for k, x in stems.items():
l, tp = meter(x); sh = bands(x)
mt, ml = meter(total - x)[::-1]
dt, dl = meter(total - x + x * 10 ** (-3 / 20))[::-1]
print(f"{k:8} {l:6.1f} {tp:+8.1f} | " + " ".join(f"{s:5.0f}%" for s in sh) + f" | {mt:+6.1f} / {ml:6.1f} | {dt:+6.1f} / {dl:6.1f}")
if __name__ == "__main__":
main(sys.argv[1] if len(sys.argv) > 1 else "stems")
Here’s what it printed for the known stems:
$ python3 stem_check.py stems
stems vs mix.wav: residual -148.7 dB (below -60 dB means the stems add back up to the mix)
summed mix: -15.8 LUFS, true peak -0.0 dBTP
stem LUFS TP dBTP | sub bass lowmid mid pres high | mute: TP / LUFS | -3 dB: TP / LUFS
bass -17.6 -10.4 | 94% 6% 0% 0% 0% 0% | -1.9 / -19.2 | -0.5 / -17.3
drums -19.5 -2.1 | 34% 57% 5% 0% 0% 2% | -8.0 / -17.4 | -2.3 / -16.7
other -34.3 -26.8 | 0% 0% 80% 20% 1% 0% | -0.2 / -15.9 | -0.1 / -15.8
vocals -33.9 -18.8 | 0% 2% 38% 50% 2% 8% | -0.0 / -15.9 | -0.0 / -15.8
Read it from right to left. Muting the vocal leaves the true peak at 0.0, so turning the vocal down buys no headroom at all. Muting the chords frees 0.2 dB. Muting the 808 frees 1.9 dB and muting the drums frees 8. But look at the middle columns: the drums alone peak at −2.1 dBTP and the 808 alone at −10.4. Neither one is over the ceiling by itself. Together they hit 0.0. That’s two parts landing on the same moments in the same low band (the drum stem is 91% sub and bass energy, the 808 is 94% sub). The kick and the 808 are stacking.
Also notice that turning the 808 down 3 dB only gets you to −0.5. A plain level change isn’t enough. The real fix is a mix move: duck the 808 under the kick with a short sidechain, shorten the 808’s attack so it doesn’t start on the kick’s transient, or choose which one owns the very bottom. Then limit the mix bus. You can only do that properly in the session, where the kick and the 808 are still separate tracks.
What happens when the stems come from a separator?
Known stems are the best case. Usually you only have the stereo file. So we ran the same synthetic mix through Demucs (the htdemucs model described in the Hybrid Transformer Demucs paper), on an ordinary CPU with no GPU. It took about 14 seconds for 30 seconds of audio.
$ pip install demucs
$ demucs -n htdemucs --float32 -o sep stems/mix.wav
# writes sep/htdemucs/mix/drums.wav, bass.wav, vocals.wav, other.wav
Then we compared each separated stem with the real one. SDR (signal-to-distortion ratio) is the standard score from the BSS Eval / museval tools and from benchmarks like MUSDB18 and the Music Demixing Challenge. Higher is better. At 10 dB, the error has about a tenth of the stem’s power, and at 6 dB about a quarter. We also split each error into bleed (bits of the other stems) and artifacts (sound that wasn’t in any stem).
$ python3 sep_compare.py stems sep/htdemucs/mix
stem SDR dB own bleed artif. biggest leak from
drums 6.1 85% 7.6% 8% bass (7.6%)
bass 10.7 93% 0.0% 7% drums (0.0%)
vocals 6.2 76% 0.3% 24% other (0.3%)
other 10.9 92% 0.3% 8% vocals (0.2%)
separated stems summed back: residual vs mix -25.7 dB
mix.wav -15.8 LUFS, true peak -0.0 dBTP
sum of separated -15.9 LUFS, true peak -0.7 dBTP
That’s a good separation. It’s also clearly not the original. The drum stem carries 7.6% of the 808, so the two parts that were colliding are now mixed into each other’s stems. The synth “voice” came out with 24% artifacts, which makes sense because the model learned singing from real recordings and our lead isn’t one. Put all four separated stems back together and they don’t rebuild the mix: the leftover is only 25.7 dB down, and the true peak of the sum is −0.7 dBTP where the real mix was 0.0. Just splitting and re-summing changed the master’s peak by 0.7 dB.
Don’t read our numbers as a benchmark. One generated beat says nothing about how Demucs does on your genre. What it does show is the shape of the problem, and that shape holds for every separator.
Is the diagnosis still right with separated stems?
Yes, and that’s the good news. Here’s the same leave-one-out check on the Demucs stems:
$ python3 stem_check.py sep/htdemucs/mix
summed mix: -15.9 LUFS, true peak -0.7 dBTP
stem LUFS TP dBTP | sub bass lowmid mid pres high | mute: TP / LUFS | -3 dB: TP / LUFS
bass -19.1 -12.4 | 98% 2% 0% 0% 0% 0% | -2.0 / -19.1 | -1.0 / -17.1
drums -19.3 -2.2 | 40% 53% 5% 0% 0% 2% | -10.6 / -18.9 | -3.1 / -17.1
other -35.0 -25.7 | 1% 1% 76% 22% 1% 0% | -0.8 / -15.9 | -0.7 / -15.9
vocals -36.0 -22.6 | 0% 2% 38% 58% 2% 0% | -0.7 / -15.9 | -0.7 / -15.9
Compare each row with the −0.7 baseline of the re-summed stems. Muting the vocal or the chords changes nothing (−0.7, −0.8). Muting the 808 frees 1.3 dB and muting the drums frees about 10. It’s the same answer as the known stems: kick and 808 together. The exact dBs moved a little and the verdict didn’t. That’s why stems are good for diagnosing a mix: you need the right suspect, not perfect numbers.
Can I master or remix from separated stems instead?
You can, and sometimes it’s the only option, like a two-track beat with no session. Just know what you’re working with. Turn the separated 808 down and the 7.6% of it that leaked into the drum stem stays exactly where it was. Push a stem up and its artifacts come up too. Every move you make is a move on the separator’s guess.
That’s different from stem mastering, where a mix engineer prints real stems out of the session so the master can be balanced a little. Printed stems add back up to the mix exactly. Separated stems don’t, as you saw above.
So here’s the workflow we’d suggest:
- Separate the bounce and listen to each stem soloed. Solo is a flashlight.
- Measure with the leave-one-out test. Write down which part moves the true peak and which parts share a band.
- Fix in the session if you have one. If you don’t, ask the producer for the session or for printed stems.
- Re-measure the new bounce, not the stems. The mix you release is the one that has to pass.
Does separating my song mean uploading it?
It doesn’t have to. Demucs runs offline on an ordinary computer, as the timing above shows. NoDAW StemSplit also separates on your own machine, so an unreleased song never leaves it. You can hear what separated stems sound like on this page, and the mix panel on the CoProducer page shows what a finished bounce is doing.
- Can stem separation fix a bad mix?
- Not on its own. A separator guesses which sound belongs to which part, and every guess leaves some bleed and artifacts behind. It’s great for finding out what’s wrong, like which part is eating the headroom or hiding the vocal. The fix belongs in the original session, where the parts are still clean.
- Can I master from separated stems?
- You can, but you’re mastering the separator’s guesses as well as the song. In our test, adding the four separated stems back together didn’t even rebuild the original: the leftover difference was only 25.7 dB down and the true peak moved by 0.7 dB. Stem mastering works well when the mix engineer prints real stems from the session. Separated stems are a diagnostic copy.
- Do stems fix true peak?
- No. Stems help you find which parts are stacking up and using the ceiling. Then you fix that in the mix, for example by shortening the 808 under the kick, and limit the mix bus afterwards.
- How do I find what’s using up the headroom in my mix?
- Mute one stem at a time and re-measure the true peak of what’s left. When muting a stem barely changes the peak, that stem isn’t the cause. When muting it, or turning it down 3 dB, frees up a dB or more, you’ve found your suspect. Two stems that peak together are the usual answer.