use serde::{Deserialize, Serialize};
use super::MediaKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum GateReason {
Silence,
Uniform,
}
impl GateReason {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::Silence => "silence",
Self::Uniform => "uniform",
}
}
#[must_use]
pub fn from_token(s: &str) -> Option<Self> {
match s {
"silence" => Some(Self::Silence),
"uniform" => Some(Self::Uniform),
_ => None,
}
}
#[must_use]
pub fn metric(self) -> &'static str {
match self {
Self::Silence => "rms",
Self::Uniform => "variance",
}
}
#[must_use]
pub fn threshold_name(self) -> &'static str {
match self {
Self::Silence => "silence",
Self::Uniform => "uniformity",
}
}
}
impl std::fmt::Display for GateReason {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct MediaSkip {
pub reason: GateReason,
pub value: f64,
pub threshold: f64,
}
impl std::fmt::Display for MediaSkip {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"below {} threshold ({}={}, threshold {})",
self.reason.threshold_name(),
self.reason.metric(),
self.value,
self.threshold,
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct GateThresholds {
pub silence_rms: f64,
pub image_variance: f64,
}
pub const DEFAULT_SILENCE_RMS: f64 = 1e-4;
pub const DEFAULT_IMAGE_VARIANCE: f64 = 1e-5;
impl Default for GateThresholds {
fn default() -> Self {
Self {
silence_rms: DEFAULT_SILENCE_RMS,
image_variance: DEFAULT_IMAGE_VARIANCE,
}
}
}
impl GateThresholds {
#[must_use]
pub fn disabled() -> Self {
Self {
silence_rms: -1.0,
image_variance: -1.0,
}
}
}
#[must_use]
pub fn evaluate(kind: MediaKind, bytes: &[u8], thresholds: GateThresholds) -> Option<MediaSkip> {
match kind {
MediaKind::Audio => {
let stats = audio_stats(bytes)?;
(stats.rms <= thresholds.silence_rms).then_some(MediaSkip {
reason: GateReason::Silence,
value: stats.rms,
threshold: thresholds.silence_rms,
})
}
MediaKind::Vision => {
let stats = image_stats(bytes)?;
(stats.variance <= thresholds.image_variance).then_some(MediaSkip {
reason: GateReason::Uniform,
value: stats.variance,
threshold: thresholds.image_variance,
})
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct AudioStats {
pub peak: f64,
pub rms: f64,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ImageStats {
pub mean: f64,
pub variance: f64,
}
#[must_use]
pub fn audio_stats(bytes: &[u8]) -> Option<AudioStats> {
let pcm = wav_pcm(bytes)?;
Some(pcm_stats(&pcm))
}
#[must_use]
pub fn pcm_stats(samples: &[f64]) -> AudioStats {
let mut peak = 0.0_f64;
let mut sum_squares = 0.0_f64;
for s in samples {
peak = peak.max(s.abs());
sum_squares += s * s;
}
#[expect(
clippy::cast_precision_loss,
reason = "sample counts are far below 2^53; the mean only needs to be accurate \
to many more digits than a threshold comparison uses"
)]
let rms = if samples.is_empty() {
0.0
} else {
(sum_squares / samples.len() as f64).sqrt()
};
AudioStats { peak, rms }
}
#[must_use]
pub fn luma_stats(luma: &[u8]) -> ImageStats {
if luma.is_empty() {
return ImageStats {
mean: 0.0,
variance: 0.0,
};
}
#[expect(
clippy::cast_precision_loss,
reason = "pixel counts are far below 2^53 (the pixel cap is 40 megapixels)"
)]
let n = luma.len() as f64;
let mut sum = 0.0_f64;
let mut sum_squares = 0.0_f64;
for &b in luma {
let v = f64::from(b) / 255.0;
sum += v;
sum_squares += v * v;
}
let mean = sum / n;
ImageStats {
mean,
variance: (sum_squares / n - mean * mean).max(0.0),
}
}
fn wav_pcm(bytes: &[u8]) -> Option<Vec<f64>> {
const FORMAT_PCM: u16 = 0x0001;
const FORMAT_FLOAT: u16 = 0x0003;
const FORMAT_EXTENSIBLE: u16 = 0xFFFE;
const MAX_SAMPLES: usize = 64 * 1024 * 1024;
let u16_at = |at: usize| -> Option<u16> {
Some(u16::from_le_bytes(bytes.get(at..at + 2)?.try_into().ok()?))
};
let u32_at = |at: usize| -> Option<u32> {
Some(u32::from_le_bytes(bytes.get(at..at + 4)?.try_into().ok()?))
};
if bytes.get(..4)? != b"RIFF" || bytes.get(8..12)? != b"WAVE" {
return None;
}
let (mut format, mut bits) = (None, None);
let mut cursor = 12;
while cursor + 8 <= bytes.len() {
let id = bytes.get(cursor..cursor + 4)?;
let size = u32_at(cursor + 4)? as usize;
let body = cursor + 8;
match id {
b"fmt " if size >= 16 => {
let tag = u16_at(body)?;
let declared_bits = u16_at(body + 14)?;
let tag = if tag == FORMAT_EXTENSIBLE && size >= 26 {
u16_at(body + 24)?
} else {
tag
};
format = Some(tag);
bits = Some(declared_bits);
}
b"data" => {
let (format, bits) = (format?, bits?);
let data = bytes.get(body..body.saturating_add(size))?;
return decode_samples(data, format, bits, FORMAT_PCM, FORMAT_FLOAT, MAX_SAMPLES);
}
_ => {}
}
cursor = body.checked_add(size)?.checked_add(size & 1)?;
}
None
}
fn decode_samples(
data: &[u8],
format: u16,
bits: u16,
format_pcm: u16,
format_float: u16,
max_samples: usize,
) -> Option<Vec<f64>> {
let width = usize::from(bits).div_ceil(8);
if width == 0 || data.len() / width > max_samples {
return None;
}
if !data.len().is_multiple_of(width) {
return None;
}
let mut out = Vec::with_capacity(data.len() / width);
match (format, bits) {
(f, 8) if f == format_pcm => {
out.extend(data.iter().map(|&b| (f64::from(b) - 128.0) / 128.0));
}
(f, 16) if f == format_pcm => {
out.extend(
data.as_chunks::<2>()
.0
.iter()
.map(|c| f64::from(i16::from_le_bytes([c[0], c[1]])) / f64::from(1_i32 << 15)),
);
}
(f, 24) if f == format_pcm => {
out.extend(data.as_chunks::<3>().0.iter().map(|c| {
let v = i32::from_le_bytes([0, c[0], c[1], c[2]]) >> 8;
f64::from(v) / f64::from(1_i32 << 23)
}));
}
(f, 32) if f == format_pcm => {
out.extend(data.as_chunks::<4>().0.iter().map(|c| {
f64::from(i32::from_le_bytes([c[0], c[1], c[2], c[3]])) / 2_147_483_648.0
}));
}
(f, 32) if f == format_float => {
out.extend(
data.as_chunks::<4>()
.0
.iter()
.map(|c| f64::from(f32::from_le_bytes([c[0], c[1], c[2], c[3]]))),
);
}
(f, 64) if f == format_float => {
out.extend(
data.as_chunks::<8>()
.0
.iter()
.map(|c| f64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]])),
);
}
_ => return None,
}
out.iter().all(|s| s.is_finite()).then_some(out)
}
#[cfg(any(feature = "image-ocr", feature = "image-vision"))]
#[must_use]
pub fn image_stats(bytes: &[u8]) -> Option<ImageStats> {
if !crate::extract::image_dimensions_ok(bytes) {
return None;
}
let luma = image::load_from_memory(bytes).ok()?.into_luma8();
Some(luma_stats(luma.as_raw()))
}
#[cfg(not(any(feature = "image-ocr", feature = "image-vision")))]
#[must_use]
pub fn image_stats(_bytes: &[u8]) -> Option<ImageStats> {
None
}
#[cfg(test)]
mod tests {
use super::{
AudioStats, DEFAULT_IMAGE_VARIANCE, DEFAULT_SILENCE_RMS, GateReason, GateThresholds,
ImageStats, MediaKind, MediaSkip, audio_stats, evaluate, luma_stats, pcm_stats,
};
fn wav16(samples: &[i16]) -> Vec<u8> {
let data: Vec<u8> = samples.iter().flat_map(|s| s.to_le_bytes()).collect();
let mut out = Vec::new();
out.extend_from_slice(b"RIFF");
out.extend_from_slice(&u32::try_from(36 + data.len()).expect("fits").to_le_bytes());
out.extend_from_slice(b"WAVEfmt ");
out.extend_from_slice(&16_u32.to_le_bytes()); out.extend_from_slice(&1_u16.to_le_bytes()); out.extend_from_slice(&1_u16.to_le_bytes()); out.extend_from_slice(&8000_u32.to_le_bytes()); out.extend_from_slice(&16_000_u32.to_le_bytes()); out.extend_from_slice(&2_u16.to_le_bytes()); out.extend_from_slice(&16_u16.to_le_bytes()); out.extend_from_slice(b"data");
out.extend_from_slice(&u32::try_from(data.len()).expect("fits").to_le_bytes());
out.extend_from_slice(&data);
out
}
fn wav_with_data(bits: u16, data: &[u8]) -> Vec<u8> {
let mut out = Vec::new();
out.extend_from_slice(b"RIFF");
out.extend_from_slice(&u32::try_from(36 + data.len()).expect("fits").to_le_bytes());
out.extend_from_slice(b"WAVEfmt ");
out.extend_from_slice(&16_u32.to_le_bytes()); out.extend_from_slice(&1_u16.to_le_bytes()); out.extend_from_slice(&1_u16.to_le_bytes()); out.extend_from_slice(&8000_u32.to_le_bytes()); out.extend_from_slice(&16_000_u32.to_le_bytes()); out.extend_from_slice(&2_u16.to_le_bytes()); out.extend_from_slice(&bits.to_le_bytes());
out.extend_from_slice(b"data");
out.extend_from_slice(&u32::try_from(data.len()).expect("fits").to_le_bytes());
out.extend_from_slice(data);
out
}
#[test]
fn an_unaligned_data_chunk_abstains_rather_than_being_measured() {
for (bits, len) in [(16_u16, 65_usize), (24, 64), (32, 66)] {
let wav = wav_with_data(bits, &vec![0_u8; len]);
assert!(
audio_stats(&wav).is_none(),
"{bits}-bit with a {len}-byte data chunk must not be measured",
);
assert!(
evaluate(MediaKind::Audio, &wav, GateThresholds::default()).is_none(),
"{bits}-bit with a {len}-byte data chunk must PASS — measuring the \
aligned prefix of a corrupt clip would be a false skip",
);
}
assert_eq!(
audio_stats(&wav_with_data(16, &[0; 64])).expect("64 bytes is 32 whole samples"),
AudioStats {
peak: 0.0,
rms: 0.0
},
);
}
#[test]
fn digital_silence_measures_exactly_zero() {
let stats = audio_stats(&wav16(&[0; 800])).expect("a WAV is measurable");
assert_eq!(
stats,
AudioStats {
peak: 0.0,
rms: 0.0
}
);
}
#[test]
fn a_tone_is_far_above_the_silence_threshold() {
let samples: Vec<i16> = (0..800)
.map(|i| if i % 2 == 0 { 16_384 } else { -16_384 })
.collect();
let stats = audio_stats(&wav16(&samples)).expect("measurable");
assert!(
stats.rms > DEFAULT_SILENCE_RMS * 1000.0,
"a tone must clear the gate by orders of magnitude: {stats:?}"
);
assert!(
evaluate(
MediaKind::Audio,
&wav16(&samples),
GateThresholds::default()
)
.is_none()
);
}
#[test]
fn silence_is_refused_with_its_measured_value() {
let skip = evaluate(
MediaKind::Audio,
&wav16(&[0; 800]),
GateThresholds::default(),
)
.expect("digital silence must be refused");
assert_eq!(
skip,
MediaSkip {
reason: GateReason::Silence,
value: 0.0,
threshold: DEFAULT_SILENCE_RMS,
}
);
assert_eq!(
skip.to_string(),
"below silence threshold (rms=0, threshold 0.0001)"
);
}
#[test]
fn the_default_threshold_admits_dither_and_nothing_louder() {
let dither: Vec<i16> = (0..800).map(|i| if i % 2 == 0 { 2 } else { -2 }).collect();
assert!(
evaluate(MediaKind::Audio, &wav16(&dither), GateThresholds::default()).is_some(),
"a couple of least-significant bits is still silence"
);
let room_tone: Vec<i16> = (0..800)
.map(|i| if i % 2 == 0 { 33 } else { -33 })
.collect();
assert!(
evaluate(
MediaKind::Audio,
&wav16(&room_tone),
GateThresholds::default()
)
.is_none(),
"room tone must pass — the gate does not claim to stop confabulation"
);
}
#[test]
fn an_unmeasurable_blob_passes_rather_than_being_refused() {
for bytes in [
b"ID3\x04\x00\x00\x00\x00\x00\x00".as_slice(), b"fLaC\x00\x00\x00\x22".as_slice(), b"RIFF".as_slice(), b"".as_slice(),
&wav16(&[0; 4])[..20], ] {
assert!(audio_stats(bytes).is_none(), "must not measure {bytes:?}");
assert!(
evaluate(MediaKind::Audio, bytes, GateThresholds::default()).is_none(),
"abstention must pass, not skip: {bytes:?}"
);
}
}
#[test]
fn the_common_wav_sample_formats_are_all_measured_as_silent() {
const CASES: [(u16, u16, &[u8]); 6] = [
(1, 8, &[128]), (1, 16, &[0, 0]), (1, 24, &[0, 0, 0]), (1, 32, &[0, 0, 0, 0]), (3, 32, &[0, 0, 0, 0]), (3, 64, &[0, 0, 0, 0, 0, 0, 0, 0]), ];
for (format, bits, sample) in CASES {
let data: Vec<u8> = sample.repeat(64);
let mut out = Vec::new();
out.extend_from_slice(b"RIFF");
out.extend_from_slice(&u32::try_from(36 + data.len()).expect("fits").to_le_bytes());
out.extend_from_slice(b"WAVEfmt ");
out.extend_from_slice(&16_u32.to_le_bytes());
out.extend_from_slice(&format.to_le_bytes());
out.extend_from_slice(&1_u16.to_le_bytes());
out.extend_from_slice(&8000_u32.to_le_bytes());
out.extend_from_slice(&16_000_u32.to_le_bytes());
out.extend_from_slice(&2_u16.to_le_bytes());
out.extend_from_slice(&bits.to_le_bytes());
out.extend_from_slice(b"data");
out.extend_from_slice(&u32::try_from(data.len()).expect("fits").to_le_bytes());
out.extend_from_slice(&data);
let stats = audio_stats(&out).unwrap_or_else(|| panic!("{format}/{bits} must decode"));
assert_eq!(
stats,
AudioStats {
peak: 0.0,
rms: 0.0
},
"{format}/{bits} silence must measure zero",
);
}
}
#[test]
fn intervening_chunks_and_their_padding_are_walked_over() {
let data: Vec<u8> = vec![0; 128];
let mut out = Vec::new();
out.extend_from_slice(b"RIFFxxxxWAVEfmt ");
out.extend_from_slice(&16_u32.to_le_bytes());
out.extend_from_slice(&1_u16.to_le_bytes());
out.extend_from_slice(&1_u16.to_le_bytes());
out.extend_from_slice(&8000_u32.to_le_bytes());
out.extend_from_slice(&16_000_u32.to_le_bytes());
out.extend_from_slice(&2_u16.to_le_bytes());
out.extend_from_slice(&16_u16.to_le_bytes());
out.extend_from_slice(b"LIST");
out.extend_from_slice(&3_u32.to_le_bytes());
out.extend_from_slice(b"abc\0");
out.extend_from_slice(b"data");
out.extend_from_slice(&u32::try_from(data.len()).expect("fits").to_le_bytes());
out.extend_from_slice(&data);
assert_eq!(
audio_stats(&out).expect("measurable"),
AudioStats {
peak: 0.0,
rms: 0.0
}
);
}
#[test]
#[expect(
clippy::float_cmp,
reason = "a flat plane's variance is exactly zero — E[x^2] and E[x]^2 are the \
same sum, so the subtraction cancels bit for bit; a tolerance here \
would weaken the claim being made"
)]
fn a_flat_luma_plane_has_no_variance_whatever_its_colour() {
for level in [0_u8, 128, 255] {
let stats = luma_stats(&[level; 4096]);
assert_eq!(stats.variance, 0.0, "level {level} must be uniform");
assert!(
(stats.mean - f64::from(level) / 255.0).abs() < 1e-12,
"level {level} mean was {}",
stats.mean,
);
}
assert!(luma_stats(&[0; 16]).variance <= DEFAULT_IMAGE_VARIANCE);
assert!(luma_stats(&[255; 16]).variance <= DEFAULT_IMAGE_VARIANCE);
}
#[test]
fn a_textured_luma_plane_clears_the_uniformity_threshold() {
let plane: Vec<u8> = (0..4096)
.map(|i| if i % 2 == 0 { 120 } else { 136 })
.collect();
let variance = luma_stats(&plane).variance;
assert!(
variance > DEFAULT_IMAGE_VARIANCE * 50.0,
"a checkerboard of adjacent greys must clear the threshold: got {variance}",
);
}
#[test]
fn statistics_of_nothing_are_zero_rather_than_nan() {
assert_eq!(
pcm_stats(&[]),
AudioStats {
peak: 0.0,
rms: 0.0
}
);
assert_eq!(
luma_stats(&[]),
ImageStats {
mean: 0.0,
variance: 0.0
}
);
}
#[test]
fn disabled_thresholds_refuse_nothing() {
assert!(
evaluate(
MediaKind::Audio,
&wav16(&[0; 800]),
GateThresholds::disabled()
)
.is_none()
);
}
#[test]
fn gate_reason_tokens_round_trip() {
for reason in [GateReason::Silence, GateReason::Uniform] {
assert_eq!(GateReason::from_token(reason.as_str()), Some(reason));
}
assert_eq!(GateReason::from_token("blank"), None);
}
}