@@ -196,6 +196,13 @@ pub enum MidiEventSource {
196196
197197type NoteId = u8 ;
198198
199+ #[ derive( Debug , Default ) ]
200+ struct NoteStats {
201+ notes_missed : usize ,
202+ notes_hit : usize ,
203+ wrong_notes : usize ,
204+ }
205+
199206#[ derive( Debug ) ]
200207struct NotePress {
201208 timestamp : Instant ,
@@ -212,6 +219,8 @@ pub struct PlayAlong {
212219 user_pressed_recently : HashMap < NoteId , NotePress > ,
213220 /// File notes that had NoteOn event, but no NoteOff yet
214221 in_proggres_file_notes : HashSet < NoteId > ,
222+
223+ stats : NoteStats ,
215224}
216225
217226impl PlayAlong {
@@ -221,6 +230,7 @@ impl PlayAlong {
221230 required_notes : Default :: default ( ) ,
222231 user_pressed_recently : Default :: default ( ) ,
223232 in_proggres_file_notes : Default :: default ( ) ,
233+ stats : NoteStats :: default ( ) ,
224234 }
225235 }
226236
@@ -229,20 +239,41 @@ impl PlayAlong {
229239 let now = Instant :: now ( ) ;
230240 let threshold = Duration :: from_millis ( 500 ) ;
231241
242+ // Track the count of items before retain
243+ let count_before = self . user_pressed_recently . len ( ) ;
244+
232245 // Retain only the items that are within the threshold
233246 self . user_pressed_recently
234247 . retain ( |_, item| now. duration_since ( item. timestamp ) <= threshold) ;
248+
249+ self . stats . wrong_notes += count_before - self . user_pressed_recently . len ( ) ;
235250 }
236251
237252 fn user_press_key ( & mut self , note_id : u8 , active : bool ) {
238253 let timestamp = Instant :: now ( ) ;
239254
240255 if active {
241256 // Check if note has already been played by a file
242- if self . required_notes . remove ( & note_id) . is_none ( ) {
257+ if let Some ( required_press) = self . required_notes . remove ( & note_id) {
258+ // 160 to forgive touching the bottom
259+ let threshold = Duration :: from_millis ( 160 ) ;
260+
261+ if timestamp. duration_since ( required_press. timestamp ) > threshold {
262+ self . stats . notes_missed += 1
263+ } else {
264+ self . stats . notes_hit += 1
265+ }
266+ } else {
243267 // This note was not played by file yet, place it in recents
244- self . user_pressed_recently
245- . insert ( note_id, NotePress { timestamp } ) ;
268+ let got_replaced = self
269+ . user_pressed_recently
270+ . insert ( note_id, NotePress { timestamp } )
271+ . is_some ( ) ;
272+
273+ if got_replaced {
274+ // TODO: This is not right, this may be to_early note, rather than wrong
275+ self . stats . wrong_notes += 1
276+ }
246277 }
247278 }
248279 }
@@ -251,7 +282,9 @@ impl PlayAlong {
251282 let timestamp = Instant :: now ( ) ;
252283 if active {
253284 // Check if note got pressed earlier 500ms (user_pressed_recently)
254- if self . user_pressed_recently . remove ( & note_id) . is_none ( ) {
285+ if self . user_pressed_recently . remove ( & note_id) . is_some ( ) {
286+ self . stats . notes_hit += 1
287+ } else {
255288 // Player never pressed that note, let it reach required_notes
256289
257290 // Ignore overlapping notes
0 commit comments