Skip to main content

rlx_orpheus/decoder/
mod.rs

1// RLX — versatile ML compiler + runtime.
2// Copyright (C) 2026 Eugene Hauptmann, Nataliya Kosmyna.
3
4//! SNAC 24 kHz RVQ decoder for Orpheus speech tokens.
5//!
6//! - **Eager** ([`SnacDecoder`]): host safetensors + ndarray (default).
7//! - **CoreML** ([`SnacBackend`] with [`SnacLoadOptions::coreml`]): quantizer on CPU,
8//!   conv decoder compiled to [`Device::Ane`] via `rlx-ir` (feature `coreml`).
9//!
10//! Weights: [`decoder_weights_path`] (`ORPHEUS_SNAC_PATH`).
11
12mod backend;
13mod config;
14mod eager;
15mod ops;
16
17#[cfg(feature = "coreml")]
18mod compiled;
19
20pub use backend::{SnacBackend, SnacLoadOptions};
21pub use config::SnacConfig;
22pub use eager::{SAMPLE_RATE, SAMPLES_PER_FRAME, SnacDecoder};
23
24use std::path::PathBuf;
25
26use anyhow::{Result, bail};
27
28/// Resolve SNAC decoder weights from `ORPHEUS_SNAC_PATH`.
29pub fn decoder_weights_path() -> Result<PathBuf> {
30    let path = std::env::var("ORPHEUS_SNAC_PATH")
31        .ok()
32        .filter(|p| !p.is_empty())
33        .map(PathBuf::from)
34        .ok_or_else(|| {
35            anyhow::anyhow!(
36                "ORPHEUS_SNAC_PATH is not set (SNAC weights are not bundled in rlx-orpheus)"
37            )
38        })?;
39    if !path.exists() {
40        bail!("ORPHEUS_SNAC_PATH does not exist: {}", path.display());
41    }
42    Ok(path)
43}
44
45/// Like [`decoder_weights_path`], but returns `None` when unset or missing (for tests).
46pub fn decoder_weights_path_if_available() -> Option<PathBuf> {
47    let path = std::env::var("ORPHEUS_SNAC_PATH")
48        .ok()
49        .filter(|p| !p.is_empty())
50        .map(PathBuf::from)?;
51    if path.exists() { Some(path) } else { None }
52}