Demucs for Swift
On-device music source separation for Swift apps. Give it a song; get back drums, bass, vocals and the rest as separate tracks. It runs Meta's HTDemucs v4 through demucs-rs on the GPU via Metal, entirely on the device.
Supports iOS 16, macOS 14 (Apple silicon), tvOS 16 and visionOS 1.
Installation
In Xcode, choose File > Add Package Dependencies and enter:
https://github.com/SplitFireAI/demucs-swift
Or in Package.swift:
dependencies: [
.package(url: "https://github.com/SplitFireAI/demucs-swift", from: "0.1.0"),
]
Then add the Demucs product to your target.
Quick start
import Demucs
// Once at launch: keep the weights inside the app container.
let caches = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
DemucsEngine.configureCacheDirectory(caches.appendingPathComponent("demucs"))
// Download the weights once (84–333 MB from Hugging Face, cached on disk).
try await DemucsEngine.download(.fourStem) { progress in
print("download \(Int(progress.fraction * 100))%")
}
// Load the model. Warmup compiles the GPU shaders ahead of the first song.
let engine = DemucsEngine()
try await engine.load(.fourStem)
try await engine.warmup()
// Separate. Input is per-channel Float PCM at any sample rate (decode files
// with AVFoundation); each stem comes back at the same rate and length.
let stems = try await engine.separate(left: left, right: right, sampleRate: 44_100) { progress in
print("separating \(Int(progress.fraction * 100))%")
}
for stem in stems {
print(stem.kind, stem.left.count)
}
Cancelling the calling task cancels a download immediately and a separation at the next ~7.8 second chunk boundary. Progress handlers run on a background thread.
See Examples/DemucsExample for a SwiftUI app that
decodes a file with AVFoundation, separates it and shares the stems as WAV.
Models
| Model | Case | Stems | Size |
|---|---|---|---|
| htdemucs | .fourStem |
drums, bass, other, vocals | ~84 MB |
| htdemucs_6s | .sixStem |
+ guitar, piano | ~84 MB |
| htdemucs_ft | .fineTuned(stems:) |
up to 4, best quality | ~333 MB |
The fine-tuned model runs one sub-model per stem, so
.fineTuned(stems: [.vocals]) is about four times faster than
.fineTunedAll. All selections share one download.
DemucsEngine.models, isDownloaded(_:), downloadedFileURL(for:) and
deleteDownload(_:) manage the files.
How this package is built
Sources/Demucs/demucs_ffi.swift is generated by UniFFI from the demucs-ffi
crate in demucs-rs, and DemucsFramework is the matching static library. On
every swift-vX.Y.Z tag, demucs-rs's Release SDK Swift workflow uploads the
XCFramework, then rewrites the release URL and checksum in Package.swift and
the generated file here, and tags this repository. Do not edit those by hand;
the hand-written API lives in Sources/Demucs/DemucsEngine.swift.
Local development
Keep demucs-rs and demucs-swift next to each other, then build a local
framework before running tests:
make macos
swift test
Use make ios, make tvos or make visionos for another platform (tvOS and
visionOS need a nightly toolchain with rust-src). Set DEMUCS_REPO when the
repositories are not siblings. The package uses DemucsFramework.xcframework
automatically when that local file exists; without it, SwiftPM downloads the
release asset.
License
Apache-2.0, same as demucs-rs.