Skip to main content

aria_kit/voice_activity/
mod.rs

1//! Voice-activity inference over canonical audio frames: which stretches
2//! carry a human voice rather than music, noise, or silence.
3
4#[cfg(feature = "silero")]
5mod silero;
6
7#[cfg(feature = "silero")]
8pub use silero::{SileroVad, Speech, speech_gate};
9
10pub const SPEECH_THRESHOLD: f32 = 0.5;
11
12pub trait VoiceActivityDetector {
13    /// The exact number of canonical samples `probability` accepts per call.
14    const FRAME_SAMPLES: usize;
15
16    /// Clears state carried across recordings; stateless detectors keep the no-op.
17    fn reset(&mut self) {}
18
19    fn probability(&mut self, samples: &[i16]) -> Result<f32, VoiceActivityError>;
20}
21
22impl<V: VoiceActivityDetector> VoiceActivityDetector for &mut V {
23    const FRAME_SAMPLES: usize = V::FRAME_SAMPLES;
24
25    fn reset(&mut self) {
26        (**self).reset();
27    }
28
29    fn probability(&mut self, samples: &[i16]) -> Result<f32, VoiceActivityError> {
30        (**self).probability(samples)
31    }
32}
33
34#[derive(Debug, thiserror::Error)]
35pub enum VoiceActivityError {
36    #[error("failed to load the bundled voice-activity model")]
37    LoadModel(#[source] Box<dyn std::error::Error + Send + Sync>),
38
39    #[error("voice-activity frame contains {actual_samples} samples; expected {expected_samples}")]
40    InvalidFrameLength {
41        actual_samples: usize,
42        expected_samples: usize,
43    },
44
45    #[error("voice-activity inference failed")]
46    Inference(#[source] Box<dyn std::error::Error + Send + Sync>),
47
48    #[error("voice-activity model returned invalid probability {0}")]
49    InvalidProbability(f32),
50}