
Local-first · 8 October 2026 · 10 min
Before a cloud stem splitter gets your unreleased song, read four clauses
A cloud stem splitter needs your whole song on its servers, and an unreleased song is the most sensitive file you own. Before you upload one, read four clauses in the terms: the license you grant, how long they keep the file, whether they can train on it, and who else processes it. Don’t count on a renamed file to hide anything, because audio can be identified from its content. If the track isn’t out yet, split it on your own machine, and prove that “local” really is local by running the split with the network turned off.
You know the moment. It’s late, the record is almost done, and you want the acapella to send a remixer, or the drum stem to check a collision. A browser tab promises stems in ninety seconds. You drag the bounce in, and the progress bar starts. Somewhere in that bar, a copy of a song nobody else has heard just landed on a computer you’ll never see.
That might be fine. Plenty of services handle files carefully, and for released music the risk is small. But this site already has an essay on uploading an unreleased master for mastering, and stem splitting raises the stakes in a specific way. You aren’t just sending the mix. You’re asking the service to produce the most reusable pieces of it: the clean vocal, the isolated beat. That’s the stuff that gets leaked, bootlegged or flipped.
The four clauses worth five minutes
We aren’t going to quote any one company here. Terms change, and a quote that was accurate in spring is wrong by fall. What doesn’t change is where the important sentences live. Open the terms of service and the privacy policy, search for these words, and read the paragraph around each hit.
| Clause | Search for | Reassuring wording | Wording that should slow you down |
|---|---|---|---|
| License you grant | “license”, “royalty-free”, “sublicensable” | A license limited to processing your request | Worldwide, sublicensable, “to operate and improve our services” |
| Retention | “retain”, “delete”, “days” | Deleted automatically after a stated short period, including backups | “As long as necessary” or no period at all; deletion only on request |
| Training | “train”, “machine learning”, “improve” | An explicit statement that uploads are never used for training | “Improve our models,” or an opt-out buried in settings |
| Sub-processors | “third parties”, “sub-processors”, “service providers” | A named list, with storage regions | Unnamed partners; a broad right to share with affiliates |
Two habits make this quicker. Screenshot or save the page on the day you upload, because a future edit doesn’t change what you agreed to then. And remember the license and the retention clause work together. A narrow license on a file kept forever, or a broad license on a file deleted in an hour, are very different risks from a broad license on a file kept forever.
Even the big platforms spell out how broad an upload license can be. YouTube’s Terms, for instance, take a worldwide, non-exclusive, royalty-free, sublicensable and transferable license to content you provide, and say YouTube may keep server copies of removed videos. That’s a reasonable deal for publishing. It would be a strange deal for “please split this demo.” Read for the deal you actually want.
Renaming the file doesn’t hide the song
A common instinct is to upload as untitled_v2.wav and assume nobody can tell what it is. File names and hashes only identify exact bytes. Content identification works on the sound itself, and it survives the things we do to files every day. To show how little it takes, here’s a landmark fingerprint in about fifty lines. It pairs strong spectral peaks, the idea popularized by audio ID services. Everything it tests is synthetic.
#!/usr/bin/env python3
"""fingerprint_leak.py: renaming or re-encoding a file doesn't make it anonymous.
SYNTHETIC test. We build an "unreleased song" with lab.py, then make the kinds
of copies that end up on servers: a renamed copy, a 128k AAC transcode, a
12-second excerpt, a 6 dB quieter bounce, and its isolated lead stem. A
50-line landmark fingerprint (the peak-pair idea behind audio ID services)
still finds every one of them, while SHA-256 only catches the exact bytes.
An unrelated synthetic song is the control.
Usage: python3 fingerprint_leak.py (numpy + ffmpeg + lab.py)
"""
import hashlib, os, shutil, tempfile
from collections import Counter
import numpy as np
import lab
def landmarks(x, n_fft=2048, hop=512):
X, _ = lab.stft(x, n_fft, hop)
S = np.log(np.abs(X) + 1e-9)
peaks = []
for t in range(S.shape[0]):
row = S[t, 10:700] # ~200 Hz .. 15 kHz
for f in np.argsort(row)[-5:]: # 5 strongest bins per frame
peaks.append((t, int(f) + 10))
peaks.sort()
hashes = []
for i, (t1, f1) in enumerate(peaks):
for t2, f2 in peaks[i + 1:i + 40]:
dt = t2 - t1
if 1 <= dt <= 32:
hashes.append(((f1, f2, dt), t1))
return hashes
def index(h):
d = {}
for k, t in h:
d.setdefault(k, []).append(t)
return d
def match(db, q):
offs = Counter()
for k, t in q:
for t0 in db.get(k, ()):
offs[t0 - t] += 1
return offs.most_common(1)[0] if offs else (0, 0)
sha = lambda p: hashlib.sha256(open(p, "rb").read()).hexdigest()[:12]
song_stems = lab.synth_stems(seed=7)
song, song_stems = lab.mixdown(song_stems)
other, _ = lab.mixdown(lab.synth_stems(seed=99, bpm=128.0, key_shift=-5))
db = index(landmarks(song))
with tempfile.TemporaryDirectory() as d:
master = os.path.join(d, "unreleased_master.wav"); lab.write_wav(master, song)
renamed = os.path.join(d, "untitled_final_v2.wav"); shutil.copy(master, renamed)
aac, _ = lab.codec_roundtrip(song, [("m4a", ["-ac", "2", "-c:a", "aac", "-b:a", "128k"])])
variants = [
("renamed copy (same bytes)", lab.read_audio(renamed), sha(renamed)),
("AAC 128k transcode", aac, "differs"),
("5 s excerpt from 1.5 s", song[int(1.5 * lab.SR):int(6.5 * lab.SR)], "differs"),
("-6 dB quieter bounce", 0.5 * song, "differs"),
("isolated lead stem only", song_stems["lead"], "differs"),
("CONTROL: unrelated song", other, "differs"),
]
print(f"master sha256 {sha(master)} landmarks indexed: {sum(len(v) for v in db.values())}")
print(f"{'query':28s} {'sha256':>12s} {'score':>6s} {'offset(s)':>9s} verdict")
for name, x, h in variants:
q = landmarks(x)
off, votes = match(db, q)
score = votes / max(len(q), 1)
hit = score > 0.10
print(f"{name:28s} {h:>12s} {score:6.3f} {off*512/lab.SR:9.2f} {'IDENTIFIED' if hit else 'no match'}")
master sha256 b407e6fad71d landmarks indexed: 128350
query sha256 score offset(s) verdict
renamed copy (same bytes) b407e6fad71d 1.000 0.00 IDENTIFIED
AAC 128k transcode differs 0.978 0.00 IDENTIFIED
5 s excerpt from 1.5 s differs 0.891 1.50 IDENTIFIED
-6 dB quieter bounce differs 1.000 0.00 IDENTIFIED
isolated lead stem only differs 0.157 0.00 IDENTIFIED
CONTROL: unrelated song differs 0.062 0.00 no match
The SHA-256 column shows why hashing isn’t protection. Change a single sample and the hash is a different string. The score column shows the other side. The transcode scored 0.98, the excerpt was found at its real position, 1.50 s, and the quieter bounce matched perfectly. Even the isolated lead stem scored 0.157 against the full mix, while an unrelated control song scored 0.062.
Be honest about that last margin. A lone stem against a toy fingerprint is a thin match, and production systems are far better tuned in both directions. But the takeaway holds. Once a server has heard your song, it can recognize that song again, in new copies, in clips, sometimes in pieces. That isn’t an accusation against anyone. It’s just what audio is.
Why stems raise the stakes
A finished mix is hard to reuse. A clean acapella or an isolated drum break is the most portable thing in your session. It drops into someone else’s project in seconds. When a cloud splitter keeps outputs as well as inputs, the most leak-ready version of your record now sits beside the original. So check whether the retention clause covers generated files too. They’re often treated separately, and sometimes they’re kept longer so you can download them again.
There’s a quieter point about registration, too. Unreleased music often isn’t registered with your PRO, your distributor or a copyright office yet. Proving the song was yours first is easier when the only copies are on your drives and your collaborators’ drives. Every extra copy adds a little noise to that story.
And think about the people on the record. A featured vocalist agreed to be on your song, not to have their dry voice sitting on a third-party server as a separate file. If someone else’s performance is in the bounce, uploading it is partly their decision too. A short text before you hit upload costs nothing and keeps a collaboration friendly.
Prove “local” with the network off
“Offline” and “on-device” are easy words to put on a landing page. The test is easy too: take the network away and see whether the split still finishes. On Linux, unshare -rn starts a process in a fresh network namespace with nothing but a loopback interface, and it’s down. No root needed on most distros.
#!/usr/bin/env bash
# airplane_mode_test.sh: prove a local split needs no network.
# Runs a command inside a fresh Linux network namespace (unshare -rn, no root
# needed on most distros) after showing the network really is gone.
# Usage: ./airplane_mode_test.sh [your separator command...]
# Default: python3 offline_split.py (a SYNTHETIC oracle-mask split)
set -euo pipefail
if [ $# -eq 0 ]; then set -- python3 offline_split.py; fi
unshare -rn bash -c '
echo "interfaces: $(ip -br link | awk "{print \$1, \$2}" | tr "\n" " ")"
if curl -s -m 3 https://example.com >/dev/null; then
echo "network: REACHABLE (test invalid)"; exit 1
else
echo "network: unreachable"
fi
"$@"
' _ "$@"
Real output from the box, running the synthetic split in offline_split.py:
interfaces: lo DOWN
network: unreachable
split ok: kick=9.6dB bass=9.1dB pad=9.1dB lead=16.9dB hats=18.1dB
Swap in your own separator command and run it the same way. If it finishes, the split happened on your machine. If it hangs or errors, something wanted to phone home, maybe just a model download or a license check. Find out which before you trust it with a demo. On macOS or Windows, the low-tech version works: download the models once, pull the Ethernet cable, turn off Wi-Fi, and split.
One more check that matters: what part of a tool is local. Many products ship a desktop app and a web version side by side. The app may run everything on-device, while the web page sends audio to a server. Both can be honest products. Just know which one you’re using.
If you decide to upload anyway
Sometimes the cloud is the right answer. Your laptop can’t run the model, the deadline is in an hour, the terms read fine. Then shrink the exposure instead of pretending there isn’t any.
- Strip the tags. Exported WAVs and MP3s can carry title, artist, ISRC, even your DAW’s project path in the metadata.
ffmpeg -i in.wav -map_metadata -1 -c copy clean.wavremoves them without touching the audio. It won’t stop fingerprinting, as the test above shows, but it stops you from labeling the file for them. - Send only the section you need. If the job is the hook vocal, upload the hook. The excerpt is still identifiable, but it’s less of the song.
- Use the deletion controls, then ask in writing. Delete inputs and outputs in the dashboard. Where privacy law gives you a right to erasure, a short email asking for deletion of both the upload and the generated stems leaves a record.
- Keep a ledger. One line per upload: date, service, file hash, terms URL, and the screenshot you saved. If a stem ever surfaces somewhere it shouldn’t, you’ll know where it went and what you agreed to.
None of these make an upload private. They make it smaller, labeled, and on the record. For a song that isn’t out yet, that’s the difference between a known risk and a vague one.
A sane default for unreleased work
- Released music: cloud is fine if you’re comfortable with the terms. The song is already public.
- Unreleased, solo project: split locally. You lose nothing but a little setup.
- Unreleased, collaborators involved: split locally and send stems directly, or through storage your team already uses and controls.
- Label or client work: check your contract before anything leaves the room. Many agreements restrict third-party processing of unreleased masters outright.
For the local path, DeepSplit’s desktop app runs its separation models on your own computer, on GPU if you have one, and is built to work fully offline once installed. Run it through the network-off test above and you’ll know for sure. Its web-based YouTube splitter is a different path that goes through a server, so keep unreleased songs on the desktop side.
None of this is paranoia. It’s the same posture as keeping measurement local: the job doesn’t need a stranger’s disk, so don’t give it one by default. When the job really does, upload deliberately, after reading the four paragraphs that matter.
- Do cloud stem splitters train on my uploads?
- Some terms allow it and some forbid it, and the wording changes. Read the license, retention, training and sub-processor clauses for the specific service on the day you upload, and assume the broadest reading unless a contract says otherwise.
- If I rename the file, is it anonymous?
- No. Audio can be identified from its content. In our synthetic test, a simple landmark fingerprint matched a renamed copy, a 128k AAC transcode, a 5-second excerpt and a quieter bounce, while a file hash only matched the identical bytes.
- Is uploading just the vocal stem safer?
- It’s less of the song, but it isn’t anonymous either. The isolated lead still matched the full mix in our test, though with a much thinner margin than the full-mix copies.
- How do I know a ‘local’ app is really local?
- Run it with the network off. On Linux, unshare -rn gives a process no network at all. On any OS, disconnect Wi-Fi and Ethernet, split a file, and see whether it finishes.
- Is cloud ever the right call?
- Yes, for released material, for a machine that can’t run the models, or when you’ve read and accepted the terms. The point is to upload deliberately, not by default.