1use std::sync::Arc;
4use std::sync::atomic::{AtomicI32, Ordering};
5
6pub use crate::util::AtomicF32;
10
11use crate::{nice_debug_assert, nice_debug_assert_ne};
12
13#[derive(Debug, Clone)]
15pub enum SmoothingStyle {
16 OversamplingAware(Arc<AtomicF32>, &'static SmoothingStyle),
22
23 None,
26 Linear(f32),
29 Logarithmic(f32),
36 Exponential(f32),
44}
45
46#[derive(Debug)]
51pub struct Smoother<T: Smoothable> {
52 pub style: SmoothingStyle,
54 steps_left: AtomicI32,
59 step_size: AtomicF32,
66 current: AtomicF32,
68 target: T::Atomic,
70}
71
72pub struct SmootherIter<'a, T: Smoothable> {
77 smoother: &'a Smoother<T>,
78}
79
80impl SmoothingStyle {
81 #[inline]
84 pub fn num_steps(&self, sample_rate: f32) -> u32 {
85 nice_debug_assert!(sample_rate > 0.0);
86
87 match self {
88 Self::OversamplingAware(oversampling_times, style) => {
89 style.num_steps(sample_rate * oversampling_times.load(Ordering::Relaxed))
90 }
91
92 Self::None => 1,
93 Self::Linear(time) | Self::Logarithmic(time) | Self::Exponential(time) => {
94 nice_debug_assert!(*time >= 0.0);
95 (sample_rate * time / 1000.0).round() as u32
96 }
97 }
98 }
99
100 #[inline]
104 pub fn step_size(&self, start: f32, target: f32, num_steps: u32) -> f32 {
105 nice_debug_assert!(num_steps >= 1);
106
107 match self {
108 Self::OversamplingAware(_, style) => style.step_size(start, target, num_steps),
109
110 Self::None => 0.0,
111 Self::Linear(_) => (target - start) / (num_steps as f32),
112 Self::Logarithmic(_) => {
113 nice_debug_assert_ne!(start, 0.0);
115 ((target / start) as f64).powf((num_steps as f64).recip()) as f32
116 }
117 Self::Exponential(_) => 0.0001f64.powf((num_steps as f64).recip()) as f32,
122 }
123 }
124
125 #[inline]
132 pub fn next(&self, current: f32, target: f32, step_size: f32) -> f32 {
133 match self {
134 Self::OversamplingAware(_, style) => style.next(current, target, step_size),
135
136 Self::None => target,
137 Self::Linear(_) => current + step_size,
138 Self::Logarithmic(_) => current * step_size,
139 Self::Exponential(_) => (current * step_size) + (target * (1.0 - step_size)),
140 }
141 }
142
143 #[inline]
150 pub fn next_step(&self, current: f32, target: f32, step_size: f32, steps: u32) -> f32 {
151 nice_debug_assert!(steps >= 1);
152
153 match self {
154 Self::OversamplingAware(_, style) => style.next_step(current, target, step_size, steps),
155
156 Self::None => target,
157 Self::Linear(_) => current + (step_size * steps as f32),
158 Self::Logarithmic(_) => current * (step_size.powi(steps as i32)),
159 Self::Exponential(_) => {
160 let coefficient = step_size.powi(steps as i32);
163 (current * coefficient) + (target * (1.0 - coefficient))
164 }
165 }
166 }
167}
168
169pub trait Smoothable: Default + Clone + Copy {
172 type Atomic: Default;
174
175 fn to_f32(self) -> f32;
176 fn from_f32(value: f32) -> Self;
177
178 fn atomic_new(value: Self) -> Self::Atomic;
179 fn atomic_load(this: &Self::Atomic) -> Self;
181 fn atomic_store(this: &Self::Atomic, value: Self);
183}
184
185impl<T: Smoothable> Default for Smoother<T> {
186 fn default() -> Self {
187 Self {
188 style: SmoothingStyle::None,
189 steps_left: AtomicI32::new(0),
190 step_size: Default::default(),
191 current: AtomicF32::new(0.0),
192 target: Default::default(),
193 }
194 }
195}
196
197impl<T: Smoothable> Iterator for SmootherIter<'_, T> {
198 type Item = T;
199
200 #[inline]
201 fn next(&mut self) -> Option<Self::Item> {
202 Some(self.smoother.next())
203 }
204}
205
206impl<T: Smoothable> Clone for Smoother<T> {
207 fn clone(&self) -> Self {
208 Self {
211 style: self.style.clone(),
212 steps_left: AtomicI32::new(self.steps_left.load(Ordering::Relaxed)),
213 step_size: AtomicF32::new(self.step_size.load(Ordering::Relaxed)),
214 current: AtomicF32::new(self.current.load(Ordering::Relaxed)),
215 target: T::atomic_new(T::atomic_load(&self.target)),
216 }
217 }
218}
219
220impl<T: Smoothable> Smoother<T> {
221 pub fn new(style: SmoothingStyle) -> Self {
223 Self {
224 style,
225 ..Default::default()
226 }
227 }
228
229 pub fn none() -> Self {
231 Default::default()
232 }
233
234 #[inline]
237 pub fn steps_left(&self) -> i32 {
238 self.steps_left.load(Ordering::Relaxed)
239 }
240
241 #[inline]
244 pub fn is_smoothing(&self) -> bool {
245 self.steps_left() > 0
246 }
247
248 #[inline]
252 pub fn iter(&self) -> SmootherIter<'_, T> {
253 SmootherIter { smoother: self }
254 }
255
256 pub fn reset(&self, value: T) {
258 T::atomic_store(&self.target, value);
259 self.current.store(value.to_f32(), Ordering::Relaxed);
260 self.steps_left.store(0, Ordering::Relaxed);
261 }
262
263 pub fn set_target(&self, sample_rate: f32, target: T) {
265 T::atomic_store(&self.target, target);
266
267 let steps_left = self.style.num_steps(sample_rate) as i32;
268 self.steps_left.store(steps_left, Ordering::Relaxed);
269
270 let current = self.current.load(Ordering::Relaxed);
271 let target_f32 = target.to_f32();
272 self.step_size.store(
273 if steps_left > 0 {
274 self.style.step_size(current, target_f32, steps_left as u32)
275 } else {
276 0.0
277 },
278 Ordering::Relaxed,
279 );
280 }
281
282 #[allow(clippy::should_implement_trait)]
286 #[inline]
287 pub fn next(&self) -> T {
288 let target = T::atomic_load(&self.target);
289
290 if self.steps_left.load(Ordering::Relaxed) > 0 {
293 let current = self.current.load(Ordering::Relaxed);
294 let target_f32 = target.to_f32();
295 let step_size = self.step_size.load(Ordering::Relaxed);
296
297 let old_steps_left = self.steps_left.fetch_sub(1, Ordering::Relaxed);
303 let new = if old_steps_left == 1 {
304 self.steps_left.store(0, Ordering::Relaxed);
305 target_f32
306 } else {
307 self.style.next(current, target_f32, step_size)
308 };
309 self.current.store(new, Ordering::Relaxed);
310
311 T::from_f32(new)
312 } else {
313 target
314 }
315 }
316
317 #[inline]
322 pub fn next_step(&self, steps: u32) -> T {
323 nice_debug_assert_ne!(steps, 0);
324
325 let target = T::atomic_load(&self.target);
326
327 if self.steps_left.load(Ordering::Relaxed) > 0 {
328 let current = self.current.load(Ordering::Relaxed);
329 let target_f32 = target.to_f32();
330 let step_size = self.step_size.load(Ordering::Relaxed);
331
332 let old_steps_left = self.steps_left.fetch_sub(steps as i32, Ordering::Relaxed);
338 let new = if old_steps_left <= steps as i32 {
339 self.steps_left.store(0, Ordering::Relaxed);
340 target_f32
341 } else {
342 self.style.next_step(current, target_f32, step_size, steps)
343 };
344 self.current.store(new, Ordering::Relaxed);
345
346 T::from_f32(new)
347 } else {
348 target
349 }
350 }
351
352 pub fn previous_value(&self) -> T {
357 T::from_f32(self.current.load(Ordering::Relaxed))
358 }
359
360 pub fn next_block(&self, block_values: &mut [T], block_len: usize) {
370 self.next_block_exact(&mut block_values[..block_len])
371 }
372
373 pub fn next_block_exact(&self, block_values: &mut [T]) {
375 let target = T::atomic_load(&self.target);
376
377 let steps_left = self.steps_left.load(Ordering::Relaxed) as usize;
383 let num_smoothed_values = block_values.len().min(steps_left);
384 if num_smoothed_values > 0 {
385 let mut current = self.current.load(Ordering::Relaxed);
386 let target_f32 = target.to_f32();
387 let step_size = self.step_size.load(Ordering::Relaxed);
388
389 if num_smoothed_values == steps_left {
390 block_values[..num_smoothed_values - 1].fill_with(|| {
393 current = self.style.next(current, target_f32, step_size);
394 T::from_f32(current)
395 });
396
397 current = target_f32.to_f32();
400 block_values[num_smoothed_values - 1] = target;
401 } else {
402 block_values[..num_smoothed_values].fill_with(|| {
403 current = self.style.next(current, target_f32, step_size);
404 T::from_f32(current)
405 });
406 }
407
408 block_values[num_smoothed_values..].fill(target);
409
410 self.current.store(current, Ordering::Relaxed);
411 self.steps_left
412 .fetch_sub(num_smoothed_values as i32, Ordering::Relaxed);
413 } else {
414 block_values.fill(target);
415 }
416 }
417
418 pub fn next_block_mapped(
424 &self,
425 block_values: &mut [T],
426 block_len: usize,
427 f: impl FnMut(usize, f32) -> T,
428 ) {
429 self.next_block_exact_mapped(&mut block_values[..block_len], f)
430 }
431
432 pub fn next_block_exact_mapped(
435 &self,
436 block_values: &mut [T],
437 mut f: impl FnMut(usize, f32) -> T,
438 ) {
439 let target_f32 = T::atomic_load(&self.target).to_f32();
442
443 let steps_left = self.steps_left.load(Ordering::Relaxed) as usize;
444 let num_smoothed_values = block_values.len().min(steps_left);
445 if num_smoothed_values > 0 {
446 let mut current = self.current.load(Ordering::Relaxed);
447 let step_size = self.step_size.load(Ordering::Relaxed);
448
449 if num_smoothed_values == steps_left {
451 for (idx, value) in block_values
452 .iter_mut()
453 .enumerate()
454 .take(num_smoothed_values - 1)
455 {
456 current = self.style.next(current, target_f32, step_size);
457 *value = f(idx, current);
458 }
459
460 current = target_f32.to_f32();
461 block_values[num_smoothed_values - 1] = f(num_smoothed_values - 1, target_f32);
462 } else {
463 for (idx, value) in block_values
464 .iter_mut()
465 .enumerate()
466 .take(num_smoothed_values)
467 {
468 current = self.style.next(current, target_f32, step_size);
469 *value = f(idx, current);
470 }
471 }
472
473 for (idx, value) in block_values
474 .iter_mut()
475 .enumerate()
476 .skip(num_smoothed_values)
477 {
478 *value = f(idx, target_f32);
479 }
480
481 self.current.store(current, Ordering::Relaxed);
482 self.steps_left
483 .fetch_sub(num_smoothed_values as i32, Ordering::Relaxed);
484 } else {
485 for (idx, value) in block_values.iter_mut().enumerate() {
486 *value = f(idx, target_f32);
487 }
488 }
489 }
490}
491
492impl Smoothable for f32 {
493 type Atomic = AtomicF32;
494
495 #[inline]
496 fn to_f32(self) -> f32 {
497 self
498 }
499
500 #[inline]
501 fn from_f32(value: f32) -> Self {
502 value
503 }
504
505 #[inline]
506 fn atomic_new(value: Self) -> Self::Atomic {
507 AtomicF32::new(value)
508 }
509
510 #[inline]
511 fn atomic_load(this: &Self::Atomic) -> Self {
512 this.load(Ordering::Relaxed)
513 }
514
515 #[inline]
516 fn atomic_store(this: &Self::Atomic, value: Self) {
517 this.store(value, Ordering::Relaxed)
518 }
519}
520
521impl Smoothable for i32 {
522 type Atomic = AtomicI32;
523
524 #[inline]
525 fn to_f32(self) -> f32 {
526 self as f32
527 }
528
529 #[inline]
530 fn from_f32(value: f32) -> Self {
531 value.round() as i32
532 }
533
534 #[inline]
535 fn atomic_new(value: Self) -> Self::Atomic {
536 AtomicI32::new(value)
537 }
538
539 #[inline]
540 fn atomic_load(this: &Self::Atomic) -> Self {
541 this.load(Ordering::Relaxed)
542 }
543
544 #[inline]
545 fn atomic_store(this: &Self::Atomic, value: Self) {
546 this.store(value, Ordering::Relaxed)
547 }
548}
549
550#[cfg(test)]
551mod tests {
552 use super::*;
553
554 #[test]
556 fn linear_f32_next_equivalence() {
557 let style = SmoothingStyle::Linear(100.0);
558
559 let mut current = 0.4;
560 let target = 0.8;
561 let steps = 15;
562 let step_size = style.step_size(current, target, steps);
563
564 let expected_result = style.next_step(current, target, step_size, steps);
565 for _ in 0..steps {
566 current = style.next(current, target, step_size);
567 }
568
569 approx::assert_relative_eq!(current, expected_result, epsilon = 1e-5);
570 }
571
572 #[test]
573 fn logarithmic_f32_next_equivalence() {
574 let style = SmoothingStyle::Logarithmic(100.0);
575
576 let mut current = 0.4;
577 let target = 0.8;
578 let steps = 15;
579 let step_size = style.step_size(current, target, steps);
580
581 let expected_result = style.next_step(current, target, step_size, steps);
582 for _ in 0..steps {
583 current = style.next(current, target, step_size);
584 }
585
586 approx::assert_relative_eq!(current, expected_result, epsilon = 1e-5);
587 }
588
589 #[test]
590 fn exponential_f32_next_equivalence() {
591 let style = SmoothingStyle::Exponential(100.0);
592
593 let mut current = 0.4;
594 let target = 0.8;
595 let steps = 15;
596 let step_size = style.step_size(current, target, steps);
597
598 let expected_result = style.next_step(current, target, step_size, steps);
599 for _ in 0..steps {
600 current = style.next(current, target, step_size);
601 }
602
603 approx::assert_relative_eq!(current, expected_result, epsilon = 1e-5);
604 }
605
606 #[test]
607 fn linear_f32_smoothing() {
608 let smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Linear(100.0));
609 smoother.reset(10.0);
610 assert_eq!(smoother.next(), 10.0);
611
612 smoother.set_target(100.0, 20.0);
615 for _ in 0..(10 - 2) {
616 smoother.next();
617 }
618 assert_ne!(smoother.next(), 20.0);
619 assert_eq!(smoother.next(), 20.0);
620 }
621
622 #[test]
623 fn linear_i32_smoothing() {
624 let smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Linear(100.0));
625 smoother.reset(10);
626 assert_eq!(smoother.next(), 10);
627
628 smoother.set_target(100.0, 20);
630 for _ in 0..(10 - 2) {
631 smoother.next();
632 }
633 assert_ne!(smoother.next(), 20);
634 assert_eq!(smoother.next(), 20);
635 }
636
637 #[test]
638 fn logarithmic_f32_smoothing() {
639 let smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
640 smoother.reset(10.0);
641 assert_eq!(smoother.next(), 10.0);
642
643 smoother.set_target(100.0, 20.0);
646 for _ in 0..(10 - 2) {
647 smoother.next();
648 }
649 assert_ne!(smoother.next(), 20.0);
650 assert_eq!(smoother.next(), 20.0);
651 }
652
653 #[test]
654 fn logarithmic_i32_smoothing() {
655 let smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
656 smoother.reset(10);
657 assert_eq!(smoother.next(), 10);
658
659 smoother.set_target(100.0, 20);
661 for _ in 0..(10 - 2) {
662 smoother.next();
663 }
664 assert_ne!(smoother.next(), 20);
665 assert_eq!(smoother.next(), 20);
666 }
667
668 #[test]
670 fn skipping_linear_f32_smoothing() {
671 let smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Linear(100.0));
672 smoother.reset(10.0);
673 assert_eq!(smoother.next(), 10.0);
674
675 smoother.set_target(100.0, 20.0);
676 smoother.next_step(8);
677 assert_ne!(smoother.next(), 20.0);
678 assert_eq!(smoother.next(), 20.0);
679 }
680
681 #[test]
683 fn skipping_linear_i32_smoothing() {
684 let smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Linear(100.0));
685 smoother.reset(10);
686 assert_eq!(smoother.next(), 10);
687
688 smoother.set_target(100.0, 20);
689 smoother.next_step(8);
690 assert_ne!(smoother.next(), 20);
691 assert_eq!(smoother.next(), 20);
692 }
693
694 #[test]
696 fn skipping_logarithmic_f32_smoothing() {
697 let smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
698 smoother.reset(10.0);
699 assert_eq!(smoother.next(), 10.0);
700
701 smoother.set_target(100.0, 20.0);
702 smoother.next_step(8);
703 assert_ne!(smoother.next(), 20.0);
704 assert_eq!(smoother.next(), 20.0);
705 }
706
707 #[test]
709 fn skipping_logarithmic_i32_smoothing() {
710 let smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
711 smoother.reset(10);
712 assert_eq!(smoother.next(), 10);
713
714 smoother.set_target(100.0, 20);
715 smoother.next_step(8);
716 assert_ne!(smoother.next(), 20);
717 assert_eq!(smoother.next(), 20);
718 }
719
720 }