Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ jobs:
if: env.SIGNED != 'true'
run: scripts/bundle-app.sh
- name: Start check
run: dist/stemd.app/Contents/MacOS/stemd --version
run: dist/Stemd.app/Contents/MacOS/stemd --version
- name: Remove credentials
if: always()
run: |
Expand Down Expand Up @@ -271,14 +271,14 @@ jobs:
Test-Version dist\stemd-windows\stemd-server.exe
$setup = Get-Item dist\stemd-*-setup.exe
Start-Process $setup.FullName -ArgumentList '/S' -Wait
$installed = Join-Path $env:LOCALAPPDATA 'Programs\stemd'
$installed = Join-Path $env:LOCALAPPDATA 'Programs\Stemd'
Test-Version (Join-Path $installed 'stemd-server.exe')
Test-Version (Join-Path $installed 'stemd-cli.exe')
# The runner has no NVIDIA driver.
- name: CPU separation
timeout-minutes: 30
run: |
$installed = Join-Path $env:LOCALAPPDATA 'Programs\stemd'
$installed = Join-Path $env:LOCALAPPDATA 'Programs\Stemd'
.github/scripts/cpu-separation.ps1 -Server (Join-Path $installed 'stemd-server.exe') -Cli (Join-Path $installed 'stemd-cli.exe')
- uses: actions/upload-artifact@v4
with:
Expand Down
63 changes: 63 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ members = [
[workspace.package]
version = "0.1.4"
edition = "2024"
# Stated so cargo says "requires rustc 1.85" rather than failing to parse the
# edition. It is the edition's floor, not a tested one.
rust-version = "1.85"
# 1.89 for `File::try_lock`, which keeps a second server off a cache in use.
rust-version = "1.89"
license = "MIT OR Apache-2.0"
repository = "https://github.com/nsaintot/stemd"
readme = "README.md"
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<div align="center">

<img src="resources/stemd-icon-mac-256.png" width="120" alt="stemd">
<img src="resources/stemd-icon-mac-256.png" width="120" alt="Stemd">

# stemd
# Stemd

**Split any track into stems, on your own machine.**

Drop a file on the window. Get `harmonics`, `vocals` and `drums` in a folder
beside it.

<img src="resources/screenshot.png" width="440" alt="The stemd window, with a drop zone reading Drop a track">
<img src="resources/screenshot.png" width="440" alt="The Stemd window: a drop zone reading Drop a track, and the Separated list below it">

[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](#license)
[![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20Windows%20%7C%20Linux-lightgrey)](#install)
Expand Down Expand Up @@ -43,7 +43,7 @@ track bit for bit.

**macOS.** Open the `macos-arm64` disk image from the
[latest release](https://github.com/nsaintot/stemd/releases/latest) and drag
stemd to Applications. Signed and notarized, and the ticket is stapled to the
Stemd to Applications. Signed and notarized, and the ticket is stapled to the
app as well as to the image, so it opens without argument and the first launch
does not need a network.

Expand All @@ -54,7 +54,7 @@ installer.

On a machine with an NVIDIA card, tick the box at the end of the installer or run
`install-cuda.cmd` once afterwards: about 1.2 GB of NVIDIA's own runtime, fetched
once and pinned by digest. No toolkit and no repository. Without it stemd runs on
once and pinned by digest. No toolkit and no repository. Without it Stemd runs on
the CPU, correctly and far slower.

**Linux.** Take the package for your distribution and architecture
Expand All @@ -81,7 +81,7 @@ Drop a track on the window, or click to choose one. The stems appear in

### From another machine

stemd is also a server. It announces itself over mDNS, so a client does not need
Stemd is also a server. It announces itself over mDNS, so a client does not need
to be told an address, and it speaks plain HTTP:

```bash
Expand Down Expand Up @@ -126,7 +126,7 @@ by the audio and by everything else that changes the output.

## Build from source

Needs `cmake`, Rust 1.85 or later, and a recursive clone. Per-platform
Needs `cmake`, Rust 1.89 or later, and a recursive clone. Per-platform
toolchains, packaging and every flag are in
[docs/building.md](docs/building.md).

Expand Down
2 changes: 1 addition & 1 deletion crates/stemd-cli/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn discover(timeout: Duration) -> Result<String> {
let _ = daemon.shutdown();
bail!(
"no stemd server found on the network after {}s — is it running? \
start it with `open dist/stemd.app`, or pass --host host:port",
start it with `open dist/Stemd.app`, or pass --host host:port",
timeout.as_secs()
)
}
6 changes: 3 additions & 3 deletions crates/stemd-core/src/stemfmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ impl StemFormat {
match self {
Self::Flac => "FLAC",
Self::Wav => "WAV",
Self::Mp3 => "MP3 320",
Self::Pcm16 => "PCM 16",
Self::Pcm32 => "PCM 32",
Self::Mp3 => "MP3",
Self::Pcm16 => "PCM 16-bit",
Self::Pcm32 => "PCM 32-bit float",
}
}
}
Expand Down
20 changes: 19 additions & 1 deletion crates/stemd-mlx/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl Accelerator {
if !gpu {
return (Self::Cpu, false);
}
if !gpu_computes() {
if !gpu_computes_on_kept_thread() {
return (Self::demote(), true);
}
let which = if cfg!(target_vendor = "apple") {
Expand Down Expand Up @@ -118,6 +118,24 @@ impl std::fmt::Display for Accelerator {
}
}

/// [`gpu_computes`] on a thread that never exits.
///
/// MLX keeps CUDA state per thread, and on Windows its destructor throws when the
/// thread exits. Windows reports that as a crash and freezes the whole process for
/// about 3 s while it writes the report.
fn gpu_computes_on_kept_thread() -> bool {
let (tx, rx) = std::sync::mpsc::channel();
let spawned = std::thread::Builder::new()
.name("stemd-gpu-probe".into())
.spawn(move || {
let _ = tx.send(gpu_computes());
loop {
std::thread::park();
}
});
spawned.is_ok() && rx.recv().unwrap_or(false)
}

/// Whether the GPU MLX offered returns right answers.
///
/// One operation of each kind the models use, on inputs small enough that the
Expand Down
10 changes: 9 additions & 1 deletion crates/stemd-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ clap = { version = "4.6.6", features = ["derive"] }
tokio-util = { version = "0.7.19", features = ["io"] }
parking_lot = "0.12.5"
thiserror.workspace = true
eframe = { version = "0.35.0", default-features = false, features = ["glow", "default_fonts"] }
# `persistence` saves the window's position and size between launches.
eframe = { version = "0.35.0", default-features = false, features = ["glow", "default_fonts", "persistence"] }
if-addrs = "0.15.0"
# First-run model fetch: HTTP plus a pinned digest.
ureq = "3.4.0"
Expand Down Expand Up @@ -51,6 +52,12 @@ winit = { version = "0.30.13", default-features = false, features = ["x11"] }
# download only there. See `cuda`.
[target.'cfg(windows)'.dependencies]
zip = { version = "2", default-features = false, features = ["deflate"] }
# Free disk space, see `disk.rs`.
windows-sys = { version = "0.61", features = ["Win32_Storage_FileSystem"] }

[target.'cfg(unix)'.dependencies]
# statvfs and sysctl, see `disk.rs`.
libc = "0.2"

# `default-features = false` above is what keeps wgpu and accesskit out, but it
# also drops `x11` and `wayland`, and those are not extras — winit has no Linux
Expand All @@ -62,6 +69,7 @@ zip = { version = "2", default-features = false, features = ["deflate"] }
eframe = { version = "0.35.0", default-features = false, features = [
"glow",
"default_fonts",
"persistence",
"x11",
"wayland",
] }
Expand Down
Loading
Loading