1pub struct NoiseGate {
14 open_threshold: f32,
16 close_threshold: f32,
18 sample_rate: f32,
20 internal_sample_rate: f32,
22 release_rate: f32,
24 attack_rate: f32,
26 decay_rate: f32,
27 hold_time: f32,
29 channels: usize,
31 is_open: bool,
32 attenuation: f32,
33 level: f32,
34 held_time: f32,
35}
36
37impl NoiseGate {
38 pub fn new(
40 open_threshold: f32,
41 close_threshold: f32,
42 sample_rate: f32,
43 channels: usize,
44 release_rate: f32,
45 attack_rate: f32,
46 hold_time: f32
47 ) -> Self {
48 let threshold_diff = open_threshold - close_threshold;
49 let min_decay_period = (1.0 / 75.0) * sample_rate;
50
51 Self {
52 open_threshold: match open_threshold.is_finite() {
53 true => (10_f32).powf(open_threshold / 20.0),
54 false => 0.0,
55 },
56 close_threshold: match close_threshold.is_finite() {
57 true => (10_f32).powf(close_threshold / 20.0),
58 false => 0.0,
59 },
60 sample_rate: sample_rate,
61 internal_sample_rate: 1.0 / sample_rate,
62 channels: channels,
63 release_rate: 1.0 / (release_rate * 0.001 * sample_rate),
64 attack_rate: 1.0 / (attack_rate * 0.001 * sample_rate),
65 decay_rate: threshold_diff / min_decay_period,
66 hold_time: hold_time * 0.001,
67 is_open: false,
68 attenuation: 0.0,
69 level: 0.0,
70 held_time: 0.0,
71 }
72 }
73
74 pub fn update(
75 &mut self,
76 open_threshold: f32,
77 close_threshold: f32,
78 release_rate: f32,
79 attack_rate: f32,
80 hold_time: f32
81 ) {
82 let threshold_diff = open_threshold - close_threshold;
83 let min_decay_period = (1.0 / 75.0) * self.sample_rate;
84
85 self.open_threshold = match open_threshold.is_finite() {
86 true => (10_f32).powf(open_threshold / 20.0),
87 false => 0.0,
88 };
89 self.close_threshold = match close_threshold.is_finite() {
90 true => (10_f32).powf(close_threshold / 20.0),
91 false => 0.0,
92 };
93 self.release_rate = 1.0 / (release_rate * 0.001 * self.sample_rate);
94 self.attack_rate = 1.0 / (attack_rate * 0.001 * self.sample_rate);
95 self.decay_rate = threshold_diff / min_decay_period;
96 self.hold_time = hold_time * 0.001;
97 }
98
99 pub fn process_frame(&mut self, frame: &mut [f32]) {
102 let samples_per_channel = frame.len() / self.channels;
103
104 for i in 0..samples_per_channel {
105 let base_idx = i * self.channels;
107 let mut current_level = 0.0f32;
108 for c in 0..self.channels {
109 current_level = current_level.max(frame[base_idx + c].abs());
110 }
111
112 if current_level > self.open_threshold && !self.is_open {
114 self.is_open = true;
115 }
116
117 if self.level < self.close_threshold && self.is_open {
118 self.held_time = 0.0;
119 self.is_open = false;
120 }
121
122 self.level = self.level.max(current_level) - self.decay_rate;
123
124 if self.is_open {
126 self.attenuation = (self.attenuation + self.attack_rate).min(1.0);
127 } else {
128 self.held_time += self.internal_sample_rate;
129 if self.held_time > self.hold_time {
130 self.attenuation = (self.attenuation - self.release_rate).max(0.0);
131 }
132 }
133
134 for c in 0..self.channels {
136 frame[base_idx + c] *= self.attenuation;
137 }
138 }
139 }
140}