rlx-dac 0.2.11

Descript Audio Codec (DAC) neural audio codec for RLX
Documentation
#[cfg(feature = "hf-download")]
use crate::config::DacConfig;
use anyhow::Result;
use std::path::{Path, PathBuf};

pub const HF_DAC_24KHZ: &str = "hance-ai/descript-audio-codec-24khz";
pub const HF_DAC_16KHZ: &str = "hance-ai/descript-audio-codec-16khz";
pub const HF_DAC_44KHZ: &str = "hance-ai/descript-audio-codec-44khz";

pub fn default_dac_dir() -> PathBuf {
    std::env::var("RLX_DAC_DIR")
        .map(PathBuf::from)
        .unwrap_or_else(|_| PathBuf::from(".cache/dac/24khz"))
}

pub fn resolve_model_dir(explicit: Option<&Path>) -> PathBuf {
    explicit
        .map(Path::to_path_buf)
        .unwrap_or_else(default_dac_dir)
}

#[cfg(feature = "hf-download")]
fn hf_repo(model_type: &str) -> &'static str {
    match model_type {
        "16khz" => HF_DAC_16KHZ,
        "44khz" => HF_DAC_44KHZ,
        _ => HF_DAC_24KHZ,
    }
}

#[cfg(feature = "hf-download")]
fn config_for(model_type: &str) -> DacConfig {
    match model_type {
        "16khz" => DacConfig::config_16khz(),
        "44khz" => DacConfig::config_44khz(),
        _ => DacConfig::config_24khz(),
    }
}

#[cfg(feature = "hf-download")]
pub fn fetch_dac(out_dir: &Path, model_type: &str) -> Result<PathBuf> {
    use anyhow::Context;
    use hf_hub::api::sync::Api;

    std::fs::create_dir_all(out_dir).with_context(|| format!("create {}", out_dir.display()))?;
    let api = Api::new()?;
    let repo = api.model(hf_repo(model_type).to_string());
    let path = repo
        .get("model.safetensors")
        .with_context(|| "download model.safetensors")?;
    let dest = out_dir.join("model.safetensors");
    if path != dest {
        std::fs::copy(&path, &dest)
            .with_context(|| format!("copy {} -> {}", path.display(), dest.display()))?;
    }
    let cfg = config_for(model_type);
    let cfg_path = out_dir.join("config.json");
    std::fs::write(&cfg_path, serde_json::to_string_pretty(&cfg)?)?;
    eprintln!("fetched {} ({})", dest.display(), model_type);
    Ok(out_dir.to_path_buf())
}

#[cfg(not(feature = "hf-download"))]
pub fn fetch_dac(_out_dir: &Path, _model_type: &str) -> Result<PathBuf> {
    anyhow::bail!("rebuild with feature `hf-download` to fetch weights")
}

pub fn ensure_weights(model_dir: &Path) -> Result<()> {
    let st = model_dir.join("model.safetensors");
    let cfg = model_dir.join("config.json");
    if st.is_file() && cfg.is_file() {
        return Ok(());
    }
    #[cfg(feature = "hf-download")]
    {
        let model_type = model_dir
            .file_name()
            .and_then(|s| s.to_str())
            .unwrap_or("24khz");
        fetch_dac(model_dir, model_type)?;
        return Ok(());
    }
    #[cfg(not(feature = "hf-download"))]
    {
        anyhow::bail!(
            "missing weights under {} — set RLX_DAC_DIR or run with --fetch (needs hf-download feature)",
            model_dir.display()
        )
    }
}