pub struct MimoAudio {
pub tokenizer: AudioTokenizer,
pub encoder: AudioEncoder,
pub bf16_codebooks: bool,
/* private fields */
}Expand description
The MiMo audio towers.
Fields§
§tokenizer: AudioTokenizer§encoder: AudioEncoder§bf16_codebooks: boolQuantize against bf16-rounded codebooks, as the bf16 serving stacks
do (default on; CMF_MIMO_AUDIO_BF16_BOOKS=0 turns it off).
Implementations§
Source§impl MimoAudio
impl MimoAudio
Sourcepub fn present_in(model: &CmfModel) -> bool
pub fn present_in(model: &CmfModel) -> bool
Whether a CMF carries the audio towers (a companion or a single-file multimodal container).
Sourcepub fn from_model(model: &Arc<CmfModel>) -> Result<Self, String>
pub fn from_model(model: &Arc<CmfModel>) -> Result<Self, String>
Load from a CMF holding the source tensor names (the <stem>.mm.cmf
companion or a single-file multimodal container).
Examples found in repository?
175fn main() {
176 let args: Vec<String> = std::env::args().collect();
177 let cmd = args.get(1).map(String::as_str).unwrap_or("");
178 let out = PathBuf::from(arg(&args, "--out").expect("--out"));
179 match cmd {
180 "decode" => {
181 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
182 let w = mimo_audio::decode_wav(&wav).unwrap();
183 let flat: Vec<f32> = w.channels.concat();
184 save_f32(&out, &[w.channels.len(), w.frames()], &flat);
185 println!(
186 "rate {} channels {} frames {}",
187 w.sample_rate,
188 w.channels.len(),
189 w.frames()
190 );
191 }
192 "frontend" => {
193 std::fs::create_dir_all(&out).unwrap();
194 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
195 let t0 = Instant::now();
196 let w = mimo_audio::decode_wav(&wav).unwrap();
197 save_f32(
198 &out.join("dec.npy"),
199 &[w.channels.len(), w.frames()],
200 &w.channels.concat(),
201 );
202 let chans: Vec<Vec<f32>> = w
203 .channels
204 .iter()
205 .map(|c| mimo_audio::resample_sinc(c, w.sample_rate, mimo_audio::SAMPLE_RATE))
206 .collect();
207 save_f32(
208 &out.join("chan24k.npy"),
209 &[chans.len(), chans[0].len()],
210 &chans.concat(),
211 );
212 let mono = mimo_audio::wav_to_mono_24k(&w).unwrap();
213 save_f32(&out.join("wave24k.npy"), &[mono.len()], &mono);
214 let pool = cortiq_engine::pool::Pool::from_env();
215 let (mel, m) = mimo_audio::log_mel(&mono, pool.as_deref()).unwrap();
216 save_f32(&out.join("mel.npy"), &[m, mimo_audio::N_MELS], &mel);
217 println!(
218 "rate {} channels {} frames {} -> {} samples, {m} mel frames, K {} ({:.3}s)",
219 w.sample_rate,
220 w.channels.len(),
221 w.frames(),
222 mono.len(),
223 mimo_audio::audio_token_count(m, 4),
224 t0.elapsed().as_secs_f64()
225 );
226 }
227 "tower" => {
228 std::fs::create_dir_all(&out).unwrap();
229 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
230 let t0 = Instant::now();
231 let audio = if src.extension().is_some_and(|e| e == "cmf") {
232 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
233 MimoAudio::from_model(&model).expect("load towers")
234 } else {
235 MimoAudio::from_hf_dir(&src).expect("load towers")
236 };
237 let t_load = t0.elapsed().as_secs_f64();
238 let (mel, m) = if let Some(mp) = arg(&args, "--mel") {
239 let (shape, v) = load_f32(Path::new(&mp));
240 assert_eq!(shape[1], mimo_audio::N_MELS);
241 (v, shape[0])
242 } else {
243 let wav = std::fs::read(arg(&args, "--wav").expect("--wav or --mel")).unwrap();
244 audio.wav_to_mel(&wav).unwrap()
245 };
246 let t1 = Instant::now();
247 let feats = audio.features(&mel, m).unwrap();
248 let t_feats = t1.elapsed().as_secs_f64();
249 let d = audio.tokenizer.cfg.d_model;
250 let rows = feats.len() / d;
251 save_f32(&out.join("feats.npy"), &[rows, d], &feats);
252 let t2 = Instant::now();
253 let exact = audio.tokenizer.quantize(&feats, rows, false, audio.pool());
254 let t_rvq = t2.elapsed().as_secs_f64();
255 let rounded = audio.tokenizer.quantize(&feats, rows, true, audio.pool());
256 let levels = exact.len() / rows;
257 save_i32(&out.join("codes_exact.npy"), &[rows, levels], &exact);
258 save_i32(&out.join("codes_bf16books.npy"), &[rows, levels], &rounded);
259 let own = mimo_audio::AudioCodes {
260 frames: rows,
261 levels,
262 codes: if audio.bf16_codebooks {
263 rounded.clone()
264 } else {
265 exact.clone()
266 },
267 };
268 let t3 = Instant::now();
269 let emb_own = audio.embed_codes(&own).unwrap();
270 let t_enc = t3.elapsed().as_secs_f64();
271 save_f32(
272 &out.join("embeds_own.npy"),
273 &[emb_own.n_tokens, emb_own.dim],
274 &emb_own.rows,
275 );
276 let fixed = match arg(&args, "--codes") {
277 Some(cp) => {
278 let (shape, v) = load_codes(Path::new(&cp));
279 mimo_audio::AudioCodes {
280 frames: shape[0],
281 levels: shape[1],
282 codes: v,
283 }
284 }
285 None => own.clone(),
286 };
287 let emb = audio.embed_codes(&fixed).unwrap();
288 save_f32(&out.join("embeds.npy"), &[emb.n_tokens, emb.dim], &emb.rows);
289 let k = mimo_audio::audio_token_count(m, audio.encoder.cfg.group);
290 let meta = serde_json::json!({
291 "src": src.display().to_string(),
292 "mel_frames": m,
293 "segments": mimo_audio::segment_lengths(m),
294 "codes": rows,
295 "placeholder_count_K": k,
296 "embed_rows_own": emb_own.n_tokens,
297 "embed_rows_fixed": emb.n_tokens,
298 "load_s": t_load,
299 "features_s": t_feats,
300 "rvq_s": t_rvq,
301 "encoder_s": t_enc,
302 "bf16_codebooks_default": audio.bf16_codebooks,
303 "threads": cortiq_engine::pool::Pool::effective_threads(),
304 });
305 std::fs::write(
306 out.join("tower.json"),
307 serde_json::to_string_pretty(&meta).unwrap(),
308 )
309 .unwrap();
310 println!("{meta}");
311 assert_eq!(emb_own.n_tokens, k, "placeholder count != encoder rows");
312 }
313 "calib" => {
314 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
315 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
316 let audio = MimoAudio::from_model(&model).expect("load towers");
317 let dir = PathBuf::from(arg(&args, "--wav-dir").expect("--wav-dir"));
318 let mut wavs: Vec<PathBuf> = std::fs::read_dir(&dir)
319 .unwrap()
320 .filter_map(|e| e.ok().map(|e| e.path()))
321 .filter(|p| p.extension().is_some_and(|e| e == "wav"))
322 .collect();
323 wavs.sort();
324 let t0 = Instant::now();
325 cortiq_engine::gptq_capture::begin(true);
326 let mut frames = 0usize;
327 for w in &wavs {
328 let emb = audio.embed_wav(&std::fs::read(w).unwrap()).unwrap();
329 frames += emb.n_tokens;
330 eprintln!(
331 " {} -> {} rows ({:.0}s)",
332 w.display(),
333 emb.n_tokens,
334 t0.elapsed().as_secs_f64()
335 );
336 }
337 let hess = cortiq_engine::gptq_capture::end();
338 save_hessians(&out, &hess);
339 println!(
340 "{} clips, {frames} LLM rows, {} linears -> {} ({:.0}s)",
341 wavs.len(),
342 hess.len(),
343 out.display(),
344 t0.elapsed().as_secs_f64()
345 );
346 }
347 _ => {
348 eprintln!(
349 "usage: mimo_audio_dump (decode|frontend|tower|calib) --out ... (see the source header)"
350 );
351 std::process::exit(2);
352 }
353 }
354}Sourcepub fn from_hf_dir(dir: &Path) -> Result<Self, String>
pub fn from_hf_dir(dir: &Path) -> Result<Self, String>
Development loader: read the tensors straight from the HF checkpoint
directory (config.json, model.safetensors.index.json and its
shards, audio_tokenizer/), exact f32 from BF16.
Examples found in repository?
175fn main() {
176 let args: Vec<String> = std::env::args().collect();
177 let cmd = args.get(1).map(String::as_str).unwrap_or("");
178 let out = PathBuf::from(arg(&args, "--out").expect("--out"));
179 match cmd {
180 "decode" => {
181 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
182 let w = mimo_audio::decode_wav(&wav).unwrap();
183 let flat: Vec<f32> = w.channels.concat();
184 save_f32(&out, &[w.channels.len(), w.frames()], &flat);
185 println!(
186 "rate {} channels {} frames {}",
187 w.sample_rate,
188 w.channels.len(),
189 w.frames()
190 );
191 }
192 "frontend" => {
193 std::fs::create_dir_all(&out).unwrap();
194 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
195 let t0 = Instant::now();
196 let w = mimo_audio::decode_wav(&wav).unwrap();
197 save_f32(
198 &out.join("dec.npy"),
199 &[w.channels.len(), w.frames()],
200 &w.channels.concat(),
201 );
202 let chans: Vec<Vec<f32>> = w
203 .channels
204 .iter()
205 .map(|c| mimo_audio::resample_sinc(c, w.sample_rate, mimo_audio::SAMPLE_RATE))
206 .collect();
207 save_f32(
208 &out.join("chan24k.npy"),
209 &[chans.len(), chans[0].len()],
210 &chans.concat(),
211 );
212 let mono = mimo_audio::wav_to_mono_24k(&w).unwrap();
213 save_f32(&out.join("wave24k.npy"), &[mono.len()], &mono);
214 let pool = cortiq_engine::pool::Pool::from_env();
215 let (mel, m) = mimo_audio::log_mel(&mono, pool.as_deref()).unwrap();
216 save_f32(&out.join("mel.npy"), &[m, mimo_audio::N_MELS], &mel);
217 println!(
218 "rate {} channels {} frames {} -> {} samples, {m} mel frames, K {} ({:.3}s)",
219 w.sample_rate,
220 w.channels.len(),
221 w.frames(),
222 mono.len(),
223 mimo_audio::audio_token_count(m, 4),
224 t0.elapsed().as_secs_f64()
225 );
226 }
227 "tower" => {
228 std::fs::create_dir_all(&out).unwrap();
229 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
230 let t0 = Instant::now();
231 let audio = if src.extension().is_some_and(|e| e == "cmf") {
232 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
233 MimoAudio::from_model(&model).expect("load towers")
234 } else {
235 MimoAudio::from_hf_dir(&src).expect("load towers")
236 };
237 let t_load = t0.elapsed().as_secs_f64();
238 let (mel, m) = if let Some(mp) = arg(&args, "--mel") {
239 let (shape, v) = load_f32(Path::new(&mp));
240 assert_eq!(shape[1], mimo_audio::N_MELS);
241 (v, shape[0])
242 } else {
243 let wav = std::fs::read(arg(&args, "--wav").expect("--wav or --mel")).unwrap();
244 audio.wav_to_mel(&wav).unwrap()
245 };
246 let t1 = Instant::now();
247 let feats = audio.features(&mel, m).unwrap();
248 let t_feats = t1.elapsed().as_secs_f64();
249 let d = audio.tokenizer.cfg.d_model;
250 let rows = feats.len() / d;
251 save_f32(&out.join("feats.npy"), &[rows, d], &feats);
252 let t2 = Instant::now();
253 let exact = audio.tokenizer.quantize(&feats, rows, false, audio.pool());
254 let t_rvq = t2.elapsed().as_secs_f64();
255 let rounded = audio.tokenizer.quantize(&feats, rows, true, audio.pool());
256 let levels = exact.len() / rows;
257 save_i32(&out.join("codes_exact.npy"), &[rows, levels], &exact);
258 save_i32(&out.join("codes_bf16books.npy"), &[rows, levels], &rounded);
259 let own = mimo_audio::AudioCodes {
260 frames: rows,
261 levels,
262 codes: if audio.bf16_codebooks {
263 rounded.clone()
264 } else {
265 exact.clone()
266 },
267 };
268 let t3 = Instant::now();
269 let emb_own = audio.embed_codes(&own).unwrap();
270 let t_enc = t3.elapsed().as_secs_f64();
271 save_f32(
272 &out.join("embeds_own.npy"),
273 &[emb_own.n_tokens, emb_own.dim],
274 &emb_own.rows,
275 );
276 let fixed = match arg(&args, "--codes") {
277 Some(cp) => {
278 let (shape, v) = load_codes(Path::new(&cp));
279 mimo_audio::AudioCodes {
280 frames: shape[0],
281 levels: shape[1],
282 codes: v,
283 }
284 }
285 None => own.clone(),
286 };
287 let emb = audio.embed_codes(&fixed).unwrap();
288 save_f32(&out.join("embeds.npy"), &[emb.n_tokens, emb.dim], &emb.rows);
289 let k = mimo_audio::audio_token_count(m, audio.encoder.cfg.group);
290 let meta = serde_json::json!({
291 "src": src.display().to_string(),
292 "mel_frames": m,
293 "segments": mimo_audio::segment_lengths(m),
294 "codes": rows,
295 "placeholder_count_K": k,
296 "embed_rows_own": emb_own.n_tokens,
297 "embed_rows_fixed": emb.n_tokens,
298 "load_s": t_load,
299 "features_s": t_feats,
300 "rvq_s": t_rvq,
301 "encoder_s": t_enc,
302 "bf16_codebooks_default": audio.bf16_codebooks,
303 "threads": cortiq_engine::pool::Pool::effective_threads(),
304 });
305 std::fs::write(
306 out.join("tower.json"),
307 serde_json::to_string_pretty(&meta).unwrap(),
308 )
309 .unwrap();
310 println!("{meta}");
311 assert_eq!(emb_own.n_tokens, k, "placeholder count != encoder rows");
312 }
313 "calib" => {
314 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
315 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
316 let audio = MimoAudio::from_model(&model).expect("load towers");
317 let dir = PathBuf::from(arg(&args, "--wav-dir").expect("--wav-dir"));
318 let mut wavs: Vec<PathBuf> = std::fs::read_dir(&dir)
319 .unwrap()
320 .filter_map(|e| e.ok().map(|e| e.path()))
321 .filter(|p| p.extension().is_some_and(|e| e == "wav"))
322 .collect();
323 wavs.sort();
324 let t0 = Instant::now();
325 cortiq_engine::gptq_capture::begin(true);
326 let mut frames = 0usize;
327 for w in &wavs {
328 let emb = audio.embed_wav(&std::fs::read(w).unwrap()).unwrap();
329 frames += emb.n_tokens;
330 eprintln!(
331 " {} -> {} rows ({:.0}s)",
332 w.display(),
333 emb.n_tokens,
334 t0.elapsed().as_secs_f64()
335 );
336 }
337 let hess = cortiq_engine::gptq_capture::end();
338 save_hessians(&out, &hess);
339 println!(
340 "{} clips, {frames} LLM rows, {} linears -> {} ({:.0}s)",
341 wavs.len(),
342 hess.len(),
343 out.display(),
344 t0.elapsed().as_secs_f64()
345 );
346 }
347 _ => {
348 eprintln!(
349 "usage: mimo_audio_dump (decode|frontend|tower|calib) --out ... (see the source header)"
350 );
351 std::process::exit(2);
352 }
353 }
354}Sourcepub fn pool(&self) -> Option<&Pool>
pub fn pool(&self) -> Option<&Pool>
Examples found in repository?
175fn main() {
176 let args: Vec<String> = std::env::args().collect();
177 let cmd = args.get(1).map(String::as_str).unwrap_or("");
178 let out = PathBuf::from(arg(&args, "--out").expect("--out"));
179 match cmd {
180 "decode" => {
181 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
182 let w = mimo_audio::decode_wav(&wav).unwrap();
183 let flat: Vec<f32> = w.channels.concat();
184 save_f32(&out, &[w.channels.len(), w.frames()], &flat);
185 println!(
186 "rate {} channels {} frames {}",
187 w.sample_rate,
188 w.channels.len(),
189 w.frames()
190 );
191 }
192 "frontend" => {
193 std::fs::create_dir_all(&out).unwrap();
194 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
195 let t0 = Instant::now();
196 let w = mimo_audio::decode_wav(&wav).unwrap();
197 save_f32(
198 &out.join("dec.npy"),
199 &[w.channels.len(), w.frames()],
200 &w.channels.concat(),
201 );
202 let chans: Vec<Vec<f32>> = w
203 .channels
204 .iter()
205 .map(|c| mimo_audio::resample_sinc(c, w.sample_rate, mimo_audio::SAMPLE_RATE))
206 .collect();
207 save_f32(
208 &out.join("chan24k.npy"),
209 &[chans.len(), chans[0].len()],
210 &chans.concat(),
211 );
212 let mono = mimo_audio::wav_to_mono_24k(&w).unwrap();
213 save_f32(&out.join("wave24k.npy"), &[mono.len()], &mono);
214 let pool = cortiq_engine::pool::Pool::from_env();
215 let (mel, m) = mimo_audio::log_mel(&mono, pool.as_deref()).unwrap();
216 save_f32(&out.join("mel.npy"), &[m, mimo_audio::N_MELS], &mel);
217 println!(
218 "rate {} channels {} frames {} -> {} samples, {m} mel frames, K {} ({:.3}s)",
219 w.sample_rate,
220 w.channels.len(),
221 w.frames(),
222 mono.len(),
223 mimo_audio::audio_token_count(m, 4),
224 t0.elapsed().as_secs_f64()
225 );
226 }
227 "tower" => {
228 std::fs::create_dir_all(&out).unwrap();
229 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
230 let t0 = Instant::now();
231 let audio = if src.extension().is_some_and(|e| e == "cmf") {
232 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
233 MimoAudio::from_model(&model).expect("load towers")
234 } else {
235 MimoAudio::from_hf_dir(&src).expect("load towers")
236 };
237 let t_load = t0.elapsed().as_secs_f64();
238 let (mel, m) = if let Some(mp) = arg(&args, "--mel") {
239 let (shape, v) = load_f32(Path::new(&mp));
240 assert_eq!(shape[1], mimo_audio::N_MELS);
241 (v, shape[0])
242 } else {
243 let wav = std::fs::read(arg(&args, "--wav").expect("--wav or --mel")).unwrap();
244 audio.wav_to_mel(&wav).unwrap()
245 };
246 let t1 = Instant::now();
247 let feats = audio.features(&mel, m).unwrap();
248 let t_feats = t1.elapsed().as_secs_f64();
249 let d = audio.tokenizer.cfg.d_model;
250 let rows = feats.len() / d;
251 save_f32(&out.join("feats.npy"), &[rows, d], &feats);
252 let t2 = Instant::now();
253 let exact = audio.tokenizer.quantize(&feats, rows, false, audio.pool());
254 let t_rvq = t2.elapsed().as_secs_f64();
255 let rounded = audio.tokenizer.quantize(&feats, rows, true, audio.pool());
256 let levels = exact.len() / rows;
257 save_i32(&out.join("codes_exact.npy"), &[rows, levels], &exact);
258 save_i32(&out.join("codes_bf16books.npy"), &[rows, levels], &rounded);
259 let own = mimo_audio::AudioCodes {
260 frames: rows,
261 levels,
262 codes: if audio.bf16_codebooks {
263 rounded.clone()
264 } else {
265 exact.clone()
266 },
267 };
268 let t3 = Instant::now();
269 let emb_own = audio.embed_codes(&own).unwrap();
270 let t_enc = t3.elapsed().as_secs_f64();
271 save_f32(
272 &out.join("embeds_own.npy"),
273 &[emb_own.n_tokens, emb_own.dim],
274 &emb_own.rows,
275 );
276 let fixed = match arg(&args, "--codes") {
277 Some(cp) => {
278 let (shape, v) = load_codes(Path::new(&cp));
279 mimo_audio::AudioCodes {
280 frames: shape[0],
281 levels: shape[1],
282 codes: v,
283 }
284 }
285 None => own.clone(),
286 };
287 let emb = audio.embed_codes(&fixed).unwrap();
288 save_f32(&out.join("embeds.npy"), &[emb.n_tokens, emb.dim], &emb.rows);
289 let k = mimo_audio::audio_token_count(m, audio.encoder.cfg.group);
290 let meta = serde_json::json!({
291 "src": src.display().to_string(),
292 "mel_frames": m,
293 "segments": mimo_audio::segment_lengths(m),
294 "codes": rows,
295 "placeholder_count_K": k,
296 "embed_rows_own": emb_own.n_tokens,
297 "embed_rows_fixed": emb.n_tokens,
298 "load_s": t_load,
299 "features_s": t_feats,
300 "rvq_s": t_rvq,
301 "encoder_s": t_enc,
302 "bf16_codebooks_default": audio.bf16_codebooks,
303 "threads": cortiq_engine::pool::Pool::effective_threads(),
304 });
305 std::fs::write(
306 out.join("tower.json"),
307 serde_json::to_string_pretty(&meta).unwrap(),
308 )
309 .unwrap();
310 println!("{meta}");
311 assert_eq!(emb_own.n_tokens, k, "placeholder count != encoder rows");
312 }
313 "calib" => {
314 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
315 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
316 let audio = MimoAudio::from_model(&model).expect("load towers");
317 let dir = PathBuf::from(arg(&args, "--wav-dir").expect("--wav-dir"));
318 let mut wavs: Vec<PathBuf> = std::fs::read_dir(&dir)
319 .unwrap()
320 .filter_map(|e| e.ok().map(|e| e.path()))
321 .filter(|p| p.extension().is_some_and(|e| e == "wav"))
322 .collect();
323 wavs.sort();
324 let t0 = Instant::now();
325 cortiq_engine::gptq_capture::begin(true);
326 let mut frames = 0usize;
327 for w in &wavs {
328 let emb = audio.embed_wav(&std::fs::read(w).unwrap()).unwrap();
329 frames += emb.n_tokens;
330 eprintln!(
331 " {} -> {} rows ({:.0}s)",
332 w.display(),
333 emb.n_tokens,
334 t0.elapsed().as_secs_f64()
335 );
336 }
337 let hess = cortiq_engine::gptq_capture::end();
338 save_hessians(&out, &hess);
339 println!(
340 "{} clips, {frames} LLM rows, {} linears -> {} ({:.0}s)",
341 wavs.len(),
342 hess.len(),
343 out.display(),
344 t0.elapsed().as_secs_f64()
345 );
346 }
347 _ => {
348 eprintln!(
349 "usage: mimo_audio_dump (decode|frontend|tower|calib) --out ... (see the source header)"
350 );
351 std::process::exit(2);
352 }
353 }
354}Sourcepub fn wav_to_mel(&self, bytes: &[u8]) -> Result<(Vec<f32>, usize), String>
pub fn wav_to_mel(&self, bytes: &[u8]) -> Result<(Vec<f32>, usize), String>
WAV bytes → 24 kHz mono → log-mel [M][128].
Examples found in repository?
175fn main() {
176 let args: Vec<String> = std::env::args().collect();
177 let cmd = args.get(1).map(String::as_str).unwrap_or("");
178 let out = PathBuf::from(arg(&args, "--out").expect("--out"));
179 match cmd {
180 "decode" => {
181 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
182 let w = mimo_audio::decode_wav(&wav).unwrap();
183 let flat: Vec<f32> = w.channels.concat();
184 save_f32(&out, &[w.channels.len(), w.frames()], &flat);
185 println!(
186 "rate {} channels {} frames {}",
187 w.sample_rate,
188 w.channels.len(),
189 w.frames()
190 );
191 }
192 "frontend" => {
193 std::fs::create_dir_all(&out).unwrap();
194 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
195 let t0 = Instant::now();
196 let w = mimo_audio::decode_wav(&wav).unwrap();
197 save_f32(
198 &out.join("dec.npy"),
199 &[w.channels.len(), w.frames()],
200 &w.channels.concat(),
201 );
202 let chans: Vec<Vec<f32>> = w
203 .channels
204 .iter()
205 .map(|c| mimo_audio::resample_sinc(c, w.sample_rate, mimo_audio::SAMPLE_RATE))
206 .collect();
207 save_f32(
208 &out.join("chan24k.npy"),
209 &[chans.len(), chans[0].len()],
210 &chans.concat(),
211 );
212 let mono = mimo_audio::wav_to_mono_24k(&w).unwrap();
213 save_f32(&out.join("wave24k.npy"), &[mono.len()], &mono);
214 let pool = cortiq_engine::pool::Pool::from_env();
215 let (mel, m) = mimo_audio::log_mel(&mono, pool.as_deref()).unwrap();
216 save_f32(&out.join("mel.npy"), &[m, mimo_audio::N_MELS], &mel);
217 println!(
218 "rate {} channels {} frames {} -> {} samples, {m} mel frames, K {} ({:.3}s)",
219 w.sample_rate,
220 w.channels.len(),
221 w.frames(),
222 mono.len(),
223 mimo_audio::audio_token_count(m, 4),
224 t0.elapsed().as_secs_f64()
225 );
226 }
227 "tower" => {
228 std::fs::create_dir_all(&out).unwrap();
229 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
230 let t0 = Instant::now();
231 let audio = if src.extension().is_some_and(|e| e == "cmf") {
232 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
233 MimoAudio::from_model(&model).expect("load towers")
234 } else {
235 MimoAudio::from_hf_dir(&src).expect("load towers")
236 };
237 let t_load = t0.elapsed().as_secs_f64();
238 let (mel, m) = if let Some(mp) = arg(&args, "--mel") {
239 let (shape, v) = load_f32(Path::new(&mp));
240 assert_eq!(shape[1], mimo_audio::N_MELS);
241 (v, shape[0])
242 } else {
243 let wav = std::fs::read(arg(&args, "--wav").expect("--wav or --mel")).unwrap();
244 audio.wav_to_mel(&wav).unwrap()
245 };
246 let t1 = Instant::now();
247 let feats = audio.features(&mel, m).unwrap();
248 let t_feats = t1.elapsed().as_secs_f64();
249 let d = audio.tokenizer.cfg.d_model;
250 let rows = feats.len() / d;
251 save_f32(&out.join("feats.npy"), &[rows, d], &feats);
252 let t2 = Instant::now();
253 let exact = audio.tokenizer.quantize(&feats, rows, false, audio.pool());
254 let t_rvq = t2.elapsed().as_secs_f64();
255 let rounded = audio.tokenizer.quantize(&feats, rows, true, audio.pool());
256 let levels = exact.len() / rows;
257 save_i32(&out.join("codes_exact.npy"), &[rows, levels], &exact);
258 save_i32(&out.join("codes_bf16books.npy"), &[rows, levels], &rounded);
259 let own = mimo_audio::AudioCodes {
260 frames: rows,
261 levels,
262 codes: if audio.bf16_codebooks {
263 rounded.clone()
264 } else {
265 exact.clone()
266 },
267 };
268 let t3 = Instant::now();
269 let emb_own = audio.embed_codes(&own).unwrap();
270 let t_enc = t3.elapsed().as_secs_f64();
271 save_f32(
272 &out.join("embeds_own.npy"),
273 &[emb_own.n_tokens, emb_own.dim],
274 &emb_own.rows,
275 );
276 let fixed = match arg(&args, "--codes") {
277 Some(cp) => {
278 let (shape, v) = load_codes(Path::new(&cp));
279 mimo_audio::AudioCodes {
280 frames: shape[0],
281 levels: shape[1],
282 codes: v,
283 }
284 }
285 None => own.clone(),
286 };
287 let emb = audio.embed_codes(&fixed).unwrap();
288 save_f32(&out.join("embeds.npy"), &[emb.n_tokens, emb.dim], &emb.rows);
289 let k = mimo_audio::audio_token_count(m, audio.encoder.cfg.group);
290 let meta = serde_json::json!({
291 "src": src.display().to_string(),
292 "mel_frames": m,
293 "segments": mimo_audio::segment_lengths(m),
294 "codes": rows,
295 "placeholder_count_K": k,
296 "embed_rows_own": emb_own.n_tokens,
297 "embed_rows_fixed": emb.n_tokens,
298 "load_s": t_load,
299 "features_s": t_feats,
300 "rvq_s": t_rvq,
301 "encoder_s": t_enc,
302 "bf16_codebooks_default": audio.bf16_codebooks,
303 "threads": cortiq_engine::pool::Pool::effective_threads(),
304 });
305 std::fs::write(
306 out.join("tower.json"),
307 serde_json::to_string_pretty(&meta).unwrap(),
308 )
309 .unwrap();
310 println!("{meta}");
311 assert_eq!(emb_own.n_tokens, k, "placeholder count != encoder rows");
312 }
313 "calib" => {
314 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
315 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
316 let audio = MimoAudio::from_model(&model).expect("load towers");
317 let dir = PathBuf::from(arg(&args, "--wav-dir").expect("--wav-dir"));
318 let mut wavs: Vec<PathBuf> = std::fs::read_dir(&dir)
319 .unwrap()
320 .filter_map(|e| e.ok().map(|e| e.path()))
321 .filter(|p| p.extension().is_some_and(|e| e == "wav"))
322 .collect();
323 wavs.sort();
324 let t0 = Instant::now();
325 cortiq_engine::gptq_capture::begin(true);
326 let mut frames = 0usize;
327 for w in &wavs {
328 let emb = audio.embed_wav(&std::fs::read(w).unwrap()).unwrap();
329 frames += emb.n_tokens;
330 eprintln!(
331 " {} -> {} rows ({:.0}s)",
332 w.display(),
333 emb.n_tokens,
334 t0.elapsed().as_secs_f64()
335 );
336 }
337 let hess = cortiq_engine::gptq_capture::end();
338 save_hessians(&out, &hess);
339 println!(
340 "{} clips, {frames} LLM rows, {} linears -> {} ({:.0}s)",
341 wavs.len(),
342 hess.len(),
343 out.display(),
344 t0.elapsed().as_secs_f64()
345 );
346 }
347 _ => {
348 eprintln!(
349 "usage: mimo_audio_dump (decode|frontend|tower|calib) --out ... (see the source header)"
350 );
351 std::process::exit(2);
352 }
353 }
354}Sourcepub fn features(&self, mel: &[f32], m: usize) -> Result<Vec<f32>, String>
pub fn features(&self, mel: &[f32], m: usize) -> Result<Vec<f32>, String>
Pre-RVQ features of every segment, concatenated [codes][d].
Examples found in repository?
175fn main() {
176 let args: Vec<String> = std::env::args().collect();
177 let cmd = args.get(1).map(String::as_str).unwrap_or("");
178 let out = PathBuf::from(arg(&args, "--out").expect("--out"));
179 match cmd {
180 "decode" => {
181 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
182 let w = mimo_audio::decode_wav(&wav).unwrap();
183 let flat: Vec<f32> = w.channels.concat();
184 save_f32(&out, &[w.channels.len(), w.frames()], &flat);
185 println!(
186 "rate {} channels {} frames {}",
187 w.sample_rate,
188 w.channels.len(),
189 w.frames()
190 );
191 }
192 "frontend" => {
193 std::fs::create_dir_all(&out).unwrap();
194 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
195 let t0 = Instant::now();
196 let w = mimo_audio::decode_wav(&wav).unwrap();
197 save_f32(
198 &out.join("dec.npy"),
199 &[w.channels.len(), w.frames()],
200 &w.channels.concat(),
201 );
202 let chans: Vec<Vec<f32>> = w
203 .channels
204 .iter()
205 .map(|c| mimo_audio::resample_sinc(c, w.sample_rate, mimo_audio::SAMPLE_RATE))
206 .collect();
207 save_f32(
208 &out.join("chan24k.npy"),
209 &[chans.len(), chans[0].len()],
210 &chans.concat(),
211 );
212 let mono = mimo_audio::wav_to_mono_24k(&w).unwrap();
213 save_f32(&out.join("wave24k.npy"), &[mono.len()], &mono);
214 let pool = cortiq_engine::pool::Pool::from_env();
215 let (mel, m) = mimo_audio::log_mel(&mono, pool.as_deref()).unwrap();
216 save_f32(&out.join("mel.npy"), &[m, mimo_audio::N_MELS], &mel);
217 println!(
218 "rate {} channels {} frames {} -> {} samples, {m} mel frames, K {} ({:.3}s)",
219 w.sample_rate,
220 w.channels.len(),
221 w.frames(),
222 mono.len(),
223 mimo_audio::audio_token_count(m, 4),
224 t0.elapsed().as_secs_f64()
225 );
226 }
227 "tower" => {
228 std::fs::create_dir_all(&out).unwrap();
229 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
230 let t0 = Instant::now();
231 let audio = if src.extension().is_some_and(|e| e == "cmf") {
232 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
233 MimoAudio::from_model(&model).expect("load towers")
234 } else {
235 MimoAudio::from_hf_dir(&src).expect("load towers")
236 };
237 let t_load = t0.elapsed().as_secs_f64();
238 let (mel, m) = if let Some(mp) = arg(&args, "--mel") {
239 let (shape, v) = load_f32(Path::new(&mp));
240 assert_eq!(shape[1], mimo_audio::N_MELS);
241 (v, shape[0])
242 } else {
243 let wav = std::fs::read(arg(&args, "--wav").expect("--wav or --mel")).unwrap();
244 audio.wav_to_mel(&wav).unwrap()
245 };
246 let t1 = Instant::now();
247 let feats = audio.features(&mel, m).unwrap();
248 let t_feats = t1.elapsed().as_secs_f64();
249 let d = audio.tokenizer.cfg.d_model;
250 let rows = feats.len() / d;
251 save_f32(&out.join("feats.npy"), &[rows, d], &feats);
252 let t2 = Instant::now();
253 let exact = audio.tokenizer.quantize(&feats, rows, false, audio.pool());
254 let t_rvq = t2.elapsed().as_secs_f64();
255 let rounded = audio.tokenizer.quantize(&feats, rows, true, audio.pool());
256 let levels = exact.len() / rows;
257 save_i32(&out.join("codes_exact.npy"), &[rows, levels], &exact);
258 save_i32(&out.join("codes_bf16books.npy"), &[rows, levels], &rounded);
259 let own = mimo_audio::AudioCodes {
260 frames: rows,
261 levels,
262 codes: if audio.bf16_codebooks {
263 rounded.clone()
264 } else {
265 exact.clone()
266 },
267 };
268 let t3 = Instant::now();
269 let emb_own = audio.embed_codes(&own).unwrap();
270 let t_enc = t3.elapsed().as_secs_f64();
271 save_f32(
272 &out.join("embeds_own.npy"),
273 &[emb_own.n_tokens, emb_own.dim],
274 &emb_own.rows,
275 );
276 let fixed = match arg(&args, "--codes") {
277 Some(cp) => {
278 let (shape, v) = load_codes(Path::new(&cp));
279 mimo_audio::AudioCodes {
280 frames: shape[0],
281 levels: shape[1],
282 codes: v,
283 }
284 }
285 None => own.clone(),
286 };
287 let emb = audio.embed_codes(&fixed).unwrap();
288 save_f32(&out.join("embeds.npy"), &[emb.n_tokens, emb.dim], &emb.rows);
289 let k = mimo_audio::audio_token_count(m, audio.encoder.cfg.group);
290 let meta = serde_json::json!({
291 "src": src.display().to_string(),
292 "mel_frames": m,
293 "segments": mimo_audio::segment_lengths(m),
294 "codes": rows,
295 "placeholder_count_K": k,
296 "embed_rows_own": emb_own.n_tokens,
297 "embed_rows_fixed": emb.n_tokens,
298 "load_s": t_load,
299 "features_s": t_feats,
300 "rvq_s": t_rvq,
301 "encoder_s": t_enc,
302 "bf16_codebooks_default": audio.bf16_codebooks,
303 "threads": cortiq_engine::pool::Pool::effective_threads(),
304 });
305 std::fs::write(
306 out.join("tower.json"),
307 serde_json::to_string_pretty(&meta).unwrap(),
308 )
309 .unwrap();
310 println!("{meta}");
311 assert_eq!(emb_own.n_tokens, k, "placeholder count != encoder rows");
312 }
313 "calib" => {
314 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
315 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
316 let audio = MimoAudio::from_model(&model).expect("load towers");
317 let dir = PathBuf::from(arg(&args, "--wav-dir").expect("--wav-dir"));
318 let mut wavs: Vec<PathBuf> = std::fs::read_dir(&dir)
319 .unwrap()
320 .filter_map(|e| e.ok().map(|e| e.path()))
321 .filter(|p| p.extension().is_some_and(|e| e == "wav"))
322 .collect();
323 wavs.sort();
324 let t0 = Instant::now();
325 cortiq_engine::gptq_capture::begin(true);
326 let mut frames = 0usize;
327 for w in &wavs {
328 let emb = audio.embed_wav(&std::fs::read(w).unwrap()).unwrap();
329 frames += emb.n_tokens;
330 eprintln!(
331 " {} -> {} rows ({:.0}s)",
332 w.display(),
333 emb.n_tokens,
334 t0.elapsed().as_secs_f64()
335 );
336 }
337 let hess = cortiq_engine::gptq_capture::end();
338 save_hessians(&out, &hess);
339 println!(
340 "{} clips, {frames} LLM rows, {} linears -> {} ({:.0}s)",
341 wavs.len(),
342 hess.len(),
343 out.display(),
344 t0.elapsed().as_secs_f64()
345 );
346 }
347 _ => {
348 eprintln!(
349 "usage: mimo_audio_dump (decode|frontend|tower|calib) --out ... (see the source header)"
350 );
351 std::process::exit(2);
352 }
353 }
354}Sourcepub fn encode_mel(&self, mel: &[f32], m: usize) -> Result<AudioCodes, String>
pub fn encode_mel(&self, mel: &[f32], m: usize) -> Result<AudioCodes, String>
Log-mel → tokenizer codes, each 6000-frame segment on its own.
Sourcepub fn embed_codes(&self, codes: &AudioCodes) -> Result<AudioEmbeds, String>
pub fn embed_codes(&self, codes: &AudioCodes) -> Result<AudioEmbeds, String>
Codes → LLM embedding rows.
Examples found in repository?
175fn main() {
176 let args: Vec<String> = std::env::args().collect();
177 let cmd = args.get(1).map(String::as_str).unwrap_or("");
178 let out = PathBuf::from(arg(&args, "--out").expect("--out"));
179 match cmd {
180 "decode" => {
181 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
182 let w = mimo_audio::decode_wav(&wav).unwrap();
183 let flat: Vec<f32> = w.channels.concat();
184 save_f32(&out, &[w.channels.len(), w.frames()], &flat);
185 println!(
186 "rate {} channels {} frames {}",
187 w.sample_rate,
188 w.channels.len(),
189 w.frames()
190 );
191 }
192 "frontend" => {
193 std::fs::create_dir_all(&out).unwrap();
194 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
195 let t0 = Instant::now();
196 let w = mimo_audio::decode_wav(&wav).unwrap();
197 save_f32(
198 &out.join("dec.npy"),
199 &[w.channels.len(), w.frames()],
200 &w.channels.concat(),
201 );
202 let chans: Vec<Vec<f32>> = w
203 .channels
204 .iter()
205 .map(|c| mimo_audio::resample_sinc(c, w.sample_rate, mimo_audio::SAMPLE_RATE))
206 .collect();
207 save_f32(
208 &out.join("chan24k.npy"),
209 &[chans.len(), chans[0].len()],
210 &chans.concat(),
211 );
212 let mono = mimo_audio::wav_to_mono_24k(&w).unwrap();
213 save_f32(&out.join("wave24k.npy"), &[mono.len()], &mono);
214 let pool = cortiq_engine::pool::Pool::from_env();
215 let (mel, m) = mimo_audio::log_mel(&mono, pool.as_deref()).unwrap();
216 save_f32(&out.join("mel.npy"), &[m, mimo_audio::N_MELS], &mel);
217 println!(
218 "rate {} channels {} frames {} -> {} samples, {m} mel frames, K {} ({:.3}s)",
219 w.sample_rate,
220 w.channels.len(),
221 w.frames(),
222 mono.len(),
223 mimo_audio::audio_token_count(m, 4),
224 t0.elapsed().as_secs_f64()
225 );
226 }
227 "tower" => {
228 std::fs::create_dir_all(&out).unwrap();
229 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
230 let t0 = Instant::now();
231 let audio = if src.extension().is_some_and(|e| e == "cmf") {
232 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
233 MimoAudio::from_model(&model).expect("load towers")
234 } else {
235 MimoAudio::from_hf_dir(&src).expect("load towers")
236 };
237 let t_load = t0.elapsed().as_secs_f64();
238 let (mel, m) = if let Some(mp) = arg(&args, "--mel") {
239 let (shape, v) = load_f32(Path::new(&mp));
240 assert_eq!(shape[1], mimo_audio::N_MELS);
241 (v, shape[0])
242 } else {
243 let wav = std::fs::read(arg(&args, "--wav").expect("--wav or --mel")).unwrap();
244 audio.wav_to_mel(&wav).unwrap()
245 };
246 let t1 = Instant::now();
247 let feats = audio.features(&mel, m).unwrap();
248 let t_feats = t1.elapsed().as_secs_f64();
249 let d = audio.tokenizer.cfg.d_model;
250 let rows = feats.len() / d;
251 save_f32(&out.join("feats.npy"), &[rows, d], &feats);
252 let t2 = Instant::now();
253 let exact = audio.tokenizer.quantize(&feats, rows, false, audio.pool());
254 let t_rvq = t2.elapsed().as_secs_f64();
255 let rounded = audio.tokenizer.quantize(&feats, rows, true, audio.pool());
256 let levels = exact.len() / rows;
257 save_i32(&out.join("codes_exact.npy"), &[rows, levels], &exact);
258 save_i32(&out.join("codes_bf16books.npy"), &[rows, levels], &rounded);
259 let own = mimo_audio::AudioCodes {
260 frames: rows,
261 levels,
262 codes: if audio.bf16_codebooks {
263 rounded.clone()
264 } else {
265 exact.clone()
266 },
267 };
268 let t3 = Instant::now();
269 let emb_own = audio.embed_codes(&own).unwrap();
270 let t_enc = t3.elapsed().as_secs_f64();
271 save_f32(
272 &out.join("embeds_own.npy"),
273 &[emb_own.n_tokens, emb_own.dim],
274 &emb_own.rows,
275 );
276 let fixed = match arg(&args, "--codes") {
277 Some(cp) => {
278 let (shape, v) = load_codes(Path::new(&cp));
279 mimo_audio::AudioCodes {
280 frames: shape[0],
281 levels: shape[1],
282 codes: v,
283 }
284 }
285 None => own.clone(),
286 };
287 let emb = audio.embed_codes(&fixed).unwrap();
288 save_f32(&out.join("embeds.npy"), &[emb.n_tokens, emb.dim], &emb.rows);
289 let k = mimo_audio::audio_token_count(m, audio.encoder.cfg.group);
290 let meta = serde_json::json!({
291 "src": src.display().to_string(),
292 "mel_frames": m,
293 "segments": mimo_audio::segment_lengths(m),
294 "codes": rows,
295 "placeholder_count_K": k,
296 "embed_rows_own": emb_own.n_tokens,
297 "embed_rows_fixed": emb.n_tokens,
298 "load_s": t_load,
299 "features_s": t_feats,
300 "rvq_s": t_rvq,
301 "encoder_s": t_enc,
302 "bf16_codebooks_default": audio.bf16_codebooks,
303 "threads": cortiq_engine::pool::Pool::effective_threads(),
304 });
305 std::fs::write(
306 out.join("tower.json"),
307 serde_json::to_string_pretty(&meta).unwrap(),
308 )
309 .unwrap();
310 println!("{meta}");
311 assert_eq!(emb_own.n_tokens, k, "placeholder count != encoder rows");
312 }
313 "calib" => {
314 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
315 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
316 let audio = MimoAudio::from_model(&model).expect("load towers");
317 let dir = PathBuf::from(arg(&args, "--wav-dir").expect("--wav-dir"));
318 let mut wavs: Vec<PathBuf> = std::fs::read_dir(&dir)
319 .unwrap()
320 .filter_map(|e| e.ok().map(|e| e.path()))
321 .filter(|p| p.extension().is_some_and(|e| e == "wav"))
322 .collect();
323 wavs.sort();
324 let t0 = Instant::now();
325 cortiq_engine::gptq_capture::begin(true);
326 let mut frames = 0usize;
327 for w in &wavs {
328 let emb = audio.embed_wav(&std::fs::read(w).unwrap()).unwrap();
329 frames += emb.n_tokens;
330 eprintln!(
331 " {} -> {} rows ({:.0}s)",
332 w.display(),
333 emb.n_tokens,
334 t0.elapsed().as_secs_f64()
335 );
336 }
337 let hess = cortiq_engine::gptq_capture::end();
338 save_hessians(&out, &hess);
339 println!(
340 "{} clips, {frames} LLM rows, {} linears -> {} ({:.0}s)",
341 wavs.len(),
342 hess.len(),
343 out.display(),
344 t0.elapsed().as_secs_f64()
345 );
346 }
347 _ => {
348 eprintln!(
349 "usage: mimo_audio_dump (decode|frontend|tower|calib) --out ... (see the source header)"
350 );
351 std::process::exit(2);
352 }
353 }
354}Sourcepub fn embed_wav(&self, bytes: &[u8]) -> Result<AudioEmbeds, String>
pub fn embed_wav(&self, bytes: &[u8]) -> Result<AudioEmbeds, String>
WAV bytes → LLM embedding rows (one per <|audio_pad|>).
Examples found in repository?
175fn main() {
176 let args: Vec<String> = std::env::args().collect();
177 let cmd = args.get(1).map(String::as_str).unwrap_or("");
178 let out = PathBuf::from(arg(&args, "--out").expect("--out"));
179 match cmd {
180 "decode" => {
181 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
182 let w = mimo_audio::decode_wav(&wav).unwrap();
183 let flat: Vec<f32> = w.channels.concat();
184 save_f32(&out, &[w.channels.len(), w.frames()], &flat);
185 println!(
186 "rate {} channels {} frames {}",
187 w.sample_rate,
188 w.channels.len(),
189 w.frames()
190 );
191 }
192 "frontend" => {
193 std::fs::create_dir_all(&out).unwrap();
194 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
195 let t0 = Instant::now();
196 let w = mimo_audio::decode_wav(&wav).unwrap();
197 save_f32(
198 &out.join("dec.npy"),
199 &[w.channels.len(), w.frames()],
200 &w.channels.concat(),
201 );
202 let chans: Vec<Vec<f32>> = w
203 .channels
204 .iter()
205 .map(|c| mimo_audio::resample_sinc(c, w.sample_rate, mimo_audio::SAMPLE_RATE))
206 .collect();
207 save_f32(
208 &out.join("chan24k.npy"),
209 &[chans.len(), chans[0].len()],
210 &chans.concat(),
211 );
212 let mono = mimo_audio::wav_to_mono_24k(&w).unwrap();
213 save_f32(&out.join("wave24k.npy"), &[mono.len()], &mono);
214 let pool = cortiq_engine::pool::Pool::from_env();
215 let (mel, m) = mimo_audio::log_mel(&mono, pool.as_deref()).unwrap();
216 save_f32(&out.join("mel.npy"), &[m, mimo_audio::N_MELS], &mel);
217 println!(
218 "rate {} channels {} frames {} -> {} samples, {m} mel frames, K {} ({:.3}s)",
219 w.sample_rate,
220 w.channels.len(),
221 w.frames(),
222 mono.len(),
223 mimo_audio::audio_token_count(m, 4),
224 t0.elapsed().as_secs_f64()
225 );
226 }
227 "tower" => {
228 std::fs::create_dir_all(&out).unwrap();
229 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
230 let t0 = Instant::now();
231 let audio = if src.extension().is_some_and(|e| e == "cmf") {
232 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
233 MimoAudio::from_model(&model).expect("load towers")
234 } else {
235 MimoAudio::from_hf_dir(&src).expect("load towers")
236 };
237 let t_load = t0.elapsed().as_secs_f64();
238 let (mel, m) = if let Some(mp) = arg(&args, "--mel") {
239 let (shape, v) = load_f32(Path::new(&mp));
240 assert_eq!(shape[1], mimo_audio::N_MELS);
241 (v, shape[0])
242 } else {
243 let wav = std::fs::read(arg(&args, "--wav").expect("--wav or --mel")).unwrap();
244 audio.wav_to_mel(&wav).unwrap()
245 };
246 let t1 = Instant::now();
247 let feats = audio.features(&mel, m).unwrap();
248 let t_feats = t1.elapsed().as_secs_f64();
249 let d = audio.tokenizer.cfg.d_model;
250 let rows = feats.len() / d;
251 save_f32(&out.join("feats.npy"), &[rows, d], &feats);
252 let t2 = Instant::now();
253 let exact = audio.tokenizer.quantize(&feats, rows, false, audio.pool());
254 let t_rvq = t2.elapsed().as_secs_f64();
255 let rounded = audio.tokenizer.quantize(&feats, rows, true, audio.pool());
256 let levels = exact.len() / rows;
257 save_i32(&out.join("codes_exact.npy"), &[rows, levels], &exact);
258 save_i32(&out.join("codes_bf16books.npy"), &[rows, levels], &rounded);
259 let own = mimo_audio::AudioCodes {
260 frames: rows,
261 levels,
262 codes: if audio.bf16_codebooks {
263 rounded.clone()
264 } else {
265 exact.clone()
266 },
267 };
268 let t3 = Instant::now();
269 let emb_own = audio.embed_codes(&own).unwrap();
270 let t_enc = t3.elapsed().as_secs_f64();
271 save_f32(
272 &out.join("embeds_own.npy"),
273 &[emb_own.n_tokens, emb_own.dim],
274 &emb_own.rows,
275 );
276 let fixed = match arg(&args, "--codes") {
277 Some(cp) => {
278 let (shape, v) = load_codes(Path::new(&cp));
279 mimo_audio::AudioCodes {
280 frames: shape[0],
281 levels: shape[1],
282 codes: v,
283 }
284 }
285 None => own.clone(),
286 };
287 let emb = audio.embed_codes(&fixed).unwrap();
288 save_f32(&out.join("embeds.npy"), &[emb.n_tokens, emb.dim], &emb.rows);
289 let k = mimo_audio::audio_token_count(m, audio.encoder.cfg.group);
290 let meta = serde_json::json!({
291 "src": src.display().to_string(),
292 "mel_frames": m,
293 "segments": mimo_audio::segment_lengths(m),
294 "codes": rows,
295 "placeholder_count_K": k,
296 "embed_rows_own": emb_own.n_tokens,
297 "embed_rows_fixed": emb.n_tokens,
298 "load_s": t_load,
299 "features_s": t_feats,
300 "rvq_s": t_rvq,
301 "encoder_s": t_enc,
302 "bf16_codebooks_default": audio.bf16_codebooks,
303 "threads": cortiq_engine::pool::Pool::effective_threads(),
304 });
305 std::fs::write(
306 out.join("tower.json"),
307 serde_json::to_string_pretty(&meta).unwrap(),
308 )
309 .unwrap();
310 println!("{meta}");
311 assert_eq!(emb_own.n_tokens, k, "placeholder count != encoder rows");
312 }
313 "calib" => {
314 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
315 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
316 let audio = MimoAudio::from_model(&model).expect("load towers");
317 let dir = PathBuf::from(arg(&args, "--wav-dir").expect("--wav-dir"));
318 let mut wavs: Vec<PathBuf> = std::fs::read_dir(&dir)
319 .unwrap()
320 .filter_map(|e| e.ok().map(|e| e.path()))
321 .filter(|p| p.extension().is_some_and(|e| e == "wav"))
322 .collect();
323 wavs.sort();
324 let t0 = Instant::now();
325 cortiq_engine::gptq_capture::begin(true);
326 let mut frames = 0usize;
327 for w in &wavs {
328 let emb = audio.embed_wav(&std::fs::read(w).unwrap()).unwrap();
329 frames += emb.n_tokens;
330 eprintln!(
331 " {} -> {} rows ({:.0}s)",
332 w.display(),
333 emb.n_tokens,
334 t0.elapsed().as_secs_f64()
335 );
336 }
337 let hess = cortiq_engine::gptq_capture::end();
338 save_hessians(&out, &hess);
339 println!(
340 "{} clips, {frames} LLM rows, {} linears -> {} ({:.0}s)",
341 wavs.len(),
342 hess.len(),
343 out.display(),
344 t0.elapsed().as_secs_f64()
345 );
346 }
347 _ => {
348 eprintln!(
349 "usage: mimo_audio_dump (decode|frontend|tower|calib) --out ... (see the source header)"
350 );
351 std::process::exit(2);
352 }
353 }
354}