1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
#![warn(missing_docs)]

//! Audio Engine is a cross-platform crate for audio playback, build on top of cpal.
//!
//! ## Supported formats
//! - ogg
//! - wav
//!
//! ## Example
//!
//! ```no_run
//! # fn main() -> Result<(), &'static str> {
//! # let my_wav_sound = std::io::Cursor::new(vec![]);
//! use audio_engine::{AudioEngine, WavDecoder};
//! let audio_engine = AudioEngine::new()?;
//! let mut sound = audio_engine.new_sound(WavDecoder::new(my_wav_sound))?;
//! sound.play();
//! # Ok(())
//! # }
//! ```

use std::sync::{
    atomic::{AtomicU64, Ordering},
    Arc, Mutex,
};

pub mod converter;
mod ogg;
mod wav;

mod engine;
pub use engine::AudioEngine;

pub use ogg::OggDecoder;
pub use wav::WavDecoder;

type SoundId = u64;

fn next_id() -> SoundId {
    static GLOBAL_COUNT: AtomicU64 = AtomicU64::new(0);
    GLOBAL_COUNT.fetch_add(1, Ordering::Relaxed)
}

/// The number of samples processed per second for a single channel of audio.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SampleRate(pub u32);

/// Represents a sound in the AudioEngine. If this is dropped, the sound will continue to play
/// until it ends.
pub struct Sound {
    mixer: Arc<Mutex<Mixer>>,
    id: SoundId,
}
impl Sound {
    /// Starts or continue to play the sound.
    ///
    /// If the sound was paused or stop, it will start playing again.
    /// Otherwise, does nothing.
    pub fn play(&mut self) {
        self.mixer.lock().unwrap().play(self.id);
    }

    /// Pause the sound.
    ///
    /// If the sound is playing, it will pause. If play is called,
    /// this sound will continue from where it was before pause.
    /// If the sound is not playing, does nothing.
    pub fn pause(&mut self) {
        self.mixer.lock().unwrap().pause(self.id);
    }

    /// Stop the sound.
    ///
    /// If the sound is playing, it will pause and reset the song. When play is called,
    /// this sound will start from the begging.
    /// Even if the sound is not playing, it will reset the sound to the start.
    pub fn stop(&mut self) {
        self.mixer.lock().unwrap().stop(self.id);
    }

    /// Reset the sound to the start.
    ///
    /// The behaviour is the same being the sound playing or not.
    pub fn reset(&mut self) {
        self.mixer.lock().unwrap().reset(self.id);
    }

    /// Set the volume of the sound.
    pub fn set_volume(&mut self, volume: f32) {
        self.mixer.lock().unwrap().set_volume(self.id, volume);
    }

    /// Set if the sound will repeat even time it reach the end.
    pub fn set_loop(&mut self, looping: bool) {
        self.mixer.lock().unwrap().set_loop(self.id, looping);
    }
}
impl Drop for Sound {
    fn drop(&mut self) {
        self.mixer.lock().unwrap().drop_sound(self.id);
    }
}

/// A source of sound samples.
///
/// Sound samples of each channel must be interleaved.
pub trait SoundSource {
    /// Return the number of channels.
    fn channels(&self) -> u16;

    /// Return the sample rate.
    fn sample_rate(&self) -> u32;

    /// Start the sound from the begining.
    fn reset(&mut self);

    /// Write the samples to `buffer`.
    ///
    /// Return how many samples was written. If it return a value less thand the length of
    /// `buffer`, this indicate that the sound ended.
    ///
    /// The `buffer` length and the returned length should always be a multiple of
    /// [`self.channels()`](SoundSource::channels).
    fn write_samples(&mut self, buffer: &mut [i16]) -> usize;
}
impl<T: SoundSource + ?Sized> SoundSource for Box<T> {
    fn channels(&self) -> u16 {
        (**self).channels()
    }

    fn sample_rate(&self) -> u32 {
        (**self).sample_rate()
    }

    fn reset(&mut self) {
        (**self).reset()
    }

    fn write_samples(&mut self, buffer: &mut [i16]) -> usize {
        (**self).write_samples(buffer)
    }
}

struct SoundInner {
    id: SoundId,
    data: Box<dyn SoundSource + Send>,
    volume: f32,
    looping: bool,
    drop: bool,
}
impl SoundInner {
    fn new(data: Box<dyn SoundSource + Send>) -> Self {
        Self {
            id: next_id(),
            data,
            volume: 1.0,
            looping: false,
            drop: false,
        }
    }
}

/// Keep track of each Sound, and mix they output together.
struct Mixer {
    sounds: Vec<SoundInner>,
    playing: usize,
    channels: u16,
    sample_rate: SampleRate,
}
impl Mixer {
    fn new(channels: u16, sample_rate: SampleRate) -> Self {
        Self {
            sounds: vec![],
            playing: 0,
            channels,
            sample_rate,
        }
    }

    /// Change the number of channels and the sample rate.
    ///
    /// This keep also keep all currently playing sounds, and convert them to the new config, if
    /// necessary.
    fn set_config(&mut self, channels: u16, sample_rate: SampleRate) {
        struct Nop;
        #[rustfmt::skip]
        impl SoundSource for Nop {
            fn channels(&self) -> u16 { 0 }
            fn sample_rate(&self) -> u32 { 0 }
            fn reset(&mut self) { }
            fn write_samples(&mut self, _: &mut [i16]) -> usize { 0 }
        }

        let not_chaged = self.channels == channels && self.sample_rate == sample_rate;
        if not_chaged {
            return;
        }
        if !self.sounds.is_empty() {
            for sound in self.sounds.iter_mut() {
                // FIXME: if the config change multiple times, this will nest multiple converts,
                // increasing processing and loosing quality.
                // Maybe I should create something like a tree of converters, and always keep the
                // convertes Concrete.
                if sound.data.channels() != channels {
                    let inner = std::mem::replace(&mut sound.data, Box::new(Nop));
                    sound.data = Box::new(converter::ChannelConverter::new(inner, channels));
                }
                if sound.data.sample_rate() != sample_rate.0 {
                    let inner = std::mem::replace(&mut sound.data, Box::new(Nop));
                    sound.data =
                        Box::new(converter::SampleRateConverter::new(inner, sample_rate.0));
                }
            }
        }
        self.channels = channels;
        self.sample_rate = sample_rate;
    }

    fn add_sound(&mut self, sound: Box<dyn SoundSource + Send>) -> SoundId {
        let sound_inner = SoundInner::new(sound);
        let id = sound_inner.id;
        self.sounds.push(sound_inner);
        id
    }

    /// If the sound was paused or stop, it will start playing again.
    /// Otherwise, does nothing.
    fn play(&mut self, id: SoundId) {
        for i in (self.playing..self.sounds.len()).rev() {
            if self.sounds[i].id == id {
                self.sounds.swap(self.playing, i);
                self.playing += 1;
                break;
            }
        }
    }

    /// If the sound is playing, it will pause. If play is called,
    /// this sound will continue from where it was when paused.
    /// If the sound is not playing, does nothing.
    fn pause(&mut self, id: SoundId) {
        for i in (0..self.playing).rev() {
            if self.sounds[i].id == id {
                self.playing -= 1;
                self.sounds.swap(self.playing, i);
                break;
            }
        }
    }

    /// If the sound is playing, it will pause and reset the song. When play is called,
    /// this sound will start from the begging.
    /// Even if the sound is not playing, it will reset the sound to the start.
    fn stop(&mut self, id: SoundId) {
        for i in (0..self.sounds.len()).rev() {
            if self.sounds[i].id == id {
                self.sounds[i].data.reset();
                if i < self.playing {
                    self.playing -= 1;
                    self.sounds.swap(self.playing, i);
                }
                break;
            }
        }
    }

    /// This reset the sound to the start, the sound being playing or not.
    fn reset(&mut self, id: SoundId) {
        for i in (0..self.sounds.len()).rev() {
            if self.sounds[i].id == id {
                self.sounds[i].data.reset();
                break;
            }
        }
    }

    /// Set the volume of the sound.
    fn set_volume(&mut self, id: SoundId, volume: f32) {
        for i in (0..self.sounds.len()).rev() {
            if self.sounds[i].id == id {
                self.sounds[i].volume = volume;
                break;
            }
        }
    }

    /// Set if the sound will repeat ever time it reach the end.
    fn set_loop(&mut self, id: SoundId, looping: bool) {
        for i in (0..self.sounds.len()).rev() {
            if self.sounds[i].id == id {
                self.sounds[i].looping = looping;
                break;
            }
        }
    }

    /// Mark the sound to be dropped after it reach the end.
    fn drop_sound(&mut self, id: SoundId) {
        for i in (0..self.sounds.len()).rev() {
            if self.sounds[i].id == id {
                self.sounds[i].drop = true;
                break;
            }
        }
    }
}
impl SoundSource for Mixer {
    fn channels(&self) -> u16 {
        self.channels
    }

    fn sample_rate(&self) -> u32 {
        self.sample_rate.0
    }

    fn reset(&mut self) {}

    fn write_samples(&mut self, buffer: &mut [i16]) -> usize {
        if self.playing == 0 {
            for b in buffer.iter_mut() {
                *b = 0;
            }
            return buffer.len();
        }

        let mut buf = vec![0; buffer.len()];
        let mut i = 0;
        while i < self.playing {
            let mut len = 0;
            loop {
                len += self.sounds[i].data.write_samples(&mut buf[len..]);
                if len < buffer.len() {
                    self.sounds[i].data.reset();
                    if self.sounds[i].looping {
                        continue;
                    }
                }
                break;
            }

            if (self.sounds[0].volume - 1.0).abs() < 1.0 / i16::max_value() as f32 {
                for i in 0..len {
                    buffer[i] = buffer[i].saturating_add(buf[i]);
                }
            } else {
                for i in 0..len {
                    buffer[i] =
                        buffer[i].saturating_add((buf[i] as f32 * self.sounds[0].volume) as i16);
                }
            }

            if len < buffer.len() {
                if self.sounds[i].drop {
                    let _ = self.sounds.swap_remove(i);
                }
                self.playing -= 1;
                if self.playing > 0 && self.playing < self.sounds.len() {
                    self.sounds.swap(i, self.playing);
                } else {
                    break;
                }
            } else {
                i += 1;
            }
        }

        buffer.len()
    }
}