diff options
| author | Gustav Sörnäs <gustav@sornas.net> | 2021-06-25 22:14:45 +0200 |
|---|---|---|
| committer | Gustav Sörnäs <gustav@sornas.net> | 2021-06-26 07:55:51 +0200 |
| commit | 3e4c93941a3136ddbb954c141b51c5ac486d3c5f (patch) | |
| tree | aaa63650e2cb7fe2a70274ecd14a09b83a4edefb | |
| parent | 49eb4ed9fe444eec57e7ebd89f127966c00174c0 (diff) | |
| download | mum-3e4c93941a3136ddbb954c141b51c5ac486d3c5f.tar.gz | |
move hashmaps to sound effects
| -rw-r--r-- | mumd/src/audio.rs | 35 | ||||
| -rw-r--r-- | mumd/src/audio/sound_effects.rs | 73 | ||||
| -rw-r--r-- | mumd/src/state.rs | 2 |
3 files changed, 60 insertions, 50 deletions
diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index 4b64866..c51e7a5 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -13,20 +13,17 @@ use crate::state::StatePhase; use futures_util::stream::Stream; use futures_util::StreamExt; -use log::warn; use mumble_protocol::voice::{VoicePacket, VoicePacketPayload}; use mumble_protocol::Serverbound; use mumlib::config::SoundEffect; use std::collections::{hash_map::Entry, HashMap}; -use std::convert::TryFrom; use std::fmt::Debug; -use std::path::PathBuf; use std::sync::{Arc, Mutex}; use tokio::sync::watch; use self::input::{AudioInputDevice, DefaultAudioInputDevice}; use self::output::{AudioOutputDevice, ClientStream, DefaultAudioOutputDevice}; -use self::sound_effects::{NotificationEvent, SoundEffects, SoundEffectId}; +use self::sound_effects::{NotificationEvent, SoundEffects}; /// The sample rate used internally. const SAMPLE_RATE: u32 = 48000; @@ -104,11 +101,8 @@ pub struct AudioOutput { /// Shared with [DefaultAudioOutputDevice]. client_streams: Arc<Mutex<ClientStream>>, - /// Opened sound effects. + /// Loaded sound effects. sound_effects: SoundEffects, - - /// Which file should be played on specific events. - sound_effect_events: HashMap<NotificationEvent, SoundEffectId>, } impl AudioOutput { @@ -126,25 +120,17 @@ impl AudioOutput { user_volumes, client_streams, sound_effects: SoundEffects::new(num_channels), - sound_effect_events: HashMap::new(), }; - output.load_sound_effects(&[]); + output.set_sound_effects(&[]); Ok(output) } - pub fn load_sound_effects(&mut self, sound_effects: &[SoundEffect]) { + /// Sets sound effects that should be played on specific events. + pub fn set_sound_effects(&mut self, sound_effects: &[SoundEffect]) { for effect in sound_effects { - if let Ok(event) = NotificationEvent::try_from(effect.event.as_str()) { - let file = PathBuf::from(&effect.file); - if let Ok(id) = self.sound_effects.open(&file) { - self.sound_effect_events.insert(event, id); - } else { - warn!("Invalid sound data in '{}'", &effect.file); - } - } else { - warn!("Unknown sound effect '{}'", &effect.event); - } + self.sound_effects.set_sound_effect(&effect); } + self.sound_effects.load_unloaded_files(); } /// Decodes a voice packet. @@ -191,12 +177,7 @@ impl AudioOutput { /// Queues a sound effect. pub fn play_effect(&self, effect: NotificationEvent) { - let id = self - .sound_effect_events - .get(&effect) - .cloned() - .unwrap_or_else(SoundEffects::default_sound_effect); - let samples = &self.sound_effects[id]; + let samples = self.sound_effects.get_samples(&effect); self.client_streams.lock().unwrap().add_sound_effect(samples); } } diff --git a/mumd/src/audio/sound_effects.rs b/mumd/src/audio/sound_effects.rs index df8dbba..0cf6816 100644 --- a/mumd/src/audio/sound_effects.rs +++ b/mumd/src/audio/sound_effects.rs @@ -1,61 +1,90 @@ use dasp_interpolate::linear::Linear; use dasp_signal::{self as signal, Signal}; +use mumlib::config::SoundEffect; use std::borrow::Cow; +use std::collections::HashMap; use std::convert::TryFrom; use std::fmt; use std::fs::File; #[cfg(feature = "ogg")] use std::io::Cursor; use std::io::Read; -use std::ops::Index; -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::audio::SAMPLE_RATE; -#[derive(Debug, Clone, Copy)] -pub struct SoundEffectId(usize); - pub struct SoundEffects { - data: Vec<Vec<f32>>, + default_sound_effect: Vec<f32>, + // None -> invalid data, use default sound effect + opened_files: HashMap<PathBuf, Option<Vec<f32>>>, + + events: HashMap<NotificationEvent, PathBuf>, num_channels: usize, } impl fmt::Debug for SoundEffects { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let opened_files: Vec<_> = self.opened_files.keys().collect(); f.debug_struct("SoundEffects") + .field("default_sound_effect", &"..") + .field("opened_files", &opened_files) .field("num_channels", &self.num_channels) - .finish_non_exhaustive() + .field("events", &self.events) + .finish() } } impl SoundEffects { pub fn new(num_channels: usize) -> Self { SoundEffects { - data: vec![unpack_audio(get_default_sfx(), AudioFileKind::Wav).unwrap().0], + default_sound_effect: unpack_audio(get_default_sfx(), AudioFileKind::Wav).unwrap().0, + opened_files: HashMap::new(), + events: HashMap::new(), num_channels, } } - pub fn open<P: AsRef<Path>>(&mut self, path: &P) -> Result<SoundEffectId, ()> { - open_and_unpack_audio(&path.as_ref(), self.num_channels) - .map(|samples| { - let idx = SoundEffectId(self.data.len()); - self.data.push(samples); - idx - }) + pub fn load_file(&mut self, path: PathBuf) { + let samples = open_and_unpack_audio(&path, self.num_channels).ok(); + self.opened_files.insert(path, samples); } - pub fn default_sound_effect() -> SoundEffectId { - SoundEffectId(0) + pub fn set_sound_effect(&mut self, sound_effect: &SoundEffect) { + if let Ok(event) = NotificationEvent::try_from(sound_effect.event.as_str()) { + let path = PathBuf::from(&sound_effect.file); + self.events.insert(event, path); + } + } + + pub fn load_unloaded_files(&mut self) { + let mut to_load = Vec::new(); + for path in self.events.values() { + if !self.opened_files.contains_key(path) { + to_load.push(path.to_path_buf()); + } + } + for path in to_load { + self.load_file(path); + } } -} -impl Index<SoundEffectId> for SoundEffects { - type Output = [f32]; + pub fn get_samples(&self, event: &NotificationEvent) -> &[f32] { + self + .events + .get(event) + .and_then(|path| self.opened_files.get(path)) + // Here we have an Option<&Option<Vec<f32>>>, + // so we do None => None + // Some(&None) => None + // Some(&Some(v)) => Some(&v) + .and_then(|o| o.as_ref()) + .unwrap_or(&self.default_sound_effect) + } - fn index(&self, index: SoundEffectId) -> &Self::Output { - &self.data[index.0] + pub fn clear(&mut self) { + self.events.clear(); + self.opened_files.clear(); } } diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 271bf54..04bdc5d 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -305,7 +305,7 @@ impl State { self.audio_output.set_volume(output_volume); } if let Some(sound_effects) = &self.config.audio.sound_effects { - self.audio_output.load_sound_effects(sound_effects); + self.audio_output.set_sound_effects(sound_effects); } } |
