clack-common 0.1.0

Various utilities for working with the CLAP audio plugin API, for both plugins and hosts.
Documentation
use std::ops::Add;

/// A time value in beats.
pub type BeatTime = FixedPoint;
/// A time value in seconds.
pub type SecondsTime = FixedPoint;

/// A fixed-point decimal.
#[repr(C)]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct FixedPoint(i64);

impl FixedPoint {
    /// The factor by witch to multiply a value in order to make it have the same fixed-point
    /// decimal representation as this type.
    pub const FACTOR: i64 = clap_sys::fixedpoint::CLAP_BEATTIME_FACTOR;

    #[allow(clippy::cast_precision_loss)] // CLAP_BEATTIME_FACTOR only needs 31 bits of precision, so this does not actually lose anything
    const FACTOR_F64: f64 = Self::FACTOR as f64;

    /// Creates a [`FixedPoint`] decimal from its internal, raw-byte representation.
    #[inline]
    pub const fn from_bits(bits: i64) -> Self {
        Self(bits)
    }

    /// Returns the internal, raw-byte representation of this [`FixedPoint`] decimal.
    #[inline]
    pub const fn to_bits(&self) -> i64 {
        self.0
    }

    /// Creates a [`FixedPoint`] decimal from an integer value.
    #[inline]
    pub const fn from_int(val: i64) -> Self {
        Self(Self::FACTOR * val)
    }

    /// Returns the integer part of this [`FixedPoint`] decimal, discarding the decimal part.
    #[inline]
    pub const fn to_int(&self) -> i64 {
        self.0 / Self::FACTOR
    }

    /// Converts this fixed-point decimal to a floating-point value.
    ///
    /// Note that this conversion loses some precision: the [`FixedPoint`] decimal has the full
    /// 64 bits of precision, whereas `f64`'s mantissa is only 52 bits wide.
    #[inline]
    #[allow(clippy::cast_precision_loss)]
    pub const fn to_float(&self) -> f64 {
        self.0 as f64 / Self::FACTOR_F64
    }

    /// Converts the given floating-point value to a [`FixedPoint`] decimal.
    #[inline]
    pub fn from_float(val: f64) -> Self {
        #[allow(clippy::cast_possible_truncation)] // This is willingly lossy
        Self((Self::FACTOR_F64 * val).round() as i64)
    }
}

impl From<f64> for FixedPoint {
    #[inline]
    fn from(val: f64) -> Self {
        Self::from_float(val)
    }
}

impl From<FixedPoint> for f64 {
    #[inline]
    fn from(val: FixedPoint) -> Self {
        val.to_float()
    }
}

impl Add for FixedPoint {
    type Output = Self;

    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        Self::from_bits(self.0 + rhs.0)
    }
}