MANUAL · 13
Beyond mood and energy tags, SUB/WAVE can listen to each track and measure how it actually sounds — tempo, key, loudness, and, optionally, a 'sounds-like' fingerprint and where the vocals sit. The DJ leans on these to build smoother, better-matched sets. The basics run out of the box; the heavier dimensions are one line away.
WHAT IT MEASURES
The analyzer is a small service that ships and starts by defaultalongside the controller — no profile, no flag. It measures each track’s tempo (BPM), musical key, intro length and loudness, and hands them to the DJ as tie-breakers for smoother transitions: a tempo-matched, harmonically-close next track, and the right window to talk over an intro.
The default image is lean — librosa only, no PyTorch — so it stays small and runs natively on both amd64 and arm64 (a NAS, a Pi, Apple Silicon). Coverage climbs on the Library page under Acoustic analysis · bpm / key.
The acoustic-engine indicator is a live reachability check, not a saved setting. If the analyzer container is stopped, existing data still drives picks — only new analysis pauses until it’s back.
THE HEAVY TIER
Two richer dimensions need a heavier model stack (CPU PyTorch — roughly +0.8 GB of image over the lean default), so they are not in the default analyzer:
Both live in a separate subwave-analyzer-heavy image. If you turn on Audio fingerprint or Vocal activityon the Library page while running the lean analyzer, you’ll see a note that the engine can’t produce them — that’s the cue to switch to the heavy image below. (This is entirely separate from the tts-heavy voices sidecar, which is TTS-only.)
ENABLING IT
Set the switch in your root .env and recreate the analyzer — Compose re-pulls it as subwave-analyzer-heavy:
# root .env
ANALYZER_HEAVY=1docker compose up -d analyzerBy install type:
.env and run docker compose up -d analyzer. The subwave setup wizard also offers it.ANALYZER_HEAVY=1 to your .env, Save, then Pull & Up.ghcr.io/perminder-klair/subwave-aio-heavy and re-pull.The heavy image is amd64-only (the CPU-torch stack). On an arm64 host (Pi, Apple Silicon, arm cloud) also set DOCKER_DEFAULT_PLATFORM=linux/amd64 — it runs under emulation (slower, but analysis is a one-time per-track pass).
Model weights download lazily into the analyzer’s cache the first time you run a sounds-like / vocals pass. Once the heavy analyzer is up, enable the dimensions on the Library page and run a backfill.
ON AN NVIDIA GPU
Hosts with an NVIDIA card can run the heavy stack on the GPU instead of pinning CPU cores — a big speed-up on deep library ingestion. It’s a compose overlay, not an .envtoggle (a GPU reservation can’t be switched from .env):
docker compose -f docker-compose.yml -f docker-compose.analyzer-gpu.yml up -dThat swaps the analyzer to the subwave-analyzer-cuda image — everything -heavy does, on CUDA — so ANALYZER_HEAVYis unnecessary while the overlay is applied. Requirements: the NVIDIA driver + Container Toolkit on the host, nothing else (the CUDA runtime rides inside the image). If the GPU isn’t actually visible, the worker logs a warning and falls back to CPU — analysis never fails over device selection.
Point the analyzer container’s image at ghcr.io/perminder-klair/subwave-analyzer-cuda and pass the GPU through (--gpus allor your platform’s equivalent). The AIO one-click container stays CPU-only — GPU analysis needs the split stack.
Sharing the card with a local TTS or LLM? After ~5 idle minutes the worker drops its models out of VRAM and reloads them on the next request (ANALYZE_IDLE_UNLOAD_S tunes the window; 0 keeps them resident). Pair it with Quiet times below and a long scan frees the GPU whenever listeners are tuned in.
QUIET TIMES
A bulk pass over a large library runs for hours, and on a homelab it competes with local LLM / TTS — and the stream itself — for the same CPU or GPU. Quiet times (off by default, on the Library page next to the sounds-like and vocal controls) pauses any analysis run while someone is listening, and resumes once the stream has had no listeners for the configured window (default 10 minutes).
The gate checks between tracks, so a listener tuning in pauses the pass within ~30 seconds; the running view shows “Waiting for quiet” while it holds. It applies to manual Analyseruns too — a pass outlives the click, so the bypass is turning the toggle off, not the button. If the listener count can’t be read at all (Icecast down), analysis proceeds — a stats outage never stalls a library scan.