rhythm_core/
note.rs

1use std::cmp::Ordering;
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6/// The `Note` trait represents a rhythm note. (combo notes can be seen as a single note with volume > 1)
7pub trait Note: std::fmt::Debug + Ord + Clone {
8    /// Returns the start time of the note.
9    fn start(&self) -> f64;
10
11    /// Returns the duration of the note.
12    fn duration(&self) -> f64;
13
14    /// Returns the volume (max hit count) of the note.
15    fn volume(&self) -> u16;
16
17    /// Returns the user-defined hit type of the note.
18    /// For multi-track rhythm games, this can be used to the track number.
19    fn variant(&self) -> impl Into<u16>;
20
21    /// Sets the start time of the note.
22    fn set_start(&mut self, start: f64);
23
24    /// Sets the duration of the note.
25    fn set_duration(&mut self, duration: f64);
26
27    /// Sets the volume (max hit count) of the note. (combo notes can be seen as a single note with volume > 1
28    fn set_volume(&mut self, volume: u16);
29
30    /// Sets the user-defined hit type of the note.
31    /// For multi-track rhythm games, this can be used to the track number.
32    fn set_variant(&mut self, variant: impl Into<u16>);
33
34    fn cmp(&self, other: &Self) -> Ordering {
35        match self
36            .start()
37            .partial_cmp(&other.start())
38            .unwrap_or(Ordering::Equal)
39        {
40            std::cmp::Ordering::Equal => {
41                match (self.start() + self.duration())
42                    .partial_cmp(&(other.start() + other.duration()))
43                    .unwrap_or(Ordering::Equal)
44                {
45                    std::cmp::Ordering::Equal => self.variant().into().cmp(&other.variant().into()),
46                    other => other,
47                }
48            }
49            other => other,
50        }
51    }
52
53    /// Checks if the note matches a specific variant.
54    fn matches_variant(&self, variant: impl Into<u16>) -> bool {
55        self.variant().into() == variant.into()
56    }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
60#[cfg(feature = "serde")]
61#[derive(Serialize, Deserialize)]
62pub struct SimpleNote {
63    pub start: f64,
64    pub duration: f64,
65    pub volume: u16,
66    pub variant: u16,
67}
68
69impl Eq for SimpleNote {}
70
71impl SimpleNote {
72    pub fn new(
73        start: impl Into<f64>,
74        duration: impl Into<f64>,
75        volume: impl Into<u16>,
76        variant: impl Into<u16>,
77    ) -> Self {
78        Self {
79            start: start.into(),
80            duration: duration.into(),
81            volume: volume.into(),
82            variant: variant.into(),
83        }
84    }
85}
86
87impl Note for SimpleNote {
88    fn start(&self) -> f64 {
89        self.start
90    }
91    fn duration(&self) -> f64 {
92        self.duration
93    }
94    fn volume(&self) -> u16 {
95        self.volume
96    }
97    fn variant(&self) -> impl Into<u16> {
98        self.variant
99    }
100
101    fn set_start(&mut self, start: f64) {
102        self.start = start;
103    }
104    fn set_duration(&mut self, duration: f64) {
105        self.duration = duration;
106    }
107    fn set_volume(&mut self, volume: u16) {
108        self.volume = volume;
109    }
110    fn set_variant(&mut self, variant: impl Into<u16>) {
111        self.variant = variant.into();
112    }
113}
114
115impl Ord for SimpleNote {
116    fn cmp(&self, other: &Self) -> Ordering {
117        Note::cmp(self, other)
118    }
119}