feedBack-Demucs-Server

feedBack-Demucs-Server

Docker app from joeygatorhands' Repository

Overview

A standalone GPU-accelerated companion server for feedBack. Offloads PyTorch/Demucs stem-splitting, Whisper lyrics alignment, and pitch extraction tasks to a separate CUDA-capable GPU. IMPORTANT: On first launch, this container will download several large AI model weights (Roformer, Whisper, Crepe), which requires 9GB+ of disk space and can take several minutes depending on your internet speed. Please be patient. GPU PASSTHROUGH: To enable GPU acceleration, you must have the Unraid NVIDIA Driver plugin installed and add --gpus all to your Extra Parameters.

Slopsmith Demucs Server

A lightweight GPU-accelerated service providing AI source separation, lyrics alignment, and per-syllable pitch extraction for Slopsmith. Designed to run on a desktop with a CUDA GPU while Slopsmith runs on a NAS or Docker host.

Docker Build

Features

Source Separation (POST /separate)

Splits audio into individual stems using Demucs:

  • Default model: htdemucs_ft (4-stem fine-tuned: drums, bass, vocals, other)
  • Other models selectable per-request: htdemucs_6s (6-stem incl. guitar/piano), mdx_extra (lighter)
  • bs_roformer_sw — BS-Roformer-SW (6-stem: vocals/drums/bass/guitar/piano/other), via audio-separator. Higher SDR than Demucs (notably bass/guitar) with far less cross-stem bleed; checkpoint (~700 MB) lazy-downloads on first use to <cache>/_roformer-models/. Stems returned as lossless FLAC.
  • File upload or URL input
  • Per-stem caching, keyed by audio and model (avoids re-processing; same song under two models caches separately)
  • WebSocket progress updates

Lyrics Transcription (POST /transcribe)

Transcribe sung audio to word-level timed lyrics — no lyrics supplied. Whisper hears the words; wav2vec2 then force-aligns Whisper's own transcript, giving timestamps far tighter than Whisper's segment boundaries (a chart built from raw Whisper segments sits visibly late).

  • Answers the question /align can't: what are the lyrics, and when is each word sung?
  • Automatic language detection (or manual hint)
  • An instrumental track transcribes to {"segments": []} — that's an answer, not an error

Lyrics Alignment (POST /align)

Forced alignment of plain text lyrics against an audio file using WhisperX — Whisper transcription plus a wav2vec2 forced aligner for tighter sub-word timestamps:

  • Line, word, syllable, or phoneme granularity
  • Phoneme/character-level CTC alignment via wav2vec2 (per-language model)
  • Syllable splitting layered on word output via pyphen hyphenation (CJK character support)
  • Automatic language detection (or manual language hint)
  • Used by the Lyrics Sync plugin and the Lyrics Karaoke plugin

Per-syllable Pitch Extraction (POST /pitch)

Estimates one MIDI note per syllable from a vocals stem using CREPE via torchcrepe. Powers the karaoke pitch chart in the Lyrics Karaoke plugin:

  • CREPE neural pitch tracker — order-of-magnitude fewer octave errors than pYIN
  • Confidence-weighted mode-of-semitone aggregation per syllable
  • Song-wide range narrowing (clamps each syllable to ±12 semitones around the median)
  • Octave-error correction against the song-wide median
  • Neighbour-borrowed pitch for tokens CREPE can't lock (so whispered phrases still get bars)

Setup

Requirements

  • Python 3.10+
  • CUDA-capable GPU (recommended) or CPU fallback
  • FFmpeg (apt install ffmpeg / brew install ffmpeg)

Install (Native)

git clone https://github.com/got-feedback/feedback-demucs-server.git
cd feedback-demucs-server
python -m venv .venv
source .venv/bin/activate

# Step 1: Install main dependencies (fastapi, whisperx, torchcrepe, etc.)
# whisperx pins torch~=2.8.0 + torchaudio~=2.8.0
pip install -r requirements.txt

# Step 2: Install audio-separator SEPARATELY (diffq source-build workaround)
# Its deps pull in `diffq`, which has no wheel for Python 3.11+ and would try to
# compile from source. Its real deps are already in requirements.txt.
pip install "audio-separator>=0.44.0" --no-deps

# Step 3: Install demucs SEPARATELY (torchaudio version conflict workaround)
# demucs requires torchaudio<2.1, which conflicts with whisperx.
# Installing with --no-deps bypasses the bad pin.
# dora-search is demucs's logging lib (imported as `import dora`).
pip install demucs --no-deps
pip install einops julius lameenc openunmix pyyaml tqdm dora-search sphn

# Step 4 (optional): diffq, for QUANTIZED demucs checkpoints only.
# --only-binary=:all: makes pip fail rather than fall back to the sdist, so this can
# never start a compile.
#
# No `|| true` here on purpose: that would hide a network/index/permissions failure too,
# and you would think diffq was installed when it isn't. Let it fail loudly, and skip it
# ONLY if pip says "No matching distribution found" / "Could not find a version that
# satisfies" — that means no wheel exists for your Python (macOS on 3.11+, Linux on 3.13),
# which is safe: the bs_roformer_sw model feedBack splits with does not use diffq.
pip install "diffq-fixed>=0.2" --no-deps --only-binary=:all:

⚠️ Why the separate install steps?

demucs (PyPI 4.0.1) pins torchaudio<2.1 while whisperx needs torchaudio~=2.8.0. These are incompatible. Installing demucs with --no-deps avoids the conflict. Demucs works fine with modern torchaudio — only the save_audio function had issues, and that's patched in run_demucs.py to use soundfile instead.

audio-separator declares diffq (>=0.2); sys_platform != "win32". diffq is a C-extension whose newest wheels stop at cp310 — so on any Python 3.11+ pip falls back to its sdist and needs a C compiler. That is why this is not in requirements.txt: pip install -r resolves that file first, so the compile would fail before the --no-deps step could run. (Windows escapes this by accident: it resolves to diffq-fixed, which does ship modern wheels.) audio-separator's real runtime deps are listed in requirements.txt instead, and it is installed on top with --no-deps.

Run

python server.py --port 7865

Options:

Flag Default Description
--port 7865 Port to listen on
--host 0.0.0.0 Host to bind to
--model htdemucs_ft Demucs model (htdemucs_ft, htdemucs_6s, mdx_extra)
--device auto Force cpu or cuda
--api-key API key for authentication
--skip-warmup Skip startup model-weight prefetch

Environment variables override CLI defaults: SLOPSMITH_DEMUCS_MODEL, SLOPSMITH_DEMUCS_DEVICE, SLOPSMITH_API_KEY.

First-start model weight download

On first start the server pre-downloads model weights (~1.5 GB for all three endpoints: htdemucs_ft, Whisper medium, CREPE full, English wav2vec2). Subsequent restarts use cached weights.

The download runs in a background thread, so /health is queryable immediately. Each library prints its own tqdm progress bar.

/health reports per-model status:

{
  "status": "ok",
  "warmup": {
    "demucs": "ready",
    "whisperx": "downloading",
    "crepe": "pending",
    "whisperx_aligners": { "en": "ready" }
  }
}

States: pendingdownloadingready | failed: <reason> | skipped | evicted.

Pass --skip-warmup for environments without internet access.

Run as a systemd service

  1. Copy and edit the service file:
cp slopsmith-demucs.service ~/.config/systemd/user/
# Edit ~/.config/systemd/user/slopsmith-demucs.service
# Set User, ExecStart paths to match your setup
nano ~/.config/systemd/user/slopsmith-demucs.service
  1. Enable and start:
systemctl --user daemon-reload
systemctl --user enable slopsmith-demucs
systemctl --user start slopsmith-demucs
  1. Monitor:
journalctl --user -u slopsmith-demucs --follow

Docker

Build

docker build -t slopsmith-demucs-server .

Run (CPU)

docker run -p 7865:7865 slopsmith-demucs-server

Run (GPU)

Requires nvidia-container-toolkit:

docker run --gpus all -p 7865:7865 slopsmith-demucs-server

Docker Compose

# Pull from GHCR and run (CPU)
docker compose up -d

# GPU mode: uncomment `gpus: all` in the compose file (needs nvidia-container-toolkit;
# Linux or Windows/WSL2 only — macOS cannot pass a GPU through at all)
docker compose up -d

⚠️ Ran an image from before 2026-07-12? Delete the cache volume.

Early images created their model-cache volume owned by root, while the server runs as an unprivileged user (uid 10001). The container would start and then immediately die with

PermissionError: [Errno 13] Permission denied: '/app/cache/_roformer-models'

...which restart: unless-stopped turns into a crash-loop.

The image is fixed — but pulling the new image is not enough on its own. Docker sets a volume's ownership only when it first creates it, so a volume made by an older image stays root-owned forever and will keep crash-looping on a perfectly good image. Remove it:

docker compose down
docker volume rm feedback-demucs-cache   # or: slopsmith-demucs-server_demucs-cache
docker compose up -d

The volume only holds cached model weights — deleting it costs you a re-download, nothing else.

Persistent model cache

Model weights are stored in /app/cache inside the container. The compose file maps this to a persistent volume so weights survive restarts:

docker compose down    # cache preserved
docker compose down -v # cache deleted (if using named volume)

To use a custom host path instead of a named volume (e.g. for Portainer or to save space on a specific drive), replace the volume in docker-compose.yml:

volumes:
  - /home/AI/slopsmith-demucs-cache:/app/cache

Then copy the existing cache to the new location:

# Find old volume path
docker volume inspect slopsmith-demucs-server_demucs-cache
# Copy to new location
sudo cp -a /var/lib/docker/volumes/slopsmith-demucs-server_demucs-cache/_data/. /home/AI/slopsmith-demucs-cache/

Cache environment variables (all redirect to /app/cache to prevent container root disk exhaustion):

Variable Purpose
SLOPSMITH_DEMUCS_CACHE Server cache root
HF_HOME HuggingFace model cache
TORCH_HOME PyTorch hub cache
HUGGINGFACE_HUB_CACHE HuggingFace hub downloads

Auto-update

The container can automatically check for repository updates and restart. Disabled by default (safe for Portainer/deployments without .git access).

To enable:

  1. Uncomment the .git bind mount in docker-compose.yml
  2. Set AUTO_UPDATE=true in environment
  3. Redeploy

How it works:

  1. A background daemon runs inside the container
  2. Every UPDATE_CHECK_INTERVAL seconds (default: 3600 = 1 hour), it checks if the current time matches UPDATE_TIME (default: 04:00)
  3. At the configured time, it runs git fetch origin and compares HEAD with @{upstream}
  4. If changes are detected, it pulls the new code, reinstalls dependencies, and gracefully restarts the server

Configuration via environment variables:

Variable Default Description
AUTO_UPDATE false Enable/disable auto-update
UPDATE_TIME 04:00 Time of day to check (HH:MM, 24h)
UPDATE_CHECK_INTERVAL 3600 Seconds between time checks (3600 = 1 hour)
SKIP_WARMUP false Skip model weight download on startup
SLOPSMITH_DEMUCS_MODEL Override default Demucs model
SLOPSMITH_API_KEY API authentication key
CACHE_TTL 24h Cache cleanup TTL (1h, 12h, 24h, or NEVER to disable auto-cleanup)

Disable auto-update (default — safe for Portainer):

docker run -e AUTO_UPDATE=false -p 7865:7865 slopsmith-demucs-server

Cache cleanup

The server automatically deletes old stem cache directories to prevent disk growth. A background thread runs every 10 minutes, checks each stem cache directory under SLOPSMITH_DEMUCS_CACHE, and removes directories older than CACHE_TTL.

Model weight caches (torch/, huggingface/, locale/) are never deleted — only the stem output cache is cleaned.

Variable Default Description
CACHE_TTL 24h Maximum age of cache entries (1h, 12h, 24h, or NEVER to disable)

Disable auto-cleanup:

docker run -e CACHE_TTL=NEVER -p 7865:7865 slopsmith-demucs-server

Set custom TTL (e.g. 12 hours):

docker run -e CACHE_TTL=12h -p 7865:7865 slopsmith-demucs-server

GitHub Container Registry (CI)

The CI workflow (.github/workflows/docker-build.yml) automatically builds the Docker image, pushes it to GHCR, generates an SBOM, and runs a grype vulnerability scan on every push to main.

To enable on your fork:

  1. Go to your fork on GitHub → Actions tab
  2. Click "I understand my workflows, go ahead and enable them"
  3. Push to main — the CI builds and scans automatically

Pull the latest image:

docker pull ghcr.io/YOUR_GITHUB_USER/slopsmith-demucs-server:latest

Or from the upstream repo (once PR is merged):

docker pull ghcr.io/byrongamatos/slopsmith-demucs-server:latest

Build directly from git (no clone needed):

# From upstream main
docker build -t slopsmith-demucs-server https://github.com/byrongamatos/slopsmith-demucs-server.git#main

# From your fork
docker build -t slopsmith-demucs-server https://github.com/YOUR_USER/slopsmith-demucs-server.git#main

# Run it
docker run --gpus all -p 7865:7865 slopsmith-demucs-server

Run via Docker Compose with git build:

services:
  slopsmith-demucs:
    build: https://github.com/byrongamatos/slopsmith-demucs-server.git#main
    ports:
      - "7865:7865"

API

GET /health

Returns server status, model, GPU availability, cache directory, and per-model warmup state (see First-start model weight download).

POST /separate

Separate audio into stems.

Parameter Type Description
file Upload Audio file
stems Query Comma-separated stem names (default: drums,bass,vocals,other)
model Query Override model (optional)

POST /transcribe

Transcribe sung audio to word-level timed lyrics using WhisperX (faster-whisper ASR + wav2vec2 forced alignment of its own transcript). Use this when you do not have the lyrics; use /align when you do.

Parameter Type Description
file Form (file) Audio file (vocals stem)
language Form ISO 639-1/2 language code hint, e.g. en, es, pt (optional, auto-detected). Case-insensitive — the value is trimmed and lowercased before validation, so EN and en both work. Must then be 2–8 letters; subtags like en-US are rejected (400) because the hyphen is not a letter.

Returns native WhisperX alignment output:

{"segments": [{"start": 12.3, "end": 15.1, "text": "hello world",
               "words": [{"word": "hello", "start": 12.3, "end": 12.8, "score": 0.94}]}],
 "language": "en"}

A stem with no singing in it returns {"segments": [], "language": "en"} with a 200 — an instrumental is a valid answer, not a failed request.

POST /align

Forced-align lyrics against audio using WhisperX (faster-whisper transcription + wav2vec2 forced aligner).

Parameter Type Description
file Form (file) Audio file (vocals stem)
text Form Plain text lyrics
language Form ISO 639-1/2 language code hint, e.g. en, es, pt (optional, auto-detected). Case-insensitive — the value is trimmed and lowercased before validation, so EN and en both work. Must then be 2–8 letters; subtags like en-US are rejected (400) because the hyphen is not a letter.
granularity Form line (default), word, syllable, or phoneme

Granularity behaviour:

  • line — segment-level boundaries.
  • word — wav2vec2-aligned word timestamps. The first entry in each line carries new_line: true.
  • syllableword output split via pyphen; carries new_line on the first syllable of each line.
  • phoneme — character-level CTC token timestamps from the aligner. Each entry carries phoneme: true. With wav2vec2 character models these are letter-aligned; with phoneme-trained models they're true phonemes.

Returns: {"segments": [...], "language": "en"} where each segment is {start, end, text, ...}.

POST /pitch

Per-syllable pitch extraction using CREPE.

Parameter Type Description
file Form (file) Vocals stem (any format librosa can read)
lyrics Form JSON array of {"t": float, "d": float} — token start / duration in seconds

Returns: {"notes": [{"t": 12.34, "d": 0.5, "midi": 64}, ...]}. Tokens for which no pitch could be estimated (even after neighbour-borrow) are omitted.

GET /download/{job_id}/{stem}

Download a separated stem by job ID.

GET /jobs / GET /jobs/{job_id}

List or inspect separation jobs.

WS /ws/jobs/{job_id}

WebSocket for real-time separation progress updates.

Configure in Slopsmith

Set the Demucs Server URL to http://<your-server-ip>:7865 in Slopsmith settings.

License

AGPL-3.0-only — the same license as the feedBack app this server exists to serve, and as the plugins that call it. See LICENSE.

Install feedBack-Demucs-Server on Unraid in a few clicks.

Find feedBack-Demucs-Server in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for feedBack-Demucs-Server Review the template variables and paths Click Install

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/got-feedback/feedback-demucs-server:latest
Last Updated2026-07-17
First Seen2026-07-15

Runtime arguments

Web UI
http://[IP]:[PORT:7865]
Network
bridge
Privileged
false
Extra Params
--user 0:0

Template configuration

API PortPorttcp

The port for the Demucs Server REST API (defaulted to 8020)

Target
7865
Default
8020
Value
8020
Cache DirectoryPathrw

Location for downloaded model weights (Demucs, Whisper, Crepe) and transient audio caches.

Target
/app/cache
Default
/mnt/user/appdata/feedback-demucs-server
Value
/mnt/user/appdata/feedback-demucs-server
Demucs ModelVariable

The default Demucs separation model (e.g., htdemucs_ft, htdemucs, htdemucs_6s).

Target
SLOPSMITH_DEMUCS_MODEL
Default
htdemucs_ft
Value
htdemucs_ft
DeviceVariable

Optional: The device PyTorch should use (e.g., cuda, cpu). Leave blank to auto-detect Nvidia GPU.

Target
SLOPSMITH_DEMUCS_DEVICE
API KeyVariable

Optional: API authentication key to secure the Demucs server endpoints.

Target
SLOPSMITH_API_KEY
Cache TTLVariable

Maximum age of transient audio/stems cache folders before deletion (e.g., 1h, 12h, 24h, or NEVER to disable auto-cleanup).

Target
CACHE_TTL
Default
24h
Value
24h
Skip WarmupVariable

Set to true to skip downloading AI model weights on container startup. (Weights will instead download on-demand on the first request).

Target
SKIP_WARMUP
Default
false
Value
false
Cache Directory EnvVariable

Internal application cache root directory.

Target
SLOPSMITH_DEMUCS_CACHE
Default
/app/cache
Value
/app/cache
HuggingFace Cache LocationVariable

Redirects HuggingFace models to the persistent cache directory.

Target
HF_HOME
Default
/app/cache/huggingface
Value
/app/cache/huggingface
PyTorch Cache LocationVariable

Redirects PyTorch models to the persistent cache directory.

Target
TORCH_HOME
Default
/app/cache/torch
Value
/app/cache/torch
HuggingFace Hub Cache LocationVariable

Redirects HuggingFace hub downloads to the persistent cache directory.

Target
HUGGINGFACE_HUB_CACHE
Default
/app/cache/huggingface/hub
Value
/app/cache/huggingface/hub
Auto UpdateVariable

Enables auto-updates of server files at the configured update time (Requires .git mount).

Target
AUTO_UPDATE
Default
false
Value
false
Update TimeVariable

Daily time check for updates (HH:MM format).

Target
UPDATE_TIME
Default
04:00
Value
04:00
Update Check IntervalVariable

Seconds between daily time check sweeps.

Target
UPDATE_CHECK_INTERVAL
Default
3600
Value
3600
PORT EnvVariable

Internal port the Demucs server listens to inside the container.

Target
PORT
Default
7865
Value
7865