Stem Splitter Live
Stem Splitter Live: six coloured faders, one per stem.

One tab. Six stems. Nothing leaves.

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.

CtrlShift9 ⌃⇧9 on macOS
Install it
Model
htdemucs_6s
Runtime
ONNX Runtime Web · WebGPU
Latency
~3.4 s
Uploads
0
Network requests, lifetime
1
02Separation

One thing,
taken apart into six.

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.

In — one stereo pair, 44100 Hz Out — six stems
  • 01vocals1 · ⇧1 · ⌥1
  • 02drums2 · ⇧2 · ⌥2
  • 03bass3 · ⇧3 · ⌥3
  • 04other4 · ⇧4 · ⌥4
  • 05guitar5 · ⇧5 · ⌥5
  • 06piano6 · ⇧6 · ⌥6

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.

03The surface

Six faders,
and no audio at all.

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.

Six-channel deck Demonstration · synthetic meters · no audio
VOCALS
0.0 dB

LIVE

DRUMS
0.0 dB

LIVE

BASS
0.0 dB

LIVE

OTHER
0.0 dB

LIVE

GUITAR
0.0 dB

LIVE

PIANO
0.0 dB

LIVE

Master
Speed · key-locked
1.00×
Transpose
+0 st

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 16 to mute and Shift+16 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.

04What it works out

The key and the tempo, read off the stems themselves.

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.

from the repo
Key read from
other stem
Tempo read from
drums stem
Key resolution
16384-pt FFT, 2.69 Hz/bin
Key decided at
~2 Hz, with hysteresis
Tempo range
60 – 200 BPM
Tempo history
8 s autocorrelation
Speed
0.5× – 2.0×, 29 steps
Speed moves pitch
±2 cents, every rung
Transpose
±6 st, drums unshifted
Written pitch
concert · E♭ · B♭
Tempo drives playback
never — display only

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.

from the repo

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.

06Claim one — what it can hear

It only ever hears what your own player renders.

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.

from the repo
Audio source
chrome.tabCapture
Stream-URL resolution
none
yt-dlp / scraping
none
downloads permission
absent
Absence asserted by
CI, every run
Export feature
not coming back
Bytes uploaded
0
07Claim two — what it sends

It makes exactly one network request, ever.

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.

from the repo
Requests, lifetime
1
What it is
model weights, 109 MB
Host
pinned + hashed
Telemetry
none
Analytics
none
Error reporting
none
Web fonts
none
Update pings
none
Offline session
acceptance test
08Signal path

Everything between the tab
and your speakers.

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.

  1. 00 YouTube tab48 kHz, whatever your player is rendering
  2. 01 chrome.tabCapturethe only source of audio
  3. 02 AudioContext @ 44100 Hzthe model's native rate
  4. 03 Capture worklet → SharedArrayBuffer ring23.8 s of history, lock-free
  5. 04 Causal chunk planrun the model on the last 7.8 s, emit the last hop
  6. 05 ONNX Runtime Web + WebGPU · htdemucs_6s in (1, 2, 343980) → out (1, 6, 2, 343980)
  7. 06 Weighted overlap-add50 ms linear seam crossfade
  8. 07 14-plane stem ring6 stems × 2 ch + passthrough
  9. 08 Optional transpose±6 semitones · the drums lane is left untouched
  10. 09 Playback workletper-stem gain, mute, solo, master, soft clip, meters
  11. 10 Your speakersand nowhere else
Fig. 1 — capture to output, one AudioContext throughout
Context 1

service worker

The only context that can mint a tabCapture stream.

Context 2

offscreen document

The engine — the only context with getUserMedia, workers, and SharedArrayBuffer.

Context 3

content script

Injects the deck and owns the page's <video>.

Context 4

the deck

An extension-origin iframe. Four Manifest V3 contexts, none of them interchangeable.

The architecture is the argument rather than the promise.

from the repo

Which means the next section is not marketing. It is the measurement table.

10Receipts

Measured, gated,
and written down.

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.

Table 1 — measurement, result, gate or control
MeasurementResultGate / 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

Two numbers this project refuses to quote

Because a number you cannot stand behind is worse than no number at all.

  • Any millisecond figure from the pitch bank. Three runs of identical code swung 69 %. That is the machine, not the code, so frame counts are quoted instead.
  • Any repo-wide timing absolute. Same reason. There isn't one on this page either.
11Install

Three commands
and a folder.

There is no Chrome Web Store listing. You load it unpacked, from source you can read.

bash
$ 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
  1. Open chrome://extensions.
  2. Enable Developer mode.
  3. Choose Load unpacked and select the extension/ directory.
  4. On first run a welcome tab offers the 109 MB model download. That is the one network request.
  5. Open a YouTube video and press CtrlShift9.
Browser
Chrome 128 or newer.
Acceleration
WebGPU strongly recommended. The WASM fallback works, but blocks for seconds at a time.
Disk
~26 MB of runtime, fetched by the script; 109 MB of weights, fetched on first run.
12Keyboard

The map.

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.

Table 2 — deck shortcuts
KeyDoes
16Mute a stem — vocals, drums, bass, other, guitar, piano, left to right.
Shift+16Solo a stem.
Alt+16Reset that stem's fader to unity.
0Unmute everything and clear the solo.
?The full list.
Ctrl+Shift+9Show or hide the deck. ⌃⇧9 on macOS
13What's next

A roadmap, not a set of promises.

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.

  1. 01

    Practice loops

    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.

  2. 02

    Notation from a stem

    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.

  3. 03

    A second deck

    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.

14Licence, honestly

Free, and staying free.

Two licences, because two different things are involved, and pretending otherwise would be the easy lie.

The code

MIT

Take it, fork it, ship it. All of the capture, the ring buffers, the overlap-add, the pitch bank, the deck.

The weights

CC BY-NC 4.0

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.

The consequence

No paid tier

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.

from the repo
15Who made this

Built by Itzik Lerner.

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.

Creator
Itzik Lerner
Contributors
you, potentially
Licence, code
MIT
CLA required
none
Copyright assignment
none

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.