From 2bca20cf696b1148de876691fd8f488a7952f25c Mon Sep 17 00:00:00 2001 From: Louis Pearson Date: Thu, 5 Sep 2019 03:03:24 -0600 Subject: [PATCH] Get sound effects working --- voxygen/src/audio/channel.rs | 35 ++++++++++++++++++++--- voxygen/src/audio/mod.rs | 54 +++++++++++++++++++++++------------- voxygen/src/main.rs | 2 +- voxygen/src/menu/main/mod.rs | 2 -- 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index cf680177b9..ea918a54b0 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -1,4 +1,4 @@ -use rodio::{SpatialSink, Decoder, Device}; +use rodio::{SpatialSink, Decoder, Device, Source, Sample}; use std::io::BufReader; use std::fs::File; use crate::audio::fader::Fader; @@ -8,6 +8,7 @@ use vek::*; pub enum AudioType { Sfx, Music, + None, } #[derive(PartialEq, Clone, Copy)] @@ -27,10 +28,22 @@ pub struct Channel { state: ChannelState, fader: Fader, pub pos: Vec3::, - // sound_cache: Option<&SoundCache>, } +// TODO: Implement asynchronous loading impl Channel { + /// Create an empty channel for future use + pub fn new(device: &Device) -> Self { + Self { + id: 0, + sink: SpatialSink::new(device, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [-1.0, 0.0, 0.0]), + audio_type: AudioType::None, + state: ChannelState::Stopped, + fader: Fader::fade_in(0.0), + pos: Vec3::zero(), + } + } + pub fn music(id: usize, device: &Device, bufr: BufReader) -> Self { let sink = SpatialSink::new(device, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [-1.0, 0.0, 0.0]); let sound = Decoder::new(bufr).unwrap(); @@ -44,7 +57,6 @@ impl Channel { state: ChannelState::Playing, fader: Fader::fade_in(0.0), pos: Vec3::zero(), - // sound_cache: None, } } @@ -56,10 +68,20 @@ impl Channel { state: ChannelState::Playing, fader: Fader::fade_in(0.0), pos, - // sound_cache, } } + pub fn play(&mut self, source: S) + where + S: Source + Send + 'static, + S::Item: Sample, + S::Item: Send, + ::Item: std::fmt::Debug, + { + self.state = ChannelState::Playing; + self.sink.append(source); + } + pub fn is_done(&self) -> bool { self.sink.empty() || self.state == ChannelState::Stopped } @@ -73,6 +95,10 @@ impl Channel { self.id } + pub fn set_id(&mut self, new_id: usize) { + self.id = new_id; + } + pub fn get_audio_type(&self) -> AudioType { self.audio_type } @@ -102,6 +128,7 @@ impl Channel { ChannelState::Stopping => { self.fader.update(dt); self.sink.set_volume(self.fader.get_volume()); + if self.fader.is_finished() { self.state = ChannelState::Stopped; } diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index d130d30856..00c079fbb6 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -33,14 +33,21 @@ pub struct AudioFrontend { impl AudioFrontend { /// Construct with given device - pub fn new(device: String) -> Self { + pub fn new(device: String, channel_num: usize) -> Self { + let mut channels = Vec::with_capacity(channel_num); + let audio_device = get_device_raw(&device); + if let Some(audio_device) = &audio_device { + for i in (0..channel_num) { + channels.push(Channel::new(&audio_device)); + } + } Self { device: device.clone(), device_list: list_devices(), - audio_device: get_device_raw(device), + audio_device, sound_cache: SoundCache::new(), - channels: Vec::new(), - next_channel_id: 0, + channels: channels, + next_channel_id: 1, sfx_volume: 1.0, music_volume: 1.0, listener_pos: Vec3::zero(), @@ -58,7 +65,7 @@ impl AudioFrontend { audio_device: None, sound_cache: SoundCache::new(), channels: Vec::new(), - next_channel_id: 0, + next_channel_id: 1, sfx_volume: 1.0, music_volume: 1.0, listener_pos: Vec3::zero(), @@ -70,18 +77,15 @@ impl AudioFrontend { /// Maintain audio pub fn maintain(&mut self, dt: f32) { - let mut stopped_channels = Vec::::new(); for (i, channel) in self.channels.iter_mut().enumerate() { channel.update(dt); - if channel.is_done() { - stopped_channels.push(i); - } - } - for i in stopped_channels.iter().rev() { - self.channels.remove(*i); } } + pub fn get_channel(&mut self) -> Option<&mut Channel> { + self.channels.iter_mut().find(|c| c.is_done()) + } + /// Play specfied sound file. ///```ignore ///audio.play_sound("voxygen.audio.sfx.step"); @@ -96,15 +100,21 @@ impl AudioFrontend { (pos.y - self.listener_pos.y) * FALLOFF, (pos.z - self.listener_pos.z) * FALLOFF, ]; - let sink = SpatialSink::new(device, calc_pos, - self.listener_pos_left, - self.listener_pos_right); let sound = self.sound_cache.load_sound(sound); - sink.append(sound); + let left_ear = self.listener_pos_left; + let right_ear = self.listener_pos_right; - self.channels.push(Channel::sfx(id, sink, pos)); + if let Some(channel) = self.get_channel() { + channel.set_id(id); + channel.set_emitter_position(calc_pos); + channel.set_left_ear_position(left_ear); + channel.set_right_ear_position(right_ear); + channel.play(sound); + } else { + println!("No available channels!"); + } } id @@ -141,8 +151,12 @@ impl AudioFrontend { if let Some(device) = &self.audio_device { let file = assets::load_file(&sound, &["ogg"]).unwrap(); + let sound = Decoder::new(file).unwrap(); - self.channels.push(Channel::music(id, device, file)); + if let Some(channel) = self.get_channel() { + channel.set_id(id); + channel.play(sound); + } } id @@ -186,7 +200,7 @@ impl AudioFrontend { // TODO: figure out how badly this will break things when it is called pub fn set_device(&mut self, name: String) { self.device = name.clone(); - self.audio_device = get_device_raw(name); + self.audio_device = get_device_raw(&name); } } @@ -230,6 +244,6 @@ fn list_devices_raw() -> Vec { rodio::output_devices().collect() } -fn get_device_raw(device: String) -> Option { +fn get_device_raw(device: &str) -> Option { rodio::output_devices().find(|d| d.name() == device) } diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 49d6c7ac7d..07e7f26e0d 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -114,7 +114,7 @@ fn main() { None => audio::get_default_device(), }; let audio = if settings.audio.audio_on { - AudioFrontend::new(audio_device) + AudioFrontend::new(audio_device, 16) } else { AudioFrontend::no_audio() }; diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs index 04f7c2a111..884f136de1 100644 --- a/voxygen/src/menu/main/mod.rs +++ b/voxygen/src/menu/main/mod.rs @@ -34,8 +34,6 @@ impl PlayState for MainMenuState { // Used for client creation. let mut client_init: Option = None; - let music = global_state.audio.play_music("voxygen.audio.soundtrack.veloren_title_tune-3".to_string()); - loop { // Handle window events. for event in global_state.window.fetch_events() {