1pub const DENORMAL_THRESHOLD: f32 = 1e-30;
5
6#[inline(always)]
12pub fn sanitize_sample(sample: f32) -> f32 {
13 if !sample.is_finite() {
14 return 0.0;
15 }
16 if sample.abs() < DENORMAL_THRESHOLD {
17 return 0.0;
18 }
19 sample
20}
21
22pub fn sanitize_buffer(buffer: &mut [f32]) {
24 for sample in buffer.iter_mut() {
25 *sample = sanitize_sample(*sample);
26 }
27}
28
29pub fn sanitize_block(block: &mut crate::engine::AudioBlock<'_>) {
31 for channel_index in 0..block.channels() {
32 if let Some(channel) = block.channel_mut(channel_index) {
33 sanitize_buffer(channel);
34 }
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn non_finite_values_become_silence() {
44 assert_eq!(sanitize_sample(f32::NAN), 0.0);
45 assert_eq!(sanitize_sample(f32::INFINITY), 0.0);
46 assert_eq!(sanitize_sample(f32::NEG_INFINITY), 0.0);
47 }
48
49 #[test]
50 fn denormals_and_finite_values() {
51 assert_eq!(sanitize_sample(1e-32), 0.0);
52 assert!((sanitize_sample(0.5) - 0.5).abs() < 1e-6);
53 assert!((sanitize_sample(-0.25) + 0.25).abs() < 1e-6);
54 }
55
56 #[test]
57 fn buffer_is_sanitized_in_place() {
58 let mut buffer = [f32::NAN, 0.5, f32::INFINITY, 1e-35];
59 sanitize_buffer(&mut buffer);
60 assert_eq!(buffer, [0.0, 0.5, 0.0, 0.0]);
61 }
62}