rgc_chart/models/generic/
sound.rs1use 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}