diff --git a/dsp/src/unwrap.rs b/dsp/src/unwrap.rs index 0c20852..c89599f 100644 --- a/dsp/src/unwrap.rs +++ b/dsp/src/unwrap.rs @@ -1,24 +1,25 @@ use serde::{Deserialize, Serialize}; -/// Get phase wrap from x to y. +/// Subtract `y - x` with signed overflow. /// -/// Phases are modulo integer overflow. The wraps have the same bias as -/// the base data type itself. -/// -/// Args: -/// * `x`: Old phase sample -/// * `y`: New phase sample +/// This is very similar to `i32::overflowing_sub(y, x)` except that the +/// overflow indicator is not a boolean but the signum of the overflow. +/// Additionally it's typically faster. /// /// Returns: -/// A tuple containg the (wrapped) phase difference and the signum of the wrap. +/// A tuple containg the (wrapped) difference `y - x` and the signum of the +/// overflow. #[inline(always)] -pub fn get_wrap(x: i32, y: i32) -> (i32, i8) { +pub fn overflowing_sub(y: i32, x: i32) -> (i32, i8) { let delta = y.wrapping_sub(x); let wrap = (delta >= 0) as i8 - (y >= x) as i8; (delta, wrap) } -/// Phase unwrapper. +/// Overflow unwrapper. +/// +/// This is unwrapping as in the phase unwrapping context, not unwrapping as +/// in the `Result`/`Option` context. #[derive(Copy, Clone, Default, Deserialize, Serialize)] pub struct Unwrapper { // last input @@ -28,19 +29,18 @@ pub struct Unwrapper { } impl Unwrapper { - /// Unwrap a new sample from a phase sequence and update the unwrapper - /// state. + /// Unwrap a new sample from a sequence and update the unwrapper state. /// /// Args: - /// * `x`: New phase sample + /// * `x`: New sample /// /// Returns: - /// A tuple containing the (wrapped) phase difference and the signed - /// number of phase wraps accumulated to the new sample. + /// A tuple containing the (wrapped) difference `x - x_old` and the signed + /// number of wraps accumulated by `x`. pub fn update(&mut self, x: i32) -> (i32, i32) { - let (dx, v) = get_wrap(self.x, x); + let (dx, v) = overflowing_sub(x, self.x); self.x = x; - self.v = self.v.wrapping_add(v as i32); + self.v = self.v.saturating_add(v as i32); (dx, self.v) } } @@ -73,8 +73,11 @@ mod tests { ] .iter() { - let (_dx, w) = get_wrap(*x0, *x1); - assert_eq!(*v, w, " = get_wrap({:#x}, {:#x})", *x0, *x1); + let (dx, w) = overflowing_sub(*x1, *x0); + assert_eq!(*v, w, " = overflowing_sub({:#x}, {:#x})", *x0, *x1); + let (dx0, w0) = x1.overflowing_sub(*x0); + assert_eq!(w0, w != 0); + assert_eq!(dx, dx0); } } }