1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4use crate::note::Note;
5
6#[derive(Debug, Clone, PartialEq)]
7#[cfg(feature = "serde")]
8#[derive(Serialize, Deserialize)]
9pub struct Rhythm<T: Note> {
10 pub notes: Vec<T>,
11 time: f64,
13 #[serde(skip_serializing, skip_deserializing)]
15 availables: Vec<T>,
16}
17
18impl<T: Note> Rhythm<T> {
19 pub fn new(notes: Vec<T>) -> Self {
20 let mut availables = notes.clone();
21 availables.sort_unstable();
22
23 Self {
24 notes,
25 time: 0.0,
26 availables,
27 }
28 }
29
30 pub fn current_time(&self) -> f64 {
31 self.time
32 }
33
34 pub fn forward(&mut self, time: impl Into<f64>) -> Vec<T> {
35 self.time += time.into();
36 self.update_availables()
37 }
38
39 pub fn set_time(&mut self, time: impl Into<f64>) {
40 self.time = time.into();
41 self.availables = self.notes.clone();
42 self.availables.sort_unstable();
43 self.update_availables();
44 }
45
46 pub fn finished(&self) -> bool {
47 self.availables.is_empty()
48 }
49
50 pub fn hit(&mut self, variant: impl Into<u16>) -> Option<(&T, f64)> {
51 let variant: u16 = variant.into();
52 let hitables = self.availables.iter_mut().filter(|note| {
53 note.start() <= self.time && note.start() + note.duration() >= self.time
54 });
55
56 for note in hitables {
57 if note.matches_variant(variant) && note.volume() > 0 {
58 note.set_volume(note.volume() - 1);
59 let time = self.time - note.start();
60 return Some((note, time));
61 }
62 }
63
64 None
65 }
66
67 fn update_availables(&mut self) -> Vec<T> {
68 let mut removed = vec![];
69 self.availables.retain(|note| {
70 let keep = note.start() + note.duration() >= self.time && note.volume() > 0;
71 if !keep && note.volume() > 0 {
72 removed.push(note.clone());
73 }
74 keep
75 });
76 removed
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use crate::note::SimpleNote;
84
85 #[test]
86 fn test_single_note() {
87 let notes = vec![
88 SimpleNote::new(1000, 100, 1u16, 0u16),
89 SimpleNote::new(1100, 100, 1u16, 1u16),
90 SimpleNote::new(2000, 100, 1u16, 0u16),
91 SimpleNote::new(2100, 100, 1u16, 1u16),
92 ];
93
94 let mut rhythm = Rhythm::new(notes);
95
96 assert_eq!(rhythm.current_time(), 0.0);
97
98 assert_eq!(rhythm.forward(500), vec![]);
99 assert_eq!(rhythm.current_time(), 500.0);
100 assert_eq!(rhythm.hit(0u16), None);
101
102 assert_eq!(rhythm.forward(550), vec![]);
103 assert_eq!(rhythm.current_time(), 1050.0);
104 assert_eq!(rhythm.hit(1u16), None);
105 assert_eq!(
106 rhythm.hit(0u16),
107 Some((&SimpleNote::new(1000, 100, 0u16, 0u16), 50.0))
108 );
109 assert_eq!(rhythm.hit(0u16), None);
110
111 assert_eq!(
112 rhythm.forward(200),
113 vec![SimpleNote::new(1100, 100, 1u16, 1u16)]
114 );
115 assert_eq!(rhythm.current_time(), 1250.0);
116 assert_eq!(rhythm.hit(1u16), None);
117
118 assert_eq!(
119 rhythm.forward(2000),
120 vec![
121 SimpleNote::new(2000, 100, 1u16, 0u16),
122 SimpleNote::new(2100, 100, 1u16, 1u16)
123 ]
124 );
125 }
126
127 #[test]
128 fn test_combo_note() {
129 let notes = vec![
130 SimpleNote::new(1000, 1000, 10u16, 0u16),
131 SimpleNote::new(3000, 2000, u16::MAX, 1u16),
132 ];
133
134 let mut rhythm = Rhythm::new(notes);
135
136 assert_eq!(rhythm.current_time(), 0.0);
137
138 assert_eq!(rhythm.forward(1500), vec![]);
139 assert_eq!(rhythm.current_time(), 1500.0);
140 for i in 0..10 {
141 assert_eq!(
142 rhythm.hit(0u16),
143 Some((
144 &SimpleNote::new(1000, 1000, 9 - i as u16, 0u16),
145 500.0 + i as f64 * 10.0
146 ))
147 );
148 assert_eq!(rhythm.forward(10), vec![]);
149 }
150 assert_eq!(rhythm.current_time(), 1600.0);
151 assert_eq!(rhythm.hit(0u16), None);
152
153 assert_eq!(rhythm.forward(3000), vec![]);
154 assert_eq!(rhythm.current_time(), 4600.0);
155 for i in 0..1000 {
156 assert_eq!(
157 rhythm.hit(1u16),
158 Some((
159 &SimpleNote::new(3000, 2000, u16::MAX - 1 - i as u16, 1u16),
160 1600.0
161 ))
162 );
163 }
164 }
165}