//! Phase 8.1.3 follow-up: build a 10 s WAV that is 50% silence + 50% //! real speech so we can verify the energy VAD gate actually skips //! silence. The standard /tmp/asr_test.flac is ~90% speech, which //! masks the structural VAD win. //! //! Output: /tmp/asr_silence_heavy.wav (10 s @ 24 kHz mono). //! //! Layout: 1 s silence, 4 s speech, 2 s silence, 3 s silence (total //! 5 s silence + 5 s speech). Speech is taken from the start of the //! input WAV. //! //! Usage: //! ```bash //! cargo run -p rtx-csm --release --example make_silence_test -- \ //! --in /tmp/asr_test.flac --out /tmp/asr_silence_heavy.wav //! ``` use anyhow::{Context, Result}; use clap::Parser; use rtx_csm::audio_io; use std::path::PathBuf; const SR: u32 = 24_000; #[derive(Debug, Parser)] struct Cli { #[arg(long = "in", default_value = "/tmp/asr_test.flac")] input: PathBuf, #[arg(long, default_value = "/tmp/asr_silence_heavy.wav")] out: PathBuf, } fn main() -> Result<()> { let cli = Cli::parse(); let speech = audio_io::load_mono_at_rate(&cli.input, SR).context("load speech")?; eprintln!( "loaded speech: {} samples ({:.2}s)", speech.len(), speech.len() as f32 / SR as f32 ); // Build: 1s silence | 4s speech | 2s silence | 3s silence (= 5s+5s). let mut out: Vec = Vec::with_capacity(SR as usize * 10); out.extend(std::iter::repeat(0.0f32).take(SR as usize)); // 1 s let speech_4s = (SR as usize * 4).min(speech.len()); out.extend_from_slice(&speech[..speech_4s]); // 4 s out.extend(std::iter::repeat(0.0f32).take(SR as usize * 2)); // 2 s out.extend(std::iter::repeat(0.0f32).take(SR as usize * 3)); // 3 s audio_io::write_wav_mono(cli.out.as_path(), &out, SR).context("write wav")?; eprintln!( "wrote {} ({} samples = {:.2}s, ~50% silence + 50% speech)", cli.out.display(), out.len(), out.len() as f32 / SR as f32 ); Ok(()) }