diff --git a/src-tauri/src/audio_toolkit/vad/smoothed.rs b/src-tauri/src/audio_toolkit/vad/smoothed.rs index cd3c608..50ef19a 100644 --- a/src-tauri/src/audio_toolkit/vad/smoothed.rs +++ b/src-tauri/src/audio_toolkit/vad/smoothed.rs @@ -6,9 +6,11 @@ pub struct SmoothedVad { inner_vad: Box, prefill_frames: usize, hangover_frames: usize, + onset_frames: usize, frame_buffer: VecDeque>, hangover_counter: usize, + onset_counter: usize, in_speech: bool, temp_out: Vec, @@ -19,13 +21,16 @@ impl SmoothedVad { inner_vad: Box, prefill_frames: usize, hangover_frames: usize, + onset_frames: usize, ) -> Self { Self { inner_vad, prefill_frames, hangover_frames, + onset_frames, frame_buffer: VecDeque::new(), hangover_counter: 0, + onset_counter: 0, in_speech: false, temp_out: Vec::new(), } @@ -42,19 +47,28 @@ impl VoiceActivityDetector for SmoothedVad { // 2. Delegate to the wrapped boolean VAD let is_voice = self.inner_vad.is_voice(frame)?; + // println!("Is Voice: {}", is_voice); match (self.in_speech, is_voice) { - // Start of Speech + // Potential start of speech - need to accumulate onset frames (false, true) => { - self.in_speech = true; - self.hangover_counter = self.hangover_frames; + self.onset_counter += 1; + if self.onset_counter >= self.onset_frames { + // We have enough consecutive voice frames to trigger speech + self.in_speech = true; + self.hangover_counter = self.hangover_frames; + self.onset_counter = 0; // Reset for next time - // Collect prefill + current frame - self.temp_out.clear(); - for buf in &self.frame_buffer { - self.temp_out.extend(buf); + // Collect prefill + current frame + self.temp_out.clear(); + for buf in &self.frame_buffer { + self.temp_out.extend(buf); + } + Ok(VadFrame::Speech(&self.temp_out)) + } else { + // Not enough frames yet, still silence + Ok(VadFrame::Noise) } - Ok(VadFrame::Speech(&self.temp_out)) } // Ongoing Speech @@ -63,7 +77,7 @@ impl VoiceActivityDetector for SmoothedVad { Ok(VadFrame::Speech(frame)) } - // End of Speech + // End of Speech or interruption during onset phase (true, false) => { if self.hangover_counter > 0 { self.hangover_counter -= 1; @@ -74,14 +88,18 @@ impl VoiceActivityDetector for SmoothedVad { } } - // Silence - (false, false) => Ok(VadFrame::Noise), + // Silence or broken onset sequence + (false, false) => { + self.onset_counter = 0; // Reset onset counter on silence + Ok(VadFrame::Noise) + } } } fn reset(&mut self) { self.frame_buffer.clear(); self.hangover_counter = 0; + self.onset_counter = 0; self.in_speech = false; self.temp_out.clear(); } diff --git a/src-tauri/src/managers/audio.rs b/src-tauri/src/managers/audio.rs index 3b12ae4..e5c8994 100644 --- a/src-tauri/src/managers/audio.rs +++ b/src-tauri/src/managers/audio.rs @@ -24,9 +24,9 @@ pub enum MicrophoneMode { /* ──────────────────────────────────────────────────────────────── */ fn create_audio_recorder(vad_path: &str) -> Result { - let silero = SileroVad::new(vad_path, 0.5) + let silero = SileroVad::new(vad_path, 0.3) .map_err(|e| anyhow::anyhow!("Failed to create SileroVad: {}", e))?; - let smoothed_vad = SmoothedVad::new(Box::new(silero), 15, 15); + let smoothed_vad = SmoothedVad::new(Box::new(silero), 15, 15, 2); let recorder = AudioRecorder::new() .map_err(|e| anyhow::anyhow!("Failed to create AudioRecorder: {}", e))? .with_vad(Box::new(smoothed_vad)); @@ -246,7 +246,8 @@ impl AudioRecordingManager { // Pad if very short let s_len = samples.len(); - if s_len < WHISPER_SAMPLE_RATE && s_len > 1000 { + // println!("Got {} samples", { s_len }); + if s_len < WHISPER_SAMPLE_RATE && s_len > 0 { let mut padded = samples; padded.resize(WHISPER_SAMPLE_RATE * 5 / 4, 0.0); Some(padded)