1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
pub mod handle;
mod metronomes;
mod settings;
use ringbuf::Producer;
use uuid::Uuid;
use crate::{parameter::Parameters, tempo::Tempo, value::CachedValue, Value};
use handle::MetronomeHandle;
pub(crate) use metronomes::Metronomes;
pub use settings::MetronomeSettings;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(
feature = "serde_support",
derive(serde::Serialize, serde::Deserialize),
serde(transparent)
)]
pub struct MetronomeId {
uuid: Uuid,
}
impl MetronomeId {
pub(crate) fn new() -> Self {
Self {
uuid: Uuid::new_v4(),
}
}
}
impl From<&MetronomeHandle> for MetronomeId {
fn from(handle: &MetronomeHandle) -> Self {
handle.id()
}
}
pub(crate) struct Metronome {
tempo: CachedValue<Tempo>,
interval_events_to_emit: Vec<f64>,
ticking: bool,
time: f64,
previous_time: f64,
event_producer: Producer<f64>,
}
impl Metronome {
pub fn new(settings: MetronomeSettings, event_producer: Producer<f64>) -> Self {
Self {
tempo: CachedValue::new(settings.tempo, Tempo(120.0)).with_min(Tempo(0.0)),
interval_events_to_emit: settings.interval_events_to_emit,
ticking: false,
time: 0.0,
previous_time: 0.0,
event_producer,
}
}
pub fn effective_tempo(&self) -> Tempo {
if self.ticking {
self.tempo.value()
} else {
Tempo(0.0)
}
}
pub fn set_tempo(&mut self, tempo: Value<Tempo>) {
self.tempo.set(tempo);
}
pub fn start(&mut self) {
self.ticking = true;
}
pub fn pause(&mut self) {
self.ticking = false;
}
pub fn stop(&mut self) {
self.ticking = false;
self.time = 0.0;
self.previous_time = 0.0;
}
pub fn update(&mut self, dt: f64, parameters: &Parameters) {
self.tempo.update(parameters);
if self.ticking {
self.previous_time = self.time;
self.time += (self.tempo.value().0 / 60.0) * dt;
for interval in &self.interval_events_to_emit {
if self.interval_passed(*interval) {
self.event_producer.push(*interval).ok();
}
}
}
}
pub fn interval_passed(&self, interval: f64) -> bool {
if !self.ticking {
return false;
}
if self.previous_time == 0.0 {
return true;
}
(self.previous_time % interval) > (self.time % interval)
}
}