
Privacy · 8 October 2026 · 10 min
Keeping an unreleased master on your own machine, honestly
Local processing means the audio you select is converted on your device instead of being uploaded, which removes the biggest exposure for an unreleased master. It does not make you invisible: pages still load over the network, synced folders still upload outputs, and tags inside the file still travel. Process locally, strip metadata from delivery copies, and promise only what is true.
There's a specific kind of nervous you feel holding an unreleased record. It might be a client's single under embargo, a feature verse you were trusted with, or a vocal that hasn't been registered or cleared yet. Then you want to try something small on it, like a 432 alternate or a quick check, and the tool you find wants you to upload the file first. For a job that's basically one ratio applied to some samples, that's a strange trade.
This essay is about what local processing actually protects, what it doesn't, and how to talk about it without overpromising, to a client or to yourself. If you've read Should you upload an unreleased master to the cloud?, this is the next layer down: not whether to upload, but what "it stays on your machine" really means once you look closely.
Why a retune doesn't need a server
Some jobs genuinely need someone else's computer. Large AI models, collaborative sessions, and human mastering engineers all qualify. A pitch-reference conversion isn't one of them. Moving 440 to 432 is a resample by 432/440. On an ordinary laptop it usually finishes before an upload of the same file would. In a browser, the Web Audio API can decode a file you choose, render it offline at a new rate, and hand you back a WAV, all inside the tab.
So the honest default flips. If the operation is narrow and deterministic, the burden of proof is on the upload, not on keeping it local. Every transfer adds another copy, another storage policy to read, another retention window you don't control, and another place a file can surface before release day.
What "local" protects, and what it doesn't
Here's the part privacy copy usually skips. When a web tool processes audio in the browser, the bytes of the song you pick don't need to go to an application server for the conversion. That's real, and it removes the biggest single exposure. It isn't invisibility.
- The page still came over the internet. The host's normal logs can record that your browser requested the page and its assets, along with the network details any website sees.
- Your device is still your device. Browser extensions with broad permissions, malware, screen recorders, and backups all operate outside the tool's control.
- The output lands somewhere. If your Downloads folder syncs to a cloud drive, the rendered file gets uploaded anyway, just by a different program.
- Paying isn't processing. A checkout or license system may receive your email and a payment record. That identity doesn't need to contain the music, and it shouldn't.
The defensible sentence is narrow: the selected audio is processed on this device, and it isn't intentionally uploaded for conversion. That's meaningful, it's checkable, and it doesn't pretend to be more.
Where the copies go, path by path
| Workflow | Audio leaves the device? | Who else may hold a copy | Works offline? | Your remaining job |
|---|---|---|---|---|
| Upload-based online converter | Yes, by design | The service, its storage and processing vendors, per its terms | No | Read retention and training terms before uploading |
| Browser-local tool (Web Audio) | No, for the conversion | Nobody, unless extensions or sync grab it | Once the page is loaded, often | Trusted browser, controlled download folder |
| Offline desktop batch | No | Nobody, unless backup or sync tools copy it | Yes | Trusted install, read-only inputs, backups |
| Cloud-synced output folder | Yes, after render | The sync provider | N/A | Render outside synced folders, or accept it knowingly |
| Handoff by chat or email | Yes | The platform, every recipient, their devices | N/A | Use the client-approved channel, strip tags, send hashes |
Read the table top to bottom and something becomes obvious. Local processing fixes one link in the chain. It's an important link, but the leaks that actually hurt people tend to happen at the edges: the synced Downloads folder, the forwarded email, the file whose tags announce what it is.
The leak nobody checks: what's written inside the file
Audio files carry text. Titles, artist names, comments, copyright lines, and encoder names ride along in the container. DAWs and assistants fill them in helpfully, with things like "v7 for Label X" or "do not share before the 20th." Most conversion tools copy those tags forward by default, because usually that's what you want. With an unreleased record, it's the opposite of what you want. You can strip every identifying word from the file name and still send a WAV whose comment field names the label and the embargo date.
Proving it on the box
This script does three things with a synthetic file: a decaying 440 Hz tone generated in code, tagged like a real unreleased mix so you can see what happens to the tags. First, it renders the 432 version inside a Linux sandbox with no network at all (unshare -rn), and tells FFmpeg to accept only local files and pipes. Then it tries to feed the same sandboxed FFmpeg a remote URL, to show the refusal. Second, it follows the tags through a default render, an MP3 made from that render, and a render with metadata stripped. Third, it writes a short hash manifest and confirms that stripping tags didn't change a single audio sample.
#!/usr/bin/env python3
"""11_local_private_render.py: prove a 432 render needs no network, and catch the metadata
that quietly travels with an "unreleased" file. SYNTHETIC AUDIO ONLY.
Needs: python3 + numpy, ffmpeg/ffprobe on PATH. Part 1 uses Linux `unshare -rn` (no network
namespace); on other systems, switch the network off and run the same ffmpeg command.
Usage: python3 11_local_private_render.py [workdir]"""
import hashlib, json, os, shutil, subprocess, sys
import numpy as np
SR = 48000
work = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else "private_demo")
shutil.rmtree(work, ignore_errors=True); os.makedirs(work)
src = os.path.join(work, "client_unreleased_v7.wav")
CHAIN = "aresample=88000:resampler=soxr:precision=28,asetrate=86400,aresample=48000:resampler=soxr:precision=28"
def sh(cmd, **kw):
return subprocess.run(cmd, capture_output=True, text=True, **kw)
def tags(p):
j = json.loads(sh(["ffprobe", "-v", "error", "-show_entries", "format_tags", "-of", "json", p]).stdout)
return j.get("format", {}).get("tags", {})
# a synthetic "unreleased" mix with the kind of tags DAWs and assistants leave behind
t = np.arange(SR * 6) / SR
x = (0.3 * np.sin(2 * np.pi * 440 * t) * np.exp(-((t % 1.5) * 1.2))).astype(np.float32)
subprocess.run(["ffmpeg", "-y", "-v", "error", "-f", "f32le", "-ar", str(SR), "-ac", "1", "-i", "-",
"-metadata", "title=SECRET SINGLE (unreleased) v7",
"-metadata", "artist=Client Artist",
"-metadata", "comment=mix v7 for Label X, embargo until 2026-11-20, do not share",
"-metadata", "copyright=Client Artist / Label X",
"-c:a", "pcm_s24le", src], input=x.tobytes(), check=True)
print("1) render with the network switched off")
offline = os.path.join(work, "offline_432.wav")
r = sh(["unshare", "-rn", "sh", "-c",
"ip -o link show | awk '{print $2, $9}'; "
f"ffmpeg -y -v error -protocol_whitelist file,pipe -i '{src}' -af '{CHAIN}' -c:a pcm_s24le '{offline}' "
"&& echo render: ok"])
print(" interfaces inside sandbox:", " | ".join(l for l in r.stdout.splitlines() if not l.startswith("render")))
print(" ", [l for l in r.stdout.splitlines() if l.startswith("render")][0], "| stderr:", r.stderr.strip() or "none")
r = sh(["unshare", "-rn", "ffmpeg", "-v", "error", "-protocol_whitelist", "file,pipe",
"-i", "https://example.com/upload.wav", "-f", "null", "-"])
print(" same sandbox, remote URL as input:", (r.stderr.strip().splitlines() or ["(no error)"])[0].split("] ")[-1])
print("\n2) what travels inside the file")
default = os.path.join(work, "default_432.wav")
sh(["ffmpeg", "-y", "-v", "error", "-i", src, "-af", CHAIN, "-c:a", "pcm_s24le", default], check=True)
mp3 = os.path.join(work, "default_432.mp3")
sh(["ffmpeg", "-y", "-v", "error", "-i", default, "-c:a", "libmp3lame", "-b:a", "320k", mp3], check=True)
clean = os.path.join(work, "clean_432.wav")
sh(["ffmpeg", "-y", "-v", "error", "-i", src, "-map_metadata", "-1", "-fflags", "+bitexact",
"-flags:a", "+bitexact", "-af", CHAIN, "-c:a", "pcm_s24le", clean], check=True)
for label, p in (("source", src), ("default render", default), ("mp3 of render", mp3), ("stripped render", clean)):
tg = tags(p)
print(f" {label:16s}: {len(tg)} tags")
for k, v in sorted(tg.items()):
print(f" {k:10s} = {v}")
print("\n3) handoff manifest (hash what you send, so the receiver can verify it arrived intact)")
for p in (src, clean):
h = hashlib.sha256(open(p, "rb").read()).hexdigest()
print(f" {h[:20]}... {os.path.getsize(p):>8d} B {os.path.basename(p)}")
same_audio = sh(["ffmpeg", "-v", "error", "-i", default, "-f", "md5", "-"]).stdout.strip() == \
sh(["ffmpeg", "-v", "error", "-i", clean, "-f", "md5", "-"]).stdout.strip()
print(" audio identical between default and stripped render:", same_audio)
Unedited output:
1) render with the network switched off
interfaces inside sandbox: lo: DOWN
render: ok | stderr: none
same sandbox, remote URL as input: Protocol 'https' not on whitelist 'file,pipe'!
2) what travels inside the file
source : 5 tags
artist = Client Artist
comment = mix v7 for Label X, embargo until 2026-11-20, do not share
copyright = Client Artist / Label X
encoder = Lavf61.7.103
title = SECRET SINGLE (unreleased) v7
default render : 5 tags
artist = Client Artist
comment = mix v7 for Label X, embargo until 2026-11-20, do not share
copyright = Client Artist / Label X
encoder = Lavf61.7.103
title = SECRET SINGLE (unreleased) v7
mp3 of render : 5 tags
artist = Client Artist
comment = mix v7 for Label X, embargo until 2026-11-20, do not share
copyright = Client Artist / Label X
encoder = Lavf61.7.103
title = SECRET SINGLE (unreleased) v7
stripped render : 0 tags
3) handoff manifest (hash what you send, so the receiver can verify it arrived intact)
75aa39c178c3534007fa... 864262 B client_unreleased_v7.wav
382857b0c59010a731c6... 880068 B clean_432.wav
audio identical between default and stripped render: True
What that output means for a real session
The render finished with the only network interface down. Inside the sandbox, the loopback interface was the only one, and it was down. The 432 render still completed with no errors. That's the cleanest possible evidence that this job never needed the internet. On a Mac or Windows machine you can run the same test the low-tech way: turn Wi-Fi off, render, check the file.
The whitelist turned away a remote input. -protocol_whitelist file,pipe made FFmpeg refuse an https address outright, before it even tried the network. It's a small belt-and-braces flag for scripts that handle sensitive material, because it means a typo or a pasted URL can't quietly make a local job reach out.
The tags survived everything. The default render carried all five tags, including the embargo comment. The MP3 made from it carried all five too, even though it was a separate encode of a separate file. That's the point to remember: conversion doesn't launder metadata. Only the explicit strip, -map_metadata -1 plus the bitexact flags (which also drop FFmpeg's own encoder tag), produced a file with zero tags.
The audio didn't change when the tags did. The default and stripped renders have identical decoded audio, checked by an MD5 of the samples, not the file. Stripping is a container change, not a sound change, so there's no quality excuse for skipping it.
The hashes are for the person on the other end. Send the SHA-256 alongside the file through a different channel. The receiver can confirm they got exactly what you sent, not a re-encode some chat app made "to save space." It also gives your notes a fingerprint that says which file left the room on which day.
Offline goes one step further
A browser tool removes the upload. A downloadable offline tool also removes the dependency on a live web page. It works on a plane, behind a studio firewall, on a machine that's never logged into anything, and it keeps working if the website changes or disappears. For catalog work, it also keeps the files right next to the storage they already live on instead of shuttling them anywhere. That ties into why local tools beat upload queues on speed as well as privacy.
It still isn't a security system. Offline means nobody else is involved in the conversion. It doesn't mean you have backups, permission, malware protection, or a sane delivery plan. Those were always your job.
A private workflow for someone else's record
- Confirm you're allowed. Before any tool question, make sure you have permission to process this audio. A private test of someone else's unreleased master is still their master.
- Work from a copy. Keep the original where it lives and process a duplicate in a local, non-synced working folder. Check your Downloads and Desktop sync settings once and you'll know for good.
- Use a trusted environment. An updated browser and a short list of extensions, ideally a clean profile for client work. Close the tab full of random plugins before you drop in an embargoed file.
- Render locally, strip tags on delivery copies. Keep full internal tags in your archive copy if they help you. Strip them from anything that leaves the room, unless the client asked for specific tags, and then write only those.
- Hand off through the approved channel. Whatever the client or label specified, with a hash manifest sent separately.
- Clean up. Delete temp renders and stray exports you don't need. An old test file in a forgotten folder is how a record leaks a year later.
How to say it without overpromising
Privacy language gets a studio in trouble when it's broader than the truth. "Your music never touches the internet" is a promise about your whole device, network, and future behavior, and nobody can make it. "This tool processes the selected audio on your device and doesn't upload it for conversion" is a promise about one code path, and you can stand behind it. The same goes for what you tell a client: "I render alternates locally, strip metadata from delivery copies, and send through the channel you specified." Specific beats sweeping, every time.
None of this needs to be paranoid. It's the same habit as checking true peak before delivery: a few small, boring steps that make the bad day much less likely. The unreleased record is often the most valuable file in the room. It deserves a workflow that treats it that way.
- Does browser-based audio processing upload my file?
- Not necessarily. Tools built on the Web Audio API can decode and render a file you select inside the browser tab, without sending it to a server for conversion. The page itself still loads over the network, so check how a specific tool works before trusting it.
- Is local audio processing completely private?
- No. It removes the upload for the conversion, but extensions, malware, backups, and cloud-synced download folders can still copy files, and the page request is still logged like any website visit. It protects one important link, not the whole chain.
- Do audio files contain hidden metadata?
- Yes. WAV and MP3 files can carry titles, artist names, comments, copyright lines, and encoder tags. In our synthetic test, an embargo comment survived both a 432 render and an MP3 made from it until the metadata was explicitly stripped.
- How do I remove metadata from an audio file with FFmpeg?
- Add -map_metadata -1 to drop copied tags, and -fflags +bitexact with -flags:a +bitexact to stop FFmpeg writing its own encoder tag. This changes the container, not the audio samples.
- Can I retune audio to 432 Hz without an internet connection?
- Yes. A 432 conversion is a resample by 432/440 and needs no server. Our demo rendered it inside a sandbox with no network at all. Offline desktop tools do the same for whole folders.