1mod activation;
19pub mod convert;
20pub mod optimise;
21mod wavenet;
22
23use std::path::Path;
24
25use serde_json::Value;
26
27pub use activation::Activation;
28pub use convert::{Converted, convert};
29pub use wavenet::WaveNet;
30
31#[derive(Debug)]
32pub enum NamError {
33 Io(std::io::Error),
34 Json(serde_json::Error),
35 Format(String),
37 Unsupported(String),
39 Weights { expected: usize, got: usize },
41}
42
43impl std::fmt::Display for NamError {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 match self {
46 NamError::Io(e) => write!(f, "{e}"),
47 NamError::Json(e) => write!(f, "invalid JSON: {e}"),
48 NamError::Format(s) => write!(f, "invalid model: {s}"),
49 NamError::Unsupported(s) => write!(f, "unsupported model feature: {s}"),
50 NamError::Weights { expected, got } => write!(f, "weight count mismatch: model needs {expected}, file has {got}"),
51 }
52 }
53}
54
55impl std::error::Error for NamError {
56 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
57 match self {
58 NamError::Io(e) => Some(e),
59 NamError::Json(e) => Some(e),
60 _ => None,
61 }
62 }
63}
64
65impl From<std::io::Error> for NamError {
66 fn from(e: std::io::Error) -> Self {
67 NamError::Io(e)
68 }
69}
70
71impl From<serde_json::Error> for NamError {
72 fn from(e: serde_json::Error) -> Self {
73 NamError::Json(e)
74 }
75}
76
77#[derive(Clone, Debug)]
79pub struct Model {
80 net: WaveNet,
81 pub name: Option<String>,
83 pub architecture: String,
85 pub loudness: Option<f64>,
88}
89
90fn weights_of(v: &Value) -> Result<Vec<f32>, NamError> {
91 match v.get("weights") {
92 Some(Value::Array(a)) => a
93 .iter()
94 .map(|x| x.as_f64().map(|f| f as f32).ok_or_else(|| NamError::Format("non-numeric weight".into())))
95 .collect(),
96 None => Ok(vec![]),
97 _ => Err(NamError::Format("weights must be an array".into())),
98 }
99}
100
101fn build(v: &Value) -> Result<WaveNet, NamError> {
102 let arch = v.get("architecture").and_then(Value::as_str).unwrap_or("");
103 let config = v.get("config").ok_or_else(|| NamError::Format("missing config".into()))?;
104 let sample_rate = v.get("sample_rate").and_then(Value::as_f64);
105 match arch {
106 "WaveNet" => WaveNet::from_json(config, &weights_of(v)?, sample_rate),
107 "SlimmableContainer" => {
108 let subs = config
110 .get("submodels")
111 .and_then(Value::as_array)
112 .filter(|s| !s.is_empty())
113 .ok_or_else(|| NamError::Format("SlimmableContainer without submodels".into()))?;
114 let last = subs.last().and_then(|s| s.get("model")).ok_or_else(|| NamError::Format("submodel".into()))?;
115 build(last)
116 }
117 other => Err(NamError::Unsupported(format!("architecture {other:?}"))),
118 }
119}
120
121impl Model {
122 pub fn load(path: impl AsRef<Path>) -> Result<Model, NamError> {
123 Model::from_json_str(&std::fs::read_to_string(path)?)
124 }
125
126 pub fn from_json_str(s: &str) -> Result<Model, NamError> {
127 let v: Value = serde_json::from_str(s)?;
128 let net = build(&v)?;
129 let name = v.get("metadata").and_then(|m| m.get("name")).and_then(Value::as_str).map(str::to_owned);
130 let architecture = v.get("architecture").and_then(Value::as_str).unwrap_or("").to_owned();
131 let loudness = v.get("metadata").and_then(|m| m.get("loudness")).and_then(Value::as_f64);
132 Ok(Model { net, name, architecture, loudness })
133 }
134
135 pub fn process(&mut self, input: &[f32], output: &mut [f32]) {
137 for (i, o) in input.chunks(4096).zip(output.chunks_mut(4096)) {
138 self.net.process(i, o);
139 }
140 }
141
142 pub fn reset(&mut self) {
144 self.net.reset();
145 }
146
147 pub fn sample_rate(&self) -> Option<f64> {
149 self.net.sample_rate()
150 }
151}