Skip to main content

clack_common/utils/
fixed_point.rs

1use std::ops::Add;
2
3/// A time value in beats.
4pub type BeatTime = FixedPoint;
5/// A time value in seconds.
6pub type SecondsTime = FixedPoint;
7
8/// A fixed-point decimal.
9#[repr(C)]
10#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
11pub struct FixedPoint(i64);
12
13impl FixedPoint {
14    /// The factor by witch to multiply a value in order to make it have the same fixed-point
15    /// decimal representation as this type.
16    pub const FACTOR: i64 = clap_sys::fixedpoint::CLAP_BEATTIME_FACTOR;
17
18    #[allow(clippy::cast_precision_loss)] // CLAP_BEATTIME_FACTOR only needs 31 bits of precision, so this does not actually lose anything
19    const FACTOR_F64: f64 = Self::FACTOR as f64;
20
21    /// Creates a [`FixedPoint`] decimal from its internal, raw-byte representation.
22    #[inline]
23    pub const fn from_bits(bits: i64) -> Self {
24        Self(bits)
25    }
26
27    /// Returns the internal, raw-byte representation of this [`FixedPoint`] decimal.
28    #[inline]
29    pub const fn to_bits(&self) -> i64 {
30        self.0
31    }
32
33    /// Creates a [`FixedPoint`] decimal from an integer value.
34    #[inline]
35    pub const fn from_int(val: i64) -> Self {
36        Self(Self::FACTOR * val)
37    }
38
39    /// Returns the integer part of this [`FixedPoint`] decimal, discarding the decimal part.
40    #[inline]
41    pub const fn to_int(&self) -> i64 {
42        self.0 / Self::FACTOR
43    }
44
45    /// Converts this fixed-point decimal to a floating-point value.
46    ///
47    /// Note that this conversion loses some precision: the [`FixedPoint`] decimal has the full
48    /// 64 bits of precision, whereas `f64`'s mantissa is only 52 bits wide.
49    #[inline]
50    #[allow(clippy::cast_precision_loss)]
51    pub const fn to_float(&self) -> f64 {
52        self.0 as f64 / Self::FACTOR_F64
53    }
54
55    /// Converts the given floating-point value to a [`FixedPoint`] decimal.
56    #[inline]
57    pub fn from_float(val: f64) -> Self {
58        #[allow(clippy::cast_possible_truncation)] // This is willingly lossy
59        Self((Self::FACTOR_F64 * val).round() as i64)
60    }
61}
62
63impl From<f64> for FixedPoint {
64    #[inline]
65    fn from(val: f64) -> Self {
66        Self::from_float(val)
67    }
68}
69
70impl From<FixedPoint> for f64 {
71    #[inline]
72    fn from(val: FixedPoint) -> Self {
73        val.to_float()
74    }
75}
76
77impl Add for FixedPoint {
78    type Output = Self;
79
80    #[inline]
81    fn add(self, rhs: Self) -> Self::Output {
82        Self::from_bits(self.0 + rhs.0)
83    }
84}