src/clock.rsView |
---|
6 | 6 … | use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError}; |
7 | 7 … | |
8 | 8 … | use control; |
9 | 9 … | |
10 | | -pub type Time = Instant; |
11 | | - |
12 | 10 … | pub type Nanos = u64; |
13 | 11 … | pub type Ticks = u64; |
14 | 12 … | pub type Beats = u64; |
15 | 13 … | pub type Bars = u64; |
21 | 19 … | static DEFAULT_BEATS_PER_BAR: u64 = 4; |
22 | 20 … | static DEFAULT_BARS_PER_LOOP: u64 = 4; |
23 | 21 … | static DEFAULT_BEATS_PER_MINUTE: f64 = 60_f64; |
24 | 22 … | |
25 | | -#[derive(Clone, Copy, Debug, Hash)] |
| 23 … | +#[derive(Clone, Copy, Debug)] |
26 | 24 … | pub struct ClockSignature { |
27 | 25 … | pub nanos_per_beat: u64, |
28 | 26 … | pub ticks_per_beat: u64, |
29 | 27 … | pub beats_per_bar: u64, |
30 | 28 … | pub bars_per_loop: u64, |
31 | 29 … | } |
32 | 30 … | |
33 | 31 … | impl ClockSignature { |
34 | | - pub fn new (beats_per_minute: f64) -> Self { |
35 | | - let minutes_per_beat = 1_f64 / beats_per_minute; |
36 | | - let seconds_per_beat = minutes_per_beat * SECONDS_PER_MINUTE as f64; |
37 | | - let nanos_per_beat = seconds_per_beat * NANOS_PER_SECOND as f64; |
38 | | - |
| 32 … | + pub fn new (nanos_per_beat: u64) -> Self { |
39 | 33 … | Self { |
40 | | - nanos_per_beat: nanos_per_beat as u64, |
| 34 … | + nanos_per_beat: nanos_per_beat, |
41 | 35 … | ticks_per_beat: DEFAULT_TICKS_PER_BEAT, |
42 | 36 … | beats_per_bar: DEFAULT_BEATS_PER_BAR, |
43 | 37 … | bars_per_loop: DEFAULT_BARS_PER_LOOP, |
44 | 38 … | } |
45 | 39 … | } |
46 | 40 … | |
47 | 41 … | pub fn default () -> Self { |
48 | | - Self::new(DEFAULT_BEATS_PER_MINUTE) |
| 42 … | + Self::from_beats_per_minute(DEFAULT_BEATS_PER_MINUTE) |
49 | 43 … | } |
50 | 44 … | |
| 45 … | + pub fn from_beats_per_minute (beats_per_minute: f64) -> Self { |
| 46 … | + let minutes_per_beat = 1_f64 / beats_per_minute; |
| 47 … | + let seconds_per_beat = minutes_per_beat * SECONDS_PER_MINUTE as f64; |
| 48 … | + let nanos_per_beat = seconds_per_beat * NANOS_PER_SECOND as f64; |
| 49 … | + Self::new(nanos_per_beat as u64) |
| 50 … | + } |
| 51 … | + |
51 | 52 … | pub fn to_beats_per_minute (&self) -> f64 { |
52 | 53 … | let nanos_per_beat = self.nanos_per_beat; |
53 | 54 … | let beats_per_nano = 1_f64 / self.nanos_per_beat as f64; |
54 | 55 … | let beats_per_second = beats_per_nano * NANOS_PER_SECOND as f64; |
67 | 68 … | pub fn nanos_per_bar (&self) -> u64 { |
68 | 69 … | self.nanos_per_beat() * self.beats_per_bar |
69 | 70 … | } |
70 | 71 … | |
| 72 … | + pub fn nanos_per_loop (&self) -> u64 { |
| 73 … | + self.nanos_per_bar() * self.bars_per_loop |
| 74 … | + } |
| 75 … | + |
71 | 76 … | pub fn nanos_to_ticks (&self, nanos: Nanos) -> u64 { |
72 | 77 … | (nanos / self.nanos_per_tick()) % self.ticks_per_beat |
73 | 78 … | } |
74 | 79 … | |
80 | 85 … | nanos / self.nanos_per_bar() % self.bars_per_loop |
81 | 86 … | } |
82 | 87 … | } |
83 | 88 … | |
84 | | -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] |
| 89 … | +#[derive(Clone, Copy, Debug)] |
85 | 90 … | pub struct ClockTime { |
86 | | - pub nanos: Nanos, |
87 | | - pub ticks: Ticks, |
88 | | - pub beats: Beats, |
89 | | - pub bars: Bars |
| 91 … | + nanos: Nanos, |
| 92 … | + signature: ClockSignature |
90 | 93 … | } |
91 | 94 … | |
92 | 95 … | impl ClockTime { |
93 | 96 … | pub fn new (nanos: Nanos, signature: ClockSignature) -> Self { |
94 | 97 … | Self { |
95 | 98 … | nanos, |
96 | | - ticks: signature.nanos_to_ticks(nanos), |
97 | | - beats: signature.nanos_to_beats(nanos), |
98 | | - bars: signature.nanos_to_bars(nanos), |
99 | | - |
100 | | - |
| 99 … | + signature |
101 | 100 … | } |
102 | 101 … | } |
| 102 … | + |
| 103 … | + pub fn nanos (&self) -> Nanos { |
| 104 … | + self.nanos |
| 105 … | + } |
| 106 … | + |
| 107 … | + pub fn ticks (&self) -> Ticks { |
| 108 … | + self.signature.nanos_to_ticks(self.nanos) |
| 109 … | + } |
| 110 … | + |
| 111 … | + pub fn beats (&self) -> Beats { |
| 112 … | + self.signature.nanos_to_beats(self.nanos) |
| 113 … | + } |
| 114 … | + |
| 115 … | + pub fn bars (&self) -> Bars { |
| 116 … | + self.signature.nanos_to_bars(self.nanos) |
| 117 … | + } |
| 118 … | + |
| 119 … | + pub fn nanos_since_loop (&self) -> Nanos { |
| 120 … | + self.nanos % self.signature.nanos_per_loop() |
| 121 … | + } |
| 122 … | + |
| 123 … | + pub fn nanos_since_tick (&self) -> Nanos { |
| 124 … | + self.nanos % self.signature.nanos_per_tick() |
| 125 … | + } |
| 126 … | + |
| 127 … | + pub fn nanos_since_beat (&self) -> Nanos { |
| 128 … | + self.nanos % self.signature.nanos_per_beat() |
| 129 … | + } |
| 130 … | + |
| 131 … | + pub fn nanos_since_bar (&self) -> Nanos { |
| 132 … | + self.nanos % self.signature.nanos_per_bar() |
| 133 … | + } |
103 | 134 … | } |
104 | 135 … | |
105 | 136 … | #[derive(Debug)] |
106 | 137 … | pub struct Clock { |
107 | | - start: Time, |
108 | | - tick: Time, |
| 138 … | + nanos: Nanos, |
| 139 … | + instant: Instant, |
109 | 140 … | signature: ClockSignature |
110 | 141 … | } |
111 | 142 … | |
112 | 143 … | pub enum ClockMessage { |
| 144 … | + NudgeTempo(f64), |
113 | 145 … | Reset, |
114 | | - NudgeTempo(f64), |
115 | | - Signature(ClockSignature) |
| 146 … | + Signature(ClockSignature), |
| 147 … | + Tap, |
116 | 148 … | } |
117 | 149 … | |
118 | 150 … | impl Clock { |
119 | 151 … | pub fn new () -> Self { |
120 | | - let start = Time::now(); |
| 152 … | + let instant = Instant::now(); |
121 | 153 … | let signature = ClockSignature::default(); |
122 | 154 … | |
123 | 155 … | Self { |
124 | | - start, |
125 | | - tick: start, |
| 156 … | + nanos: 0, |
| 157 … | + instant, |
126 | 158 … | signature |
127 | 159 … | } |
128 | 160 … | } |
129 | 161 … | |
131 | 163 … | let mut clock = Self::new(); |
132 | 164 … | |
133 | 165 … | let (tx, rx) = channel(); |
134 | 166 … | |
135 | | - control_tx.send(control::ControlMessage::Signature(ClockSignature::new(DEFAULT_BEATS_PER_MINUTE))).unwrap(); |
| 167 … | + control_tx.send(control::ControlMessage::Signature(ClockSignature::from_beats_per_minute(DEFAULT_BEATS_PER_MINUTE))).unwrap(); |
136 | 168 … | |
137 | 169 … | spawn(move|| { |
138 | 170 … | loop { |
139 | 171 … | |
150 | 182 … | }, |
151 | 183 … | Ok(ClockMessage::Signature(signature)) => { |
152 | 184 … | clock.signature = signature; |
153 | 185 … | }, |
| 186 … | + Ok(ClockMessage::Tap) => { |
| 187 … | + |
| 188 … | + let time = clock.time(); |
| 189 … | + let nanos_since_beat = time.nanos_since_beat(); |
| 190 … | + let nanos_per_beat = time.signature.nanos_per_beat(); |
| 191 … | + let nanos_per_half_beat = time.signature.nanos_per_beat() / 2; |
| 192 … | + |
| 193 … | + if nanos_since_beat < nanos_per_half_beat { |
| 194 … | + |
| 195 … | + clock.nanos = time.nanos - nanos_since_beat |
| 196 … | + } else { |
| 197 … | + |
| 198 … | + clock.nanos = time.nanos + nanos_per_beat - nanos_since_beat |
| 199 … | + } |
| 200 … | + }, |
154 | 201 … | Ok(ClockMessage::NudgeTempo(nudge)) => { |
155 | 202 … | let old_beats_per_minute = clock.signature.to_beats_per_minute(); |
156 | | - let new_beats_per_minute = old_beats_per_minute - nudge; |
157 | | - let next_signature = ClockSignature::new(new_beats_per_minute); |
| 203 … | + let new_beats_per_minute = old_beats_per_minute + nudge; |
| 204 … | + let next_signature = ClockSignature::from_beats_per_minute(new_beats_per_minute); |
158 | 205 … | control_tx.send(control::ControlMessage::Signature(next_signature)); |
159 | 206 … | }, |
160 | 207 … | Err(TryRecvError::Empty) => {}, |
161 | 208 … | Err(TryRecvError::Disconnected) => { |
168 | 215 … | tx |
169 | 216 … | } |
170 | 217 … | |
171 | 218 … | pub fn reset (&mut self) { |
172 | | - self.start = Time::now(); |
| 219 … | + self.nanos = 0; |
| 220 … | + self.instant = Instant::now(); |
173 | 221 … | } |
174 | 222 … | |
175 | 223 … | pub fn time (&self) -> ClockTime { |
176 | | - ClockTime::new(self.nanos_since_start(), self.signature) |
| 224 … | + ClockTime::new(self.nanos_since_loop(), self.signature) |
177 | 225 … | } |
178 | 226 … | |
179 | | - pub fn diff (&self) -> ClockTime { |
180 | | - let nanos_since_tick = self.nanos_since_tick(); |
181 | | - let nanos_per_tick = self.signature.nanos_per_tick(); |
182 | | - let diff = nanos_per_tick - nanos_since_tick; |
183 | | - ClockTime::new(diff, self.signature) |
| 227 … | + pub fn nanos_since_loop (&self) -> Nanos { |
| 228 … | + self.nanos % self.signature.nanos_per_loop() |
184 | 229 … | } |
185 | | - |
186 | | - pub fn nanos_since_start (&self) -> Nanos { |
187 | | - duration_to_nanos(self.start.elapsed()) |
188 | | - } |
189 | 230 … | |
190 | 231 … | pub fn nanos_since_tick (&self) -> Nanos { |
191 | | - duration_to_nanos(self.tick.elapsed()) |
| 232 … | + duration_to_nanos(self.instant.elapsed()) % self.signature.nanos_per_tick() |
192 | 233 … | } |
193 | 234 … | |
| 235 … | + pub fn nanos_until_tick (&self) -> Nanos { |
| 236 … | + let nanos_since_tick = self.nanos_since_tick(); |
| 237 … | + let nanos_per_tick = self.signature.nanos_per_tick(); |
| 238 … | + nanos_per_tick - nanos_since_tick |
| 239 … | + } |
| 240 … | + |
194 | 241 … | |
195 | | - pub fn tick (&mut self) -> ClockTime { |
196 | | - let diff = self.diff(); |
| 242 … | + pub fn tick (&mut self) -> Nanos { |
| 243 … | + let nanos_until_tick = self.nanos_until_tick(); |
197 | 244 … | |
198 | | - if diff.nanos > 0 { |
199 | | - sleep(Duration::new(0, diff.nanos as u32)) |
200 | | - }; |
| 245 … | + sleep(Duration::new(0, nanos_until_tick as u32)); |
201 | 246 … | |
202 | | - self.tick = Time::now(); |
| 247 … | + self.nanos = self.nanos + nanos_until_tick; |
| 248 … | + self.instant = Instant::now(); |
203 | 249 … | |
204 | | - diff |
| 250 … | + nanos_until_tick |
205 | 251 … | } |
206 | 252 … | } |
207 | 253 … | |
208 | 254 … | fn duration_to_nanos (duration: Duration) -> Nanos { |