1use crate::{converter, SampleRate, SoundId, SoundSource};
2use std::{
3 collections::HashMap,
4 hash::Hash,
5 sync::atomic::{AtomicU64, Ordering},
6};
7
8fn next_id() -> SoundId {
9 static GLOBAL_COUNT: AtomicU64 = AtomicU64::new(0);
10 GLOBAL_COUNT.fetch_add(1, Ordering::Relaxed)
11}
12
13struct SoundInner<G = ()> {
14 id: SoundId,
15 data: Box<dyn SoundSource + Send>,
16 volume: f32,
17 group: G,
18 looping: bool,
19 drop: bool,
20}
21impl<G> SoundInner<G> {
22 fn new(group: G, data: Box<dyn SoundSource + Send>) -> Self {
23 Self {
24 id: next_id(),
25 data,
26 volume: 1.0,
27 group,
28 looping: false,
29 drop: true,
30 }
31 }
32}
33
34pub struct Mixer<G: Eq + Hash + Send + 'static = ()> {
36 sounds: Vec<SoundInner<G>>,
37 playing: usize,
38 channels: u16,
39 sample_rate: SampleRate,
40 group_volumes: HashMap<G, f32>,
41}
42
43impl<G: Eq + Hash + Send + 'static> Mixer<G> {
44 pub fn new(channels: u16, sample_rate: SampleRate) -> Self {
49 Self {
50 sounds: vec![],
51 playing: 0,
52 channels,
53 sample_rate,
54 group_volumes: HashMap::new(),
55 }
56 }
57
58 pub fn set_config(&mut self, channels: u16, sample_rate: SampleRate) {
63 struct Nop;
64 #[rustfmt::skip]
65 impl SoundSource for Nop {
66 fn channels(&self) -> u16 { 0 }
67 fn sample_rate(&self) -> u32 { 0 }
68 fn reset(&mut self) { }
69 fn write_samples(&mut self, _: &mut [i16]) -> usize { 0 }
70 }
71
72 let not_chaged = self.channels == channels && self.sample_rate == sample_rate;
73 if not_chaged {
74 return;
75 }
76 if !self.sounds.is_empty() {
77 for sound in self.sounds.iter_mut() {
78 if sound.data.channels() != channels {
83 let inner = std::mem::replace(&mut sound.data, Box::new(Nop));
84 sound.data = Box::new(converter::ChannelConverter::new(inner, channels));
85 }
86 if sound.data.sample_rate() != sample_rate.0 {
87 let inner = std::mem::replace(&mut sound.data, Box::new(Nop));
88 sound.data =
89 Box::new(converter::SampleRateConverter::new(inner, sample_rate.0));
90 }
91 }
92 }
93 self.channels = channels;
94 self.sample_rate = sample_rate;
95 }
96
97 pub fn add_sound(&mut self, group: G, sound: Box<dyn SoundSource + Send>) -> SoundId {
104 let sound_inner = SoundInner::new(group, sound);
105 let id = sound_inner.id;
106 self.sounds.push(sound_inner);
107 id
108 }
109
110 pub fn play(&mut self, id: SoundId) {
115 for i in (self.playing..self.sounds.len()).rev() {
116 if self.sounds[i].id == id {
117 self.sounds.swap(self.playing, i);
118 self.playing += 1;
119 break;
120 }
121 }
122 }
123
124 pub fn pause(&mut self, id: SoundId) {
130 for i in (0..self.playing).rev() {
131 if self.sounds[i].id == id {
132 self.playing -= 1;
133 self.sounds.swap(self.playing, i);
134 break;
135 }
136 }
137 }
138
139 pub fn stop(&mut self, id: SoundId) {
147 for i in (0..self.sounds.len()).rev() {
148 if self.sounds[i].id == id {
149 if self.sounds[i].drop {
150 self.sounds.swap_remove(i);
151 } else {
152 self.sounds[i].data.reset();
153 }
154 if i < self.playing {
155 self.playing -= 1;
156 self.sounds.swap(self.playing, i);
157 }
158 break;
159 }
160 }
161 }
162
163 pub fn reset(&mut self, id: SoundId) {
167 for i in (0..self.sounds.len()).rev() {
168 if self.sounds[i].id == id {
169 self.sounds[i].data.reset();
170 break;
171 }
172 }
173 }
174
175 pub fn set_loop(&mut self, id: SoundId, looping: bool) {
181 for i in (0..self.sounds.len()).rev() {
182 if self.sounds[i].id == id {
183 self.sounds[i].looping = looping;
184 break;
185 }
186 }
187 }
188
189 pub fn set_volume(&mut self, id: SoundId, volume: f32) {
194 for i in (0..self.sounds.len()).rev() {
195 if self.sounds[i].id == id {
196 self.sounds[i].volume = volume;
197 break;
198 }
199 }
200 }
201
202 pub fn set_group_volume(&mut self, group: G, volume: f32) {
206 self.group_volumes.insert(group, volume);
207 }
208
209 pub fn mark_to_remove(&mut self, id: SoundId, drop: bool) {
215 for i in (0..self.sounds.len()).rev() {
216 if self.sounds[i].id == id {
217 self.sounds[i].drop = drop;
218 break;
219 }
220 }
221 }
222
223 pub fn sound_count(&self) -> usize {
227 self.sounds.len()
228 }
229
230 pub fn playing_count(&self) -> usize {
234 self.playing
235 }
236}
237
238impl<G: Eq + Hash + Send + 'static> SoundSource for Mixer<G> {
239 fn channels(&self) -> u16 {
240 self.channels
241 }
242
243 fn sample_rate(&self) -> u32 {
244 self.sample_rate.0
245 }
246
247 fn reset(&mut self) {}
248
249 fn write_samples(&mut self, buffer: &mut [i16]) -> usize {
250 if self.playing == 0 {
251 for b in buffer.iter_mut() {
252 *b = 0;
253 }
254 return buffer.len();
255 }
256
257 let mut buf = vec![0; buffer.len()];
258 let mut s = 0;
259 while s < self.playing {
260 let mut len = 0;
261 loop {
262 len += self.sounds[s].data.write_samples(&mut buf[len..]);
263 if len < buffer.len() {
264 self.sounds[s].data.reset();
265 if self.sounds[s].looping {
266 continue;
267 }
268 }
269 break;
270 }
271
272 let group_volume = *self
273 .group_volumes
274 .get(&self.sounds[s].group)
275 .unwrap_or(&1.0);
276 let volume = self.sounds[s].volume * group_volume;
277
278 if (volume - 1.0).abs() < 1.0 / i16::max_value() as f32 {
279 for i in 0..len {
280 buffer[i] = buffer[i].saturating_add(buf[i]);
281 }
282 } else {
283 for i in 0..len {
284 buffer[i] = buffer[i].saturating_add((buf[i] as f32 * volume) as i16);
285 }
286 }
287
288 if len < buffer.len() {
289 if self.sounds[s].drop {
290 let _ = self.sounds.swap_remove(s);
291 }
292 self.playing -= 1;
293 if self.playing > 0 && self.playing < self.sounds.len() {
294 self.sounds.swap(s, self.playing);
295 }
296 } else {
297 s += 1;
298 }
299 }
300
301 buffer.len()
302 }
303}
304
305#[cfg(test)]
306mod test {
307 use crate::SoundSource;
308
309 use super::Mixer;
310
311 struct DebugSource {
312 i: usize,
313 v: i16,
314 len: usize,
315 }
316 impl DebugSource {
317 fn new(v: i16, len: usize) -> Self {
318 Self { i: 0, v, len }
319 }
320 }
321 impl SoundSource for DebugSource {
322 fn channels(&self) -> u16 {
323 1
324 }
325
326 fn sample_rate(&self) -> u32 {
327 1
328 }
329
330 fn reset(&mut self) {
331 self.i = 0;
332 }
333
334 fn write_samples(&mut self, buffer: &mut [i16]) -> usize {
335 for (i, o) in buffer.iter_mut().enumerate() {
336 *o = self.v;
337 self.i += 1;
338 if self.i > self.len {
339 return i;
340 }
341 }
342 buffer.len()
343 }
344 }
345
346 #[test]
347 fn start_stopped() {
348 let mut mixer = Mixer::new(1, crate::SampleRate(1));
349
350 let id = mixer.add_sound((), Box::new(DebugSource::new(2, 5)));
352
353 let mut buffer = [0; 10];
355 assert_eq!(mixer.write_samples(&mut buffer), 10);
356 assert_eq!(buffer, [0; 10]);
357
358 mixer.play(id);
360 assert_eq!(mixer.write_samples(&mut buffer), 10);
361 assert_eq!(buffer, [2, 2, 2, 2, 2, 0, 0, 0, 0, 0]);
362
363 mixer.reset(id);
365 mixer.play(id);
366 assert_eq!(mixer.write_samples(&mut buffer), 10);
367 assert_eq!(buffer, [0; 10]);
368
369 let id = mixer.add_sound((), Box::new(DebugSource::new(2, 5)));
371
372 mixer.stop(id);
373 }
374
375 #[test]
376 fn mark_to_remove_true() {
377 let mut mixer = Mixer::new(1, crate::SampleRate(1));
378
379 let id = mixer.add_sound((), Box::new(DebugSource::new(2, 5)));
381
382 mixer.stop(id);
384
385 mixer.reset(id);
387 mixer.play(id);
388 let mut buffer = [0; 10];
389 assert_eq!(mixer.write_samples(&mut buffer), 10);
390 assert_eq!(buffer, [0; 10]);
391 }
392
393 #[test]
394 fn mark_to_remove_false() {
395 let mut mixer = Mixer::new(1, crate::SampleRate(1));
396
397 let id = mixer.add_sound((), Box::new(DebugSource::new(2, 5)));
398 mixer.mark_to_remove(id, false);
399
400 mixer.stop(id);
402
403 let mut buffer = [0; 10];
405 assert_eq!(mixer.write_samples(&mut buffer), 10);
406 assert_eq!(buffer, [0; 10]);
407
408 mixer.play(id);
410 assert_eq!(mixer.playing_count(), 1);
411 assert_eq!(mixer.write_samples(&mut buffer), 10);
412 assert_eq!(buffer, [2, 2, 2, 2, 2, 0, 0, 0, 0, 0]);
413
414 mixer.play(id);
416 buffer = [0; 10];
417 assert_eq!(mixer.playing_count(), 1);
418 assert_eq!(mixer.write_samples(&mut buffer), 10);
419 assert_eq!(buffer, [2, 2, 2, 2, 2, 0, 0, 0, 0, 0]);
420 }
421
422 #[test]
423 fn volume() {
424 let mut mixer = Mixer::new(1, crate::SampleRate(1));
425
426 let id0 = mixer.add_sound((), Box::new(DebugSource::new(10, 2)));
427 let id1 = mixer.add_sound((), Box::new(DebugSource::new(10, 4)));
428 let id2 = mixer.add_sound((), Box::new(DebugSource::new(10, 6)));
429
430 mixer.set_volume(id0, 0.2);
431 mixer.set_volume(id1, 0.4);
432 mixer.set_volume(id2, 0.8);
433
434 mixer.play(id0);
435 mixer.play(id1);
436 mixer.play(id2);
437
438 let mut buffer = [0; 10];
439 assert_eq!(mixer.write_samples(&mut buffer), 10);
440 assert_eq!(buffer, [14, 14, 12, 12, 8, 8, 0, 0, 0, 0]);
441 }
442
443 #[test]
444 fn group_volume() {
445 #[derive(Eq, Hash, PartialEq)]
446 enum Group {
447 A,
448 B,
449 }
450
451 let mut mixer = Mixer::new(1, crate::SampleRate(1));
452
453 let a0 = mixer.add_sound(Group::A, Box::new(DebugSource::new(10, 2)));
454 let a1 = mixer.add_sound(Group::A, Box::new(DebugSource::new(10, 4)));
455 let a2 = mixer.add_sound(Group::A, Box::new(DebugSource::new(10, 6)));
456
457 let b0 = mixer.add_sound(Group::B, Box::new(DebugSource::new(10, 8)));
458 let b1 = mixer.add_sound(Group::B, Box::new(DebugSource::new(10, 10)));
459 let b2 = mixer.add_sound(Group::B, Box::new(DebugSource::new(10, 12)));
460
461 mixer.set_volume(a0, 0.2);
462 mixer.set_volume(a1, 0.4);
463 mixer.set_volume(a2, 0.8);
464
465 mixer.set_volume(b0, 0.2);
466 mixer.set_volume(b1, 0.4);
467 mixer.set_volume(b2, 0.8);
468
469 mixer.set_group_volume(Group::A, 2.0);
470 mixer.set_group_volume(Group::B, 4.0);
471
472 assert_eq!(mixer.sound_count(), 6);
473 assert_eq!(mixer.playing_count(), 0);
474
475 mixer.play(a0);
476 mixer.play(a1);
477 mixer.play(a2);
478
479 mixer.play(b0);
480 mixer.play(b1);
481 mixer.play(b2);
482
483 assert_eq!(mixer.sound_count(), 6);
484 assert_eq!(mixer.playing_count(), 6);
485
486 let mut buffer = [0; 10];
487 assert_eq!(mixer.write_samples(&mut buffer), 10);
488 assert_eq!(buffer, [84, 84, 80, 80, 72, 72, 56, 56, 48, 48]);
490 buffer = [0; 10];
491 assert_eq!(mixer.write_samples(&mut buffer), 10);
492 assert_eq!(buffer, [32, 32, 0, 0, 0, 0, 0, 0, 0, 0]);
494
495 assert_eq!(mixer.sound_count(), 0);
496 assert_eq!(mixer.playing_count(), 0);
497 }
498}