vad_rs/
helpers.rs

1use ebur128::EbuR128;
2use eyre::{bail, Result};
3
4pub fn audio_resample(
5    data: &[f32],
6    sample_rate0: u32,
7    sample_rate: u32,
8    channels: u16,
9) -> Vec<f32> {
10    use samplerate::{convert, ConverterType};
11    convert(
12        sample_rate0 as _,
13        sample_rate as _,
14        channels as _,
15        ConverterType::SincBestQuality,
16        data,
17    )
18    .unwrap_or_default()
19}
20
21pub fn stereo_to_mono(stereo_data: &[f32]) -> Result<Vec<f32>> {
22    if stereo_data.len() % 2 != 0 {
23        bail!("Stereo data length should be even.")
24    }
25
26    let mut mono_data = Vec::with_capacity(stereo_data.len() / 2);
27
28    for chunk in stereo_data.chunks_exact(2) {
29        let average = (chunk[0] + chunk[1]) / 2.0;
30        mono_data.push(average);
31    }
32
33    Ok(mono_data)
34}
35
36pub struct Normalizer {
37    ebur128: EbuR128,
38}
39
40impl Normalizer {
41    pub fn new(channels: u32, sample_rate: u32) -> Self {
42        let ebur128 = ebur128::EbuR128::new(channels, sample_rate, ebur128::Mode::all())
43            .expect("Failed to create ebur128");
44        Self { ebur128 }
45    }
46
47    /// Normalize loudness using ebur128. making the volume stable if too quiet / loud.
48    pub fn normalize_loudness(&mut self, samples: &[f32]) -> Vec<f32> {
49        // Apply loudness normalization
50        self.ebur128.add_frames_f32(samples).unwrap();
51        let loudness = self
52            .ebur128
53            .loudness_global()
54            .expect("Failed to get global loudness");
55        let target_loudness = -23.0; // EBU R128 target loudness
56        let gain = 10f32.powf(((target_loudness - loudness) / 20.0) as f32);
57
58        // Apply gain and clamp the result
59        let normalized_samples: Vec<f32> = samples
60            .iter()
61            .map(|&sample| (sample * gain).clamp(-1.0, 1.0))
62            .collect();
63
64        normalized_samples
65    }
66}