diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index bd33471d10..68a7cab77d 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -51,7 +51,7 @@ impl AudioFrontend { device: device.clone(), device_list: list_devices(), audio_device, - sound_cache: SoundCache::new(), + sound_cache: SoundCache::default(), music_channels: Vec::new(), sfx_channels, sfx_volume: 1.0, @@ -69,7 +69,7 @@ impl AudioFrontend { device: "none".to_string(), device_list: Vec::new(), audio_device: None, - sound_cache: SoundCache::new(), + sound_cache: SoundCache::default(), music_channels: Vec::new(), sfx_channels: Vec::new(), sfx_volume: 1.0, diff --git a/voxygen/src/audio/soundcache.rs b/voxygen/src/audio/soundcache.rs index e9e499affc..f7672720dc 100644 --- a/voxygen/src/audio/soundcache.rs +++ b/voxygen/src/audio/soundcache.rs @@ -1,3 +1,5 @@ +//! Handles caching and retrieval of decoded `.wav` sfx sound data, eliminating +//! the need to decode files on each playback use common::assets; use hashbrown::HashMap; use std::{convert::AsRef, io, io::Read, sync::Arc}; @@ -10,6 +12,7 @@ impl AsRef<[u8]> for Sound { fn as_ref(&self) -> &[u8] { &self.0 } } +/// Wrapper for decoded audio data impl Sound { pub fn load(filename: &str) -> Result { let mut file = assets::load_file(filename, &["wav"])?; @@ -23,24 +26,37 @@ impl Sound { pub fn decoder(&self) -> rodio::Decoder> { rodio::Decoder::new(self.cursor()).unwrap() } + + /// 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, + ])) + } } +#[derive(Default)] pub struct SoundCache { sounds: HashMap, } impl SoundCache { - #[allow(clippy::new_without_default)] // TODO: Pending review in #587 - pub fn new() -> Self { - Self { - sounds: HashMap::new(), - } - } - pub fn load_sound(&mut self, name: &str) -> rodio::Decoder> { self.sounds .entry(name.to_string()) - .or_insert(Sound::load(name).unwrap()) + .or_insert_with(|| { + Sound::load(name).unwrap_or_else(|_| { + log::warn!("SoundCache: Failed to load sound: {}", name); + + Sound::empty() + }) + }) .decoder() } }