Skip to main content

rlx_orpheus/decoder/
backend.rs

1//! SNAC decode backend — host eager safetensors or native RLX CoreML ([`Device::Ane`]).
2
3use std::path::Path;
4
5use anyhow::{Result, bail};
6#[cfg(feature = "coreml")]
7use rlx_runtime::{Device, is_available};
8
9use super::eager::SnacDecoder;
10
11/// Load options for [`SnacBackend::open`].
12#[derive(Debug, Clone, Copy, Default)]
13pub struct SnacLoadOptions {
14    /// Run the SNAC conv decoder on native RLX CoreML ([`Device::Ane`]).
15    pub coreml: bool,
16}
17
18/// SNAC vocoder: host eager safetensors or compiled RLX graph (feature `coreml`).
19pub enum SnacBackend {
20    Eager(SnacDecoder),
21    #[cfg(feature = "coreml")]
22    Rlx(super::compiled::RlxSnacDecoder),
23}
24
25impl SnacBackend {
26    pub fn open(path: &Path, opts: SnacLoadOptions) -> Result<Self> {
27        if opts.coreml {
28            #[cfg(feature = "coreml")]
29            {
30                if !is_available(Device::Ane) {
31                    bail!(
32                        "SNAC CoreML (Device::Ane) is not available — rebuild with \
33                         `--features coreml` on macOS"
34                    );
35                }
36                return Ok(Self::Rlx(super::compiled::RlxSnacDecoder::load(
37                    path,
38                    Device::Ane,
39                )?));
40            }
41            #[cfg(not(feature = "coreml"))]
42            {
43                bail!(
44                    "SNAC CoreML requested but rlx-orpheus was built without \
45                     `--features coreml`"
46                );
47            }
48        }
49        Ok(Self::Eager(SnacDecoder::from_file(path)?))
50    }
51
52    pub fn decode_codes(
53        &self,
54        codes_0: &[i32],
55        codes_1: &[i32],
56        codes_2: &[i32],
57    ) -> Result<Vec<f32>> {
58        match self {
59            Self::Eager(d) => d.decode_codes(codes_0, codes_1, codes_2),
60            #[cfg(feature = "coreml")]
61            Self::Rlx(d) => d.decode_codes(codes_0, codes_1, codes_2),
62        }
63    }
64
65    pub fn decode_orpheus_frames(&self, frame_tokens: &[i32]) -> Result<Vec<f32>> {
66        match self {
67            Self::Eager(d) => d.decode_orpheus_frames(frame_tokens),
68            #[cfg(feature = "coreml")]
69            Self::Rlx(d) => d.decode_orpheus_frames(frame_tokens),
70        }
71    }
72}