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 #[inline]
43 pub const fn half(&self) -> Self {
44 Self(self.0 * 2)
45 }
46
47 #[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}