Skip to main content

rgc_chart/models/generic/
sound.rs

1use crate::wasm_bindgen;
2use std::collections::HashMap;
3
4#[wasm_bindgen]
5#[derive(Debug, Clone, Copy, Eq, PartialEq)]
6pub enum HitSoundType {
7    Normal,
8    Clap,
9    Whistle,
10    Finish,
11}
12
13#[wasm_bindgen]
14#[derive(Debug, Clone)]
15pub struct SoundEffect {
16    #[wasm_bindgen(getter_with_clone)]
17    pub time: i32,
18    #[wasm_bindgen(getter_with_clone)]
19    pub volume: u8,
20    #[wasm_bindgen(getter_with_clone)]
21    pub sample: usize,
22}
23
24#[wasm_bindgen]
25impl SoundEffect {
26    #[inline]
27    #[wasm_bindgen(constructor)]
28    pub fn new(time: i32, volume: u8, sample: usize) -> Self {
29        Self { time, volume, sample }
30    }
31}
32
33#[wasm_bindgen]
34#[derive(Debug, Clone, Copy)]
35pub struct KeySound {
36    #[wasm_bindgen(getter_with_clone)]
37    pub volume: u8,
38    #[wasm_bindgen(getter_with_clone)]
39    pub hitsound_type: HitSoundType,
40    #[wasm_bindgen(getter_with_clone)]
41    pub sample: Option<usize>,
42    #[wasm_bindgen(getter_with_clone)]
43    pub has_custom: bool,
44}
45
46impl Default for KeySound {
47    fn default() -> Self {
48        KeySound::normal(100)
49    }
50}
51
52impl KeySound {
53    pub fn of_type(volume: u8, hitsound_type: HitSoundType) -> Self  {
54        Self {
55            volume,
56            hitsound_type,
57            sample: None,
58            has_custom: false
59        }
60    }
61
62    pub fn normal(volume: u8) -> Self {
63        Self {
64            volume,
65            hitsound_type: HitSoundType::Normal,
66            sample: None,
67            has_custom: false
68        }
69    }
70
71    pub fn clap(volume: u8) -> Self {
72        Self {
73            volume,
74            hitsound_type: HitSoundType::Clap,
75            sample: None,
76            has_custom: false
77        }
78    }
79
80    pub fn whistle(volume: u8) -> Self {
81        Self {
82            volume,
83            hitsound_type: HitSoundType::Whistle,
84            sample: None,
85            has_custom: false
86        }
87    }
88
89    pub fn finish(volume: u8) -> Self {
90        Self {
91            volume,
92            hitsound_type: HitSoundType::Finish,
93            sample: None,
94            has_custom: false
95        }
96    }
97
98    pub fn with_custom(volume: u8, sample_index: usize, hitsound_type: Option<HitSoundType>) -> Self {
99        let hstype = if let Some(hstype) = hitsound_type {
100            hstype
101        } else {
102            HitSoundType::Normal
103        };
104        Self {
105            volume,
106            hitsound_type: hstype,
107            sample: Some(sample_index),
108            has_custom: true
109        }
110    }
111}
112
113#[wasm_bindgen]
114#[derive(Debug, Clone)]
115pub struct KeySoundRow {
116    sounds: Vec<KeySound>,
117    pub is_empty: bool,
118}
119
120impl KeySoundRow {
121    pub fn with_capacity(capacity: usize) -> Self {
122        Self {
123            sounds: vec![KeySound::normal(100); capacity],
124            is_empty: true,
125        }
126    }
127
128    pub fn empty() -> Self {
129        Self {
130            sounds: Vec::new(),
131            is_empty: true,
132        }
133    }
134    
135    pub fn with(sounds: Vec<KeySound>) -> Self {
136        Self {
137            sounds,
138            is_empty: false,
139        }
140    }
141
142    pub fn with_unwrap(sounds: &[Option<KeySound>]) -> Self {
143        Self {
144            sounds: sounds
145                .iter()
146                .map(|s| s.unwrap_or(KeySound::normal(100)))
147                .collect(),
148            is_empty: false,
149        }
150    }
151    
152    pub fn get_sounds(&self) -> &Vec<KeySound> {
153        &self.sounds
154    }
155
156    pub fn len(&self) -> usize {
157        self.sounds.len()
158    }
159    
160    pub fn as_ptr(&mut self) -> *const KeySound {
161        self.sounds.as_ptr()
162    }
163
164    pub fn as_mut_ptr(&mut self) -> *mut KeySound {
165        self.sounds.as_mut_ptr()
166    }
167}
168
169impl std::ops::Index<usize> for KeySoundRow {
170    type Output = KeySound;
171
172    fn index(&self, index: usize) -> &Self::Output {
173        &self.sounds[index]
174    }
175}
176
177impl std::ops::IndexMut<usize> for KeySoundRow {
178    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
179        &mut self.sounds[index]
180    }
181}
182
183#[wasm_bindgen]
184#[derive(Debug, Clone)]
185pub struct SoundBank {
186    #[wasm_bindgen(getter_with_clone)]
187    pub audio_tracks: Vec<String>,
188    sound_sample_paths: Vec<String>,
189    #[wasm_bindgen(getter_with_clone)]
190    pub sound_effects: Vec<SoundEffect>,
191    sample_map: HashMap<String, usize>,
192}
193
194impl Default for SoundBank {
195    fn default() -> Self {
196        SoundBank::new()
197    }
198}
199
200#[wasm_bindgen]
201impl SoundBank {
202    #[wasm_bindgen(constructor)]
203    pub fn new() -> Self {
204        Self {
205            audio_tracks: Vec::new(),
206            sound_sample_paths: Vec::new(),
207            sound_effects: Vec::new(),
208            sample_map: HashMap::new(),
209        }
210    }
211
212    #[wasm_bindgen]
213    pub fn add_sound_sample(&mut self, path: String) -> usize {
214        if let Some(&index) = self.sample_map.get(&path) {
215            index
216        } else {
217            let index = self.sound_sample_paths.len();
218            self.sound_sample_paths.push(path.clone());
219            self.sample_map.insert(path, index);
220            index
221        }
222    }
223
224    #[wasm_bindgen]
225    pub fn add_sound_sample_with_index(&mut self, index: usize, path: String) {
226        if path.is_empty() {
227            return;
228        }
229
230        if index >= self.sound_sample_paths.len() {
231            self.sound_sample_paths.resize(index + 1, String::new());
232        }
233        
234        if !self.sound_sample_paths[index].is_empty() {
235            self.sample_map.remove(&self.sound_sample_paths[index]);
236        }
237        
238        self.sound_sample_paths[index] = path.clone();
239        self.sample_map.insert(path, index);
240    }
241
242    pub fn add_sound_effect(&mut self, sound_effect: SoundEffect) {
243        self.sound_effects.push(sound_effect);
244    }
245
246    #[wasm_bindgen]
247    pub fn get_sound_sample(&self, index: usize) -> Option<String> {
248        self.sound_sample_paths.get(index)
249            .filter(|s| !s.is_empty())  
250            .cloned()
251    }
252
253    #[wasm_bindgen]
254    pub fn get_index_sample(&self, sample_path: &str) -> Option<usize> {
255        self.sample_map.get(sample_path).copied()
256    }
257
258    #[wasm_bindgen]
259    pub fn get_sample_paths(&self) -> Vec<String> {
260        self.sound_sample_paths.clone()
261    }
262
263    #[wasm_bindgen]
264    pub fn contains_path(&self, path: &str) -> bool {
265        self.sample_map.contains_key(path)
266    }
267
268    #[wasm_bindgen]
269    pub fn sample_count(&self) -> usize {
270        self.sound_sample_paths.iter().filter(|s| !s.is_empty()).count()
271    }
272
273    #[wasm_bindgen]
274    pub fn is_empty(&self) -> bool {
275        self.sample_map.is_empty()
276    }
277}