2020-06-11 12:53:24 +00:00
|
|
|
//! Handles caching and retrieval of decoded `.wav` sfx sound data, eliminating
|
|
|
|
//! the need to decode files on each playback
|
2019-09-05 09:11:18 +00:00
|
|
|
use common::assets;
|
2019-09-01 23:00:12 +00:00
|
|
|
use hashbrown::HashMap;
|
2020-02-01 20:39:39 +00:00
|
|
|
use std::{convert::AsRef, io, io::Read, sync::Arc};
|
2020-06-21 10:22:26 +00:00
|
|
|
use tracing::warn;
|
2019-09-01 23:00:12 +00:00
|
|
|
|
|
|
|
// Implementation of sound taken from this github issue:
|
|
|
|
// https://github.com/RustAudio/rodio/issues/141
|
2019-09-05 09:11:18 +00:00
|
|
|
pub struct Sound(Arc<Vec<u8>>);
|
2019-09-01 23:00:12 +00:00
|
|
|
|
|
|
|
impl AsRef<[u8]> for Sound {
|
2020-02-01 20:39:39 +00:00
|
|
|
fn as_ref(&self) -> &[u8] { &self.0 }
|
2019-09-01 23:00:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-11 12:53:24 +00:00
|
|
|
/// Wrapper for decoded audio data
|
2019-09-01 23:00:12 +00:00
|
|
|
impl Sound {
|
|
|
|
pub fn load(filename: &str) -> Result<Sound, assets::Error> {
|
|
|
|
let mut file = assets::load_file(filename, &["wav"])?;
|
|
|
|
let mut buf = Vec::new();
|
|
|
|
file.read_to_end(&mut buf)?;
|
|
|
|
Ok(Sound(Arc::new(buf)))
|
|
|
|
}
|
|
|
|
|
2020-09-27 16:20:40 +00:00
|
|
|
pub fn cursor(&self) -> io::Cursor<Sound> { io::Cursor::new(Sound(Arc::clone(&self.0))) }
|
2019-09-01 23:00:12 +00:00
|
|
|
|
|
|
|
pub fn decoder(&self) -> rodio::Decoder<io::Cursor<Sound>> {
|
|
|
|
rodio::Decoder::new(self.cursor()).unwrap()
|
|
|
|
}
|
2020-06-11 12:53:24 +00:00
|
|
|
|
|
|
|
/// Returns a `Sound` containing empty .wav data. This intentionally doesn't
|
|
|
|
/// load from the filesystem so we have a reliable fallback when there
|
|
|
|
/// is a failure to read a file.
|
|
|
|
///
|
|
|
|
/// The data below is the result of passing a very short, silent .wav file
|
|
|
|
/// to `Sound::load()`.
|
|
|
|
pub fn empty() -> Sound {
|
|
|
|
Sound(Arc::new(vec![
|
|
|
|
82, 73, 70, 70, 40, 0, 0, 0, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 1, 0, 1,
|
|
|
|
0, 68, 172, 0, 0, 136, 88, 1, 0, 2, 0, 16, 0, 100, 97, 116, 97, 4, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
]))
|
|
|
|
}
|
2019-09-01 23:00:12 +00:00
|
|
|
}
|
|
|
|
|
2020-06-11 12:53:24 +00:00
|
|
|
#[derive(Default)]
|
2019-09-01 23:00:12 +00:00
|
|
|
pub struct SoundCache {
|
|
|
|
sounds: HashMap<String, Sound>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SoundCache {
|
2019-09-06 10:36:42 +00:00
|
|
|
pub fn load_sound(&mut self, name: &str) -> rodio::Decoder<io::Cursor<Sound>> {
|
2019-09-01 23:00:12 +00:00
|
|
|
self.sounds
|
2019-09-06 10:36:42 +00:00
|
|
|
.entry(name.to_string())
|
2020-06-11 12:53:24 +00:00
|
|
|
.or_insert_with(|| {
|
|
|
|
Sound::load(name).unwrap_or_else(|_| {
|
2020-06-21 21:47:49 +00:00
|
|
|
warn!(?name, "SoundCache: Failed to load sound");
|
2020-06-11 12:53:24 +00:00
|
|
|
|
|
|
|
Sound::empty()
|
|
|
|
})
|
|
|
|
})
|
2019-09-01 23:00:12 +00:00
|
|
|
.decoder()
|
|
|
|
}
|
|
|
|
}
|