From 17cd70a7e1f31fd493cd382d9b2d8c23cf10401d Mon Sep 17 00:00:00 2001 From: Wouter Ensink <46427708+w-ensink@users.noreply.github.com> Date: Tue, 20 Dec 2022 17:51:22 +0100 Subject: [PATCH] added some more utilities and documentation --- src/units/duration.rs | 15 ++++++++++++++- src/units/percentage.rs | 21 ++++++++++++++++++++- src/units/sample_rate.rs | 36 ++++++++++++++++++++++++++++++++---- src/units/samples.rs | 2 +- src/units/seconds.rs | 2 +- src/units/time_point.rs | 25 +++++++++++++++++++++++++ src/units/time_section.rs | 19 +++++++++++++++++++ 7 files changed, 112 insertions(+), 8 deletions(-) diff --git a/src/units/duration.rs b/src/units/duration.rs index 26eb532..415bb95 100644 --- a/src/units/duration.rs +++ b/src/units/duration.rs @@ -9,7 +9,14 @@ use crate::units::{SampleRate, Samples, Seconds}; pub struct Duration(Seconds); impl Duration { - /// Converts the duration to samples using the given sample rate. + /// Converts the duration to samples using the given sample rate: + /// ``` + /// use rabu::units::{Duration, SampleRate, Samples}; + /// let duration = Duration::from_secs_f64(5.0); + /// let sample_rate = SampleRate::from(44100); + /// let num_samples = duration.to_samples(sample_rate); + /// assert_eq!(num_samples, Samples::from(220500)); + /// ``` pub fn to_samples(&self, sr: SampleRate) -> Samples { self.0.to_samples(sr) } @@ -29,6 +36,12 @@ impl Duration { } } +impl PartialEq for Duration { + fn eq(&self, other: &Seconds) -> bool { + self.as_seconds() == *other + } +} + impl From for Duration { fn from(value: Seconds) -> Self { Self::from_secs_f64(value.as_f64()) diff --git a/src/units/percentage.rs b/src/units/percentage.rs index 45d4e8b..5c54ccd 100644 --- a/src/units/percentage.rs +++ b/src/units/percentage.rs @@ -4,4 +4,23 @@ use serde::{Deserialize, Serialize}; /// Represents a percentage, e.g. the export progress. #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Percentage(pub f64); +pub struct Percentage(f64); + +macro_rules! impl_float_conversions { + ($float_type: ty) => { + impl From<$float_type> for Percentage { + fn from(value: $float_type) -> Self { + Self(value as _) + } + } + + impl From for $float_type { + fn from(value: Percentage) -> Self { + value.0 as _ + } + } + }; +} + +impl_float_conversions!(f32); +impl_float_conversions!(f64); diff --git a/src/units/sample_rate.rs b/src/units/sample_rate.rs index f0dd005..860599e 100644 --- a/src/units/sample_rate.rs +++ b/src/units/sample_rate.rs @@ -1,3 +1,4 @@ +use crate::units::{Duration, Seconds}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -8,23 +9,50 @@ pub struct SampleRate(u32); impl SampleRate { /// Gives back the raw value as a `u32`. - pub fn value(&self) -> u32 { + pub fn as_u32(&self) -> u32 { self.0 } /// Gives back the raw value as a `usize`. pub fn as_usize(&self) -> usize { - self.value() as usize + self.as_u32() as usize } /// Gives back the raw value as a `f64`. pub fn as_f64(&self) -> f64 { - self.value() as f64 + self.as_u32() as f64 } /// Gives back the raw value as a `u64`. pub fn as_u64(&self) -> u64 { - self.value() as u64 + self.as_u32() as u64 + } + + /// Gets the duration between two consecutive samples: + /// Gets the time in seconds between tho consecutive samples: + /// ``` + /// use rabu::units::{Duration, SampleRate}; + /// + /// let sample_rate = SampleRate::from(20); + /// let period = sample_rate.time_between_samples(); + /// + /// assert_eq!(period, Duration::from_secs_f64(0.05)); + /// ``` + pub fn time_between_samples(&self) -> Duration { + Duration::from_secs_f64(1.0 / self.as_f64()) + } + + /// Gets the time in seconds between tho consecutive samples: + /// ``` + /// use rabu::units::{SampleRate, Seconds}; + /// + /// let sample_rate = SampleRate::from(10); + /// let period_secs = sample_rate.secs_between_samples(); + /// + /// assert_eq!(period_secs, Seconds::from(0.1)); + /// ``` + pub fn secs_between_samples(&self) -> Seconds { + Seconds::from(1.0 / self.as_f64()) } } diff --git a/src/units/samples.rs b/src/units/samples.rs index d004dca..01ea8ec 100644 --- a/src/units/samples.rs +++ b/src/units/samples.rs @@ -17,7 +17,7 @@ impl Samples { /// Converts to seconds using the given sample rate. pub fn to_seconds(&self, sr: SampleRate) -> Seconds { - Seconds::from(self.as_u64() as f64 / sr.value() as f64) + Seconds::from(self.as_u64() as f64 / sr.as_u32() as f64) } /// Gives back the raw value as a `usize`. diff --git a/src/units/seconds.rs b/src/units/seconds.rs index 9426efa..830ae73 100644 --- a/src/units/seconds.rs +++ b/src/units/seconds.rs @@ -12,7 +12,7 @@ pub struct Seconds(f64); impl Seconds { /// Convert to samples using the given sample rate. pub fn to_samples(&self, sr: SampleRate) -> Samples { - Samples::from((self.as_f64() * sr.value() as f64) as u64) + Samples::from((self.as_f64() * sr.as_u32() as f64) as u64) } /// Gives back the raw value in f64. diff --git a/src/units/time_point.rs b/src/units/time_point.rs index 528270b..3ac2120 100644 --- a/src/units/time_point.rs +++ b/src/units/time_point.rs @@ -6,6 +6,25 @@ use serde::{Deserialize, Serialize}; use crate::units::{Duration, Seconds}; /// Represents a time point in the audio domain, e.g. the start position of a file. +/// Has the correct conversions when adding/subtracting other types to/from it: +/// ``` +/// use rabu::units::{Duration, Seconds, TimePoint}; +/// +/// let t1 = TimePoint::from_secs_f64(10.0); +/// let t2 = TimePoint::from(Seconds::from(12.0)); +/// let time_between = t2 - t1; +/// +/// assert_eq!(time_between, Duration::from_secs_f64(2.0)); +/// +/// let next_time_point = t2 + Duration::from_secs_f64(2.0); +/// assert_eq!(next_time_point, TimePoint::from_secs_f64(14.0)); +/// +/// let earlier_time_point = t2 - Duration::from_secs_f64(2.0); +/// assert_eq!(earlier_time_point, t1); +/// +/// let next_time_point = t2 + Seconds::from(0.5); +/// assert_eq!(next_time_point, TimePoint::from_secs_f64(12.5)); +/// ``` #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TimePoint(Seconds); @@ -27,6 +46,12 @@ impl TimePoint { } } +impl PartialEq for TimePoint { + fn eq(&self, other: &Seconds) -> bool { + self.as_seconds() == *other + } +} + impl From for TimePoint { fn from(value: Seconds) -> Self { value.as_time_point() diff --git a/src/units/time_section.rs b/src/units/time_section.rs index a278984..41fb987 100644 --- a/src/units/time_section.rs +++ b/src/units/time_section.rs @@ -14,6 +14,25 @@ pub struct TimeSection { impl TimeSection { /// Returns the overlap (if any) between this time section and another. + /// This should also be used in order to find out whether there is overlap or not. + /// ``` + /// use rabu::units::{Seconds, TimePoint, TimeSection}; + /// + /// let section_1 = TimeSection { + /// start: Seconds::from(1.0).into(), + /// duration: Seconds::from(2.0).into(), + /// }; + /// + /// let section_2 = TimeSection { + /// start: Seconds::from(1.5).into(), + /// duration: Seconds::from(1.0).into(), + /// }; + /// + /// let overlap = section_1.get_overlap(section_2).unwrap(); + /// + /// assert_eq!(overlap.start, Seconds::from(1.5)); + /// assert_eq!(overlap.duration, Seconds::from(1.0)); + /// ``` pub fn get_overlap(&self, other: Self) -> Option { if self.end() <= other.start || other.end() <= self.start { return None;