rosu_pattern_detector/mania/
transform.rs

1use 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}