1use crate::{AudioContext, PlaySoundParams};
2
3use std::cell::Cell;
4use std::collections::HashMap;
5use std::sync::Arc;
6use std::sync::mpsc;
7
8enum AudioMessage {
9 AddSound(u32, Vec<f32>),
10 Play(u32, u32, bool, f32),
11 Stop(u32),
12 StopAll(u32),
13 SetVolume(u32, f32),
14 SetVolumeAll(u32, f32),
15 Delete(u32),
16}
17
18#[derive(Debug)]
19pub struct SoundState {
20 sound_id: u32,
21 play_id: u32,
22 sample: usize,
23 data: Arc<[f32]>,
24 looped: bool,
25 volume: f32,
26}
27
28impl SoundState {
29 fn get_samples(&mut self, n: usize) -> &[f32] {
30 let data = &self.data[self.sample..];
31
32 self.sample += n;
33
34 match data.get(..n) {
35 Some(data) => data,
36 None => data,
37 }
38 }
39
40 fn rewind(&mut self) {
41 self.sample = 0;
42 }
43}
44
45pub struct Mixer {
46 rx: mpsc::Receiver<AudioMessage>,
47 sounds: HashMap<u32, Arc<[f32]>>,
48 mixer_state: Vec<SoundState>,
49}
50
51pub struct MixerBuilder {
52 rx: mpsc::Receiver<AudioMessage>,
53}
54
55pub struct MixerControl {
56 tx: mpsc::Sender<AudioMessage>,
57 sound_id: Cell<u32>,
58 play_id: Cell<u32>,
59}
60
61pub struct Playback {
62 play_id: u32,
63}
64
65impl Playback {
66 pub fn stop(self, ctx: &AudioContext) {
67 ctx.mixer_ctrl.send(AudioMessage::Stop(self.play_id));
68 }
69
70 pub fn set_volume(&self, ctx: &AudioContext, volume: f32) {
71 ctx.mixer_ctrl
72 .send(AudioMessage::SetVolume(self.play_id, volume));
73 }
74}
75
76impl MixerControl {
77 pub fn load(&self, data: &[u8]) -> u32 {
78 let sound_id = self.sound_id.get();
79
80 let samples = load_samples_from_file(data).unwrap();
81
82 self.tx
83 .send(crate::mixer::AudioMessage::AddSound(sound_id, samples))
84 .unwrap_or_else(|_| println!("Audio thread died"));
85 self.sound_id.set(sound_id + 1);
86
87 sound_id
88 }
89
90 pub fn play(&self, sound_id: u32, params: PlaySoundParams) -> Playback {
91 let play_id = self.play_id.get();
92
93 self.send(AudioMessage::Play(
94 sound_id,
95 play_id,
96 params.looped,
97 params.volume,
98 ));
99
100 self.play_id.set(play_id + 1);
101
102 Playback { play_id }
103 }
104
105 pub fn stop(&self, play_id: u32) {
106 self.send(AudioMessage::Stop(play_id));
107 }
108
109 pub fn stop_all(&self, sound_id: u32) {
110 self.send(AudioMessage::StopAll(sound_id));
111 }
112
113 pub fn set_volume_all(&self, sound_id: u32, volume: f32) {
114 self.send(AudioMessage::SetVolumeAll(sound_id, volume));
115 }
116
117 pub fn delete(&self, sound_id: u32) {
118 self.send(AudioMessage::Delete(sound_id));
119 }
120
121 fn send(&self, message: AudioMessage) {
122 self.tx
123 .send(message)
124 .unwrap_or_else(|_| println!("Audio thread died"))
125 }
126}
127
128impl MixerBuilder {
129 pub fn build(self) -> Mixer {
130 Mixer {
131 rx: self.rx,
132 sounds: HashMap::new(),
133 mixer_state: vec![],
134 }
135 }
136}
137
138impl Mixer {
139 pub fn new() -> (MixerBuilder, MixerControl) {
140 let (tx, rx) = mpsc::channel();
141
142 (
143 MixerBuilder { rx },
144 MixerControl {
145 tx,
146 sound_id: Cell::new(0),
147 play_id: Cell::new(0),
148 },
149 )
150 }
151
152 pub fn fill_audio_buffer(&mut self, buffer: &mut [f32], frames: usize) {
153 while let Ok(message) = self.rx.try_recv() {
154 match message {
155 AudioMessage::AddSound(id, data) => {
156 self.sounds.insert(id, data.into());
157 }
158 AudioMessage::Play(sound_id, play_id, looped, volume) => {
159 if let Some(data) = self.sounds.get(&sound_id) {
160 self.mixer_state.push(SoundState {
161 sound_id,
162 play_id,
163 sample: 0,
164 data: data.clone(),
165 looped,
166 volume,
167 });
168 }
169 }
170 AudioMessage::Stop(play_id) => {
171 if let Some(i) = self.mixer_state.iter().position(|s| s.play_id == play_id) {
172 self.mixer_state.swap_remove(i);
173 }
174 }
175 AudioMessage::StopAll(sound_id) => {
176 for i in (0..self.mixer_state.len()).rev() {
177 if self.mixer_state[i].sound_id == sound_id {
178 self.mixer_state.swap_remove(i);
179 }
180 }
181 }
182 AudioMessage::SetVolume(play_id, volume) => {
183 if let Some(sound) = self.mixer_state.iter_mut().find(|s| s.play_id == play_id)
184 {
185 sound.volume = volume;
186 }
187 }
188 AudioMessage::SetVolumeAll(sound_id, volume) => {
189 for sound in self
190 .mixer_state
191 .iter_mut()
192 .filter(|s| s.sound_id == sound_id)
193 {
194 sound.volume = volume;
195 }
196 }
197 AudioMessage::Delete(sound_id) => {
198 for i in (0..self.mixer_state.len()).rev() {
199 if self.mixer_state[i].sound_id == sound_id {
200 self.mixer_state.swap_remove(i);
201 }
202 }
203 self.sounds.remove(&sound_id);
204 }
205 }
206 }
207
208 buffer.fill(0.0);
210
211 let mut i = 0;
213
214 while let Some(sound) = self.mixer_state.get_mut(i) {
215 let volume = sound.volume;
216 let mut remainder = buffer.len();
217
218 loop {
219 let samples = sound.get_samples(remainder);
220
221 for (b, s) in buffer.iter_mut().zip(samples) {
222 *b += s * volume;
223 }
224
225 remainder -= samples.len();
226
227 if remainder > 0 && sound.looped {
228 sound.rewind();
229 continue;
230 }
231
232 break;
233 }
234
235 if remainder > 0 {
236 self.mixer_state.swap_remove(i);
237 } else {
238 i += 1;
239 }
240 }
241 }
242}
243
244pub fn load_samples_from_file(bytes: &[u8]) -> Result<Vec<f32>, ()> {
246 let mut audio_stream = {
247 let file = std::io::Cursor::new(bytes);
248 audrey::Reader::new(file).unwrap()
249 };
250
251 let description = audio_stream.description();
252 let channels_count = description.channel_count();
253 assert!(channels_count == 1 || channels_count == 2);
254
255 let mut frames: Vec<f32> = Vec::with_capacity(4096);
256 let mut samples_iterator = audio_stream
257 .samples::<f32>()
258 .map(std::result::Result::unwrap);
259
260 if channels_count == 1 {
263 frames.extend(samples_iterator.flat_map(|sample| [sample, sample]));
264 } else if channels_count == 2 {
265 frames.extend(samples_iterator);
266 }
267
268 let sample_rate = description.sample_rate();
269
270 if sample_rate != 44100 {
272 let mut new_length = ((44100 as f32 / sample_rate as f32) * frames.len() as f32) as usize;
273
274 new_length -= new_length % 2;
276
277 let mut resampled = vec![0.0; new_length];
278
279 for (n, sample) in resampled.chunks_exact_mut(2).enumerate() {
280 let ix = 2 * ((n as f32 / new_length as f32) * frames.len() as f32) as usize;
281 sample[0] = frames[ix];
282 sample[1] = frames[ix + 1];
283 }
284 return Ok(resampled);
285 }
286
287 Ok(frames)
288}