Skip to content

Add native Rust demucs-rs build for stem separation - #35

Open
ains wants to merge 1 commit into
mainfrom
claude/rust-demucs-build-66fxh4
Open

Add native Rust demucs-rs build for stem separation#35
ains wants to merge 1 commit into
mainfrom
claude/rust-demucs-build-66fxh4

Conversation

@ains

@ains ains commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Stem separation now has two engines behind the same job interface, preferring the much faster native one when it's available:

  • Native: the demucs CLI built from nikhilunni/demucs-rs, spawned in the main process on the project's source audio file (src/main/demucsCli.ts). Coarse download/separate progress is parsed from the CLI's plain stderr lines (its interactive bars are hidden off-TTY), cancellation kills the child process, and the resulting stem WAVs are decoded back to PCM at the playback buffer's sample rate so everything downstream (bundle persistence, transport) is unchanged.
  • WebGPU WASM (existing): used whenever the native binary is absent — the web build, or a dev environment that hasn't built it — or if a native run fails (e.g. missing GPU driver), in which case the renderer falls back automatically.

Build & packaging

  • npm run build:demucs (scripts/build-demucs-cli.mjs) clones demucs-rs at a pinned tag (v0.3.4, overridable via DEMUCS_RS_REPO/DEMUCS_RS_REF), runs cargo build --release -p demucs-cli, and stages the binary at resources/demucs/ (gitignored). resources/** already ships asar-unpacked, so the binary is bundled whenever it's present at package time and the app finds it via app.getAppPath() in dev and the app.asar.unpacked twin when packaged.
  • The Release workflow builds it on both the macOS and Windows jobs (with cargo caching keyed on the pinned tag) before packaging, so production builds always bundle it. Job timeouts are raised to 90 min to absorb a cold cargo build.
  • In development it's optional: without it the app just uses WebGPU, and NOTA_DEMUCS_CLI=/path/to/demucs points the app at an existing binary without staging.

Details

  • Availability is checked once, synchronously, via the preload bridge (stems:nativeAvailable), so the existing synchronous stemSeparationSupported() UI gating keeps working; it now returns true when either engine can run.
  • One native job at a time is enforced in the main process; temp output dirs are cleaned up on every path.
  • The website FAQ no longer apologizes for WebGPU-speed separation.
  • New unit tests cover the stderr → phase parser (tests/demucsStderr.test.ts).

Verified with format, lint, both typecheck projects, and the vitest suite (45 passing).

🤖 Generated with Claude Code

https://claude.ai/code/session_01T6sm1K8qgKZBkaPehBpQmz


Generated by Claude Code

Stem separation now has two engines behind the same job interface:

- Native: the demucs CLI built from nikhilunni/demucs-rs, spawned in the
  main process on the source audio file. Much faster than WASM; coarse
  download/separate progress is parsed from the CLI's stderr, and
  cancellation kills the child process.
- WebGPU WASM (existing): used whenever the native binary is absent
  (web build, dev without it) or a native run fails.

`npm run build:demucs` clones demucs-rs at a pinned tag, cargo-builds
demucs-cli, and stages the binary at resources/demucs/ (gitignored),
which ships asar-unpacked. The Release workflow now builds it on macOS
and Windows with cargo caching, so production builds always bundle it;
in development it is optional, with NOTA_DEMUCS_CLI as an escape hatch
to point at an existing binary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6sm1K8qgKZBkaPehBpQmz
@ains
ains force-pushed the claude/rust-demucs-build-66fxh4 branch from 86a4fac to 81a5cad Compare July 19, 2026 03:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants