xsynth_core/effects/
limiter.rs

1use std::marker::PhantomData;
2
3struct SingleChannelLimiter {
4    loudness: f32,
5    attack: f32,
6    falloff: f32,
7    strength: f32,
8    min_thresh: f32,
9}
10
11impl SingleChannelLimiter {
12    fn new() -> SingleChannelLimiter {
13        SingleChannelLimiter {
14            loudness: 1.0,
15            attack: 100.0,
16            falloff: 16000.0,
17            strength: 1.0,
18            min_thresh: 1.0,
19        }
20    }
21
22    fn limit(&mut self, val: f32) -> f32 {
23        let abs = val.abs();
24        if self.loudness > abs {
25            self.loudness = (self.loudness * self.falloff + abs) / (self.falloff + 1.0);
26        } else {
27            self.loudness = (self.loudness * self.attack + abs) / (self.attack + 1.0);
28        }
29
30        if self.loudness < self.min_thresh {
31            self.loudness = self.min_thresh;
32        }
33
34        let val = val / (self.loudness * self.strength + 2.0 * (1.0 - self.strength)) / 2.0;
35
36        val
37    }
38}
39
40/// A multi-channel audio limiter.
41///
42/// Can be useful to prevent clipping on loud audio.
43pub struct VolumeLimiter {
44    channels: Vec<SingleChannelLimiter>,
45    channel_count: usize,
46}
47
48pub struct VolumeLimiterIter<'a, 'b, T: 'b + Iterator<Item = f32>> {
49    limiter: &'a mut VolumeLimiter,
50    samples: T,
51    pos: usize,
52    _b: PhantomData<&'b T>,
53}
54
55impl VolumeLimiter {
56    /// Initializes a new audio limiter with a specified audio channel count.
57    pub fn new(channel_count: u16) -> VolumeLimiter {
58        let mut limiters = Vec::new();
59        for _ in 0..channel_count {
60            limiters.push(SingleChannelLimiter::new());
61        }
62        VolumeLimiter {
63            channels: limiters,
64            channel_count: channel_count as usize,
65        }
66    }
67
68    /// Applies the limiting algorithm to the given sample buffer to prevent clipping.
69    pub fn limit(&mut self, sample: &mut [f32]) {
70        for (i, s) in sample.iter_mut().enumerate() {
71            *s = self.channels[i % self.channel_count].limit(*s);
72        }
73    }
74
75    pub fn limit_iter<'a, 'b, T: 'b + Iterator<Item = f32>>(
76        &'a mut self,
77        samples: T,
78    ) -> VolumeLimiterIter<'a, 'b, T> {
79        impl<'b, T: 'b + Iterator<Item = f32>> Iterator for VolumeLimiterIter<'_, 'b, T> {
80            type Item = f32;
81
82            fn next(&mut self) -> Option<Self::Item> {
83                let next = self.samples.next();
84                if let Some(next) = next {
85                    let val =
86                        self.limiter.channels[self.pos % self.limiter.channel_count].limit(next);
87                    self.pos += 1;
88                    Some(val)
89                } else {
90                    None
91                }
92            }
93        }
94
95        VolumeLimiterIter::<'a, 'b, T> {
96            _b: PhantomData,
97            limiter: self,
98            samples,
99            pos: 0,
100        }
101    }
102}