aboutsummaryrefslogtreecommitdiffstats
path: root/mumd/src/audio
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2021-06-19 13:54:58 +0200
committerGustav Sörnäs <gustav@sornas.net>2021-06-19 13:54:58 +0200
commit023b69bca57d47b6b2800b7295d28ed2884096e5 (patch)
tree7ae93452d408ad5691862e6fde84cc314e044896 /mumd/src/audio
parent42275c61510f38318332a20c1ee41dbc17663b13 (diff)
downloadmum-023b69bca57d47b6b2800b7295d28ed2884096e5.tar.gz
move sound effect to new file
Diffstat (limited to 'mumd/src/audio')
-rw-r--r--mumd/src/audio/fallback_sfx.wavbin0 -> 32002 bytes
-rw-r--r--mumd/src/audio/sound_effects.rs116
2 files changed, 116 insertions, 0 deletions
diff --git a/mumd/src/audio/fallback_sfx.wav b/mumd/src/audio/fallback_sfx.wav
new file mode 100644
index 0000000..82ee4d4
--- /dev/null
+++ b/mumd/src/audio/fallback_sfx.wav
Binary files differ
diff --git a/mumd/src/audio/sound_effects.rs b/mumd/src/audio/sound_effects.rs
new file mode 100644
index 0000000..3d70bbb
--- /dev/null
+++ b/mumd/src/audio/sound_effects.rs
@@ -0,0 +1,116 @@
+use dasp_interpolate::linear::Linear;
+use dasp_signal::{self as signal, Signal};
+use log::warn;
+use mumlib::config::SoundEffect;
+use std::{borrow::Cow, collections::HashMap, convert::TryFrom, fs::File, io::Read};
+use strum::IntoEnumIterator;
+use strum_macros::EnumIter;
+
+use crate::audio::SAMPLE_RATE;
+
+#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, EnumIter)]
+pub enum NotificationEvents {
+ ServerConnect,
+ ServerDisconnect,
+ UserConnected,
+ UserDisconnected,
+ UserJoinedChannel,
+ UserLeftChannel,
+ Mute,
+ Unmute,
+ Deafen,
+ Undeafen,
+}
+
+impl TryFrom<&str> for NotificationEvents {
+ type Error = ();
+ fn try_from(s: &str) -> Result<Self, Self::Error> {
+ match s {
+ "server_connect" => Ok(NotificationEvents::ServerConnect),
+ "server_disconnect" => Ok(NotificationEvents::ServerDisconnect),
+ "user_connected" => Ok(NotificationEvents::UserConnected),
+ "user_disconnected" => Ok(NotificationEvents::UserDisconnected),
+ "user_joined_channel" => Ok(NotificationEvents::UserJoinedChannel),
+ "user_left_channel" => Ok(NotificationEvents::UserLeftChannel),
+ "mute" => Ok(NotificationEvents::Mute),
+ "unmute" => Ok(NotificationEvents::Unmute),
+ "deafen" => Ok(NotificationEvents::Deafen),
+ "undeafen" => Ok(NotificationEvents::Undeafen),
+ _ => {
+ warn!("Unknown notification event '{}' in config", s);
+ Err(())
+ }
+ }
+ }
+}
+
+pub fn load_sound_effects(overrides: &[SoundEffect], num_channels: usize) -> HashMap<NotificationEvents, Vec<f32>> {
+ let overrides: HashMap<_, _> = overrides
+ .iter()
+ .filter_map(|sound_effect| {
+ let (event, file) = (&sound_effect.event, &sound_effect.file);
+ if let Ok(event) = NotificationEvents::try_from(event.as_str()) {
+ Some((event, file))
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ NotificationEvents::iter()
+ .map(|event| {
+ let bytes = overrides
+ .get(&event)
+ .map(|file| get_sfx(file))
+ .unwrap_or_else(get_default_sfx);
+ let reader = hound::WavReader::new(bytes.as_ref()).unwrap();
+ let spec = reader.spec();
+ let samples = match spec.sample_format {
+ hound::SampleFormat::Float => reader
+ .into_samples::<f32>()
+ .map(|e| e.unwrap())
+ .collect::<Vec<_>>(),
+ hound::SampleFormat::Int => reader
+ .into_samples::<i16>()
+ .map(|e| cpal::Sample::to_f32(&e.unwrap()))
+ .collect::<Vec<_>>(),
+ };
+ let iter: Box<dyn Iterator<Item = f32>> = match spec.channels {
+ 1 => Box::new(samples.into_iter().flat_map(|e| vec![e, e])),
+ 2 => Box::new(samples.into_iter()),
+ _ => unimplemented!("Only mono and stereo sound is supported. See #80."),
+ };
+ let mut signal = signal::from_interleaved_samples_iter::<_, [f32; 2]>(iter);
+ let interp = Linear::new(Signal::next(&mut signal), Signal::next(&mut signal));
+ let samples = signal
+ .from_hz_to_hz(interp, spec.sample_rate as f64, SAMPLE_RATE as f64)
+ .until_exhausted()
+ // if the source audio is stereo and is being played as mono, discard the right audio
+ .flat_map(|e| {
+ if num_channels == 1 {
+ vec![e[0]]
+ } else {
+ e.to_vec()
+ }
+ })
+ .collect::<Vec<f32>>();
+ (event, samples)
+ })
+ .collect()
+}
+
+// moo
+fn get_sfx(file: &str) -> Cow<'static, [u8]> {
+ let mut buf: Vec<u8> = Vec::new();
+ if let Ok(mut file) = File::open(file) {
+ file.read_to_end(&mut buf).unwrap();
+ Cow::from(buf)
+ } else {
+ warn!("File not found: '{}'", file);
+ get_default_sfx()
+ }
+}
+
+fn get_default_sfx() -> Cow<'static, [u8]> {
+ Cow::from(include_bytes!("fallback_sfx.wav").as_ref())
+}