1use std::fmt;
10use std::ops;
11use std::slice;
12
13use super::{SampleRate, Seconds};
14
15const SETTLE: f32 = 0.00001f32;
16
17#[derive(Debug, PartialEq, Clone, Copy)]
18pub enum SmoothStatus {
19 Inactive,
20 Active,
21 Deactivating,
22}
23
24impl SmoothStatus {
25 fn is_active(&self) -> bool {
26 self != &SmoothStatus::Inactive
27 }
28}
29
30pub struct SmoothOutputF32<'a, const MAX_BLOCKSIZE: usize> {
31 pub values: &'a [f32; MAX_BLOCKSIZE],
32 pub status: SmoothStatus,
33}
34
35impl<'a, const MAX_BLOCKSIZE: usize> SmoothOutputF32<'a, MAX_BLOCKSIZE> {
36 pub fn is_smoothing(&self) -> bool {
37 self.status.is_active()
38 }
39}
40
41impl<'a, I, const MAX_BLOCKSIZE: usize> ops::Index<I> for SmoothOutputF32<'a, MAX_BLOCKSIZE>
42where
43 I: slice::SliceIndex<[f32]>,
44{
45 type Output = I::Output;
46
47 #[inline]
48 fn index(&self, idx: I) -> &I::Output {
49 &self.values[idx]
50 }
51}
52
53pub struct SmoothF32<const MAX_BLOCKSIZE: usize> {
54 output: [f32; MAX_BLOCKSIZE],
55 input: f32,
56
57 status: SmoothStatus,
58
59 a: f32,
60 b: f32,
61 last_output: f32,
62}
63
64impl<const MAX_BLOCKSIZE: usize> SmoothF32<MAX_BLOCKSIZE> {
65 pub fn new(input: f32) -> Self {
66 Self {
67 status: SmoothStatus::Inactive,
68 input,
69 output: [input; MAX_BLOCKSIZE],
70
71 a: 1.0,
72 b: 0.0,
73 last_output: input,
74 }
75 }
76
77 pub fn reset(&mut self, val: f32) {
78 *self = Self {
79 a: self.a,
80 b: self.b,
81 ..Self::new(val)
82 };
83 }
84
85 pub fn set(&mut self, val: f32) {
86 self.input = val;
87 self.status = SmoothStatus::Active;
88 }
89
90 pub fn dest(&self) -> f32 {
91 self.input
92 }
93
94 pub fn output(&self) -> SmoothOutputF32<MAX_BLOCKSIZE> {
95 SmoothOutputF32 {
96 values: &self.output,
97 status: self.status,
98 }
99 }
100
101 pub fn current_value(&self) -> (f32, SmoothStatus) {
102 (self.last_output, self.status)
103 }
104
105 pub fn update_status_with_epsilon(&mut self, epsilon: f32) -> SmoothStatus {
106 let status = self.status;
107
108 match status {
109 SmoothStatus::Active => {
110 if (self.input - self.output[0]).abs() < epsilon {
111 self.reset(self.input);
112 self.status = SmoothStatus::Deactivating;
113 }
114 }
115
116 SmoothStatus::Deactivating => self.status = SmoothStatus::Inactive,
117
118 _ => (),
119 };
120
121 self.status
122 }
123
124 pub fn process(&mut self, frames: usize) {
125 if self.status != SmoothStatus::Active {
126 return;
127 }
128
129 let frames = frames.min(MAX_BLOCKSIZE);
130 let input = self.input * self.a;
131
132 self.output[0] = input + (self.last_output * self.b);
133
134 for i in 1..frames {
135 unsafe {
138 *self.output.get_unchecked_mut(i) =
139 input + (*self.output.get_unchecked(i - 1) * self.b);
140 }
141
142 self.output[i] = input + (self.output[i - 1] * self.b);
143 }
144
145 unsafe {
148 self.last_output = *self.output.get_unchecked(frames - 1);
149 }
150 }
151
152 pub fn is_active(&self) -> bool {
153 self.status.is_active()
154 }
155}
156
157impl<const MAX_BLOCKSIZE: usize> SmoothF32<MAX_BLOCKSIZE> {
158 pub fn set_speed(&mut self, sample_rate: SampleRate, seconds: Seconds) {
159 self.b = (-1.0f32 / (seconds.0 as f32 * sample_rate.0 as f32)).exp();
160 self.a = 1.0f32 - self.b;
161 }
162
163 pub fn update_status(&mut self) -> SmoothStatus {
164 self.update_status_with_epsilon(SETTLE)
165 }
166}
167
168impl<const MAX_BLOCKSIZE: usize> From<f32> for SmoothF32<MAX_BLOCKSIZE> {
169 fn from(val: f32) -> Self {
170 Self::new(val)
171 }
172}
173
174impl<const MAX_BLOCKSIZE: usize> fmt::Debug for SmoothF32<MAX_BLOCKSIZE> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_struct(concat!("SmoothF32"))
177 .field("output[0]", &self.output[0])
178 .field("input", &self.input)
179 .field("status", &self.status)
180 .field("last_output", &self.last_output)
181 .finish()
182 }
183}
184
185pub struct SmoothOutputF64<'a, const MAX_BLOCKSIZE: usize> {
188 pub values: &'a [f64; MAX_BLOCKSIZE],
189 pub status: SmoothStatus,
190}
191
192impl<'a, const MAX_BLOCKSIZE: usize> SmoothOutputF64<'a, MAX_BLOCKSIZE> {
193 pub fn is_smoothing(&self) -> bool {
194 self.status.is_active()
195 }
196}
197
198impl<'a, I, const MAX_BLOCKSIZE: usize> ops::Index<I> for SmoothOutputF64<'a, MAX_BLOCKSIZE>
199where
200 I: slice::SliceIndex<[f64]>,
201{
202 type Output = I::Output;
203
204 #[inline]
205 fn index(&self, idx: I) -> &I::Output {
206 &self.values[idx]
207 }
208}
209
210pub struct SmoothF64<const MAX_BLOCKSIZE: usize> {
211 output: [f64; MAX_BLOCKSIZE],
212 input: f64,
213
214 status: SmoothStatus,
215
216 a: f64,
217 b: f64,
218 last_output: f64,
219}
220
221impl<const MAX_BLOCKSIZE: usize> SmoothF64<MAX_BLOCKSIZE> {
222 pub fn new(input: f64) -> Self {
223 Self {
224 status: SmoothStatus::Inactive,
225 input,
226 output: [input; MAX_BLOCKSIZE],
227
228 a: 1.0,
229 b: 0.0,
230 last_output: input,
231 }
232 }
233
234 pub fn reset(&mut self, val: f64) {
235 *self = Self {
236 a: self.a,
237 b: self.b,
238 ..Self::new(val)
239 };
240 }
241
242 pub fn set(&mut self, val: f64) {
243 self.input = val;
244 self.status = SmoothStatus::Active;
245 }
246
247 pub fn dest(&self) -> f64 {
248 self.input
249 }
250
251 pub fn output(&self) -> SmoothOutputF64<MAX_BLOCKSIZE> {
252 SmoothOutputF64 {
253 values: &self.output,
254 status: self.status,
255 }
256 }
257
258 pub fn current_value(&self) -> (f64, SmoothStatus) {
259 (self.last_output, self.status)
260 }
261
262 pub fn update_status_with_epsilon(&mut self, epsilon: f64) -> SmoothStatus {
263 let status = self.status;
264
265 match status {
266 SmoothStatus::Active => {
267 if (self.input - self.output[0]).abs() < epsilon {
268 self.reset(self.input);
269 self.status = SmoothStatus::Deactivating;
270 }
271 }
272
273 SmoothStatus::Deactivating => self.status = SmoothStatus::Inactive,
274
275 _ => (),
276 };
277
278 self.status
279 }
280
281 pub fn process(&mut self, frames: usize) {
282 if self.status != SmoothStatus::Active {
283 return;
284 }
285
286 let frames = frames.min(MAX_BLOCKSIZE);
287 let input = self.input * self.a;
288
289 self.output[0] = input + (self.last_output * self.b);
290
291 for i in 1..frames {
292 unsafe {
295 *self.output.get_unchecked_mut(i) =
296 input + (*self.output.get_unchecked(i - 1) * self.b);
297 }
298
299 self.output[i] = input + (self.output[i - 1] * self.b);
300 }
301
302 unsafe {
305 self.last_output = *self.output.get_unchecked(frames - 1);
306 }
307 }
308
309 pub fn is_active(&self) -> bool {
310 self.status.is_active()
311 }
312}
313
314impl<const MAX_BLOCKSIZE: usize> SmoothF64<MAX_BLOCKSIZE> {
315 pub fn set_speed(&mut self, sample_rate: SampleRate, seconds: Seconds) {
316 self.b = (-1.0f64 / (seconds.0 as f64 * sample_rate.0 as f64)).exp();
317 self.a = 1.0f64 - self.b;
318 }
319
320 pub fn update_status(&mut self) -> SmoothStatus {
321 self.update_status_with_epsilon(SETTLE as f64)
322 }
323}
324
325impl<const MAX_BLOCKSIZE: usize> From<f64> for SmoothF64<MAX_BLOCKSIZE> {
326 fn from(val: f64) -> Self {
327 Self::new(val)
328 }
329}
330
331impl<const MAX_BLOCKSIZE: usize> fmt::Debug for SmoothF64<MAX_BLOCKSIZE> {
332 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333 f.debug_struct(concat!("SmoothF64"))
334 .field("output[0]", &self.output[0])
335 .field("input", &self.input)
336 .field("status", &self.status)
337 .field("last_output", &self.last_output)
338 .finish()
339 }
340}