1use std::sync::Arc;
4use std::sync::atomic::{AtomicI32, Ordering};
5
6pub use atomic_float::AtomicF32;
8
9use crate::{nice_debug_assert, nice_debug_assert_ne};
10
11#[derive(Debug, Clone)]
13pub enum SmoothingStyle {
14 OversamplingAware(Arc<AtomicF32>, &'static SmoothingStyle),
20
21 None,
24 Linear(f32),
27 Logarithmic(f32),
34 Exponential(f32),
42}
43
44#[derive(Debug)]
49pub struct Smoother<T: Smoothable> {
50 pub style: SmoothingStyle,
52 steps_left: AtomicI32,
57 step_size: AtomicF32,
64 current: AtomicF32,
66 target: T::Atomic,
68}
69
70pub struct SmootherIter<'a, T: Smoothable> {
75 smoother: &'a Smoother<T>,
76}
77
78impl SmoothingStyle {
79 #[inline]
82 pub fn num_steps(&self, sample_rate: f32) -> u32 {
83 nice_debug_assert!(sample_rate > 0.0);
84
85 match self {
86 Self::OversamplingAware(oversampling_times, style) => {
87 style.num_steps(sample_rate * oversampling_times.load(Ordering::Relaxed))
88 }
89
90 Self::None => 1,
91 Self::Linear(time) | Self::Logarithmic(time) | Self::Exponential(time) => {
92 nice_debug_assert!(*time >= 0.0);
93 (sample_rate * time / 1000.0).round() as u32
94 }
95 }
96 }
97
98 #[inline]
102 pub fn step_size(&self, start: f32, target: f32, num_steps: u32) -> f32 {
103 nice_debug_assert!(num_steps >= 1);
104
105 match self {
106 Self::OversamplingAware(_, style) => style.step_size(start, target, num_steps),
107
108 Self::None => 0.0,
109 Self::Linear(_) => (target - start) / (num_steps as f32),
110 Self::Logarithmic(_) => {
111 nice_debug_assert_ne!(start, 0.0);
113 ((target / start) as f64).powf((num_steps as f64).recip()) as f32
114 }
115 Self::Exponential(_) => 0.0001f64.powf((num_steps as f64).recip()) as f32,
120 }
121 }
122
123 #[inline]
130 pub fn next(&self, current: f32, target: f32, step_size: f32) -> f32 {
131 match self {
132 Self::OversamplingAware(_, style) => style.next(current, target, step_size),
133
134 Self::None => target,
135 Self::Linear(_) => current + step_size,
136 Self::Logarithmic(_) => current * step_size,
137 Self::Exponential(_) => (current * step_size) + (target * (1.0 - step_size)),
138 }
139 }
140
141 #[inline]
148 pub fn next_step(&self, current: f32, target: f32, step_size: f32, steps: u32) -> f32 {
149 nice_debug_assert!(steps >= 1);
150
151 match self {
152 Self::OversamplingAware(_, style) => style.next_step(current, target, step_size, steps),
153
154 Self::None => target,
155 Self::Linear(_) => current + (step_size * steps as f32),
156 Self::Logarithmic(_) => current * (step_size.powi(steps as i32)),
157 Self::Exponential(_) => {
158 let coefficient = step_size.powi(steps as i32);
161 (current * coefficient) + (target * (1.0 - coefficient))
162 }
163 }
164 }
165}
166
167pub trait Smoothable: Default + Clone + Copy {
170 type Atomic: Default;
172
173 fn to_f32(self) -> f32;
174 fn from_f32(value: f32) -> Self;
175
176 fn atomic_new(value: Self) -> Self::Atomic;
177 fn atomic_load(this: &Self::Atomic) -> Self;
179 fn atomic_store(this: &Self::Atomic, value: Self);
181}
182
183impl<T: Smoothable> Default for Smoother<T> {
184 fn default() -> Self {
185 Self {
186 style: SmoothingStyle::None,
187 steps_left: AtomicI32::new(0),
188 step_size: Default::default(),
189 current: AtomicF32::new(0.0),
190 target: Default::default(),
191 }
192 }
193}
194
195impl<T: Smoothable> Iterator for SmootherIter<'_, T> {
196 type Item = T;
197
198 #[inline]
199 fn next(&mut self) -> Option<Self::Item> {
200 Some(self.smoother.next())
201 }
202}
203
204impl<T: Smoothable> Clone for Smoother<T> {
205 fn clone(&self) -> Self {
206 Self {
209 style: self.style.clone(),
210 steps_left: AtomicI32::new(self.steps_left.load(Ordering::Relaxed)),
211 step_size: AtomicF32::new(self.step_size.load(Ordering::Relaxed)),
212 current: AtomicF32::new(self.current.load(Ordering::Relaxed)),
213 target: T::atomic_new(T::atomic_load(&self.target)),
214 }
215 }
216}
217
218impl<T: Smoothable> Smoother<T> {
219 pub fn new(style: SmoothingStyle) -> Self {
221 Self {
222 style,
223 ..Default::default()
224 }
225 }
226
227 pub fn none() -> Self {
229 Default::default()
230 }
231
232 #[inline]
235 pub fn steps_left(&self) -> i32 {
236 self.steps_left.load(Ordering::Relaxed)
237 }
238
239 #[inline]
242 pub fn is_smoothing(&self) -> bool {
243 self.steps_left() > 0
244 }
245
246 #[inline]
250 pub fn iter(&self) -> SmootherIter<'_, T> {
251 SmootherIter { smoother: self }
252 }
253
254 pub fn reset(&self, value: T) {
256 T::atomic_store(&self.target, value);
257 self.current.store(value.to_f32(), Ordering::Relaxed);
258 self.steps_left.store(0, Ordering::Relaxed);
259 }
260
261 pub fn set_target(&self, sample_rate: f32, target: T) {
263 T::atomic_store(&self.target, target);
264
265 let steps_left = self.style.num_steps(sample_rate) as i32;
266 self.steps_left.store(steps_left, Ordering::Relaxed);
267
268 let current = self.current.load(Ordering::Relaxed);
269 let target_f32 = target.to_f32();
270 self.step_size.store(
271 if steps_left > 0 {
272 self.style.step_size(current, target_f32, steps_left as u32)
273 } else {
274 0.0
275 },
276 Ordering::Relaxed,
277 );
278 }
279
280 #[allow(clippy::should_implement_trait)]
284 #[inline]
285 pub fn next(&self) -> T {
286 let target = T::atomic_load(&self.target);
287
288 if self.steps_left.load(Ordering::Relaxed) > 0 {
291 let current = self.current.load(Ordering::Relaxed);
292 let target_f32 = target.to_f32();
293 let step_size = self.step_size.load(Ordering::Relaxed);
294
295 let old_steps_left = self.steps_left.fetch_sub(1, Ordering::Relaxed);
301 let new = if old_steps_left == 1 {
302 self.steps_left.store(0, Ordering::Relaxed);
303 target_f32
304 } else {
305 self.style.next(current, target_f32, step_size)
306 };
307 self.current.store(new, Ordering::Relaxed);
308
309 T::from_f32(new)
310 } else {
311 target
312 }
313 }
314
315 #[inline]
320 pub fn next_step(&self, steps: u32) -> T {
321 nice_debug_assert_ne!(steps, 0);
322
323 let target = T::atomic_load(&self.target);
324
325 if self.steps_left.load(Ordering::Relaxed) > 0 {
326 let current = self.current.load(Ordering::Relaxed);
327 let target_f32 = target.to_f32();
328 let step_size = self.step_size.load(Ordering::Relaxed);
329
330 let old_steps_left = self.steps_left.fetch_sub(steps as i32, Ordering::Relaxed);
336 let new = if old_steps_left <= steps as i32 {
337 self.steps_left.store(0, Ordering::Relaxed);
338 target_f32
339 } else {
340 self.style.next_step(current, target_f32, step_size, steps)
341 };
342 self.current.store(new, Ordering::Relaxed);
343
344 T::from_f32(new)
345 } else {
346 target
347 }
348 }
349
350 pub fn previous_value(&self) -> T {
355 T::from_f32(self.current.load(Ordering::Relaxed))
356 }
357
358 pub fn next_block(&self, block_values: &mut [T], block_len: usize) {
368 self.next_block_exact(&mut block_values[..block_len])
369 }
370
371 pub fn next_block_exact(&self, block_values: &mut [T]) {
373 let target = T::atomic_load(&self.target);
374
375 let steps_left = self.steps_left.load(Ordering::Relaxed) as usize;
381 let num_smoothed_values = block_values.len().min(steps_left);
382 if num_smoothed_values > 0 {
383 let mut current = self.current.load(Ordering::Relaxed);
384 let target_f32 = target.to_f32();
385 let step_size = self.step_size.load(Ordering::Relaxed);
386
387 if num_smoothed_values == steps_left {
388 block_values[..num_smoothed_values - 1].fill_with(|| {
391 current = self.style.next(current, target_f32, step_size);
392 T::from_f32(current)
393 });
394
395 current = target_f32.to_f32();
398 block_values[num_smoothed_values - 1] = target;
399 } else {
400 block_values[..num_smoothed_values].fill_with(|| {
401 current = self.style.next(current, target_f32, step_size);
402 T::from_f32(current)
403 });
404 }
405
406 block_values[num_smoothed_values..].fill(target);
407
408 self.current.store(current, Ordering::Relaxed);
409 self.steps_left
410 .fetch_sub(num_smoothed_values as i32, Ordering::Relaxed);
411 } else {
412 block_values.fill(target);
413 }
414 }
415
416 pub fn next_block_mapped(
422 &self,
423 block_values: &mut [T],
424 block_len: usize,
425 f: impl FnMut(usize, f32) -> T,
426 ) {
427 self.next_block_exact_mapped(&mut block_values[..block_len], f)
428 }
429
430 pub fn next_block_exact_mapped(
433 &self,
434 block_values: &mut [T],
435 mut f: impl FnMut(usize, f32) -> T,
436 ) {
437 let target_f32 = T::atomic_load(&self.target).to_f32();
440
441 let steps_left = self.steps_left.load(Ordering::Relaxed) as usize;
442 let num_smoothed_values = block_values.len().min(steps_left);
443 if num_smoothed_values > 0 {
444 let mut current = self.current.load(Ordering::Relaxed);
445 let step_size = self.step_size.load(Ordering::Relaxed);
446
447 if num_smoothed_values == steps_left {
449 for (idx, value) in block_values
450 .iter_mut()
451 .enumerate()
452 .take(num_smoothed_values - 1)
453 {
454 current = self.style.next(current, target_f32, step_size);
455 *value = f(idx, current);
456 }
457
458 current = target_f32.to_f32();
459 block_values[num_smoothed_values - 1] = f(num_smoothed_values - 1, target_f32);
460 } else {
461 for (idx, value) in block_values
462 .iter_mut()
463 .enumerate()
464 .take(num_smoothed_values)
465 {
466 current = self.style.next(current, target_f32, step_size);
467 *value = f(idx, current);
468 }
469 }
470
471 for (idx, value) in block_values
472 .iter_mut()
473 .enumerate()
474 .skip(num_smoothed_values)
475 {
476 *value = f(idx, target_f32);
477 }
478
479 self.current.store(current, Ordering::Relaxed);
480 self.steps_left
481 .fetch_sub(num_smoothed_values as i32, Ordering::Relaxed);
482 } else {
483 for (idx, value) in block_values.iter_mut().enumerate() {
484 *value = f(idx, target_f32);
485 }
486 }
487 }
488}
489
490impl Smoothable for f32 {
491 type Atomic = AtomicF32;
492
493 #[inline]
494 fn to_f32(self) -> f32 {
495 self
496 }
497
498 #[inline]
499 fn from_f32(value: f32) -> Self {
500 value
501 }
502
503 #[inline]
504 fn atomic_new(value: Self) -> Self::Atomic {
505 AtomicF32::new(value)
506 }
507
508 #[inline]
509 fn atomic_load(this: &Self::Atomic) -> Self {
510 this.load(Ordering::Relaxed)
511 }
512
513 #[inline]
514 fn atomic_store(this: &Self::Atomic, value: Self) {
515 this.store(value, Ordering::Relaxed)
516 }
517}
518
519impl Smoothable for i32 {
520 type Atomic = AtomicI32;
521
522 #[inline]
523 fn to_f32(self) -> f32 {
524 self as f32
525 }
526
527 #[inline]
528 fn from_f32(value: f32) -> Self {
529 value.round() as i32
530 }
531
532 #[inline]
533 fn atomic_new(value: Self) -> Self::Atomic {
534 AtomicI32::new(value)
535 }
536
537 #[inline]
538 fn atomic_load(this: &Self::Atomic) -> Self {
539 this.load(Ordering::Relaxed)
540 }
541
542 #[inline]
543 fn atomic_store(this: &Self::Atomic, value: Self) {
544 this.store(value, Ordering::Relaxed)
545 }
546}
547
548#[cfg(test)]
549mod tests {
550 use super::*;
551
552 #[test]
554 fn linear_f32_next_equivalence() {
555 let style = SmoothingStyle::Linear(100.0);
556
557 let mut current = 0.4;
558 let target = 0.8;
559 let steps = 15;
560 let step_size = style.step_size(current, target, steps);
561
562 let expected_result = style.next_step(current, target, step_size, steps);
563 for _ in 0..steps {
564 current = style.next(current, target, step_size);
565 }
566
567 approx::assert_relative_eq!(current, expected_result, epsilon = 1e-5);
568 }
569
570 #[test]
571 fn logarithmic_f32_next_equivalence() {
572 let style = SmoothingStyle::Logarithmic(100.0);
573
574 let mut current = 0.4;
575 let target = 0.8;
576 let steps = 15;
577 let step_size = style.step_size(current, target, steps);
578
579 let expected_result = style.next_step(current, target, step_size, steps);
580 for _ in 0..steps {
581 current = style.next(current, target, step_size);
582 }
583
584 approx::assert_relative_eq!(current, expected_result, epsilon = 1e-5);
585 }
586
587 #[test]
588 fn exponential_f32_next_equivalence() {
589 let style = SmoothingStyle::Exponential(100.0);
590
591 let mut current = 0.4;
592 let target = 0.8;
593 let steps = 15;
594 let step_size = style.step_size(current, target, steps);
595
596 let expected_result = style.next_step(current, target, step_size, steps);
597 for _ in 0..steps {
598 current = style.next(current, target, step_size);
599 }
600
601 approx::assert_relative_eq!(current, expected_result, epsilon = 1e-5);
602 }
603
604 #[test]
605 fn linear_f32_smoothing() {
606 let smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Linear(100.0));
607 smoother.reset(10.0);
608 assert_eq!(smoother.next(), 10.0);
609
610 smoother.set_target(100.0, 20.0);
613 for _ in 0..(10 - 2) {
614 smoother.next();
615 }
616 assert_ne!(smoother.next(), 20.0);
617 assert_eq!(smoother.next(), 20.0);
618 }
619
620 #[test]
621 fn linear_i32_smoothing() {
622 let smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Linear(100.0));
623 smoother.reset(10);
624 assert_eq!(smoother.next(), 10);
625
626 smoother.set_target(100.0, 20);
628 for _ in 0..(10 - 2) {
629 smoother.next();
630 }
631 assert_ne!(smoother.next(), 20);
632 assert_eq!(smoother.next(), 20);
633 }
634
635 #[test]
636 fn logarithmic_f32_smoothing() {
637 let smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
638 smoother.reset(10.0);
639 assert_eq!(smoother.next(), 10.0);
640
641 smoother.set_target(100.0, 20.0);
644 for _ in 0..(10 - 2) {
645 smoother.next();
646 }
647 assert_ne!(smoother.next(), 20.0);
648 assert_eq!(smoother.next(), 20.0);
649 }
650
651 #[test]
652 fn logarithmic_i32_smoothing() {
653 let smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
654 smoother.reset(10);
655 assert_eq!(smoother.next(), 10);
656
657 smoother.set_target(100.0, 20);
659 for _ in 0..(10 - 2) {
660 smoother.next();
661 }
662 assert_ne!(smoother.next(), 20);
663 assert_eq!(smoother.next(), 20);
664 }
665
666 #[test]
668 fn skipping_linear_f32_smoothing() {
669 let smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Linear(100.0));
670 smoother.reset(10.0);
671 assert_eq!(smoother.next(), 10.0);
672
673 smoother.set_target(100.0, 20.0);
674 smoother.next_step(8);
675 assert_ne!(smoother.next(), 20.0);
676 assert_eq!(smoother.next(), 20.0);
677 }
678
679 #[test]
681 fn skipping_linear_i32_smoothing() {
682 let smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Linear(100.0));
683 smoother.reset(10);
684 assert_eq!(smoother.next(), 10);
685
686 smoother.set_target(100.0, 20);
687 smoother.next_step(8);
688 assert_ne!(smoother.next(), 20);
689 assert_eq!(smoother.next(), 20);
690 }
691
692 #[test]
694 fn skipping_logarithmic_f32_smoothing() {
695 let smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
696 smoother.reset(10.0);
697 assert_eq!(smoother.next(), 10.0);
698
699 smoother.set_target(100.0, 20.0);
700 smoother.next_step(8);
701 assert_ne!(smoother.next(), 20.0);
702 assert_eq!(smoother.next(), 20.0);
703 }
704
705 #[test]
707 fn skipping_logarithmic_i32_smoothing() {
708 let smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
709 smoother.reset(10);
710 assert_eq!(smoother.next(), 10);
711
712 smoother.set_target(100.0, 20);
713 smoother.next_step(8);
714 assert_ne!(smoother.next(), 20);
715 assert_eq!(smoother.next(), 20);
716 }
717
718 }