note_pen/
duration.rs

1#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3pub struct PrimitiveDuration(u64);
4impl TryFrom<u64> for PrimitiveDuration {
5    type Error = ();
6
7    fn try_from(value: u64) -> Result<Self, Self::Error> {
8        match value {
9            1 => Ok(Self::WHOLE),
10            2 => Ok(Self::HALF),
11            4 => Ok(Self::QUARTER),
12            8 => Ok(Self::EIGHTH),
13            16 => Ok(Self::SIXTEENTH),
14            32 => Ok(Self::THIRTY_SECOND),
15            64 => Ok(Self::SIXTY_FOURTH),
16            _ => Err(()),
17        }
18    }
19}
20
21impl PrimitiveDuration {
22    pub const WHOLE: Self = Self(1);
23    pub const HALF: Self = Self(2);
24    pub const QUARTER: Self = Self(4);
25    pub const EIGHTH: Self = Self(8);
26    pub const SIXTEENTH: Self = Self(16);
27    pub const THIRTY_SECOND: Self = Self(32);
28    pub const SIXTY_FOURTH: Self = Self(64);
29
30    #[inline]
31    pub const fn value(&self) -> u64 {
32        self.0
33    }
34
35    /// Halves the duration of the primitive duration.
36    /// This is equivalent to halving the note value.
37    /// # Examples
38    /// ```rust
39    /// use note_pen::prelude::*;
40    /// assert_eq!(PrimitiveDuration::WHOLE.half(), PrimitiveDuration::HALF);
41    /// ```
42    #[inline]
43    pub const fn half(&self) -> Self {
44        Self(self.0 * 2)
45    }
46
47    /// Doubles the duration of the primitive duration.
48    /// This is equivalent to doubling the note value.
49    /// # Examples
50    /// ```rust
51    /// use note_pen::prelude::*;
52    /// assert_eq!(PrimitiveDuration::HALF.double(), PrimitiveDuration::WHOLE);
53    /// ```
54    #[inline]
55    pub const fn double(&self) -> Self {
56        Self(self.0 / 2)
57    }
58}
59
60#[derive(Copy, Clone, Debug, PartialEq, Eq)]
61#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
62pub struct Duration {
63    pub primitive: PrimitiveDuration,
64    pub dots: u8,
65}
66
67impl From<PrimitiveDuration> for Duration {
68    fn from(primitive: PrimitiveDuration) -> Self {
69        Self { primitive, dots: 0 }
70    }
71}
72
73impl Duration {
74    pub const WHOLE: Self = Self {
75        primitive: PrimitiveDuration::WHOLE,
76        dots: 0,
77    };
78    pub const HALF: Self = Self {
79        primitive: PrimitiveDuration::HALF,
80        dots: 0,
81    };
82    pub const QUARTER: Self = Self {
83        primitive: PrimitiveDuration::QUARTER,
84        dots: 0,
85    };
86    pub const EIGHTH: Self = Self {
87        primitive: PrimitiveDuration::EIGHTH,
88        dots: 0,
89    };
90    pub const SIXTEENTH: Self = Self {
91        primitive: PrimitiveDuration::SIXTEENTH,
92        dots: 0,
93    };
94    pub const THIRTY_SECOND: Self = Self {
95        primitive: PrimitiveDuration::THIRTY_SECOND,
96        dots: 0,
97    };
98    pub const SIXTY_FOURTH: Self = Self {
99        primitive: PrimitiveDuration::SIXTY_FOURTH,
100        dots: 0,
101    };
102}
103
104#[cfg(feature = "midi")]
105mod midi {
106    use crate::duration::Duration;
107    use crate::prelude::PrimitiveDuration;
108
109    impl PrimitiveDuration {
110        pub fn to_midi(&self) -> u32 {
111            match self {
112                &Self::WHOLE => 8192,
113                &Self::HALF => 2048,
114                &Self::QUARTER => 1024,
115                &Self::EIGHTH => 512,
116                &Self::SIXTEENTH => 256,
117                &Self::THIRTY_SECOND => 128,
118                &Self::SIXTY_FOURTH => 64,
119                _ => unimplemented!("Unsupported time signature: {:?}", self),
120            }
121        }
122    }
123
124    impl Duration {
125        pub fn to_midi(&self) -> u32 {
126            let mut primitive = self.primitive.to_midi();
127            let mut value = primitive;
128            for _ in 0..self.dots {
129                value += primitive / 2;
130                primitive /= 2;
131            }
132            value
133        }
134    }
135}