Skip to main content

NeuCodecEncoder

Struct NeuCodecEncoder 

Source
pub struct NeuCodecEncoder;
Expand description

NeuCodec encoder: converts a 16 kHz audio waveform to speech token IDs.

Note: The full NeuCodec encoder requires Wav2Vec2BertModel (~600 MB) as a semantic feature extractor. Encoder support is not yet implemented in this pure-Rust build.

For reference audio encoding, use the Python neucodec package:

from neucodec import NeuCodec
model = NeuCodec.from_pretrained("neuphonic/neucodec")
codes = model.encode_code(waveform)   # → i32 array

Then save the codes as a .npy file and pass via --ref-codes to the synthesis examples.

Implementations§

Source§

impl NeuCodecEncoder

Source

pub fn new() -> Result<Self>

Always returns an error — encoder not yet implemented.

Examples found in repository?
examples/test_pipeline.rs (line 328)
292fn test_burn_backend() {
293    section("6 · Burn Backend");
294
295    // Feature-flag report
296    let wgpu_feature = neutts::codec::wgpu_feature_enabled();
297    item(
298        "wgpu Cargo feature",
299        if wgpu_feature { "\x1b[32menabled\x1b[0m (GPU tried first, NdArray fallback)" }
300        else            { "\x1b[2mdisabled\x1b[0m (NdArray CPU always used)" },
301    );
302
303    // Codec constants
304    item("decoder sample rate", &format!("{} Hz", neutts::codec::SAMPLE_RATE));
305    item("encoder sample rate", &format!("{} Hz", neutts::codec::ENCODER_SAMPLE_RATE));
306    item("samples / token (decoder)", &format!("{}", neutts::codec::SAMPLES_PER_TOKEN));
307    item("samples / token (encoder)", &format!("{}", neutts::codec::ENCODER_SAMPLES_PER_TOKEN));
308    item("encoder default input",
309        &format!("{} samples = {} s @ {} Hz",
310            neutts::codec::ENCODER_DEFAULT_INPUT_SAMPLES,
311            neutts::codec::ENCODER_DEFAULT_INPUT_SAMPLES / neutts::codec::ENCODER_SAMPLE_RATE as usize,
312            neutts::codec::ENCODER_SAMPLE_RATE));
313
314    // Runtime decoder probe (only succeeds if ONNX was converted at build time)
315    match neutts::NeuCodecDecoder::new() {
316        Ok(dec) => {
317            ok(&format!("NeuCodecDecoder::new() → backend: \x1b[1m{}\x1b[0m", dec.backend_name()));
318        }
319        Err(_) => {
320            println!(
321                "  \x1b[2m~  NeuCodecDecoder::new() → not compiled in \
322                 (run `download_models` + `cargo build` to embed weights)\x1b[0m"
323            );
324        }
325    }
326
327    // Runtime encoder probe
328    match neutts::NeuCodecEncoder::new() {
329        Ok(enc) => {
330            ok(&format!("NeuCodecEncoder::new() → backend: \x1b[1m{}\x1b[0m", enc.backend_name()));
331        }
332        Err(_) => {
333            println!(
334                "  \x1b[2m~  NeuCodecEncoder::new() → not compiled in \
335                 (run `download_models` + `cargo build` to embed weights)\x1b[0m"
336            );
337        }
338    }
339}
More examples
Hide additional examples
examples/encode_reference.rs (line 108)
62fn main() -> anyhow::Result<()> {
63    // ── Parse CLI arguments ───────────────────────────────────────────────────
64    let mut args = std::env::args().skip(1).peekable();
65
66    let mut encoder_bpk: Option<PathBuf> = None; // optional external .bpk weight file
67    let mut audio_path:  Option<PathBuf> = None;
68    let mut out_path:    Option<PathBuf> = None;
69
70    while let Some(arg) = args.next() {
71        match arg.as_str() {
72            "--encoder"      => { if let Some(v) = args.next() { encoder_bpk = Some(PathBuf::from(v)); } }
73            "--audio" | "-i" => { if let Some(v) = args.next() { audio_path = Some(PathBuf::from(v)); } }
74            "--out"   | "-o" => { if let Some(v) = args.next() { out_path   = Some(PathBuf::from(v)); } }
75            "--help"  | "-h" => { print_help(); return Ok(()); }
76            other => {
77                eprintln!("Unknown argument: {other}  (use --help for usage)");
78                std::process::exit(1);
79            }
80        }
81    }
82
83    // ── Validate inputs ───────────────────────────────────────────────────────
84    let audio_path = audio_path.ok_or_else(|| {
85        anyhow::anyhow!("No audio file specified.  Use --audio <path.wav>  (--help for more)")
86    })?;
87
88    if !audio_path.exists() {
89        anyhow::bail!("Audio file not found: {}", audio_path.display());
90    }
91
92    let out_path = out_path.unwrap_or_else(|| audio_path.with_extension("npy"));
93
94    // ── Print configuration ───────────────────────────────────────────────────
95    match &encoder_bpk {
96        Some(p) => println!("Encoder  : external BurnPack  {}", p.display()),
97        None    => println!("Encoder  : embedded weights  (wgpu → ndarray fallback)"),
98    }
99    println!("Audio    : {}", audio_path.display());
100    println!("Output   : {}", out_path.display());
101    println!();
102
103    // ── Load encoder ──────────────────────────────────────────────────────────
104    println!("Initialising encoder…");
105    let encoder = match encoder_bpk {
106        Some(ref p) => neutts::NeuCodecEncoder::load(p)
107            .map_err(|e| anyhow::anyhow!("Failed to load encoder from {}: {e}", p.display()))?,
108        None => neutts::NeuCodecEncoder::new()
109            .map_err(|e| anyhow::anyhow!(
110                "{e}\n\n\
111                 Run the one-time setup to embed the encoder:\n\
112                 \n\
113                 \tcargo run --example download_models\n\
114                 \tcargo build\n"
115            ))?,
116    };
117    println!("  → backend : {}", encoder.backend_name());
118    println!();
119
120    // ── Encode ────────────────────────────────────────────────────────────────
121    println!("Encoding {}…", audio_path.display());
122    let codes = encoder.encode_wav(&audio_path)?;
123
124    let duration_s = codes.len() as f32 / 50.0;
125    println!(
126        "  → {} tokens  ({:.2} s of audio at 50 tokens/s)",
127        codes.len(),
128        duration_s,
129    );
130
131    if duration_s < 3.0 {
132        eprintln!(
133            "WARNING: reference is only {duration_s:.1} s — \
134             5–30 s of clean speech gives the best cloning quality."
135        );
136    }
137
138    // ── Save ──────────────────────────────────────────────────────────────────
139    if let Some(parent) = out_path.parent() {
140        if !parent.as_os_str().is_empty() {
141            std::fs::create_dir_all(parent).ok();
142        }
143    }
144
145    neutts::npy::write_npy_i32(&out_path, &codes)?;
146    println!("Saved  →  {}", out_path.display());
147
148    println!();
149    println!(
150        "Use these codes for synthesis:\n\
151         \n\
152         \tcargo run --example basic --features espeak -- \\\n\
153         \t  --text       \"Your text here.\" \\\n\
154         \t  --ref-codes  {} \\\n\
155         \t  --ref-text   \"Transcript of the reference recording.\"",
156        out_path.display()
157    );
158
159    Ok(())
160}
Source

pub fn load(_path: &Path) -> Result<Self>

Always returns an error — encoder not yet implemented.

Examples found in repository?
examples/encode_reference.rs (line 106)
62fn main() -> anyhow::Result<()> {
63    // ── Parse CLI arguments ───────────────────────────────────────────────────
64    let mut args = std::env::args().skip(1).peekable();
65
66    let mut encoder_bpk: Option<PathBuf> = None; // optional external .bpk weight file
67    let mut audio_path:  Option<PathBuf> = None;
68    let mut out_path:    Option<PathBuf> = None;
69
70    while let Some(arg) = args.next() {
71        match arg.as_str() {
72            "--encoder"      => { if let Some(v) = args.next() { encoder_bpk = Some(PathBuf::from(v)); } }
73            "--audio" | "-i" => { if let Some(v) = args.next() { audio_path = Some(PathBuf::from(v)); } }
74            "--out"   | "-o" => { if let Some(v) = args.next() { out_path   = Some(PathBuf::from(v)); } }
75            "--help"  | "-h" => { print_help(); return Ok(()); }
76            other => {
77                eprintln!("Unknown argument: {other}  (use --help for usage)");
78                std::process::exit(1);
79            }
80        }
81    }
82
83    // ── Validate inputs ───────────────────────────────────────────────────────
84    let audio_path = audio_path.ok_or_else(|| {
85        anyhow::anyhow!("No audio file specified.  Use --audio <path.wav>  (--help for more)")
86    })?;
87
88    if !audio_path.exists() {
89        anyhow::bail!("Audio file not found: {}", audio_path.display());
90    }
91
92    let out_path = out_path.unwrap_or_else(|| audio_path.with_extension("npy"));
93
94    // ── Print configuration ───────────────────────────────────────────────────
95    match &encoder_bpk {
96        Some(p) => println!("Encoder  : external BurnPack  {}", p.display()),
97        None    => println!("Encoder  : embedded weights  (wgpu → ndarray fallback)"),
98    }
99    println!("Audio    : {}", audio_path.display());
100    println!("Output   : {}", out_path.display());
101    println!();
102
103    // ── Load encoder ──────────────────────────────────────────────────────────
104    println!("Initialising encoder…");
105    let encoder = match encoder_bpk {
106        Some(ref p) => neutts::NeuCodecEncoder::load(p)
107            .map_err(|e| anyhow::anyhow!("Failed to load encoder from {}: {e}", p.display()))?,
108        None => neutts::NeuCodecEncoder::new()
109            .map_err(|e| anyhow::anyhow!(
110                "{e}\n\n\
111                 Run the one-time setup to embed the encoder:\n\
112                 \n\
113                 \tcargo run --example download_models\n\
114                 \tcargo build\n"
115            ))?,
116    };
117    println!("  → backend : {}", encoder.backend_name());
118    println!();
119
120    // ── Encode ────────────────────────────────────────────────────────────────
121    println!("Encoding {}…", audio_path.display());
122    let codes = encoder.encode_wav(&audio_path)?;
123
124    let duration_s = codes.len() as f32 / 50.0;
125    println!(
126        "  → {} tokens  ({:.2} s of audio at 50 tokens/s)",
127        codes.len(),
128        duration_s,
129    );
130
131    if duration_s < 3.0 {
132        eprintln!(
133            "WARNING: reference is only {duration_s:.1} s — \
134             5–30 s of clean speech gives the best cloning quality."
135        );
136    }
137
138    // ── Save ──────────────────────────────────────────────────────────────────
139    if let Some(parent) = out_path.parent() {
140        if !parent.as_os_str().is_empty() {
141            std::fs::create_dir_all(parent).ok();
142        }
143    }
144
145    neutts::npy::write_npy_i32(&out_path, &codes)?;
146    println!("Saved  →  {}", out_path.display());
147
148    println!();
149    println!(
150        "Use these codes for synthesis:\n\
151         \n\
152         \tcargo run --example basic --features espeak -- \\\n\
153         \t  --text       \"Your text here.\" \\\n\
154         \t  --ref-codes  {} \\\n\
155         \t  --ref-text   \"Transcript of the reference recording.\"",
156        out_path.display()
157    );
158
159    Ok(())
160}
Source

pub fn encode_wav(&self, _path: &Path) -> Result<Vec<i32>>

Encode a WAV file to speech token IDs (not implemented).

Examples found in repository?
examples/encode_reference.rs (line 122)
62fn main() -> anyhow::Result<()> {
63    // ── Parse CLI arguments ───────────────────────────────────────────────────
64    let mut args = std::env::args().skip(1).peekable();
65
66    let mut encoder_bpk: Option<PathBuf> = None; // optional external .bpk weight file
67    let mut audio_path:  Option<PathBuf> = None;
68    let mut out_path:    Option<PathBuf> = None;
69
70    while let Some(arg) = args.next() {
71        match arg.as_str() {
72            "--encoder"      => { if let Some(v) = args.next() { encoder_bpk = Some(PathBuf::from(v)); } }
73            "--audio" | "-i" => { if let Some(v) = args.next() { audio_path = Some(PathBuf::from(v)); } }
74            "--out"   | "-o" => { if let Some(v) = args.next() { out_path   = Some(PathBuf::from(v)); } }
75            "--help"  | "-h" => { print_help(); return Ok(()); }
76            other => {
77                eprintln!("Unknown argument: {other}  (use --help for usage)");
78                std::process::exit(1);
79            }
80        }
81    }
82
83    // ── Validate inputs ───────────────────────────────────────────────────────
84    let audio_path = audio_path.ok_or_else(|| {
85        anyhow::anyhow!("No audio file specified.  Use --audio <path.wav>  (--help for more)")
86    })?;
87
88    if !audio_path.exists() {
89        anyhow::bail!("Audio file not found: {}", audio_path.display());
90    }
91
92    let out_path = out_path.unwrap_or_else(|| audio_path.with_extension("npy"));
93
94    // ── Print configuration ───────────────────────────────────────────────────
95    match &encoder_bpk {
96        Some(p) => println!("Encoder  : external BurnPack  {}", p.display()),
97        None    => println!("Encoder  : embedded weights  (wgpu → ndarray fallback)"),
98    }
99    println!("Audio    : {}", audio_path.display());
100    println!("Output   : {}", out_path.display());
101    println!();
102
103    // ── Load encoder ──────────────────────────────────────────────────────────
104    println!("Initialising encoder…");
105    let encoder = match encoder_bpk {
106        Some(ref p) => neutts::NeuCodecEncoder::load(p)
107            .map_err(|e| anyhow::anyhow!("Failed to load encoder from {}: {e}", p.display()))?,
108        None => neutts::NeuCodecEncoder::new()
109            .map_err(|e| anyhow::anyhow!(
110                "{e}\n\n\
111                 Run the one-time setup to embed the encoder:\n\
112                 \n\
113                 \tcargo run --example download_models\n\
114                 \tcargo build\n"
115            ))?,
116    };
117    println!("  → backend : {}", encoder.backend_name());
118    println!();
119
120    // ── Encode ────────────────────────────────────────────────────────────────
121    println!("Encoding {}…", audio_path.display());
122    let codes = encoder.encode_wav(&audio_path)?;
123
124    let duration_s = codes.len() as f32 / 50.0;
125    println!(
126        "  → {} tokens  ({:.2} s of audio at 50 tokens/s)",
127        codes.len(),
128        duration_s,
129    );
130
131    if duration_s < 3.0 {
132        eprintln!(
133            "WARNING: reference is only {duration_s:.1} s — \
134             5–30 s of clean speech gives the best cloning quality."
135        );
136    }
137
138    // ── Save ──────────────────────────────────────────────────────────────────
139    if let Some(parent) = out_path.parent() {
140        if !parent.as_os_str().is_empty() {
141            std::fs::create_dir_all(parent).ok();
142        }
143    }
144
145    neutts::npy::write_npy_i32(&out_path, &codes)?;
146    println!("Saved  →  {}", out_path.display());
147
148    println!();
149    println!(
150        "Use these codes for synthesis:\n\
151         \n\
152         \tcargo run --example basic --features espeak -- \\\n\
153         \t  --text       \"Your text here.\" \\\n\
154         \t  --ref-codes  {} \\\n\
155         \t  --ref-text   \"Transcript of the reference recording.\"",
156        out_path.display()
157    );
158
159    Ok(())
160}
Source

pub fn backend_name(&self) -> &str

Backend name.

Examples found in repository?
examples/test_pipeline.rs (line 330)
292fn test_burn_backend() {
293    section("6 · Burn Backend");
294
295    // Feature-flag report
296    let wgpu_feature = neutts::codec::wgpu_feature_enabled();
297    item(
298        "wgpu Cargo feature",
299        if wgpu_feature { "\x1b[32menabled\x1b[0m (GPU tried first, NdArray fallback)" }
300        else            { "\x1b[2mdisabled\x1b[0m (NdArray CPU always used)" },
301    );
302
303    // Codec constants
304    item("decoder sample rate", &format!("{} Hz", neutts::codec::SAMPLE_RATE));
305    item("encoder sample rate", &format!("{} Hz", neutts::codec::ENCODER_SAMPLE_RATE));
306    item("samples / token (decoder)", &format!("{}", neutts::codec::SAMPLES_PER_TOKEN));
307    item("samples / token (encoder)", &format!("{}", neutts::codec::ENCODER_SAMPLES_PER_TOKEN));
308    item("encoder default input",
309        &format!("{} samples = {} s @ {} Hz",
310            neutts::codec::ENCODER_DEFAULT_INPUT_SAMPLES,
311            neutts::codec::ENCODER_DEFAULT_INPUT_SAMPLES / neutts::codec::ENCODER_SAMPLE_RATE as usize,
312            neutts::codec::ENCODER_SAMPLE_RATE));
313
314    // Runtime decoder probe (only succeeds if ONNX was converted at build time)
315    match neutts::NeuCodecDecoder::new() {
316        Ok(dec) => {
317            ok(&format!("NeuCodecDecoder::new() → backend: \x1b[1m{}\x1b[0m", dec.backend_name()));
318        }
319        Err(_) => {
320            println!(
321                "  \x1b[2m~  NeuCodecDecoder::new() → not compiled in \
322                 (run `download_models` + `cargo build` to embed weights)\x1b[0m"
323            );
324        }
325    }
326
327    // Runtime encoder probe
328    match neutts::NeuCodecEncoder::new() {
329        Ok(enc) => {
330            ok(&format!("NeuCodecEncoder::new() → backend: \x1b[1m{}\x1b[0m", enc.backend_name()));
331        }
332        Err(_) => {
333            println!(
334                "  \x1b[2m~  NeuCodecEncoder::new() → not compiled in \
335                 (run `download_models` + `cargo build` to embed weights)\x1b[0m"
336            );
337        }
338    }
339}
More examples
Hide additional examples
examples/encode_reference.rs (line 117)
62fn main() -> anyhow::Result<()> {
63    // ── Parse CLI arguments ───────────────────────────────────────────────────
64    let mut args = std::env::args().skip(1).peekable();
65
66    let mut encoder_bpk: Option<PathBuf> = None; // optional external .bpk weight file
67    let mut audio_path:  Option<PathBuf> = None;
68    let mut out_path:    Option<PathBuf> = None;
69
70    while let Some(arg) = args.next() {
71        match arg.as_str() {
72            "--encoder"      => { if let Some(v) = args.next() { encoder_bpk = Some(PathBuf::from(v)); } }
73            "--audio" | "-i" => { if let Some(v) = args.next() { audio_path = Some(PathBuf::from(v)); } }
74            "--out"   | "-o" => { if let Some(v) = args.next() { out_path   = Some(PathBuf::from(v)); } }
75            "--help"  | "-h" => { print_help(); return Ok(()); }
76            other => {
77                eprintln!("Unknown argument: {other}  (use --help for usage)");
78                std::process::exit(1);
79            }
80        }
81    }
82
83    // ── Validate inputs ───────────────────────────────────────────────────────
84    let audio_path = audio_path.ok_or_else(|| {
85        anyhow::anyhow!("No audio file specified.  Use --audio <path.wav>  (--help for more)")
86    })?;
87
88    if !audio_path.exists() {
89        anyhow::bail!("Audio file not found: {}", audio_path.display());
90    }
91
92    let out_path = out_path.unwrap_or_else(|| audio_path.with_extension("npy"));
93
94    // ── Print configuration ───────────────────────────────────────────────────
95    match &encoder_bpk {
96        Some(p) => println!("Encoder  : external BurnPack  {}", p.display()),
97        None    => println!("Encoder  : embedded weights  (wgpu → ndarray fallback)"),
98    }
99    println!("Audio    : {}", audio_path.display());
100    println!("Output   : {}", out_path.display());
101    println!();
102
103    // ── Load encoder ──────────────────────────────────────────────────────────
104    println!("Initialising encoder…");
105    let encoder = match encoder_bpk {
106        Some(ref p) => neutts::NeuCodecEncoder::load(p)
107            .map_err(|e| anyhow::anyhow!("Failed to load encoder from {}: {e}", p.display()))?,
108        None => neutts::NeuCodecEncoder::new()
109            .map_err(|e| anyhow::anyhow!(
110                "{e}\n\n\
111                 Run the one-time setup to embed the encoder:\n\
112                 \n\
113                 \tcargo run --example download_models\n\
114                 \tcargo build\n"
115            ))?,
116    };
117    println!("  → backend : {}", encoder.backend_name());
118    println!();
119
120    // ── Encode ────────────────────────────────────────────────────────────────
121    println!("Encoding {}…", audio_path.display());
122    let codes = encoder.encode_wav(&audio_path)?;
123
124    let duration_s = codes.len() as f32 / 50.0;
125    println!(
126        "  → {} tokens  ({:.2} s of audio at 50 tokens/s)",
127        codes.len(),
128        duration_s,
129    );
130
131    if duration_s < 3.0 {
132        eprintln!(
133            "WARNING: reference is only {duration_s:.1} s — \
134             5–30 s of clean speech gives the best cloning quality."
135        );
136    }
137
138    // ── Save ──────────────────────────────────────────────────────────────────
139    if let Some(parent) = out_path.parent() {
140        if !parent.as_os_str().is_empty() {
141            std::fs::create_dir_all(parent).ok();
142        }
143    }
144
145    neutts::npy::write_npy_i32(&out_path, &codes)?;
146    println!("Saved  →  {}", out_path.display());
147
148    println!();
149    println!(
150        "Use these codes for synthesis:\n\
151         \n\
152         \tcargo run --example basic --features espeak -- \\\n\
153         \t  --text       \"Your text here.\" \\\n\
154         \t  --ref-codes  {} \\\n\
155         \t  --ref-text   \"Transcript of the reference recording.\"",
156        out_path.display()
157    );
158
159    Ok(())
160}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more