1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/// Helper to linearly ramp a parameter towards a target value
///
/// Useful for implementing filters like [`Gain`](crate::Gain) which have dynamic parameters, where
/// applying changes to parameters directly would cause unpleasant artifacts such as popping.
///
/// # Example
/// ```
/// let mut value = oddio::Smoothed::new(0.0);
/// assert_eq!(value.get(), 0.0);
/// // Changes only take effect after time passes
/// value.set(1.0);
/// assert_eq!(value.get(), 0.0);
/// value.advance(0.5);
/// assert_eq!(value.get(), 0.5);
/// // A new value can be supplied mid-interpolation without causing a discontinuity
/// value.set(1.5);
/// value.advance(0.5);
/// assert_eq!(value.get(), 1.0);
/// value.advance(0.5);
/// assert_eq!(value.get(), 1.5);
/// // Interpolation halts once the target value is reached
/// value.advance(0.5);
/// assert_eq!(value.get(), 1.5);
/// ```
#[derive(Copy, Clone, Default)]
pub struct Smoothed<T> {
    prev: T,
    next: T,
    progress: f32,
}

impl<T> Smoothed<T> {
    /// Create with initial value `x`
    pub fn new(x: T) -> Self
    where
        T: Clone,
    {
        Self {
            prev: x.clone(),
            next: x,
            progress: 1.0,
        }
    }

    /// Advance interpolation by `proportion`. For example, to advance at a fixed sample rate over a
    /// particular smoothing period, pass `sample_interval / smoothing_period`.
    pub fn advance(&mut self, proportion: f32) {
        self.progress = (self.progress + proportion).min(1.0);
    }

    /// Progress from the previous towards the next value
    pub fn progress(&self) -> f32 {
        self.progress
    }

    /// Set the next value to `x`
    pub fn set(&mut self, value: T)
    where
        T: Interpolate,
    {
        self.prev = self.get();
        self.next = value;
        self.progress = 0.0;
    }

    /// Get the current value
    pub fn get(&self) -> T
    where
        T: Interpolate,
    {
        self.prev.interpolate(&self.next, self.progress)
    }

    /// Get the value most recently passed to `set`
    pub fn target(&self) -> &T {
        &self.next
    }
}

/// Types that can be linearly interpolated, for use with [`Smoothed`]
pub trait Interpolate {
    /// Interpolate between `self` and `other` by `t`, which should be in [0, 1]
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl Interpolate for f32 {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        let diff = other - self;
        self + t * diff
    }
}