rosu_pattern_detector/mania/
transform.rs1use crate::mania::models::base::{ManiaMeasure, NotesStruct};
2use crate::mania::models::pattern::Pattern;
3use crate::structs::CommonMeasure;
4use rosu_map;
5use rosu_map::section::hit_objects::{HitObject, HitObjectKind};
6use rosu_map::section::timing_points::TimingPoint;
7use std::collections::{BTreeMap, HashMap} ;
8use crate::mania::detector::HitObjects;
9
10pub(crate) fn transform_hit_object_to_mania_notes(
11 ho: Vec<HitObject>,
12 num_keys: i32,
13) -> Vec<NotesStruct> {
14 let num_keys = num_keys as usize;
15 let positions = match num_keys {
16 4 => vec![64.0, 192.0, 320.0, 448.0],
17 7 => vec![36.0, 109.0, 182.0, 256.0, 329.0, 402.0, 475.0],
18 _ => return Vec::new(),
19 };
20 let mut grouped: BTreeMap<i32, Vec<usize>> = BTreeMap::new();
21 for hit_object in ho {
22 let (pos_x, timestamp) = match &hit_object.kind {
23 HitObjectKind::Circle(circle) => (circle.pos.x, hit_object.start_time as i32),
24 HitObjectKind::Slider(slider) => (slider.pos.x, hit_object.start_time as i32),
25 _ => continue,
26 };
27 if let Some(key_index) = positions.iter().position(|&x| x == pos_x) {
28 grouped.entry(timestamp).or_default().push(key_index);
29 }
30 }
31 let mut notes_vec = Vec::with_capacity(grouped.len());
32 for (timestamp, indices) in grouped {
33 let mut keys = vec![false; num_keys];
34 for &key_index in &indices {
35 keys[key_index] = true;
36 }
37 let temporary_note = NotesStruct {
38 timestamp,
39 notes: keys.clone(),
40 };
41 notes_vec.push(temporary_note);
42 }
43 notes_vec
44}
45
46
47pub(crate) fn group_notes_by_measures(
48 notes: Vec<NotesStruct>,
49 timing_points: Vec<TimingPoint>,
50) -> HitObjects {
51 let mut measures = HitObjects(HashMap::new());
52
53 for note in notes {
54 let timing_point = timing_points
55 .iter()
56 .rev()
57 .find(|tp| note.timestamp >= tp.time as i32)
58 .unwrap_or_else(|| timing_points.first().unwrap());
59
60 let beat_len = timing_point.beat_len as f32;
61 let start_time = timing_point.time as i32;
62
63 let measure_idx = ((note.timestamp - start_time) as f32 / beat_len).floor() as i32;
64 let measure_start_time = start_time + (measure_idx as f32 * beat_len) as i32;
65
66 let measure_entry = measures.0.entry(measure_start_time).or_insert_with(|| ManiaMeasure {
67 measure: CommonMeasure {
68 start_time: measure_start_time,
69 npm: 0,
70 },
71 notes: Vec::new(),
72 pattern: Pattern::None,
73 value: 0.0,
74 });
75
76
77 measure_entry.notes.push(note.clone());
78 measure_entry.measure.npm += note.notes.iter().filter(|&&n| n).count() as i32;
79 }
80
81 measures
82}