| Crates.io | stem-splitter-core |
| lib.rs | stem-splitter-core |
| version | 1.1.3 |
| created_at | 2025-07-29 20:48:06.747879+00 |
| updated_at | 2025-12-30 12:54:56.012066+00 |
| description | Core library for AI-powered audio stem separation |
| homepage | https://github.com/gentij/stem-splitter-core |
| repository | https://github.com/gentij/stem-splitter-core |
| max_upload_size | |
| id | 1772791 |
| size | 164,758 |
High-performance, pure-Rust audio stem separation library powered by ONNX Runtime
stem-splitter-core is a Rust library for splitting audio tracks into isolated stems (vocals, drums, bass, and other instruments) using state-of-the-art AI models. Built entirely in Rust with ONNX Runtime, it provides:
Perfect for music production tools, DJ software, karaoke apps, or any application requiring audio source separation.
Add to your Cargo.toml:
[dependencies]
stem-splitter-core = "1.0.0"
No external dependencies or Python installation required!
use stem_splitter_core::{split_file, SplitOptions};
fn main() -> anyhow::Result<()> {
// Configure the split operation
let options = SplitOptions {
output_dir: "./output".to_string(),
model_name: "htdemucs_ort_v1".to_string(),
manifest_url_override: None,
};
// Split the audio file
let result = split_file("song.mp3", options)?;
// Access the separated stems
println!("Vocals: {}", result.vocals_path);
println!("Drums: {}", result.drums_path);
println!("Bass: {}", result.bass_path);
println!("Other: {}", result.other_path);
Ok(())
}
Or even simpler with defaults:
use stem_splitter_core::{split_file, SplitOptions};
fn main() -> anyhow::Result<()> {
// Use default options (htdemucs_ort_v1 model, current directory)
let result = split_file("song.mp3", SplitOptions::default())?;
println!("Vocals: {}", result.vocals_path);
Ok(())
}
use stem_splitter_core::{split_file, SplitOptions, SplitProgress};
fn main() -> anyhow::Result<()> {
// Set download progress callback
stem_splitter_core::set_download_progress_callback(|downloaded, total| {
let percent = if total > 0 {
(downloaded as f64 / total as f64 * 100.0) as u64
} else {
0
};
if total > 0 {
eprint!("\rDownloading model⦠{}% ({}/{} bytes)", percent, downloaded, total);
if downloaded >= total {
eprintln!();
}
}
});
// Set split progress callback
stem_splitter_core::set_split_progress_callback(|progress| {
match progress {
SplitProgress::Stage(stage) => {
eprintln!("> Stage: {}", stage);
}
SplitProgress::Writing { stem, percent, .. } => {
eprintln!("Writing {}: {:.0}%", stem, percent);
}
SplitProgress::Finished => {
eprintln!("Split finished!");
}
_ => {}
}
});
let options = SplitOptions {
output_dir: "./output".to_string(),
..Default::default() // Uses htdemucs_ort_v1 by default
};
split_file("song.mp3", options)?;
Ok(())
}
For applications that need to minimize latency, pre-load the model:
use stem_splitter_core::prepare_model;
fn main() -> anyhow::Result<()> {
// Download and load model at startup
prepare_model("htdemucs_ort_v1", None)?;
// Now splitting will be instant (no download delay)
// ... use split_file() as normal
Ok(())
}
split_file(input_path: &str, opts: SplitOptions) -> Result<SplitResult>Main function to split an audio file into stems.
Parameters:
input_path: Path to the audio file (supports WAV, MP3, FLAC, OGG, etc.)opts: Configuration options (see SplitOptions)Returns:
SplitResult containing paths to the separated stem filesSplitOptionsConfiguration struct for the separation process.
pub struct SplitOptions {
/// Directory where output stems will be saved
pub output_dir: String,
/// Name of the model to use (e.g., "htdemucs_ort_v1")
pub model_name: String,
/// Optional: Override the model manifest URL
/// (useful for custom models or specific versions)
pub manifest_url_override: Option<String>,
}
Default values:
output_dir: "."model_name: "htdemucs_ort_v1"manifest_url_override: NoneSplitResultResult struct containing paths to the separated stems.
pub struct SplitResult {
pub vocals_path: String,
pub drums_path: String,
pub bass_path: String,
pub other_path: String,
}
prepare_model(model_name: &str, manifest_url_override: Option<&str>) -> Result<()>Pre-loads and caches a model for faster subsequent splits.
Parameters:
model_name: Name of the model to preparemanifest_url_override: Optional URL to override the manifest locationensure_model(model_name: &str, manifest_url_override: Option<&str>) -> Result<ModelHandle>Downloads and verifies a model, returning a handle with metadata.
Parameters:
model_name: Name of the model to ensuremanifest_url_override: Optional URL to override the manifest locationReturns:
ModelHandle containing the manifest and local path to the modelset_download_progress_callback(callback: F)Set a callback to track model download progress.
pub fn set_download_progress_callback<F>(callback: F)
where
F: Fn(u64, u64) + Send + 'static,
Callback parameters:
downloaded: Bytes downloaded so fartotal: Total bytes to download (0 if unknown)set_split_progress_callback(callback: F)Set a callback to track split processing progress.
pub fn set_split_progress_callback<F>(callback: F)
where
F: Fn(SplitProgress) + Send + 'static,
SplitProgress variants:
Stage(&'static str): Current processing stage (e.g., "resolve_model", "read_audio", "infer")Chunks { done, total, percent }: Progress through audio chunksWriting { stem, done, total, percent }: Progress writing a specific stemFinished: Processing completeThe library supports a wide range of audio formats through the Symphonia decoder:
Output Format: All stems are saved as 16-bit PCM WAV files at 44.1kHz stereo.
This is the default and currently supported model:
The model is automatically downloaded from HuggingFace on first use and cached locally in your system's cache directory with SHA-256 verification.
The library includes a built-in model registry (models/registry.json) that maps model names to their manifest URLs. This allows users to simply specify "htdemucs_ort_v1" without needing to remember or provide the full HuggingFace URL.
You can use custom models by providing a manifest URL override:
let options = SplitOptions {
output_dir: "./output".to_string(),
model_name: "my_custom_model".to_string(),
manifest_url_override: Some(
"https://example.com/path/to/manifest.json".to_string()
),
};
use stem_splitter_core::{split_file, SplitOptions};
match split_file("song.mp3", SplitOptions::default()) {
Ok(result) => {
println!("Success! Vocals: {}", result.vocals_path);
}
Err(e) => {
eprintln!("Error during separation: {}", e);
}
}
For advanced use cases, you can manually manage models:
use stem_splitter_core::{ensure_model, ModelHandle};
fn main() -> anyhow::Result<()> {
// Get a handle to the model
let handle: ModelHandle = ensure_model("htdemucs_ort_v1", None)?;
// Access model metadata
println!("Model path: {}", handle.local_path.display());
println!("Sample rate: {}", handle.manifest.sample_rate);
println!("Window size: {}", handle.manifest.window);
println!("Stems: {:?}", handle.manifest.stems);
Ok(())
}
The library includes two examples demonstrating key features:
split_one - Complete stem separation with progress tracking# Split an audio file into stems
cargo run --release --example split_one -- input.mp3 ./output
# Usage: split_one <audio_file> [output_dir]
# Default output directory is ./out
This example demonstrates:
ensure_model - Model download and caching# Download and cache a model
cargo run --release --example ensure_model
This example demonstrates:
# All tests
cargo test
# Specific test
cargo test model_manager
# With output
cargo test -- --nocapture
# Debug build
cargo build
# Release build (optimized)
cargo build --release
Q: Why is the first run slow?
A: The model (~200MB) is downloaded on first use. Subsequent runs are instant.
Q: Where are models stored?
A: Models are cached in your system's standard cache directory with SHA-256 verification for integrity.
Q: Can I use GPU acceleration?
A: Yes! GPU acceleration is enabled by default and works across all platforms:
The library automatically detects available hardware and uses the best execution provider, falling back to CPU if no GPU is available. GPU mode significantly reduces CPU usage (~5x less) while maintaining similar processing speed.
Q: What's the quality compared to Python Demucs?
A: Identical quality - we use the same model architecture, just optimized for ONNX.
Q: Can I use my own custom model?
A: Yes! Use the manifest_url_override option to point to your own model manifest.
Q: Does it work offline?
A: Yes, after the initial model download, everything works offline.
Q: What sample rates are supported?
A: Input audio is automatically resampled to 44.1kHz for processing.
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
cargo buildcargo testLicensed under either of:
at your option.
Made with β€οΈ and π¦ Rust