Releases: stemdeckapp/stemdeck
v0.4.0-alpha.1
macOS Native App
StemDeck is now available as a native macOS application (.dmg) for both Apple Silicon and Intel Macs.
What's new
-
Native macOS app
Built with Tauri 2, including a first-launch setup wizard that automatically downloads and installs a self-contained backend runtime. No Python or system dependencies required. -
Apple Silicon acceleration (MPS)
Stem separation uses Metal Performance Shaders on M1 and newer Macs for significantly improved performance. -
arm64 + x64 builds
Separate native builds are available for both Apple Silicon and Intel architectures. -
Backend watchdog
The Python backend process is automatically terminated if the desktop shell exits unexpectedly.
Downloads
| File | Platform | Acceleration |
|---|---|---|
StemDeck-macOS-arm64.dmg |
macOS Apple Silicon (M1/M2/M3/M4) | Metal (MPS) |
StemDeck-macOS-x64.dmg |
macOS Intel | CPU |
StemDeck-Windows-x64.zip |
Windows | CPU |
StemDeck-Windows-x64.NVIDIA.zip |
Windows + NVIDIA GPU | CUDA |
The
.tar.zstfiles are internal runtime packages and are not required for normal installation.
Installation
macOS
- Download the correct
.dmgfile for your Mac - Open the DMG
- Drag StemDeck.app into the Applications folder
- Launch StemDeck
On first launch, StemDeck automatically downloads:
- Backend runtime
- FFmpeg
- Demucs model files
Approximate first-time download size: ~170 MB
Subsequent launches start in seconds.
Gatekeeper Warning (macOS)
Because the application is currently unsigned, macOS may display a security warning on first launch.
To open the app:
- Right click
StemDeck.app - Select Open
- Confirm by clicking Open again
Alternatively:
- Open System Settings → Privacy & Security
- Click Open Anyway
CI / Build Pipeline
- macOS arm64 and x64 packages were built and validated on a macOS Woodpecker CI agent before release upload.
- Windows packages were scanned with ClamAV during CI before publication.
v0.3.0-alpha.1
What's changed
Local MP3 and WAV file import
You can now process local audio files directly. Drag and drop an .mp3 or .wav file onto the import bar, or use the file picker — no YouTube URL required. The file goes through the same pipeline as a URL: stem separation, BPM and key analysis, LUFS measurement, and the full DAW player. Files up to 100 MB are accepted. Stem selection chips and all mixer and download features work identically.
URL and filename persist after app restart
When you load a track from the library, the original URL or filename now appears in the import bar. Previously this was lost on every Windows restart because the source address was stored only in session memory. It is now stored server-side and survives restarts. YouTube tracks show the full URL so you can change the stem selection and reprocess; local file tracks show the filename as a reference.
Fix release notes being overwritten with "System.Object[]"
The Windows release pipeline was reading the existing release body into a PowerShell variable. PowerShell captured the output as a String[] array, and converting it to a string produced the literal text System.Object[], replacing hand-written notes. Fixed by joining the array before string operations.
Artifact scan
Windows portable packages were scanned with ClamAV in CI before upload.
v0.2.0-alpha.7
What's changed
Store user data in %LocalAppData%\StemDeck (#25)
The Windows desktop app now keeps all mutable data (models, jobs, FFmpeg, logs) in %LocalAppData%\StemDeck instead of the install folder. This means your library and downloaded models survive across releases — no more copying a data/ folder when you unzip a new version.
On first launch after upgrading from alpha.6, existing data is automatically migrated via a same-volume move (instant, no copying).
Fix drag-and-drop to folders on Windows (#24)
Tracks could not be dragged to library folders in the Windows desktop app. Two issues were fixed:
dragDropEnabled: falseis now set intauri.conf.jsonso WebView2 no longer intercepts OS-level drag events at the Win32 layer, allowing HTML5dragover/dropto fire correctly.- The catalog rail panel background was not filling the full panel height in the collapsed state, causing
catalog-mainto wrap to an implicit grid row. Fixed with explicitgrid-template-rows: 1frand grid placement. dropOnFolderandgetDraggedTrackIdnow accept an explicittrackIdparameter and atext/plaindataTransfer fallback for cross-origin drag in WebView2.- Tracks can now be dragged from the trash back to the Library rail button.
Artifact scan
- Windows portable packages were scanned with ClamAV in CI before upload.
v0.2.0-alpha.6
What's changed
Fix drag-and-drop to folders on Windows (#23)
Tracks could not be dragged to library folders in the Windows desktop app. On WebView2, the dragover handler was gating e.preventDefault() behind a module-level dragId variable that can be null mid-drag — causing the browser to reject the drop. Fixed by checking e.dataTransfer.types for the custom MIME type instead, which is reliably populated during dragover on all browsers including WebView2.
Fix SSL errors when downloading model weights on macOS (#22)
Demucs failed with CERTIFICATE_VERIFY_FAILED on first run when using a Python.org install on macOS, which does not link to the system SSL store. Fixed by injecting SSL_CERT_FILE and REQUESTS_CA_BUNDLE pointing to certifi's CA bundle into the demucs subprocess environment before spawning it.
Artifact scan
- Windows portable packages were scanned with ClamAV in CI before upload.
v0.2.0-alpha.5
Summary
- Appbar collapses to a compact horizontal icon strip on double-click (same
grid-template-rowsanimation as widget sections); auto-collapses when a track finishes processing - Collapsed strip shows:
SDmonogram · URL icon · per-stem colored squares (active/inactive state) · Process button — all clickable - Clicking stem squares toggles selection; Process submits if URL is already set, otherwise expands; SD/URL icon always expands
- Brand subtitle shortened to "AI stem separation"
- Version label (
v0.1.0) added to brand area with optional green "New release available" chip that fetches the latest tag from the GitHub releases API on load - Fixed footer button underline and icon sizing
Artifact scan
- Windows portable packages were scanned with ClamAV in CI before upload.
v0.2.0-alpha.4
Summary
- Appbar collapses to a compact horizontal icon strip on double-click (same
grid-template-rowsanimation as widget sections); auto-collapses when a track finishes processing - Collapsed strip shows:
SDmonogram · URL icon · per-stem colored squares (active/inactive state) · Process button — all clickable - Clicking stem squares toggles selection; Process submits if URL is already set, otherwise expands; SD/URL icon always expands
- Brand subtitle shortened to "AI stem separation"
- Version label (
v0.1.0) added to brand area with optional green "New release available" chip that fetches the latest tag from the GitHub releases API on load - Fixed footer button underline and icon sizing
Artifact scan
- Windows portable packages were scanned with ClamAV in CI before upload.
v0.2.0-alpha.3
This release is a major UI overhaul — new DAW-style mixer, song catalog panel, collapsible appbar, and a large number of UX fixes across the player, transport, and import flow.
What's new
DAW-style mixer
The stem mixer has been completely redesigned. Each stem row now uses a horizontal DAW layout: waveform icon → stem name → fader → VU meter → dB value → Mute → Solo → Download.
- Fader renders as a styled range input with stem-colored fill and a circular thumb. Boost above 0 dB works — each stem routes through a Web Audio
GainNodeinstead ofHTMLAudioElement.volume, which is capped at 1.0 by the browser. - VU meter shows a real-time level bar driven by a pre-computed RMS envelope — no
AnalyserNodeorrequestAnimationFrameneeded. The bar fills left-to-right with a gradient that tips into red on loud passages. - Solo button lights up gold when active; soloing any stem silences the rest.
- Mute button turns red and stays fully visible when active (previously it faded out along with the dimmed row, making it hard to see the muted state).
- Download button opens the stem file in the system browser, including in the Tauri desktop app where native
<a download>was previously silently blocked.
Song catalog
A new catalog panel on the left sidebar shows the history of processed tracks.
- Tracks are listed with thumbnail, title, duration, and stem count.
- Click any entry to instantly reload that track into the player without re-processing.
- Tracks can be organised into colour-coded folders via drag-and-drop.
- A search bar filters by title.
- The panel collapses to a thumbnail strip to save space.
Collapsible appbar
The import bar at the top now collapses to a compact icon strip on double-click, using the same grid-template-rows: 0fr ↔ 1fr animation as the widget sections. It auto-collapses when a track finishes processing so the waveform gets full vertical space.
The collapsed strip contains:
- SD monogram — expands the appbar
- URL icon — expands the appbar
- Per-stem coloured squares — show active/inactive state; click to toggle stem selection without expanding
- Process button — submits the job if a URL or file is set; otherwise expands the appbar
Version badge and update chip
The brand area now shows the current version. If a newer release is available on GitHub, a green "New release available" chip appears next to the version and links to the releases page.
Transport improvements
AudioContext.resume()fires beforemultitrack.play()in the same gesture handler (Safari requires this to unblock autoplay).- Loop region and playhead state reset cleanly on new track load; playhead snaps to loop start on play.
- Keyboard shortcut
Ltoggles loop;I/Oset loop in/out points at the current playhead position.
Import flow
- File drop onto the URL bar — drag an MP3 or WAV directly onto the input area. A pill shows the filename and size; a clear button removes it.
- Stem choice chips use Spotify-style filter semantics: first click on a chip while all are selected switches to "only this stem"; subsequent clicks add to the selection; deselecting the last chip wraps back to "all selected".
Diagnostics
- Global
window.errorandunhandledrejectionhandlers log to the console with file, line, and stack trace. - Per-stem
<audio>elements attach anerrorlistener that logs the MediaError code and message.
CI
- Fixed: all pipeline steps now carry
backend: kubernetes, ensuring they run on the k3s agent and not the local Windows agent on main-branch pushes and releases.
Setup (macOS / Linux)
Unchanged — ./run.sh setup && ./run.sh start.
Known limitations
Same as previous alphas. The Windows app is ALPHA — expect rough edges.
v0.2.0-alpha.2
Bug fix release. Addresses mixer volume and mute issues reported in the previous alpha, the download button not working in the Windows desktop app, and the CUDA install failing on machines other than the build machine.
What's fixed
Mixer volume and mute
Volume boost above 0 dB now works correctly. Previously the upper half of every fader had no audible effect — the browser caps HTMLAudioElement.volume at 1.0, so pushing the fader above the midpoint did nothing. On Firefox and Safari, values above 1.0 also threw an exception that aborted the whole mixer pass, which is why muting one channel could permanently silence others until the page was reloaded.
Each track now routes through a Web Audio GainNode instead. GainNode.gain.value accepts any positive number, so boost works and mute is reliable across all browsers and in the desktop app.
Download button (Windows desktop app)
Clicking the download button on a stem now opens the file in the system default browser and triggers a normal download. The Tauri webview silently blocks native <a download> behavior, so the button did nothing before this fix.
CUDA install failing on other machines (#10)
The Windows venv is built on the CI machine, which bakes the build machine's Python path into pyvenv.cfg. When pip ran on a user's machine during the first-launch CUDA torch install, it looked for Python at that path, didn't find it, and failed. The app now patches pyvenv.cfg at runtime before invoking pip, so the install works regardless of where the user extracted the zip.
Setup (macOS / Linux)
Unchanged — ./run.sh setup && ./run.sh start.
Known limitations
Same as alpha.1. The Windows app is ALPHA — expect rough edges.
v0.2.0-alpha.1
Second alpha of StemDeck. This release adds a self-contained Windows desktop app with dual portable zip variants, and a round of DAW UI polish.
What's new
Windows desktop app
StemDeck is now available as a portable Windows app — no Python, no uv, no system dependencies. Extract and run StemDeck.exe.
Two variants ship with each release:
| Download | GPU | Approx. size |
|---|---|---|
StemDeck-Windows-x64.zip |
CPU only | ~700 MB |
StemDeck-Windows-x64.NVIDIA.zip |
NVIDIA CUDA | ~1.6 GB |
Use the CPU variant if you don't have an NVIDIA GPU. AMD and Intel GPUs don't support CUDA — CPU is the right pick for those too.
On first launch the app runs a short setup sequence (runtime check, workspace creation, compute device detection, FFmpeg, Demucs model download). Subsequent launches skip most steps and start in seconds.
The bundled Python venv has C++ static libraries stripped out — dnnl.lib alone is 623 MB and is only needed at build time, never at runtime. This is what keeps the CPU zip under 700 MB despite bundling a full PyTorch install.
DAW UI improvements
Waveform lanes and the instrument icon column now expand to fill the full window height, with icons vertically centered in each row at any window size. A ResizeObserver on the wave container keeps the playhead height and multitrack layout in sync when the window is resized.
The play button now glows green when active and the stop button glows red. Help and Tip the maker links now open in the system default browser — previously they did nothing inside the desktop app. The GPU setup step was also renamed to "Configuring compute device" since it applies to both CPU and NVIDIA builds.
Bug fixes
Fixed mixer channels getting stuck after mute or volume adjustments (#7). Per-track volume is now clamped to the browser-safe 0..1 range and each setTrackVolume call is wrapped independently, so one bad fader value can no longer abort the whole mixer pass and leave other channels stale.
Setup (macOS / Linux)
Unchanged from alpha.1 — ./run.sh setup && ./run.sh start.
Known limitations
Same as alpha.1. The Windows app is ALPHA — expect rough edges.
v0.1.0-alpha.1
First public alpha of StemDeck. Local, single-user audio stem
separation with a DAW-style mixer.
Highlights
- 6-stem separation via Demucs
htdemucs_6s. Auto-selects CUDA →
MPS → CPU; ~3-5× speedup on Apple Silicon over CPU. - DAW-style waveform editor with min/max rendering, zoom, loop
region drag, gold playhead, and stem-aligned lanes. - Per-stem mixer: volume fader, mute, solo, monitor (solo-only),
with state synced between mixer and stems sidebar. - Stem subset extraction: pick which stems to keep on import. The
studio surfaces a 7th "Original" lane (full song minus selection)
for A/B reference, plus a downloadable summedmix.wav. - Live VU per stem: post-gain RMS via Web Audio with peak hold +
slow falloff. - Song analysis in the now-playing card: BPM (librosa beat
tracker), key + scale + confidence (Albrecht-Shanahan), integrated
LUFS (BS.1770 via pyloudnorm), sample peak in dBFS. - Cancellable jobs at any pipeline stage (download, Demucs,
ffmpeg amix). Active subprocess is terminated and the partial job
dir is cleaned up.
Setup
- macOS / Linux:
git clone … && ./run.sh setup && ./run.sh start.
Thesetupsubcommand installs ffmpeg + uv via Homebrew or apt and
runsuv sync. - Docker:
docker compose -f build/docker-compose.yml up --build.
No GPU on macOS Docker; Apple Silicon users should prefer the
native install.
CI / quality
- Woodpecker pipeline runs lint (ruff), unit tests (pytest), Python
SAST (bandit), dependency CVE audit (pip-audit), and filesystem
security scan (trivy fs + trivy config). No build/publish. - Container hardening: non-root
appuser in the runtime image.
Known limitations
- Local-only / single-user. Not designed for multi-tenant hosting.
- Single concurrent pipeline (
asyncio.Semaphore(1)). Multiple jobs
queue rather than running in parallel. - yt-dlp YouTube downloads are subject to YouTube ToS. See the
Disclaimer in the README; usage is your responsibility. - Browser memory grows on long videos because each stem is decoded
into a Web Audio buffer for the overview waveform.
Thanks
Demucs (htdemucs_6s), wavesurfer.js, ffmpeg, yt-dlp, librosa,
pyloudnorm — this project is glue around their work.