Skip to main content

rgc_chart/models/generic/
timing_points.rs

1use crate::wasm_bindgen;
2use crate::models::common::TimingChangeType;
3
4#[derive(Debug, Clone, Copy)]
5pub struct TimingChange {
6    pub change_type: TimingChangeType,
7    pub value: f32,
8}
9
10#[derive(Debug, Clone)]
11pub struct TimingPoint {
12    pub time: i32,
13    pub beat: f32,
14    pub change: TimingChange,
15}
16
17// TODO: add wasm bindings for Timings
18#[wasm_bindgen]
19#[repr(C)]
20#[derive(Debug, Clone)]
21pub struct TimingPoints {
22    #[wasm_bindgen(skip)]
23    pub points: Vec<TimingPoint>,
24}
25
26impl From<Vec<TimingPoint>> for TimingPoints {
27    fn from(points: Vec<TimingPoint>) -> Self {
28        Self { points }
29    }
30}
31
32impl TimingPoints {
33    pub fn with_capacity(capacity: usize) -> Self {
34        Self {
35            points: Vec::with_capacity(capacity),
36        }
37    }
38
39    pub fn new(points: Vec<TimingPoint>) -> Self {
40        Self { points }
41    }
42
43    pub fn add(&mut self, time: i32, beat: f32, change: TimingChange) {
44        self.points.push(TimingPoint {
45            time,
46            beat,
47            change,
48        });
49    }
50
51    pub fn iter(&self) -> impl Iterator<Item = &TimingPoint> {
52        self.points.iter()
53    }
54
55    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut TimingPoint> {
56        self.points.iter_mut()
57    }
58
59    pub fn bpm_changes(&self) -> impl Iterator<Item = &TimingPoint> + '_ {
60        self.points
61            .iter()
62            .filter(|p| matches!(p.change.change_type, TimingChangeType::Bpm))
63    }
64
65    pub fn sv_changes(&self) -> impl Iterator<Item = &TimingPoint> + '_ {
66        self.points
67            .iter()
68            .filter(|p| matches!(p.change.change_type, TimingChangeType::Sv))
69    }
70
71    pub fn is_bpms_empty(&self) -> bool {
72        !self.points
73            .iter()
74            .any(|p| matches!(p.change.change_type, TimingChangeType::Bpm))
75    }
76
77    pub fn is_sv_empty(&self) -> bool {
78        !self.points
79            .iter()
80            .any(|p| matches!(p.change.change_type, TimingChangeType::Sv))
81    }
82
83    pub fn bpms(&self) -> Vec<f32> {
84        self.points
85            .iter()
86            .filter(|p| matches!(p.change.change_type, TimingChangeType::Bpm))
87            .map(|p| p.change.value)
88            .collect()
89    }
90
91    pub fn bpms_times(&self) -> Vec<i32> {
92        self.points
93            .iter()
94            .filter(|p| matches!(p.change.change_type, TimingChangeType::Bpm))
95            .map(|p| p.time)
96            .collect()
97    }
98
99    pub fn sv(&self) -> Vec<f32> {
100        self.points
101            .iter()
102            .filter(|p| matches!(p.change.change_type, TimingChangeType::Sv))
103            .map(|p| p.change.value)
104            .collect()
105    }
106}