service worker
The only context that can mint a tabCapture stream.
A free, open-source Chrome extension. Open a YouTube video, press the shortcut, and a six-channel mixing deck appears inside the page. A neural network runs on your own GPU and pulls the audio apart in real time — vocals, drums, bass, other, guitar, piano. Mute the singer. Solo the drums. Slow it to 0.75× without changing the key.
The tab plays a single stereo pair. The deck gives you six, each one on its own fader, mute, and solo — and a seventh passthrough lane so you can hear what the model was given.
The six colours come from the deck's own tokens.css. They were chosen to
stay separable under deuteranopia and protanopia in combination with a fixed
position, a number, and a text label. Colour is never the only thing carrying the
state — here or in the deck.
This is the extension's control surface, rebuilt here so you can put your hands on it before you install anything. The faders, the mutes, the solos and the keys are the real ones. The meters are generated. Nothing on this page makes a sound.
LIVE
LIVE
LIVE
LIVE
LIVE
LIVE
This is a demonstration, not a player. It is a working model of the extension's control surface, driven by generated meter data. It plays no audio, and it never will on this page — there is no audio on this site at all. Drag a fader, or press 1–6 to mute and Shift+1–6 to solo: the keys are bound right here.
Each channel spells its own state out — LIVE, MUTE, SOLO, CUT — so the desk still reads with the colour taken away. The figures across the top are the extension's real ones. The meters are not: there is no audio here to meter.
The deck shows the detected key and tempo while the track plays. Neither is read from the mix, and that is the whole point: separating the audio first is what makes both estimates easy.
Key is taken from the other
stem. A drum kit is broadband, so it lifts all twelve chroma bins together and
flattens the profile toward uniform — measured at +3.5 dB RMS over
the harmonic content, enough to take a clean F♯ minor below the display gate. A
full-mix detector spends its life fighting the drums. This one does not have to;
the drums are in another lane.
Tempo is the exact mirror — taken from the drums stem, where broadband is exactly what you want. Three RMS band envelopes, a subtraction, and an autocorrelation over eight seconds of history.
Both taps sit upstream of the pitch shifter, so your transpose is added once, at one call site, rather than baked in twice. And speed is key-locked at every rate — 0.5× to 2.0× in 29 geometric steps, held to ±2 cents on every rung. Transpose is ±6 semitones, with the drums lane deliberately left unshifted.
When it is not sure, it shows nothing rather than a guess. Nothing downstream syncs to the tempo either — it is a readout, not a clock, so a wrong number costs you a wrong label and never a wrong render.
We have the drums already, so the front end is three RMS band envelopes and a subtraction — and that is not a shortcut we are getting away with, it is the one thing this product has that a full-mix detector does not.
The key can be read in a transposing instrument's own written pitch — concert, alto/bari in E♭, or tenor/soprano in B♭ — so a horn player reads the name they would actually finger. The engine only ever sends the concert tonic; the horn and your transpose are applied once, on the way to the screen.
A version with no delay would be a version that can see the future.
Latency is inherent, not a bug. About 3.4 s behind the picture at the default hop — measured, and shown in the deck as the exact figure rather than a claim.
Audio comes from chrome.tabCapture and nothing else. No stream-URL
resolution, no yt-dlp, no player-response scraping. If your player
isn't making a sound, neither is this.
It cannot save a file. There is no downloads
permission in the manifest, and an automated CI check asserts its continued
absence on every run. This is the line between an audio tool and a ripper, and
it is enforced by the build, not by a promise.
Export specifically is not coming back, because writing a separated copy of somebody's track to disk is the thing this project exists not to do.
The model weights, once, from a pinned and hashed host. After that: no telemetry, no analytics, no error reporting, no fonts, no update pings. A full session completes with every network interface disabled — that is an acceptance test, not an aspiration.
One host for the weights is a single point of failure, and the project says so in its own documentation rather than waiting for you to find out.
This page holds itself to the same rule. No CDN, no web fonts, no analytics, no third-party anything: one HTML file and its own images. A site for a product whose headline claim is one network request cannot itself phone home.
This is a real single point of failure and we would rather name it than have you discover it.
Eleven stages, one clock. The model runs on the last 7.8 s of a rolling buffer and emits only the newest hop, which is why the delay is a property of the design rather than a defect in it.
The only context that can mint a tabCapture stream.
The engine — the only context with getUserMedia, workers, and SharedArrayBuffer.
Injects the deck and owns the page's <video>.
An extension-origin iframe. Four Manifest V3 contexts, none of them interchangeable.
The architecture is the argument rather than the promise.
Which means the next section is not marketing. It is the measurement table.
Every figure below is produced by the verification suite, against a gate that was
set before the number was known. A suite that exits 0 while asserting nothing is not
green: silence is not a pass
.
| Measurement | Result | Gate / control |
|---|---|---|
| Sample-clock round trip, capture → model → output | 1000.00 Hz | one AudioContext at 44100 Hz, no JS resampling on the live path |
| Overlap-add reconstruction, identity model | −160.6 dB | −120 dB |
| COLA error, Float32 | 3.0e-8 | 1e-6 |
| Six-source synthetic separation null | −144.5 dB | worst-single-omission control: −6.3 dB |
| Pitch shifter bypass identity | −294.5 dB | −120 dB |
| Pitch shifter alias floor | −116.9 dB | −60 dB |
| Pitch shifter passband, 40 Hz – 19 kHz | ±0.02 dB | ±0.5 dB |
| Key-lock: speed must not move pitch | ±2 cents | across all 29 rungs |
| Transpose group delay | 3072 samples | 69.66 ms, exactly, on every lane at every setting |
| Verification gates | 19 gates · 1302 assertions | 17 gates (1160 assertions) run with no browser and no weights |
| Model | htdemucs_6s | 27.4 M params · 109 MB download |
| Latency | ~3.4 s | at the default hop — measured, and displayed in the deck |
| Network requests, lifetime | 1 | the weights, once |
Because a number you cannot stand behind is worse than no number at all.
There is no Chrome Web Store listing. You load it unpacked, from source you can read.
$ git clone https://github.com/itziklerner-pag/stem-splitter-live
$ cd stem-splitter-live
$ bash tools/fetch-vendor.sh # ONNX Runtime WebGPU runtime, ~26 MB, not in git
chrome://extensions.extension/ directory.These are the extension's real bindings, and on this page they drive the demonstration deck in 03 · The surface. Press one now — the row lights up and the deck answers.
| Key | Does |
|---|---|
| 1–6 | Mute a stem — vocals, drums, bass, other, guitar, piano, left to right. |
| Shift+1–6 | Solo a stem. |
| Alt+1–6 | Reset that stem's fader to unity. |
| 0 | Unmute everything and clear the solo. |
| ? | The full list. |
| Ctrl+Shift+9 | Show or hide the deck. ⌃⇧9 on macOS |
Nothing below has a date, and anything below can be cut. Two features already were — an offline export mode and a two-deck console were both built and both removed, and the architecture appendix records what went and why, so a re-proposal starts from that rather than from scratch.
Mark a section of a track and loop it, so a phrase can be drilled rather than scrubbed back to by hand. It composes with what is already here: loop four bars, drop the vocal, take it to 0.75× in the original key.
Generate readable notation from a separated stem, so the line you are learning can be read as well as heard — and read in your own written pitch, which the key readout already knows how to do.
Two decks, for beat-matching and DJ use. This one has been built before and cut. Bringing it back is a real proposal rather than a wish, because the tempo detector and the key-locked speed control it would need are already shipping.
More beyond these. The place to argue for something, or against something here, is Discussions.
Two licences, because two different things are involved, and pretending otherwise would be the easy lie.
Take it, fork it, ship it. All of the capture, the ring buffers, the overlap-add, the pitch bank, the deck.
htdemucs_6s is Meta's, and non-commercial. They are not ours to license. The repo has never contained them; they are fetched at runtime from a pinned, hashed revision.
There is no paid tier and no plan for one, because a commercial product built on non-commercial weights would be a licence violation. That is the whole reason, stated plainly.
We could have quietly said 'MIT' and let people assume. Publishing a licence claim you cannot support is a worse problem than the constraint itself.
Stem Splitter Live was created by Itzik Lerner — the architecture, the DSP, the deck, and the 19 verification gates that keep the numbers on this page honest.
It is MIT-licensed and open, which means the next names on this list are not written yet. The contributor list is currently one name long — that is an invitation rather than a boast. CONTRIBUTING.md is where to start, and if you are touching audio, docs/AUDIO.md is normative rather than descriptive.
Everyone who lands a change gets their name here and in the repository's own contributor list. No CLA, no copyright assignment — your commits stay yours under the same MIT grant as everything else.
The separator itself is not this project's work. htdemucs_6s
is Meta's, and the ONNX Runtime build is Microsoft's;
NOTICE.md
carries the full attribution.