Skip to main content

MimoAudio

Struct MimoAudio 

Source
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: bool

Quantize 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

Source

pub fn present_in(model: &CmfModel) -> bool

Whether a CMF carries the audio towers (a companion or a single-file multimodal container).

Source

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?
examples/mimo_audio_dump.rs (line 233)
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}
Source

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?
examples/mimo_audio_dump.rs (line 235)
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}
Source

pub fn pool(&self) -> Option<&Pool>

Examples found in repository?
examples/mimo_audio_dump.rs (line 253)
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}
Source

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?
examples/mimo_audio_dump.rs (line 244)
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}
Source

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?
examples/mimo_audio_dump.rs (line 247)
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}
Source

pub fn encode_mel(&self, mel: &[f32], m: usize) -> Result<AudioCodes, String>

Log-mel → tokenizer codes, each 6000-frame segment on its own.

Source

pub fn embed_codes(&self, codes: &AudioCodes) -> Result<AudioEmbeds, String>

Codes → LLM embedding rows.

Examples found in repository?
examples/mimo_audio_dump.rs (line 269)
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}
Source

pub fn embed_wav(&self, bytes: &[u8]) -> Result<AudioEmbeds, String>

WAV bytes → LLM embedding rows (one per <|audio_pad|>).

Examples found in repository?
examples/mimo_audio_dump.rs (line 328)
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}

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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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<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