aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2021-06-25 22:14:45 +0200
committerGustav Sörnäs <gustav@sornas.net>2021-06-26 07:55:51 +0200
commit3e4c93941a3136ddbb954c141b51c5ac486d3c5f (patch)
treeaaa63650e2cb7fe2a70274ecd14a09b83a4edefb
parent49eb4ed9fe444eec57e7ebd89f127966c00174c0 (diff)
downloadmum-3e4c93941a3136ddbb954c141b51c5ac486d3c5f.tar.gz
move hashmaps to sound effects
-rw-r--r--mumd/src/audio.rs35
-rw-r--r--mumd/src/audio/sound_effects.rs73
-rw-r--r--mumd/src/state.rs2
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);
}
}