Production-grade audio stem separation powered by Meta's HTDemucs — built for the Prism audio engine by R13 Labs.
Split any track into 6 isolated stems (vocals, drums, bass, guitar, piano, other) through a clean web interface or REST API. Output is lossless 32-bit float WAV at 44.1 kHz.
Upload any audio file (MP3, FLAC, WAV, M4A, …) and get back six clean, lossless stems:
| Stem | What you get |
|---|---|
| Vocals | Lead and backing vocals |
| Drums | Full drum kit |
| Bass | Bass guitar / bass synth |
| Guitar | Electric and acoustic guitar |
| Piano | Piano and keyboards |
| Other | Everything else |
Each stem is delivered as a 32-bit float WAV you can play directly in the browser or download for use in your DAW.
upload ──► ffmpeg normalize ──► HTDemucs separation ──► 6 × 32-bit float WAV
(any format → (htdemucs_6s,
44.1 kHz stereo WAV) shifts=10, overlap=0.25,
rescale clipping)
The service uses Meta's HTDemucs (htdemucs_6s), a hybrid transformer/convolutional model — the best open-source separator available (~8–9 dB SDR on vocals).
This is an offline / batch preprocessing service. It is not real-time.
| Requirement | Version |
|---|---|
| Python | 3.10 or 3.11 |
| ffmpeg | bundled or system install |
| CUDA (optional) | 12.1 recommended (RTX 20xx/30xx/40xx) |
| Disk space | ~5 GB (PyTorch + model weights) |
| RAM | 4 GB minimum, 8 GB recommended |
git clone https://github.com/your-org/prism-stem-splitter.git
cd prism-stem-splitter# Windows (PowerShell)
python -m venv .venv
.\.venv\Scripts\Activate.ps1# macOS / Linux
python3 -m venv .venv
source .venv/bin/activateInstall PyTorch before the other requirements. Pick the build that matches your setup:
GPU (CUDA 12.1) — recommended
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu121GPU (CUDA 12.4 / 12.8)
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu124
# or cu128CPU only (works, but 4–6× slower)
pip install torch torchaudioOn Windows,
pip install torchwithout an index URL gives you a CPU-only build — always use the--index-urlflag if you have an NVIDIA GPU.
pip install -r requirements.txtOption A — bundle it (recommended, no system install needed)
Download a static ffmpeg build and place the binary at ./ffmpeg/ffmpeg.exe (Windows) or ./ffmpeg/ffmpeg (Mac/Linux). config.py will find it automatically.
- Windows: BtbN FFmpeg builds →
ffmpeg-master-latest-win64-gpl.zip - macOS:
brew install ffmpeg - Linux:
sudo apt install ffmpeg
Option B — system install
Make sure ffmpeg is on your PATH. config.py falls back to a PATH lookup automatically.
uvicorn main:app --host 0.0.0.0 --port 8000The first run downloads the htdemucs_6s model weights (~320 MB) and caches them under ~/.cache/torch/hub. Subsequent starts are instant.
http://localhost:8000
The built-in interface runs entirely in the browser — no extra front-end toolchain needed.
Workflow:
- Drop a file onto the upload zone (or click to browse)
- Click Split into Stems
- Watch the progress bar and stem checklist fill in as each stem completes
- Play each stem directly in the browser, or click Download WAV to save it
The badge in the top-right corner shows the active compute device (GPU · CUDA, GPU · MPS, or CPU) so you always know how fast the job will run.
The web interface uses the same endpoints under the hood. You can drive the service programmatically with any HTTP client.
Returns service info and the active compute device.
curl http://localhost:8000/health{
"service": "prism-stem-splitter",
"model": "htdemucs_6s",
"device": "cuda",
"stems": ["vocals", "drums", "bass", "guitar", "piano", "other"]
}Upload an audio file. Returns a job_id immediately; separation runs in the background.
curl -X POST http://localhost:8000/split -F "file=@song.mp3"{ "job_id": "a1b2c3d4...", "status": "queued" }Poll for progress. progress runs from 0.0 to 1.0. When status is complete, the response includes a stems map of download URLs.
curl http://localhost:8000/status/a1b2c3d4{
"job_id": "a1b2c3d4",
"status": "complete",
"progress": 1.0,
"stems_done": ["vocals", "drums", "bass", "guitar", "piano", "other"],
"error": null,
"stems": {
"vocals": "/download/a1b2c3d4/vocals",
"drums": "/download/a1b2c3d4/drums",
"bass": "/download/a1b2c3d4/bass",
"guitar": "/download/a1b2c3d4/guitar",
"piano": "/download/a1b2c3d4/piano",
"other": "/download/a1b2c3d4/other"
}
}status values: queued → processing → complete (or failed, with the reason in error).
Stream a finished stem as a 32-bit float WAV file.
# Linux / macOS / Git Bash
curl -O -J http://localhost:8000/download/a1b2c3d4/vocals
# Windows PowerShell — use curl.exe to avoid the Invoke-WebRequest alias
curl.exe -O -J http://localhost:8000/download/a1b2c3d4/vocalsAll tunable constants live in config.py:
| Constant | Default | Effect |
|---|---|---|
MODEL_NAME |
htdemucs_6s |
HTDemucs model variant |
SHIFTS |
10 |
Time-shift ensemble passes — higher = better quality, slower |
OVERLAP |
0.25 |
Chunk overlap — reduces boundary artifacts |
CLIP_MODE |
rescale |
Clipping prevention strategy |
OUTPUT_SR |
44100 |
Output sample rate (Hz) |
MAX_CONCURRENT_JOBS |
2 |
Maximum parallel separation jobs |
OUTPUT_DIR |
./outputs |
Directory for per-job stem WAVs |
Speed vs. quality trade-off: Reduce SHIFTS from 10 to 2 for ~5× faster processing at slightly lower quality. This is useful for previewing or high-volume batch jobs.
| Scenario | Time (3-min track) |
|---|---|
| CPU only | ~4–6 min |
| GPU — RTX 2060 (CUDA) | ~30–60 s |
| GPU — RTX 3080+ | ~15–25 s |
Separation quality (HTDemucs 6s, shifts=10):
| Metric | Value |
|---|---|
| SDR — Vocals | ~8–9 dB |
| SDR — Drums | ~7–8 dB |
| Output format | 32-bit float WAV, 44.1 kHz |
prism-stem-splitter/
├── main.py # FastAPI app — routes, job queue, upload/download
├── splitter.py # HTDemucs separation (device detection, model cache)
├── audio_utils.py # ffmpeg normalization, peak normalize, silence trim
├── config.py # All tunable constants and ffmpeg path resolution
├── requirements.txt
├── README.md
├── static/
│ ├── index.html # Single-page web interface
│ ├── style.css # R13 Labs design system (green accent, light theme)
│ ├── app.js # Upload, polling, stem player / download UI logic
│ └── r13-labs-logo.jpeg
├── ffmpeg/ # Bundled ffmpeg binary (optional — ignored by git)
└── outputs/ # Created at runtime — per-job stem WAV files
splitter.py auto-detects the best available device in order: CUDA → Apple MPS → CPU. No code changes are needed — you only need a CUDA-enabled PyTorch build.
Verify CUDA is available:
python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
# Expected: True NVIDIA GeForce RTX ...Check the active device via the health endpoint:
curl http://localhost:8000/health
# "device": "cuda" ← GPU acceleration confirmedRuntimeError: Couldn't find appropriate backend to handle uri
Install the soundfile backend for torchaudio (required on Windows):
pip install soundfileModel weights not downloading
The first run fetches ~320 MB from Meta's servers. If you're behind a proxy, set HTTPS_PROXY before starting uvicorn.
Slow on CPU
Lower SHIFTS in config.py from 10 to 2 for faster (but slightly lower quality) output. Install a CUDA build of PyTorch for full GPU acceleration.
Port already in use
Change the port: uvicorn main:app --host 0.0.0.0 --port 8080
- HTDemucs — Meta AI's state-of-the-art hybrid source separation model
- FastAPI — high-performance Python web framework
- PyTorch — deep learning backend with CUDA support
- torchaudio — audio I/O and processing
- ffmpeg — universal audio format conversion
This project is released under the MIT License. See LICENSE for details.
HTDemucs model weights are subject to Meta's model license.
Built by R13 Labs for the Prism audio engine.