From 46d3f6f6d259be24e7c8b5806671f9a69f237c4d Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Fri, 16 Oct 2020 16:52:09 -0700 Subject: [PATCH 01/37] Initial biome specific music and ambient sound channel --- assets/voxygen/audio/ambient.ron | 22 ++++ assets/voxygen/audio/soundtrack.ron | 34 +++--- common/src/terrain/biome.rs | 2 +- voxygen/src/audio/ambient.rs | 183 ++++++++++++++++++++++++++++ voxygen/src/audio/channel.rs | 105 ++++++++++++++++ voxygen/src/audio/mod.rs | 70 ++++++++++- voxygen/src/audio/music.rs | 24 +++- voxygen/src/scene/mod.rs | 8 +- voxygen/src/session.rs | 1 + 9 files changed, 424 insertions(+), 25 deletions(-) create mode 100644 assets/voxygen/audio/ambient.ron create mode 100644 voxygen/src/audio/ambient.rs diff --git a/assets/voxygen/audio/ambient.ron b/assets/voxygen/audio/ambient.ron new file mode 100644 index 0000000000..48cd6454c2 --- /dev/null +++ b/assets/voxygen/audio/ambient.ron @@ -0,0 +1,22 @@ +// TODO: Add an ambient-soundtrack that runs independently from the musical soundtrack + +( + tracks: [ + ( + title: "Forest Day", // Ambience Track + path: "voxygen.audio.ambient.forest_day", + length: 629.0, + timing: Some(Night), + biome: Some(Forest), + artist: "https://www.youtube.com/watch?v=FwVTkB-BIvM", + ), + ( + title: "Forest Morning", // Ambience Track + path: "voxygen.audio.ambient.forest_morning", + length: 600.0, + timing: Some(Day), + biome: Some(Forest), + artist: "https://www.youtube.com/watch?v=eq4nfIdK6C4", + ), + ] +) diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index 775d63a4e8..7f628765a3 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -3,18 +3,12 @@ ( tracks: [ - ( - title: "Forest Day", // Ambience Track - path: "voxygen.audio.ambient.forest_day", - length: 629.0, - timing: Some(Day), - artist: "https://www.youtube.com/watch?v=FwVTkB-BIvM", - ), ( title: "A Solemn Quest", path: "voxygen.audio.soundtrack.a_solemn_quest", length: 206.0, timing: Some(Night), + biome: Some(Grassland), artist: "Eden", ), ( @@ -22,6 +16,7 @@ path: "voxygen.audio.soundtrack.into_the_dark_forest", length: 184.0, timing: Some(Night), + biome: Some(Snowlands), artist: "Aeronic", ), ( @@ -29,6 +24,7 @@ path: "voxygen.audio.soundtrack.field_grazing", length: 154.0, timing: Some(Day), + biome: Some(Grassland), artist: "Aeronic", ), ( @@ -36,20 +32,23 @@ path: "voxygen.audio.soundtrack.wandering_voices", length: 137.0, timing: Some(Night), + biome: Some(Snowlands), artist: "Aeronic", ), - /*( + ( title: "Snowtop Volume", //Snow Region path: "voxygen.audio.soundtrack.snowtop_volume", length: 89.0, timing: Some(Day), + biome: Some(Snowlands), artist: "Aeronic", - ),*/ + ), ( title: "Mineral Deposits", path: "voxygen.audio.soundtrack.mineral_deposits", length: 148.0, timing: Some(Day), + biome: Some(Snowlands), artist: "Aeronic", ), ( @@ -57,6 +56,7 @@ path: "voxygen.audio.soundtrack.moonbeams", length: 158.0, timing: Some(Night), + biome: Some(Snowlands), artist: "Aeronic", ), ( @@ -64,6 +64,7 @@ path: "voxygen.audio.soundtrack.serene_meadows", length: 173.0, timing: Some(Night), + biome: Some(Snowlands), artist: "Aeronic", ), /*( @@ -71,6 +72,7 @@ path: "voxygen.audio.soundtrack.rest_assured", length: 185.0, timing: Some(Day), + biome: Some(Snowlands), artist: "badbbad", ),*/ ( @@ -78,6 +80,7 @@ path: "voxygen.audio.soundtrack.just_the_beginning", length: 188.0, timing: Some(Day), + biome: Some(Snowlands), artist: "badbbad", ), ( @@ -85,6 +88,7 @@ path: "voxygen.audio.soundtrack.campfire_stories", length: 100.0, timing: Some(Night), + biome: Some(Snowlands), artist: "badbbad", ), ( @@ -92,6 +96,7 @@ path: "voxygen.audio.soundtrack.limits", length: 203.0, timing: Some(Night), + biome: Some(Snowlands), artist: "badbbad", ), /*( // Dungeon @@ -99,6 +104,7 @@ path: "voxygen.audio.soundtrack.down_the_rabbit_hole", length: 244.0, timing: Some(Night), + biome: Some(Snowlands), artist: "badbbad", ),*/ ( @@ -106,14 +112,8 @@ path: "voxygen.audio.soundtrack.between_the_fairies", length: 175.0, timing: Some(Night), + biome: Some(Snowlands), artist: "badbbad", ), - ( - title: "Forest Morning", // Ambience Track - path: "voxygen.audio.ambient.forest_morning", - length: 600.0, - timing: Some(Day), - artist: "https://www.youtube.com/watch?v=eq4nfIdK6C4", - ), ] -) \ No newline at end of file +) diff --git a/common/src/terrain/biome.rs b/common/src/terrain/biome.rs index 8e196d4e4b..ecb9e2cf27 100644 --- a/common/src/terrain/biome.rs +++ b/common/src/terrain/biome.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] pub enum BiomeKind { Void, Grassland, diff --git a/voxygen/src/audio/ambient.rs b/voxygen/src/audio/ambient.rs new file mode 100644 index 0000000000..d5e283e291 --- /dev/null +++ b/voxygen/src/audio/ambient.rs @@ -0,0 +1,183 @@ +//! Handles ambient sound playback and transitions +//! +//! Game ambient sound is controlled though a configuration file found in the +//! source at `/assets/voxygen/audio/ambient.ron`. Each track enabled in game +//! has a configuration corresponding to the +//! [`SoundtrackItem`](struct.SoundtrackItem.html) format, as well as the +//! corresponding `.ogg` file in the `/assets/voxygen/audio/soundtrack/` +//! directory. +//! +//! If there are errors while reading or deserialising the configuration file, a +//! warning is logged and music will be disabled. +//! +//! ## Adding new ambient sound +//! +//! To add a new item, append the details to the audio configuration file, and +//! add the audio file (in `.ogg` format) to the assets directory. +//! +//! The `length` should be provided in seconds. This allows us to know when to +//! transition to another track, without having to spend time determining track +//! length programmatically. +//! +//! An example of a new night time track: +//! ```text +//! ( +//! title: "Sleepy Song", +//! path: "voxygen.audio.soundtrack.sleepy", +//! length: 400.0, +//! timing: Some(Night), +//! biome: Some(Forest), +//! artist: "Elvis", +//! ), +//! ``` +//! +//! Before sending an MR for your new track item: +//! - Be conscious of the file size for your new track. Assets contribute to +//! download sizes +//! - Ensure that the track is mastered to a volume proportionate to other music +//! tracks +//! - If you are not the author of the track, ensure that the song's licensing +//! permits usage of the track for non-commercial use +use crate::audio::AudioFrontend; +use client::Client; +use common::{assets, state::State, terrain::BiomeKind}; +use rand::{seq::IteratorRandom, thread_rng}; +use serde::Deserialize; +use std::time::Instant; +use tracing::warn; + +const DAY_START_SECONDS: u32 = 28800; // 8:00 +const DAY_END_SECONDS: u32 = 70200; // 19:30 + +#[derive(Debug, Default, Deserialize)] +struct AmbientSoundtrackCollection { + tracks: Vec, +} + +/// Configuration for a single music track in the soundtrack +#[derive(Debug, Deserialize)] +pub struct AmbientSoundtrackItem { + title: String, + path: String, + /// Length of the track in seconds + length: f64, + /// Whether this track should play during day or night + timing: Option, + biome: Option, +} + +/// Allows control over when a track should play based on in-game time of day +#[derive(Debug, Deserialize, PartialEq)] +enum DayPeriod { + /// 8:00 AM to 7:30 PM + Day, + /// 7:31 PM to 6:59 AM + Night, +} + +/// Provides methods to control music playback +pub struct AmbientMgr { + ambient_soundtrack: AmbientSoundtrackCollection, + began_playing: Instant, + next_track_change: f64, + /// The title of the last track played. Used to prevent a track + /// being played twice in a row + last_track: String, +} + +impl AmbientMgr { + #[allow(clippy::new_without_default)] // TODO: Pending review in #587 + pub fn new() -> Self { + Self { + ambient_soundtrack: Self::load_ambient_soundtrack_items(), + began_playing: Instant::now(), + next_track_change: 0.0, + last_track: String::from("None"), + } + } + + /// Checks whether the previous track has completed. If so, sends a + /// request to play the next (random) track + pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { + if audio.music_enabled() + && !self.ambient_soundtrack.tracks.is_empty() + && self.began_playing.elapsed().as_secs_f64() > self.next_track_change + { + self.play_random_track(audio, state, client); + } + } + + fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { + const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; + + let game_time = (state.get_time_of_day() as u64 % 86400) as u32; + let current_period_of_day = Self::get_current_day_period(game_time); + let current_biome = Self::get_current_biome(client); + println!("Ambient Current biome: {:?}", current_biome); + let mut rng = thread_rng(); + + let maybe_track = self + .ambient_soundtrack + .tracks + .iter() + .filter(|track| { + !track.title.eq(&self.last_track) + && match &track.timing { + Some(period_of_day) => period_of_day == ¤t_period_of_day, + None => true, + } + }) + .filter(|track| match &track.biome { + Some(biome) => biome == ¤t_biome, + None => true, + }) + .choose(&mut rng); + + if let Some(track) = maybe_track { + self.last_track = String::from(&track.title); + self.began_playing = Instant::now(); + self.next_track_change = track.length + SILENCE_BETWEEN_TRACKS_SECONDS; + + audio.play_exploration_ambient(&track.path); + } + } + + fn get_current_day_period(game_time: u32) -> DayPeriod { + if game_time > DAY_START_SECONDS && game_time < DAY_END_SECONDS { + DayPeriod::Day + } else { + DayPeriod::Night + } + } + + fn get_current_biome(client: &Client) -> BiomeKind { + match client.current_chunk() { + Some(chunk) => chunk.meta().biome(), + _ => BiomeKind::Void, + } + } + + fn load_ambient_soundtrack_items() -> AmbientSoundtrackCollection { + match assets::load_file("voxygen.audio.ambient", &["ron"]) { + Ok(file) => match ron::de::from_reader(file) { + Ok(config) => config, + Err(error) => { + warn!( + "Error parsing music config file, music will not be available: {}", + format!("{:#?}", error) + ); + + AmbientSoundtrackCollection::default() + }, + }, + Err(error) => { + warn!( + "Error reading music config file, music will not be available: {}", + format!("{:#?}", error) + ); + + AmbientSoundtrackCollection::default() + }, + } + } +} diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index 3bbdd70672..5780dc7ac8 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -134,6 +134,111 @@ impl MusicChannel { } } +/// Each `AmbientChannel` has a `AmbientChannelTag` which help us determine when +/// we should transition between two types of in-game music. For example, we +/// transition between `TitleMusic` and `Exploration` when a player enters the +/// world by crossfading over a slow duration. In the future, transitions in the +/// world such as `Exploration` -> `BossBattle` would transition more rapidly. +#[derive(PartialEq, Clone, Copy)] +pub enum AmbientChannelTag { + TitleMusic, + Exploration, +} + +/// An AmbientChannel uses a non-positional audio sink designed to play ambient +/// sound which is always heard at the player's position. +/// +/// See also: [`Rodio::Sink`](https://docs.rs/rodio/0.11.0/rodio/struct.Sink.html) +pub struct AmbientChannel { + tag: AmbientChannelTag, + sink: Sink, + state: ChannelState, + fader: Fader, +} +impl AmbientChannel { + pub fn new(device: &Device) -> Self { + Self { + sink: Sink::new(device), + tag: AmbientChannelTag::TitleMusic, + state: ChannelState::Stopped, + fader: Fader::default(), + } + } + + // Play an ambient track item on this channel. If the channel has an existing + // track playing, the new sounds will be appended and played once they + // complete. Otherwise it will begin playing immediately. + pub fn play(&mut self, source: S, tag: AmbientChannelTag) + where + S: Source + Send + 'static, + S::Item: Sample, + S::Item: Send, + ::Item: std::fmt::Debug, + { + self.tag = tag; + if !self.sink.len() > 0 { + self.sink.append(source); + } + + self.state = if !self.fader.is_finished() { + ChannelState::Fading + } else { + ChannelState::Playing + }; + } + + /// Set the volume of the current channel. If the channel is currently + /// fading, the volume of the fader is updated to this value. + pub fn set_volume(&mut self, volume: f32) { + if !self.fader.is_finished() { + self.fader.update_target_volume(volume); + } else { + self.sink.set_volume(volume); + } + } + + /// Set a fader for the channel. If a fader exists already, it is replaced. + /// If the channel has not begun playing, and the fader is set to fade in, + /// we set the volume of the channel to the initial volume of the fader so + /// that the volumes match when playing begins. + pub fn set_fader(&mut self, fader: Fader) { + self.fader = fader; + self.state = ChannelState::Fading; + + if self.state == ChannelState::Stopped && fader.direction() == FadeDirection::In { + self.sink.set_volume(fader.get_volume()); + } + } + + /// Returns true if either the channels sink reports itself as empty (no + /// more sounds in the queue) or we have forcibly set the channels state to + /// the 'Stopped' state + pub fn is_done(&self) -> bool { self.sink.empty() || self.state == ChannelState::Stopped } + + pub fn get_tag(&self) -> AmbientChannelTag { self.tag } + + /// Maintain the fader attached to this channel. If the channel is not + /// fading, no action is taken. + pub fn maintain(&mut self, dt: f32) { + if self.state == ChannelState::Fading { + self.fader.update(dt); + self.sink.set_volume(self.fader.get_volume()); + + if self.fader.is_finished() { + match self.fader.direction() { + FadeDirection::Out => { + self.state = ChannelState::Stopped; + self.sink.stop(); + }, + FadeDirection::In => { + self.state = ChannelState::Playing; + }, + } + } + } + } +} + /// An SfxChannel uses a positional audio sink, and is designed for short-lived /// audio which can be spatially controlled, but does not need control over /// playback or fading/transitions diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 6e38549b4d..9f065bc577 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -1,12 +1,13 @@ //! Handles audio device detection and playback of sound effects and music +pub mod ambient; pub mod channel; pub mod fader; pub mod music; pub mod sfx; pub mod soundcache; -use channel::{MusicChannel, MusicChannelTag, SfxChannel}; +use channel::{AmbientChannel, AmbientChannelTag, MusicChannel, MusicChannelTag, SfxChannel}; use fader::Fader; use soundcache::SoundCache; use std::time::Duration; @@ -38,9 +39,11 @@ pub struct AudioFrontend { music_channels: Vec, sfx_channels: Vec, + ambient_channels: Vec, sfx_volume: f32, music_volume: f32, + ambient_volume: f32, listener: Listener, } @@ -61,9 +64,11 @@ impl AudioFrontend { audio_device, sound_cache: SoundCache::default(), music_channels: Vec::new(), + ambient_channels: Vec::new(), sfx_channels, sfx_volume: 1.0, music_volume: 1.0, + ambient_volume: 1.0, listener: Listener::default(), } @@ -77,9 +82,11 @@ impl AudioFrontend { audio_device: None, sound_cache: SoundCache::default(), music_channels: Vec::new(), + ambient_channels: Vec::new(), sfx_channels: Vec::new(), sfx_volume: 1.0, music_volume: 1.0, + ambient_volume: 1.0, listener: Listener::default(), } } @@ -87,10 +94,15 @@ impl AudioFrontend { /// Drop any unused music channels, and update their faders pub fn maintain(&mut self, dt: Duration) { self.music_channels.retain(|c| !c.is_done()); + self.ambient_channels.retain(|c| !c.is_done()); for channel in self.music_channels.iter_mut() { channel.maintain(dt); } + + for channel in self.ambient_channels.iter_mut() { + channel.maintain(dt); + } } fn get_sfx_channel(&mut self) -> Option<&mut SfxChannel> { @@ -141,6 +153,35 @@ impl AudioFrontend { self.music_channels.last_mut() } + fn get_ambient_channel( + &mut self, + next_channel_tag: AmbientChannelTag, + ) -> Option<&mut AmbientChannel> { + if let Some(audio_device) = &self.audio_device { + if self.ambient_channels.is_empty() { + let mut next_ambient_channel = AmbientChannel::new(&audio_device); + next_ambient_channel.set_volume(self.ambient_volume); + + self.ambient_channels.push(next_ambient_channel); + } else { + let existing_channel = self.ambient_channels.last_mut()?; + + if existing_channel.get_tag() != next_channel_tag { + // Fade the existing channel out. It will be removed when the fade completes. + existing_channel.set_fader(Fader::fade_out(2.0, self.ambient_volume)); + + let mut next_ambient_channel = AmbientChannel::new(&audio_device); + + next_ambient_channel.set_fader(Fader::fade_in(12.0, self.ambient_volume)); + + self.ambient_channels.push(next_ambient_channel); + } + } + } + + self.ambient_channels.last_mut() + } + /// Play (once) an sfx file by file path at the give position and volume pub fn play_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { if self.audio_device.is_some() { @@ -167,6 +208,15 @@ impl AudioFrontend { } } + fn play_ambient(&mut self, sound: &str, channel_tag: AmbientChannelTag) { + if let Some(channel) = self.get_ambient_channel(channel_tag) { + let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); + let sound = Decoder::new(file).expect("Failed to decode sound"); + + channel.play(sound, channel_tag); + } + } + pub fn set_listener_pos(&mut self, pos: Vec3, ori: Vec3) { self.listener.pos = pos; self.listener.ori = ori.normalized(); @@ -199,14 +249,24 @@ impl AudioFrontend { } } + pub fn play_exploration_ambient(&mut self, item: &str) { + if self.ambient_enabled() { + self.play_ambient(item, AmbientChannelTag::Exploration) + } + } + pub fn get_sfx_volume(&self) -> f32 { self.sfx_volume } pub fn get_music_volume(&self) -> f32 { self.music_volume } + pub fn get_ambient_volume(&self) -> f32 { self.ambient_volume } + pub fn sfx_enabled(&self) -> bool { self.sfx_volume > 0.0 } pub fn music_enabled(&self) -> bool { self.music_volume > 0.0 } + pub fn ambient_enabled(&self) -> bool { self.ambient_volume > 0.0 } + pub fn set_sfx_volume(&mut self, sfx_volume: f32) { self.sfx_volume = sfx_volume; @@ -223,6 +283,14 @@ impl AudioFrontend { } } + pub fn set_ambient_volume(&mut self, ambient_volume: f32) { + self.ambient_volume = ambient_volume; + + for channel in self.ambient_channels.iter_mut() { + channel.set_volume(ambient_volume); + } + } + // 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(); diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 643b4826b5..5f11fb9c7d 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -26,6 +26,7 @@ //! path: "voxygen.audio.soundtrack.sleepy", //! length: 400.0, //! timing: Some(Night), +//! biome: Some(Forest), //! artist: "Elvis", //! ), //! ``` @@ -38,7 +39,8 @@ //! - If you are not the author of the track, ensure that the song's licensing //! permits usage of the track for non-commercial use use crate::audio::AudioFrontend; -use common::{assets, state::State}; +use client::Client; +use common::{assets, state::State, terrain::BiomeKind}; use rand::{seq::IteratorRandom, thread_rng}; use serde::Deserialize; use std::time::Instant; @@ -61,6 +63,7 @@ pub struct SoundtrackItem { length: f64, /// Whether this track should play during day or night timing: Option, + biome: Option, } /// Allows control over when a track should play based on in-game time of day @@ -95,20 +98,22 @@ impl MusicMgr { /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track - pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State) { + pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { if audio.music_enabled() && !self.soundtrack.tracks.is_empty() && self.began_playing.elapsed().as_secs_f64() > self.next_track_change { - self.play_random_track(audio, state); + self.play_random_track(audio, state, client); } } - fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State) { + fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); + let current_biome = Self::get_current_biome(client); + println!("======> Music Current biome: {:?}", current_biome); let mut rng = thread_rng(); let maybe_track = self @@ -122,6 +127,10 @@ impl MusicMgr { None => true, } }) + .filter(|track| match &track.biome { + Some(biome) => biome == ¤t_biome, + None => true, + }) .choose(&mut rng); if let Some(track) = maybe_track { @@ -141,6 +150,13 @@ impl MusicMgr { } } + fn get_current_biome(client: &Client) -> BiomeKind { + match client.current_chunk() { + Some(chunk) => chunk.meta().biome(), + _ => BiomeKind::Void, + } + } + fn load_soundtrack_items() -> SoundtrackCollection { match assets::load_file("voxygen.audio.soundtrack", &["ron"]) { Ok(file) => match ron::de::from_reader(file) { diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 0faae1a64f..0c853d217b 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -14,7 +14,7 @@ pub use self::{ terrain::Terrain, }; use crate::{ - audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend}, + audio::{ambient::AmbientMgr, music::MusicMgr, sfx::SfxMgr, AudioFrontend}, render::{ create_clouds_mesh, create_pp_mesh, create_skybox_mesh, CloudsLocals, CloudsPipeline, Consts, GlobalModel, Globals, Light, LodData, Model, PostProcessLocals, @@ -103,6 +103,7 @@ pub struct Scene { figure_mgr: FigureMgr, sfx_mgr: SfxMgr, music_mgr: MusicMgr, + ambient_mgr: AmbientMgr, } pub struct SceneData<'a> { @@ -308,6 +309,7 @@ impl Scene { figure_mgr: FigureMgr::new(renderer), sfx_mgr: SfxMgr::new(), music_mgr: MusicMgr::new(), + ambient_mgr: AmbientMgr::new(), } } @@ -441,6 +443,7 @@ impl Scene { renderer: &mut Renderer, audio: &mut AudioFrontend, scene_data: &SceneData, + client: &Client, ) { span!(_guard, "maintain", "Scene::maintain"); // Get player position. @@ -994,7 +997,8 @@ impl Scene { scene_data.player_entity, &self.camera, ); - self.music_mgr.maintain(audio, scene_data.state); + self.music_mgr.maintain(audio, scene_data.state, client); + self.ambient_mgr.maintain(audio, scene_data.state, client); } /// Render the scene using the provided `Renderer`. diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 98a3a075dd..2c15a6984b 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -1077,6 +1077,7 @@ impl PlayState for SessionState { global_state.window.renderer_mut(), &mut global_state.audio, &scene_data, + &client, ); // Process outcomes from client From b5aea464f3b92065da879a909163a18b0d081555 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Mon, 19 Oct 2020 17:28:25 -0700 Subject: [PATCH 02/37] Switch music at biome transitions --- assets/voxygen/audio/soundtrack.ron | 8 ++++---- voxygen/src/audio/ambient.rs | 1 - voxygen/src/audio/channel.rs | 12 +++++++++--- voxygen/src/audio/mod.rs | 15 +++++++++++++++ voxygen/src/audio/music.rs | 27 ++++++++++++++++++++++++--- 5 files changed, 52 insertions(+), 11 deletions(-) diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index 7f628765a3..77b33a9978 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -31,8 +31,8 @@ title: "Wandering Voices", path: "voxygen.audio.soundtrack.wandering_voices", length: 137.0, - timing: Some(Night), - biome: Some(Snowlands), + timing: Some(Day), + biome: Some(Grassland), artist: "Aeronic", ), ( @@ -48,7 +48,7 @@ path: "voxygen.audio.soundtrack.mineral_deposits", length: 148.0, timing: Some(Day), - biome: Some(Snowlands), + biome: Some(Forest), artist: "Aeronic", ), ( @@ -56,7 +56,7 @@ path: "voxygen.audio.soundtrack.moonbeams", length: 158.0, timing: Some(Night), - biome: Some(Snowlands), + biome: Some(Forest), artist: "Aeronic", ), ( diff --git a/voxygen/src/audio/ambient.rs b/voxygen/src/audio/ambient.rs index d5e283e291..0f82d28583 100644 --- a/voxygen/src/audio/ambient.rs +++ b/voxygen/src/audio/ambient.rs @@ -113,7 +113,6 @@ impl AmbientMgr { let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); let current_biome = Self::get_current_biome(client); - println!("Ambient Current biome: {:?}", current_biome); let mut rng = thread_rng(); let maybe_track = self diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index 5780dc7ac8..b51fd69590 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -62,9 +62,9 @@ impl MusicChannel { } } - // Play a music track item on this channel. If the channel has an existing track - // playing, the new sounds will be appended and played once they complete. - // Otherwise it will begin playing immediately. + /// Play a music track item on this channel. If the channel has an existing + /// track playing, the new sounds will be appended and played once they + /// complete. Otherwise it will begin playing immediately. pub fn play(&mut self, source: S, tag: MusicChannelTag) where S: Source + Send + 'static, @@ -82,6 +82,12 @@ impl MusicChannel { }; } + /// Stop whatever is playing on a given channel + pub fn stop(&mut self, tag: MusicChannelTag) { + self.tag = tag; + self.sink.stop(); + } + /// Set the volume of the current channel. If the channel is currently /// fading, the volume of the fader is updated to this value. pub fn set_volume(&mut self, volume: f32) { diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 9f065bc577..2ad50f8476 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -205,6 +205,15 @@ impl AudioFrontend { let sound = Decoder::new(file).expect("Failed to decode sound"); channel.play(sound, channel_tag); + //channel.set_fader(Fader::fade_in(2.0, music_volume)); + } + } + + fn stop_music(&mut self, channel_tag: MusicChannelTag) { + let music_volume = self.music_volume; + if let Some(channel) = self.get_music_channel(channel_tag) { + //channel.set_fader(Fader::fade_out(5.0, music_volume)); + channel.stop(channel_tag); } } @@ -249,6 +258,12 @@ impl AudioFrontend { } } + pub fn stop_exploration_music(&mut self) { + if self.music_enabled() { + self.stop_music(MusicChannelTag::Exploration) + } + } + pub fn play_exploration_ambient(&mut self, item: &str) { if self.ambient_enabled() { self.play_ambient(item, AmbientChannelTag::Exploration) diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 5f11fb9c7d..b81500ff1c 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -83,6 +83,8 @@ pub struct MusicMgr { /// The title of the last track played. Used to prevent a track /// being played twice in a row last_track: String, + last_biome: BiomeKind, + playing: bool, } impl MusicMgr { @@ -93,27 +95,46 @@ impl MusicMgr { began_playing: Instant::now(), next_track_change: 0.0, last_track: String::from("None"), + last_biome: BiomeKind::Void, + playing: false, } } /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { + // Gets the current player biome + let current_biome: BiomeKind = match client.current_chunk() { + Some(chunk) => chunk.meta().biome(), + _ => self.last_biome, + }; + if audio.music_enabled() && !self.soundtrack.tracks.is_empty() - && self.began_playing.elapsed().as_secs_f64() > self.next_track_change + && (self.began_playing.elapsed().as_secs_f64() > self.next_track_change + || !self.playing) { + println!("It shoooooooooooooooooooooooooooooooooooooooooooooooooooooooould play!!!"); self.play_random_track(audio, state, client); + self.playing = true; + } else if current_biome != self.last_biome { + println!( + "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSStop!\ + !!" + ); + audio.stop_exploration_music(); + self.playing = false; } + self.last_biome = current_biome; } fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; + //const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; + const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 5.0; let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); let current_biome = Self::get_current_biome(client); - println!("======> Music Current biome: {:?}", current_biome); let mut rng = thread_rng(); let maybe_track = self From 0689630d987bc4818d56969cdcb39ec8471ea208 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Wed, 21 Oct 2020 15:10:32 -0700 Subject: [PATCH 03/37] Fading music/ambient sounds decently upon biome transition --- assets/voxygen/audio/ambient.ron | 80 +++++++++++++++++-- assets/voxygen/audio/ambient/desert_night.ogg | 3 + .../voxygen/audio/ambient/grassland_day.ogg | 3 + .../voxygen/audio/ambient/grassland_night.ogg | 3 + assets/voxygen/audio/ambient/jungle_day.ogg | 3 + assets/voxygen/audio/ambient/jungle_night.ogg | 3 + assets/voxygen/audio/ambient/snowlands.ogg | 3 + assets/voxygen/audio/soundtrack.ron | 32 ++++---- voxygen/src/audio/ambient.rs | 62 ++++++++++---- voxygen/src/audio/channel.rs | 8 +- voxygen/src/audio/mod.rs | 69 +++++++++++++++- voxygen/src/audio/music.rs | 39 ++++++--- 12 files changed, 251 insertions(+), 57 deletions(-) create mode 100644 assets/voxygen/audio/ambient/desert_night.ogg create mode 100644 assets/voxygen/audio/ambient/grassland_day.ogg create mode 100644 assets/voxygen/audio/ambient/grassland_night.ogg create mode 100644 assets/voxygen/audio/ambient/jungle_day.ogg create mode 100644 assets/voxygen/audio/ambient/jungle_night.ogg create mode 100644 assets/voxygen/audio/ambient/snowlands.ogg diff --git a/assets/voxygen/audio/ambient.ron b/assets/voxygen/audio/ambient.ron index 48cd6454c2..e6e1432758 100644 --- a/assets/voxygen/audio/ambient.ron +++ b/assets/voxygen/audio/ambient.ron @@ -2,14 +2,6 @@ ( tracks: [ - ( - title: "Forest Day", // Ambience Track - path: "voxygen.audio.ambient.forest_day", - length: 629.0, - timing: Some(Night), - biome: Some(Forest), - artist: "https://www.youtube.com/watch?v=FwVTkB-BIvM", - ), ( title: "Forest Morning", // Ambience Track path: "voxygen.audio.ambient.forest_morning", @@ -18,5 +10,77 @@ biome: Some(Forest), artist: "https://www.youtube.com/watch?v=eq4nfIdK6C4", ), + ( + title: "Crickets and Tawny Owl", // Ambience Track + path: "voxygen.audio.ambient.grassland_night", + length: 141.0, + timing: Some(Night), + biome: Some(Forest), + artist: "https://freesound.org/people/raoul_slayer/sounds/203598/", + ), + //( + // title: "Forest Day", // Ambience Track + // path: "voxygen.audio.ambient.forest_day", + // length: 629.0, + // timing: Some(Night), + // biome: Some(Forest), + // artist: "https://www.youtube.com/watch?v=FwVTkB-BIvM", + //), + ( + title: "Desert Night", // Ambience Track + path: "voxygen.audio.ambient.desert_night", + length: 328.0, + timing: Some(Night), + biome: Some(Desert), + artist: "https://freesound.org/people/kangaroovindaloo/sounds/483550/", + ), + ( + title: "Village Jungle Morning", // Ambience Track + path: "voxygen.audio.ambient.jungle_day", + length: 105.0, + timing: Some(Day), + biome: Some(Swamp), + artist: "https://freesound.org/people/aurelien.leveque/sounds/417635/", + ), + ( + title: "Jungle in Maharashtra at Night", // Ambience Track + path: "voxygen.audio.ambient.jungle_night", + length: 63.0, + timing: Some(Night), + biome: Some(Swamp), + artist: "https://freesound.org/people/Agim/sounds/417872/", + ), + ( + title: "Mountain Glacier Distant", // Ambience Track + path: "voxygen.audio.ambient.snowlands", + length: 22.0, + timing: Some(Day), + biome: Some(Snowlands), + artist: "https://freesound.org/people/Eelke/sounds/462623/", + ), + ( + title: "Mountain Glacier Distant", // Ambience Track + path: "voxygen.audio.ambient.snowlands", + length: 22.0, + timing: Some(Night), + biome: Some(Snowlands), + artist: "https://freesound.org/people/Eelke/sounds/462623/", + ), + ( + title: "Summer Meadow", // Ambience Track + path: "voxygen.audio.ambient.grassland_day", + length: 92.0, + timing: Some(Day), + biome: Some(Grassland), + artist: "https://freesound.org/people/baryy/sounds/409143/", + ), + ( + title: "Crickets and Tawny Owl", // Ambience Track + path: "voxygen.audio.ambient.grassland_night", + length: 141.0, + timing: Some(Night), + biome: Some(Grassland), + artist: "https://freesound.org/people/raoul_slayer/sounds/203598/", + ), ] ) diff --git a/assets/voxygen/audio/ambient/desert_night.ogg b/assets/voxygen/audio/ambient/desert_night.ogg new file mode 100644 index 0000000000..c7b94e73fa --- /dev/null +++ b/assets/voxygen/audio/ambient/desert_night.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f787ce96814e416c898274abc1b78dca07bbdf0fdc2866b9de9daa354240bcbf +size 6083895 diff --git a/assets/voxygen/audio/ambient/grassland_day.ogg b/assets/voxygen/audio/ambient/grassland_day.ogg new file mode 100644 index 0000000000..1437c9158e --- /dev/null +++ b/assets/voxygen/audio/ambient/grassland_day.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f2b26e35c60bf00d555605bde3e5ce3d634f1e3221523e5a67b6c1c4d9a05aa +size 1657695 diff --git a/assets/voxygen/audio/ambient/grassland_night.ogg b/assets/voxygen/audio/ambient/grassland_night.ogg new file mode 100644 index 0000000000..debcfa5afa --- /dev/null +++ b/assets/voxygen/audio/ambient/grassland_night.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3386acd7dea5c63f11a363b82926f6df9770a266d327e54a5992dfbed29579d8 +size 3000009 diff --git a/assets/voxygen/audio/ambient/jungle_day.ogg b/assets/voxygen/audio/ambient/jungle_day.ogg new file mode 100644 index 0000000000..e2e80c9622 --- /dev/null +++ b/assets/voxygen/audio/ambient/jungle_day.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:381d2171c785a9aa46618b52c82abd915de50dadac8e9697aa6887114026006e +size 2014591 diff --git a/assets/voxygen/audio/ambient/jungle_night.ogg b/assets/voxygen/audio/ambient/jungle_night.ogg new file mode 100644 index 0000000000..c428c1ceaa --- /dev/null +++ b/assets/voxygen/audio/ambient/jungle_night.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc1677bdae9a06df578b18ee5cbb001b20c679573381505755594986d5f3a8c1 +size 629181 diff --git a/assets/voxygen/audio/ambient/snowlands.ogg b/assets/voxygen/audio/ambient/snowlands.ogg new file mode 100644 index 0000000000..d5c342f550 --- /dev/null +++ b/assets/voxygen/audio/ambient/snowlands.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3cc3fa048c94b33e032643efd1dd6bfd252fe3ac1065138a65656c71f16c8a0b +size 193015 diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index 77b33a9978..a8eb947258 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -7,16 +7,16 @@ title: "A Solemn Quest", path: "voxygen.audio.soundtrack.a_solemn_quest", length: 206.0, - timing: Some(Night), - biome: Some(Grassland), + timing: Some(Day), + biome: Some(Forest), artist: "Eden", ), ( title: "Into The Dark Forest", path: "voxygen.audio.soundtrack.into_the_dark_forest", length: 184.0, - timing: Some(Night), - biome: Some(Snowlands), + timing: Some(Day), + biome: Some(Grassland), artist: "Aeronic", ), ( @@ -24,7 +24,7 @@ path: "voxygen.audio.soundtrack.field_grazing", length: 154.0, timing: Some(Day), - biome: Some(Grassland), + biome: Some(Snowlands), artist: "Aeronic", ), ( @@ -32,7 +32,7 @@ path: "voxygen.audio.soundtrack.wandering_voices", length: 137.0, timing: Some(Day), - biome: Some(Grassland), + biome: Some(Desert), artist: "Aeronic", ), ( @@ -40,7 +40,7 @@ path: "voxygen.audio.soundtrack.snowtop_volume", length: 89.0, timing: Some(Day), - biome: Some(Snowlands), + biome: Some(Desert), artist: "Aeronic", ), ( @@ -48,7 +48,7 @@ path: "voxygen.audio.soundtrack.mineral_deposits", length: 148.0, timing: Some(Day), - biome: Some(Forest), + biome: Some(Desert), artist: "Aeronic", ), ( @@ -56,7 +56,7 @@ path: "voxygen.audio.soundtrack.moonbeams", length: 158.0, timing: Some(Night), - biome: Some(Forest), + biome: Some(Desert), artist: "Aeronic", ), ( @@ -64,7 +64,7 @@ path: "voxygen.audio.soundtrack.serene_meadows", length: 173.0, timing: Some(Night), - biome: Some(Snowlands), + biome: Some(Desert), artist: "Aeronic", ), /*( @@ -72,7 +72,7 @@ path: "voxygen.audio.soundtrack.rest_assured", length: 185.0, timing: Some(Day), - biome: Some(Snowlands), + biome: Some(Desert), artist: "badbbad", ),*/ ( @@ -80,7 +80,7 @@ path: "voxygen.audio.soundtrack.just_the_beginning", length: 188.0, timing: Some(Day), - biome: Some(Snowlands), + biome: Some(Desert), artist: "badbbad", ), ( @@ -88,7 +88,7 @@ path: "voxygen.audio.soundtrack.campfire_stories", length: 100.0, timing: Some(Night), - biome: Some(Snowlands), + biome: Some(Desert), artist: "badbbad", ), ( @@ -96,7 +96,7 @@ path: "voxygen.audio.soundtrack.limits", length: 203.0, timing: Some(Night), - biome: Some(Snowlands), + biome: Some(Desert), artist: "badbbad", ), /*( // Dungeon @@ -104,7 +104,7 @@ path: "voxygen.audio.soundtrack.down_the_rabbit_hole", length: 244.0, timing: Some(Night), - biome: Some(Snowlands), + biome: Some(Desert), artist: "badbbad", ),*/ ( @@ -112,7 +112,7 @@ path: "voxygen.audio.soundtrack.between_the_fairies", length: 175.0, timing: Some(Night), - biome: Some(Snowlands), + biome: Some(Desert), artist: "badbbad", ), ] diff --git a/voxygen/src/audio/ambient.rs b/voxygen/src/audio/ambient.rs index 0f82d28583..ce87478564 100644 --- a/voxygen/src/audio/ambient.rs +++ b/voxygen/src/audio/ambient.rs @@ -54,7 +54,7 @@ struct AmbientSoundtrackCollection { tracks: Vec, } -/// Configuration for a single music track in the soundtrack +/// Configuration for a single ambient sound track in the soundtrack #[derive(Debug, Deserialize)] pub struct AmbientSoundtrackItem { title: String, @@ -75,14 +75,26 @@ enum DayPeriod { Night, } -/// Provides methods to control music playback +/// Determines whether the sound is stopped, playing, or fading +#[derive(Debug, Deserialize, PartialEq)] +enum PlayState { + Playing, + Stopped, + FadingOut, + FadingIn, +} + +/// Provides methods to control ambient sound playback pub struct AmbientMgr { ambient_soundtrack: AmbientSoundtrackCollection, began_playing: Instant, + began_fading: Instant, next_track_change: f64, /// The title of the last track played. Used to prevent a track /// being played twice in a row last_track: String, + last_biome: BiomeKind, + playing: PlayState, } impl AmbientMgr { @@ -91,25 +103,45 @@ impl AmbientMgr { Self { ambient_soundtrack: Self::load_ambient_soundtrack_items(), began_playing: Instant::now(), + began_fading: Instant::now(), next_track_change: 0.0, last_track: String::from("None"), + last_biome: BiomeKind::Void, + playing: PlayState::Stopped, } } /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - if audio.music_enabled() + // Gets the current player biome + let current_biome: BiomeKind = match client.current_chunk() { + Some(chunk) => chunk.meta().biome(), + _ => self.last_biome, + }; + + if audio.music_enabled() // TODO: Change this to ambient_enabled && !self.ambient_soundtrack.tracks.is_empty() - && self.began_playing.elapsed().as_secs_f64() > self.next_track_change + && (self.began_playing.elapsed().as_secs_f64() > self.next_track_change + || self.playing == PlayState::Stopped) + && self.playing != PlayState::FadingOut { self.play_random_track(audio, state, client); + self.playing = PlayState::Playing; + } else if current_biome != self.last_biome && self.playing == PlayState::Playing { + audio.fade_out_exploration_ambient(); + self.began_fading = Instant::now(); + self.playing = PlayState::FadingOut; + } else if self.began_fading.elapsed().as_secs_f64() > 5.0 + && self.playing == PlayState::FadingOut + { + audio.stop_exploration_ambient(); + self.playing = PlayState::Stopped; } + self.last_biome = current_biome; } fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; - let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); let current_biome = Self::get_current_biome(client); @@ -119,12 +151,9 @@ impl AmbientMgr { .ambient_soundtrack .tracks .iter() - .filter(|track| { - !track.title.eq(&self.last_track) - && match &track.timing { - Some(period_of_day) => period_of_day == ¤t_period_of_day, - None => true, - } + .filter(|track| match &track.timing { + Some(period_of_day) => period_of_day == ¤t_period_of_day, + None => true, }) .filter(|track| match &track.biome { Some(biome) => biome == ¤t_biome, @@ -135,8 +164,9 @@ impl AmbientMgr { if let Some(track) = maybe_track { self.last_track = String::from(&track.title); self.began_playing = Instant::now(); - self.next_track_change = track.length + SILENCE_BETWEEN_TRACKS_SECONDS; + self.next_track_change = track.length; + audio.fade_in_exploration_ambient(); audio.play_exploration_ambient(&track.path); } } @@ -162,7 +192,8 @@ impl AmbientMgr { Ok(config) => config, Err(error) => { warn!( - "Error parsing music config file, music will not be available: {}", + "Error parsing ambient sound config file, ambient sound will not be \ + available: {}", format!("{:#?}", error) ); @@ -171,7 +202,8 @@ impl AmbientMgr { }, Err(error) => { warn!( - "Error reading music config file, music will not be available: {}", + "Error reading ambient sound config file, ambient sound will not be \ + available: {}", format!("{:#?}", error) ); diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index b51fd69590..150897746a 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -82,7 +82,7 @@ impl MusicChannel { }; } - /// Stop whatever is playing on a given channel + /// Stop whatever is playing on a given music channel pub fn stop(&mut self, tag: MusicChannelTag) { self.tag = tag; self.sink.stop(); @@ -193,6 +193,12 @@ impl AmbientChannel { }; } + /// Stop whatever is playing on a given channel + pub fn stop(&mut self, tag: AmbientChannelTag) { + self.tag = tag; + self.sink.stop(); + } + /// Set the volume of the current channel. If the channel is currently /// fading, the volume of the fader is updated to this value. pub fn set_volume(&mut self, volume: f32) { diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 2ad50f8476..fdea2b5216 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -205,18 +205,49 @@ impl AudioFrontend { let sound = Decoder::new(file).expect("Failed to decode sound"); channel.play(sound, channel_tag); - //channel.set_fader(Fader::fade_in(2.0, music_volume)); + } + } + + fn fade_out_music(&mut self, channel_tag: MusicChannelTag) { + let music_volume = self.music_volume; + if let Some(channel) = self.get_music_channel(channel_tag) { + channel.set_fader(Fader::fade_out(5.0, music_volume)); + } + } + + fn fade_in_music(&mut self, channel_tag: MusicChannelTag) { + let music_volume = self.music_volume; + if let Some(channel) = self.get_music_channel(channel_tag) { + channel.set_fader(Fader::fade_in(5.0, music_volume)); } } fn stop_music(&mut self, channel_tag: MusicChannelTag) { - let music_volume = self.music_volume; if let Some(channel) = self.get_music_channel(channel_tag) { - //channel.set_fader(Fader::fade_out(5.0, music_volume)); channel.stop(channel_tag); } } + fn stop_ambient(&mut self, channel_tag: AmbientChannelTag) { + if let Some(channel) = self.get_ambient_channel(channel_tag) { + channel.stop(channel_tag); + } + } + + fn fade_out_ambient(&mut self, channel_tag: AmbientChannelTag) { + let ambient_volume = self.ambient_volume; + if let Some(channel) = self.get_ambient_channel(channel_tag) { + channel.set_fader(Fader::fade_out(2.0, ambient_volume)); + } + } + + fn fade_in_ambient(&mut self, channel_tag: AmbientChannelTag) { + let ambient_volume = self.ambient_volume; + if let Some(channel) = self.get_ambient_channel(channel_tag) { + channel.set_fader(Fader::fade_in(2.0, ambient_volume)); + } + } + fn play_ambient(&mut self, sound: &str, channel_tag: AmbientChannelTag) { if let Some(channel) = self.get_ambient_channel(channel_tag) { let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); @@ -258,6 +289,18 @@ impl AudioFrontend { } } + pub fn fade_out_exploration_music(&mut self) { + if self.music_enabled() { + self.fade_out_music(MusicChannelTag::Exploration) + } + } + + pub fn fade_in_exploration_music(&mut self) { + if self.music_enabled() { + self.fade_in_music(MusicChannelTag::Exploration) + } + } + pub fn stop_exploration_music(&mut self) { if self.music_enabled() { self.stop_music(MusicChannelTag::Exploration) @@ -265,11 +308,29 @@ impl AudioFrontend { } pub fn play_exploration_ambient(&mut self, item: &str) { - if self.ambient_enabled() { + if self.music_enabled() { self.play_ambient(item, AmbientChannelTag::Exploration) } } + pub fn fade_out_exploration_ambient(&mut self) { + if self.music_enabled() { + self.fade_out_ambient(AmbientChannelTag::Exploration) + } + } + + pub fn fade_in_exploration_ambient(&mut self) { + if self.music_enabled() { + self.fade_in_ambient(AmbientChannelTag::Exploration) + } + } + + pub fn stop_exploration_ambient(&mut self) { + if self.music_enabled() { + self.stop_ambient(AmbientChannelTag::Exploration) + } + } + pub fn get_sfx_volume(&self) -> f32 { self.sfx_volume } pub fn get_music_volume(&self) -> f32 { self.music_volume } diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index b81500ff1c..9cd4ffa97e 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -75,16 +75,26 @@ enum DayPeriod { Night, } +/// Determines whether the sound is stopped, playing, or fading +#[derive(Debug, Deserialize, PartialEq)] +enum PlayState { + Playing, + Stopped, + FadingOut, + FadingIn, +} + /// Provides methods to control music playback pub struct MusicMgr { soundtrack: SoundtrackCollection, began_playing: Instant, + began_fading: Instant, next_track_change: f64, /// The title of the last track played. Used to prevent a track /// being played twice in a row last_track: String, last_biome: BiomeKind, - playing: bool, + playing: PlayState, } impl MusicMgr { @@ -93,10 +103,11 @@ impl MusicMgr { Self { soundtrack: Self::load_soundtrack_items(), began_playing: Instant::now(), + began_fading: Instant::now(), next_track_change: 0.0, last_track: String::from("None"), last_biome: BiomeKind::Void, - playing: false, + playing: PlayState::Stopped, } } @@ -112,25 +123,27 @@ impl MusicMgr { if audio.music_enabled() && !self.soundtrack.tracks.is_empty() && (self.began_playing.elapsed().as_secs_f64() > self.next_track_change - || !self.playing) + || self.playing == PlayState::Stopped) + && self.playing != PlayState::FadingOut { - println!("It shoooooooooooooooooooooooooooooooooooooooooooooooooooooooould play!!!"); self.play_random_track(audio, state, client); - self.playing = true; - } else if current_biome != self.last_biome { - println!( - "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSStop!\ - !!" - ); + self.playing = PlayState::Playing; + } else if current_biome != self.last_biome && self.playing == PlayState::Playing { + audio.fade_out_exploration_music(); + self.began_fading = Instant::now(); + self.playing = PlayState::FadingOut; + } else if self.began_fading.elapsed().as_secs_f64() > 5.0 + && self.playing == PlayState::FadingOut + { audio.stop_exploration_music(); - self.playing = false; + self.playing = PlayState::Stopped; } self.last_biome = current_biome; } fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - //const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; - const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 5.0; + const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; + //const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 5.0; let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); From 347334774239cdeba2102dad3ba1f9f9f8b0501d Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sat, 24 Oct 2020 18:12:05 -0700 Subject: [PATCH 04/37] Sfx from blocks --- assets/voxygen/audio/sfx.ron | 12 +- .../src/audio/sfx/event_mapper/block/mod.rs | 216 ++++++++++++++++++ .../src/audio/sfx/event_mapper/combat/mod.rs | 4 +- voxygen/src/audio/sfx/event_mapper/mod.rs | 11 +- .../audio/sfx/event_mapper/movement/mod.rs | 4 +- .../audio/sfx/event_mapper/progression/mod.rs | 5 +- voxygen/src/audio/sfx/mod.rs | 9 +- voxygen/src/scene/mod.rs | 1 + 8 files changed, 247 insertions(+), 15 deletions(-) create mode 100644 voxygen/src/audio/sfx/event_mapper/block/mod.rs diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index fd826c758e..ac434b91a0 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -65,12 +65,12 @@ ], threshold: 0.5, ), - Glide: ( - files: [ - // Event Missing or not implemented? - ], - threshold: 0.5, - ), + //Glide: ( + // files: [ + // // Event Missing or not implemented? + // ], + // threshold: 0.5, + //), GliderClose: ( files: [ "voxygen.audio.sfx.glider_close", diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs new file mode 100644 index 0000000000..c8f5085963 --- /dev/null +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -0,0 +1,216 @@ +/// EventMapper::Block watches the sound emitting blocks in the same +/// chunk as the player and emits ambient sfx +use crate::{ + audio::sfx::{SfxEvent, SfxEventItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, + scene::{terrain::BlocksOfInterest, Camera, Terrain}, +}; + +use super::EventMapper; +use common::{ + comp::Pos, event::EventBus, spiral::Spiral2d, state::State, terrain::TerrainChunk, + vol::RectRasterableVol, +}; +use rand::{prelude::SliceRandom, thread_rng}; +use specs::{Join, WorldExt}; +use std::time::Instant; +use vek::*; + +enum BlockEmitter { + Leaves, + Grass, + Embers, + Beehives, + Reeds, + Flowers, +} + +pub struct BlockEventMapper { + timer: Instant, +} + +impl EventMapper for BlockEventMapper { + fn maintain( + &mut self, + state: &State, + player_entity: specs::Entity, + camera: &Camera, + triggers: &SfxTriggers, + terrain: &Terrain, + ) { + let ecs = state.ecs(); + + let sfx_event_bus = ecs.read_resource::>(); + let mut sfx_emitter = sfx_event_bus.emitter(); + + let focus_off = camera.get_focus_pos().map(f32::trunc); + let cam_pos = camera.dependents().cam_pos + focus_off; + + //for (entity, pos) in (&ecs.entities(), &ecs.read_storage::()) + // .join() + // .filter(|(_, e_pos, ..)| (e_pos.0.distance_squared(cam_pos)) < + // SFX_DIST_LIMIT_SQR) + //{ + //} + + let player_pos = state + .read_component_copied::(player_entity) + .unwrap_or_default(); + let player_chunk = player_pos.0.xy().map2(TerrainChunk::RECT_SIZE, |e, sz| { + (e.floor() as i32).div_euclid(sz as i32) + }); + + struct BlockSounds<'a> { + // The function to select the blocks of interest that we should emit from + blocks: fn(&'a BlocksOfInterest) -> &'a [Vec3], + // The range, in chunks, that the particles should be generated in from the player + range: usize, + // The emission rate, per block per second, of the generated particles + rate: f32, + // The number of seconds that each particle should live for + lifetime: f32, + // The sound of the generated particle + sound: SfxEvent, + // Condition that must be true + cond: fn(&State) -> bool, + } + let sounds: &[BlockSounds] = &[ + BlockSounds { + blocks: |boi| &boi.leaves, + range: 4, + rate: 0.1, + lifetime: 3.0, + sound: SfxEvent::LevelUp, + cond: |_| true, + }, + BlockSounds { + blocks: |boi| &boi.embers, + range: 2, + rate: 0.5, + lifetime: 2.25, + sound: SfxEvent::Roll, + cond: |_| true, + }, + BlockSounds { + blocks: |boi| &boi.reeds, + range: 6, + rate: 0.4, + lifetime: 4.0, + sound: SfxEvent::Roll, + cond: |st| st.get_day_period().is_dark(), + }, + BlockSounds { + blocks: |boi| &boi.flowers, + range: 5, + rate: 0.2, + lifetime: 4.0, + sound: SfxEvent::Roll, + cond: |st| st.get_day_period().is_dark(), + }, + BlockSounds { + blocks: |boi| &boi.beehives, + range: 3, + rate: 0.5, + lifetime: 3.0, + sound: SfxEvent::Roll, + cond: |st| st.get_day_period().is_light(), + }, + ]; + let mut rng = thread_rng(); + for sounds in sounds.iter() { + if !(sounds.cond)(state) { + continue; + } + for offset in Spiral2d::new().take((sounds.range * 2 + 1).pow(2)) { + let chunk_pos = player_chunk + offset; + + terrain.get(chunk_pos).map(|chunk_data| { + let blocks = (sounds.blocks)(&chunk_data.blocks_of_interest); + let block_pos: Vec3 = + Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)) + + blocks + .choose(&mut rng) + .copied() + .unwrap_or_else(|| Vec3::new(0, 0, 0)); + + let block_pos = Vec3::new( + block_pos[0] as f32, + block_pos[1] as f32, + block_pos[2] as f32, + ); + + if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { + if let Some(mapped_event) = self.map_event(BlockEmitter::Leaves) { + let sfx_trigger_item = triggers.get_trigger(&mapped_event); + if sfx_trigger_item.is_some() { + println!("sound"); + ecs.read_resource::>().emit_now( + SfxEventItem::new( + mapped_event.clone(), + Some(block_pos), + Some(1.0), + ), + ); + } + } + } + }); + } + } + } + //let leaves_pos = BlocksOfInterest::from_chunk(&player_chunk).leaves; + //if leaves_pos.len() > 0 { + // let my_leaf_pos = Vec3::new( + // leaves_pos[0][0] as f32, + // leaves_pos[0][1] as f32, + // leaves_pos[0][2] as f32, + // ); + // println!("my leaf pos: {:?}", my_leaf_pos); + + // if let Some(mapped_event) = self.map_event(BlockEmitter::Leaves) { + // let sfx_trigger_item = triggers.get_trigger(&mapped_event); + + // if leaves_pos.len() > 0 { + // println!("Num leaves: {:?}", leaves_pos.len()); + // } + // //for i in 0..leaves_pos.len() { + // // if i < 5 { + // if sfx_trigger_item.is_some() { + // println!("sound"); + // ecs.read_resource::>() + // .emit_now(SfxEventItem::new( + // mapped_event.clone(), + // Some(my_leaf_pos), + // Some(1.0), + // )); + // } + // // } + // //} + // } + //} +} + +impl BlockEventMapper { + pub fn new() -> Self { + Self { + timer: Instant::now(), + } + } + + fn map_event(&mut self, blocktype: BlockEmitter) -> Option { + if self.timer.elapsed().as_secs_f32() > 1.0 { + self.timer = Instant::now(); + let sfx_event = match blocktype { + BlockEmitter::Leaves => Some(SfxEvent::LevelUp), + BlockEmitter::Grass => Some(SfxEvent::Roll), + BlockEmitter::Embers => Some(SfxEvent::Roll), + BlockEmitter::Beehives => Some(SfxEvent::Roll), + BlockEmitter::Reeds => Some(SfxEvent::Roll), + BlockEmitter::Flowers => Some(SfxEvent::Roll), + }; + + sfx_event + } else { + None + } + } +} diff --git a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs index e46c19b21b..ff2c9b82e6 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs @@ -2,7 +2,7 @@ /// emits sfx related to weapons and attacks/abilities use crate::{ audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, - scene::Camera, + scene::{Camera, Terrain}, }; use super::EventMapper; @@ -11,6 +11,7 @@ use common::{ comp::{item::ItemKind, CharacterAbilityType, CharacterState, Loadout, Pos}, event::EventBus, state::State, + terrain::TerrainChunk, }; use hashbrown::HashMap; use specs::{Entity as EcsEntity, Join, WorldExt}; @@ -44,6 +45,7 @@ impl EventMapper for CombatEventMapper { player_entity: specs::Entity, camera: &Camera, triggers: &SfxTriggers, + terrain: &Terrain, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/event_mapper/mod.rs b/voxygen/src/audio/sfx/event_mapper/mod.rs index d5a9d6f8cb..a9f5dd9e9d 100644 --- a/voxygen/src/audio/sfx/event_mapper/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/mod.rs @@ -1,15 +1,17 @@ +mod block; mod combat; mod movement; mod progression; -use common::state::State; +use common::{state::State, terrain::TerrainChunk}; +use block::BlockEventMapper; use combat::CombatEventMapper; use movement::MovementEventMapper; use progression::ProgressionEventMapper; use super::SfxTriggers; -use crate::scene::Camera; +use crate::scene::{Camera, Terrain}; trait EventMapper { fn maintain( @@ -18,6 +20,7 @@ trait EventMapper { player_entity: specs::Entity, camera: &Camera, triggers: &SfxTriggers, + terrain: &Terrain, ); } @@ -32,6 +35,7 @@ impl SfxEventMapper { Box::new(CombatEventMapper::new()), Box::new(MovementEventMapper::new()), Box::new(ProgressionEventMapper::new()), + Box::new(BlockEventMapper::new()), ], } } @@ -42,9 +46,10 @@ impl SfxEventMapper { player_entity: specs::Entity, camera: &Camera, triggers: &SfxTriggers, + terrain: &Terrain, ) { for mapper in &mut self.mappers { - mapper.maintain(state, player_entity, camera, triggers); + mapper.maintain(state, player_entity, camera, triggers, terrain); } } } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 8cdeb8c4da..ee02996ed7 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -4,12 +4,13 @@ use super::EventMapper; use crate::{ audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, - scene::Camera, + scene::{Camera, Terrain}, }; use common::{ comp::{Body, CharacterState, PhysicsState, Pos, Vel}, event::EventBus, state::State, + terrain::TerrainChunk, }; use hashbrown::HashMap; use specs::{Entity as EcsEntity, Join, WorldExt}; @@ -44,6 +45,7 @@ impl EventMapper for MovementEventMapper { player_entity: specs::Entity, camera: &Camera, triggers: &SfxTriggers, + terrain: &Terrain, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/event_mapper/progression/mod.rs b/voxygen/src/audio/sfx/event_mapper/progression/mod.rs index 499e39e559..84588c3acb 100644 --- a/voxygen/src/audio/sfx/event_mapper/progression/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/progression/mod.rs @@ -4,10 +4,10 @@ use super::EventMapper; use crate::{ audio::sfx::{SfxEvent, SfxEventItem, SfxTriggers}, - scene::Camera, + scene::{Camera, Terrain}, }; -use common::{comp::Stats, event::EventBus, state::State}; +use common::{comp::Stats, event::EventBus, state::State, terrain::TerrainChunk}; use specs::WorldExt; #[derive(Clone, PartialEq)] @@ -32,6 +32,7 @@ impl EventMapper for ProgressionEventMapper { player_entity: specs::Entity, _camera: &Camera, triggers: &SfxTriggers, + terrain: &Terrain, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index fe76a43b27..9b424a163b 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -82,7 +82,10 @@ mod event_mapper; -use crate::{audio::AudioFrontend, scene::Camera}; +use crate::{ + audio::AudioFrontend, + scene::{Camera, Terrain}, +}; use common::{ assets, @@ -93,6 +96,7 @@ use common::{ event::EventBus, outcome::Outcome, state::State, + terrain::TerrainChunk, }; use event_mapper::SfxEventMapper; use hashbrown::HashMap; @@ -228,6 +232,7 @@ impl SfxMgr { state: &State, player_entity: specs::Entity, camera: &Camera, + terrain: &Terrain, ) { if !audio.sfx_enabled() { return; @@ -241,7 +246,7 @@ impl SfxMgr { // TODO: replace; deprecated in favor of outcomes self.event_mapper - .maintain(state, player_entity, camera, &self.triggers); + .maintain(state, player_entity, camera, &self.triggers, terrain); // TODO: replace; deprecated in favor of outcomes let events = ecs.read_resource::>().recv_all(); diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 0c853d217b..717738ec2e 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -996,6 +996,7 @@ impl Scene { scene_data.state, scene_data.player_entity, &self.camera, + &self.terrain, ); self.music_mgr.maintain(audio, scene_data.state, client); self.ambient_mgr.maintain(audio, scene_data.state, client); From 9e790f6cacc4c97f5f11c9066e7278831645c1d9 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Tue, 27 Oct 2020 15:45:03 -0700 Subject: [PATCH 05/37] Really broken block sfx pushed so others can see --- assets/voxygen/audio/sfx.ron | 9 + assets/voxygen/audio/sfx/ambient/embers.wav | 3 + .../src/audio/sfx/event_mapper/block/mod.rs | 310 +++++++++++------- .../audio/sfx/event_mapper/campfire/mod.rs | 72 ++++ voxygen/src/audio/sfx/event_mapper/mod.rs | 3 + voxygen/src/audio/sfx/mod.rs | 1 + 6 files changed, 273 insertions(+), 125 deletions(-) create mode 100644 assets/voxygen/audio/sfx/ambient/embers.wav create mode 100644 voxygen/src/audio/sfx/event_mapper/campfire/mod.rs diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index ac434b91a0..5d8aedfc9e 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -1,5 +1,14 @@ ( { + // + // Ambient + // + Embers: ( + files: [ + "voxygen.audio.sfx.ambient.embers", + ], + threshold: 1.2, + ), // // Character States // diff --git a/assets/voxygen/audio/sfx/ambient/embers.wav b/assets/voxygen/audio/sfx/ambient/embers.wav new file mode 100644 index 0000000000..9d999a5022 --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/embers.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc2a7234fb92b3395b43fc279d2a553b1c9b3e093f8f5d3aad98af4a27bcfbdd +size 217472 diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index c8f5085963..6ff7c40d10 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -1,7 +1,7 @@ /// EventMapper::Block watches the sound emitting blocks in the same /// chunk as the player and emits ambient sfx use crate::{ - audio::sfx::{SfxEvent, SfxEventItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, + audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, scene::{terrain::BlocksOfInterest, Camera, Terrain}, }; @@ -10,22 +10,49 @@ use common::{ comp::Pos, event::EventBus, spiral::Spiral2d, state::State, terrain::TerrainChunk, vol::RectRasterableVol, }; +use hashbrown::HashMap; use rand::{prelude::SliceRandom, thread_rng}; -use specs::{Join, WorldExt}; +use specs::WorldExt; use std::time::Instant; use vek::*; -enum BlockEmitter { - Leaves, - Grass, - Embers, - Beehives, - Reeds, - Flowers, +//enum BlockEmitter { +// Leaves, +// Grass, +// Embers, +// Beehives, +// Reeds, +// Flowers, +//} + +#[derive(Clone, PartialEq)] +struct PreviousBlockState { + event: SfxEvent, + time: Instant, +} + +impl Default for PreviousBlockState { + fn default() -> Self { + Self { + event: SfxEvent::Idle, + time: Instant::now(), + } + } +} + +impl PreviousBlockState { + fn new(event: SfxEvent, pos: Vec3) -> Self { + PreviousBlockState { + event, + time: Instant::now(), + } + } } pub struct BlockEventMapper { timer: Instant, + counter: usize, + history: HashMap, PreviousBlockState>, } impl EventMapper for BlockEventMapper { @@ -45,13 +72,6 @@ impl EventMapper for BlockEventMapper { let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; - //for (entity, pos) in (&ecs.entities(), &ecs.read_storage::()) - // .join() - // .filter(|(_, e_pos, ..)| (e_pos.0.distance_squared(cam_pos)) < - // SFX_DIST_LIMIT_SQR) - //{ - //} - let player_pos = state .read_component_copied::(player_entity) .unwrap_or_default(); @@ -64,153 +84,193 @@ impl EventMapper for BlockEventMapper { blocks: fn(&'a BlocksOfInterest) -> &'a [Vec3], // The range, in chunks, that the particles should be generated in from the player range: usize, - // The emission rate, per block per second, of the generated particles - rate: f32, - // The number of seconds that each particle should live for - lifetime: f32, + // The spacing between sfx, per block, seconds + spacing: f32, // The sound of the generated particle - sound: SfxEvent, + sfx: SfxEvent, + // The volume of the sfx + volume: f32, // Condition that must be true cond: fn(&State) -> bool, } let sounds: &[BlockSounds] = &[ - BlockSounds { - blocks: |boi| &boi.leaves, - range: 4, - rate: 0.1, - lifetime: 3.0, - sound: SfxEvent::LevelUp, - cond: |_| true, - }, + //BlockSounds { + // blocks: |boi| &boi.leaves, + // range: 4, + // spacing: 1.5, + // sfx: SfxEvent::LevelUp, + // volume: 1.0 + // cond: |_| true, + //}, BlockSounds { blocks: |boi| &boi.embers, - range: 2, - rate: 0.5, - lifetime: 2.25, - sound: SfxEvent::Roll, - cond: |_| true, - }, - BlockSounds { - blocks: |boi| &boi.reeds, - range: 6, - rate: 0.4, - lifetime: 4.0, - sound: SfxEvent::Roll, - cond: |st| st.get_day_period().is_dark(), - }, - BlockSounds { - blocks: |boi| &boi.flowers, - range: 5, - rate: 0.2, - lifetime: 4.0, - sound: SfxEvent::Roll, - cond: |st| st.get_day_period().is_dark(), - }, - BlockSounds { - blocks: |boi| &boi.beehives, range: 3, - rate: 0.5, - lifetime: 3.0, - sound: SfxEvent::Roll, - cond: |st| st.get_day_period().is_light(), + spacing: 1.2, + sfx: SfxEvent::Embers, + volume: 0.5, + //volume: 0.05, + cond: |_| true, + //cond: |st| st.get_day_period().is_dark(), }, + //BlockSounds { + // blocks: |boi| &boi.reeds, + // range: 4, + // spacing: 2.0, + // sfx: SfxEvent::Run, + // volume: 1.0, + // //cond: |st| st.get_day_period().is_dark(), + // cond: |_| true, + //}, + //BlockSounds { + // blocks: |boi| &boi.flowers, + // range: 4, + // spacing: 2.5, + // sfx: SfxEvent::LevelUp, + // volume: 1.0, + // cond: |st| st.get_day_period().is_dark(), + //}, + //BlockSounds { + // blocks: |boi| &boi.grass, + // range: 4, + // spacing: 2.5, + // sfx: SfxEvent::Roll, + // volume: 1.0, + // //cond: |st| st.get_day_period().is_light(), + // cond: |_| false, + //}, + //BlockSounds { + // blocks: |boi| &boi.beehives, + // range: 4, + // spacing: 1.5, + // sfx: SfxEvent::Roll, + // volume: 1.0, + // //cond: |st| st.get_day_period().is_light(), + // cond: |_| true, + //}, ]; let mut rng = thread_rng(); + + // Iterate through each kind of block of interest for sounds in sounds.iter() { if !(sounds.cond)(state) { continue; } + // For chunks surrounding the player position for offset in Spiral2d::new().take((sounds.range * 2 + 1).pow(2)) { let chunk_pos = player_chunk + offset; + // Get all the blocks of interest in this chunk terrain.get(chunk_pos).map(|chunk_data| { + // Get all the blocks of type sounds let blocks = (sounds.blocks)(&chunk_data.blocks_of_interest); - let block_pos: Vec3 = - Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)) - + blocks - .choose(&mut rng) - .copied() - .unwrap_or_else(|| Vec3::new(0, 0, 0)); - let block_pos = Vec3::new( - block_pos[0] as f32, - block_pos[1] as f32, - block_pos[2] as f32, - ); + let absolute_pos: Vec3 = + Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)); - if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { - if let Some(mapped_event) = self.map_event(BlockEmitter::Leaves) { - let sfx_trigger_item = triggers.get_trigger(&mapped_event); - if sfx_trigger_item.is_some() { - println!("sound"); - ecs.read_resource::>().emit_now( - SfxEventItem::new( - mapped_event.clone(), - Some(block_pos), - Some(1.0), - ), - ); - } + // Iterate through each individual block + for block in blocks { + let block_pos: Vec3 = absolute_pos + block; + let state = self.history.entry(block_pos).or_default(); + + // Convert to f32 for sfx emitter + let block_pos = Vec3::new( + block_pos[0] as f32, + block_pos[1] as f32, + block_pos[2] as f32, + ); + + if Self::should_emit(state, triggers.get_key_value(&sounds.sfx)) { + sfx_emitter.emit(SfxEventItem::new(sounds.sfx.clone(), Some(block_pos), Some(sounds.volume))); + state.time = Instant::now(); + state.event = sounds.sfx.clone(); } } + + //// If the timer for this block is over the spacing + //// and the block is in the history + //if self.history.contains_key(&block_pos) { + // if self + // .history + // .get(&block_pos) + // .unwrap() // can't fail as the key is in the hashmap + // .elapsed() + // .as_secs_f32() + // > sounds.spacing + // { + // // Reset timer for this block + // self.history.insert(block_pos, Instant::now()); + + // // Convert to f32 for distance_squared function + // let block_pos = Vec3::new( + // block_pos[0] as f32, + // block_pos[1] as f32, + // block_pos[2] as f32, + // ); + + // // If the camera is within SFX distance + // if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { + // // Emit the sound + // let sfx_trigger_item = triggers.get_trigger(&sounds.sfx); + // if sfx_trigger_item.is_some() { + // ecs.read_resource::>().emit_now( + // SfxEventItem::new( + // sounds.sfx.clone(), + // Some(block_pos), + // Some(sounds.volume), + // ), + // ); + // } + // } + // } + //} else { + // // Start the timer for this block + // self.history.insert(block_pos, Instant::now()); + //} + //} }); } } } - //let leaves_pos = BlocksOfInterest::from_chunk(&player_chunk).leaves; - //if leaves_pos.len() > 0 { - // let my_leaf_pos = Vec3::new( - // leaves_pos[0][0] as f32, - // leaves_pos[0][1] as f32, - // leaves_pos[0][2] as f32, - // ); - // println!("my leaf pos: {:?}", my_leaf_pos); - - // if let Some(mapped_event) = self.map_event(BlockEmitter::Leaves) { - // let sfx_trigger_item = triggers.get_trigger(&mapped_event); - - // if leaves_pos.len() > 0 { - // println!("Num leaves: {:?}", leaves_pos.len()); - // } - // //for i in 0..leaves_pos.len() { - // // if i < 5 { - // if sfx_trigger_item.is_some() { - // println!("sound"); - // ecs.read_resource::>() - // .emit_now(SfxEventItem::new( - // mapped_event.clone(), - // Some(my_leaf_pos), - // Some(1.0), - // )); - // } - // // } - // //} - // } - //} } impl BlockEventMapper { pub fn new() -> Self { Self { timer: Instant::now(), + counter: 0, + history: HashMap::new(), } } - fn map_event(&mut self, blocktype: BlockEmitter) -> Option { - if self.timer.elapsed().as_secs_f32() > 1.0 { - self.timer = Instant::now(); - let sfx_event = match blocktype { - BlockEmitter::Leaves => Some(SfxEvent::LevelUp), - BlockEmitter::Grass => Some(SfxEvent::Roll), - BlockEmitter::Embers => Some(SfxEvent::Roll), - BlockEmitter::Beehives => Some(SfxEvent::Roll), - BlockEmitter::Reeds => Some(SfxEvent::Roll), - BlockEmitter::Flowers => Some(SfxEvent::Roll), - }; - - sfx_event + fn should_emit( + previous_state: &PreviousBlockState, + sfx_trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>, + ) -> bool { + if let Some((event, item)) = sfx_trigger_item { + if &previous_state.event == event { + previous_state.time.elapsed().as_secs_f64() >= item.threshold + } else { + true + } } else { - None + false } } + //fn map_event(&mut self, blocktype: BlockEmitter) -> Option { + // if self.timer.elapsed().as_secs_f32() > 1.0 { + // self.timer = Instant::now(); + // let sfx_event = match blocktype { + // BlockEmitter::Leaves => Some(SfxEvent::LevelUp), + // BlockEmitter::Grass => Some(SfxEvent::Roll), + // BlockEmitter::Embers => Some(SfxEvent::Roll), + // BlockEmitter::Beehives => Some(SfxEvent::Roll), + // BlockEmitter::Reeds => Some(SfxEvent::Roll), + // BlockEmitter::Flowers => Some(SfxEvent::Roll), + // }; + + // sfx_event + // } else { + // None + // } + //} } diff --git a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs new file mode 100644 index 0000000000..b86640c5db --- /dev/null +++ b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs @@ -0,0 +1,72 @@ +/// EventMapper::Campfire maps sfx to campfires +use crate::{ + audio::sfx::{SfxEvent, SfxEventItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, + scene::{Camera, Terrain}, +}; + +use super::EventMapper; + +use common::{ + comp::{object, Body, Pos}, + event::EventBus, + state::State, + terrain::TerrainChunk, +}; +use specs::{Entity as EcsEntity, Join, WorldExt}; +use std::time::{Duration, Instant}; + +pub struct CampfireEventMapper { + timer: Instant, +} + +impl EventMapper for CampfireEventMapper { + fn maintain( + &mut self, + state: &State, + player_entity: specs::Entity, + camera: &Camera, + triggers: &SfxTriggers, + _terrain: &Terrain, + ) { + let ecs = state.ecs(); + + let sfx_event_bus = ecs.read_resource::>(); + let sfx_emitter = sfx_event_bus.emitter(); + + let focus_off = camera.get_focus_pos().map(f32::trunc); + let cam_pos = camera.dependents().cam_pos + focus_off; + for (body, pos) in (&ecs.read_storage::(), &ecs.read_storage::()).join() { + match body { + Body::Object(object::Body::CampfireLit) => { + if (pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { + if self.timer.elapsed().as_secs_f32() > 3.0 + /* TODO Replace with sensible time */ + { + self.timer = Instant::now(); + let sfx_trigger_item = triggers.get_trigger(&SfxEvent::LevelUp); + if sfx_trigger_item.is_some() { + println!("sound"); + ecs.read_resource::>().emit_now( + SfxEventItem::new( + SfxEvent::LevelUp.clone(), + Some(pos.0), + Some(0.0), + ), + ); + } + } + } + }, + _ => {}, + } + } + } +} + +impl CampfireEventMapper { + pub fn new() -> Self { + Self { + timer: Instant::now(), + } + } +} diff --git a/voxygen/src/audio/sfx/event_mapper/mod.rs b/voxygen/src/audio/sfx/event_mapper/mod.rs index a9f5dd9e9d..c414d0c6af 100644 --- a/voxygen/src/audio/sfx/event_mapper/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/mod.rs @@ -1,4 +1,5 @@ mod block; +//mod campfire; mod combat; mod movement; mod progression; @@ -6,6 +7,7 @@ mod progression; use common::{state::State, terrain::TerrainChunk}; use block::BlockEventMapper; +//use campfire::CampfireEventMapper; use combat::CombatEventMapper; use movement::MovementEventMapper; use progression::ProgressionEventMapper; @@ -36,6 +38,7 @@ impl SfxEventMapper { Box::new(MovementEventMapper::new()), Box::new(ProgressionEventMapper::new()), Box::new(BlockEventMapper::new()), + //Box::new(CampfireEventMapper::new()), ], } } diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 9b424a163b..ee592bb9c9 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -135,6 +135,7 @@ impl SfxEventItem { #[derive(Clone, Debug, PartialEq, Deserialize, Hash, Eq)] pub enum SfxEvent { + Embers, Idle, Run, Roll, From aa6b7cbb6510b090e019b9c28ef4885619c8ebe5 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Thu, 29 Oct 2020 00:39:17 -0700 Subject: [PATCH 06/37] Bird calls from trees --- assets/voxygen/audio/sfx.ron | 8 + .../voxygen/audio/sfx/ambient/birdcall_1.wav | 3 + .../voxygen/audio/sfx/ambient/birdcall_2.wav | 3 + .../voxygen/audio/sfx/ambient/birdcall_3.wav | 3 + voxygen/src/audio/mod.rs | 177 +++++++++--------- .../src/audio/sfx/event_mapper/block/mod.rs | 42 +++-- voxygen/src/audio/sfx/mod.rs | 1 + voxygen/src/scene/mod.rs | 8 +- 8 files changed, 134 insertions(+), 111 deletions(-) create mode 100644 assets/voxygen/audio/sfx/ambient/birdcall_1.wav create mode 100644 assets/voxygen/audio/sfx/ambient/birdcall_2.wav create mode 100644 assets/voxygen/audio/sfx/ambient/birdcall_3.wav diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 5d8aedfc9e..9a885fac41 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -9,6 +9,14 @@ ], threshold: 1.2, ), + Birdcall: ( + files: [ + "voxygen.audio.sfx.ambient.birdcall_1", + "voxygen.audio.sfx.ambient.birdcall_2", + "voxygen.audio.sfx.ambient.birdcall_3", + ], + threshold: 30.0, + ), // // Character States // diff --git a/assets/voxygen/audio/sfx/ambient/birdcall_1.wav b/assets/voxygen/audio/sfx/ambient/birdcall_1.wav new file mode 100644 index 0000000000..175f7e8fa9 --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/birdcall_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eff53828813ed459df17f76cfe24057c601c839a99936ce64f1728e1e82728bb +size 1306004 diff --git a/assets/voxygen/audio/sfx/ambient/birdcall_2.wav b/assets/voxygen/audio/sfx/ambient/birdcall_2.wav new file mode 100644 index 0000000000..c6249782b0 --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/birdcall_2.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0359f1387f257c04ba0e01d1f94ecc68bd9606fccb996555629bea782f58ab2b +size 2038924 diff --git a/assets/voxygen/audio/sfx/ambient/birdcall_3.wav b/assets/voxygen/audio/sfx/ambient/birdcall_3.wav new file mode 100644 index 0000000000..615d6ba075 --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/birdcall_3.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5494c1f8e30c0b3fd686ae2c93ece3c145a83bff221801bc3de3eb37ac2d034 +size 1162164 diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index fdea2b5216..93be825ed0 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -1,6 +1,6 @@ //! Handles audio device detection and playback of sound effects and music -pub mod ambient; +//pub mod ambient; pub mod channel; pub mod fader; pub mod music; @@ -39,12 +39,10 @@ pub struct AudioFrontend { music_channels: Vec, sfx_channels: Vec, - ambient_channels: Vec, - + //ambient_channels: Vec, sfx_volume: f32, music_volume: f32, - ambient_volume: f32, - + //ambient_volume: f32, listener: Listener, } @@ -64,12 +62,11 @@ impl AudioFrontend { audio_device, sound_cache: SoundCache::default(), music_channels: Vec::new(), - ambient_channels: Vec::new(), + //ambient_channels: Vec::new(), sfx_channels, sfx_volume: 1.0, music_volume: 1.0, - ambient_volume: 1.0, - + //ambient_volume: 1.0, listener: Listener::default(), } } @@ -82,11 +79,11 @@ impl AudioFrontend { audio_device: None, sound_cache: SoundCache::default(), music_channels: Vec::new(), - ambient_channels: Vec::new(), + //ambient_channels: Vec::new(), sfx_channels: Vec::new(), sfx_volume: 1.0, music_volume: 1.0, - ambient_volume: 1.0, + //ambient_volume: 1.0, listener: Listener::default(), } } @@ -94,15 +91,15 @@ impl AudioFrontend { /// Drop any unused music channels, and update their faders pub fn maintain(&mut self, dt: Duration) { self.music_channels.retain(|c| !c.is_done()); - self.ambient_channels.retain(|c| !c.is_done()); + //self.ambient_channels.retain(|c| !c.is_done()); for channel in self.music_channels.iter_mut() { channel.maintain(dt); } - for channel in self.ambient_channels.iter_mut() { - channel.maintain(dt); - } + //for channel in self.ambient_channels.iter_mut() { + // channel.maintain(dt); + //} } fn get_sfx_channel(&mut self) -> Option<&mut SfxChannel> { @@ -153,34 +150,37 @@ impl AudioFrontend { self.music_channels.last_mut() } - fn get_ambient_channel( - &mut self, - next_channel_tag: AmbientChannelTag, - ) -> Option<&mut AmbientChannel> { - if let Some(audio_device) = &self.audio_device { - if self.ambient_channels.is_empty() { - let mut next_ambient_channel = AmbientChannel::new(&audio_device); - next_ambient_channel.set_volume(self.ambient_volume); + //fn get_ambient_channel( + // &mut self, + // next_channel_tag: AmbientChannelTag, + //) -> Option<&mut AmbientChannel> { + // if let Some(audio_device) = &self.audio_device { + // if self.ambient_channels.is_empty() { + // let mut next_ambient_channel = AmbientChannel::new(&audio_device); + // next_ambient_channel.set_volume(self.music_volume); - self.ambient_channels.push(next_ambient_channel); - } else { - let existing_channel = self.ambient_channels.last_mut()?; + // self.ambient_channels.push(next_ambient_channel); + // } else { + // let existing_channel = self.ambient_channels.last_mut()?; - if existing_channel.get_tag() != next_channel_tag { - // Fade the existing channel out. It will be removed when the fade completes. - existing_channel.set_fader(Fader::fade_out(2.0, self.ambient_volume)); + // if existing_channel.get_tag() != next_channel_tag { + // // Fade the existing channel out. It will be removed when the + // fade completes. + // existing_channel.set_fader(Fader::fade_out(2.0, self.music_volume)); - let mut next_ambient_channel = AmbientChannel::new(&audio_device); + // let mut next_ambient_channel = + // AmbientChannel::new(&audio_device); - next_ambient_channel.set_fader(Fader::fade_in(12.0, self.ambient_volume)); + // next_ambient_channel.set_fader(Fader::fade_in(12.0, + // self.music_volume)); - self.ambient_channels.push(next_ambient_channel); - } - } - } + // self.ambient_channels.push(next_ambient_channel); + // } + // } + // } - self.ambient_channels.last_mut() - } + // self.ambient_channels.last_mut() + //} /// Play (once) an sfx file by file path at the give position and volume pub fn play_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { @@ -228,34 +228,35 @@ impl AudioFrontend { } } - fn stop_ambient(&mut self, channel_tag: AmbientChannelTag) { - if let Some(channel) = self.get_ambient_channel(channel_tag) { - channel.stop(channel_tag); - } - } + //fn stop_ambient(&mut self, channel_tag: AmbientChannelTag) { + // if let Some(channel) = self.get_ambient_channel(channel_tag) { + // channel.stop(channel_tag); + // } + //} - fn fade_out_ambient(&mut self, channel_tag: AmbientChannelTag) { - let ambient_volume = self.ambient_volume; - if let Some(channel) = self.get_ambient_channel(channel_tag) { - channel.set_fader(Fader::fade_out(2.0, ambient_volume)); - } - } + //fn fade_out_ambient(&mut self, channel_tag: AmbientChannelTag) { + // let music_volume = self.music_volume; + // if let Some(channel) = self.get_ambient_channel(channel_tag) { + // channel.set_fader(Fader::fade_out(2.0, music_volume)); + // } + //} - fn fade_in_ambient(&mut self, channel_tag: AmbientChannelTag) { - let ambient_volume = self.ambient_volume; - if let Some(channel) = self.get_ambient_channel(channel_tag) { - channel.set_fader(Fader::fade_in(2.0, ambient_volume)); - } - } + //fn fade_in_ambient(&mut self, channel_tag: AmbientChannelTag) { + // let music_volume = self.music_volume; + // if let Some(channel) = self.get_ambient_channel(channel_tag) { + // channel.set_fader(Fader::fade_in(2.0, music_volume)); + // } + //} - fn play_ambient(&mut self, sound: &str, channel_tag: AmbientChannelTag) { - if let Some(channel) = self.get_ambient_channel(channel_tag) { - let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); - let sound = Decoder::new(file).expect("Failed to decode sound"); + //fn play_ambient(&mut self, sound: &str, channel_tag: AmbientChannelTag) { + // if let Some(channel) = self.get_ambient_channel(channel_tag) { + // let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load + // sound"); let sound = Decoder::new(file).expect("Failed to decode + // sound"); - channel.play(sound, channel_tag); - } - } + // channel.play(sound, channel_tag); + // } + //} pub fn set_listener_pos(&mut self, pos: Vec3, ori: Vec3) { self.listener.pos = pos; @@ -307,41 +308,41 @@ impl AudioFrontend { } } - pub fn play_exploration_ambient(&mut self, item: &str) { - if self.music_enabled() { - self.play_ambient(item, AmbientChannelTag::Exploration) - } - } + //pub fn play_exploration_ambient(&mut self, item: &str) { + // if self.music_enabled() { + // self.play_ambient(item, AmbientChannelTag::Exploration) + // } + //} - pub fn fade_out_exploration_ambient(&mut self) { - if self.music_enabled() { - self.fade_out_ambient(AmbientChannelTag::Exploration) - } - } + //pub fn fade_out_exploration_ambient(&mut self) { + // if self.music_enabled() { + // self.fade_out_ambient(AmbientChannelTag::Exploration) + // } + //} - pub fn fade_in_exploration_ambient(&mut self) { - if self.music_enabled() { - self.fade_in_ambient(AmbientChannelTag::Exploration) - } - } + //pub fn fade_in_exploration_ambient(&mut self) { + // if self.music_enabled() { + // self.fade_in_ambient(AmbientChannelTag::Exploration) + // } + //} - pub fn stop_exploration_ambient(&mut self) { - if self.music_enabled() { - self.stop_ambient(AmbientChannelTag::Exploration) - } - } + //pub fn stop_exploration_ambient(&mut self) { + // if self.music_enabled() { + // self.stop_ambient(AmbientChannelTag::Exploration) + // } + //} pub fn get_sfx_volume(&self) -> f32 { self.sfx_volume } pub fn get_music_volume(&self) -> f32 { self.music_volume } - pub fn get_ambient_volume(&self) -> f32 { self.ambient_volume } + //pub fn get_ambient_volume(&self) -> f32 { self.music_volume } pub fn sfx_enabled(&self) -> bool { self.sfx_volume > 0.0 } pub fn music_enabled(&self) -> bool { self.music_volume > 0.0 } - pub fn ambient_enabled(&self) -> bool { self.ambient_volume > 0.0 } + //pub fn ambient_enabled(&self) -> bool { self.music_volume > 0.0 } pub fn set_sfx_volume(&mut self, sfx_volume: f32) { self.sfx_volume = sfx_volume; @@ -359,13 +360,13 @@ impl AudioFrontend { } } - pub fn set_ambient_volume(&mut self, ambient_volume: f32) { - self.ambient_volume = ambient_volume; + //pub fn set_ambient_volume(&mut self, ambient_volume: f32) { + // self.music_volume = ambient_volume; - for channel in self.ambient_channels.iter_mut() { - channel.set_volume(ambient_volume); - } - } + // for channel in self.ambient_channels.iter_mut() { + // channel.set_volume(ambient_volume); + // } + //} // TODO: figure out how badly this will break things when it is called pub fn set_device(&mut self, name: String) { diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index 6ff7c40d10..ed9130dc55 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -11,7 +11,7 @@ use common::{ vol::RectRasterableVol, }; use hashbrown::HashMap; -use rand::{prelude::SliceRandom, thread_rng}; +use rand::{prelude::SliceRandom, thread_rng, Rng}; use specs::WorldExt; use std::time::Instant; use vek::*; @@ -41,7 +41,7 @@ impl Default for PreviousBlockState { } impl PreviousBlockState { - fn new(event: SfxEvent, pos: Vec3) -> Self { + fn new(event: SfxEvent) -> Self { PreviousBlockState { event, time: Instant::now(), @@ -84,8 +84,6 @@ impl EventMapper for BlockEventMapper { blocks: fn(&'a BlocksOfInterest) -> &'a [Vec3], // The range, in chunks, that the particles should be generated in from the player range: usize, - // The spacing between sfx, per block, seconds - spacing: f32, // The sound of the generated particle sfx: SfxEvent, // The volume of the sfx @@ -94,20 +92,18 @@ impl EventMapper for BlockEventMapper { cond: fn(&State) -> bool, } let sounds: &[BlockSounds] = &[ - //BlockSounds { - // blocks: |boi| &boi.leaves, - // range: 4, - // spacing: 1.5, - // sfx: SfxEvent::LevelUp, - // volume: 1.0 - // cond: |_| true, - //}, + BlockSounds { + blocks: |boi| &boi.leaves, + range: 1, + sfx: SfxEvent::Birdcall, + volume: 1.0, + cond: |_| true, + }, BlockSounds { blocks: |boi| &boi.embers, - range: 3, - spacing: 1.2, + range: 1, sfx: SfxEvent::Embers, - volume: 0.5, + volume: 0.05, //volume: 0.05, cond: |_| true, //cond: |st| st.get_day_period().is_dark(), @@ -148,13 +144,13 @@ impl EventMapper for BlockEventMapper { // cond: |_| true, //}, ]; - let mut rng = thread_rng(); // Iterate through each kind of block of interest for sounds in sounds.iter() { if !(sounds.cond)(state) { continue; } + // For chunks surrounding the player position for offset in Spiral2d::new().take((sounds.range * 2 + 1).pow(2)) { let chunk_pos = player_chunk + offset; @@ -169,6 +165,11 @@ impl EventMapper for BlockEventMapper { // Iterate through each individual block for block in blocks { + // Reduce the number of bird calls from trees + if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen::() < 0.25 { + continue; + } + let block_pos: Vec3 = absolute_pos + block; let state = self.history.entry(block_pos).or_default(); @@ -180,9 +181,12 @@ impl EventMapper for BlockEventMapper { ); if Self::should_emit(state, triggers.get_key_value(&sounds.sfx)) { - sfx_emitter.emit(SfxEventItem::new(sounds.sfx.clone(), Some(block_pos), Some(sounds.volume))); - state.time = Instant::now(); - state.event = sounds.sfx.clone(); + // If the camera is within SFX distance + if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { + sfx_emitter.emit(SfxEventItem::new(sounds.sfx.clone(), Some(block_pos), Some(sounds.volume))); + state.time = Instant::now(); + state.event = sounds.sfx.clone(); + } } } diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index ee592bb9c9..d7288f1cb3 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -136,6 +136,7 @@ impl SfxEventItem { #[derive(Clone, Debug, PartialEq, Deserialize, Hash, Eq)] pub enum SfxEvent { Embers, + Birdcall, Idle, Run, Roll, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 717738ec2e..cbbdd7fc9c 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -14,7 +14,7 @@ pub use self::{ terrain::Terrain, }; use crate::{ - audio::{ambient::AmbientMgr, music::MusicMgr, sfx::SfxMgr, AudioFrontend}, + audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend}, render::{ create_clouds_mesh, create_pp_mesh, create_skybox_mesh, CloudsLocals, CloudsPipeline, Consts, GlobalModel, Globals, Light, LodData, Model, PostProcessLocals, @@ -103,7 +103,7 @@ pub struct Scene { figure_mgr: FigureMgr, sfx_mgr: SfxMgr, music_mgr: MusicMgr, - ambient_mgr: AmbientMgr, + //ambient_mgr: AmbientMgr, } pub struct SceneData<'a> { @@ -309,7 +309,7 @@ impl Scene { figure_mgr: FigureMgr::new(renderer), sfx_mgr: SfxMgr::new(), music_mgr: MusicMgr::new(), - ambient_mgr: AmbientMgr::new(), + //ambient_mgr: AmbientMgr::new(), } } @@ -999,7 +999,7 @@ impl Scene { &self.terrain, ); self.music_mgr.maintain(audio, scene_data.state, client); - self.ambient_mgr.maintain(audio, scene_data.state, client); + //self.ambient_mgr.maintain(audio, scene_data.state, client); } /// Render the scene using the provided `Renderer`. From 3169562a8086ef683e00ee5c9425f6dfe8137c08 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Thu, 29 Oct 2020 23:53:15 -0700 Subject: [PATCH 07/37] Night time sfx and swimming --- assets/voxygen/audio/sfx.ron | 27 ++++++++ assets/voxygen/audio/sfx/ambient/bees_1.wav | 3 + .../voxygen/audio/sfx/ambient/crickets_1.wav | 3 + assets/voxygen/audio/sfx/ambient/embers.wav | 2 +- .../audio/sfx/ambient/frog_croak_1.wav | 3 + .../audio/sfx/footsteps/water_splash_1.wav | 4 +- .../audio/sfx/footsteps/water_splash_2.wav | 4 +- .../audio/sfx/footsteps/water_splash_3.wav | 4 +- .../audio/sfx/footsteps/water_splash_4.wav | 4 +- .../src/audio/sfx/event_mapper/block/mod.rs | 69 ++++++++++--------- .../audio/sfx/event_mapper/movement/mod.rs | 17 ++++- voxygen/src/audio/sfx/mod.rs | 4 ++ 12 files changed, 102 insertions(+), 42 deletions(-) create mode 100644 assets/voxygen/audio/sfx/ambient/bees_1.wav create mode 100644 assets/voxygen/audio/sfx/ambient/crickets_1.wav create mode 100644 assets/voxygen/audio/sfx/ambient/frog_croak_1.wav diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 9a885fac41..b7a3e3ab4c 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -17,9 +17,36 @@ ], threshold: 30.0, ), + Cricket: ( + files: [ + "voxygen.audio.sfx.ambient.crickets_1", + ], + threshold: 3.0, + ), + Frog: ( + files: [ + "voxygen.audio.sfx.ambient.frog_croak_1", + ], + threshold: 4.0, + ), + Bees: ( + files: [ + "voxygen.audio.sfx.ambient.bees_1", + ], + threshold: 15.0, + ), // // Character States // + Swim: ( + files: [ + "voxygen.audio.sfx.footsteps.water_splash_1", + "voxygen.audio.sfx.footsteps.water_splash_2", + "voxygen.audio.sfx.footsteps.water_splash_3", + "voxygen.audio.sfx.footsteps.water_splash_4", + ], + threshold: 0.25, + ), Run: ( files: [ "voxygen.audio.sfx.footsteps.stepgrass_1", diff --git a/assets/voxygen/audio/sfx/ambient/bees_1.wav b/assets/voxygen/audio/sfx/ambient/bees_1.wav new file mode 100644 index 0000000000..54643ce225 --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/bees_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79cba70909371875bb6199355397096c2345d6e12512a83cdcf0d33b34928b78 +size 2642668 diff --git a/assets/voxygen/audio/sfx/ambient/crickets_1.wav b/assets/voxygen/audio/sfx/ambient/crickets_1.wav new file mode 100644 index 0000000000..0da586731e --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/crickets_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b36412b86538f64041720a8a46e25426087713badd577b358d976bc812488cb7 +size 80192 diff --git a/assets/voxygen/audio/sfx/ambient/embers.wav b/assets/voxygen/audio/sfx/ambient/embers.wav index 9d999a5022..dd3450abef 100644 --- a/assets/voxygen/audio/sfx/ambient/embers.wav +++ b/assets/voxygen/audio/sfx/ambient/embers.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc2a7234fb92b3395b43fc279d2a553b1c9b3e093f8f5d3aad98af4a27bcfbdd +oid sha256:596c20b9b9cffed74274bac3bf22f7868f1adaf3a1780af7897c06b058f1cb94 size 217472 diff --git a/assets/voxygen/audio/sfx/ambient/frog_croak_1.wav b/assets/voxygen/audio/sfx/ambient/frog_croak_1.wav new file mode 100644 index 0000000000..e399bc3d21 --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/frog_croak_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:239c4895cbb65d42d1bc02d3570c4cacaf194dd37d92c414810bed36b69eacae +size 48902 diff --git a/assets/voxygen/audio/sfx/footsteps/water_splash_1.wav b/assets/voxygen/audio/sfx/footsteps/water_splash_1.wav index 2cb522a9a3..c5451a1418 100644 --- a/assets/voxygen/audio/sfx/footsteps/water_splash_1.wav +++ b/assets/voxygen/audio/sfx/footsteps/water_splash_1.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4908be3241c984445d84643abaefaf1c388435bda15ef77f0302347024377f09 -size 319548 +oid sha256:13a2902c0a05d305f0a16ac109ba3104608e590983c81216037dfd44e7e3ff27 +size 213136 diff --git a/assets/voxygen/audio/sfx/footsteps/water_splash_2.wav b/assets/voxygen/audio/sfx/footsteps/water_splash_2.wav index 3d583cfe44..6bcedebdc3 100644 --- a/assets/voxygen/audio/sfx/footsteps/water_splash_2.wav +++ b/assets/voxygen/audio/sfx/footsteps/water_splash_2.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21a794b36ca1a023f1b5175c81df21e71f46cdcbd68cd3d4faeec730c5103ed0 -size 398810 +oid sha256:6536fc3a8f4065099fc5d99c1ce215e6c6624bf20b96900aa2e298d3ae5485cc +size 266056 diff --git a/assets/voxygen/audio/sfx/footsteps/water_splash_3.wav b/assets/voxygen/audio/sfx/footsteps/water_splash_3.wav index 052db7451b..10af299e2c 100644 --- a/assets/voxygen/audio/sfx/footsteps/water_splash_3.wav +++ b/assets/voxygen/audio/sfx/footsteps/water_splash_3.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9b82e87e42b2e2b6a24d7284a1d763d6cde9dee3733b0b9aeba5c5bc41b78639 -size 240050 +oid sha256:0a838a67b35e1bc2ead97dcf00670038067730a0c54e7f721c37e8bbf11164ea +size 160216 diff --git a/assets/voxygen/audio/sfx/footsteps/water_splash_4.wav b/assets/voxygen/audio/sfx/footsteps/water_splash_4.wav index 1220d4eef2..dd52365f19 100644 --- a/assets/voxygen/audio/sfx/footsteps/water_splash_4.wav +++ b/assets/voxygen/audio/sfx/footsteps/water_splash_4.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:832bcacae4a5b0bec39fc46af3ab5d3cb565ee0518a4e1fe63276e4f77bc1524 -size 241700 +oid sha256:e24c9c45c3c7d6f07f2a5c8001e640fc7d962ffc659d3c979d75a347251efca7 +size 161316 diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index ed9130dc55..77eda8ffbb 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -97,7 +97,8 @@ impl EventMapper for BlockEventMapper { range: 1, sfx: SfxEvent::Birdcall, volume: 1.0, - cond: |_| true, + //cond: |_| true, + cond: |st| st.get_day_period().is_light(), }, BlockSounds { blocks: |boi| &boi.embers, @@ -108,41 +109,35 @@ impl EventMapper for BlockEventMapper { cond: |_| true, //cond: |st| st.get_day_period().is_dark(), }, - //BlockSounds { - // blocks: |boi| &boi.reeds, - // range: 4, - // spacing: 2.0, - // sfx: SfxEvent::Run, - // volume: 1.0, - // //cond: |st| st.get_day_period().is_dark(), - // cond: |_| true, - //}, + BlockSounds { + blocks: |boi| &boi.reeds, + range: 1, + sfx: SfxEvent::Frog, + volume: 0.8, + cond: |st| st.get_day_period().is_dark(), + //cond: |_| true, + }, //BlockSounds { // blocks: |boi| &boi.flowers, // range: 4, - // spacing: 2.5, // sfx: SfxEvent::LevelUp, // volume: 1.0, // cond: |st| st.get_day_period().is_dark(), //}, - //BlockSounds { - // blocks: |boi| &boi.grass, - // range: 4, - // spacing: 2.5, - // sfx: SfxEvent::Roll, - // volume: 1.0, - // //cond: |st| st.get_day_period().is_light(), - // cond: |_| false, - //}, - //BlockSounds { - // blocks: |boi| &boi.beehives, - // range: 4, - // spacing: 1.5, - // sfx: SfxEvent::Roll, - // volume: 1.0, - // //cond: |st| st.get_day_period().is_light(), - // cond: |_| true, - //}, + BlockSounds { + blocks: |boi| &boi.grass, + range: 1, + sfx: SfxEvent::Cricket, + volume: 0.5, + cond: |st| st.get_day_period().is_dark(), + }, + BlockSounds { + blocks: |boi| &boi.beehives, + range: 1, + sfx: SfxEvent::Bees, + volume: 1.0, + cond: |_| true, + }, ]; // Iterate through each kind of block of interest @@ -166,7 +161,10 @@ impl EventMapper for BlockEventMapper { // Iterate through each individual block for block in blocks { // Reduce the number of bird calls from trees - if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen::() < 0.25 { + if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen::() > 0.05 { + println!("skipped a bird"); + continue; + } else if sounds.sfx == SfxEvent::Cricket && thread_rng().gen::() > 0.5 { continue; } @@ -252,7 +250,16 @@ impl BlockEventMapper { ) -> bool { if let Some((event, item)) = sfx_trigger_item { if &previous_state.event == event { - previous_state.time.elapsed().as_secs_f64() >= item.threshold + if event == &SfxEvent::Birdcall { + if thread_rng().gen_bool(0.5) { + previous_state.time.elapsed().as_secs_f64() + >= (item.threshold + thread_rng().gen_range(-3.0, 3.0)) + } else { + false + } + } else { + previous_state.time.elapsed().as_secs_f64() >= item.threshold + } } else { true } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index ee02996ed7..6c29dc4a89 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -22,6 +22,7 @@ struct PreviousEntityState { event: SfxEvent, time: Instant, on_ground: bool, + in_water: bool, } impl Default for PreviousEntityState { @@ -30,6 +31,7 @@ impl Default for PreviousEntityState { event: SfxEvent::Idle, time: Instant::now(), on_ground: true, + in_water: false, } } } @@ -95,6 +97,11 @@ impl EventMapper for MovementEventMapper { // it was dispatched state.event = mapped_event; state.on_ground = physics.on_ground; + if physics.in_fluid.is_some() { + state.in_water = true; + } else { + state.in_water = false; + } } } @@ -156,8 +163,14 @@ impl MovementEventMapper { previous_state: &PreviousEntityState, vel: Vec3, ) -> SfxEvent { - // Match run / roll state - if physics_state.on_ground && vel.magnitude() > 0.1 + // Match run / roll / swim state + if physics_state.in_fluid.is_some() + && physics_state.in_fluid.unwrap() < 2.0 + && vel.magnitude() > 0.1 + || !previous_state.in_water && physics_state.in_fluid.is_some() + { + return SfxEvent::Swim; + } else if physics_state.on_ground && vel.magnitude() > 0.1 || !previous_state.on_ground && physics_state.on_ground { return if matches!(character_state, CharacterState::Roll(_)) { diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index d7288f1cb3..1bc35411c4 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -137,7 +137,11 @@ impl SfxEventItem { pub enum SfxEvent { Embers, Birdcall, + Cricket, + Frog, + Bees, Idle, + Swim, Run, Roll, Sneak, From c6a443ac0fbdcd07840f2af148ea987fd0ad25ca Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Fri, 30 Oct 2020 11:15:30 -0700 Subject: [PATCH 08/37] fixed false audio track lengths --- assets/voxygen/audio/soundtrack/a_solemn_quest.ogg | 4 ++-- assets/voxygen/audio/soundtrack/between_the_fairies.ogg | 4 ++-- assets/voxygen/audio/soundtrack/campfire_stories.ogg | 4 ++-- assets/voxygen/audio/soundtrack/down_the_rabbit_hole.ogg | 4 ++-- assets/voxygen/audio/soundtrack/field_grazing.ogg | 4 ++-- assets/voxygen/audio/soundtrack/into_the_dark_forest.ogg | 4 ++-- assets/voxygen/audio/soundtrack/just_the_beginning.ogg | 4 ++-- assets/voxygen/audio/soundtrack/limits.ogg | 4 ++-- assets/voxygen/audio/soundtrack/mineral_deposits.ogg | 4 ++-- assets/voxygen/audio/soundtrack/moonbeams.ogg | 4 ++-- assets/voxygen/audio/soundtrack/rest_assured.ogg | 4 ++-- assets/voxygen/audio/soundtrack/serene_meadows.ogg | 4 ++-- assets/voxygen/audio/soundtrack/snowtop_volume.ogg | 4 ++-- assets/voxygen/audio/soundtrack/veloren_title_tune.ogg | 4 ++-- assets/voxygen/audio/soundtrack/wandering_voices.ogg | 4 ++-- 15 files changed, 30 insertions(+), 30 deletions(-) diff --git a/assets/voxygen/audio/soundtrack/a_solemn_quest.ogg b/assets/voxygen/audio/soundtrack/a_solemn_quest.ogg index f3e7b16c95..33a2cf5e4e 100644 --- a/assets/voxygen/audio/soundtrack/a_solemn_quest.ogg +++ b/assets/voxygen/audio/soundtrack/a_solemn_quest.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03d18d9709710be041d9426681e3c43add2482fcb5075dbd67dbb0ef2c8c5132 -size 11626250 +oid sha256:41a51f0a0cc43ae76d7c372d6392a8d128979dcf542b14244479e6f00a2a480b +size 3662863 diff --git a/assets/voxygen/audio/soundtrack/between_the_fairies.ogg b/assets/voxygen/audio/soundtrack/between_the_fairies.ogg index 268ae9ac9d..ac76bcf4d1 100644 --- a/assets/voxygen/audio/soundtrack/between_the_fairies.ogg +++ b/assets/voxygen/audio/soundtrack/between_the_fairies.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de8949c0e815d5f9811a93d97198a7d92460f3cc50d7222f5972f5c12c16c949 -size 3812226 +oid sha256:01a8d1a67fb0b60e0eb14a3f768cfd5d5b073fe2ecf952cd85468406e33240e9 +size 2870126 diff --git a/assets/voxygen/audio/soundtrack/campfire_stories.ogg b/assets/voxygen/audio/soundtrack/campfire_stories.ogg index 4b6bf49c6c..ae56af47b4 100644 --- a/assets/voxygen/audio/soundtrack/campfire_stories.ogg +++ b/assets/voxygen/audio/soundtrack/campfire_stories.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c635e91c3e2cef6e42c529ee52a03e59b606d37cbd242c77a6e77e9e6170b54 -size 2120441 +oid sha256:66a5159174d17727622a35ac8430cc88923662f36584ca9b3fba07f74cdad300 +size 1616058 diff --git a/assets/voxygen/audio/soundtrack/down_the_rabbit_hole.ogg b/assets/voxygen/audio/soundtrack/down_the_rabbit_hole.ogg index 3a4e0cb140..4ecba0dfd8 100644 --- a/assets/voxygen/audio/soundtrack/down_the_rabbit_hole.ogg +++ b/assets/voxygen/audio/soundtrack/down_the_rabbit_hole.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1dc958d540b0f7127599f8e715a316ebfb8b58dc15792a6e6512ca297df3446 -size 4538935 +oid sha256:f96cda2bdcb40f60ede7539e5a838604f8c5ac43063056b2fffb68324115deed +size 3819981 diff --git a/assets/voxygen/audio/soundtrack/field_grazing.ogg b/assets/voxygen/audio/soundtrack/field_grazing.ogg index a41f231a5b..363e5450a8 100644 --- a/assets/voxygen/audio/soundtrack/field_grazing.ogg +++ b/assets/voxygen/audio/soundtrack/field_grazing.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af0f5a347fcd788f602b8d8988bac5c8faf32b44576721723f2b196f6b7474c3 -size 8438062 +oid sha256:1ed4f4e2617060e6de8de218a6d139ac556b886ea458e706226646a661f1f7cf +size 2924974 diff --git a/assets/voxygen/audio/soundtrack/into_the_dark_forest.ogg b/assets/voxygen/audio/soundtrack/into_the_dark_forest.ogg index 5a0940cc8f..634446e8fe 100644 --- a/assets/voxygen/audio/soundtrack/into_the_dark_forest.ogg +++ b/assets/voxygen/audio/soundtrack/into_the_dark_forest.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bd2524122e4067b2e3ef2471e2233c1f21e2ed16a468ebcf3f45a9a6ba55a89 -size 10383401 +oid sha256:bb72527a937cdfe7bbbf663c6eed9e9770ba85ece796bdf2175ba615cf8a504f +size 3202814 diff --git a/assets/voxygen/audio/soundtrack/just_the_beginning.ogg b/assets/voxygen/audio/soundtrack/just_the_beginning.ogg index 7468492ba1..b96429aa89 100644 --- a/assets/voxygen/audio/soundtrack/just_the_beginning.ogg +++ b/assets/voxygen/audio/soundtrack/just_the_beginning.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:194e5f3ad9b2826c6ff188b248d7ab12c5ac6554d41acf1c25a4480745a98509 -size 4674700 +oid sha256:1e7ab1da4b606e46bf6f8476a85852c12420ea2bcb1260a7dfb416fba45c35c4 +size 3029482 diff --git a/assets/voxygen/audio/soundtrack/limits.ogg b/assets/voxygen/audio/soundtrack/limits.ogg index 5f96e7d0ff..87b4a4ec49 100644 --- a/assets/voxygen/audio/soundtrack/limits.ogg +++ b/assets/voxygen/audio/soundtrack/limits.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a7fb11c0b881746f574589d951ea5f2c2d0fb0ab18a80ec4931d4f090b58a57 -size 3507541 +oid sha256:394b95004942f260fa2ddc573d1c64142ab2b7446939886ffb6bcdfc30a83756 +size 3057813 diff --git a/assets/voxygen/audio/soundtrack/mineral_deposits.ogg b/assets/voxygen/audio/soundtrack/mineral_deposits.ogg index 65158dedcb..68395464f6 100644 --- a/assets/voxygen/audio/soundtrack/mineral_deposits.ogg +++ b/assets/voxygen/audio/soundtrack/mineral_deposits.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b6ea514983932b234b5284b3a9358efa9e3d154aa6cdd634e9a9aec889c9bfd -size 8149944 +oid sha256:e48b383e9ffedbf57544a34de87e2e5bb8be6a349e520b93be1cf55180d27c13 +size 2637115 diff --git a/assets/voxygen/audio/soundtrack/moonbeams.ogg b/assets/voxygen/audio/soundtrack/moonbeams.ogg index bc72aa8fc6..eb1d0a2d8a 100644 --- a/assets/voxygen/audio/soundtrack/moonbeams.ogg +++ b/assets/voxygen/audio/soundtrack/moonbeams.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c0c563ca638d52ce801b439bb04c5244fd722fe2184497ac7476cc5eebbffd1 -size 2995303 +oid sha256:c5960253ec1abf308240178b5571b58f18706def3cf5ff4493ffb7cbad6140dc +size 2558857 diff --git a/assets/voxygen/audio/soundtrack/rest_assured.ogg b/assets/voxygen/audio/soundtrack/rest_assured.ogg index aff9541289..3245cddc6e 100644 --- a/assets/voxygen/audio/soundtrack/rest_assured.ogg +++ b/assets/voxygen/audio/soundtrack/rest_assured.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80c606b50aa26100591252ed2d573539faeb301f9d2fdf12ad417812dc074c0c -size 2609469 +oid sha256:0e561cd8bcd46a377a468a851686e24af4f1145d13d2a6936f33857c64b9ca30 +size 2462666 diff --git a/assets/voxygen/audio/soundtrack/serene_meadows.ogg b/assets/voxygen/audio/soundtrack/serene_meadows.ogg index 20419cca99..ca3740f85c 100644 --- a/assets/voxygen/audio/soundtrack/serene_meadows.ogg +++ b/assets/voxygen/audio/soundtrack/serene_meadows.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c38089f9c89fa66cefd89a174239efc24469ff607cb27f297a09931b64798d1 -size 3354481 +oid sha256:9fa39788e7c2f006f2f2d83b3f9527dfe2cc744a19148b6ada1a0b54b2bc1be7 +size 2828061 diff --git a/assets/voxygen/audio/soundtrack/snowtop_volume.ogg b/assets/voxygen/audio/soundtrack/snowtop_volume.ogg index 46fa77d3c0..d991691002 100644 --- a/assets/voxygen/audio/soundtrack/snowtop_volume.ogg +++ b/assets/voxygen/audio/soundtrack/snowtop_volume.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1b85a9cc03e0d8862afe6a0b1428a81c75e31e1fda506d21c5cabbffdd02c83 -size 4722298 +oid sha256:96b7e4ec19089ebc4ee57008c2c2aa1d1d72a52c13764d0c198fcc77b9e75407 +size 1799241 diff --git a/assets/voxygen/audio/soundtrack/veloren_title_tune.ogg b/assets/voxygen/audio/soundtrack/veloren_title_tune.ogg index e51dcda733..37c17ec878 100644 --- a/assets/voxygen/audio/soundtrack/veloren_title_tune.ogg +++ b/assets/voxygen/audio/soundtrack/veloren_title_tune.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:86f5a2d8172203fe8eca0032789b3b4e461f282c1a1443d47056127a590fbbfc -size 2506549 +oid sha256:ed589e262b641285d19ef0a699deeeedc0e126d2ad7b898381739d43dbd998d7 +size 807371 diff --git a/assets/voxygen/audio/soundtrack/wandering_voices.ogg b/assets/voxygen/audio/soundtrack/wandering_voices.ogg index 19ec0e8c6a..7fc29b502e 100644 --- a/assets/voxygen/audio/soundtrack/wandering_voices.ogg +++ b/assets/voxygen/audio/soundtrack/wandering_voices.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78ea14808af79b14e25ca59f5b241cb70ec22903984c0cecc9d6ba75cfcf14cd -size 7598477 +oid sha256:a729163758ca6bc0bb9ef28a0bc4afcae177bf5e7f00f8896396780f53aed2da +size 2515729 From 39d4ee8a96ff704a401cf58b3d763a74ee8e1c29 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sat, 31 Oct 2020 16:41:08 -0700 Subject: [PATCH 09/37] Owls, campfires, and better bird sfx handling --- assets/voxygen/audio/sfx.ron | 16 ++- assets/voxygen/audio/sfx/ambient/embers.wav | 4 +- assets/voxygen/audio/sfx/ambient/fire.wav | 3 + assets/voxygen/audio/sfx/ambient/owl_1.wav | 3 + .../src/audio/sfx/event_mapper/block/mod.rs | 78 +++++++------- .../audio/sfx/event_mapper/campfire/mod.rs | 100 ++++++++++++++---- .../src/audio/sfx/event_mapper/combat/mod.rs | 2 +- voxygen/src/audio/sfx/event_mapper/mod.rs | 6 +- .../audio/sfx/event_mapper/movement/mod.rs | 2 +- voxygen/src/audio/sfx/mod.rs | 2 + 10 files changed, 146 insertions(+), 70 deletions(-) create mode 100644 assets/voxygen/audio/sfx/ambient/fire.wav create mode 100644 assets/voxygen/audio/sfx/ambient/owl_1.wav diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index b7a3e3ab4c..374d65584e 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -3,11 +3,17 @@ // // Ambient // + Campfire: ( + files: [ + "voxygen.audio.sfx.ambient.fire", + ], + threshold: 0.5, + ), Embers: ( files: [ "voxygen.audio.sfx.ambient.embers", ], - threshold: 1.2, + threshold: 0.5, ), Birdcall: ( files: [ @@ -15,7 +21,13 @@ "voxygen.audio.sfx.ambient.birdcall_2", "voxygen.audio.sfx.ambient.birdcall_3", ], - threshold: 30.0, + threshold: 10.0, + ), + Owl: ( + files: [ + "voxygen.audio.sfx.ambient.owl_1", + ], + threshold: 14.0, ), Cricket: ( files: [ diff --git a/assets/voxygen/audio/sfx/ambient/embers.wav b/assets/voxygen/audio/sfx/ambient/embers.wav index dd3450abef..96d5a0a941 100644 --- a/assets/voxygen/audio/sfx/ambient/embers.wav +++ b/assets/voxygen/audio/sfx/ambient/embers.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:596c20b9b9cffed74274bac3bf22f7868f1adaf3a1780af7897c06b058f1cb94 -size 217472 +oid sha256:47d04804be81c882ad5e0314016ab6fb7659d81997ab4bcc5154487b15771dfe +size 372540 diff --git a/assets/voxygen/audio/sfx/ambient/fire.wav b/assets/voxygen/audio/sfx/ambient/fire.wav new file mode 100644 index 0000000000..fc78392d20 --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/fire.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa0da468a1af98a51565f4430bfd5eb3a12db3bce2959c24b0d11b0e99c9c7b7 +size 372540 diff --git a/assets/voxygen/audio/sfx/ambient/owl_1.wav b/assets/voxygen/audio/sfx/ambient/owl_1.wav new file mode 100644 index 0000000000..a6d59653ef --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/owl_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7309844c204faf31bce19d4faf6657018b87fa5b1729f4f2fc4276fa139c6bc2 +size 775048 diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index 77eda8ffbb..051bd7005d 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -11,20 +11,14 @@ use common::{ vol::RectRasterableVol, }; use hashbrown::HashMap; -use rand::{prelude::SliceRandom, thread_rng, Rng}; +use rand::{ + prelude::{IteratorRandom, SliceRandom}, + thread_rng, Rng, +}; use specs::WorldExt; use std::time::Instant; use vek::*; -//enum BlockEmitter { -// Leaves, -// Grass, -// Embers, -// Beehives, -// Reeds, -// Flowers, -//} - #[derive(Clone, PartialEq)] struct PreviousBlockState { event: SfxEvent, @@ -50,8 +44,6 @@ impl PreviousBlockState { } pub struct BlockEventMapper { - timer: Instant, - counter: usize, history: HashMap, PreviousBlockState>, } @@ -88,7 +80,7 @@ impl EventMapper for BlockEventMapper { sfx: SfxEvent, // The volume of the sfx volume: f32, - // Condition that must be true + // Condition that must be true to play cond: fn(&State) -> bool, } let sounds: &[BlockSounds] = &[ @@ -97,14 +89,20 @@ impl EventMapper for BlockEventMapper { range: 1, sfx: SfxEvent::Birdcall, volume: 1.0, - //cond: |_| true, cond: |st| st.get_day_period().is_light(), }, + BlockSounds { + blocks: |boi| &boi.leaves, + range: 1, + sfx: SfxEvent::Owl, + volume: 1.0, + cond: |st| st.get_day_period().is_dark(), + }, BlockSounds { blocks: |boi| &boi.embers, range: 1, sfx: SfxEvent::Embers, - volume: 0.05, + volume: 0.15, //volume: 0.05, cond: |_| true, //cond: |st| st.get_day_period().is_dark(), @@ -136,7 +134,8 @@ impl EventMapper for BlockEventMapper { range: 1, sfx: SfxEvent::Bees, volume: 1.0, - cond: |_| true, + //cond: |_| true, + cond: |st| st.get_day_period().is_light(), }, ]; @@ -144,6 +143,8 @@ impl EventMapper for BlockEventMapper { for sounds in sounds.iter() { if !(sounds.cond)(state) { continue; + } else if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen_bool(0.99) { + continue; } // For chunks surrounding the player position @@ -152,31 +153,37 @@ impl EventMapper for BlockEventMapper { // Get all the blocks of interest in this chunk terrain.get(chunk_pos).map(|chunk_data| { - // Get all the blocks of type sounds + // Get the positions of the blocks of type sounds let blocks = (sounds.blocks)(&chunk_data.blocks_of_interest); + //let mut my_blocks = blocks.to_vec(); + //// Reduce the number of bird calls from trees + //if sounds.sfx == SfxEvent::Birdcall { + // my_blocks = my_blocks.choose_multiple(&mut thread_rng(), 6).cloned().collect(); + // //blocks = blocks.to_vec().choose_multiple(&mut thread_rng(), 6).cloned().collect::>>().as_slice(); + //} else if sounds.sfx == SfxEvent::Cricket { + // my_blocks = my_blocks.choose_multiple(&mut thread_rng(), 6).cloned().collect(); + //} + let absolute_pos: Vec3 = Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)); // Iterate through each individual block for block in blocks { - // Reduce the number of bird calls from trees - if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen::() > 0.05 { - println!("skipped a bird"); - continue; - } else if sounds.sfx == SfxEvent::Cricket && thread_rng().gen::() > 0.5 { - continue; - } + if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen_bool(0.999) { + continue; + } let block_pos: Vec3 = absolute_pos + block; let state = self.history.entry(block_pos).or_default(); // Convert to f32 for sfx emitter - let block_pos = Vec3::new( - block_pos[0] as f32, - block_pos[1] as f32, - block_pos[2] as f32, - ); + //let block_pos = Vec3::new( + // block_pos[0] as f32, + // block_pos[1] as f32, + // block_pos[2] as f32, + //); + let block_pos = block_pos.map(|x| x as f32); if Self::should_emit(state, triggers.get_key_value(&sounds.sfx)) { // If the camera is within SFX distance @@ -238,8 +245,6 @@ impl EventMapper for BlockEventMapper { impl BlockEventMapper { pub fn new() -> Self { Self { - timer: Instant::now(), - counter: 0, history: HashMap::new(), } } @@ -250,16 +255,7 @@ impl BlockEventMapper { ) -> bool { if let Some((event, item)) = sfx_trigger_item { if &previous_state.event == event { - if event == &SfxEvent::Birdcall { - if thread_rng().gen_bool(0.5) { - previous_state.time.elapsed().as_secs_f64() - >= (item.threshold + thread_rng().gen_range(-3.0, 3.0)) - } else { - false - } - } else { - previous_state.time.elapsed().as_secs_f64() >= item.threshold - } + previous_state.time.elapsed().as_secs_f64() >= item.threshold } else { true } diff --git a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs index b86640c5db..a6f6a973d1 100644 --- a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs @@ -1,6 +1,6 @@ /// EventMapper::Campfire maps sfx to campfires use crate::{ - audio::sfx::{SfxEvent, SfxEventItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, + audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, scene::{Camera, Terrain}, }; @@ -12,11 +12,28 @@ use common::{ state::State, terrain::TerrainChunk, }; +use hashbrown::HashMap; use specs::{Entity as EcsEntity, Join, WorldExt}; use std::time::{Duration, Instant}; +#[derive(Clone)] +struct PreviousEntityState { + event: SfxEvent, + time: Instant, +} + +impl Default for PreviousEntityState { + fn default() -> Self { + Self { + event: SfxEvent::Idle, + time: Instant::now(), + } + } +} + pub struct CampfireEventMapper { timer: Instant, + event_history: HashMap, } impl EventMapper for CampfireEventMapper { @@ -31,35 +48,43 @@ impl EventMapper for CampfireEventMapper { let ecs = state.ecs(); let sfx_event_bus = ecs.read_resource::>(); - let sfx_emitter = sfx_event_bus.emitter(); + let mut sfx_emitter = sfx_event_bus.emitter(); let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; - for (body, pos) in (&ecs.read_storage::(), &ecs.read_storage::()).join() { + for (entity, body, pos) in ( + &ecs.entities(), + &ecs.read_storage::(), + &ecs.read_storage::(), + ) + .join() + .filter(|(_, _, e_pos)| (e_pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR) + { match body { Body::Object(object::Body::CampfireLit) => { - if (pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { - if self.timer.elapsed().as_secs_f32() > 3.0 - /* TODO Replace with sensible time */ - { - self.timer = Instant::now(); - let sfx_trigger_item = triggers.get_trigger(&SfxEvent::LevelUp); - if sfx_trigger_item.is_some() { - println!("sound"); - ecs.read_resource::>().emit_now( - SfxEventItem::new( - SfxEvent::LevelUp.clone(), - Some(pos.0), - Some(0.0), - ), - ); - } - } + let state = self.event_history.entry(entity).or_default(); + + let mapped_event = SfxEvent::Campfire; + + // Check for SFX config entry for this movement + if Self::should_emit(state, triggers.get_key_value(&mapped_event)) { + sfx_emitter.emit(SfxEventItem::new( + mapped_event.clone(), + Some(pos.0), + Some(0.25), + )); + + state.time = Instant::now(); } + + // update state to determine the next event. We only record the time (above) if + // it was dispatched + state.event = mapped_event; }, _ => {}, } } + self.cleanup(player_entity); } } @@ -67,6 +92,41 @@ impl CampfireEventMapper { pub fn new() -> Self { Self { timer: Instant::now(), + event_history: HashMap::new(), + } + } + + /// As the player explores the world, we track the last event of the nearby + /// entities to determine the correct SFX item to play next based on + /// their activity. `cleanup` will remove entities from event tracking if + /// they have not triggered an event for > n seconds. This prevents + /// stale records from bloating the Map size. + fn cleanup(&mut self, player: EcsEntity) { + const TRACKING_TIMEOUT: u64 = 10; + + let now = Instant::now(); + self.event_history.retain(|entity, event| { + now.duration_since(event.time) < Duration::from_secs(TRACKING_TIMEOUT) + || entity.id() == player.id() + }); + } + + /// Ensures that: + /// 1. An sfx.ron entry exists for an SFX event + /// 2. The sfx has not been played since it's timeout threshold has elapsed, + /// which prevents firing every tick + fn should_emit( + previous_state: &PreviousEntityState, + sfx_trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>, + ) -> bool { + if let Some((event, item)) = sfx_trigger_item { + if &previous_state.event == event { + previous_state.time.elapsed().as_secs_f64() >= item.threshold + } else { + true + } + } else { + false } } } diff --git a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs index ff2c9b82e6..426a0db6c4 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs @@ -45,7 +45,7 @@ impl EventMapper for CombatEventMapper { player_entity: specs::Entity, camera: &Camera, triggers: &SfxTriggers, - terrain: &Terrain, + _terrain: &Terrain, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/event_mapper/mod.rs b/voxygen/src/audio/sfx/event_mapper/mod.rs index c414d0c6af..a1e2419223 100644 --- a/voxygen/src/audio/sfx/event_mapper/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/mod.rs @@ -1,5 +1,5 @@ mod block; -//mod campfire; +mod campfire; mod combat; mod movement; mod progression; @@ -7,7 +7,7 @@ mod progression; use common::{state::State, terrain::TerrainChunk}; use block::BlockEventMapper; -//use campfire::CampfireEventMapper; +use campfire::CampfireEventMapper; use combat::CombatEventMapper; use movement::MovementEventMapper; use progression::ProgressionEventMapper; @@ -38,7 +38,7 @@ impl SfxEventMapper { Box::new(MovementEventMapper::new()), Box::new(ProgressionEventMapper::new()), Box::new(BlockEventMapper::new()), - //Box::new(CampfireEventMapper::new()), + Box::new(CampfireEventMapper::new()), ], } } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 6c29dc4a89..6cd104c4d3 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -165,7 +165,7 @@ impl MovementEventMapper { ) -> SfxEvent { // Match run / roll / swim state if physics_state.in_fluid.is_some() - && physics_state.in_fluid.unwrap() < 2.0 + //&& physics_state.in_fluid.unwrap() < 2.0 // To control different sound based on depth && vel.magnitude() > 0.1 || !previous_state.in_water && physics_state.in_fluid.is_some() { diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 1bc35411c4..b7992d9bae 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -135,8 +135,10 @@ impl SfxEventItem { #[derive(Clone, Debug, PartialEq, Deserialize, Hash, Eq)] pub enum SfxEvent { + Campfire, Embers, Birdcall, + Owl, Cricket, Frog, Bees, From 0a9f1ee11cf3afc7c39aae73a0c4698f3df560c5 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sat, 31 Oct 2020 18:00:08 -0700 Subject: [PATCH 10/37] Remove ambient channel system in favor of sfx system --- assets/voxygen/audio/ambient.ron | 86 ------- assets/voxygen/audio/ambient/desert_night.ogg | 3 - assets/voxygen/audio/ambient/forest_day.ogg | 3 - .../voxygen/audio/ambient/forest_morning.ogg | 3 - .../voxygen/audio/ambient/grassland_day.ogg | 3 - .../voxygen/audio/ambient/grassland_night.ogg | 3 - assets/voxygen/audio/ambient/jungle_day.ogg | 3 - assets/voxygen/audio/ambient/jungle_night.ogg | 3 - assets/voxygen/audio/ambient/snowlands.ogg | 3 - .../audio/sfx/character/dive_roll_1.wav | 4 +- .../audio/sfx/character/dive_roll_2.wav | 4 +- voxygen/src/audio/ambient.rs | 214 ------------------ voxygen/src/audio/channel.rs | 111 --------- voxygen/src/audio/mod.rs | 112 +-------- .../src/audio/sfx/event_mapper/block/mod.rs | 14 +- .../audio/sfx/event_mapper/campfire/mod.rs | 2 - .../audio/sfx/event_mapper/movement/mod.rs | 2 +- .../audio/sfx/event_mapper/progression/mod.rs | 2 +- 18 files changed, 8 insertions(+), 567 deletions(-) delete mode 100644 assets/voxygen/audio/ambient.ron delete mode 100644 assets/voxygen/audio/ambient/desert_night.ogg delete mode 100644 assets/voxygen/audio/ambient/forest_day.ogg delete mode 100644 assets/voxygen/audio/ambient/forest_morning.ogg delete mode 100644 assets/voxygen/audio/ambient/grassland_day.ogg delete mode 100644 assets/voxygen/audio/ambient/grassland_night.ogg delete mode 100644 assets/voxygen/audio/ambient/jungle_day.ogg delete mode 100644 assets/voxygen/audio/ambient/jungle_night.ogg delete mode 100644 assets/voxygen/audio/ambient/snowlands.ogg delete mode 100644 voxygen/src/audio/ambient.rs diff --git a/assets/voxygen/audio/ambient.ron b/assets/voxygen/audio/ambient.ron deleted file mode 100644 index e6e1432758..0000000000 --- a/assets/voxygen/audio/ambient.ron +++ /dev/null @@ -1,86 +0,0 @@ -// TODO: Add an ambient-soundtrack that runs independently from the musical soundtrack - -( - tracks: [ - ( - title: "Forest Morning", // Ambience Track - path: "voxygen.audio.ambient.forest_morning", - length: 600.0, - timing: Some(Day), - biome: Some(Forest), - artist: "https://www.youtube.com/watch?v=eq4nfIdK6C4", - ), - ( - title: "Crickets and Tawny Owl", // Ambience Track - path: "voxygen.audio.ambient.grassland_night", - length: 141.0, - timing: Some(Night), - biome: Some(Forest), - artist: "https://freesound.org/people/raoul_slayer/sounds/203598/", - ), - //( - // title: "Forest Day", // Ambience Track - // path: "voxygen.audio.ambient.forest_day", - // length: 629.0, - // timing: Some(Night), - // biome: Some(Forest), - // artist: "https://www.youtube.com/watch?v=FwVTkB-BIvM", - //), - ( - title: "Desert Night", // Ambience Track - path: "voxygen.audio.ambient.desert_night", - length: 328.0, - timing: Some(Night), - biome: Some(Desert), - artist: "https://freesound.org/people/kangaroovindaloo/sounds/483550/", - ), - ( - title: "Village Jungle Morning", // Ambience Track - path: "voxygen.audio.ambient.jungle_day", - length: 105.0, - timing: Some(Day), - biome: Some(Swamp), - artist: "https://freesound.org/people/aurelien.leveque/sounds/417635/", - ), - ( - title: "Jungle in Maharashtra at Night", // Ambience Track - path: "voxygen.audio.ambient.jungle_night", - length: 63.0, - timing: Some(Night), - biome: Some(Swamp), - artist: "https://freesound.org/people/Agim/sounds/417872/", - ), - ( - title: "Mountain Glacier Distant", // Ambience Track - path: "voxygen.audio.ambient.snowlands", - length: 22.0, - timing: Some(Day), - biome: Some(Snowlands), - artist: "https://freesound.org/people/Eelke/sounds/462623/", - ), - ( - title: "Mountain Glacier Distant", // Ambience Track - path: "voxygen.audio.ambient.snowlands", - length: 22.0, - timing: Some(Night), - biome: Some(Snowlands), - artist: "https://freesound.org/people/Eelke/sounds/462623/", - ), - ( - title: "Summer Meadow", // Ambience Track - path: "voxygen.audio.ambient.grassland_day", - length: 92.0, - timing: Some(Day), - biome: Some(Grassland), - artist: "https://freesound.org/people/baryy/sounds/409143/", - ), - ( - title: "Crickets and Tawny Owl", // Ambience Track - path: "voxygen.audio.ambient.grassland_night", - length: 141.0, - timing: Some(Night), - biome: Some(Grassland), - artist: "https://freesound.org/people/raoul_slayer/sounds/203598/", - ), - ] -) diff --git a/assets/voxygen/audio/ambient/desert_night.ogg b/assets/voxygen/audio/ambient/desert_night.ogg deleted file mode 100644 index c7b94e73fa..0000000000 --- a/assets/voxygen/audio/ambient/desert_night.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f787ce96814e416c898274abc1b78dca07bbdf0fdc2866b9de9daa354240bcbf -size 6083895 diff --git a/assets/voxygen/audio/ambient/forest_day.ogg b/assets/voxygen/audio/ambient/forest_day.ogg deleted file mode 100644 index ce3a610e52..0000000000 --- a/assets/voxygen/audio/ambient/forest_day.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0b19158db44b60fe3059864c86f9159381871178587514762d6968a64ce25395 -size 9120471 diff --git a/assets/voxygen/audio/ambient/forest_morning.ogg b/assets/voxygen/audio/ambient/forest_morning.ogg deleted file mode 100644 index 69552ad92e..0000000000 --- a/assets/voxygen/audio/ambient/forest_morning.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9352a34b8bcabb96f872d23a2459c819cb334889b929a4efeeba89f09d2b1738 -size 8346495 diff --git a/assets/voxygen/audio/ambient/grassland_day.ogg b/assets/voxygen/audio/ambient/grassland_day.ogg deleted file mode 100644 index 1437c9158e..0000000000 --- a/assets/voxygen/audio/ambient/grassland_day.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8f2b26e35c60bf00d555605bde3e5ce3d634f1e3221523e5a67b6c1c4d9a05aa -size 1657695 diff --git a/assets/voxygen/audio/ambient/grassland_night.ogg b/assets/voxygen/audio/ambient/grassland_night.ogg deleted file mode 100644 index debcfa5afa..0000000000 --- a/assets/voxygen/audio/ambient/grassland_night.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3386acd7dea5c63f11a363b82926f6df9770a266d327e54a5992dfbed29579d8 -size 3000009 diff --git a/assets/voxygen/audio/ambient/jungle_day.ogg b/assets/voxygen/audio/ambient/jungle_day.ogg deleted file mode 100644 index e2e80c9622..0000000000 --- a/assets/voxygen/audio/ambient/jungle_day.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:381d2171c785a9aa46618b52c82abd915de50dadac8e9697aa6887114026006e -size 2014591 diff --git a/assets/voxygen/audio/ambient/jungle_night.ogg b/assets/voxygen/audio/ambient/jungle_night.ogg deleted file mode 100644 index c428c1ceaa..0000000000 --- a/assets/voxygen/audio/ambient/jungle_night.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dc1677bdae9a06df578b18ee5cbb001b20c679573381505755594986d5f3a8c1 -size 629181 diff --git a/assets/voxygen/audio/ambient/snowlands.ogg b/assets/voxygen/audio/ambient/snowlands.ogg deleted file mode 100644 index d5c342f550..0000000000 --- a/assets/voxygen/audio/ambient/snowlands.ogg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3cc3fa048c94b33e032643efd1dd6bfd252fe3ac1065138a65656c71f16c8a0b -size 193015 diff --git a/assets/voxygen/audio/sfx/character/dive_roll_1.wav b/assets/voxygen/audio/sfx/character/dive_roll_1.wav index b3c61e2276..4d2645cb5a 100644 --- a/assets/voxygen/audio/sfx/character/dive_roll_1.wav +++ b/assets/voxygen/audio/sfx/character/dive_roll_1.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9804c75d4aa7c689a34f91a2f84ffdfa4b7619b275ca8562d8dee7eb0a251cf -size 240050 +oid sha256:9986ff72f3405f5c12ddb17cce0ab0b5e2f0816e73ed383e566846483bee6777 +size 160216 diff --git a/assets/voxygen/audio/sfx/character/dive_roll_2.wav b/assets/voxygen/audio/sfx/character/dive_roll_2.wav index 190d19b4f3..6b6650b5af 100644 --- a/assets/voxygen/audio/sfx/character/dive_roll_2.wav +++ b/assets/voxygen/audio/sfx/character/dive_roll_2.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:365a188a89ea79d788075bf3aa84278cb4880445d73f9c74a37976f0e4398dab -size 319430 +oid sha256:1ca8b8bd0da5bf4e01cb308221b595e3aeaa4dadcc2c14f0f105f7b507f56059 +size 213136 diff --git a/voxygen/src/audio/ambient.rs b/voxygen/src/audio/ambient.rs deleted file mode 100644 index ce87478564..0000000000 --- a/voxygen/src/audio/ambient.rs +++ /dev/null @@ -1,214 +0,0 @@ -//! Handles ambient sound playback and transitions -//! -//! Game ambient sound is controlled though a configuration file found in the -//! source at `/assets/voxygen/audio/ambient.ron`. Each track enabled in game -//! has a configuration corresponding to the -//! [`SoundtrackItem`](struct.SoundtrackItem.html) format, as well as the -//! corresponding `.ogg` file in the `/assets/voxygen/audio/soundtrack/` -//! directory. -//! -//! If there are errors while reading or deserialising the configuration file, a -//! warning is logged and music will be disabled. -//! -//! ## Adding new ambient sound -//! -//! To add a new item, append the details to the audio configuration file, and -//! add the audio file (in `.ogg` format) to the assets directory. -//! -//! The `length` should be provided in seconds. This allows us to know when to -//! transition to another track, without having to spend time determining track -//! length programmatically. -//! -//! An example of a new night time track: -//! ```text -//! ( -//! title: "Sleepy Song", -//! path: "voxygen.audio.soundtrack.sleepy", -//! length: 400.0, -//! timing: Some(Night), -//! biome: Some(Forest), -//! artist: "Elvis", -//! ), -//! ``` -//! -//! Before sending an MR for your new track item: -//! - Be conscious of the file size for your new track. Assets contribute to -//! download sizes -//! - Ensure that the track is mastered to a volume proportionate to other music -//! tracks -//! - If you are not the author of the track, ensure that the song's licensing -//! permits usage of the track for non-commercial use -use crate::audio::AudioFrontend; -use client::Client; -use common::{assets, state::State, terrain::BiomeKind}; -use rand::{seq::IteratorRandom, thread_rng}; -use serde::Deserialize; -use std::time::Instant; -use tracing::warn; - -const DAY_START_SECONDS: u32 = 28800; // 8:00 -const DAY_END_SECONDS: u32 = 70200; // 19:30 - -#[derive(Debug, Default, Deserialize)] -struct AmbientSoundtrackCollection { - tracks: Vec, -} - -/// Configuration for a single ambient sound track in the soundtrack -#[derive(Debug, Deserialize)] -pub struct AmbientSoundtrackItem { - title: String, - path: String, - /// Length of the track in seconds - length: f64, - /// Whether this track should play during day or night - timing: Option, - biome: Option, -} - -/// Allows control over when a track should play based on in-game time of day -#[derive(Debug, Deserialize, PartialEq)] -enum DayPeriod { - /// 8:00 AM to 7:30 PM - Day, - /// 7:31 PM to 6:59 AM - Night, -} - -/// Determines whether the sound is stopped, playing, or fading -#[derive(Debug, Deserialize, PartialEq)] -enum PlayState { - Playing, - Stopped, - FadingOut, - FadingIn, -} - -/// Provides methods to control ambient sound playback -pub struct AmbientMgr { - ambient_soundtrack: AmbientSoundtrackCollection, - began_playing: Instant, - began_fading: Instant, - next_track_change: f64, - /// The title of the last track played. Used to prevent a track - /// being played twice in a row - last_track: String, - last_biome: BiomeKind, - playing: PlayState, -} - -impl AmbientMgr { - #[allow(clippy::new_without_default)] // TODO: Pending review in #587 - pub fn new() -> Self { - Self { - ambient_soundtrack: Self::load_ambient_soundtrack_items(), - began_playing: Instant::now(), - began_fading: Instant::now(), - next_track_change: 0.0, - last_track: String::from("None"), - last_biome: BiomeKind::Void, - playing: PlayState::Stopped, - } - } - - /// Checks whether the previous track has completed. If so, sends a - /// request to play the next (random) track - pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - // Gets the current player biome - let current_biome: BiomeKind = match client.current_chunk() { - Some(chunk) => chunk.meta().biome(), - _ => self.last_biome, - }; - - if audio.music_enabled() // TODO: Change this to ambient_enabled - && !self.ambient_soundtrack.tracks.is_empty() - && (self.began_playing.elapsed().as_secs_f64() > self.next_track_change - || self.playing == PlayState::Stopped) - && self.playing != PlayState::FadingOut - { - self.play_random_track(audio, state, client); - self.playing = PlayState::Playing; - } else if current_biome != self.last_biome && self.playing == PlayState::Playing { - audio.fade_out_exploration_ambient(); - self.began_fading = Instant::now(); - self.playing = PlayState::FadingOut; - } else if self.began_fading.elapsed().as_secs_f64() > 5.0 - && self.playing == PlayState::FadingOut - { - audio.stop_exploration_ambient(); - self.playing = PlayState::Stopped; - } - self.last_biome = current_biome; - } - - fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - let game_time = (state.get_time_of_day() as u64 % 86400) as u32; - let current_period_of_day = Self::get_current_day_period(game_time); - let current_biome = Self::get_current_biome(client); - let mut rng = thread_rng(); - - let maybe_track = self - .ambient_soundtrack - .tracks - .iter() - .filter(|track| match &track.timing { - Some(period_of_day) => period_of_day == ¤t_period_of_day, - None => true, - }) - .filter(|track| match &track.biome { - Some(biome) => biome == ¤t_biome, - None => true, - }) - .choose(&mut rng); - - if let Some(track) = maybe_track { - self.last_track = String::from(&track.title); - self.began_playing = Instant::now(); - self.next_track_change = track.length; - - audio.fade_in_exploration_ambient(); - audio.play_exploration_ambient(&track.path); - } - } - - fn get_current_day_period(game_time: u32) -> DayPeriod { - if game_time > DAY_START_SECONDS && game_time < DAY_END_SECONDS { - DayPeriod::Day - } else { - DayPeriod::Night - } - } - - fn get_current_biome(client: &Client) -> BiomeKind { - match client.current_chunk() { - Some(chunk) => chunk.meta().biome(), - _ => BiomeKind::Void, - } - } - - fn load_ambient_soundtrack_items() -> AmbientSoundtrackCollection { - match assets::load_file("voxygen.audio.ambient", &["ron"]) { - Ok(file) => match ron::de::from_reader(file) { - Ok(config) => config, - Err(error) => { - warn!( - "Error parsing ambient sound config file, ambient sound will not be \ - available: {}", - format!("{:#?}", error) - ); - - AmbientSoundtrackCollection::default() - }, - }, - Err(error) => { - warn!( - "Error reading ambient sound config file, ambient sound will not be \ - available: {}", - format!("{:#?}", error) - ); - - AmbientSoundtrackCollection::default() - }, - } - } -} diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index 150897746a..473809ea84 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -140,117 +140,6 @@ impl MusicChannel { } } -/// Each `AmbientChannel` has a `AmbientChannelTag` which help us determine when -/// we should transition between two types of in-game music. For example, we -/// transition between `TitleMusic` and `Exploration` when a player enters the -/// world by crossfading over a slow duration. In the future, transitions in the -/// world such as `Exploration` -> `BossBattle` would transition more rapidly. -#[derive(PartialEq, Clone, Copy)] -pub enum AmbientChannelTag { - TitleMusic, - Exploration, -} - -/// An AmbientChannel uses a non-positional audio sink designed to play ambient -/// sound which is always heard at the player's position. -/// -/// See also: [`Rodio::Sink`](https://docs.rs/rodio/0.11.0/rodio/struct.Sink.html) -pub struct AmbientChannel { - tag: AmbientChannelTag, - sink: Sink, - state: ChannelState, - fader: Fader, -} -impl AmbientChannel { - pub fn new(device: &Device) -> Self { - Self { - sink: Sink::new(device), - tag: AmbientChannelTag::TitleMusic, - state: ChannelState::Stopped, - fader: Fader::default(), - } - } - - // Play an ambient track item on this channel. If the channel has an existing - // track playing, the new sounds will be appended and played once they - // complete. Otherwise it will begin playing immediately. - pub fn play(&mut self, source: S, tag: AmbientChannelTag) - where - S: Source + Send + 'static, - S::Item: Sample, - S::Item: Send, - ::Item: std::fmt::Debug, - { - self.tag = tag; - if !self.sink.len() > 0 { - self.sink.append(source); - } - - self.state = if !self.fader.is_finished() { - ChannelState::Fading - } else { - ChannelState::Playing - }; - } - - /// Stop whatever is playing on a given channel - pub fn stop(&mut self, tag: AmbientChannelTag) { - self.tag = tag; - self.sink.stop(); - } - - /// Set the volume of the current channel. If the channel is currently - /// fading, the volume of the fader is updated to this value. - pub fn set_volume(&mut self, volume: f32) { - if !self.fader.is_finished() { - self.fader.update_target_volume(volume); - } else { - self.sink.set_volume(volume); - } - } - - /// Set a fader for the channel. If a fader exists already, it is replaced. - /// If the channel has not begun playing, and the fader is set to fade in, - /// we set the volume of the channel to the initial volume of the fader so - /// that the volumes match when playing begins. - pub fn set_fader(&mut self, fader: Fader) { - self.fader = fader; - self.state = ChannelState::Fading; - - if self.state == ChannelState::Stopped && fader.direction() == FadeDirection::In { - self.sink.set_volume(fader.get_volume()); - } - } - - /// Returns true if either the channels sink reports itself as empty (no - /// more sounds in the queue) or we have forcibly set the channels state to - /// the 'Stopped' state - pub fn is_done(&self) -> bool { self.sink.empty() || self.state == ChannelState::Stopped } - - pub fn get_tag(&self) -> AmbientChannelTag { self.tag } - - /// Maintain the fader attached to this channel. If the channel is not - /// fading, no action is taken. - pub fn maintain(&mut self, dt: f32) { - if self.state == ChannelState::Fading { - self.fader.update(dt); - self.sink.set_volume(self.fader.get_volume()); - - if self.fader.is_finished() { - match self.fader.direction() { - FadeDirection::Out => { - self.state = ChannelState::Stopped; - self.sink.stop(); - }, - FadeDirection::In => { - self.state = ChannelState::Playing; - }, - } - } - } - } -} - /// An SfxChannel uses a positional audio sink, and is designed for short-lived /// audio which can be spatially controlled, but does not need control over /// playback or fading/transitions diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 93be825ed0..6065d3b8db 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -1,13 +1,12 @@ //! Handles audio device detection and playback of sound effects and music -//pub mod ambient; pub mod channel; pub mod fader; pub mod music; pub mod sfx; pub mod soundcache; -use channel::{AmbientChannel, AmbientChannelTag, MusicChannel, MusicChannelTag, SfxChannel}; +use channel::{MusicChannel, MusicChannelTag, SfxChannel}; use fader::Fader; use soundcache::SoundCache; use std::time::Duration; @@ -39,10 +38,8 @@ pub struct AudioFrontend { music_channels: Vec, sfx_channels: Vec, - //ambient_channels: Vec, sfx_volume: f32, music_volume: f32, - //ambient_volume: f32, listener: Listener, } @@ -62,11 +59,9 @@ impl AudioFrontend { audio_device, sound_cache: SoundCache::default(), music_channels: Vec::new(), - //ambient_channels: Vec::new(), sfx_channels, sfx_volume: 1.0, music_volume: 1.0, - //ambient_volume: 1.0, listener: Listener::default(), } } @@ -79,11 +74,9 @@ impl AudioFrontend { audio_device: None, sound_cache: SoundCache::default(), music_channels: Vec::new(), - //ambient_channels: Vec::new(), sfx_channels: Vec::new(), sfx_volume: 1.0, music_volume: 1.0, - //ambient_volume: 1.0, listener: Listener::default(), } } @@ -91,15 +84,10 @@ impl AudioFrontend { /// Drop any unused music channels, and update their faders pub fn maintain(&mut self, dt: Duration) { self.music_channels.retain(|c| !c.is_done()); - //self.ambient_channels.retain(|c| !c.is_done()); for channel in self.music_channels.iter_mut() { channel.maintain(dt); } - - //for channel in self.ambient_channels.iter_mut() { - // channel.maintain(dt); - //} } fn get_sfx_channel(&mut self) -> Option<&mut SfxChannel> { @@ -150,38 +138,6 @@ impl AudioFrontend { self.music_channels.last_mut() } - //fn get_ambient_channel( - // &mut self, - // next_channel_tag: AmbientChannelTag, - //) -> Option<&mut AmbientChannel> { - // if let Some(audio_device) = &self.audio_device { - // if self.ambient_channels.is_empty() { - // let mut next_ambient_channel = AmbientChannel::new(&audio_device); - // next_ambient_channel.set_volume(self.music_volume); - - // self.ambient_channels.push(next_ambient_channel); - // } else { - // let existing_channel = self.ambient_channels.last_mut()?; - - // if existing_channel.get_tag() != next_channel_tag { - // // Fade the existing channel out. It will be removed when the - // fade completes. - // existing_channel.set_fader(Fader::fade_out(2.0, self.music_volume)); - - // let mut next_ambient_channel = - // AmbientChannel::new(&audio_device); - - // next_ambient_channel.set_fader(Fader::fade_in(12.0, - // self.music_volume)); - - // self.ambient_channels.push(next_ambient_channel); - // } - // } - // } - - // self.ambient_channels.last_mut() - //} - /// Play (once) an sfx file by file path at the give position and volume pub fn play_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { if self.audio_device.is_some() { @@ -228,36 +184,6 @@ impl AudioFrontend { } } - //fn stop_ambient(&mut self, channel_tag: AmbientChannelTag) { - // if let Some(channel) = self.get_ambient_channel(channel_tag) { - // channel.stop(channel_tag); - // } - //} - - //fn fade_out_ambient(&mut self, channel_tag: AmbientChannelTag) { - // let music_volume = self.music_volume; - // if let Some(channel) = self.get_ambient_channel(channel_tag) { - // channel.set_fader(Fader::fade_out(2.0, music_volume)); - // } - //} - - //fn fade_in_ambient(&mut self, channel_tag: AmbientChannelTag) { - // let music_volume = self.music_volume; - // if let Some(channel) = self.get_ambient_channel(channel_tag) { - // channel.set_fader(Fader::fade_in(2.0, music_volume)); - // } - //} - - //fn play_ambient(&mut self, sound: &str, channel_tag: AmbientChannelTag) { - // if let Some(channel) = self.get_ambient_channel(channel_tag) { - // let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load - // sound"); let sound = Decoder::new(file).expect("Failed to decode - // sound"); - - // channel.play(sound, channel_tag); - // } - //} - pub fn set_listener_pos(&mut self, pos: Vec3, ori: Vec3) { self.listener.pos = pos; self.listener.ori = ori.normalized(); @@ -308,42 +234,14 @@ impl AudioFrontend { } } - //pub fn play_exploration_ambient(&mut self, item: &str) { - // if self.music_enabled() { - // self.play_ambient(item, AmbientChannelTag::Exploration) - // } - //} - - //pub fn fade_out_exploration_ambient(&mut self) { - // if self.music_enabled() { - // self.fade_out_ambient(AmbientChannelTag::Exploration) - // } - //} - - //pub fn fade_in_exploration_ambient(&mut self) { - // if self.music_enabled() { - // self.fade_in_ambient(AmbientChannelTag::Exploration) - // } - //} - - //pub fn stop_exploration_ambient(&mut self) { - // if self.music_enabled() { - // self.stop_ambient(AmbientChannelTag::Exploration) - // } - //} - pub fn get_sfx_volume(&self) -> f32 { self.sfx_volume } pub fn get_music_volume(&self) -> f32 { self.music_volume } - //pub fn get_ambient_volume(&self) -> f32 { self.music_volume } - pub fn sfx_enabled(&self) -> bool { self.sfx_volume > 0.0 } pub fn music_enabled(&self) -> bool { self.music_volume > 0.0 } - //pub fn ambient_enabled(&self) -> bool { self.music_volume > 0.0 } - pub fn set_sfx_volume(&mut self, sfx_volume: f32) { self.sfx_volume = sfx_volume; @@ -360,14 +258,6 @@ impl AudioFrontend { } } - //pub fn set_ambient_volume(&mut self, ambient_volume: f32) { - // self.music_volume = ambient_volume; - - // for channel in self.ambient_channels.iter_mut() { - // channel.set_volume(ambient_volume); - // } - //} - // 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(); diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index 051bd7005d..f10360799a 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -11,10 +11,7 @@ use common::{ vol::RectRasterableVol, }; use hashbrown::HashMap; -use rand::{ - prelude::{IteratorRandom, SliceRandom}, - thread_rng, Rng, -}; +use rand::{thread_rng, Rng}; use specs::WorldExt; use std::time::Instant; use vek::*; @@ -34,15 +31,6 @@ impl Default for PreviousBlockState { } } -impl PreviousBlockState { - fn new(event: SfxEvent) -> Self { - PreviousBlockState { - event, - time: Instant::now(), - } - } -} - pub struct BlockEventMapper { history: HashMap, PreviousBlockState>, } diff --git a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs index a6f6a973d1..d596986ed5 100644 --- a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs @@ -32,7 +32,6 @@ impl Default for PreviousEntityState { } pub struct CampfireEventMapper { - timer: Instant, event_history: HashMap, } @@ -91,7 +90,6 @@ impl EventMapper for CampfireEventMapper { impl CampfireEventMapper { pub fn new() -> Self { Self { - timer: Instant::now(), event_history: HashMap::new(), } } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 6cd104c4d3..b421ecbf50 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -47,7 +47,7 @@ impl EventMapper for MovementEventMapper { player_entity: specs::Entity, camera: &Camera, triggers: &SfxTriggers, - terrain: &Terrain, + _terrain: &Terrain, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/event_mapper/progression/mod.rs b/voxygen/src/audio/sfx/event_mapper/progression/mod.rs index 84588c3acb..9f9a05a124 100644 --- a/voxygen/src/audio/sfx/event_mapper/progression/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/progression/mod.rs @@ -32,7 +32,7 @@ impl EventMapper for ProgressionEventMapper { player_entity: specs::Entity, _camera: &Camera, triggers: &SfxTriggers, - terrain: &Terrain, + _terrain: &Terrain, ) { let ecs = state.ecs(); From c8d79b0b0e537b0e4cdf909eab9d7cabe710a8d2 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sun, 1 Nov 2020 23:19:28 -0800 Subject: [PATCH 11/37] Dungeon and cave specific music --- assets/voxygen/audio/soundtrack.ron | 218 +++++++++++++++------------- client/src/lib.rs | 4 + common/src/store.rs | 2 + common/src/terrain/biome.rs | 4 +- common/src/terrain/mod.rs | 75 +++++++++- common/src/terrain/site.rs | 10 ++ voxygen/src/audio/music.rs | 73 ++++++++-- world/src/lib.rs | 13 +- world/src/sim/mod.rs | 10 +- 9 files changed, 286 insertions(+), 123 deletions(-) create mode 100644 common/src/terrain/site.rs diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index a8eb947258..a09c34260c 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -3,116 +3,130 @@ ( tracks: [ - ( - title: "A Solemn Quest", - path: "voxygen.audio.soundtrack.a_solemn_quest", - length: 206.0, - timing: Some(Day), - biome: Some(Forest), - artist: "Eden", - ), - ( - title: "Into The Dark Forest", - path: "voxygen.audio.soundtrack.into_the_dark_forest", - length: 184.0, - timing: Some(Day), - biome: Some(Grassland), - artist: "Aeronic", - ), - ( - title: "Field Grazing", - path: "voxygen.audio.soundtrack.field_grazing", - length: 154.0, - timing: Some(Day), - biome: Some(Snowlands), - artist: "Aeronic", - ), - ( - title: "Wandering Voices", - path: "voxygen.audio.soundtrack.wandering_voices", - length: 137.0, - timing: Some(Day), - biome: Some(Desert), - artist: "Aeronic", - ), - ( - title: "Snowtop Volume", //Snow Region - path: "voxygen.audio.soundtrack.snowtop_volume", - length: 89.0, - timing: Some(Day), - biome: Some(Desert), - artist: "Aeronic", - ), - ( - title: "Mineral Deposits", - path: "voxygen.audio.soundtrack.mineral_deposits", - length: 148.0, - timing: Some(Day), - biome: Some(Desert), - artist: "Aeronic", - ), - ( - title: "Moonbeams", - path: "voxygen.audio.soundtrack.moonbeams", - length: 158.0, - timing: Some(Night), - biome: Some(Desert), - artist: "Aeronic", - ), - ( - title: "Serene Meadows", - path: "voxygen.audio.soundtrack.serene_meadows", - length: 173.0, - timing: Some(Night), - biome: Some(Desert), - artist: "Aeronic", - ), - /*( - title: "Rest Assured", // Town/Shop - path: "voxygen.audio.soundtrack.rest_assured", - length: 185.0, - timing: Some(Day), - biome: Some(Desert), - artist: "badbbad", - ),*/ - ( - title: "Just The Beginning", - path: "voxygen.audio.soundtrack.just_the_beginning", - length: 188.0, - timing: Some(Day), - biome: Some(Desert), - artist: "badbbad", - ), - ( - title: "Campfire Stories", - path: "voxygen.audio.soundtrack.campfire_stories", - length: 100.0, - timing: Some(Night), - biome: Some(Desert), - artist: "badbbad", - ), - ( - title: "Limits", - path: "voxygen.audio.soundtrack.limits", - length: 203.0, - timing: Some(Night), - biome: Some(Desert), - artist: "badbbad", - ), - /*( // Dungeon + //( + // title: "A Solemn Quest", + // path: "voxygen.audio.soundtrack.a_solemn_quest", + // length: 206.0, + // timing: Some(Day), + // biome: Some(Forest), + // site: None, + // artist: "Eden", + //), + //( + // title: "Into The Dark Forest", + // path: "voxygen.audio.soundtrack.into_the_dark_forest", + // length: 184.0, + // timing: Some(Day), + // biome: Some(Grassland), + // site: None, + // artist: "Aeronic", + //), + //( + // title: "Field Grazing", + // path: "voxygen.audio.soundtrack.field_grazing", + // length: 154.0, + // timing: Some(Day), + // biome: Some(Snowland), + // site: None, + // artist: "Aeronic", + //), + //( + // title: "Wandering Voices", + // path: "voxygen.audio.soundtrack.wandering_voices", + // length: 137.0, + // timing: Some(Day), + // biome: Some(Desert), + // site: None, + // artist: "Aeronic", + //), + //( + // title: "Snowtop Volume", //Snow Region + // path: "voxygen.audio.soundtrack.snowtop_volume", + // length: 89.0, + // timing: Some(Day), + // biome: Some(Desert), + // site: None, + // artist: "Aeronic", + //), + //( + // title: "Mineral Deposits", + // path: "voxygen.audio.soundtrack.mineral_deposits", + // length: 148.0, + // timing: Some(Day), + // biome: Some(Desert), + // site: None, + // artist: "Aeronic", + //), + //( + // title: "Moonbeams", + // path: "voxygen.audio.soundtrack.moonbeams", + // length: 158.0, + // timing: Some(Night), + // biome: Some(Desert), + // site: None, + // artist: "Aeronic", + //), + //( + // title: "Serene Meadows", + // path: "voxygen.audio.soundtrack.serene_meadows", + // length: 173.0, + // timing: Some(Night), + // biome: Some(Desert), + // site: None, + // artist: "Aeronic", + //), + ///*( + // title: "Rest Assured", // Town/Shop + // path: "voxygen.audio.soundtrack.rest_assured", + // length: 185.0, + // timing: Some(Day), + // biome: Some(Desert), + // site: None, + // artist: "badbbad", + //),*/ + //( + // title: "Just The Beginning", + // path: "voxygen.audio.soundtrack.just_the_beginning", + // length: 188.0, + // timing: Some(Day), + // biome: Some(Desert), + // site: None, + // artist: "badbbad", + //), + //( + // title: "Campfire Stories", + // path: "voxygen.audio.soundtrack.campfire_stories", + // length: 100.0, + // timing: Some(Night), + // biome: Some(Desert), + // site: None, + // artist: "badbbad", + //), + //( + // title: "Limits", + // path: "voxygen.audio.soundtrack.limits", + // length: 203.0, + // timing: Some(Night), + // biome: Some(Desert), + // site: None, + // artist: "badbbad", + //), + ( // Dungeon title: "Down The Rabbit Hole", path: "voxygen.audio.soundtrack.down_the_rabbit_hole", length: 244.0, - timing: Some(Night), - biome: Some(Desert), + timing: None, + biome: None, + site: Some(Cave), artist: "badbbad", - ),*/ + ), ( title: "Between The Fairies", path: "voxygen.audio.soundtrack.between_the_fairies", length: 175.0, - timing: Some(Night), - biome: Some(Desert), + timing: None, + biome: None, + site: Some(Dungeon), artist: "badbbad", ), ] diff --git a/client/src/lib.rs b/client/src/lib.rs index b70ed562c9..16c1db3747 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -857,6 +857,10 @@ impl Client { self.state.terrain().get_key_arc(chunk_pos).cloned() } + pub fn current_position(&self) -> Option> { + Some(self.state.read_storage::().get(self.entity).cloned()?.0) + } + pub fn inventories(&self) -> ReadStorage { self.state.read_storage() } pub fn loadouts(&self) -> ReadStorage { self.state.read_storage() } diff --git a/common/src/store.rs b/common/src/store.rs index e3ededbd25..75c957895a 100644 --- a/common/src/store.rs +++ b/common/src/store.rs @@ -11,6 +11,8 @@ pub struct Id(u64, PhantomData); impl Id { pub fn id(&self) -> u64 { self.0 } + + pub fn phantomdata(&self) -> PhantomData { self.1 } } impl Copy for Id {} diff --git a/common/src/terrain/biome.rs b/common/src/terrain/biome.rs index ecb9e2cf27..67661b13a3 100644 --- a/common/src/terrain/biome.rs +++ b/common/src/terrain/biome.rs @@ -3,11 +3,13 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] pub enum BiomeKind { Void, + Lake, Grassland, Ocean, Mountain, - Snowlands, + Snowland, Desert, Swamp, + Jungle, Forest, } diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index 899eaa016c..0918f1c764 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -2,6 +2,7 @@ pub mod biome; pub mod block; pub mod chonk; pub mod map; +pub mod site; pub mod sprite; pub mod structure; @@ -10,6 +11,7 @@ pub use self::{ biome::BiomeKind, block::{Block, BlockKind}, map::MapSizeLg, + site::SitesKind, sprite::SpriteKind, structure::Structure, }; @@ -50,21 +52,92 @@ impl RectVolSize for TerrainChunkSize { pub struct TerrainChunkMeta { name: Option, biome: BiomeKind, + + chaos: f32, + alt: f32, + //basement: f32, + //water_alt: f32, + //downhill: Option>, + //flux: f32, + temp: f32, + humidity: f32, + rockiness: f32, + //is_cliffs: bool, + //near_cliffs: bool, + tree_density: f32, + //forest_kind: ForestKind, + //spawn_rate: f32, + //river: RiverData, + //warp_factor: f32, + surface_veg: f32, + cave_alt: f32, + /*place: Option>, */ + + /*path: (Way, Path),*/ + /* contains_waypoint: bool, */ } impl TerrainChunkMeta { - pub fn new(name: Option, biome: BiomeKind) -> Self { Self { name, biome } } + pub fn new( + name: Option, + biome: BiomeKind, + chaos: f32, + alt: f32, + temp: f32, + humidity: f32, + rockiness: f32, + tree_density: f32, + surface_veg: f32, + cave_alt: f32, + ) -> Self { + Self { + name, + biome, + chaos, + alt, + temp, + humidity, + rockiness, + tree_density, + surface_veg, + cave_alt, + } + } pub fn void() -> Self { Self { name: None, biome: BiomeKind::Void, + chaos: 0.0, + alt: 0.0, + temp: 0.0, + humidity: 0.0, + rockiness: 0.0, + tree_density: 0.0, + surface_veg: 0.0, + cave_alt: 0.0, } } pub fn name(&self) -> &str { self.name.as_deref().unwrap_or("Wilderness") } pub fn biome(&self) -> BiomeKind { self.biome } + + pub fn chaos(&self) -> f32 { self.chaos } + + pub fn alt(&self) -> f32 { self.alt } + + pub fn temp(&self) -> f32 { self.temp } + + pub fn humidity(&self) -> f32 { self.humidity } + + pub fn rockiness(&self) -> f32 { self.rockiness } + + pub fn tree_density(&self) -> f32 { self.tree_density } + + pub fn surface_veg(&self) -> f32 { self.surface_veg } + + pub fn cave_alt(&self) -> f32 { self.cave_alt } } // Terrain type aliases diff --git a/common/src/terrain/site.rs b/common/src/terrain/site.rs new file mode 100644 index 0000000000..eaf69b9d86 --- /dev/null +++ b/common/src/terrain/site.rs @@ -0,0 +1,10 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] +pub enum SitesKind { + Dungeon, + Cave, + Settlement, + Castle, + None, +} diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 9cd4ffa97e..c0ae6ea73c 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -40,7 +40,11 @@ //! permits usage of the track for non-commercial use use crate::audio::AudioFrontend; use client::Client; -use common::{assets, state::State, terrain::BiomeKind}; +use common::{ + assets, + state::State, + terrain::{BiomeKind, SitesKind}, +}; use rand::{seq::IteratorRandom, thread_rng}; use serde::Deserialize; use std::time::Instant; @@ -64,6 +68,7 @@ pub struct SoundtrackItem { /// Whether this track should play during day or night timing: Option, biome: Option, + site: Option, } /// Allows control over when a track should play based on in-game time of day @@ -120,25 +125,38 @@ impl MusicMgr { _ => self.last_biome, }; + if let Some(current_chunk) = client.current_chunk() { + println!("biome: {:?}", current_chunk.meta().biome()); + println!("chaos: {}", current_chunk.meta().chaos()); + println!("alt: {}", current_chunk.meta().alt()); + println!("temp: {}", current_chunk.meta().temp()); + println!("tree_density: {}", current_chunk.meta().tree_density()); + println!("humidity: {}", current_chunk.meta().humidity()); + println!("cave_alt: {}", current_chunk.meta().cave_alt()); + if let Some(position) = client.current_position() { + println!("player_alt: {}", position[2]); + } + } + if audio.music_enabled() && !self.soundtrack.tracks.is_empty() - && (self.began_playing.elapsed().as_secs_f64() > self.next_track_change - || self.playing == PlayState::Stopped) - && self.playing != PlayState::FadingOut + && self.began_playing.elapsed().as_secs_f64() > self.next_track_change + // || self.playing == PlayState::Stopped) + // && self.playing != PlayState::FadingOut { self.play_random_track(audio, state, client); - self.playing = PlayState::Playing; - } else if current_biome != self.last_biome && self.playing == PlayState::Playing { - audio.fade_out_exploration_music(); - self.began_fading = Instant::now(); - self.playing = PlayState::FadingOut; - } else if self.began_fading.elapsed().as_secs_f64() > 5.0 - && self.playing == PlayState::FadingOut - { - audio.stop_exploration_music(); - self.playing = PlayState::Stopped; + // self.playing = PlayState::Playing; + //} else if current_biome != self.last_biome && self.playing == PlayState::Playing { + // audio.fade_out_exploration_music(); + // self.began_fading = Instant::now(); + // self.playing = PlayState::FadingOut; + //} else if self.began_fading.elapsed().as_secs_f64() > 5.0 + // && self.playing == PlayState::FadingOut + //{ + // audio.stop_exploration_music(); + // self.playing = PlayState::Stopped; } - self.last_biome = current_biome; + //self.last_biome = current_biome; } fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { @@ -148,6 +166,7 @@ impl MusicMgr { let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); let current_biome = Self::get_current_biome(client); + let current_site = Self::get_current_site(client); let mut rng = thread_rng(); let maybe_track = self @@ -165,6 +184,10 @@ impl MusicMgr { Some(biome) => biome == ¤t_biome, None => true, }) + .filter(|track| match &track.site { + Some(site) => site == ¤t_site, + None => true, + }) .choose(&mut rng); if let Some(track) = maybe_track { @@ -191,6 +214,26 @@ impl MusicMgr { } } + fn get_current_site(client: &Client) -> SitesKind { + let mut player_alt = 0.0; + if let Some(position) = client.current_position() { + player_alt = position[2]; + } + let mut cave_alt = 0.0; + let mut alt = 0.0; + if let Some(chunk) = client.current_chunk() { + alt = chunk.meta().alt(); + cave_alt = chunk.meta().cave_alt(); + } + if player_alt < cave_alt && cave_alt != 0.0 { + SitesKind::Cave + } else if player_alt < (alt - 30.0) { + SitesKind::Dungeon + } else { + SitesKind::None + } + } + fn load_soundtrack_items() -> SoundtrackCollection { match assets::load_file("voxygen.audio.soundtrack", &["ron"]) { Ok(file) => match ron::de::from_reader(file) { diff --git a/world/src/lib.rs b/world/src/lib.rs index 9f6812dfed..91e537e995 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -155,7 +155,18 @@ impl World { }, }; - let meta = TerrainChunkMeta::new(sim_chunk.get_name(&self.sim), sim_chunk.get_biome()); + let meta = TerrainChunkMeta::new( + sim_chunk.get_name(&self.sim), + sim_chunk.get_biome(), + sim_chunk.chaos, + sim_chunk.alt, + sim_chunk.temp, + sim_chunk.humidity, + sim_chunk.rockiness, + sim_chunk.tree_density, + sim_chunk.surface_veg, + sim_chunk.cave.1.alt, + ); let mut chunk = TerrainChunk::new(base_z, stone, air, meta); diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index e099bde409..60bf0efe0d 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -2303,14 +2303,18 @@ impl SimChunk { pub fn get_biome(&self) -> BiomeKind { if self.alt < CONFIG.sea_level { BiomeKind::Ocean - } else if self.chaos > 0.6 { + } else if self.alt > 450.0 && self.chaos > 0.4 && self.tree_density < 0.7 { BiomeKind::Mountain - } else if self.temp > CONFIG.desert_temp { + } else if self.temp > CONFIG.desert_temp && self.humidity < 0.1 { BiomeKind::Desert } else if self.temp < CONFIG.snow_temp { - BiomeKind::Snowlands + BiomeKind::Snowland + } else if self.tree_density > 0.65 && self.humidity > 0.9 && self.temp > 0.8 { + BiomeKind::Jungle } else if self.tree_density > 0.65 { BiomeKind::Forest + } else if self.humidity > 0.8 { + BiomeKind::Swamp } else { BiomeKind::Grassland } From e880654f2e4280e263524c1d43823f32e3ea8406 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Tue, 3 Nov 2020 22:41:54 -0800 Subject: [PATCH 12/37] Probability for biome play --- assets/voxygen/audio/soundtrack.ron | 84 ++++++++++++++++++++++------- voxygen/src/audio/music.rs | 67 ++++++++++++++++++----- 2 files changed, 117 insertions(+), 34 deletions(-) diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index a09c34260c..e3e8349e2c 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -3,24 +3,46 @@ ( tracks: [ - //( - // title: "A Solemn Quest", - // path: "voxygen.audio.soundtrack.a_solemn_quest", - // length: 206.0, - // timing: Some(Day), - // biome: Some(Forest), - // site: None, - // artist: "Eden", - //), - //( - // title: "Into The Dark Forest", - // path: "voxygen.audio.soundtrack.into_the_dark_forest", - // length: 184.0, - // timing: Some(Day), - // biome: Some(Grassland), - // site: None, - // artist: "Aeronic", - //), + ( + title: "A Solemn Quest", + path: "voxygen.audio.soundtrack.a_solemn_quest", + length: 206.0, + timing: Some(Day), + biomes: ( + void: 1, + lake: 1, + grassland: 1, + ocean: 1, + mountain: 1, + snowland: 1, + desert: 1, + swamp: 1, + jungle: 1, + forest: 0, + ), + site: None, + artist: "Eden", + ), + ( + title: "Into The Dark Forest", + path: "voxygen.audio.soundtrack.into_the_dark_forest", + length: 184.0, + timing: Some(Day), + biomes: ( + void: 1, + lake: 1, + grassland: 1, + ocean: 1, + mountain: 1, + snowland: 1, + desert: 1, + swamp: 1, + jungle: 1, + forest: 0, + ), + site: None, + artist: "Aeronic", + ), //( // title: "Field Grazing", // path: "voxygen.audio.soundtrack.field_grazing", @@ -116,7 +138,18 @@ path: "voxygen.audio.soundtrack.down_the_rabbit_hole", length: 244.0, timing: None, - biome: None, + biomes: ( + void: 1, + lake: 1, + grassland: 1, + ocean: 1, + mountain: 1, + snowland: 1, + desert: 1, + swamp: 1, + jungle: 1, + forest: 1, + ), site: Some(Cave), artist: "badbbad", ), @@ -125,7 +158,18 @@ path: "voxygen.audio.soundtrack.between_the_fairies", length: 175.0, timing: None, - biome: None, + biomes: ( + void: 1, + lake: 1, + grassland: 1, + ocean: 1, + mountain: 1, + snowland: 1, + desert: 1, + swamp: 1, + jungle: 1, + forest: 1, + ), site: Some(Dungeon), artist: "badbbad", ), diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index c0ae6ea73c..d8c0a2cdd4 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -45,7 +45,7 @@ use common::{ state::State, terrain::{BiomeKind, SitesKind}, }; -use rand::{seq::IteratorRandom, thread_rng}; +use rand::{prelude::SliceRandom, thread_rng}; use serde::Deserialize; use std::time::Instant; use tracing::warn; @@ -67,10 +67,24 @@ pub struct SoundtrackItem { length: f64, /// Whether this track should play during day or night timing: Option, - biome: Option, + biomes: BiomeProbability, site: Option, } +#[derive(Debug, Deserialize)] +pub struct BiomeProbability { + void: u8, + lake: u8, + grassland: u8, + ocean: u8, + mountain: u8, + snowland: u8, + desert: u8, + swamp: u8, + jungle: u8, + forest: u8, +} + /// Allows control over when a track should play based on in-game time of day #[derive(Debug, Deserialize, PartialEq)] enum DayPeriod { @@ -120,10 +134,10 @@ impl MusicMgr { /// request to play the next (random) track pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { // Gets the current player biome - let current_biome: BiomeKind = match client.current_chunk() { - Some(chunk) => chunk.meta().biome(), - _ => self.last_biome, - }; + //let current_biome: BiomeKind = match client.current_chunk() { + // Some(chunk) => chunk.meta().biome(), + // _ => self.last_biome, + //}; if let Some(current_chunk) = client.current_chunk() { println!("biome: {:?}", current_chunk.meta().biome()); @@ -160,8 +174,8 @@ impl MusicMgr { } fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; - //const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 5.0; + //const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; + const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 5.0; let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); @@ -180,17 +194,42 @@ impl MusicMgr { None => true, } }) - .filter(|track| match &track.biome { - Some(biome) => biome == ¤t_biome, - None => true, - }) .filter(|track| match &track.site { Some(site) => site == ¤t_site, None => true, }) - .choose(&mut rng); + .filter(|track| match current_biome { + BiomeKind::Void => false, + BiomeKind::Lake => track.biomes.lake > 0, + BiomeKind::Grassland => track.biomes.grassland > 0, + BiomeKind::Ocean => track.biomes.ocean > 0, + BiomeKind::Mountain => track.biomes.mountain > 0, + BiomeKind::Snowland => track.biomes.snowland > 0, + BiomeKind::Desert => track.biomes.desert > 0, + BiomeKind::Swamp => track.biomes.swamp > 0, + BiomeKind::Jungle => track.biomes.jungle > 0, + BiomeKind::Forest => track.biomes.forest > 0, + }) + .collect::>(); - if let Some(track) = maybe_track { + //let new_maybe_track = maybe_track + // .choose_weighted(&mut rng, |track| + // track.biomes.unwrap().entry(current_biome)); + + let new_maybe_track = maybe_track.choose_weighted(&mut rng, |track| match current_biome { + BiomeKind::Void => track.biomes.void, + BiomeKind::Lake => track.biomes.lake, + BiomeKind::Grassland => track.biomes.grassland, + BiomeKind::Ocean => track.biomes.ocean, + BiomeKind::Mountain => track.biomes.mountain, + BiomeKind::Snowland => track.biomes.snowland, + BiomeKind::Desert => track.biomes.desert, + BiomeKind::Swamp => track.biomes.swamp, + BiomeKind::Jungle => track.biomes.jungle, + BiomeKind::Forest => track.biomes.forest, + }); + + if let Ok(track) = new_maybe_track { self.last_track = String::from(&track.title); self.began_playing = Instant::now(); self.next_track_change = track.length + SILENCE_BETWEEN_TRACKS_SECONDS; From d0bd5118bf3a0ba01cabe96d46366e7b614dcee4 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Wed, 4 Nov 2020 15:22:56 -0800 Subject: [PATCH 13/37] Made biome probabilities neater --- assets/voxygen/audio/sfx.ron | 1 - .../voxygen/audio/sfx/ambient/birdcall_3.wav | 3 - assets/voxygen/audio/soundtrack.ron | 110 ++++++------------ voxygen/src/audio/music.rs | 107 ++++++++--------- .../src/audio/sfx/event_mapper/block/mod.rs | 20 ++-- 5 files changed, 92 insertions(+), 149 deletions(-) delete mode 100644 assets/voxygen/audio/sfx/ambient/birdcall_3.wav diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 374d65584e..bbd864282e 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -19,7 +19,6 @@ files: [ "voxygen.audio.sfx.ambient.birdcall_1", "voxygen.audio.sfx.ambient.birdcall_2", - "voxygen.audio.sfx.ambient.birdcall_3", ], threshold: 10.0, ), diff --git a/assets/voxygen/audio/sfx/ambient/birdcall_3.wav b/assets/voxygen/audio/sfx/ambient/birdcall_3.wav deleted file mode 100644 index 615d6ba075..0000000000 --- a/assets/voxygen/audio/sfx/ambient/birdcall_3.wav +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5494c1f8e30c0b3fd686ae2c93ece3c145a83bff221801bc3de3eb37ac2d034 -size 1162164 diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index e3e8349e2c..90dc6d5232 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -8,18 +8,10 @@ path: "voxygen.audio.soundtrack.a_solemn_quest", length: 206.0, timing: Some(Day), - biomes: ( - void: 1, - lake: 1, - grassland: 1, - ocean: 1, - mountain: 1, - snowland: 1, - desert: 1, - swamp: 1, - jungle: 1, - forest: 0, - ), + biomes: [ + (Lake, 1), + (Grassland, 1), + ], site: None, artist: "Eden", ), @@ -28,30 +20,22 @@ path: "voxygen.audio.soundtrack.into_the_dark_forest", length: 184.0, timing: Some(Day), - biomes: ( - void: 1, - lake: 1, - grassland: 1, - ocean: 1, - mountain: 1, - snowland: 1, - desert: 1, - swamp: 1, - jungle: 1, - forest: 0, - ), + biomes: [ + (Forest, 1), + (Jungle, 1), + ], + site: None, + artist: "Aeronic", + ), + ( + title: "Field Grazing", + path: "voxygen.audio.soundtrack.field_grazing", + length: 154.0, + timing: Some(Day), + biomes: [], site: None, artist: "Aeronic", ), - //( - // title: "Field Grazing", - // path: "voxygen.audio.soundtrack.field_grazing", - // length: 154.0, - // timing: Some(Day), - // biome: Some(Snowland), - // site: None, - // artist: "Aeronic", - //), //( // title: "Wandering Voices", // path: "voxygen.audio.soundtrack.wandering_voices", @@ -124,54 +108,32 @@ // site: None, // artist: "badbbad", //), - //( - // title: "Limits", - // path: "voxygen.audio.soundtrack.limits", - // length: 203.0, - // timing: Some(Night), - // biome: Some(Desert), - // site: None, - // artist: "badbbad", - //), + ( + title: "Limits", + path: "voxygen.audio.soundtrack.limits", + length: 203.0, + timing: Some(Night), + biomes: [], + site: Some(Dungeon), + artist: "badbbad", + ), ( // Dungeon title: "Down The Rabbit Hole", path: "voxygen.audio.soundtrack.down_the_rabbit_hole", length: 244.0, timing: None, - biomes: ( - void: 1, - lake: 1, - grassland: 1, - ocean: 1, - mountain: 1, - snowland: 1, - desert: 1, - swamp: 1, - jungle: 1, - forest: 1, - ), + biomes: [], site: Some(Cave), artist: "badbbad", ), - ( - title: "Between The Fairies", - path: "voxygen.audio.soundtrack.between_the_fairies", - length: 175.0, - timing: None, - biomes: ( - void: 1, - lake: 1, - grassland: 1, - ocean: 1, - mountain: 1, - snowland: 1, - desert: 1, - swamp: 1, - jungle: 1, - forest: 1, - ), - site: Some(Dungeon), - artist: "badbbad", - ), + //( + // title: "Between The Fairies", + // path: "voxygen.audio.soundtrack.between_the_fairies", + // length: 175.0, + // timing: None, + // biomes: [], + // site: Some(Cave), + // artist: "badbbad", + //), ] ) diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index d8c0a2cdd4..2434904bf3 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -67,24 +67,10 @@ pub struct SoundtrackItem { length: f64, /// Whether this track should play during day or night timing: Option, - biomes: BiomeProbability, + biomes: Vec<(BiomeKind, u8)>, site: Option, } -#[derive(Debug, Deserialize)] -pub struct BiomeProbability { - void: u8, - lake: u8, - grassland: u8, - ocean: u8, - mountain: u8, - snowland: u8, - desert: u8, - swamp: u8, - jungle: u8, - forest: u8, -} - /// Allows control over when a track should play based on in-game time of day #[derive(Debug, Deserialize, PartialEq)] enum DayPeriod { @@ -107,13 +93,13 @@ enum PlayState { pub struct MusicMgr { soundtrack: SoundtrackCollection, began_playing: Instant, - began_fading: Instant, + //began_fading: Instant, next_track_change: f64, /// The title of the last track played. Used to prevent a track /// being played twice in a row last_track: String, - last_biome: BiomeKind, - playing: PlayState, + /*last_biome: BiomeKind, + *playing: PlayState, */ } impl MusicMgr { @@ -122,11 +108,11 @@ impl MusicMgr { Self { soundtrack: Self::load_soundtrack_items(), began_playing: Instant::now(), - began_fading: Instant::now(), + //began_fading: Instant::now(), next_track_change: 0.0, last_track: String::from("None"), - last_biome: BiomeKind::Void, - playing: PlayState::Stopped, + /*last_biome: BiomeKind::Void, + *playing: PlayState::Stopped, */ } } @@ -139,18 +125,19 @@ impl MusicMgr { // _ => self.last_biome, //}; - if let Some(current_chunk) = client.current_chunk() { - println!("biome: {:?}", current_chunk.meta().biome()); - println!("chaos: {}", current_chunk.meta().chaos()); - println!("alt: {}", current_chunk.meta().alt()); - println!("temp: {}", current_chunk.meta().temp()); - println!("tree_density: {}", current_chunk.meta().tree_density()); - println!("humidity: {}", current_chunk.meta().humidity()); - println!("cave_alt: {}", current_chunk.meta().cave_alt()); - if let Some(position) = client.current_position() { - println!("player_alt: {}", position[2]); - } - } + //if let Some(current_chunk) = client.current_chunk() { + // println!("biome: {:?}", current_chunk.meta().biome()); + // println!("chaos: {}", current_chunk.meta().chaos()); + // println!("alt: {}", current_chunk.meta().alt()); + // println!("temp: {}", current_chunk.meta().temp()); + // println!("tree_density: {}", + // current_chunk.meta().tree_density()); + // println!("humidity: {}", current_chunk.meta().humidity()); + // println!("cave_alt: {}", current_chunk.meta().cave_alt()); + // if let Some(position) = client.current_position() { + // println!("player_alt: {}", position[2]); + // } + //} if audio.music_enabled() && !self.soundtrack.tracks.is_empty() @@ -198,35 +185,33 @@ impl MusicMgr { Some(site) => site == ¤t_site, None => true, }) - .filter(|track| match current_biome { - BiomeKind::Void => false, - BiomeKind::Lake => track.biomes.lake > 0, - BiomeKind::Grassland => track.biomes.grassland > 0, - BiomeKind::Ocean => track.biomes.ocean > 0, - BiomeKind::Mountain => track.biomes.mountain > 0, - BiomeKind::Snowland => track.biomes.snowland > 0, - BiomeKind::Desert => track.biomes.desert > 0, - BiomeKind::Swamp => track.biomes.swamp > 0, - BiomeKind::Jungle => track.biomes.jungle > 0, - BiomeKind::Forest => track.biomes.forest > 0, + .filter(|track| { + let mut result = false; + if track.biomes.len() > 0 { + for biome in track.biomes.iter() { + if biome.0 == current_biome { + result = true; + } + } + } else { + result = true; + } + result }) .collect::>(); - //let new_maybe_track = maybe_track - // .choose_weighted(&mut rng, |track| - // track.biomes.unwrap().entry(current_biome)); - - let new_maybe_track = maybe_track.choose_weighted(&mut rng, |track| match current_biome { - BiomeKind::Void => track.biomes.void, - BiomeKind::Lake => track.biomes.lake, - BiomeKind::Grassland => track.biomes.grassland, - BiomeKind::Ocean => track.biomes.ocean, - BiomeKind::Mountain => track.biomes.mountain, - BiomeKind::Snowland => track.biomes.snowland, - BiomeKind::Desert => track.biomes.desert, - BiomeKind::Swamp => track.biomes.swamp, - BiomeKind::Jungle => track.biomes.jungle, - BiomeKind::Forest => track.biomes.forest, + let new_maybe_track = maybe_track.choose_weighted(&mut rng, |track| { + let mut chance = 0; + if track.biomes.len() > 0 { + for biome in track.biomes.iter() { + if biome.0 == current_biome { + chance = biome.1; + } + } + } else { + chance = 1; + } + chance }); if let Ok(track) = new_maybe_track { @@ -264,9 +249,9 @@ impl MusicMgr { alt = chunk.meta().alt(); cave_alt = chunk.meta().cave_alt(); } - if player_alt < cave_alt && cave_alt != 0.0 { + if player_alt < (alt - 20.0) && cave_alt != 0.0 { SitesKind::Cave - } else if player_alt < (alt - 30.0) { + } else if player_alt < (alt - 20.0) { SitesKind::Dungeon } else { SitesKind::None diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index f10360799a..f0004df1b8 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -86,15 +86,15 @@ impl EventMapper for BlockEventMapper { volume: 1.0, cond: |st| st.get_day_period().is_dark(), }, - BlockSounds { - blocks: |boi| &boi.embers, - range: 1, - sfx: SfxEvent::Embers, - volume: 0.15, - //volume: 0.05, - cond: |_| true, - //cond: |st| st.get_day_period().is_dark(), - }, + //BlockSounds { + // blocks: |boi| &boi.embers, + // range: 1, + // sfx: SfxEvent::Embers, + // volume: 0.15, + // //volume: 0.05, + // cond: |_| true, + // //cond: |st| st.get_day_period().is_dark(), + //}, BlockSounds { blocks: |boi| &boi.reeds, range: 1, @@ -131,7 +131,7 @@ impl EventMapper for BlockEventMapper { for sounds in sounds.iter() { if !(sounds.cond)(state) { continue; - } else if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen_bool(0.99) { + } else if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen_bool(0.995) { continue; } From decb0e3e248f6794688b3376a2ef96461b8dab65 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Wed, 4 Nov 2020 23:48:06 -0800 Subject: [PATCH 14/37] Hackily upgraded rodio and cpal to 0.13 --- Cargo.lock | 300 ++++++++++++++++++++++++++--- voxygen/Cargo.toml | 4 +- voxygen/src/audio/channel.rs | 11 +- voxygen/src/audio/mod.rs | 131 +++++++------ voxygen/src/hud/mod.rs | 8 +- voxygen/src/hud/settings_window.rs | 48 ++--- voxygen/src/main.rs | 6 +- voxygen/src/session.rs | 10 +- voxygen/src/settings.rs | 2 - 9 files changed, 387 insertions(+), 133 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd04e29ddc..a53854a3ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,10 +56,22 @@ dependencies = [ ] [[package]] -name = "alsa-sys" -version = "0.1.2" +name = "alsa" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" +checksum = "44581add1add74ade32aca327b550342359ec00191672c23c1caa3d492b85930" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix 0.15.0", +] + +[[package]] +name = "alsa-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a0559bcd3f7a482690d98be41c08a43e92f669b179433e95ddf5e8b8fd36a3" dependencies = [ "libc", "pkg-config", @@ -196,6 +208,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + [[package]] name = "ascii" version = "1.0.0" @@ -275,7 +293,7 @@ dependencies = [ "hex", "rust-argon2", "serde_json", - "ureq", + "ureq 1.4.1", "uuid", ] @@ -311,6 +329,21 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + [[package]] name = "base64" version = "0.12.3" @@ -435,6 +468,12 @@ dependencies = [ "iovec", ] +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + [[package]] name = "calloop" version = "0.6.4" @@ -469,6 +508,12 @@ dependencies = [ "jobserver", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.4.0" @@ -643,6 +688,30 @@ dependencies = [ "objc", ] +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii 0.9.3", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "combine" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2809f67365382d65fd2b6d9c22577231b954ed27400efeafbe687bda75abcc0b" +dependencies = [ + "bytes 0.5.6", + "memchr", + "pin-project-lite", +] + [[package]] name = "conrod_core" version = "0.63.0" @@ -885,18 +954,26 @@ dependencies = [ [[package]] name = "cpal" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b55d55d69f403f62a95bd3c04b431e0aedf5120c70f15d07a8edd234443dd59" +checksum = "4919d30839e3924b45b84319997a554db1a56918bc5b2a08a6c29886e65e2dca" dependencies = [ - "alsa-sys", + "alsa", "core-foundation-sys 0.6.2", "coreaudio-rs", + "jni 0.17.0", + "js-sys", "lazy_static", "libc", - "num-traits 0.2.12", + "mach 0.3.2", + "ndk", + "ndk-glue", + "nix 0.15.0", + "oboe", + "parking_lot 0.9.0", "stdweb 0.1.3", "thiserror", + "web-sys", "winapi 0.3.9", ] @@ -1490,6 +1567,17 @@ dependencies = [ "syn 1.0.42", ] +[[package]] +name = "fetch_unroll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5c55005e95bbe15f5f72a73b6597d0dc82ddc97ffe2ca097a99dcd591fefbca" +dependencies = [ + "libflate", + "tar", + "ureq 0.11.4", +] + [[package]] name = "filetime" version = "0.2.12" @@ -1980,7 +2068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" dependencies = [ "byteorder", - "bytes", + "bytes 0.4.12", "fnv", "futures 0.1.29", "http", @@ -2067,7 +2155,7 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" dependencies = [ - "bytes", + "bytes 0.4.12", "fnv", "itoa", ] @@ -2078,7 +2166,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" dependencies = [ - "bytes", + "bytes 0.4.12", "futures 0.1.29", "http", "tokio-buf", @@ -2091,7 +2179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9625f605ddfaf894bf78a544a7b8e31f562dc843654723a49892d9c7e75ac708" dependencies = [ "async-std", - "bytes", + "bytes 0.4.12", "futures 0.3.5", "http", "pin-project-lite", @@ -2121,7 +2209,7 @@ version = "0.12.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" dependencies = [ - "bytes", + "bytes 0.4.12", "futures 0.1.29", "futures-cpupool", "h2", @@ -2305,7 +2393,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f21dcc74995dd4cd090b147e79789f8d65959cbfb5f0b118002db869ea3bd0a0" dependencies = [ "core-foundation-sys 0.6.2", - "mach", + "mach 0.2.3", ] [[package]] @@ -2332,6 +2420,34 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +[[package]] +name = "jni" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1981310da491a4f0f815238097d0d43d8072732b5ae5f8bd0d8eadf5bf245402" +dependencies = [ + "cesu8", + "combine 3.8.1", + "error-chain", + "jni-sys", + "log", + "walkdir 2.3.1", +] + +[[package]] +name = "jni" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36bcc950632e48b86da402c5c077590583da5ac0d480103611d5374e7c967a3c" +dependencies = [ + "cesu8", + "combine 4.3.2", + "error-chain", + "jni-sys", + "log", + "walkdir 2.3.1", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -2416,6 +2532,18 @@ version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +[[package]] +name = "libflate" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd" +dependencies = [ + "adler32", + "crc32fast", + "rle-decode-fast", + "take_mut", +] + [[package]] name = "libgit2-sys" version = "0.12.13+1.0.1" @@ -2567,6 +2695,15 @@ dependencies = [ "libc", ] +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -3125,6 +3262,29 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +[[package]] +name = "oboe" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a13c9fe73346ff3cee5530b8dd9da1ce3e13cb663be210af3938a2a1dd3eab" +dependencies = [ + "jni 0.14.0", + "ndk", + "ndk-glue", + "num-derive", + "num-traits 0.2.12", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ff7a51600eabe34e189eec5c995a62f151d8d97e5fbca39e87ca738bb99b82" +dependencies = [ + "fetch_unroll", +] + [[package]] name = "ogg" version = "0.7.0" @@ -3842,14 +4002,19 @@ dependencies = [ ] [[package]] -name = "rodio" -version = "0.11.0" +name = "rle-decode-fast" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73bbf260262fd5501b7a17d6827e0d25c1127e921eb177150a060faf6e217a70" +checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" + +[[package]] +name = "rodio" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9683532495146e98878d4948fa1a1953f584cd923f2a5f5c26b7a8701b56943" dependencies = [ "cpal", "hound", - "lazy_static", "lewton", ] @@ -3859,7 +4024,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8a58080b7bb83b2ea28c3b7a9a994fd5e310330b7c8ca5258d99b98128ecfe4" dependencies = [ - "base64", + "base64 0.12.3", "bitflags", "serde", ] @@ -3882,7 +4047,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ - "base64", + "base64 0.12.3", "blake2b_simd", "constant_time_eq", "crossbeam-utils 0.7.2", @@ -3909,13 +4074,26 @@ dependencies = [ "semver", ] +[[package]] +name = "rustls" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" +dependencies = [ + "base64 0.10.1", + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "rustls" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81" dependencies = [ - "base64", + "base64 0.12.3", "log", "ring", "sct", @@ -4424,7 +4602,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" dependencies = [ - "bytes", + "bytes 0.4.12", ] [[package]] @@ -4509,6 +4687,24 @@ dependencies = [ "unicode-xid 0.2.1", ] +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tar" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489997b7557e9a43e192c527face4feacc78bfbe6eed67fd55c4c9e381cba290" +dependencies = [ + "filetime", + "libc", + "redox_syscall", + "xattr", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -4585,7 +4781,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15ce4fc3c4cdea1a4399bb1819a539195fb69db4bbe0bde5b7c7f18fed412e02" dependencies = [ - "ascii", + "ascii 1.0.0", "chrono", "chunked_transfer", "log", @@ -4614,7 +4810,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" dependencies = [ - "bytes", + "bytes 0.4.12", "futures 0.1.29", "mio 0.6.22", "num_cpus", @@ -4632,7 +4828,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" dependencies = [ - "bytes", + "bytes 0.4.12", "either", "futures 0.1.29", ] @@ -4663,7 +4859,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ - "bytes", + "bytes 0.4.12", "futures 0.1.29", "log", ] @@ -4703,7 +4899,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" dependencies = [ - "bytes", + "bytes 0.4.12", "futures 0.1.29", "iovec", "mio 0.6.22", @@ -4975,26 +5171,52 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + [[package]] name = "untrusted" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "ureq" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801125e6d1ba6864cf3a5a92cfb2f0b0a3ee73e40602a0cd206ad2f3c040aa96" +dependencies = [ + "base64 0.11.0", + "chunked_transfer", + "cookie", + "lazy_static", + "qstring", + "rustls 0.16.0", + "url 2.1.1", + "webpki", + "webpki-roots 0.18.0", +] + [[package]] name = "ureq" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fb6c9aba13a511bcbb7770864c0e9b8392acda0454a71104498a2bb112d701" dependencies = [ - "base64", + "base64 0.12.3", "chunked_transfer", "lazy_static", "qstring", - "rustls", + "rustls 0.18.1", "url 2.1.1", "webpki", - "webpki-roots", + "webpki-roots 0.20.0", ] [[package]] @@ -5648,6 +5870,15 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki-roots" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cd5736df7f12a964a5067a12c62fa38e1bd8080aff1f80bc29be7c80d19ab4" +dependencies = [ + "webpki", +] + [[package]] name = "webpki-roots" version = "0.20.0" @@ -5804,6 +6035,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +dependencies = [ + "libc", +] + [[package]] name = "xcb" version = "0.9.0" diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 4b69213961..6132ebe8e7 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -58,7 +58,7 @@ server = {package = "veloren-server", path = "../server", optional = true} backtrace = "0.3.40" bincode = "1.2" chrono = "0.4.9" -cpal = "0.11" +cpal = "0.13" copy_dir = "0.1.2" crossbeam = "=0.7.2" deunicode = "1.0" @@ -75,7 +75,7 @@ native-dialog = { version = "0.4.2", default-features = false, optional = true } num = "0.2" ordered-float = { version = "2.0.0", default-features = false } rand = "0.7" -rodio = {version = "0.11", default-features = false, features = ["wav", "vorbis"]} +rodio = {version = "0.13", default-features = false, features = ["wav", "vorbis"]} ron = {version = "0.6", default-features = false} serde = {version = "1.0", features = [ "rc", "derive" ]} treeculler = "0.1.0" diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index 473809ea84..5dde4544fa 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -20,7 +20,7 @@ use crate::audio::{ fader::{FadeDirection, Fader}, Listener, }; -use rodio::{Device, Sample, Sink, Source, SpatialSink}; +use rodio::{Device, OutputStream, OutputStreamHandle, Sample, Sink, Source, SpatialSink}; use vek::*; #[derive(PartialEq, Clone, Copy)] @@ -53,9 +53,9 @@ pub struct MusicChannel { } impl MusicChannel { - pub fn new(device: &Device) -> Self { + pub fn new(stream: &OutputStreamHandle) -> Self { Self { - sink: Sink::new(device), + sink: Sink::try_new(stream).unwrap(), tag: MusicChannelTag::TitleMusic, state: ChannelState::Stopped, fader: Fader::default(), @@ -151,9 +151,10 @@ pub struct SfxChannel { } impl SfxChannel { - pub fn new(device: &Device) -> Self { + pub fn new(stream: &OutputStreamHandle) -> Self { Self { - sink: SpatialSink::new(device, [0.0; 3], [1.0, 0.0, 0.0], [-1.0, 0.0, 0.0]), + sink: SpatialSink::try_new(stream, [0.0; 3], [1.0, 0.0, 0.0], [-1.0, 0.0, 0.0]) + .unwrap(), pos: Vec3::zero(), } } diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 6065d3b8db..7f81e5aebf 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -14,7 +14,7 @@ use tracing::warn; use common::assets; use cpal::traits::DeviceTrait; -use rodio::{source::Source, Decoder, Device}; +use rodio::{source::Source, Decoder, Device, OutputStream, OutputStreamHandle, StreamError}; use vek::*; #[derive(Default, Clone)] @@ -31,9 +31,10 @@ pub struct Listener { /// Voxygen's [`GlobalState`](../struct.GlobalState.html#structfield.audio) to /// provide access to devices and playback control in-game pub struct AudioFrontend { - pub device: String, - pub device_list: Vec, - audio_device: Option, + //pub device: String, + pub stream: Option, + //pub device_list: Vec, + audio_stream: Option, sound_cache: SoundCache, music_channels: Vec, @@ -45,18 +46,23 @@ pub struct AudioFrontend { impl AudioFrontend { /// Construct with given device - pub fn new(device: String, max_sfx_channels: usize) -> Self { - let audio_device = get_device_raw(&device); + pub fn new(max_sfx_channels: usize) -> Self { + //let audio_device = get_device_raw(&device); + let (stream, audio_stream) = match get_default_stream() { + Ok(s) => (Some(s.0), Some(s.1)), + Err(_) => (None, None), + }; let mut sfx_channels = Vec::with_capacity(max_sfx_channels); - if let Some(audio_device) = &audio_device { - sfx_channels.resize_with(max_sfx_channels, || SfxChannel::new(&audio_device)); - } + if let Some(audio_stream) = &audio_stream { + sfx_channels.resize_with(max_sfx_channels, || SfxChannel::new(audio_stream)); + }; Self { - device, - device_list: list_devices(), - audio_device, + //device, + //device_list: list_devices(), + stream, + audio_stream, sound_cache: SoundCache::default(), music_channels: Vec::new(), sfx_channels, @@ -69,9 +75,11 @@ impl AudioFrontend { /// Construct in `no-audio` mode for debugging pub fn no_audio() -> Self { Self { - device: "none".to_string(), - device_list: Vec::new(), - audio_device: None, + //device: "none".to_string(), + //device_list: Vec::new(), + //audio_device: None, + stream: None, + audio_stream: None, sound_cache: SoundCache::default(), music_channels: Vec::new(), sfx_channels: Vec::new(), @@ -91,7 +99,7 @@ impl AudioFrontend { } fn get_sfx_channel(&mut self) -> Option<&mut SfxChannel> { - if self.audio_device.is_some() { + if self.audio_stream.is_some() { if let Some(channel) = self.sfx_channels.iter_mut().find(|c| c.is_done()) { channel.set_volume(self.sfx_volume); @@ -111,9 +119,9 @@ impl AudioFrontend { &mut self, next_channel_tag: MusicChannelTag, ) -> Option<&mut MusicChannel> { - if let Some(audio_device) = &self.audio_device { + if let Some(audio_stream) = &self.audio_stream { if self.music_channels.is_empty() { - let mut next_music_channel = MusicChannel::new(&audio_device); + let mut next_music_channel = MusicChannel::new(audio_stream); next_music_channel.set_volume(self.music_volume); self.music_channels.push(next_music_channel); @@ -125,7 +133,7 @@ impl AudioFrontend { existing_channel .set_fader(Fader::fade_out(Duration::from_secs(2), self.music_volume)); - let mut next_music_channel = MusicChannel::new(&audio_device); + let mut next_music_channel = MusicChannel::new(&audio_stream); next_music_channel .set_fader(Fader::fade_in(Duration::from_secs(12), self.music_volume)); @@ -140,7 +148,7 @@ impl AudioFrontend { /// Play (once) an sfx file by file path at the give position and volume pub fn play_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { - if self.audio_device.is_some() { + if self.audio_stream.is_some() { let sound = self .sound_cache .load_sound(sound) @@ -258,47 +266,52 @@ 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); - } + //// 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); + //} } -/// Returns the default audio device. -/// Does not return rodio Device struct in case our audio backend changes. -pub fn get_default_device() -> Option { - match rodio::default_output_device() { - Some(x) => Some(x.name().ok()?), - None => None, - } +///// Returns the default audio device. +///// Does not return rodio Device struct in case our audio backend changes. +//pub fn get_default_device() -> Option { +// match rodio::default_output_device() { +// Some(x) => Some(x.name().ok()?), +// None => None, +// } +//} + +/// Returns the default stream +pub fn get_default_stream() -> Result<(OutputStream, OutputStreamHandle), StreamError> { + rodio::OutputStream::try_default() } -/// Returns a vec of the audio devices available. -/// Does not return rodio Device struct in case our audio backend changes. -pub fn list_devices() -> Vec { - list_devices_raw() - .iter() - .map(|x| x.name().unwrap()) - .collect() -} +///// Returns a vec of the audio devices available. +///// Does not return rodio Device struct in case our audio backend changes. +//pub fn list_devices() -> Vec { +// list_devices_raw() +// .iter() +// .map(|x| x.name().unwrap()) +// .collect() +//} -/// Returns vec of devices -fn list_devices_raw() -> Vec { - match rodio::output_devices() { - Ok(devices) => { - // Filter out any devices that the name isn't available for - devices.filter(|d| d.name().is_ok()).collect() - }, - Err(_) => { - warn!("Failed to enumerate audio output devices, audio will not be available"); - Vec::new() - }, - } -} - -fn get_device_raw(device: &str) -> Option { - list_devices_raw() - .into_iter() - .find(|d| d.name().unwrap() == device) -} +///// Returns vec of devices +//fn list_devices_raw() -> Vec { +// match rodio::output_devices() { +// Ok(devices) => { +// // Filter out any devices that the name isn't available for +// devices.filter(|d| d.name().is_ok()).collect() +// }, +// Err(_) => { +// warn!("Failed to enumerate audio output devices, audio will not be +// available"); Vec::new() +// }, +// } +//} +// +//fn get_device_raw(device: &str) -> Option { +// list_devices_raw() +// .into_iter() +// .find(|d| d.name().unwrap() == device) +//} diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 1ccf95d029..6377d57d8a 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -319,7 +319,7 @@ pub enum Event { AdjustFigureLoDRenderDistance(u32), AdjustMusicVolume(f32), AdjustSfxVolume(f32), - ChangeAudioDevice(String), + //ChangeAudioDevice(String), ChangeMaxFPS(u32), ChangeFOV(u16), ChangeGamma(f32), @@ -2131,9 +2131,9 @@ impl Hud { settings_window::Event::MaximumFPS(max_fps) => { events.push(Event::ChangeMaxFPS(max_fps)); }, - settings_window::Event::ChangeAudioDevice(name) => { - events.push(Event::ChangeAudioDevice(name)); - }, + //settings_window::Event::ChangeAudioDevice(name) => { + // events.push(Event::ChangeAudioDevice(name)); + //}, settings_window::Event::CrosshairType(crosshair_type) => { events.push(Event::CrosshairType(crosshair_type)); }, diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index 29ea570eda..506b0f1aa8 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -291,7 +291,7 @@ pub enum Event { ChangeRenderMode(Box), AdjustMusicVolume(f32), AdjustSfxVolume(f32), - ChangeAudioDevice(String), + //ChangeAudioDevice(String), MaximumFPS(u32), CrosshairTransp(f32), CrosshairType(CrosshairType), @@ -2693,30 +2693,32 @@ impl<'a> Widget for SettingsWindow<'a> { events.push(Event::AdjustSfxVolume(new_val)); } - // Audio Device Selector -------------------------------------------- - let device = &self.global_state.audio.device; - let device_list = &self.global_state.audio.device_list; - Text::new(&self.localized_strings.get("hud.settings.audio_device")) - .down_from(state.ids.sfx_volume_slider, 10.0) - .font_size(self.fonts.cyri.scale(14)) - .font_id(self.fonts.cyri.conrod_id) - .color(TEXT_COLOR) - .set(state.ids.audio_device_text, ui); + // Audio Device Selector + // -------------------------------------------- + // let device = &self.global_state.audio.device; + //let device_list = &self.global_state.audio.device_list; + //Text::new(&self.localized_strings.get("hud.settings.audio_device" + // )) .down_from(state.ids.sfx_volume_slider, 10.0) + // .font_size(self.fonts.cyri.scale(14)) + // .font_id(self.fonts.cyri.conrod_id) + // .color(TEXT_COLOR) + // .set(state.ids.audio_device_text, ui); - // Get which device is currently selected - let selected = device_list.iter().position(|x| x.contains(device)); + //// Get which device is currently selected + //let selected = device_list.iter().position(|x| + // x.contains(device)); - if let Some(clicked) = DropDownList::new(&device_list, selected) - .w_h(400.0, 22.0) - .color(MENU_BG) - .label_color(TEXT_COLOR) - .label_font_id(self.fonts.opensans.conrod_id) - .down_from(state.ids.audio_device_text, 10.0) - .set(state.ids.audio_device_list, ui) - { - let new_val = device_list[clicked].clone(); - events.push(Event::ChangeAudioDevice(new_val)); - } + //if let Some(clicked) = DropDownList::new(&device_list, selected) + // .w_h(400.0, 22.0) + // .color(MENU_BG) + // .label_color(TEXT_COLOR) + // .label_font_id(self.fonts.opensans.conrod_id) + // .down_from(state.ids.audio_device_text, 10.0) + // .set(state.ids.audio_device_list, ui) + //{ + // let new_val = device_list[clicked].clone(); + // events.push(Event::ChangeAudioDevice(new_val)); + //} } // 5) Languages Tab ----------------------------------- diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 8fe5867110..4d89a9dc79 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -144,10 +144,10 @@ fn main() { // Setup audio let mut audio = match settings.audio.output { AudioOutput::Off => None, - AudioOutput::Automatic => audio::get_default_device(), - AudioOutput::Device(ref dev) => Some(dev.clone()), + AudioOutput::Automatic => audio::get_default_stream().ok(), + //AudioOutput::Device(ref dev) => Some(dev.clone()), } - .map(|dev| AudioFrontend::new(dev, settings.audio.max_sfx_channels)) + .map(|dev| AudioFrontend::new(/* dev, */ settings.audio.max_sfx_channels)) .unwrap_or_else(AudioFrontend::no_audio); audio.set_music_volume(settings.audio.music_volume); diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 2c15a6984b..36b9914c14 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -901,12 +901,12 @@ impl PlayState for SessionState { global_state.settings.audio.sfx_volume = sfx_volume; global_state.settings.save_to_file_warn(); }, - HudEvent::ChangeAudioDevice(name) => { - global_state.audio.set_device(name.clone()); + //HudEvent::ChangeAudioDevice(name) => { + // global_state.audio.set_device(name.clone()); - global_state.settings.audio.output = AudioOutput::Device(name); - global_state.settings.save_to_file_warn(); - }, + // global_state.settings.audio.output = AudioOutput::Device(name); + // global_state.settings.save_to_file_warn(); + //}, HudEvent::ChangeMaxFPS(fps) => { global_state.settings.graphics.max_fps = fps; global_state.settings.save_to_file_warn(); diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 49d166fe47..79691e8c26 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -654,8 +654,6 @@ pub enum AudioOutput { // If this option is disabled, functions in the rodio // library MUST NOT be called. Off, - Device(String), - #[serde(other)] Automatic, } From 8f5a22671d5d0644c08ab6efee379c92b8d4de3c Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Thu, 5 Nov 2020 14:16:00 -0800 Subject: [PATCH 15/37] Re-added device selector to settings with new rodio --- voxygen/src/audio/channel.rs | 2 +- voxygen/src/audio/mod.rs | 92 +++++++++++++++---- .../src/audio/sfx/event_mapper/block/mod.rs | 6 +- voxygen/src/hud/mod.rs | 8 +- voxygen/src/hud/settings_window.rs | 48 +++++----- voxygen/src/main.rs | 6 +- voxygen/src/scene/terrain/watcher.rs | 8 ++ voxygen/src/session.rs | 10 +- 8 files changed, 120 insertions(+), 60 deletions(-) diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index 5dde4544fa..d4daae40e2 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -20,7 +20,7 @@ use crate::audio::{ fader::{FadeDirection, Fader}, Listener, }; -use rodio::{Device, OutputStream, OutputStreamHandle, Sample, Sink, Source, SpatialSink}; +use rodio::{OutputStreamHandle, Sample, Sink, Source, SpatialSink}; use vek::*; #[derive(PartialEq, Clone, Copy)] diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 7f81e5aebf..b77262cf1a 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -13,7 +13,7 @@ use std::time::Duration; use tracing::warn; use common::assets; -use cpal::traits::DeviceTrait; +use cpal::traits::{DeviceTrait, HostTrait}; use rodio::{source::Source, Decoder, Device, OutputStream, OutputStreamHandle, StreamError}; use vek::*; @@ -31,9 +31,10 @@ pub struct Listener { /// Voxygen's [`GlobalState`](../struct.GlobalState.html#structfield.audio) to /// provide access to devices and playback control in-game pub struct AudioFrontend { - //pub device: String, + pub device: String, + pub device_list: Vec, + pub audio_device: Option, pub stream: Option, - //pub device_list: Vec, audio_stream: Option, sound_cache: SoundCache, @@ -46,12 +47,33 @@ pub struct AudioFrontend { impl AudioFrontend { /// Construct with given device - pub fn new(max_sfx_channels: usize) -> Self { - //let audio_device = get_device_raw(&device); + pub fn new(dev: String, max_sfx_channels: usize) -> Self { + let audio_device = get_device_raw(&dev); + let device = match get_default_device() { + Some(d) => d, + None => "".to_string(), + }; + //if let Some(this_device) = device { + //let (stream, audio_stream) = match get_stream(&device.clone().unwrap()) { + // Ok(s) => (Some(s.0), Some(s.1)), + // Err(_) => (None, None), + //}; + //} else { let (stream, audio_stream) = match get_default_stream() { Ok(s) => (Some(s.0), Some(s.1)), Err(_) => (None, None), }; + //} + //let (stream, audio_stream) = match &device { + // Some(dev) => match get_stream(&dev) { + // Ok(s) => (Some(s.0), Some(s.1)), + // Err(_) => (None, None), + // }, + // None => match get_default_stream() { + // Ok(s) => (Some(s.0), Some(s.1)), + // Err(_) => (None, None), + // }, + //}; let mut sfx_channels = Vec::with_capacity(max_sfx_channels); if let Some(audio_stream) = &audio_stream { @@ -59,8 +81,9 @@ impl AudioFrontend { }; Self { - //device, - //device_list: list_devices(), + device, + device_list: list_devices(), + audio_device, stream, audio_stream, sound_cache: SoundCache::default(), @@ -75,9 +98,9 @@ impl AudioFrontend { /// Construct in `no-audio` mode for debugging pub fn no_audio() -> Self { Self { - //device: "none".to_string(), - //device_list: Vec::new(), - //audio_device: None, + device: "".to_string(), + device_list: Vec::new(), + audio_device: None, stream: None, audio_stream: None, sound_cache: SoundCache::default(), @@ -266,11 +289,11 @@ 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); - //} + // 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); + } } ///// Returns the default audio device. @@ -281,12 +304,25 @@ impl AudioFrontend { // None => None, // } //} +pub fn get_default_device() -> Option { + match cpal::default_host().default_output_device() { + Some(x) => Some(x.name().ok()?), + None => None, + } +} /// Returns the default stream pub fn get_default_stream() -> Result<(OutputStream, OutputStreamHandle), StreamError> { rodio::OutputStream::try_default() } +/// Returns a stream on the specified device +pub fn get_stream( + device: &rodio::Device, +) -> Result<(OutputStream, OutputStreamHandle), StreamError> { + rodio::OutputStream::try_from_device(device) +} + ///// Returns a vec of the audio devices available. ///// Does not return rodio Device struct in case our audio backend changes. //pub fn list_devices() -> Vec { @@ -309,9 +345,25 @@ pub fn get_default_stream() -> Result<(OutputStream, OutputStreamHandle), Stream // }, // } //} +fn list_devices_raw() -> Vec { + match cpal::default_host().devices() { + Ok(devices) => devices.filter(|d| d.name().is_ok()).collect(), + Err(_) => { + warn!("Failed to enumerate audio output devices, audio will not be available"); + Vec::new() + }, + } +} + +fn list_devices() -> Vec { + list_devices_raw() + .iter() + .map(|x| x.name().unwrap()) + .collect() +} // -//fn get_device_raw(device: &str) -> Option { -// list_devices_raw() -// .into_iter() -// .find(|d| d.name().unwrap() == device) -//} +fn get_device_raw(device: &str) -> Option { + list_devices_raw() + .into_iter() + .find(|d| d.name().unwrap() == device) +} diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index f0004df1b8..e4ceccd17e 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -131,7 +131,9 @@ impl EventMapper for BlockEventMapper { for sounds in sounds.iter() { if !(sounds.cond)(state) { continue; - } else if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen_bool(0.995) { + } else if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) + && thread_rng().gen_bool(0.995) + { continue; } @@ -159,7 +161,7 @@ impl EventMapper for BlockEventMapper { // Iterate through each individual block for block in blocks { - if sounds.sfx == SfxEvent::Birdcall && thread_rng().gen_bool(0.999) { + if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) && thread_rng().gen_bool(0.999) { continue; } let block_pos: Vec3 = absolute_pos + block; diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 6377d57d8a..1ccf95d029 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -319,7 +319,7 @@ pub enum Event { AdjustFigureLoDRenderDistance(u32), AdjustMusicVolume(f32), AdjustSfxVolume(f32), - //ChangeAudioDevice(String), + ChangeAudioDevice(String), ChangeMaxFPS(u32), ChangeFOV(u16), ChangeGamma(f32), @@ -2131,9 +2131,9 @@ impl Hud { settings_window::Event::MaximumFPS(max_fps) => { events.push(Event::ChangeMaxFPS(max_fps)); }, - //settings_window::Event::ChangeAudioDevice(name) => { - // events.push(Event::ChangeAudioDevice(name)); - //}, + settings_window::Event::ChangeAudioDevice(name) => { + events.push(Event::ChangeAudioDevice(name)); + }, settings_window::Event::CrosshairType(crosshair_type) => { events.push(Event::CrosshairType(crosshair_type)); }, diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index 506b0f1aa8..29ea570eda 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -291,7 +291,7 @@ pub enum Event { ChangeRenderMode(Box), AdjustMusicVolume(f32), AdjustSfxVolume(f32), - //ChangeAudioDevice(String), + ChangeAudioDevice(String), MaximumFPS(u32), CrosshairTransp(f32), CrosshairType(CrosshairType), @@ -2693,32 +2693,30 @@ impl<'a> Widget for SettingsWindow<'a> { events.push(Event::AdjustSfxVolume(new_val)); } - // Audio Device Selector - // -------------------------------------------- - // let device = &self.global_state.audio.device; - //let device_list = &self.global_state.audio.device_list; - //Text::new(&self.localized_strings.get("hud.settings.audio_device" - // )) .down_from(state.ids.sfx_volume_slider, 10.0) - // .font_size(self.fonts.cyri.scale(14)) - // .font_id(self.fonts.cyri.conrod_id) - // .color(TEXT_COLOR) - // .set(state.ids.audio_device_text, ui); + // Audio Device Selector -------------------------------------------- + let device = &self.global_state.audio.device; + let device_list = &self.global_state.audio.device_list; + Text::new(&self.localized_strings.get("hud.settings.audio_device")) + .down_from(state.ids.sfx_volume_slider, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.audio_device_text, ui); - //// Get which device is currently selected - //let selected = device_list.iter().position(|x| - // x.contains(device)); + // Get which device is currently selected + let selected = device_list.iter().position(|x| x.contains(device)); - //if let Some(clicked) = DropDownList::new(&device_list, selected) - // .w_h(400.0, 22.0) - // .color(MENU_BG) - // .label_color(TEXT_COLOR) - // .label_font_id(self.fonts.opensans.conrod_id) - // .down_from(state.ids.audio_device_text, 10.0) - // .set(state.ids.audio_device_list, ui) - //{ - // let new_val = device_list[clicked].clone(); - // events.push(Event::ChangeAudioDevice(new_val)); - //} + if let Some(clicked) = DropDownList::new(&device_list, selected) + .w_h(400.0, 22.0) + .color(MENU_BG) + .label_color(TEXT_COLOR) + .label_font_id(self.fonts.opensans.conrod_id) + .down_from(state.ids.audio_device_text, 10.0) + .set(state.ids.audio_device_list, ui) + { + let new_val = device_list[clicked].clone(); + events.push(Event::ChangeAudioDevice(new_val)); + } } // 5) Languages Tab ----------------------------------- diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 4d89a9dc79..8fe5867110 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -144,10 +144,10 @@ fn main() { // Setup audio let mut audio = match settings.audio.output { AudioOutput::Off => None, - AudioOutput::Automatic => audio::get_default_stream().ok(), - //AudioOutput::Device(ref dev) => Some(dev.clone()), + AudioOutput::Automatic => audio::get_default_device(), + AudioOutput::Device(ref dev) => Some(dev.clone()), } - .map(|dev| AudioFrontend::new(/* dev, */ settings.audio.max_sfx_channels)) + .map(|dev| AudioFrontend::new(dev, settings.audio.max_sfx_channels)) .unwrap_or_else(AudioFrontend::no_audio); audio.set_music_volume(settings.audio.music_volume); diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs index 23989f305b..8645e14954 100644 --- a/voxygen/src/scene/terrain/watcher.rs +++ b/voxygen/src/scene/terrain/watcher.rs @@ -9,6 +9,7 @@ use vek::*; pub struct BlocksOfInterest { pub leaves: Vec>, pub grass: Vec>, + pub water: Vec>, pub embers: Vec>, pub beehives: Vec>, pub reeds: Vec>, @@ -23,6 +24,7 @@ impl BlocksOfInterest { span!(_guard, "from_chunk", "BlocksOfInterest::from_chunk"); let mut leaves = Vec::new(); let mut grass = Vec::new(); + let mut water = Vec::new(); let mut embers = Vec::new(); let mut beehives = Vec::new(); let mut reeds = Vec::new(); @@ -50,6 +52,11 @@ impl BlocksOfInterest { grass.push(pos) } }, + BlockKind::Water => { + if thread_rng().gen_range(0, 16) == 0 { + water.push(pos) + } + }, _ => match block.get_sprite() { Some(SpriteKind::Ember) => embers.push(pos), Some(SpriteKind::Beehive) => beehives.push(pos), @@ -71,6 +78,7 @@ impl BlocksOfInterest { Self { leaves, grass, + water, embers, beehives, reeds, diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 36b9914c14..2c15a6984b 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -901,12 +901,12 @@ impl PlayState for SessionState { global_state.settings.audio.sfx_volume = sfx_volume; global_state.settings.save_to_file_warn(); }, - //HudEvent::ChangeAudioDevice(name) => { - // global_state.audio.set_device(name.clone()); + HudEvent::ChangeAudioDevice(name) => { + global_state.audio.set_device(name.clone()); - // global_state.settings.audio.output = AudioOutput::Device(name); - // global_state.settings.save_to_file_warn(); - //}, + global_state.settings.audio.output = AudioOutput::Device(name); + global_state.settings.save_to_file_warn(); + }, HudEvent::ChangeMaxFPS(fps) => { global_state.settings.graphics.max_fps = fps; global_state.settings.save_to_file_warn(); From 09a19749741d96b5b380155da86b4f1e4ea7486c Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Thu, 5 Nov 2020 15:12:38 -0800 Subject: [PATCH 16/37] River water sfx --- assets/voxygen/audio/sfx.ron | 6 ++++++ assets/voxygen/audio/sfx/ambient/running_water_1.wav | 3 +++ common/src/terrain/mod.rs | 6 ++++++ voxygen/src/audio/sfx/event_mapper/block/mod.rs | 7 +++++++ voxygen/src/audio/sfx/mod.rs | 1 + voxygen/src/scene/terrain/watcher.rs | 10 +++++----- world/src/lib.rs | 1 + 7 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 assets/voxygen/audio/sfx/ambient/running_water_1.wav diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index bbd864282e..5434e7818a 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -46,6 +46,12 @@ ], threshold: 15.0, ), + RunningWater: ( + files: [ + "voxygen.audio.sfx.ambient.running_water_1", + ], + threshold: 7.0, + ), // // Character States // diff --git a/assets/voxygen/audio/sfx/ambient/running_water_1.wav b/assets/voxygen/audio/sfx/ambient/running_water_1.wav new file mode 100644 index 0000000000..5c34a5eaa5 --- /dev/null +++ b/assets/voxygen/audio/sfx/ambient/running_water_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8d639dd1ba7308c053495f166836a9786ffbd31e08039763f8f641e6322422f +size 1406680 diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index 0918f1c764..02d46020e6 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -71,6 +71,7 @@ pub struct TerrainChunkMeta { //warp_factor: f32, surface_veg: f32, cave_alt: f32, + contains_river: bool, /*place: Option>, */ /*path: (Way, Path),*/ @@ -89,6 +90,7 @@ impl TerrainChunkMeta { tree_density: f32, surface_veg: f32, cave_alt: f32, + contains_river: bool, ) -> Self { Self { name, @@ -101,6 +103,7 @@ impl TerrainChunkMeta { tree_density, surface_veg, cave_alt, + contains_river, } } @@ -116,6 +119,7 @@ impl TerrainChunkMeta { tree_density: 0.0, surface_veg: 0.0, cave_alt: 0.0, + contains_river: false, } } @@ -138,6 +142,8 @@ impl TerrainChunkMeta { pub fn surface_veg(&self) -> f32 { self.surface_veg } pub fn cave_alt(&self) -> f32 { self.cave_alt } + + pub fn contains_river(&self) -> bool { self.contains_river } } // Terrain type aliases diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index e4ceccd17e..8282892a41 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -86,6 +86,13 @@ impl EventMapper for BlockEventMapper { volume: 1.0, cond: |st| st.get_day_period().is_dark(), }, + BlockSounds { + blocks: |boi| &boi.river, + range: 1, + sfx: SfxEvent::RunningWater, + volume: 1.0, + cond: |_| true, + }, //BlockSounds { // blocks: |boi| &boi.embers, // range: 1, diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index b7992d9bae..d4e56855bc 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -142,6 +142,7 @@ pub enum SfxEvent { Cricket, Frog, Bees, + RunningWater, Idle, Swim, Run, diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs index 8645e14954..ca7ef1b4f9 100644 --- a/voxygen/src/scene/terrain/watcher.rs +++ b/voxygen/src/scene/terrain/watcher.rs @@ -9,7 +9,7 @@ use vek::*; pub struct BlocksOfInterest { pub leaves: Vec>, pub grass: Vec>, - pub water: Vec>, + pub river: Vec>, pub embers: Vec>, pub beehives: Vec>, pub reeds: Vec>, @@ -24,7 +24,7 @@ impl BlocksOfInterest { span!(_guard, "from_chunk", "BlocksOfInterest::from_chunk"); let mut leaves = Vec::new(); let mut grass = Vec::new(); - let mut water = Vec::new(); + let mut river = Vec::new(); let mut embers = Vec::new(); let mut beehives = Vec::new(); let mut reeds = Vec::new(); @@ -53,8 +53,8 @@ impl BlocksOfInterest { } }, BlockKind::Water => { - if thread_rng().gen_range(0, 16) == 0 { - water.push(pos) + if chunk.meta().contains_river() && thread_rng().gen_range(0, 16) == 0 { + river.push(pos) } }, _ => match block.get_sprite() { @@ -78,7 +78,7 @@ impl BlocksOfInterest { Self { leaves, grass, - water, + river, embers, beehives, reeds, diff --git a/world/src/lib.rs b/world/src/lib.rs index 91e537e995..98455bc852 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -166,6 +166,7 @@ impl World { sim_chunk.tree_density, sim_chunk.surface_veg, sim_chunk.cave.1.alt, + sim_chunk.river.is_river(), ); let mut chunk = TerrainChunk::new(base_z, stone, air, meta); From 9b759efe41476722679f75efe0437bd709cb40e7 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Fri, 6 Nov 2020 00:05:29 -0800 Subject: [PATCH 17/37] Snow footsteps --- assets/voxygen/audio/sfx.ron | 8 ++ .../audio/sfx/footsteps/snow_step_1.wav | 4 +- .../audio/sfx/footsteps/snow_step_2.wav | 4 +- .../audio/sfx/footsteps/snow_step_3.wav | 4 +- common/src/terrain/block.rs | 1 + voxygen/src/audio/music.rs | 75 +++++++-------- .../src/audio/sfx/event_mapper/block/mod.rs | 91 +++---------------- .../audio/sfx/event_mapper/movement/mod.rs | 60 ++++++++---- voxygen/src/audio/sfx/mod.rs | 1 + world/src/block/mod.rs | 7 +- world/src/sim/mod.rs | 12 ++- 11 files changed, 113 insertions(+), 154 deletions(-) diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 5434e7818a..7deae97637 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -75,6 +75,14 @@ ], threshold: 0.25, ), + SnowRun: ( + files: [ + "voxygen.audio.sfx.footsteps.snow_step_1", + "voxygen.audio.sfx.footsteps.snow_step_2", + "voxygen.audio.sfx.footsteps.snow_step_3", + ], + threshold: 0.25, + ), ExperienceGained: ( files: [ // "voxygen.audio.sfx.character.experience_gained_1", diff --git a/assets/voxygen/audio/sfx/footsteps/snow_step_1.wav b/assets/voxygen/audio/sfx/footsteps/snow_step_1.wav index 15f1da1ff9..38fb243d2a 100644 --- a/assets/voxygen/audio/sfx/footsteps/snow_step_1.wav +++ b/assets/voxygen/audio/sfx/footsteps/snow_step_1.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14b5b2d7867a04886b235902e6655c362a6d7e26d9a7f3ab6935433c3c3a3577 -size 174854 +oid sha256:b5df4056f85354b477c81dfde450542c3684eb11ffc850ddebdd730cae5c16db +size 116752 diff --git a/assets/voxygen/audio/sfx/footsteps/snow_step_2.wav b/assets/voxygen/audio/sfx/footsteps/snow_step_2.wav index 1e79239998..28cb9352cc 100644 --- a/assets/voxygen/audio/sfx/footsteps/snow_step_2.wav +++ b/assets/voxygen/audio/sfx/footsteps/snow_step_2.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7009a1825d54f68df2c68e1bd1186793de52574d53817f60550558f8ae27ce55 -size 174854 +oid sha256:2d6ebde0ec293ba854987ac4473b3d0db0f83a9c4edfaf281b69b6fe33f49170 +size 116752 diff --git a/assets/voxygen/audio/sfx/footsteps/snow_step_3.wav b/assets/voxygen/audio/sfx/footsteps/snow_step_3.wav index 1778435063..0e05ef9814 100644 --- a/assets/voxygen/audio/sfx/footsteps/snow_step_3.wav +++ b/assets/voxygen/audio/sfx/footsteps/snow_step_3.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f3bf83db6c9d68423ee36f6c3f8e07caf37a40292b05ad730f6e6a964dcea021 -size 131654 +oid sha256:37042b31ca33c07967a8f94dac7cc8f4887e22e812f8baedc774c0adf781049d +size 87952 diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 494ee2c0ad..0cb9752003 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -42,6 +42,7 @@ make_case_elim!( Wood = 0x40, Leaves = 0x41, // 0x42 <= x < 0x50 is reserved for future tree parts + Snow = 0x50, // Covers all other cases (we sometimes have bizarrely coloured misc blocks, and also we // often want to experiment with new kinds of block without allocating them a diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 2434904bf3..96b8ecad36 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -45,7 +45,7 @@ use common::{ state::State, terrain::{BiomeKind, SitesKind}, }; -use rand::{prelude::SliceRandom, thread_rng}; +use rand::{prelude::SliceRandom, thread_rng, Rng}; use serde::Deserialize; use std::time::Instant; use tracing::warn; @@ -64,7 +64,7 @@ pub struct SoundtrackItem { title: String, path: String, /// Length of the track in seconds - length: f64, + length: f32, /// Whether this track should play during day or night timing: Option, biomes: Vec<(BiomeKind, u8)>, @@ -93,13 +93,10 @@ enum PlayState { pub struct MusicMgr { soundtrack: SoundtrackCollection, began_playing: Instant, - //began_fading: Instant, - next_track_change: f64, + next_track_change: f32, /// The title of the last track played. Used to prevent a track /// being played twice in a row last_track: String, - /*last_biome: BiomeKind, - *playing: PlayState, */ } impl MusicMgr { @@ -108,61 +105,51 @@ impl MusicMgr { Self { soundtrack: Self::load_soundtrack_items(), began_playing: Instant::now(), - //began_fading: Instant::now(), next_track_change: 0.0, last_track: String::from("None"), - /*last_biome: BiomeKind::Void, - *playing: PlayState::Stopped, */ } } /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - // Gets the current player biome - //let current_biome: BiomeKind = match client.current_chunk() { - // Some(chunk) => chunk.meta().biome(), - // _ => self.last_biome, + if let Some(current_chunk) = client.current_chunk() { + println!("biome: {:?}", current_chunk.meta().biome()); + println!("chaos: {}", current_chunk.meta().chaos()); + println!("alt: {}", current_chunk.meta().alt()); + println!("temp: {}", current_chunk.meta().temp()); + println!("tree_density: {}", current_chunk.meta().tree_density()); + println!("humidity: {}", current_chunk.meta().humidity()); + println!("cave_alt: {}", current_chunk.meta().cave_alt()); + //if let Some(position) = client.current_position() { + // println!("player_pos: {:?}", position); + } + //let player_position = match client.current_position() { + // Some(pos) => pos, + // None => Vec3::default(), //}; - - //if let Some(current_chunk) = client.current_chunk() { - // println!("biome: {:?}", current_chunk.meta().biome()); - // println!("chaos: {}", current_chunk.meta().chaos()); - // println!("alt: {}", current_chunk.meta().alt()); - // println!("temp: {}", current_chunk.meta().temp()); - // println!("tree_density: {}", - // current_chunk.meta().tree_density()); - // println!("humidity: {}", current_chunk.meta().humidity()); - // println!("cave_alt: {}", current_chunk.meta().cave_alt()); - // if let Some(position) = client.current_position() { - // println!("player_alt: {}", position[2]); - // } - //} + //let block_position = Vec3::new( + // player_position[0], + // player_position[1], + // player_position[2] - 1.0, + //) + //.map(|x| x as i32); + //let block_kind = match state.get_block(block_position) { + // Some(block) => block.kind(), + // None => BlockKind::Air, + //}; + //println!("BlockKind: {:?}", block_kind); if audio.music_enabled() && !self.soundtrack.tracks.is_empty() - && self.began_playing.elapsed().as_secs_f64() > self.next_track_change - // || self.playing == PlayState::Stopped) - // && self.playing != PlayState::FadingOut + && self.began_playing.elapsed().as_secs_f32() > self.next_track_change { self.play_random_track(audio, state, client); - // self.playing = PlayState::Playing; - //} else if current_biome != self.last_biome && self.playing == PlayState::Playing { - // audio.fade_out_exploration_music(); - // self.began_fading = Instant::now(); - // self.playing = PlayState::FadingOut; - //} else if self.began_fading.elapsed().as_secs_f64() > 5.0 - // && self.playing == PlayState::FadingOut - //{ - // audio.stop_exploration_music(); - // self.playing = PlayState::Stopped; } - //self.last_biome = current_biome; } fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - //const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0; - const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 5.0; + let silence_between_tracks_seconds: f32 = thread_rng().gen_range(30.0, 60.0); let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); @@ -217,7 +204,7 @@ impl MusicMgr { if let Ok(track) = new_maybe_track { self.last_track = String::from(&track.title); self.began_playing = Instant::now(); - self.next_track_change = track.length + SILENCE_BETWEEN_TRACKS_SECONDS; + self.next_track_change = track.length + silence_between_tracks_seconds; audio.play_exploration_music(&track.path); } diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index 8282892a41..991f72987c 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -71,6 +71,7 @@ impl EventMapper for BlockEventMapper { // Condition that must be true to play cond: fn(&State) -> bool, } + let sounds: &[BlockSounds] = &[ BlockSounds { blocks: |boi| &boi.leaves, @@ -108,7 +109,6 @@ impl EventMapper for BlockEventMapper { sfx: SfxEvent::Frog, volume: 0.8, cond: |st| st.get_day_period().is_dark(), - //cond: |_| true, }, //BlockSounds { // blocks: |boi| &boi.flowers, @@ -153,86 +153,34 @@ impl EventMapper for BlockEventMapper { // Get the positions of the blocks of type sounds let blocks = (sounds.blocks)(&chunk_data.blocks_of_interest); - //let mut my_blocks = blocks.to_vec(); - //// Reduce the number of bird calls from trees - //if sounds.sfx == SfxEvent::Birdcall { - // my_blocks = my_blocks.choose_multiple(&mut thread_rng(), 6).cloned().collect(); - // //blocks = blocks.to_vec().choose_multiple(&mut thread_rng(), 6).cloned().collect::>>().as_slice(); - //} else if sounds.sfx == SfxEvent::Cricket { - // my_blocks = my_blocks.choose_multiple(&mut thread_rng(), 6).cloned().collect(); - //} - let absolute_pos: Vec3 = Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)); // Iterate through each individual block for block in blocks { - - if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) && thread_rng().gen_bool(0.999) { - continue; - } + if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) + && thread_rng().gen_bool(0.999) + { + continue; + } let block_pos: Vec3 = absolute_pos + block; let state = self.history.entry(block_pos).or_default(); - // Convert to f32 for sfx emitter - //let block_pos = Vec3::new( - // block_pos[0] as f32, - // block_pos[1] as f32, - // block_pos[2] as f32, - //); let block_pos = block_pos.map(|x| x as f32); if Self::should_emit(state, triggers.get_key_value(&sounds.sfx)) { // If the camera is within SFX distance if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { - sfx_emitter.emit(SfxEventItem::new(sounds.sfx.clone(), Some(block_pos), Some(sounds.volume))); + sfx_emitter.emit(SfxEventItem::new( + sounds.sfx.clone(), + Some(block_pos), + Some(sounds.volume), + )); state.time = Instant::now(); state.event = sounds.sfx.clone(); } } } - - //// If the timer for this block is over the spacing - //// and the block is in the history - //if self.history.contains_key(&block_pos) { - // if self - // .history - // .get(&block_pos) - // .unwrap() // can't fail as the key is in the hashmap - // .elapsed() - // .as_secs_f32() - // > sounds.spacing - // { - // // Reset timer for this block - // self.history.insert(block_pos, Instant::now()); - - // // Convert to f32 for distance_squared function - // let block_pos = Vec3::new( - // block_pos[0] as f32, - // block_pos[1] as f32, - // block_pos[2] as f32, - // ); - - // // If the camera is within SFX distance - // if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { - // // Emit the sound - // let sfx_trigger_item = triggers.get_trigger(&sounds.sfx); - // if sfx_trigger_item.is_some() { - // ecs.read_resource::>().emit_now( - // SfxEventItem::new( - // sounds.sfx.clone(), - // Some(block_pos), - // Some(sounds.volume), - // ), - // ); - // } - // } - // } - //} else { - // // Start the timer for this block - // self.history.insert(block_pos, Instant::now()); - //} - //} }); } } @@ -260,21 +208,4 @@ impl BlockEventMapper { false } } - //fn map_event(&mut self, blocktype: BlockEmitter) -> Option { - // if self.timer.elapsed().as_secs_f32() > 1.0 { - // self.timer = Instant::now(); - // let sfx_event = match blocktype { - // BlockEmitter::Leaves => Some(SfxEvent::LevelUp), - // BlockEmitter::Grass => Some(SfxEvent::Roll), - // BlockEmitter::Embers => Some(SfxEvent::Roll), - // BlockEmitter::Beehives => Some(SfxEvent::Roll), - // BlockEmitter::Reeds => Some(SfxEvent::Roll), - // BlockEmitter::Flowers => Some(SfxEvent::Roll), - // }; - - // sfx_event - // } else { - // None - // } - //} } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index b421ecbf50..c0bc9c574b 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -10,7 +10,7 @@ use common::{ comp::{Body, CharacterState, PhysicsState, Pos, Vel}, event::EventBus, state::State, - terrain::TerrainChunk, + terrain::{BlockKind, TerrainChunk}, }; use hashbrown::HashMap; use specs::{Entity as EcsEntity, Join, WorldExt}; @@ -69,38 +69,53 @@ impl EventMapper for MovementEventMapper { .filter(|(_, e_pos, ..)| (e_pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR) { if let Some(character) = character { - let state = self.event_history.entry(entity).or_default(); + let internal_state = self.event_history.entry(entity).or_default(); + + // Get the underfoot block + let block_position = Vec3::new(pos.0.x, pos.0.y, pos.0.z - 1.0).map(|x| x as i32); + let underfoot_block_kind = match state.get_block(block_position) { + Some(block) => block.kind(), + None => BlockKind::Air, + }; let mapped_event = match body { - Body::Humanoid(_) => Self::map_movement_event(character, physics, state, vel.0), + Body::Humanoid(_) => Self::map_movement_event( + character, + physics, + internal_state, + vel.0, + underfoot_block_kind, + ), Body::QuadrupedMedium(_) | Body::QuadrupedSmall(_) | Body::QuadrupedLow(_) | Body::BirdMedium(_) | Body::BirdSmall(_) - | Body::BipedLarge(_) => Self::map_non_humanoid_movement_event(physics, vel.0), + | Body::BipedLarge(_) => { + Self::map_non_humanoid_movement_event(physics, vel.0, underfoot_block_kind) + }, _ => SfxEvent::Idle, // Ignore fish, etc... }; // Check for SFX config entry for this movement - if Self::should_emit(state, triggers.get_key_value(&mapped_event)) { + if Self::should_emit(internal_state, triggers.get_key_value(&mapped_event)) { sfx_emitter.emit(SfxEventItem::new( mapped_event.clone(), Some(pos.0), Some(Self::get_volume_for_body_type(body)), )); - state.time = Instant::now(); + internal_state.time = Instant::now(); } // update state to determine the next event. We only record the time (above) if // it was dispatched - state.event = mapped_event; - state.on_ground = physics.on_ground; + internal_state.event = mapped_event; + internal_state.on_ground = physics.on_ground; if physics.in_fluid.is_some() { - state.in_water = true; + internal_state.in_water = true; } else { - state.in_water = false; + internal_state.in_water = false; } } } @@ -162,11 +177,10 @@ impl MovementEventMapper { physics_state: &PhysicsState, previous_state: &PreviousEntityState, vel: Vec3, + underfoot_block_kind: BlockKind, ) -> SfxEvent { // Match run / roll / swim state - if physics_state.in_fluid.is_some() - //&& physics_state.in_fluid.unwrap() < 2.0 // To control different sound based on depth - && vel.magnitude() > 0.1 + if physics_state.in_fluid.is_some() && vel.magnitude() > 0.1 || !previous_state.in_water && physics_state.in_fluid.is_some() { return SfxEvent::Swim; @@ -178,7 +192,10 @@ impl MovementEventMapper { } else if matches!(character_state, CharacterState::Sneak) { SfxEvent::Sneak } else { - SfxEvent::Run + match underfoot_block_kind { + BlockKind::Snow => SfxEvent::SnowRun, + _ => SfxEvent::Run, + } }; } @@ -198,9 +215,18 @@ impl MovementEventMapper { } /// Maps a limited set of movements for other non-humanoid entities - fn map_non_humanoid_movement_event(physics_state: &PhysicsState, vel: Vec3) -> SfxEvent { - if physics_state.on_ground && vel.magnitude() > 0.1 { - SfxEvent::Run + fn map_non_humanoid_movement_event( + physics_state: &PhysicsState, + vel: Vec3, + underfoot_block_kind: BlockKind, + ) -> SfxEvent { + if physics_state.in_fluid.is_some() && vel.magnitude() > 0.1 { + return SfxEvent::Swim; + } else if physics_state.on_ground && vel.magnitude() > 0.1 { + match underfoot_block_kind { + BlockKind::Snow => SfxEvent::SnowRun, + _ => SfxEvent::Run, + } } else { SfxEvent::Idle } diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index d4e56855bc..cb72910152 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -146,6 +146,7 @@ pub enum SfxEvent { Idle, Swim, Run, + SnowRun, Roll, Sneak, Climb, diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index 53ddc1cc73..e543f6e00e 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -1,7 +1,7 @@ use crate::{ column::{ColumnGen, ColumnSample}, util::{RandomField, Sampler, SmallCache}, - IndexRef, + IndexRef, CONFIG, }; use common::terrain::{ structure::{self, StructureBlock}, @@ -67,6 +67,7 @@ impl<'a> BlockGen<'a> { // marble_small, rock, // temp, + temp, // humidity, stone_col, .. @@ -128,7 +129,9 @@ impl<'a> BlockGen<'a> { let col = Lerp::lerp(sub_surface_color, surface_color, grass_factor); // Surface Some(Block::new( - if grass_factor > 0.7 { + if temp < CONFIG.snow_temp + 0.031 { + BlockKind::Snow + } else if grass_factor > 0.7 { BlockKind::Grass } else { BlockKind::Earth diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 60bf0efe0d..2ec204b473 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -2303,13 +2303,15 @@ impl SimChunk { pub fn get_biome(&self) -> BiomeKind { if self.alt < CONFIG.sea_level { BiomeKind::Ocean - } else if self.alt > 450.0 && self.chaos > 0.4 && self.tree_density < 0.7 { - BiomeKind::Mountain - } else if self.temp > CONFIG.desert_temp && self.humidity < 0.1 { - BiomeKind::Desert + } else if self.humidity == 0.0 { + BiomeKind::Lake } else if self.temp < CONFIG.snow_temp { BiomeKind::Snowland - } else if self.tree_density > 0.65 && self.humidity > 0.9 && self.temp > 0.8 { + } else if self.alt > 450.0 && self.chaos > 0.35 && self.tree_density < 0.7 { + BiomeKind::Mountain + } else if self.temp > CONFIG.desert_temp && self.humidity < 0.6 { + BiomeKind::Desert + } else if self.tree_density > 0.65 && self.humidity > 0.7 && self.temp > 0.8 { BiomeKind::Jungle } else if self.tree_density > 0.65 { BiomeKind::Forest From 695cc7f5cb12708c20fc9bdffcef8a4944787db1 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Fri, 6 Nov 2020 17:55:59 -0800 Subject: [PATCH 18/37] Broken wind implementation --- assets/voxygen/audio/ambient/wind.ogg | 3 + assets/voxygen/audio/wind.ron | 9 ++ common/src/store.rs | 2 - voxygen/src/audio/channel.rs | 24 ++++ voxygen/src/audio/mod.rs | 39 ++++++- voxygen/src/audio/music.rs | 22 ++-- voxygen/src/audio/wind.rs | 153 ++++++++++++++++++++++++++ voxygen/src/scene/mod.rs | 8 +- 8 files changed, 242 insertions(+), 18 deletions(-) create mode 100644 assets/voxygen/audio/ambient/wind.ogg create mode 100644 assets/voxygen/audio/wind.ron create mode 100644 voxygen/src/audio/wind.rs diff --git a/assets/voxygen/audio/ambient/wind.ogg b/assets/voxygen/audio/ambient/wind.ogg new file mode 100644 index 0000000000..66a0bcf6be --- /dev/null +++ b/assets/voxygen/audio/ambient/wind.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4e34c87ebbad553857788a44c14715388edab227069a23cd8d6409458b343f8 +size 107555 diff --git a/assets/voxygen/audio/wind.ron b/assets/voxygen/audio/wind.ron new file mode 100644 index 0000000000..3939a49ec1 --- /dev/null +++ b/assets/voxygen/audio/wind.ron @@ -0,0 +1,9 @@ +( + tracks: [ + ( + path: "voxygen.audio.ambient.wind", + length: 4.5, + timing: Some(Day), + ), + ] +) diff --git a/common/src/store.rs b/common/src/store.rs index 75c957895a..e3ededbd25 100644 --- a/common/src/store.rs +++ b/common/src/store.rs @@ -11,8 +11,6 @@ pub struct Id(u64, PhantomData); impl Id { pub fn id(&self) -> u64 { self.0 } - - pub fn phantomdata(&self) -> PhantomData { self.1 } } impl Copy for Id {} diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index d4daae40e2..b88b5d0b70 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -140,6 +140,30 @@ impl MusicChannel { } } +pub struct WindChannel { + sink: Sink, +} + +impl WindChannel { + pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume); } + + pub fn new(stream: &OutputStreamHandle) -> Self { + Self { + sink: Sink::try_new(stream).unwrap(), + } + } + + pub fn play(&mut self, source: S) + where + S: Source + Send + 'static, + S::Item: Sample, + S::Item: Send, + ::Item: std::fmt::Debug, + { + self.sink.append(source); + } +} + /// An SfxChannel uses a positional audio sink, and is designed for short-lived /// audio which can be spatially controlled, but does not need control over /// playback or fading/transitions diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index b77262cf1a..0c96cbe5c9 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -5,8 +5,9 @@ pub mod fader; pub mod music; pub mod sfx; pub mod soundcache; +pub mod wind; -use channel::{MusicChannel, MusicChannelTag, SfxChannel}; +use channel::{MusicChannel, MusicChannelTag, SfxChannel, WindChannel}; use fader::Fader; use soundcache::SoundCache; use std::time::Duration; @@ -39,6 +40,7 @@ pub struct AudioFrontend { sound_cache: SoundCache, music_channels: Vec, + wind_channels: Vec, sfx_channels: Vec, sfx_volume: f32, music_volume: f32, @@ -76,8 +78,10 @@ impl AudioFrontend { //}; let mut sfx_channels = Vec::with_capacity(max_sfx_channels); + let mut wind_channels = Vec::new(); if let Some(audio_stream) = &audio_stream { sfx_channels.resize_with(max_sfx_channels, || SfxChannel::new(audio_stream)); + wind_channels.push(WindChannel::new(audio_stream)); }; Self { @@ -89,6 +93,7 @@ impl AudioFrontend { sound_cache: SoundCache::default(), music_channels: Vec::new(), sfx_channels, + wind_channels, sfx_volume: 1.0, music_volume: 1.0, listener: Listener::default(), @@ -106,6 +111,7 @@ impl AudioFrontend { sound_cache: SoundCache::default(), music_channels: Vec::new(), sfx_channels: Vec::new(), + wind_channels: Vec::new(), sfx_volume: 1.0, music_volume: 1.0, listener: Listener::default(), @@ -186,6 +192,37 @@ impl AudioFrontend { } } + fn play_wind(&mut self, sound: &str, volume_multiplier: f32) { + if self.audio_stream.is_some() { + if let Some(channel) = self.get_wind_channel(volume_multiplier) { + let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); + let sound = Decoder::new(file).expect("Failed to decode sound"); + + channel.play(sound); + } + } + } + + fn get_wind_channel(&mut self, volume_multiplier: f32) -> Option<&mut WindChannel> { + if self.audio_stream.is_some() { + if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { + channel.set_volume(self.sfx_volume * volume_multiplier); + + return Some(channel); + } + } + + None + } + + fn set_wind_volume(&mut self, volume_multiplier: f32) { + if self.audio_stream.is_some() { + if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { + channel.set_volume(self.sfx_volume * volume_multiplier); + } + } + } + fn play_music(&mut self, sound: &str, channel_tag: MusicChannelTag) { if let Some(channel) = self.get_music_channel(channel_tag) { let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 96b8ecad36..499102ccdd 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -113,17 +113,17 @@ impl MusicMgr { /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - if let Some(current_chunk) = client.current_chunk() { - println!("biome: {:?}", current_chunk.meta().biome()); - println!("chaos: {}", current_chunk.meta().chaos()); - println!("alt: {}", current_chunk.meta().alt()); - println!("temp: {}", current_chunk.meta().temp()); - println!("tree_density: {}", current_chunk.meta().tree_density()); - println!("humidity: {}", current_chunk.meta().humidity()); - println!("cave_alt: {}", current_chunk.meta().cave_alt()); - //if let Some(position) = client.current_position() { - // println!("player_pos: {:?}", position); - } + //if let Some(current_chunk) = client.current_chunk() { + //println!("biome: {:?}", current_chunk.meta().biome()); + //println!("chaos: {}", current_chunk.meta().chaos()); + //println!("alt: {}", current_chunk.meta().alt()); + //println!("temp: {}", current_chunk.meta().temp()); + //println!("tree_density: {}", current_chunk.meta().tree_density()); + //println!("humidity: {}", current_chunk.meta().humidity()); + //println!("cave_alt: {}", current_chunk.meta().cave_alt()); + //if let Some(position) = client.current_position() { + // println!("player_pos: {:?}", position); + //} //let player_position = match client.current_position() { // Some(pos) => pos, // None => Vec3::default(), diff --git a/voxygen/src/audio/wind.rs b/voxygen/src/audio/wind.rs new file mode 100644 index 0000000000..bf11383e44 --- /dev/null +++ b/voxygen/src/audio/wind.rs @@ -0,0 +1,153 @@ +//! Handles ambient wind sounds +use crate::audio::AudioFrontend; +use client::Client; +use common::{ + assets, + state::State, + terrain::{BiomeKind, SitesKind}, +}; +use rand::{prelude::SliceRandom, thread_rng, Rng}; +use serde::Deserialize; +use std::time::Instant; +use tracing::warn; + +const DAY_START_SECONDS: u32 = 28800; // 8:00 +const DAY_END_SECONDS: u32 = 70200; // 19:30 + +#[derive(Debug, Default, Deserialize)] +struct WindCollection { + tracks: Vec, +} + +/// Configuration for a single music track in the soundtrack +#[derive(Debug, Deserialize)] +pub struct WindItem { + path: String, + /// Length of the track in seconds + length: f32, + /// Whether this track should play during day or night + timing: Option, +} + +/// Allows control over when a track should play based on in-game time of day +#[derive(Debug, Deserialize, PartialEq)] +enum DayPeriod { + /// 8:00 AM to 7:30 PM + Day, + /// 7:31 PM to 6:59 AM + Night, +} + +/// Determines whether the sound is stopped, playing, or fading +#[derive(Debug, Deserialize, PartialEq)] +enum PlayState { + Playing, + Stopped, + FadingOut, + FadingIn, +} + +pub struct WindMgr { + soundtrack: WindCollection, + began_playing: Instant, + next_track_change: f32, +} + +impl WindMgr { + #[allow(clippy::new_without_default)] // TODO: Pending review in #587 + pub fn new() -> Self { + Self { + soundtrack: Self::load_soundtrack_items(), + began_playing: Instant::now(), + next_track_change: 0.0, + } + } + + /// Checks whether the previous track has completed. If so, sends a + /// request to play the next (random) track + pub fn maintain(&mut self, audio: &mut AudioFrontend, _state: &State, client: &Client) { + if audio.sfx_enabled() && !self.soundtrack.tracks.is_empty() { + let alt_multiplier = ((Self::get_current_alt(client) - 250.0) / 1500.0).min(0.0); + + let tree_multiplier = 1.0 - Self::get_current_tree_density(client); + + let volume_multiplier = alt_multiplier * tree_multiplier; + + audio.set_wind_volume(volume_multiplier); + + if self.began_playing.elapsed().as_secs_f32() > self.next_track_change { + println!("Got to wind maintain"); + //let game_time = (state.get_time_of_day() as u64 % 86400) as u32; + //let current_period_of_day = Self::get_current_day_period(game_time); + let track = &self.soundtrack.tracks[0]; + + self.began_playing = Instant::now(); + self.next_track_change = track.length; + + //let alt_multiplier = (Self::get_current_alt(client) + // - Self::get_current_terrain_alt(client)) + // / 1500.0; + + //let tree_multiplier = 1.0 - Self::get_current_tree_density(client); + + //let volume_multiplier = alt_multiplier * tree_multiplier; + + audio.play_wind(&track.path, volume_multiplier); + } + } + } + + fn get_current_day_period(game_time: u32) -> DayPeriod { + if game_time > DAY_START_SECONDS && game_time < DAY_END_SECONDS { + DayPeriod::Day + } else { + DayPeriod::Night + } + } + + fn get_current_alt(client: &Client) -> f32 { + match client.current_position() { + Some(pos) => pos.z, + None => 0.0, + } + } + + fn get_current_terrain_alt(client: &Client) -> f32 { + if let Some(chunk) = client.current_chunk() { + chunk.meta().alt() + } else { + 0.0 + } + } + + fn get_current_tree_density(client: &Client) -> f32 { + match client.current_chunk() { + Some(current_chunk) => current_chunk.meta().tree_density(), + None => 0.0, + } + } + + fn load_soundtrack_items() -> WindCollection { + match assets::load_file("voxygen.audio.wind", &["ron"]) { + Ok(file) => match ron::de::from_reader(file) { + Ok(config) => config, + Err(error) => { + warn!( + "Error parsing music config file, music will not be available: {}", + format!("{:#?}", error) + ); + + WindCollection::default() + }, + }, + Err(error) => { + warn!( + "Error reading music config file, music will not be available: {}", + format!("{:#?}", error) + ); + + WindCollection::default() + }, + } + } +} diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index cbbdd7fc9c..29824ac508 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -14,7 +14,7 @@ pub use self::{ terrain::Terrain, }; use crate::{ - audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend}, + audio::{music::MusicMgr, sfx::SfxMgr, wind::WindMgr, AudioFrontend}, render::{ create_clouds_mesh, create_pp_mesh, create_skybox_mesh, CloudsLocals, CloudsPipeline, Consts, GlobalModel, Globals, Light, LodData, Model, PostProcessLocals, @@ -103,7 +103,7 @@ pub struct Scene { figure_mgr: FigureMgr, sfx_mgr: SfxMgr, music_mgr: MusicMgr, - //ambient_mgr: AmbientMgr, + ambient_mgr: WindMgr, } pub struct SceneData<'a> { @@ -309,7 +309,7 @@ impl Scene { figure_mgr: FigureMgr::new(renderer), sfx_mgr: SfxMgr::new(), music_mgr: MusicMgr::new(), - //ambient_mgr: AmbientMgr::new(), + ambient_mgr: WindMgr::new(), } } @@ -999,7 +999,7 @@ impl Scene { &self.terrain, ); self.music_mgr.maintain(audio, scene_data.state, client); - //self.ambient_mgr.maintain(audio, scene_data.state, client); + self.ambient_mgr.maintain(audio, scene_data.state, client); } /// Render the scene using the provided `Renderer`. From f182002e380960f583192abe9fc7cbe8f3668ef6 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sat, 7 Nov 2020 02:02:29 -0800 Subject: [PATCH 19/37] Underwater and cave reverb --- voxygen/src/audio/channel.rs | 22 +++++++++ voxygen/src/audio/mod.rs | 38 +++++++++++++++ .../src/audio/sfx/event_mapper/block/mod.rs | 13 ++++++ .../audio/sfx/event_mapper/campfire/mod.rs | 2 + .../src/audio/sfx/event_mapper/combat/mod.rs | 2 + voxygen/src/audio/sfx/event_mapper/mod.rs | 5 +- .../audio/sfx/event_mapper/movement/mod.rs | 2 + .../audio/sfx/event_mapper/progression/mod.rs | 2 + voxygen/src/audio/sfx/mod.rs | 35 ++++++++++++-- voxygen/src/audio/wind.rs | 46 +++++++++++-------- voxygen/src/scene/mod.rs | 4 +- 11 files changed, 146 insertions(+), 25 deletions(-) diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index b88b5d0b70..a343cc9176 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -21,6 +21,7 @@ use crate::audio::{ Listener, }; use rodio::{OutputStreamHandle, Sample, Sink, Source, SpatialSink}; +use std::time::Duration; use vek::*; #[derive(PartialEq, Clone, Copy)] @@ -193,6 +194,27 @@ impl SfxChannel { self.sink.append(source); } + pub fn play_with_low_pass_filter(&mut self, source: S) + where + S: Sized + Send + 'static, + S: Source, + { + let source = source.low_pass(300); + self.sink.append(source); + } + + pub fn play_with_reverb(&mut self, source: S) + where + S: Sized + Send + 'static, + ::Item: Sample, + ::Item: Sync, + ::Item: Send, + ::Item: std::fmt::Debug, + { + let source = source.buffered().reverb(Duration::from_millis(200), 0.2); + self.sink.append(source); + } + pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume); } pub fn is_done(&self) -> bool { self.sink.empty() } diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 0c96cbe5c9..59235c34a6 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -192,6 +192,44 @@ impl AudioFrontend { } } + /// Play (once) an sfx file by file path at the give position and volume + /// but with the sound passed through a low pass filter to simulate + /// underwater + pub fn play_underwater_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { + if self.audio_stream.is_some() { + let sound = self + .sound_cache + .load_sound(sound) + .amplify(vol.unwrap_or(1.0)); + + let listener = self.listener.clone(); + if let Some(channel) = self.get_sfx_channel() { + channel.set_pos(pos); + channel.update(&listener); + let sound = sound.convert_samples(); + channel.play_with_low_pass_filter(sound); + } + } + } + + /// Play (once) an sfx file by file path at the give position and volume + /// but with reverb + pub fn play_reverb_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { + if self.audio_stream.is_some() { + let sound = self + .sound_cache + .load_sound(sound) + .amplify(vol.unwrap_or(1.0)); + + let listener = self.listener.clone(); + if let Some(channel) = self.get_sfx_channel() { + channel.set_pos(pos); + channel.update(&listener); + channel.play_with_reverb(sound); + } + } + } + fn play_wind(&mut self, sound: &str, volume_multiplier: f32) { if self.audio_stream.is_some() { if let Some(channel) = self.get_wind_channel(volume_multiplier) { diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index 991f72987c..02c77492c1 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -6,6 +6,7 @@ use crate::{ }; use super::EventMapper; +use client::Client; use common::{ comp::Pos, event::EventBus, spiral::Spiral2d, state::State, terrain::TerrainChunk, vol::RectRasterableVol, @@ -43,6 +44,7 @@ impl EventMapper for BlockEventMapper { camera: &Camera, triggers: &SfxTriggers, terrain: &Terrain, + client: &Client, ) { let ecs = state.ecs(); @@ -59,6 +61,12 @@ impl EventMapper for BlockEventMapper { (e.floor() as i32).div_euclid(sz as i32) }); + // For determining if underground + let terrain_alt = match client.current_chunk() { + Some(chunk) => chunk.meta().alt(), + None => 0.0, + }; + struct BlockSounds<'a> { // The function to select the blocks of interest that we should emit from blocks: fn(&'a BlocksOfInterest) -> &'a [Vec3], @@ -136,8 +144,13 @@ impl EventMapper for BlockEventMapper { // Iterate through each kind of block of interest for sounds in sounds.iter() { + // If the timing condition is false, continue if !(sounds.cond)(state) { continue; + // If the player is underground, continue + } else if player_pos.0.z < (terrain_alt - 20.0) { + continue; + // Hack to reduce the number of birdcalls (too many leaf blocks) } else if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) && thread_rng().gen_bool(0.995) { diff --git a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs index d596986ed5..8713fc0ddc 100644 --- a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs @@ -6,6 +6,7 @@ use crate::{ use super::EventMapper; +use client::Client; use common::{ comp::{object, Body, Pos}, event::EventBus, @@ -43,6 +44,7 @@ impl EventMapper for CampfireEventMapper { camera: &Camera, triggers: &SfxTriggers, _terrain: &Terrain, + _client: &Client, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs index 426a0db6c4..12453e52b1 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs @@ -7,6 +7,7 @@ use crate::{ use super::EventMapper; +use client::Client; use common::{ comp::{item::ItemKind, CharacterAbilityType, CharacterState, Loadout, Pos}, event::EventBus, @@ -46,6 +47,7 @@ impl EventMapper for CombatEventMapper { camera: &Camera, triggers: &SfxTriggers, _terrain: &Terrain, + _client: &Client, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/event_mapper/mod.rs b/voxygen/src/audio/sfx/event_mapper/mod.rs index a1e2419223..c46e16cb8e 100644 --- a/voxygen/src/audio/sfx/event_mapper/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/mod.rs @@ -4,6 +4,7 @@ mod combat; mod movement; mod progression; +use client::Client; use common::{state::State, terrain::TerrainChunk}; use block::BlockEventMapper; @@ -23,6 +24,7 @@ trait EventMapper { camera: &Camera, triggers: &SfxTriggers, terrain: &Terrain, + client: &Client, ); } @@ -50,9 +52,10 @@ impl SfxEventMapper { camera: &Camera, triggers: &SfxTriggers, terrain: &Terrain, + client: &Client, ) { for mapper in &mut self.mappers { - mapper.maintain(state, player_entity, camera, triggers, terrain); + mapper.maintain(state, player_entity, camera, triggers, terrain, client); } } } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index c0bc9c574b..7ad6fb3ce2 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -6,6 +6,7 @@ use crate::{ audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, scene::{Camera, Terrain}, }; +use client::Client; use common::{ comp::{Body, CharacterState, PhysicsState, Pos, Vel}, event::EventBus, @@ -48,6 +49,7 @@ impl EventMapper for MovementEventMapper { camera: &Camera, triggers: &SfxTriggers, _terrain: &Terrain, + _client: &Client, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/event_mapper/progression/mod.rs b/voxygen/src/audio/sfx/event_mapper/progression/mod.rs index 9f9a05a124..49e89dab45 100644 --- a/voxygen/src/audio/sfx/event_mapper/progression/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/progression/mod.rs @@ -7,6 +7,7 @@ use crate::{ scene::{Camera, Terrain}, }; +use client::Client; use common::{comp::Stats, event::EventBus, state::State, terrain::TerrainChunk}; use specs::WorldExt; @@ -33,6 +34,7 @@ impl EventMapper for ProgressionEventMapper { _camera: &Camera, triggers: &SfxTriggers, _terrain: &Terrain, + _client: &Client, ) { let ecs = state.ecs(); diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index cb72910152..41271bd087 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -87,6 +87,7 @@ use crate::{ scene::{Camera, Terrain}, }; +use client::Client; use common::{ assets, comp::{ @@ -96,7 +97,8 @@ use common::{ event::EventBus, outcome::Outcome, state::State, - terrain::TerrainChunk, + terrain::{BlockKind, TerrainChunk}, + vol::ReadVol, }; use event_mapper::SfxEventMapper; use hashbrown::HashMap; @@ -243,6 +245,7 @@ impl SfxMgr { player_entity: specs::Entity, camera: &Camera, terrain: &Terrain, + client: &Client, ) { if !audio.sfx_enabled() { return; @@ -250,13 +253,30 @@ impl SfxMgr { let ecs = state.ecs(); let focus_off = camera.get_focus_pos().map(f32::trunc); + + let cave = match client.current_chunk() { + Some(chunk) => chunk.meta().cave_alt() != 0.0, + None => false, + }; + let underwater = state + .terrain() + .get((camera.dependents().cam_pos + focus_off).map(|e| e.floor() as i32)) + .map(|b| b.kind()) + .unwrap_or(BlockKind::Air) + == BlockKind::Water; let cam_pos = camera.dependents().cam_pos + focus_off; audio.set_listener_pos(cam_pos, camera.dependents().cam_dir); // TODO: replace; deprecated in favor of outcomes - self.event_mapper - .maintain(state, player_entity, camera, &self.triggers, terrain); + self.event_mapper.maintain( + state, + player_entity, + camera, + &self.triggers, + terrain, + client, + ); // TODO: replace; deprecated in favor of outcomes let events = ecs.read_resource::>().recv_all(); @@ -283,7 +303,14 @@ impl SfxMgr { }, }; - audio.play_sfx(sfx_file, position, event.vol); + if underwater { + audio.play_underwater_sfx(sfx_file, position, event.vol); + } else if cave { + println!("Reverbbbbbbbbbb"); + audio.play_reverb_sfx(sfx_file, position, event.vol); + } else { + audio.play_sfx(sfx_file, position, event.vol); + } } else { debug!("Missing sfx trigger config for sfx event. {:?}", event.sfx); } diff --git a/voxygen/src/audio/wind.rs b/voxygen/src/audio/wind.rs index bf11383e44..c7daf89a5e 100644 --- a/voxygen/src/audio/wind.rs +++ b/voxygen/src/audio/wind.rs @@ -1,11 +1,7 @@ //! Handles ambient wind sounds -use crate::audio::AudioFrontend; +use crate::{audio::AudioFrontend, scene::Camera}; use client::Client; -use common::{ - assets, - state::State, - terrain::{BiomeKind, SitesKind}, -}; +use common::{assets, state::State, terrain::BlockKind, vol::ReadVol}; use rand::{prelude::SliceRandom, thread_rng, Rng}; use serde::Deserialize; use std::time::Instant; @@ -65,18 +61,38 @@ impl WindMgr { /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track - pub fn maintain(&mut self, audio: &mut AudioFrontend, _state: &State, client: &Client) { + pub fn maintain( + &mut self, + audio: &mut AudioFrontend, + state: &State, + client: &Client, + camera: &Camera, + ) { if audio.sfx_enabled() && !self.soundtrack.tracks.is_empty() { - let alt_multiplier = ((Self::get_current_alt(client) - 250.0) / 1500.0).min(0.0); - + let alt_multiplier = ((Self::get_current_alt(client) - 250.0) / 1200.0).abs(); let tree_multiplier = 1.0 - Self::get_current_tree_density(client); + let mut volume_multiplier = alt_multiplier * tree_multiplier; - let volume_multiplier = alt_multiplier * tree_multiplier; + let focus_off = camera.get_focus_pos().map(f32::trunc); + let cam_pos = camera.dependents().cam_pos + focus_off; + + // Checks if the camera is underwater to stop wind sounds + if state + .terrain() + .get((cam_pos).map(|e| e.floor() as i32)) + .map(|b| b.kind()) + .unwrap_or(BlockKind::Air) + == BlockKind::Water + { + volume_multiplier = volume_multiplier * 0.1; + } + if cam_pos.z < Self::get_current_terrain_alt(client) { + volume_multiplier = 0.0; + } audio.set_wind_volume(volume_multiplier); if self.began_playing.elapsed().as_secs_f32() > self.next_track_change { - println!("Got to wind maintain"); //let game_time = (state.get_time_of_day() as u64 % 86400) as u32; //let current_period_of_day = Self::get_current_day_period(game_time); let track = &self.soundtrack.tracks[0]; @@ -84,14 +100,6 @@ impl WindMgr { self.began_playing = Instant::now(); self.next_track_change = track.length; - //let alt_multiplier = (Self::get_current_alt(client) - // - Self::get_current_terrain_alt(client)) - // / 1500.0; - - //let tree_multiplier = 1.0 - Self::get_current_tree_density(client); - - //let volume_multiplier = alt_multiplier * tree_multiplier; - audio.play_wind(&track.path, volume_multiplier); } } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 29824ac508..6b59d03985 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -997,9 +997,11 @@ impl Scene { scene_data.player_entity, &self.camera, &self.terrain, + client, ); self.music_mgr.maintain(audio, scene_data.state, client); - self.ambient_mgr.maintain(audio, scene_data.state, client); + self.ambient_mgr + .maintain(audio, scene_data.state, client, &self.camera); } /// Render the scene using the provided `Renderer`. From 2d088faea4765e4f3824d9d30304c0501535436b Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sat, 7 Nov 2020 21:26:20 -0800 Subject: [PATCH 20/37] Wind transition smoothing --- voxygen/src/audio/channel.rs | 15 +-- voxygen/src/audio/mod.rs | 30 +++--- .../audio/sfx/event_mapper/movement/mod.rs | 8 +- voxygen/src/audio/sfx/mod.rs | 7 -- voxygen/src/audio/wind.rs | 94 ++++++++++++------- 5 files changed, 78 insertions(+), 76 deletions(-) diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index a343cc9176..af773cd1c5 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -21,7 +21,6 @@ use crate::audio::{ Listener, }; use rodio::{OutputStreamHandle, Sample, Sink, Source, SpatialSink}; -use std::time::Duration; use vek::*; #[derive(PartialEq, Clone, Copy)] @@ -148,6 +147,8 @@ pub struct WindChannel { impl WindChannel { pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume); } + pub fn volume(&mut self) -> f32 { self.sink.volume() } + pub fn new(stream: &OutputStreamHandle) -> Self { Self { sink: Sink::try_new(stream).unwrap(), @@ -203,18 +204,6 @@ impl SfxChannel { self.sink.append(source); } - pub fn play_with_reverb(&mut self, source: S) - where - S: Sized + Send + 'static, - ::Item: Sample, - ::Item: Sync, - ::Item: Send, - ::Item: std::fmt::Debug, - { - let source = source.buffered().reverb(Duration::from_millis(200), 0.2); - self.sink.append(source); - } - pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume); } pub fn is_done(&self) -> bool { self.sink.empty() } diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 59235c34a6..4a885b27fe 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -212,24 +212,6 @@ impl AudioFrontend { } } - /// Play (once) an sfx file by file path at the give position and volume - /// but with reverb - pub fn play_reverb_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { - if self.audio_stream.is_some() { - let sound = self - .sound_cache - .load_sound(sound) - .amplify(vol.unwrap_or(1.0)); - - let listener = self.listener.clone(); - if let Some(channel) = self.get_sfx_channel() { - channel.set_pos(pos); - channel.update(&listener); - channel.play_with_reverb(sound); - } - } - } - fn play_wind(&mut self, sound: &str, volume_multiplier: f32) { if self.audio_stream.is_some() { if let Some(channel) = self.get_wind_channel(volume_multiplier) { @@ -261,6 +243,18 @@ impl AudioFrontend { } } + fn get_wind_volume(&mut self) -> f32 { + if self.audio_stream.is_some() { + if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { + channel.volume() / self.sfx_volume + } else { + 0.0 + } + } else { + 0.0 + } + } + fn play_music(&mut self, sound: &str, channel_tag: MusicChannelTag) { if let Some(channel) = self.get_music_channel(channel_tag) { let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 7ad6fb3ce2..37720d4c3b 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -114,7 +114,7 @@ impl EventMapper for MovementEventMapper { // it was dispatched internal_state.event = mapped_event; internal_state.on_ground = physics.on_ground; - if physics.in_fluid.is_some() { + if physics.in_liquid.is_some() { internal_state.in_water = true; } else { internal_state.in_water = false; @@ -182,8 +182,8 @@ impl MovementEventMapper { underfoot_block_kind: BlockKind, ) -> SfxEvent { // Match run / roll / swim state - if physics_state.in_fluid.is_some() && vel.magnitude() > 0.1 - || !previous_state.in_water && physics_state.in_fluid.is_some() + if physics_state.in_liquid.is_some() && vel.magnitude() > 0.1 + || !previous_state.in_water && physics_state.in_liquid.is_some() { return SfxEvent::Swim; } else if physics_state.on_ground && vel.magnitude() > 0.1 @@ -222,7 +222,7 @@ impl MovementEventMapper { vel: Vec3, underfoot_block_kind: BlockKind, ) -> SfxEvent { - if physics_state.in_fluid.is_some() && vel.magnitude() > 0.1 { + if physics_state.in_liquid.is_some() && vel.magnitude() > 0.1 { return SfxEvent::Swim; } else if physics_state.on_ground && vel.magnitude() > 0.1 { match underfoot_block_kind { diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 41271bd087..241e651c05 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -254,10 +254,6 @@ impl SfxMgr { let ecs = state.ecs(); let focus_off = camera.get_focus_pos().map(f32::trunc); - let cave = match client.current_chunk() { - Some(chunk) => chunk.meta().cave_alt() != 0.0, - None => false, - }; let underwater = state .terrain() .get((camera.dependents().cam_pos + focus_off).map(|e| e.floor() as i32)) @@ -305,9 +301,6 @@ impl SfxMgr { if underwater { audio.play_underwater_sfx(sfx_file, position, event.vol); - } else if cave { - println!("Reverbbbbbbbbbb"); - audio.play_reverb_sfx(sfx_file, position, event.vol); } else { audio.play_sfx(sfx_file, position, event.vol); } diff --git a/voxygen/src/audio/wind.rs b/voxygen/src/audio/wind.rs index c7daf89a5e..909df1c8a6 100644 --- a/voxygen/src/audio/wind.rs +++ b/voxygen/src/audio/wind.rs @@ -2,13 +2,13 @@ use crate::{audio::AudioFrontend, scene::Camera}; use client::Client; use common::{assets, state::State, terrain::BlockKind, vol::ReadVol}; -use rand::{prelude::SliceRandom, thread_rng, Rng}; use serde::Deserialize; use std::time::Instant; use tracing::warn; -const DAY_START_SECONDS: u32 = 28800; // 8:00 -const DAY_END_SECONDS: u32 = 70200; // 19:30 +// For if we want wind to vary strength by time of day +//const DAY_START_SECONDS: u32 = 28800; // 8:00 +//const DAY_END_SECONDS: u32 = 70200; // 19:30 #[derive(Debug, Default, Deserialize)] struct WindCollection { @@ -21,32 +21,25 @@ pub struct WindItem { path: String, /// Length of the track in seconds length: f32, - /// Whether this track should play during day or night - timing: Option, + /* Whether this track should play during day or night + * timing: Option, */ } -/// Allows control over when a track should play based on in-game time of day -#[derive(Debug, Deserialize, PartialEq)] -enum DayPeriod { - /// 8:00 AM to 7:30 PM - Day, - /// 7:31 PM to 6:59 AM - Night, -} - -/// Determines whether the sound is stopped, playing, or fading -#[derive(Debug, Deserialize, PartialEq)] -enum PlayState { - Playing, - Stopped, - FadingOut, - FadingIn, -} +///// Allows control over when a track should play based on in-game time of day +//#[derive(Debug, Deserialize, PartialEq)] +//enum DayPeriod { +// /// 8:00 AM to 7:30 PM +// Day, +// /// 7:31 PM to 6:59 AM +// Night, +//} pub struct WindMgr { soundtrack: WindCollection, began_playing: Instant, next_track_change: f32, + volume: f32, + tree_multiplier: f32, } impl WindMgr { @@ -56,6 +49,8 @@ impl WindMgr { soundtrack: Self::load_soundtrack_items(), began_playing: Instant::now(), next_track_change: 0.0, + volume: 0.0, + tree_multiplier: 0.0, } } @@ -69,9 +64,27 @@ impl WindMgr { camera: &Camera, ) { if audio.sfx_enabled() && !self.soundtrack.tracks.is_empty() { - let alt_multiplier = ((Self::get_current_alt(client) - 250.0) / 1200.0).abs(); - let tree_multiplier = 1.0 - Self::get_current_tree_density(client); - let mut volume_multiplier = alt_multiplier * tree_multiplier; + let player_alt = Self::get_current_alt(client); + let terrain_alt = Self::get_current_terrain_alt(client); + + let alt_multiplier = (player_alt / 1200.0).abs(); + + let mut tree_multiplier = self.tree_multiplier; + let new_tree_multiplier = if (player_alt - terrain_alt) < 150.0 { + 1.0 - Self::get_current_tree_density(client) + } else { + 1.0 + }; + + if tree_multiplier < new_tree_multiplier { + tree_multiplier += 0.001; + } else if tree_multiplier > new_tree_multiplier { + tree_multiplier -= 0.001; + } + self.tree_multiplier = tree_multiplier; + + println!("tree multiplier: {}", tree_multiplier); + let mut volume_multiplier = alt_multiplier * self.tree_multiplier; let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; @@ -86,11 +99,24 @@ impl WindMgr { { volume_multiplier = volume_multiplier * 0.1; } - if cam_pos.z < Self::get_current_terrain_alt(client) { + if cam_pos.z < Self::get_current_terrain_alt(client) - 20.0 { volume_multiplier = 0.0; } - audio.set_wind_volume(volume_multiplier); + if volume_multiplier > 1.0 { + volume_multiplier = 1.0 + } + + let target_volume = volume_multiplier; + println!("target vol: {}", volume_multiplier); + + println!("current_wind_volume: {}", self.volume); + self.volume = audio.get_wind_volume(); + if self.volume < target_volume { + audio.set_wind_volume(self.volume + 0.001); + } else if self.volume > target_volume { + audio.set_wind_volume(self.volume - 0.001); + } if self.began_playing.elapsed().as_secs_f32() > self.next_track_change { //let game_time = (state.get_time_of_day() as u64 % 86400) as u32; @@ -105,13 +131,13 @@ impl WindMgr { } } - fn get_current_day_period(game_time: u32) -> DayPeriod { - if game_time > DAY_START_SECONDS && game_time < DAY_END_SECONDS { - DayPeriod::Day - } else { - DayPeriod::Night - } - } + //fn get_current_day_period(game_time: u32) -> DayPeriod { + // if game_time > DAY_START_SECONDS && game_time < DAY_END_SECONDS { + // DayPeriod::Day + // } else { + // DayPeriod::Night + // } + //} fn get_current_alt(client: &Client) -> f32 { match client.current_position() { From d47e0bbb7312ed3c37728c1341b5e0685c51cb99 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sun, 8 Nov 2020 23:05:07 -0800 Subject: [PATCH 21/37] Getting merge ready minus device picker --- assets/voxygen/audio/sfx.ron | 12 ++--- .../audio/sfx/abilities/flame_thrower.wav | 3 ++ assets/voxygen/audio/soundtrack.ron | 2 +- assets/voxygen/audio/wind.ron | 1 - voxygen/src/audio/channel.rs | 40 ++++++++++++--- voxygen/src/audio/mod.rs | 36 ++++++------- voxygen/src/audio/music.rs | 51 +++++++++++++------ .../src/audio/sfx/event_mapper/block/mod.rs | 17 ++++--- .../audio/sfx/event_mapper/campfire/mod.rs | 2 +- .../src/audio/sfx/event_mapper/combat/mod.rs | 2 +- .../audio/sfx/event_mapper/movement/mod.rs | 2 +- voxygen/src/audio/sfx/mod.rs | 18 +++++-- voxygen/src/audio/wind.rs | 7 +-- voxygen/src/scene/mod.rs | 2 +- 14 files changed, 124 insertions(+), 71 deletions(-) create mode 100644 assets/voxygen/audio/sfx/abilities/flame_thrower.wav diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 7deae97637..d933131be6 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -280,25 +280,25 @@ ), // - // Fire Rod / Regeneration Staff + // Fire Staff // Wield(Staff): ( files: [ - "voxygen.audio.sfx.weapon.staff_out", + "voxygen.audio.sfx.weapon.sword_out", ], threshold: 0.5, ), Unwield(Staff): ( files: [ - "voxygen.audio.sfx.weapon.staff_in", + "voxygen.audio.sfx.weapon.sword_in", ], threshold: 0.5, ), - Attack(BasicMelee, Staff): ( + Attack(BasicBeam, Staff): ( files: [ - "voxygen.audio.sfx.abilities.swing", + "voxygen.audio.sfx.abilities.flame_thrower", ], - threshold: 0.8, + threshold: 0.2, ), Attack(BasicRanged, Staff): ( files: [ diff --git a/assets/voxygen/audio/sfx/abilities/flame_thrower.wav b/assets/voxygen/audio/sfx/abilities/flame_thrower.wav new file mode 100644 index 0000000000..306420695b --- /dev/null +++ b/assets/voxygen/audio/sfx/abilities/flame_thrower.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:507a78da5d8e3d8a01133640803b7bda101c763c14270b6486b948c23ca75eff +size 77368 diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index 90dc6d5232..e642d24873 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -112,7 +112,7 @@ title: "Limits", path: "voxygen.audio.soundtrack.limits", length: 203.0, - timing: Some(Night), + timing: None, biomes: [], site: Some(Dungeon), artist: "badbbad", diff --git a/assets/voxygen/audio/wind.ron b/assets/voxygen/audio/wind.ron index 3939a49ec1..6505b59e4f 100644 --- a/assets/voxygen/audio/wind.ron +++ b/assets/voxygen/audio/wind.ron @@ -3,7 +3,6 @@ ( path: "voxygen.audio.ambient.wind", length: 4.5, - timing: Some(Day), ), ] ) diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index af773cd1c5..3215db600a 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -21,6 +21,7 @@ use crate::audio::{ Listener, }; use rodio::{OutputStreamHandle, Sample, Sink, Source, SpatialSink}; +use tracing::warn; use vek::*; #[derive(PartialEq, Clone, Copy)] @@ -54,11 +55,23 @@ pub struct MusicChannel { impl MusicChannel { pub fn new(stream: &OutputStreamHandle) -> Self { - Self { - sink: Sink::try_new(stream).unwrap(), - tag: MusicChannelTag::TitleMusic, - state: ChannelState::Stopped, - fader: Fader::default(), + let new_sink = Sink::try_new(stream); + match new_sink { + Ok(sink) => Self { + sink, + tag: MusicChannelTag::TitleMusic, + state: ChannelState::Stopped, + fader: Fader::default(), + }, + Err(_) => { + warn!("Failed to create a rodio sink. May not play sounds."); + Self { + sink: Sink::new_idle().0, + tag: MusicChannelTag::TitleMusic, + state: ChannelState::Stopped, + fader: Fader::default(), + } + }, } } @@ -140,6 +153,8 @@ impl MusicChannel { } } +/// A WindChannel uses a non-positional audio sink designed to play music which +/// is always heard at the player's position. pub struct WindChannel { sink: Sink, } @@ -147,11 +162,18 @@ pub struct WindChannel { impl WindChannel { pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume); } - pub fn volume(&mut self) -> f32 { self.sink.volume() } + pub fn get_volume(&mut self) -> f32 { self.sink.volume() } pub fn new(stream: &OutputStreamHandle) -> Self { - Self { - sink: Sink::try_new(stream).unwrap(), + let new_sink = Sink::try_new(stream); + match new_sink { + Ok(sink) => Self { sink }, + Err(_) => { + warn!("Failed to create rodio sink. May not play wind sounds."); + Self { + sink: Sink::new_idle().0, + } + }, } } @@ -195,6 +217,8 @@ impl SfxChannel { self.sink.append(source); } + /// Same as SfxChannel::play but with the source passed through + /// a low pass filter at 300 Hz pub fn play_with_low_pass_filter(&mut self, source: S) where S: Sized + Send + 'static, diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 4a885b27fe..194f2819d5 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -51,31 +51,24 @@ impl AudioFrontend { /// Construct with given device pub fn new(dev: String, max_sfx_channels: usize) -> Self { let audio_device = get_device_raw(&dev); + let device = match get_default_device() { Some(d) => d, None => "".to_string(), }; - //if let Some(this_device) = device { - //let (stream, audio_stream) = match get_stream(&device.clone().unwrap()) { - // Ok(s) => (Some(s.0), Some(s.1)), - // Err(_) => (None, None), - //}; - //} else { - let (stream, audio_stream) = match get_default_stream() { - Ok(s) => (Some(s.0), Some(s.1)), - Err(_) => (None, None), + + //let (stream, audio_stream) = match get_default_stream() { + let (stream, audio_stream) = if get_device_raw(&dev).is_some() { + match get_stream(&get_device_raw(&dev).unwrap()) { + Ok(s) => (Some(s.0), Some(s.1)), + Err(_) => (None, None), + } + } else { + match get_default_stream() { + Ok(s) => (Some(s.0), Some(s.1)), + Err(_) => (None, None), + } }; - //} - //let (stream, audio_stream) = match &device { - // Some(dev) => match get_stream(&dev) { - // Ok(s) => (Some(s.0), Some(s.1)), - // Err(_) => (None, None), - // }, - // None => match get_default_stream() { - // Ok(s) => (Some(s.0), Some(s.1)), - // Err(_) => (None, None), - // }, - //}; let mut sfx_channels = Vec::with_capacity(max_sfx_channels); let mut wind_channels = Vec::new(); @@ -127,6 +120,7 @@ impl AudioFrontend { } } + /// Retrive an empty sfx channel from the list fn get_sfx_channel(&mut self) -> Option<&mut SfxChannel> { if self.audio_stream.is_some() { if let Some(channel) = self.sfx_channels.iter_mut().find(|c| c.is_done()) { @@ -246,7 +240,7 @@ impl AudioFrontend { fn get_wind_volume(&mut self) -> f32 { if self.audio_stream.is_some() { if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { - channel.volume() / self.sfx_volume + channel.get_volume() / self.sfx_volume } else { 0.0 } diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 499102ccdd..761cce2044 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -50,24 +50,31 @@ use serde::Deserialize; use std::time::Instant; use tracing::warn; +// TODO These should eventually not be constants if we have seasons const DAY_START_SECONDS: u32 = 28800; // 8:00 const DAY_END_SECONDS: u32 = 70200; // 19:30 +/// Collection of all the tracks #[derive(Debug, Default, Deserialize)] struct SoundtrackCollection { + /// List of tracks tracks: Vec, } /// Configuration for a single music track in the soundtrack #[derive(Debug, Deserialize)] pub struct SoundtrackItem { + /// Song title title: String, + /// File path to asset path: String, /// Length of the track in seconds length: f32, /// Whether this track should play during day or night timing: Option, + /// What biomes this track should play in with chance of play biomes: Vec<(BiomeKind, u8)>, + /// Whether this track should play in a specific site site: Option, } @@ -91,17 +98,19 @@ enum PlayState { /// Provides methods to control music playback pub struct MusicMgr { + /// Collection of all the tracks soundtrack: SoundtrackCollection, + /// Instant at which the current track began playing began_playing: Instant, + /// Time until the next track should be played next_track_change: f32, /// The title of the last track played. Used to prevent a track /// being played twice in a row last_track: String, } -impl MusicMgr { - #[allow(clippy::new_without_default)] // TODO: Pending review in #587 - pub fn new() -> Self { +impl Default for MusicMgr { + fn default() -> Self { Self { soundtrack: Self::load_soundtrack_items(), began_playing: Instant::now(), @@ -109,7 +118,9 @@ impl MusicMgr { last_track: String::from("None"), } } +} +impl MusicMgr { /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { @@ -149,15 +160,18 @@ impl MusicMgr { } fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) { - let silence_between_tracks_seconds: f32 = thread_rng().gen_range(30.0, 60.0); + let mut rng = thread_rng(); + + // Adds a bit of randomness between plays + let silence_between_tracks_seconds: f32 = rng.gen_range(30.0, 60.0); let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); let current_biome = Self::get_current_biome(client); let current_site = Self::get_current_site(client); - let mut rng = thread_rng(); - let maybe_track = self + // Filters out tracks not matching the timing, site, and biome + let maybe_tracks = self .soundtrack .tracks .iter() @@ -167,10 +181,10 @@ impl MusicMgr { Some(period_of_day) => period_of_day == ¤t_period_of_day, None => true, } - }) - .filter(|track| match &track.site { - Some(site) => site == ¤t_site, - None => true, + && match &track.site { + Some(site) => site == ¤t_site, + None => true, + } }) .filter(|track| { let mut result = false; @@ -187,7 +201,9 @@ impl MusicMgr { }) .collect::>(); - let new_maybe_track = maybe_track.choose_weighted(&mut rng, |track| { + // Randomly selects a track from the remaining tracks weighted based + // on the biome + let new_maybe_track = maybe_tracks.choose_weighted(&mut rng, |track| { let mut chance = 0; if track.biomes.len() > 0 { for biome in track.biomes.iter() { @@ -196,6 +212,9 @@ impl MusicMgr { } } } else { + // If no biome is listed, the song is still added to the + // rotation to allow for site specific songs to play + // in any biome chance = 1; } chance @@ -228,17 +247,17 @@ impl MusicMgr { fn get_current_site(client: &Client) -> SitesKind { let mut player_alt = 0.0; if let Some(position) = client.current_position() { - player_alt = position[2]; + player_alt = position.z; } let mut cave_alt = 0.0; - let mut alt = 0.0; + let mut terrain_alt = 0.0; if let Some(chunk) = client.current_chunk() { - alt = chunk.meta().alt(); + terrain_alt = chunk.meta().alt(); cave_alt = chunk.meta().cave_alt(); } - if player_alt < (alt - 20.0) && cave_alt != 0.0 { + if player_alt < (terrain_alt - 20.0) && cave_alt != 0.0 { SitesKind::Cave - } else if player_alt < (alt - 20.0) { + } else if player_alt < (terrain_alt - 20.0) { SitesKind::Dungeon } else { SitesKind::None diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index 02c77492c1..59044cd73a 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -1,5 +1,5 @@ -/// EventMapper::Block watches the sound emitting blocks in the same -/// chunk as the player and emits ambient sfx +/// EventMapper::Block watches the sound emitting blocks within +/// chunk range of the player and emits ambient sfx use crate::{ audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, scene::{terrain::BlocksOfInterest, Camera, Terrain}, @@ -54,6 +54,7 @@ impl EventMapper for BlockEventMapper { let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; + // Get the player position and chunk let player_pos = state .read_component_copied::(player_entity) .unwrap_or_default(); @@ -137,7 +138,6 @@ impl EventMapper for BlockEventMapper { range: 1, sfx: SfxEvent::Bees, volume: 1.0, - //cond: |_| true, cond: |st| st.get_day_period().is_light(), }, ]; @@ -147,8 +147,8 @@ impl EventMapper for BlockEventMapper { // If the timing condition is false, continue if !(sounds.cond)(state) { continue; - // If the player is underground, continue - } else if player_pos.0.z < (terrain_alt - 20.0) { + // If the player is far enough underground, continue + } else if player_pos.0.z < (terrain_alt - 30.0) { continue; // Hack to reduce the number of birdcalls (too many leaf blocks) } else if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) @@ -171,6 +171,7 @@ impl EventMapper for BlockEventMapper { // Iterate through each individual block for block in blocks { + // Hack to reduce the number of bird sounds (too many leaf blocks) if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) && thread_rng().gen_bool(0.999) { @@ -189,9 +190,9 @@ impl EventMapper for BlockEventMapper { Some(block_pos), Some(sounds.volume), )); - state.time = Instant::now(); - state.event = sounds.sfx.clone(); } + state.time = Instant::now(); + state.event = sounds.sfx.clone(); } } }); @@ -213,7 +214,7 @@ impl BlockEventMapper { ) -> bool { if let Some((event, item)) = sfx_trigger_item { if &previous_state.event == event { - previous_state.time.elapsed().as_secs_f64() >= item.threshold + previous_state.time.elapsed().as_secs_f32() >= item.threshold } else { true } diff --git a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs index 8713fc0ddc..106cf9f6b4 100644 --- a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs @@ -121,7 +121,7 @@ impl CampfireEventMapper { ) -> bool { if let Some((event, item)) = sfx_trigger_item { if &previous_state.event == event { - previous_state.time.elapsed().as_secs_f64() >= item.threshold + previous_state.time.elapsed().as_secs_f32() >= item.threshold } else { true } diff --git a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs index 12453e52b1..b90031d4e2 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs @@ -121,7 +121,7 @@ impl CombatEventMapper { ) -> bool { if let Some((event, item)) = sfx_trigger_item { if &previous_state.event == event { - previous_state.time.elapsed().as_secs_f64() >= item.threshold + previous_state.time.elapsed().as_secs_f32() >= item.threshold } else { true } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 37720d4c3b..9cfe30561f 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -159,7 +159,7 @@ impl MovementEventMapper { ) -> bool { if let Some((event, item)) = sfx_trigger_item { if &previous_state.event == event { - previous_state.time.elapsed().as_secs_f64() >= item.threshold + previous_state.time.elapsed().as_secs_f32() >= item.threshold } else { true } diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 241e651c05..4e76fa0978 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -116,8 +116,11 @@ use vek::*; const SFX_DIST_LIMIT_SQR: f32 = 20000.0; pub struct SfxEventItem { + /// The SFX event that triggers this sound pub sfx: SfxEvent, + /// The position at which the sound should play pub pos: Option>, + /// The volume to play the sound at pub vol: Option, } @@ -179,6 +182,7 @@ pub enum SfxInventoryEvent { Swapped, } +// TODO Move to a separate event mapper? impl From<&InventoryUpdateEvent> for SfxEvent { fn from(value: &InventoryUpdateEvent) -> Self { match value { @@ -209,8 +213,10 @@ impl From<&InventoryUpdateEvent> for SfxEvent { #[derive(Deserialize)] pub struct SfxTriggerItem { + /// A list of SFX filepaths for this event pub files: Vec, - pub threshold: f64, + /// The time to wait before repeating this SfxEvent + pub threshold: f32, } #[derive(Deserialize, Default)] @@ -247,13 +253,16 @@ impl SfxMgr { terrain: &Terrain, client: &Client, ) { + // Checks if the SFX volume is set to zero or audio is disabled + // This prevents us from running all the following code unnecessarily if !audio.sfx_enabled() { return; } - let ecs = state.ecs(); - let focus_off = camera.get_focus_pos().map(f32::trunc); + // This checks to see if the camera is underwater. If it is, + // we pass all sfx through a low pass filter + let focus_off = camera.get_focus_pos().map(f32::trunc); let underwater = state .terrain() .get((camera.dependents().cam_pos + focus_off).map(|e| e.floor() as i32)) @@ -262,6 +271,8 @@ impl SfxMgr { == BlockKind::Water; let cam_pos = camera.dependents().cam_pos + focus_off; + // Sets the listener position to the camera position facing the + // same direction as the camera audio.set_listener_pos(cam_pos, camera.dependents().cam_dir); // TODO: replace; deprecated in favor of outcomes @@ -294,6 +305,7 @@ impl SfxMgr { .last() .expect("Failed to determine sound file for this trigger item."), _ => { + // If more than one file is listed, choose one at random let rand_step = rand::random::() % item.files.len(); &item.files[rand_step] }, diff --git a/voxygen/src/audio/wind.rs b/voxygen/src/audio/wind.rs index 909df1c8a6..f0ef72d679 100644 --- a/voxygen/src/audio/wind.rs +++ b/voxygen/src/audio/wind.rs @@ -69,6 +69,8 @@ impl WindMgr { let alt_multiplier = (player_alt / 1200.0).abs(); + // Tree density factors into wind volume. The more trees, + // the less wind let mut tree_multiplier = self.tree_multiplier; let new_tree_multiplier = if (player_alt - terrain_alt) < 150.0 { 1.0 - Self::get_current_tree_density(client) @@ -76,6 +78,7 @@ impl WindMgr { 1.0 }; + // Smooths tree_multiplier transitions between chunks if tree_multiplier < new_tree_multiplier { tree_multiplier += 0.001; } else if tree_multiplier > new_tree_multiplier { @@ -83,7 +86,6 @@ impl WindMgr { } self.tree_multiplier = tree_multiplier; - println!("tree multiplier: {}", tree_multiplier); let mut volume_multiplier = alt_multiplier * self.tree_multiplier; let focus_off = camera.get_focus_pos().map(f32::trunc); @@ -108,9 +110,8 @@ impl WindMgr { } let target_volume = volume_multiplier; - println!("target vol: {}", volume_multiplier); - println!("current_wind_volume: {}", self.volume); + // Transitions the wind smoothly self.volume = audio.get_wind_volume(); if self.volume < target_volume { audio.set_wind_volume(self.volume + 0.001); diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 6b59d03985..53385c14e8 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -308,7 +308,7 @@ impl Scene { particle_mgr: ParticleMgr::new(renderer), figure_mgr: FigureMgr::new(renderer), sfx_mgr: SfxMgr::new(), - music_mgr: MusicMgr::new(), + music_mgr: MusicMgr::default(), ambient_mgr: WindMgr::new(), } } From ea1bc2941be077c2ded88fdfedd91cfcbc5c7d3d Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sun, 8 Nov 2020 23:50:19 -0800 Subject: [PATCH 22/37] Clippy fixes --- common/src/terrain/mod.rs | 15 ++------------- voxygen/src/audio/sfx/event_mapper/block/mod.rs | 6 ++---- .../src/audio/sfx/event_mapper/movement/mod.rs | 2 +- voxygen/src/audio/wind.rs | 2 +- world/src/lib.rs | 2 -- 5 files changed, 6 insertions(+), 21 deletions(-) diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index 02d46020e6..eb1d6d800e 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -52,7 +52,6 @@ impl RectVolSize for TerrainChunkSize { pub struct TerrainChunkMeta { name: Option, biome: BiomeKind, - chaos: f32, alt: f32, //basement: f32, @@ -61,7 +60,7 @@ pub struct TerrainChunkMeta { //flux: f32, temp: f32, humidity: f32, - rockiness: f32, + //rockiness: f32, //is_cliffs: bool, //near_cliffs: bool, tree_density: f32, @@ -69,7 +68,7 @@ pub struct TerrainChunkMeta { //spawn_rate: f32, //river: RiverData, //warp_factor: f32, - surface_veg: f32, + //surface_veg: f32, cave_alt: f32, contains_river: bool, /*place: Option>, */ @@ -86,9 +85,7 @@ impl TerrainChunkMeta { alt: f32, temp: f32, humidity: f32, - rockiness: f32, tree_density: f32, - surface_veg: f32, cave_alt: f32, contains_river: bool, ) -> Self { @@ -99,9 +96,7 @@ impl TerrainChunkMeta { alt, temp, humidity, - rockiness, tree_density, - surface_veg, cave_alt, contains_river, } @@ -115,9 +110,7 @@ impl TerrainChunkMeta { alt: 0.0, temp: 0.0, humidity: 0.0, - rockiness: 0.0, tree_density: 0.0, - surface_veg: 0.0, cave_alt: 0.0, contains_river: false, } @@ -135,12 +128,8 @@ impl TerrainChunkMeta { pub fn humidity(&self) -> f32 { self.humidity } - pub fn rockiness(&self) -> f32 { self.rockiness } - pub fn tree_density(&self) -> f32 { self.tree_density } - pub fn surface_veg(&self) -> f32 { self.surface_veg } - pub fn cave_alt(&self) -> f32 { self.cave_alt } pub fn contains_river(&self) -> bool { self.contains_river } diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index 59044cd73a..ba0ebbbf27 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -145,10 +145,8 @@ impl EventMapper for BlockEventMapper { // Iterate through each kind of block of interest for sounds in sounds.iter() { // If the timing condition is false, continue - if !(sounds.cond)(state) { - continue; - // If the player is far enough underground, continue - } else if player_pos.0.z < (terrain_alt - 30.0) { + // or if the player is far enough underground, continue + if !(sounds.cond)(state) || player_pos.0.z < (terrain_alt - 30.0) { continue; // Hack to reduce the number of birdcalls (too many leaf blocks) } else if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 9cfe30561f..2a61a87d28 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -223,7 +223,7 @@ impl MovementEventMapper { underfoot_block_kind: BlockKind, ) -> SfxEvent { if physics_state.in_liquid.is_some() && vel.magnitude() > 0.1 { - return SfxEvent::Swim; + SfxEvent::Swim } else if physics_state.on_ground && vel.magnitude() > 0.1 { match underfoot_block_kind { BlockKind::Snow => SfxEvent::SnowRun, diff --git a/voxygen/src/audio/wind.rs b/voxygen/src/audio/wind.rs index f0ef72d679..1c5f31ad7d 100644 --- a/voxygen/src/audio/wind.rs +++ b/voxygen/src/audio/wind.rs @@ -99,7 +99,7 @@ impl WindMgr { .unwrap_or(BlockKind::Air) == BlockKind::Water { - volume_multiplier = volume_multiplier * 0.1; + volume_multiplier *= volume_multiplier; } if cam_pos.z < Self::get_current_terrain_alt(client) - 20.0 { volume_multiplier = 0.0; diff --git a/world/src/lib.rs b/world/src/lib.rs index 98455bc852..26b4bc2b0a 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -162,9 +162,7 @@ impl World { sim_chunk.alt, sim_chunk.temp, sim_chunk.humidity, - sim_chunk.rockiness, sim_chunk.tree_density, - sim_chunk.surface_veg, sim_chunk.cave.1.alt, sim_chunk.river.is_river(), ); From e1fcb3744e58bea35f5d12ed6792361da41f99ce Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Mon, 9 Nov 2020 16:19:21 -0800 Subject: [PATCH 23/37] Comment out audio device picker --- assets/voxygen/audio/sfx.ron | 6 + .../audio/sfx/footsteps/wood_step_1.wav | 3 + .../audio/sfx/footsteps/wood_step_2.wav | 3 + .../audio/sfx/footsteps/wood_step_3.wav | 3 + .../audio/sfx/footsteps/wood_step_4.wav | 3 + voxygen/src/audio/mod.rs | 132 +++++++----------- voxygen/src/audio/sfx/mod.rs | 11 +- voxygen/src/hud/mod.rs | 8 +- voxygen/src/hud/settings_window.rs | 48 ++++--- voxygen/src/main.rs | 17 +-- voxygen/src/session.rs | 12 +- 11 files changed, 120 insertions(+), 126 deletions(-) create mode 100644 assets/voxygen/audio/sfx/footsteps/wood_step_1.wav create mode 100644 assets/voxygen/audio/sfx/footsteps/wood_step_2.wav create mode 100644 assets/voxygen/audio/sfx/footsteps/wood_step_3.wav create mode 100644 assets/voxygen/audio/sfx/footsteps/wood_step_4.wav diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index d933131be6..9b7701454e 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -412,6 +412,12 @@ ], threshold: 0.3, ), + Inventory(CollectedItem("ShinyGem")): ( + files: [ + "voxygen.audio.sfx.weapon.staff_out", + ], + threshold: 0.3, + ), Inventory(CollectFailed): ( files: [ "voxygen.audio.sfx.inventory.add_failed", diff --git a/assets/voxygen/audio/sfx/footsteps/wood_step_1.wav b/assets/voxygen/audio/sfx/footsteps/wood_step_1.wav new file mode 100644 index 0000000000..dd93ea5476 --- /dev/null +++ b/assets/voxygen/audio/sfx/footsteps/wood_step_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7519bbdea2c5e2713ec884cf08a7c4b03d1bef30eb264091ae8c22623449a259 +size 31090 diff --git a/assets/voxygen/audio/sfx/footsteps/wood_step_2.wav b/assets/voxygen/audio/sfx/footsteps/wood_step_2.wav new file mode 100644 index 0000000000..d918f7fd9f --- /dev/null +++ b/assets/voxygen/audio/sfx/footsteps/wood_step_2.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4a3a3025be119a89064e0f48adde1f2494d9df217040626b514b047254f3742 +size 27654 diff --git a/assets/voxygen/audio/sfx/footsteps/wood_step_3.wav b/assets/voxygen/audio/sfx/footsteps/wood_step_3.wav new file mode 100644 index 0000000000..b288c2bf48 --- /dev/null +++ b/assets/voxygen/audio/sfx/footsteps/wood_step_3.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57fb2f3a6219020b9f4834eb255720b86ca49976a53867f49b74f863982c11e9 +size 25582 diff --git a/assets/voxygen/audio/sfx/footsteps/wood_step_4.wav b/assets/voxygen/audio/sfx/footsteps/wood_step_4.wav new file mode 100644 index 0000000000..afaf29fe54 --- /dev/null +++ b/assets/voxygen/audio/sfx/footsteps/wood_step_4.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50a3ab5b659a5a4d054eaf82b3e1af45cf07b54f051627c91424166d7e3cc6f3 +size 32258 diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 194f2819d5..0d9d9d0e71 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -14,8 +14,8 @@ use std::time::Duration; use tracing::warn; use common::assets; -use cpal::traits::{DeviceTrait, HostTrait}; -use rodio::{source::Source, Decoder, Device, OutputStream, OutputStreamHandle, StreamError}; +//use cpal::traits::{DeviceTrait, HostTrait}; +use rodio::{source::Source, Decoder, OutputStream, OutputStreamHandle, StreamError}; use vek::*; #[derive(Default, Clone)] @@ -32,9 +32,9 @@ pub struct Listener { /// Voxygen's [`GlobalState`](../struct.GlobalState.html#structfield.audio) to /// provide access to devices and playback control in-game pub struct AudioFrontend { - pub device: String, - pub device_list: Vec, - pub audio_device: Option, + //pub device: String, + //pub device_list: Vec, + //pub audio_device: Option, pub stream: Option, audio_stream: Option, sound_cache: SoundCache, @@ -49,25 +49,17 @@ pub struct AudioFrontend { impl AudioFrontend { /// Construct with given device - pub fn new(dev: String, max_sfx_channels: usize) -> Self { - let audio_device = get_device_raw(&dev); + pub fn new(/* dev: String, */ max_sfx_channels: usize) -> Self { + //let audio_device = get_device_raw(&dev); - let device = match get_default_device() { - Some(d) => d, - None => "".to_string(), - }; + //let device = match get_default_device() { + // Some(d) => d, + // None => "".to_string(), + //}; - //let (stream, audio_stream) = match get_default_stream() { - let (stream, audio_stream) = if get_device_raw(&dev).is_some() { - match get_stream(&get_device_raw(&dev).unwrap()) { - Ok(s) => (Some(s.0), Some(s.1)), - Err(_) => (None, None), - } - } else { - match get_default_stream() { - Ok(s) => (Some(s.0), Some(s.1)), - Err(_) => (None, None), - } + let (stream, audio_stream) = match get_default_stream() { + Ok(s) => (Some(s.0), Some(s.1)), + Err(_) => (None, None), }; let mut sfx_channels = Vec::with_capacity(max_sfx_channels); @@ -78,9 +70,9 @@ impl AudioFrontend { }; Self { - device, - device_list: list_devices(), - audio_device, + //device, + //device_list: list_devices(), + //audio_device, stream, audio_stream, sound_cache: SoundCache::default(), @@ -96,9 +88,9 @@ impl AudioFrontend { /// Construct in `no-audio` mode for debugging pub fn no_audio() -> Self { Self { - device: "".to_string(), - device_list: Vec::new(), - audio_device: None, + //device: "".to_string(), + //device_list: Vec::new(), + //audio_device: None, stream: None, audio_stream: None, sound_cache: SoundCache::default(), @@ -352,81 +344,55 @@ 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); - } + //// 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); + //} } ///// Returns the default audio device. ///// Does not return rodio Device struct in case our audio backend changes. //pub fn get_default_device() -> Option { -// match rodio::default_output_device() { +// match cpal::default_host().default_output_device() { // Some(x) => Some(x.name().ok()?), // None => None, // } //} -pub fn get_default_device() -> Option { - match cpal::default_host().default_output_device() { - Some(x) => Some(x.name().ok()?), - None => None, - } -} /// Returns the default stream pub fn get_default_stream() -> Result<(OutputStream, OutputStreamHandle), StreamError> { rodio::OutputStream::try_default() } -/// Returns a stream on the specified device -pub fn get_stream( - device: &rodio::Device, -) -> Result<(OutputStream, OutputStreamHandle), StreamError> { - rodio::OutputStream::try_from_device(device) -} - -///// Returns a vec of the audio devices available. -///// Does not return rodio Device struct in case our audio backend changes. -//pub fn list_devices() -> Vec { -// list_devices_raw() -// .iter() -// .map(|x| x.name().unwrap()) -// .collect() +///// Returns a stream on the specified device +//pub fn get_stream( +// device: &rodio::Device, +//) -> Result<(OutputStream, OutputStreamHandle), StreamError> { +// rodio::OutputStream::try_from_device(device) //} - -///// Returns vec of devices -//fn list_devices_raw() -> Vec { -// match rodio::output_devices() { -// Ok(devices) => { -// // Filter out any devices that the name isn't available for -// devices.filter(|d| d.name().is_ok()).collect() -// }, +// +//fn list_devices_raw() -> Vec { +// match cpal::default_host().devices() { +// Ok(devices) => devices.filter(|d| d.name().is_ok()).collect(), // Err(_) => { // warn!("Failed to enumerate audio output devices, audio will not be // available"); Vec::new() // }, // } //} -fn list_devices_raw() -> Vec { - match cpal::default_host().devices() { - Ok(devices) => devices.filter(|d| d.name().is_ok()).collect(), - Err(_) => { - warn!("Failed to enumerate audio output devices, audio will not be available"); - Vec::new() - }, - } -} - -fn list_devices() -> Vec { - list_devices_raw() - .iter() - .map(|x| x.name().unwrap()) - .collect() -} // -fn get_device_raw(device: &str) -> Option { - list_devices_raw() - .into_iter() - .find(|d| d.name().unwrap() == device) -} +///// Returns a vec of the audio devices available. +///// Does not return rodio Device struct in case our audio backend changes. +//fn list_devices() -> Vec { +// list_devices_raw() +// .iter() +// .map(|x| x.name().unwrap()) +// .collect() +//} +// +//fn get_device_raw(device: &str) -> Option { +// list_devices_raw() +// .into_iter() +// .find(|d| d.name().unwrap() == device) +//} diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 4e76fa0978..5f9e004719 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -174,6 +174,7 @@ pub enum SfxEvent { pub enum SfxInventoryEvent { Collected, CollectedTool(ToolKind), + CollectedItem(String), CollectFailed, Consumed(String), Debug, @@ -187,12 +188,18 @@ impl From<&InventoryUpdateEvent> for SfxEvent { fn from(value: &InventoryUpdateEvent) -> Self { match value { InventoryUpdateEvent::Collected(item) => { - // Handle sound effects for types of collected items, falling back to the - // default Collected event + // Handle sound effects for types of collected items, falling + // back to the default Collected event match &item.kind() { ItemKind::Tool(tool) => { SfxEvent::Inventory(SfxInventoryEvent::CollectedTool(tool.kind.clone())) }, + ItemKind::Ingredient { kind } => match &kind[..] { + "ShinyGem" => { + SfxEvent::Inventory(SfxInventoryEvent::CollectedItem(kind.clone())) + }, + _ => SfxEvent::Inventory(SfxInventoryEvent::Collected), + }, _ => SfxEvent::Inventory(SfxInventoryEvent::Collected), } }, diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 1ccf95d029..6377d57d8a 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -319,7 +319,7 @@ pub enum Event { AdjustFigureLoDRenderDistance(u32), AdjustMusicVolume(f32), AdjustSfxVolume(f32), - ChangeAudioDevice(String), + //ChangeAudioDevice(String), ChangeMaxFPS(u32), ChangeFOV(u16), ChangeGamma(f32), @@ -2131,9 +2131,9 @@ impl Hud { settings_window::Event::MaximumFPS(max_fps) => { events.push(Event::ChangeMaxFPS(max_fps)); }, - settings_window::Event::ChangeAudioDevice(name) => { - events.push(Event::ChangeAudioDevice(name)); - }, + //settings_window::Event::ChangeAudioDevice(name) => { + // events.push(Event::ChangeAudioDevice(name)); + //}, settings_window::Event::CrosshairType(crosshair_type) => { events.push(Event::CrosshairType(crosshair_type)); }, diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index 29ea570eda..506b0f1aa8 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -291,7 +291,7 @@ pub enum Event { ChangeRenderMode(Box), AdjustMusicVolume(f32), AdjustSfxVolume(f32), - ChangeAudioDevice(String), + //ChangeAudioDevice(String), MaximumFPS(u32), CrosshairTransp(f32), CrosshairType(CrosshairType), @@ -2693,30 +2693,32 @@ impl<'a> Widget for SettingsWindow<'a> { events.push(Event::AdjustSfxVolume(new_val)); } - // Audio Device Selector -------------------------------------------- - let device = &self.global_state.audio.device; - let device_list = &self.global_state.audio.device_list; - Text::new(&self.localized_strings.get("hud.settings.audio_device")) - .down_from(state.ids.sfx_volume_slider, 10.0) - .font_size(self.fonts.cyri.scale(14)) - .font_id(self.fonts.cyri.conrod_id) - .color(TEXT_COLOR) - .set(state.ids.audio_device_text, ui); + // Audio Device Selector + // -------------------------------------------- + // let device = &self.global_state.audio.device; + //let device_list = &self.global_state.audio.device_list; + //Text::new(&self.localized_strings.get("hud.settings.audio_device" + // )) .down_from(state.ids.sfx_volume_slider, 10.0) + // .font_size(self.fonts.cyri.scale(14)) + // .font_id(self.fonts.cyri.conrod_id) + // .color(TEXT_COLOR) + // .set(state.ids.audio_device_text, ui); - // Get which device is currently selected - let selected = device_list.iter().position(|x| x.contains(device)); + //// Get which device is currently selected + //let selected = device_list.iter().position(|x| + // x.contains(device)); - if let Some(clicked) = DropDownList::new(&device_list, selected) - .w_h(400.0, 22.0) - .color(MENU_BG) - .label_color(TEXT_COLOR) - .label_font_id(self.fonts.opensans.conrod_id) - .down_from(state.ids.audio_device_text, 10.0) - .set(state.ids.audio_device_list, ui) - { - let new_val = device_list[clicked].clone(); - events.push(Event::ChangeAudioDevice(new_val)); - } + //if let Some(clicked) = DropDownList::new(&device_list, selected) + // .w_h(400.0, 22.0) + // .color(MENU_BG) + // .label_color(TEXT_COLOR) + // .label_font_id(self.fonts.opensans.conrod_id) + // .down_from(state.ids.audio_device_text, 10.0) + // .set(state.ids.audio_device_list, ui) + //{ + // let new_val = device_list[clicked].clone(); + // events.push(Event::ChangeAudioDevice(new_val)); + //} } // 5) Languages Tab ----------------------------------- diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 8fe5867110..5bb028a9f1 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -9,7 +9,7 @@ use veloren_voxygen::{ logging, profile::Profile, run, - settings::{AudioOutput, Settings}, + settings::Settings, window::Window, GlobalState, }; @@ -142,13 +142,14 @@ fn main() { anim::init(); // Setup audio - let mut audio = match settings.audio.output { - AudioOutput::Off => None, - AudioOutput::Automatic => audio::get_default_device(), - AudioOutput::Device(ref dev) => Some(dev.clone()), - } - .map(|dev| AudioFrontend::new(dev, settings.audio.max_sfx_channels)) - .unwrap_or_else(AudioFrontend::no_audio); + //let mut audio = match settings.audio.output { + // AudioOutput::Off => None, + // AudioOutput::Automatic => audio::get_default_device(), + // AudioOutput::Device(ref dev) => Some(dev.clone()), + //} + //.map(|dev| AudioFrontend::new(dev, settings.audio.max_sfx_channels)) + //.unwrap_or_else(AudioFrontend::no_audio); + let mut audio = AudioFrontend::new(settings.audio.max_sfx_channels); audio.set_music_volume(settings.audio.music_volume); audio.set_sfx_volume(settings.audio.sfx_volume); diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 2c15a6984b..260f057086 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -7,7 +7,7 @@ use crate::{ menu::char_selection::CharSelectionState, render::Renderer, scene::{camera, CameraMode, Scene, SceneData}, - settings::{AudioOutput, ControlSettings, Settings}, + settings::{ControlSettings, Settings}, window::{AnalogGameInput, Event, GameInput}, Direction, Error, GlobalState, PlayState, PlayStateResult, }; @@ -901,12 +901,12 @@ impl PlayState for SessionState { global_state.settings.audio.sfx_volume = sfx_volume; global_state.settings.save_to_file_warn(); }, - HudEvent::ChangeAudioDevice(name) => { - global_state.audio.set_device(name.clone()); + //HudEvent::ChangeAudioDevice(name) => { + // global_state.audio.set_device(name.clone()); - global_state.settings.audio.output = AudioOutput::Device(name); - global_state.settings.save_to_file_warn(); - }, + // global_state.settings.audio.output = AudioOutput::Device(name); + // global_state.settings.save_to_file_warn(); + //}, HudEvent::ChangeMaxFPS(fps) => { global_state.settings.graphics.max_fps = fps; global_state.settings.save_to_file_warn(); From c2a2361c2277fd4909555a33cbda296e0b57f9dd Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Mon, 9 Nov 2020 16:35:43 -0800 Subject: [PATCH 24/37] Fix rebase --- common/src/terrain/block.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 0cb9752003..bfc7505ea3 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -42,8 +42,6 @@ make_case_elim!( Wood = 0x40, Leaves = 0x41, // 0x42 <= x < 0x50 is reserved for future tree parts - Snow = 0x50, - // Covers all other cases (we sometimes have bizarrely coloured misc blocks, and also we // often want to experiment with new kinds of block without allocating them a // dedicated block kind. From bc1059610b600d7f89e76fdc2682328a9652bd50 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Mon, 9 Nov 2020 16:57:30 -0800 Subject: [PATCH 25/37] More clippy fixes --- common/src/terrain/mod.rs | 34 ---------------------------------- world/src/lib.rs | 3 --- 2 files changed, 37 deletions(-) diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index eb1d6d800e..8eb024760e 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -52,39 +52,17 @@ impl RectVolSize for TerrainChunkSize { pub struct TerrainChunkMeta { name: Option, biome: BiomeKind, - chaos: f32, alt: f32, - //basement: f32, - //water_alt: f32, - //downhill: Option>, - //flux: f32, - temp: f32, - humidity: f32, - //rockiness: f32, - //is_cliffs: bool, - //near_cliffs: bool, tree_density: f32, - //forest_kind: ForestKind, - //spawn_rate: f32, - //river: RiverData, - //warp_factor: f32, - //surface_veg: f32, cave_alt: f32, contains_river: bool, - /*place: Option>, */ - - /*path: (Way, Path),*/ - /* contains_waypoint: bool, */ } impl TerrainChunkMeta { pub fn new( name: Option, biome: BiomeKind, - chaos: f32, alt: f32, - temp: f32, - humidity: f32, tree_density: f32, cave_alt: f32, contains_river: bool, @@ -92,10 +70,7 @@ impl TerrainChunkMeta { Self { name, biome, - chaos, alt, - temp, - humidity, tree_density, cave_alt, contains_river, @@ -106,10 +81,7 @@ impl TerrainChunkMeta { Self { name: None, biome: BiomeKind::Void, - chaos: 0.0, alt: 0.0, - temp: 0.0, - humidity: 0.0, tree_density: 0.0, cave_alt: 0.0, contains_river: false, @@ -120,14 +92,8 @@ impl TerrainChunkMeta { pub fn biome(&self) -> BiomeKind { self.biome } - pub fn chaos(&self) -> f32 { self.chaos } - pub fn alt(&self) -> f32 { self.alt } - pub fn temp(&self) -> f32 { self.temp } - - pub fn humidity(&self) -> f32 { self.humidity } - pub fn tree_density(&self) -> f32 { self.tree_density } pub fn cave_alt(&self) -> f32 { self.cave_alt } diff --git a/world/src/lib.rs b/world/src/lib.rs index 26b4bc2b0a..67f544e6ed 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -158,10 +158,7 @@ impl World { let meta = TerrainChunkMeta::new( sim_chunk.get_name(&self.sim), sim_chunk.get_biome(), - sim_chunk.chaos, sim_chunk.alt, - sim_chunk.temp, - sim_chunk.humidity, sim_chunk.tree_density, sim_chunk.cave.1.alt, sim_chunk.river.is_river(), From ddd970b9865262f81c39992c06e4922671a82ea3 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Mon, 9 Nov 2020 17:10:08 -0800 Subject: [PATCH 26/37] Even more clippy fixes --- voxygen/src/audio/music.rs | 4 +-- .../src/audio/sfx/event_mapper/block/mod.rs | 9 +++-- .../audio/sfx/event_mapper/campfire/mod.rs | 33 +++++++++---------- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 761cce2044..e1ae49daf0 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -188,7 +188,7 @@ impl MusicMgr { }) .filter(|track| { let mut result = false; - if track.biomes.len() > 0 { + if !track.biomes.is_empty() { for biome in track.biomes.iter() { if biome.0 == current_biome { result = true; @@ -205,7 +205,7 @@ impl MusicMgr { // on the biome let new_maybe_track = maybe_tracks.choose_weighted(&mut rng, |track| { let mut chance = 0; - if track.biomes.len() > 0 { + if !track.biomes.is_empty() { for biome in track.biomes.iter() { if biome.0 == current_biome { chance = biome.1; diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index ba0ebbbf27..b6d263208b 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -146,11 +146,10 @@ impl EventMapper for BlockEventMapper { for sounds in sounds.iter() { // If the timing condition is false, continue // or if the player is far enough underground, continue - if !(sounds.cond)(state) || player_pos.0.z < (terrain_alt - 30.0) { - continue; - // Hack to reduce the number of birdcalls (too many leaf blocks) - } else if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) - && thread_rng().gen_bool(0.995) + if !(sounds.cond)(state) + || player_pos.0.z < (terrain_alt - 30.0) + || ((sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) + && thread_rng().gen_bool(0.995)) { continue; } diff --git a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs index 106cf9f6b4..d5a94cf9a9 100644 --- a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs @@ -61,28 +61,25 @@ impl EventMapper for CampfireEventMapper { .join() .filter(|(_, _, e_pos)| (e_pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR) { - match body { - Body::Object(object::Body::CampfireLit) => { - let state = self.event_history.entry(entity).or_default(); + if let Body::Object(object::Body::CampfireLit) = body { + let state = self.event_history.entry(entity).or_default(); - let mapped_event = SfxEvent::Campfire; + let mapped_event = SfxEvent::Campfire; - // Check for SFX config entry for this movement - if Self::should_emit(state, triggers.get_key_value(&mapped_event)) { - sfx_emitter.emit(SfxEventItem::new( - mapped_event.clone(), - Some(pos.0), - Some(0.25), - )); + // Check for SFX config entry for this movement + if Self::should_emit(state, triggers.get_key_value(&mapped_event)) { + sfx_emitter.emit(SfxEventItem::new( + mapped_event.clone(), + Some(pos.0), + Some(0.25), + )); - state.time = Instant::now(); - } + state.time = Instant::now(); + } - // update state to determine the next event. We only record the time (above) if - // it was dispatched - state.event = mapped_event; - }, - _ => {}, + // update state to determine the next event. We only record the time (above) if + // it was dispatched + state.event = mapped_event; } } self.cleanup(player_entity); From 27dc43fe188eaf2bb6dc4b2f8ebb29b23eb7fef4 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Mon, 9 Nov 2020 18:00:51 -0800 Subject: [PATCH 27/37] Audio test fixes --- .../audio/sfx/event_mapper/movement/tests.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/voxygen/src/audio/sfx/event_mapper/movement/tests.rs b/voxygen/src/audio/sfx/event_mapper/movement/tests.rs index 66db5f3d81..0b54595453 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/tests.rs @@ -5,6 +5,7 @@ use common::{ bird_small, humanoid, quadruped_medium, quadruped_small, Body, CharacterState, PhysicsState, }, states, + terrain::BlockKind, }; use std::time::{Duration, Instant}; @@ -28,6 +29,7 @@ fn config_but_played_since_threshold_no_emit() { event: SfxEvent::Run, time: Instant::now(), on_ground: true, + in_water: false, }; let result = @@ -47,6 +49,7 @@ fn config_and_not_played_since_threshold_emits() { event: SfxEvent::Idle, time: Instant::now().checked_add(Duration::from_secs(1)).unwrap(), on_ground: true, + in_water: false, }; let result = @@ -68,6 +71,7 @@ fn same_previous_event_elapsed_emits() { .checked_sub(Duration::from_millis(500)) .unwrap(), on_ground: true, + in_water: false, }; let result = @@ -88,8 +92,10 @@ fn maps_idle() { event: SfxEvent::Idle, time: Instant::now(), on_ground: true, + in_water: false, }, Vec3::zero(), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::Idle); @@ -107,8 +113,10 @@ fn maps_run_with_sufficient_velocity() { event: SfxEvent::Idle, time: Instant::now(), on_ground: true, + in_water: false, }, Vec3::new(0.5, 0.8, 0.0), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::Run); @@ -126,8 +134,10 @@ fn does_not_map_run_with_insufficient_velocity() { event: SfxEvent::Idle, time: Instant::now(), on_ground: true, + in_water: false, }, Vec3::new(0.02, 0.0001, 0.0), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::Idle); @@ -142,8 +152,10 @@ fn does_not_map_run_with_sufficient_velocity_but_not_on_ground() { event: SfxEvent::Idle, time: Instant::now(), on_ground: false, + in_water: false, }, Vec3::new(0.5, 0.8, 0.0), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::Idle); @@ -173,8 +185,10 @@ fn maps_roll() { event: SfxEvent::Run, time: Instant::now(), on_ground: true, + in_water: false, }, Vec3::new(0.5, 0.5, 0.0), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::Roll); @@ -192,8 +206,10 @@ fn maps_land_on_ground_to_run() { event: SfxEvent::Idle, time: Instant::now(), on_ground: false, + in_water: false, }, Vec3::zero(), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::Run); @@ -208,8 +224,10 @@ fn maps_glider_open() { event: SfxEvent::Jump, time: Instant::now(), on_ground: false, + in_water: false, }, Vec3::zero(), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::GliderOpen); @@ -224,8 +242,10 @@ fn maps_glide() { event: SfxEvent::Glide, time: Instant::now(), on_ground: false, + in_water: false, }, Vec3::zero(), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::Glide); @@ -240,8 +260,10 @@ fn maps_glider_close_when_closing_mid_flight() { event: SfxEvent::Glide, time: Instant::now(), on_ground: false, + in_water: false, }, Vec3::zero(), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::GliderClose); @@ -260,8 +282,10 @@ fn maps_glider_close_when_landing() { event: SfxEvent::Glide, time: Instant::now(), on_ground: false, + in_water: false, }, Vec3::zero(), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::GliderClose); @@ -275,6 +299,7 @@ fn maps_quadrupeds_running() { ..Default::default() }, Vec3::new(0.5, 0.8, 0.0), + BlockKind::Grass, ); assert_eq!(result, SfxEvent::Run); From a684bc90fd28a9633e3d9fa3c61735a44e0bf6c7 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Wed, 11 Nov 2020 00:51:14 -0800 Subject: [PATCH 28/37] Quadraped footsteps and songs in biomes --- CHANGELOG.md | 4 + assets/voxygen/audio/ambient/wind.ogg | 4 +- assets/voxygen/audio/sfx.ron | 29 +- assets/voxygen/audio/soundtrack.ron | 313 ++++++++++-------- client/src/lib.rs | 8 +- common/src/terrain/site.rs | 2 +- voxygen/src/audio/mod.rs | 15 +- voxygen/src/audio/music.rs | 16 +- .../audio/sfx/event_mapper/movement/mod.rs | 28 +- voxygen/src/audio/sfx/mod.rs | 2 + voxygen/src/audio/wind.rs | 2 +- world/src/sim/mod.rs | 2 +- 12 files changed, 262 insertions(+), 163 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d709f84974..fd21d91c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upscaling support - Added "Persist Combo from Combo Melee State" when rolling mid-combo - You can no longer spam hammer and bow special when stamina is 0 +- Biome and site specific music system +- Ambient SFX emitted from terrain blocks +- Campfire SFX +- Wind SFX system ### Changed diff --git a/assets/voxygen/audio/ambient/wind.ogg b/assets/voxygen/audio/ambient/wind.ogg index 66a0bcf6be..37cac9eb05 100644 --- a/assets/voxygen/audio/ambient/wind.ogg +++ b/assets/voxygen/audio/ambient/wind.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d4e34c87ebbad553857788a44c14715388edab227069a23cd8d6409458b343f8 -size 107555 +oid sha256:c28c1067d78474057c8a5b4608bb0a6026f90377074e287bb87fbd3e8fa39098 +size 94292 diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 9b7701454e..9feadcc507 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -75,6 +75,17 @@ ], threshold: 0.25, ), + QuadRun: ( + files: [ + "voxygen.audio.sfx.footsteps.stepgrass_1", + "voxygen.audio.sfx.footsteps.stepgrass_2", + "voxygen.audio.sfx.footsteps.stepgrass_3", + "voxygen.audio.sfx.footsteps.stepgrass_4", + "voxygen.audio.sfx.footsteps.stepgrass_5", + "voxygen.audio.sfx.footsteps.stepgrass_6", + ], + threshold: 0.12, + ), SnowRun: ( files: [ "voxygen.audio.sfx.footsteps.snow_step_1", @@ -83,6 +94,14 @@ ], threshold: 0.25, ), + QuadSnowRun: ( + files: [ + "voxygen.audio.sfx.footsteps.snow_step_1", + "voxygen.audio.sfx.footsteps.snow_step_2", + "voxygen.audio.sfx.footsteps.snow_step_3", + ], + threshold: 0.12, + ), ExperienceGained: ( files: [ // "voxygen.audio.sfx.character.experience_gained_1", @@ -214,7 +233,7 @@ ], threshold: 0.5, ), - Attack(BasicMelee, Hammer): ( + Attack(ComboMelee(Swing, 1), Hammer): ( files: [ "voxygen.audio.sfx.abilities.swing", ], @@ -254,7 +273,13 @@ ], threshold: 0.5, ), - Attack(BasicMelee, Axe): ( + Attack(ComboMelee(Swing, 1), Axe): ( + files: [ + "voxygen.audio.sfx.abilities.swing", + ], + threshold: 0.7, + ), + Attack(ComboMelee(Swing, 2), Axe): ( files: [ "voxygen.audio.sfx.abilities.swing", ], diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index e642d24873..5abdb84d9b 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -1,139 +1,174 @@ -// TODO: Re-add tunes that are not fitting general outside day/night situations -// TODO: Add an ambient-soundtrack that runs independently from the musical soundtrack - -( - tracks: [ - ( - title: "A Solemn Quest", - path: "voxygen.audio.soundtrack.a_solemn_quest", - length: 206.0, - timing: Some(Day), - biomes: [ - (Lake, 1), - (Grassland, 1), - ], - site: None, - artist: "Eden", - ), - ( - title: "Into The Dark Forest", - path: "voxygen.audio.soundtrack.into_the_dark_forest", - length: 184.0, - timing: Some(Day), - biomes: [ - (Forest, 1), - (Jungle, 1), - ], - site: None, - artist: "Aeronic", - ), - ( - title: "Field Grazing", - path: "voxygen.audio.soundtrack.field_grazing", - length: 154.0, - timing: Some(Day), - biomes: [], - site: None, - artist: "Aeronic", - ), - //( - // title: "Wandering Voices", - // path: "voxygen.audio.soundtrack.wandering_voices", - // length: 137.0, - // timing: Some(Day), - // biome: Some(Desert), - // site: None, - // artist: "Aeronic", - //), - //( - // title: "Snowtop Volume", //Snow Region - // path: "voxygen.audio.soundtrack.snowtop_volume", - // length: 89.0, - // timing: Some(Day), - // biome: Some(Desert), - // site: None, - // artist: "Aeronic", - //), - //( - // title: "Mineral Deposits", - // path: "voxygen.audio.soundtrack.mineral_deposits", - // length: 148.0, - // timing: Some(Day), - // biome: Some(Desert), - // site: None, - // artist: "Aeronic", - //), - //( - // title: "Moonbeams", - // path: "voxygen.audio.soundtrack.moonbeams", - // length: 158.0, - // timing: Some(Night), - // biome: Some(Desert), - // site: None, - // artist: "Aeronic", - //), - //( - // title: "Serene Meadows", - // path: "voxygen.audio.soundtrack.serene_meadows", - // length: 173.0, - // timing: Some(Night), - // biome: Some(Desert), - // site: None, - // artist: "Aeronic", - //), - ///*( - // title: "Rest Assured", // Town/Shop - // path: "voxygen.audio.soundtrack.rest_assured", - // length: 185.0, - // timing: Some(Day), - // biome: Some(Desert), - // site: None, - // artist: "badbbad", - //),*/ - //( - // title: "Just The Beginning", - // path: "voxygen.audio.soundtrack.just_the_beginning", - // length: 188.0, - // timing: Some(Day), - // biome: Some(Desert), - // site: None, - // artist: "badbbad", - //), - //( - // title: "Campfire Stories", - // path: "voxygen.audio.soundtrack.campfire_stories", - // length: 100.0, - // timing: Some(Night), - // biome: Some(Desert), - // site: None, - // artist: "badbbad", - //), - ( - title: "Limits", - path: "voxygen.audio.soundtrack.limits", - length: 203.0, - timing: None, - biomes: [], - site: Some(Dungeon), - artist: "badbbad", - ), - ( // Dungeon - title: "Down The Rabbit Hole", - path: "voxygen.audio.soundtrack.down_the_rabbit_hole", - length: 244.0, - timing: None, - biomes: [], - site: Some(Cave), - artist: "badbbad", - ), - //( - // title: "Between The Fairies", - // path: "voxygen.audio.soundtrack.between_the_fairies", - // length: 175.0, - // timing: None, - // biomes: [], - // site: Some(Cave), - // artist: "badbbad", - //), - ] -) +// TODO: Re-add tunes that are not fitting general outside day/night situations +// TODO: Add an ambient-soundtrack that runs independently from the musical soundtrack +//Times: Some(Day), Some(Night), None +//List of biomes currently: Grassland, Forest, Jungle, Desert, Snowland, Lake, Mountain +//Sites: Cave, Dungeon + +( + tracks: [ + ( + title: "A Solemn Quest", + path: "voxygen.audio.soundtrack.a_solemn_quest", + length: 206.0, + timing: Some(Night), + biomes: [ + (Jungle, 1), + (Desert, 1), + (Grassland, 1), + (Snowland, 1), + (Mountain, 1), + (Lake, 1), + ], + site: Some(Void), + artist: "Eden", + ), + ( + title: "Into The Dark Forest", + path: "voxygen.audio.soundtrack.into_the_dark_forest", + length: 184.0, + timing: Some(Night), + biomes: [ + (Forest, 1), + (Jungle, 1), + ], + site: Some(Void), + artist: "Aeronic", + ), + ( + title: "Field Grazing", + path: "voxygen.audio.soundtrack.field_grazing", + length: 154.0, + timing: Some(Day), + biomes: [ + (Grassland, 1), + ], + site: Some(Void), + artist: "Aeronic", + ), + ( + title: "Wandering Voices", + path: "voxygen.audio.soundtrack.wandering_voices", + length: 137.0, + timing: Some(Night), + biomes: [], + site: Some(Void), + artist: "Aeronic", + ), + ( + title: "Snowtop Volume", + path: "voxygen.audio.soundtrack.snowtop_volume", + length: 89.0, + timing: None, + biomes: [ + (Snowland, 1), + (Mountain, 1), + ], + site: Some(Void), + artist: "Aeronic", + ), + ( + title: "Mineral Deposits", + path: "voxygen.audio.soundtrack.mineral_deposits", + length: 148.0, + timing: None, + biomes: [], + site: Some(Cave), + artist: "Aeronic", + ), + ( + title: "Moonbeams", + path: "voxygen.audio.soundtrack.moonbeams", + length: 158.0, + timing: Some(Night), + biomes: [], + site: Some(Void), + artist: "Aeronic", + ), + ( + title: "Serene Meadows", + path: "voxygen.audio.soundtrack.serene_meadows", + length: 173.0, + timing: Some(Night), + biomes: [ + (Forest, 1), + (Grassland, 1), + ], + site: Some(Void), + artist: "Aeronic", + ), + //( + // title: "Rest Assured", // Town/Shop + // path: "voxygen.audio.soundtrack.rest_assured", + // length: 185.0, + // timing: Some(Day), + // biomes: [], + // site: Some(Void), + // artist: "badbbad", + //), + ( + title: "Just The Beginning", + path: "voxygen.audio.soundtrack.just_the_beginning", + length: 188.0, + timing: Some(Day), + biomes: [ + (Grassland, 1), + (Snowland, 1), + (Mountain, 1), + ], + site: Some(Void), + artist: "badbbad", + ), + ( + title: "Campfire Stories", + path: "voxygen.audio.soundtrack.campfire_stories", + length: 100.0, + timing: Some(Night), + biomes: [], + site: Some(Void), + artist: "badbbad", + ), + ( + title: "Limits", + path: "voxygen.audio.soundtrack.limits", + length: 203.0, + timing: None, + biomes: [ + (Desert, 1), + (Lake, 1) + ], + site: Some(Void), + artist: "badbbad", + ), + ( + title: "Down The Rabbit Hole", + path: "voxygen.audio.soundtrack.down_the_rabbit_hole", + length: 244.0, + timing: None, + biomes: [], + site: Some(Cave), + artist: "badbbad", + ), + ( //Repeat for other site + title: "Down The Rabbit Hole", + path: "voxygen.audio.soundtrack.down_the_rabbit_hole", + length: 244.0, + timing: None, + biomes: [], + site: Some(Dungeon), + artist: "badbbad", + ), + ( + title: "Between The Fairies", + path: "voxygen.audio.soundtrack.between_the_fairies", + length: 175.0, + timing: Some(Night), + biomes: [ + (Forest, 1), + (Lake, 1), + (Snowland, 1), + ], + site: Some(Void), + artist: "badbbad", + ) + ] +) diff --git a/client/src/lib.rs b/client/src/lib.rs index 16c1db3747..dc176b8f15 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -858,7 +858,13 @@ impl Client { } pub fn current_position(&self) -> Option> { - Some(self.state.read_storage::().get(self.entity).cloned()?.0) + Some( + self.state + .read_storage::() + .get(self.entity) + .cloned()? + .0, + ) } pub fn inventories(&self) -> ReadStorage { self.state.read_storage() } diff --git a/common/src/terrain/site.rs b/common/src/terrain/site.rs index eaf69b9d86..2156de3664 100644 --- a/common/src/terrain/site.rs +++ b/common/src/terrain/site.rs @@ -6,5 +6,5 @@ pub enum SitesKind { Cave, Settlement, Castle, - None, + Void, } diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 0d9d9d0e71..9ec556affc 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -11,10 +11,9 @@ use channel::{MusicChannel, MusicChannelTag, SfxChannel, WindChannel}; use fader::Fader; use soundcache::SoundCache; use std::time::Duration; -use tracing::warn; +//use tracing::warn; use common::assets; -//use cpal::traits::{DeviceTrait, HostTrait}; use rodio::{source::Source, Decoder, OutputStream, OutputStreamHandle, StreamError}; use vek::*; @@ -32,6 +31,7 @@ pub struct Listener { /// Voxygen's [`GlobalState`](../struct.GlobalState.html#structfield.audio) to /// provide access to devices and playback control in-game pub struct AudioFrontend { + // The following is for the disabled device switcher //pub device: String, //pub device_list: Vec, //pub audio_device: Option, @@ -70,6 +70,7 @@ impl AudioFrontend { }; Self { + // The following is for the disabled device switcher //device, //device_list: list_devices(), //audio_device, @@ -88,6 +89,7 @@ impl AudioFrontend { /// Construct in `no-audio` mode for debugging pub fn no_audio() -> Self { Self { + // The following is for the disabled device switcher //device: "".to_string(), //device_list: Vec::new(), //audio_device: None, @@ -211,7 +213,7 @@ impl AudioFrontend { fn get_wind_channel(&mut self, volume_multiplier: f32) -> Option<&mut WindChannel> { if self.audio_stream.is_some() { - if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { + if let Some(channel) = self.wind_channels.iter_mut().last() { channel.set_volume(self.sfx_volume * volume_multiplier); return Some(channel); @@ -223,7 +225,7 @@ impl AudioFrontend { fn set_wind_volume(&mut self, volume_multiplier: f32) { if self.audio_stream.is_some() { - if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { + if let Some(channel) = self.wind_channels.iter_mut().last() { channel.set_volume(self.sfx_volume * volume_multiplier); } } @@ -231,7 +233,7 @@ impl AudioFrontend { fn get_wind_volume(&mut self) -> f32 { if self.audio_stream.is_some() { - if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { + if let Some(channel) = self.wind_channels.iter_mut().last() { channel.get_volume() / self.sfx_volume } else { 0.0 @@ -344,6 +346,7 @@ impl AudioFrontend { } } + // The following is for the disabled device switcher //// 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(); @@ -351,6 +354,7 @@ impl AudioFrontend { //} } +// The following is for the disabled device switcher ///// Returns the default audio device. ///// Does not return rodio Device struct in case our audio backend changes. //pub fn get_default_device() -> Option { @@ -365,6 +369,7 @@ pub fn get_default_stream() -> Result<(OutputStream, OutputStreamHandle), Stream rodio::OutputStream::try_default() } +// The following is for the disabled device switcher ///// Returns a stream on the specified device //pub fn get_stream( // device: &rodio::Device, diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index e1ae49daf0..8130b7d438 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -26,7 +26,11 @@ //! path: "voxygen.audio.soundtrack.sleepy", //! length: 400.0, //! timing: Some(Night), -//! biome: Some(Forest), +//! biome: [ +//! (Forest, 1), +//! (Grassland, 2), +//! ], +//! site: None, //! artist: "Elvis", //! ), //! ``` @@ -129,8 +133,9 @@ impl MusicMgr { //println!("chaos: {}", current_chunk.meta().chaos()); //println!("alt: {}", current_chunk.meta().alt()); //println!("temp: {}", current_chunk.meta().temp()); - //println!("tree_density: {}", current_chunk.meta().tree_density()); - //println!("humidity: {}", current_chunk.meta().humidity()); + //println!("tree_density: {}", + // current_chunk.meta().tree_density()); + // println!("humidity: {}", current_chunk.meta().humidity()); //println!("cave_alt: {}", current_chunk.meta().cave_alt()); //if let Some(position) = client.current_position() { // println!("player_pos: {:?}", position); @@ -163,7 +168,7 @@ impl MusicMgr { let mut rng = thread_rng(); // Adds a bit of randomness between plays - let silence_between_tracks_seconds: f32 = rng.gen_range(30.0, 60.0); + let silence_between_tracks_seconds: f32 = rng.gen_range(15.0, 60.0); let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); @@ -221,6 +226,7 @@ impl MusicMgr { }); if let Ok(track) = new_maybe_track { + println!("Now playing {:?}", track.title); self.last_track = String::from(&track.title); self.began_playing = Instant::now(); self.next_track_change = track.length + silence_between_tracks_seconds; @@ -260,7 +266,7 @@ impl MusicMgr { } else if player_alt < (terrain_alt - 20.0) { SitesKind::Dungeon } else { - SitesKind::None + SitesKind::Void } } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 2a61a87d28..df9d33366e 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -88,12 +88,10 @@ impl EventMapper for MovementEventMapper { vel.0, underfoot_block_kind, ), - Body::QuadrupedMedium(_) - | Body::QuadrupedSmall(_) - | Body::QuadrupedLow(_) - | Body::BirdMedium(_) - | Body::BirdSmall(_) - | Body::BipedLarge(_) => { + Body::QuadrupedMedium(_) | Body::QuadrupedSmall(_) | Body::QuadrupedLow(_) => { + Self::map_quadruped_movement_event(physics, vel.0, underfoot_block_kind) + }, + Body::BirdMedium(_) | Body::BirdSmall(_) | Body::BipedLarge(_) => { Self::map_non_humanoid_movement_event(physics, vel.0, underfoot_block_kind) }, _ => SfxEvent::Idle, // Ignore fish, etc... @@ -234,6 +232,24 @@ impl MovementEventMapper { } } + /// Maps a limited set of movements for quadruped entities + fn map_quadruped_movement_event( + physics_state: &PhysicsState, + vel: Vec3, + underfoot_block_kind: BlockKind, + ) -> SfxEvent { + if physics_state.in_liquid.is_some() && vel.magnitude() > 0.1 { + SfxEvent::Swim + } else if physics_state.on_ground && vel.magnitude() > 0.1 { + match underfoot_block_kind { + BlockKind::Snow => SfxEvent::QuadSnowRun, + _ => SfxEvent::QuadRun, + } + } else { + SfxEvent::Idle + } + } + /// Returns a relative volume value for a body type. This helps us emit sfx /// at a volume appropriate fot the entity we are emitting the event for fn get_volume_for_body_type(body: &Body) -> f32 { diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 5f9e004719..55d40531cc 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -151,7 +151,9 @@ pub enum SfxEvent { Idle, Swim, Run, + QuadRun, SnowRun, + QuadSnowRun, Roll, Sneak, Climb, diff --git a/voxygen/src/audio/wind.rs b/voxygen/src/audio/wind.rs index 1c5f31ad7d..2544dceaf5 100644 --- a/voxygen/src/audio/wind.rs +++ b/voxygen/src/audio/wind.rs @@ -101,7 +101,7 @@ impl WindMgr { { volume_multiplier *= volume_multiplier; } - if cam_pos.z < Self::get_current_terrain_alt(client) - 20.0 { + if cam_pos.z < Self::get_current_terrain_alt(client) - 10.0 { volume_multiplier = 0.0; } diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 2ec204b473..d587ba4106 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -2303,7 +2303,7 @@ impl SimChunk { pub fn get_biome(&self) -> BiomeKind { if self.alt < CONFIG.sea_level { BiomeKind::Ocean - } else if self.humidity == 0.0 { + } else if self.humidity == 0.5 { BiomeKind::Lake } else if self.temp < CONFIG.snow_temp { BiomeKind::Snowland From f0d14ebe20699964178e83ca57a4311cd93cc646 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Wed, 11 Nov 2020 01:03:52 -0800 Subject: [PATCH 29/37] fix rebase --- voxygen/src/audio/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 9ec556affc..a8ea7ea0de 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -255,14 +255,14 @@ impl AudioFrontend { fn fade_out_music(&mut self, channel_tag: MusicChannelTag) { let music_volume = self.music_volume; if let Some(channel) = self.get_music_channel(channel_tag) { - channel.set_fader(Fader::fade_out(5.0, music_volume)); + channel.set_fader(Fader::fade_out(Duration::from_secs(5), music_volume)); } } fn fade_in_music(&mut self, channel_tag: MusicChannelTag) { let music_volume = self.music_volume; if let Some(channel) = self.get_music_channel(channel_tag) { - channel.set_fader(Fader::fade_in(5.0, music_volume)); + channel.set_fader(Fader::fade_in(Duration::from_secs(5), music_volume)); } } From c44a9092d33235e035cc6b44b476a7efd5547393 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Wed, 11 Nov 2020 19:55:40 -0800 Subject: [PATCH 30/37] Biome definition tweaks and more sfx --- assets/voxygen/audio/sfx.ron | 22 +++++++ .../audio/sfx/abilities/flame_thrower.wav | 2 +- .../audio/sfx/abilities/staff_channeling.wav | 4 +- assets/voxygen/audio/soundtrack.ron | 22 ++++--- voxygen/src/audio/music.rs | 21 +------ voxygen/src/audio/sfx/mod.rs | 13 +++-- voxygen/src/audio/wind.rs | 57 ++++--------------- voxygen/src/main.rs | 2 +- voxygen/src/scene/mod.rs | 4 +- world/src/block/mod.rs | 7 ++- world/src/sim/mod.rs | 14 ++--- 11 files changed, 77 insertions(+), 91 deletions(-) diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 9feadcc507..a2a2b9f168 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -366,6 +366,28 @@ threshold: 0.3, ), + // + // Sceptre + // + Wield(Sceptre): ( + files: [ + "voxygen.audio.sfx.weapon.sword_out", + ], + threshold: 0.5, + ), + Unwield(Sceptre): ( + files: [ + "voxygen.audio.sfx.weapon.sword_in", + ], + threshold: 0.5, + ), + Attack(BasicBeam, Sceptre): ( + files: [ + "voxygen.audio.sfx.abilities.staff_channeling", + ], + threshold: 0.6, + ), + // // Dagger // diff --git a/assets/voxygen/audio/sfx/abilities/flame_thrower.wav b/assets/voxygen/audio/sfx/abilities/flame_thrower.wav index 306420695b..1f6b029d6d 100644 --- a/assets/voxygen/audio/sfx/abilities/flame_thrower.wav +++ b/assets/voxygen/audio/sfx/abilities/flame_thrower.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:507a78da5d8e3d8a01133640803b7bda101c763c14270b6486b948c23ca75eff +oid sha256:b54842c0b98562ffc6f609f7f947544bee28269da0bab5ff2562b12cd2ae3aad size 77368 diff --git a/assets/voxygen/audio/sfx/abilities/staff_channeling.wav b/assets/voxygen/audio/sfx/abilities/staff_channeling.wav index 3cf52abb56..768b9049f9 100644 --- a/assets/voxygen/audio/sfx/abilities/staff_channeling.wav +++ b/assets/voxygen/audio/sfx/abilities/staff_channeling.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7029cf7dccedbf6593c135964c45b9aacaa9d5bd11af577695b73851ce2efbd1 -size 636950 +oid sha256:cbc64e9c923f80192a8cb6720335d6927824914a44c948b0915d09f00367eeac +size 156072 diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index 5abdb84d9b..2cb39fe157 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -1,8 +1,10 @@ // TODO: Re-add tunes that are not fitting general outside day/night situations // TODO: Add an ambient-soundtrack that runs independently from the musical soundtrack -//Times: Some(Day), Some(Night), None -//List of biomes currently: Grassland, Forest, Jungle, Desert, Snowland, Lake, Mountain -//Sites: Cave, Dungeon +// Times: Some(Day), Some(Night), None +// List of biomes currently: Grassland, Forest, Desert, Snowland, Lake, Mountain, Ocean +// Also Jungle and Swamp but these are not defined currently as the worldgen around +// them is changing and not stable +// Sites: Cave, Dungeon ( tracks: [ @@ -12,7 +14,6 @@ length: 206.0, timing: Some(Night), biomes: [ - (Jungle, 1), (Desert, 1), (Grassland, 1), (Snowland, 1), @@ -29,7 +30,6 @@ timing: Some(Night), biomes: [ (Forest, 1), - (Jungle, 1), ], site: Some(Void), artist: "Aeronic", @@ -75,6 +75,15 @@ site: Some(Cave), artist: "Aeronic", ), + ( //Repeat for other site + title: "Mineral Deposits", + path: "voxygen.audio.soundtrack.mineral_deposits", + length: 148.0, + timing: None, + biomes: [], + site: Some(Dungeon), + artist: "Aeronic", + ), ( title: "Moonbeams", path: "voxygen.audio.soundtrack.moonbeams", @@ -90,7 +99,6 @@ length: 173.0, timing: Some(Night), biomes: [ - (Forest, 1), (Grassland, 1), ], site: Some(Void), @@ -148,7 +156,7 @@ site: Some(Cave), artist: "badbbad", ), - ( //Repeat for other site + ( //Repeat for other site title: "Down The Rabbit Hole", path: "voxygen.audio.soundtrack.down_the_rabbit_hole", length: 244.0, diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 8130b7d438..b8b7c18bc2 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -26,7 +26,7 @@ //! path: "voxygen.audio.soundtrack.sleepy", //! length: 400.0, //! timing: Some(Night), -//! biome: [ +//! biomes: [ //! (Forest, 1), //! (Grassland, 2), //! ], @@ -132,29 +132,12 @@ impl MusicMgr { //println!("biome: {:?}", current_chunk.meta().biome()); //println!("chaos: {}", current_chunk.meta().chaos()); //println!("alt: {}", current_chunk.meta().alt()); - //println!("temp: {}", current_chunk.meta().temp()); //println!("tree_density: {}", // current_chunk.meta().tree_density()); - // println!("humidity: {}", current_chunk.meta().humidity()); //println!("cave_alt: {}", current_chunk.meta().cave_alt()); //if let Some(position) = client.current_position() { // println!("player_pos: {:?}", position); //} - //let player_position = match client.current_position() { - // Some(pos) => pos, - // None => Vec3::default(), - //}; - //let block_position = Vec3::new( - // player_position[0], - // player_position[1], - // player_position[2] - 1.0, - //) - //.map(|x| x as i32); - //let block_kind = match state.get_block(block_position) { - // Some(block) => block.kind(), - // None => BlockKind::Air, - //}; - //println!("BlockKind: {:?}", block_kind); if audio.music_enabled() && !self.soundtrack.tracks.is_empty() @@ -226,7 +209,7 @@ impl MusicMgr { }); if let Ok(track) = new_maybe_track { - println!("Now playing {:?}", track.title); + //println!("Now playing {:?}", track.title); self.last_track = String::from(&track.title); self.began_playing = Instant::now(); self.next_track_change = track.length + silence_between_tracks_seconds; diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 55d40531cc..c060e8c8d0 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -244,15 +244,16 @@ pub struct SfxMgr { event_mapper: SfxEventMapper, } -impl SfxMgr { - #[allow(clippy::new_without_default)] // TODO: Pending review in #587 - pub fn new() -> Self { +impl Default for SfxMgr { + fn default() -> Self { Self { triggers: Self::load_sfx_items(), event_mapper: SfxEventMapper::new(), } } +} +impl SfxMgr { pub fn maintain( &mut self, audio: &mut AudioFrontend, @@ -360,7 +361,11 @@ impl SfxMgr { audio.play_sfx(file_ref, *pos, None); }, - Body::Object(object::Body::BoltFire | object::Body::BoltFireBig) => { + Body::Object( + object::Body::BoltFire + | object::Body::BoltFireBig + | object::Body::BoltNature, + ) => { let file_ref = vec![ "voxygen.audio.sfx.abilities.fire_shot_1", "voxygen.audio.sfx.abilities.fire_shot_2", diff --git a/voxygen/src/audio/wind.rs b/voxygen/src/audio/wind.rs index 2544dceaf5..ca739c3d45 100644 --- a/voxygen/src/audio/wind.rs +++ b/voxygen/src/audio/wind.rs @@ -6,10 +6,6 @@ use serde::Deserialize; use std::time::Instant; use tracing::warn; -// For if we want wind to vary strength by time of day -//const DAY_START_SECONDS: u32 = 28800; // 8:00 -//const DAY_END_SECONDS: u32 = 70200; // 19:30 - #[derive(Debug, Default, Deserialize)] struct WindCollection { tracks: Vec, @@ -21,19 +17,8 @@ pub struct WindItem { path: String, /// Length of the track in seconds length: f32, - /* Whether this track should play during day or night - * timing: Option, */ } -///// Allows control over when a track should play based on in-game time of day -//#[derive(Debug, Deserialize, PartialEq)] -//enum DayPeriod { -// /// 8:00 AM to 7:30 PM -// Day, -// /// 7:31 PM to 6:59 AM -// Night, -//} - pub struct WindMgr { soundtrack: WindCollection, began_playing: Instant, @@ -42,9 +27,8 @@ pub struct WindMgr { tree_multiplier: f32, } -impl WindMgr { - #[allow(clippy::new_without_default)] // TODO: Pending review in #587 - pub fn new() -> Self { +impl Default for WindMgr { + fn default() -> Self { Self { soundtrack: Self::load_soundtrack_items(), began_playing: Instant::now(), @@ -53,7 +37,9 @@ impl WindMgr { tree_multiplier: 0.0, } } +} +impl WindMgr { /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track pub fn maintain( @@ -64,15 +50,18 @@ impl WindMgr { camera: &Camera, ) { if audio.sfx_enabled() && !self.soundtrack.tracks.is_empty() { - let player_alt = Self::get_current_alt(client); + let focus_off = camera.get_focus_pos().map(f32::trunc); + let cam_pos = camera.dependents().cam_pos + focus_off; + + let cam_alt = cam_pos.z; let terrain_alt = Self::get_current_terrain_alt(client); - let alt_multiplier = (player_alt / 1200.0).abs(); + let alt_multiplier = (cam_alt / 1200.0).abs(); // Tree density factors into wind volume. The more trees, // the less wind let mut tree_multiplier = self.tree_multiplier; - let new_tree_multiplier = if (player_alt - terrain_alt) < 150.0 { + let new_tree_multiplier = if (cam_alt - terrain_alt) < 150.0 { 1.0 - Self::get_current_tree_density(client) } else { 1.0 @@ -88,9 +77,6 @@ impl WindMgr { let mut volume_multiplier = alt_multiplier * self.tree_multiplier; - let focus_off = camera.get_focus_pos().map(f32::trunc); - let cam_pos = camera.dependents().cam_pos + focus_off; - // Checks if the camera is underwater to stop wind sounds if state .terrain() @@ -99,17 +85,13 @@ impl WindMgr { .unwrap_or(BlockKind::Air) == BlockKind::Water { - volume_multiplier *= volume_multiplier; + volume_multiplier *= 0.1; } if cam_pos.z < Self::get_current_terrain_alt(client) - 10.0 { volume_multiplier = 0.0; } - if volume_multiplier > 1.0 { - volume_multiplier = 1.0 - } - - let target_volume = volume_multiplier; + let target_volume = volume_multiplier.max(0.0).min(1.0); // Transitions the wind smoothly self.volume = audio.get_wind_volume(); @@ -132,21 +114,6 @@ impl WindMgr { } } - //fn get_current_day_period(game_time: u32) -> DayPeriod { - // if game_time > DAY_START_SECONDS && game_time < DAY_END_SECONDS { - // DayPeriod::Day - // } else { - // DayPeriod::Night - // } - //} - - fn get_current_alt(client: &Client) -> f32 { - match client.current_position() { - Some(pos) => pos.z, - None => 0.0, - } - } - fn get_current_terrain_alt(client: &Client) -> f32 { if let Some(chunk) = client.current_chunk() { chunk.meta().alt() diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 5bb028a9f1..e4c5b60a42 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -4,7 +4,7 @@ #![recursion_limit = "2048"] use veloren_voxygen::{ - audio::{self, AudioFrontend}, + audio::AudioFrontend, i18n::{self, i18n_asset_key, Localization}, logging, profile::Profile, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 53385c14e8..cd0b3db87d 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -307,9 +307,9 @@ impl Scene { light_data: Vec::new(), particle_mgr: ParticleMgr::new(renderer), figure_mgr: FigureMgr::new(renderer), - sfx_mgr: SfxMgr::new(), + sfx_mgr: SfxMgr::default(), music_mgr: MusicMgr::default(), - ambient_mgr: WindMgr::new(), + ambient_mgr: WindMgr::default(), } } diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index e543f6e00e..b3977419d1 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -1,7 +1,7 @@ use crate::{ column::{ColumnGen, ColumnSample}, util::{RandomField, Sampler, SmallCache}, - IndexRef, CONFIG, + IndexRef, }; use common::terrain::{ structure::{self, StructureBlock}, @@ -67,9 +67,9 @@ impl<'a> BlockGen<'a> { // marble_small, rock, // temp, - temp, // humidity, stone_col, + snow_cover, .. } = sample; @@ -129,7 +129,8 @@ impl<'a> BlockGen<'a> { let col = Lerp::lerp(sub_surface_color, surface_color, grass_factor); // Surface Some(Block::new( - if temp < CONFIG.snow_temp + 0.031 { + if snow_cover { + //if temp < CONFIG.snow_temp + 0.031 { BlockKind::Snow } else if grass_factor > 0.7 { BlockKind::Grass diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index d587ba4106..67905b01c9 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -2303,20 +2303,20 @@ impl SimChunk { pub fn get_biome(&self) -> BiomeKind { if self.alt < CONFIG.sea_level { BiomeKind::Ocean - } else if self.humidity == 0.5 { + } else if (self.temp - 0.5) < 0.005 && self.humidity < 0.1 { BiomeKind::Lake } else if self.temp < CONFIG.snow_temp { BiomeKind::Snowland - } else if self.alt > 450.0 && self.chaos > 0.35 && self.tree_density < 0.7 { + } else if self.alt > 450.0 && self.chaos > 0.3 && self.tree_density < 0.6 { BiomeKind::Mountain } else if self.temp > CONFIG.desert_temp && self.humidity < 0.6 { BiomeKind::Desert - } else if self.tree_density > 0.65 && self.humidity > 0.7 && self.temp > 0.8 { - BiomeKind::Jungle - } else if self.tree_density > 0.65 { + //} else if self.tree_density > 0.65 && self.humidity > 0.7 && self.temp > 0.8 { + // BiomeKind::Jungle + } else if self.tree_density > 0.5 { BiomeKind::Forest - } else if self.humidity > 0.8 { - BiomeKind::Swamp + //} else if self.humidity > 0.8 { + // BiomeKind::Swamp } else { BiomeKind::Grassland } From a9711eea01ac200cac7605716daaf2a0da7b3a7d Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Fri, 13 Nov 2020 16:27:09 -0800 Subject: [PATCH 31/37] Beginning to address comments --- .../voxygen/audio/{wind.ron => ambient.ron} | 1 + client/src/lib.rs | 10 +- common/src/terrain/mod.rs | 10 +- voxygen/src/audio/{wind.rs => ambient.rs} | 64 ++++++++----- voxygen/src/audio/channel.rs | 38 ++++++-- voxygen/src/audio/mod.rs | 96 +++++++++---------- voxygen/src/audio/music.rs | 21 ++-- voxygen/src/scene/mod.rs | 6 +- voxygen/src/settings.rs | 1 + world/src/lib.rs | 2 +- 10 files changed, 141 insertions(+), 108 deletions(-) rename assets/voxygen/audio/{wind.ron => ambient.ron} (84%) rename voxygen/src/audio/{wind.rs => ambient.rs} (70%) diff --git a/assets/voxygen/audio/wind.ron b/assets/voxygen/audio/ambient.ron similarity index 84% rename from assets/voxygen/audio/wind.ron rename to assets/voxygen/audio/ambient.ron index 6505b59e4f..e5f2a615fe 100644 --- a/assets/voxygen/audio/wind.ron +++ b/assets/voxygen/audio/ambient.ron @@ -3,6 +3,7 @@ ( path: "voxygen.audio.ambient.wind", length: 4.5, + tag: Wind, ), ] ) diff --git a/client/src/lib.rs b/client/src/lib.rs index dc176b8f15..73e1fab9ea 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -46,6 +46,7 @@ use image::DynamicImage; use network::{Network, Participant, Pid, ProtocolAddr, Stream}; use num::traits::FloatConst; use rayon::prelude::*; +use specs::Component; use std::{ collections::VecDeque, net::SocketAddr, @@ -857,13 +858,14 @@ impl Client { self.state.terrain().get_key_arc(chunk_pos).cloned() } - pub fn current_position(&self) -> Option> { + pub fn current(&self) -> Option where + C: Clone, + { Some( self.state - .read_storage::() + .read_storage::() .get(self.entity) - .cloned()? - .0, + .cloned()?, ) } diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index 8eb024760e..4832a3b53e 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -54,7 +54,7 @@ pub struct TerrainChunkMeta { biome: BiomeKind, alt: f32, tree_density: f32, - cave_alt: f32, + contains_cave: bool, contains_river: bool, } @@ -64,7 +64,7 @@ impl TerrainChunkMeta { biome: BiomeKind, alt: f32, tree_density: f32, - cave_alt: f32, + contains_cave: bool, contains_river: bool, ) -> Self { Self { @@ -72,7 +72,7 @@ impl TerrainChunkMeta { biome, alt, tree_density, - cave_alt, + contains_cave, contains_river, } } @@ -83,7 +83,7 @@ impl TerrainChunkMeta { biome: BiomeKind::Void, alt: 0.0, tree_density: 0.0, - cave_alt: 0.0, + contains_cave: false, contains_river: false, } } @@ -96,7 +96,7 @@ impl TerrainChunkMeta { pub fn tree_density(&self) -> f32 { self.tree_density } - pub fn cave_alt(&self) -> f32 { self.cave_alt } + pub fn contains_cave(&self) -> bool { self.contains_cave } pub fn contains_river(&self) -> bool { self.contains_river } } diff --git a/voxygen/src/audio/wind.rs b/voxygen/src/audio/ambient.rs similarity index 70% rename from voxygen/src/audio/wind.rs rename to voxygen/src/audio/ambient.rs index ca739c3d45..c56f833f4f 100644 --- a/voxygen/src/audio/wind.rs +++ b/voxygen/src/audio/ambient.rs @@ -1,5 +1,8 @@ -//! Handles ambient wind sounds -use crate::{audio::AudioFrontend, scene::Camera}; +//! Handles ambient non-positional sounds +use crate::{ + audio::{channel::AmbientChannelTag, AudioFrontend}, + scene::Camera, +}; use client::Client; use common::{assets, state::State, terrain::BlockKind, vol::ReadVol}; use serde::Deserialize; @@ -7,27 +10,28 @@ use std::time::Instant; use tracing::warn; #[derive(Debug, Default, Deserialize)] -struct WindCollection { - tracks: Vec, +struct AmbientCollection { + tracks: Vec, } /// Configuration for a single music track in the soundtrack #[derive(Debug, Deserialize)] -pub struct WindItem { +pub struct AmbientItem { path: String, /// Length of the track in seconds length: f32, + tag: AmbientChannelTag, } -pub struct WindMgr { - soundtrack: WindCollection, +pub struct AmbientMgr { + soundtrack: AmbientCollection, began_playing: Instant, next_track_change: f32, volume: f32, tree_multiplier: f32, } -impl Default for WindMgr { +impl Default for AmbientMgr { fn default() -> Self { Self { soundtrack: Self::load_soundtrack_items(), @@ -39,7 +43,7 @@ impl Default for WindMgr { } } -impl WindMgr { +impl AmbientMgr { /// Checks whether the previous track has completed. If so, sends a /// request to play the next (random) track pub fn maintain( @@ -56,10 +60,14 @@ impl WindMgr { let cam_alt = cam_pos.z; let terrain_alt = Self::get_current_terrain_alt(client); + // The following code is specifically for wind, as it is the only + // non-positional ambient sound in the game. Others can be added + // as seen fit. + let alt_multiplier = (cam_alt / 1200.0).abs(); - // Tree density factors into wind volume. The more trees, - // the less wind + // Tree density factors into ambient volume. The more trees, + // the less ambient let mut tree_multiplier = self.tree_multiplier; let new_tree_multiplier = if (cam_alt - terrain_alt) < 150.0 { 1.0 - Self::get_current_tree_density(client) @@ -77,7 +85,7 @@ impl WindMgr { let mut volume_multiplier = alt_multiplier * self.tree_multiplier; - // Checks if the camera is underwater to stop wind sounds + // Checks if the camera is underwater to stop ambient sounds if state .terrain() .get((cam_pos).map(|e| e.floor() as i32)) @@ -93,23 +101,31 @@ impl WindMgr { let target_volume = volume_multiplier.max(0.0).min(1.0); - // Transitions the wind smoothly - self.volume = audio.get_wind_volume(); + // Transitions the ambient sounds (more) smoothly + self.volume = audio.get_ambient_volume(); if self.volume < target_volume { - audio.set_wind_volume(self.volume + 0.001); + audio.set_ambient_volume(self.volume + 0.001); } else if self.volume > target_volume { - audio.set_wind_volume(self.volume - 0.001); + audio.set_ambient_volume(self.volume - 0.001); } if self.began_playing.elapsed().as_secs_f32() > self.next_track_change { //let game_time = (state.get_time_of_day() as u64 % 86400) as u32; //let current_period_of_day = Self::get_current_day_period(game_time); - let track = &self.soundtrack.tracks[0]; - self.began_playing = Instant::now(); - self.next_track_change = track.length; + let track = &self + .soundtrack + .tracks + .iter() + .filter(|track| track.tag == AmbientChannelTag::Wind) + .next(); - audio.play_wind(&track.path, volume_multiplier); + if let Some(track) = track { + self.began_playing = Instant::now(); + self.next_track_change = track.length; + + audio.play_ambient(AmbientChannelTag::Wind, &track.path, volume_multiplier); + } } } } @@ -129,8 +145,8 @@ impl WindMgr { } } - fn load_soundtrack_items() -> WindCollection { - match assets::load_file("voxygen.audio.wind", &["ron"]) { + fn load_soundtrack_items() -> AmbientCollection { + match assets::load_file("voxygen.audio.ambient", &["ron"]) { Ok(file) => match ron::de::from_reader(file) { Ok(config) => config, Err(error) => { @@ -139,7 +155,7 @@ impl WindMgr { format!("{:#?}", error) ); - WindCollection::default() + AmbientCollection::default() }, }, Err(error) => { @@ -148,7 +164,7 @@ impl WindMgr { format!("{:#?}", error) ); - WindCollection::default() + AmbientCollection::default() }, } } diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index 3215db600a..f7496a9bec 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -21,6 +21,7 @@ use crate::audio::{ Listener, }; use rodio::{OutputStreamHandle, Sample, Sink, Source, SpatialSink}; +use serde::Deserialize; use tracing::warn; use vek::*; @@ -31,6 +32,13 @@ enum ChannelState { Stopped, } +#[derive(PartialEq)] +pub enum ChannelKind { + Music(MusicChannelTag), + Sfx, + Ambient(AmbientChannelTag), +} + /// Each `MusicChannel` has a `MusicChannelTag` which help us determine when we /// should transition between two types of in-game music. For example, we /// transition between `TitleMusic` and `Exploration` when a player enters the @@ -153,25 +161,29 @@ impl MusicChannel { } } -/// A WindChannel uses a non-positional audio sink designed to play music which -/// is always heard at the player's position. -pub struct WindChannel { +/// AmbientChannelTags are used for non-positional sfx. Currently the only use +/// is for wind. +#[derive(Debug, PartialEq, Clone, Copy, Deserialize)] +pub enum AmbientChannelTag { + Wind, +} +/// A AmbientChannel uses a non-positional audio sink designed to play sounds +/// which are always heard at the camera's position. +pub struct AmbientChannel { + tag: AmbientChannelTag, sink: Sink, } -impl WindChannel { - pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume); } - - pub fn get_volume(&mut self) -> f32 { self.sink.volume() } - - pub fn new(stream: &OutputStreamHandle) -> Self { +impl AmbientChannel { + pub fn new(stream: &OutputStreamHandle, tag: AmbientChannelTag) -> Self { let new_sink = Sink::try_new(stream); match new_sink { - Ok(sink) => Self { sink }, + Ok(sink) => Self { sink, tag }, Err(_) => { warn!("Failed to create rodio sink. May not play wind sounds."); Self { sink: Sink::new_idle().0, + tag, } }, } @@ -186,6 +198,12 @@ impl WindChannel { { self.sink.append(source); } + + pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume); } + + pub fn get_volume(&mut self) -> f32 { self.sink.volume() } + + pub fn get_tag(&self) -> AmbientChannelTag { self.tag } } /// An SfxChannel uses a positional audio sink, and is designed for short-lived diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index a8ea7ea0de..49da6c3689 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -1,13 +1,13 @@ //! Handles audio device detection and playback of sound effects and music +pub mod ambient; pub mod channel; pub mod fader; pub mod music; pub mod sfx; pub mod soundcache; -pub mod wind; -use channel::{MusicChannel, MusicChannelTag, SfxChannel, WindChannel}; +use channel::{AmbientChannel, AmbientChannelTag, MusicChannel, MusicChannelTag, SfxChannel}; use fader::Fader; use soundcache::SoundCache; use std::time::Duration; @@ -40,7 +40,7 @@ pub struct AudioFrontend { sound_cache: SoundCache, music_channels: Vec, - wind_channels: Vec, + ambient_channels: Vec, sfx_channels: Vec, sfx_volume: f32, music_volume: f32, @@ -50,6 +50,7 @@ pub struct AudioFrontend { impl AudioFrontend { /// Construct with given device pub fn new(/* dev: String, */ max_sfx_channels: usize) -> Self { + // Commented out until audio device switcher works //let audio_device = get_device_raw(&dev); //let device = match get_default_device() { @@ -63,10 +64,8 @@ impl AudioFrontend { }; let mut sfx_channels = Vec::with_capacity(max_sfx_channels); - let mut wind_channels = Vec::new(); if let Some(audio_stream) = &audio_stream { sfx_channels.resize_with(max_sfx_channels, || SfxChannel::new(audio_stream)); - wind_channels.push(WindChannel::new(audio_stream)); }; Self { @@ -79,7 +78,7 @@ impl AudioFrontend { sound_cache: SoundCache::default(), music_channels: Vec::new(), sfx_channels, - wind_channels, + ambient_channels: Vec::new(), sfx_volume: 1.0, music_volume: 1.0, listener: Listener::default(), @@ -98,7 +97,7 @@ impl AudioFrontend { sound_cache: SoundCache::default(), music_channels: Vec::new(), sfx_channels: Vec::new(), - wind_channels: Vec::new(), + ambient_channels: Vec::new(), sfx_volume: 1.0, music_volume: 1.0, listener: Listener::default(), @@ -182,7 +181,7 @@ impl AudioFrontend { /// Play (once) an sfx file by file path at the give position and volume /// but with the sound passed through a low pass filter to simulate - /// underwater + /// being underwater pub fn play_underwater_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { if self.audio_stream.is_some() { let sound = self @@ -194,15 +193,19 @@ impl AudioFrontend { if let Some(channel) = self.get_sfx_channel() { channel.set_pos(pos); channel.update(&listener); - let sound = sound.convert_samples(); - channel.play_with_low_pass_filter(sound); + channel.play_with_low_pass_filter(sound.convert_samples()); } } } - fn play_wind(&mut self, sound: &str, volume_multiplier: f32) { + fn play_ambient( + &mut self, + channel_tag: AmbientChannelTag, + sound: &str, + volume_multiplier: f32, + ) { if self.audio_stream.is_some() { - if let Some(channel) = self.get_wind_channel(volume_multiplier) { + if let Some(channel) = self.get_ambient_channel(channel_tag, volume_multiplier) { let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); let sound = Decoder::new(file).expect("Failed to decode sound"); @@ -211,29 +214,40 @@ impl AudioFrontend { } } - fn get_wind_channel(&mut self, volume_multiplier: f32) -> Option<&mut WindChannel> { - if self.audio_stream.is_some() { - if let Some(channel) = self.wind_channels.iter_mut().last() { - channel.set_volume(self.sfx_volume * volume_multiplier); - - return Some(channel); + fn get_ambient_channel( + &mut self, + channel_tag: AmbientChannelTag, + volume_multiplier: f32, + ) -> Option<&mut AmbientChannel> { + if let Some(audio_stream) = &self.audio_stream { + if self.ambient_channels.is_empty() { + let mut ambient_channel = AmbientChannel::new(audio_stream, channel_tag); + ambient_channel.set_volume(self.sfx_volume * volume_multiplier); + self.ambient_channels.push(ambient_channel); + } else { + for channel in self.ambient_channels.iter_mut() { + if channel.get_tag() == channel_tag { + channel.set_volume(self.sfx_volume * volume_multiplier); + return Some(channel); + } + } } } None } - fn set_wind_volume(&mut self, volume_multiplier: f32) { + fn set_ambient_volume(&mut self, volume_multiplier: f32) { if self.audio_stream.is_some() { - if let Some(channel) = self.wind_channels.iter_mut().last() { + if let Some(channel) = self.ambient_channels.iter_mut().last() { channel.set_volume(self.sfx_volume * volume_multiplier); } } } - fn get_wind_volume(&mut self) -> f32 { + fn get_ambient_volume(&mut self) -> f32 { if self.audio_stream.is_some() { - if let Some(channel) = self.wind_channels.iter_mut().last() { + if let Some(channel) = self.ambient_channels.iter_mut().last() { channel.get_volume() / self.sfx_volume } else { 0.0 @@ -244,14 +258,19 @@ impl AudioFrontend { } fn play_music(&mut self, sound: &str, channel_tag: MusicChannelTag) { - if let Some(channel) = self.get_music_channel(channel_tag) { - let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); - let sound = Decoder::new(file).expect("Failed to decode sound"); + if self.music_enabled() { + if let Some(channel) = self.get_music_channel(channel_tag) { + let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound"); + let sound = Decoder::new(file).expect("Failed to decode sound"); - channel.play(sound, channel_tag); + channel.play(sound, channel_tag); + } } } + /* These functions are saved for if we want music playback control at some + * point. They are not used currently but may be useful for later work. + * fn fade_out_music(&mut self, channel_tag: MusicChannelTag) { let music_volume = self.music_volume; if let Some(channel) = self.get_music_channel(channel_tag) { @@ -271,6 +290,7 @@ impl AudioFrontend { channel.stop(channel_tag); } } + */ pub fn set_listener_pos(&mut self, pos: Vec3, ori: Vec3) { self.listener.pos = pos; @@ -298,30 +318,6 @@ impl AudioFrontend { } } - pub fn play_exploration_music(&mut self, item: &str) { - if self.music_enabled() { - self.play_music(item, MusicChannelTag::Exploration) - } - } - - pub fn fade_out_exploration_music(&mut self) { - if self.music_enabled() { - self.fade_out_music(MusicChannelTag::Exploration) - } - } - - pub fn fade_in_exploration_music(&mut self) { - if self.music_enabled() { - self.fade_in_music(MusicChannelTag::Exploration) - } - } - - pub fn stop_exploration_music(&mut self) { - if self.music_enabled() { - self.stop_music(MusicChannelTag::Exploration) - } - } - pub fn get_sfx_volume(&self) -> f32 { self.sfx_volume } pub fn get_music_volume(&self) -> f32 { self.music_volume } diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index b8b7c18bc2..4552555f16 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -42,10 +42,10 @@ //! tracks //! - If you are not the author of the track, ensure that the song's licensing //! permits usage of the track for non-commercial use -use crate::audio::AudioFrontend; +use crate::audio::{AudioFrontend, MusicChannelTag}; use client::Client; use common::{ - assets, + assets, comp, state::State, terrain::{BiomeKind, SitesKind}, }; @@ -134,9 +134,8 @@ impl MusicMgr { //println!("alt: {}", current_chunk.meta().alt()); //println!("tree_density: {}", // current_chunk.meta().tree_density()); - //println!("cave_alt: {}", current_chunk.meta().cave_alt()); - //if let Some(position) = client.current_position() { - // println!("player_pos: {:?}", position); + //if let Some(position) = client.current::() { + // player_alt = position.0.z; //} if audio.music_enabled() @@ -214,7 +213,7 @@ impl MusicMgr { self.began_playing = Instant::now(); self.next_track_change = track.length + silence_between_tracks_seconds; - audio.play_exploration_music(&track.path); + audio.play_music(&track.path, MusicChannelTag::Exploration); } } @@ -235,16 +234,16 @@ impl MusicMgr { fn get_current_site(client: &Client) -> SitesKind { let mut player_alt = 0.0; - if let Some(position) = client.current_position() { - player_alt = position.z; + if let Some(position) = client.current::() { + player_alt = position.0.z; } - let mut cave_alt = 0.0; + let mut contains_cave = false; let mut terrain_alt = 0.0; if let Some(chunk) = client.current_chunk() { terrain_alt = chunk.meta().alt(); - cave_alt = chunk.meta().cave_alt(); + contains_cave = chunk.meta().contains_cave(); } - if player_alt < (terrain_alt - 20.0) && cave_alt != 0.0 { + if player_alt < (terrain_alt - 20.0) && contains_cave { SitesKind::Cave } else if player_alt < (terrain_alt - 20.0) { SitesKind::Dungeon diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index cd0b3db87d..06aad6ce22 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -14,7 +14,7 @@ pub use self::{ terrain::Terrain, }; use crate::{ - audio::{music::MusicMgr, sfx::SfxMgr, wind::WindMgr, AudioFrontend}, + audio::{ambient::AmbientMgr, music::MusicMgr, sfx::SfxMgr, AudioFrontend}, render::{ create_clouds_mesh, create_pp_mesh, create_skybox_mesh, CloudsLocals, CloudsPipeline, Consts, GlobalModel, Globals, Light, LodData, Model, PostProcessLocals, @@ -103,7 +103,7 @@ pub struct Scene { figure_mgr: FigureMgr, sfx_mgr: SfxMgr, music_mgr: MusicMgr, - ambient_mgr: WindMgr, + ambient_mgr: AmbientMgr, } pub struct SceneData<'a> { @@ -309,7 +309,7 @@ impl Scene { figure_mgr: FigureMgr::new(renderer), sfx_mgr: SfxMgr::default(), music_mgr: MusicMgr::default(), - ambient_mgr: WindMgr::default(), + ambient_mgr: AmbientMgr::default(), } } diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 79691e8c26..77bcea53ab 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -654,6 +654,7 @@ pub enum AudioOutput { // If this option is disabled, functions in the rodio // library MUST NOT be called. Off, + #[serde(other)] Automatic, } diff --git a/world/src/lib.rs b/world/src/lib.rs index 67f544e6ed..d1672a4677 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -160,7 +160,7 @@ impl World { sim_chunk.get_biome(), sim_chunk.alt, sim_chunk.tree_density, - sim_chunk.cave.1.alt, + sim_chunk.cave.1.alt != 0.0, sim_chunk.river.is_river(), ); From 9c873451359a198a5776e1399d6f9fa4afddefb7 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Fri, 13 Nov 2020 22:52:20 -0800 Subject: [PATCH 32/37] Moved functions to client out of audio and generalized non-positional ambient sfx --- client/src/lib.rs | 29 ++++++++++++++++++++++++++++- voxygen/src/audio/channel.rs | 7 ------- voxygen/src/audio/music.rs | 33 +++------------------------------ 3 files changed, 31 insertions(+), 38 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 73e1fab9ea..f923961be4 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -34,7 +34,7 @@ use common::{ recipe::RecipeBook, state::State, sync::{Uid, UidAllocator, WorldSyncExt}, - terrain::{block::Block, neighbors, TerrainChunk, TerrainChunkSize}, + terrain::{block::Block, neighbors, BiomeKind, SitesKind, TerrainChunk, TerrainChunkSize}, vol::RectVolSize, }; use comp::BuffKind; @@ -869,6 +869,33 @@ impl Client { ) } + pub fn current_biome(&self) -> BiomeKind { + match self.current_chunk() { + Some(chunk) => chunk.meta().biome(), + _ => BiomeKind::Void, + } + } + + pub fn current_site(&self) -> SitesKind { + let mut player_alt = 0.0; + if let Some(position) = self.current::() { + player_alt = position.0.z; + } + let mut contains_cave = false; + let mut terrain_alt = 0.0; + if let Some(chunk) = self.current_chunk() { + terrain_alt = chunk.meta().alt(); + contains_cave = chunk.meta().contains_cave(); + } + if player_alt < (terrain_alt - 15.0) && contains_cave { + SitesKind::Cave + } else if player_alt < (terrain_alt - 15.0) { + SitesKind::Dungeon + } else { + SitesKind::Void + } + } + pub fn inventories(&self) -> ReadStorage { self.state.read_storage() } pub fn loadouts(&self) -> ReadStorage { self.state.read_storage() } diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index f7496a9bec..7400c32538 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -32,13 +32,6 @@ enum ChannelState { Stopped, } -#[derive(PartialEq)] -pub enum ChannelKind { - Music(MusicChannelTag), - Sfx, - Ambient(AmbientChannelTag), -} - /// Each `MusicChannel` has a `MusicChannelTag` which help us determine when we /// should transition between two types of in-game music. For example, we /// transition between `TitleMusic` and `Exploration` when a player enters the diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 4552555f16..7d0e94b2c8 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -45,7 +45,7 @@ use crate::audio::{AudioFrontend, MusicChannelTag}; use client::Client; use common::{ - assets, comp, + assets, state::State, terrain::{BiomeKind, SitesKind}, }; @@ -154,8 +154,8 @@ impl MusicMgr { let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); - let current_biome = Self::get_current_biome(client); - let current_site = Self::get_current_site(client); + let current_biome = client.current_biome(); + let current_site = client.current_site(); // Filters out tracks not matching the timing, site, and biome let maybe_tracks = self @@ -225,33 +225,6 @@ impl MusicMgr { } } - fn get_current_biome(client: &Client) -> BiomeKind { - match client.current_chunk() { - Some(chunk) => chunk.meta().biome(), - _ => BiomeKind::Void, - } - } - - fn get_current_site(client: &Client) -> SitesKind { - let mut player_alt = 0.0; - if let Some(position) = client.current::() { - player_alt = position.0.z; - } - let mut contains_cave = false; - let mut terrain_alt = 0.0; - if let Some(chunk) = client.current_chunk() { - terrain_alt = chunk.meta().alt(); - contains_cave = chunk.meta().contains_cave(); - } - if player_alt < (terrain_alt - 20.0) && contains_cave { - SitesKind::Cave - } else if player_alt < (terrain_alt - 20.0) { - SitesKind::Dungeon - } else { - SitesKind::Void - } - } - fn load_soundtrack_items() -> SoundtrackCollection { match assets::load_file("voxygen.audio.soundtrack", &["ron"]) { Ok(file) => match ron::de::from_reader(file) { From 77d624f64079340c9df805dde264c4e28089f0b8 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sat, 14 Nov 2020 00:23:57 -0800 Subject: [PATCH 33/37] Made level up sounds use outcomes instead of emitting an event --- common/src/outcome.rs | 15 +++- server/src/events/entity_manipulation.rs | 10 +++ voxygen/src/audio/sfx/event_mapper/mod.rs | 3 - .../audio/sfx/event_mapper/progression/mod.rs | 85 ------------------- .../sfx/event_mapper/progression/tests.rs | 43 ---------- voxygen/src/audio/sfx/mod.rs | 5 ++ voxygen/src/scene/mod.rs | 1 + voxygen/src/scene/particle.rs | 1 + 8 files changed, 31 insertions(+), 132 deletions(-) delete mode 100644 voxygen/src/audio/sfx/event_mapper/progression/mod.rs delete mode 100644 voxygen/src/audio/sfx/event_mapper/progression/tests.rs diff --git a/common/src/outcome.rs b/common/src/outcome.rs index f680c321ca..bf6002aa63 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -1,5 +1,8 @@ use crate::comp; -use comp::item::Reagent; +use comp::{ + item::{tool::ToolKind, Reagent}, + CharacterAbilityType, +}; use serde::{Deserialize, Serialize}; use vek::*; @@ -22,6 +25,14 @@ pub enum Outcome { body: comp::Body, vel: Vec3, }, + Swing { + pos: Vec3, + ability: CharacterAbilityType, + tool: ToolKind, + }, + LevelUp { + pos: Vec3, + }, } impl Outcome { @@ -29,6 +40,8 @@ impl Outcome { match self { Outcome::Explosion { pos, .. } => Some(*pos), Outcome::ProjectileShot { pos, .. } => Some(*pos), + Outcome::Swing { pos, .. } => Some(*pos), + Outcome::LevelUp { pos } => Some(*pos), } } } diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 8ca9d2cfee..97e5f73c2e 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -686,14 +686,24 @@ pub fn handle_explosion( } pub fn handle_level_up(server: &mut Server, entity: EcsEntity, new_level: u32) { + let ecs = &server.state.ecs(); let uids = server.state.ecs().read_storage::(); let uid = uids .get(entity) .expect("Failed to fetch uid component for entity."); + let pos = server + .state + .ecs() + .read_storage::() + .get(entity) + .expect("Failed to fetch position component for the entity.") + .0; server.state.notify_players(ServerGeneral::PlayerListUpdate( PlayerListUpdate::LevelChange(*uid, new_level), )); + ecs.write_resource::>() + .push(Outcome::LevelUp { pos }); } pub fn handle_buff(server: &mut Server, entity: EcsEntity, buff_change: buff::BuffChange) { diff --git a/voxygen/src/audio/sfx/event_mapper/mod.rs b/voxygen/src/audio/sfx/event_mapper/mod.rs index c46e16cb8e..12976a58b8 100644 --- a/voxygen/src/audio/sfx/event_mapper/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/mod.rs @@ -2,7 +2,6 @@ mod block; mod campfire; mod combat; mod movement; -mod progression; use client::Client; use common::{state::State, terrain::TerrainChunk}; @@ -11,7 +10,6 @@ use block::BlockEventMapper; use campfire::CampfireEventMapper; use combat::CombatEventMapper; use movement::MovementEventMapper; -use progression::ProgressionEventMapper; use super::SfxTriggers; use crate::scene::{Camera, Terrain}; @@ -38,7 +36,6 @@ impl SfxEventMapper { mappers: vec![ Box::new(CombatEventMapper::new()), Box::new(MovementEventMapper::new()), - Box::new(ProgressionEventMapper::new()), Box::new(BlockEventMapper::new()), Box::new(CampfireEventMapper::new()), ], diff --git a/voxygen/src/audio/sfx/event_mapper/progression/mod.rs b/voxygen/src/audio/sfx/event_mapper/progression/mod.rs deleted file mode 100644 index 49e89dab45..0000000000 --- a/voxygen/src/audio/sfx/event_mapper/progression/mod.rs +++ /dev/null @@ -1,85 +0,0 @@ -/// EventMapper::Progress watches the player entity's stats -/// and triggers sfx for gaining experience and levelling up -use super::EventMapper; - -use crate::{ - audio::sfx::{SfxEvent, SfxEventItem, SfxTriggers}, - scene::{Camera, Terrain}, -}; - -use client::Client; -use common::{comp::Stats, event::EventBus, state::State, terrain::TerrainChunk}; -use specs::WorldExt; - -#[derive(Clone, PartialEq)] -struct ProgressionState { - level: u32, - exp: u32, -} - -impl Default for ProgressionState { - fn default() -> Self { Self { level: 1, exp: 0 } } -} - -pub struct ProgressionEventMapper { - state: ProgressionState, -} - -impl EventMapper for ProgressionEventMapper { - #[allow(clippy::op_ref)] // TODO: Pending review in #587 - fn maintain( - &mut self, - state: &State, - player_entity: specs::Entity, - _camera: &Camera, - triggers: &SfxTriggers, - _terrain: &Terrain, - _client: &Client, - ) { - let ecs = state.ecs(); - - let next_state = ecs.read_storage::().get(player_entity).map_or( - ProgressionState::default(), - |stats| ProgressionState { - level: stats.level.level(), - exp: stats.exp.current(), - }, - ); - - if &self.state != &next_state { - if let Some(mapped_event) = self.map_event(&next_state) { - let sfx_trigger_item = triggers.get_trigger(&mapped_event); - - if sfx_trigger_item.is_some() { - ecs.read_resource::>() - .emit_now(SfxEventItem::at_player_position(mapped_event)); - } - } - - self.state = next_state; - } - } -} - -impl ProgressionEventMapper { - pub fn new() -> Self { - Self { - state: ProgressionState::default(), - } - } - - #[allow(clippy::let_and_return)] // TODO: Pending review in #587 - fn map_event(&mut self, next_state: &ProgressionState) -> Option { - let sfx_event = if next_state.level > self.state.level { - Some(SfxEvent::LevelUp) - } else if next_state.exp > self.state.exp { - Some(SfxEvent::ExperienceGained) - } else { - None - }; - - sfx_event - } -} - -#[cfg(test)] mod tests; diff --git a/voxygen/src/audio/sfx/event_mapper/progression/tests.rs b/voxygen/src/audio/sfx/event_mapper/progression/tests.rs deleted file mode 100644 index dd7778f42f..0000000000 --- a/voxygen/src/audio/sfx/event_mapper/progression/tests.rs +++ /dev/null @@ -1,43 +0,0 @@ -use super::*; -use crate::audio::sfx::SfxEvent; - -#[test] -fn no_change_returns_none() { - let mut mapper = ProgressionEventMapper::new(); - let next_client_state = ProgressionState::default(); - - assert_eq!(mapper.map_event(&next_client_state), None); -} - -#[test] -fn change_level_returns_levelup() { - let mut mapper = ProgressionEventMapper::new(); - let next_client_state = ProgressionState { level: 2, exp: 0 }; - - assert_eq!( - mapper.map_event(&next_client_state), - Some(SfxEvent::LevelUp) - ); -} - -#[test] -fn change_exp_returns_expup() { - let mut mapper = ProgressionEventMapper::new(); - let next_client_state = ProgressionState { level: 1, exp: 100 }; - - assert_eq!( - mapper.map_event(&next_client_state), - Some(SfxEvent::ExperienceGained) - ); -} - -#[test] -fn level_up_and_gained_exp_prioritises_levelup() { - let mut mapper = ProgressionEventMapper::new(); - let next_client_state = ProgressionState { level: 2, exp: 100 }; - - assert_eq!( - mapper.map_event(&next_client_state), - Some(SfxEvent::LevelUp) - ); -} diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index c060e8c8d0..dcbc958e0f 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -378,6 +378,11 @@ impl SfxMgr { }, } }, + Outcome::LevelUp { pos } => { + let file_ref = "voxygen.audio.sfx.character.level_up_sound_-_shorter_wind_up"; + audio.play_sfx(file_ref, *pos, None); + }, + _ => {}, } } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 06aad6ce22..23ec0bdaf0 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -433,6 +433,7 @@ impl Scene { fadeout: |timeout| timeout * 2.0, }), Outcome::ProjectileShot { .. } => {}, + _ => {}, } } diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index f457110d76..215b1d17e5 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -124,6 +124,7 @@ impl ParticleMgr { } }, Outcome::ProjectileShot { .. } => {}, + _ => {}, } } From b3aa454f8e761733b1a98f2280d2c65cf3153c07 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Sat, 14 Nov 2020 16:14:15 -0800 Subject: [PATCH 34/37] Initial work to move combat sfx to outcomes --- assets/voxygen/audio/sfx.ron | 60 ++++++++++++++-------------- common/src/event.rs | 2 + common/src/outcome.rs | 18 +++++---- common/src/state.rs | 25 ++++++++++++ common/src/sys/melee.rs | 3 +- server/src/events/entity_creation.rs | 5 +++ voxygen/src/audio/sfx/mod.rs | 59 ++++++++++++++++++++++++++- 7 files changed, 132 insertions(+), 40 deletions(-) diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index a2a2b9f168..959d1913a1 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -181,24 +181,24 @@ ], threshold: 0.5, ), - Attack(ComboMelee(Swing, 1), Sword): ( - files: [ - "voxygen.audio.sfx.abilities.swing_sword", - ], - threshold: 0.7, - ), - Attack(ComboMelee(Swing, 2), Sword): ( - files: [ - "voxygen.audio.sfx.abilities.separated_second_swing", - ], - threshold: 0.7, - ), - Attack(ComboMelee(Swing, 3), Sword): ( - files: [ - "voxygen.audio.sfx.abilities.separated_third_swing", - ], - threshold: 0.7, - ), + //Attack(ComboMelee(Swing, 1), Sword): ( + // files: [ + // "voxygen.audio.sfx.abilities.swing_sword", + // ], + // threshold: 0.7, + //), + //Attack(ComboMelee(Swing, 2), Sword): ( + // files: [ + // "voxygen.audio.sfx.abilities.separated_second_swing", + // ], + // threshold: 0.7, + //), + //Attack(ComboMelee(Swing, 3), Sword): ( + // files: [ + // "voxygen.audio.sfx.abilities.separated_third_swing", + // ], + // threshold: 0.7, + //), Attack(DashMelee(Swing), Sword): ( files: [ "voxygen.audio.sfx.abilities.sword_dash", @@ -319,12 +319,12 @@ ], threshold: 0.5, ), - Attack(BasicBeam, Staff): ( - files: [ - "voxygen.audio.sfx.abilities.flame_thrower", - ], - threshold: 0.2, - ), + //Attack(BasicBeam, Staff): ( + // files: [ + // "voxygen.audio.sfx.abilities.flame_thrower", + // ], + // threshold: 0.2, + //), Attack(BasicRanged, Staff): ( files: [ // "voxygen.audio.sfx.abilities.staff_channeling", @@ -381,12 +381,12 @@ ], threshold: 0.5, ), - Attack(BasicBeam, Sceptre): ( - files: [ - "voxygen.audio.sfx.abilities.staff_channeling", - ], - threshold: 0.6, - ), + //Attack(BasicBeam, Sceptre): ( + // files: [ + // "voxygen.audio.sfx.abilities.staff_channeling", + // ], + // threshold: 0.6, + //), // // Dagger diff --git a/common/src/event.rs b/common/src/event.rs index fee8baf6a0..3b07c7be38 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -9,6 +9,8 @@ use std::{collections::VecDeque, ops::DerefMut}; use vek::*; pub enum LocalEvent { + /// An attack for use with particles and sfx + Attack(EcsEntity), /// Applies upward force to entity's `Vel` Jump(EcsEntity), /// Applies the `impulse` to `entity`'s `Vel` diff --git a/common/src/outcome.rs b/common/src/outcome.rs index bf6002aa63..3fab916ada 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -1,8 +1,5 @@ use crate::comp; -use comp::{ - item::{tool::ToolKind, Reagent}, - CharacterAbilityType, -}; +use comp::{item::Reagent, CharacterState, Loadout}; use serde::{Deserialize, Serialize}; use vek::*; @@ -25,14 +22,18 @@ pub enum Outcome { body: comp::Body, vel: Vec3, }, - Swing { + Attack { pos: Vec3, - ability: CharacterAbilityType, - tool: ToolKind, + character_state: CharacterState, + loadout: Loadout, }, LevelUp { pos: Vec3, }, + Beam { + pos: Vec3, + heal: bool, + }, } impl Outcome { @@ -40,8 +41,9 @@ impl Outcome { match self { Outcome::Explosion { pos, .. } => Some(*pos), Outcome::ProjectileShot { pos, .. } => Some(*pos), - Outcome::Swing { pos, .. } => Some(*pos), + Outcome::Attack { pos, .. } => Some(*pos), Outcome::LevelUp { pos } => Some(*pos), + Outcome::Beam { pos, .. } => Some(*pos), } } } diff --git a/common/src/state.rs b/common/src/state.rs index aeb90bca02..4c4e64b5d0 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -2,6 +2,7 @@ use crate::{ comp, event::{EventBus, LocalEvent, ServerEvent}, metrics::{PhysicsMetrics, SysMetrics}, + outcome::Outcome, region::RegionMap, sync::WorldSyncExt, sys, @@ -187,6 +188,9 @@ impl State { ecs.insert(SysMetrics::default()); ecs.insert(PhysicsMetrics::default()); + // Register outcomes + ecs.insert(Vec::::new()); + ecs } @@ -388,7 +392,28 @@ impl State { for event in events { let mut velocities = self.ecs.write_storage::(); let mut controllers = self.ecs.write_storage::(); + let positions = self.ecs.read_storage::(); + let character_states = self.ecs.read_storage::(); + let loadouts = self.ecs.read_storage::(); match event { + LocalEvent::Attack(entity) => { + self.ecs + .write_resource::>() + .push(Outcome::Attack { + pos: positions + .get(entity) + .expect("Failed to fetch attacking entity") + .0, + character_state: character_states + .get(entity) + .expect("Failed to get the character state of the attacking entity") + .clone(), + loadout: loadouts + .get(entity) + .expect("Failed to get attacking entity's loadout") + .clone(), + }); + }, LocalEvent::Jump(entity) => { if let Some(vel) = velocities.get_mut(entity) { vel.0.z = HUMANOID_JUMP_ACCEL; diff --git a/common/src/sys/melee.rs b/common/src/sys/melee.rs index f284cb390d..60c120ab6e 100644 --- a/common/src/sys/melee.rs +++ b/common/src/sys/melee.rs @@ -56,7 +56,7 @@ impl<'a> System<'a> for Sys { let start_time = std::time::Instant::now(); span!(_guard, "run", "melee::Sys::run"); let mut server_emitter = server_bus.emitter(); - let mut _local_emitter = local_bus.emitter(); + let mut local_emitter = local_bus.emitter(); // Attacks for (entity, uid, pos, ori, scale_maybe, attack) in ( &entities, @@ -72,6 +72,7 @@ impl<'a> System<'a> for Sys { continue; } attack.applied = true; + local_emitter.emit(LocalEvent::Attack(entity)); // Go through all other entities for (b, pos_b, scale_b_maybe, health_b, body_b, char_state_b_maybe) in ( diff --git a/server/src/events/entity_creation.rs b/server/src/events/entity_creation.rs index 6ff0943886..6d8aa4b1de 100644 --- a/server/src/events/entity_creation.rs +++ b/server/src/events/entity_creation.rs @@ -145,6 +145,11 @@ pub fn handle_shockwave( pub fn handle_beam(server: &mut Server, properties: beam::Properties, pos: Pos, ori: Ori) { let state = server.state_mut(); + let ecs = state.ecs(); + ecs.write_resource::>().push(Outcome::Beam { + pos: pos.0, + heal: properties.lifesteal_eff > 0.0, + }); state.create_beam(properties, pos, ori).build(); } diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index dcbc958e0f..c77cd7bb93 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -97,6 +97,7 @@ use common::{ event::EventBus, outcome::Outcome, state::State, + states::utils::StageSection, terrain::{BlockKind, TerrainChunk}, vol::ReadVol, }; @@ -382,7 +383,63 @@ impl SfxMgr { let file_ref = "voxygen.audio.sfx.character.level_up_sound_-_shorter_wind_up"; audio.play_sfx(file_ref, *pos, None); }, - _ => {}, + Outcome::Beam { pos, heal } => { + if *heal { + let file_ref = "voxygen.audio.sfx.abilities.staff_channeling"; + audio.play_sfx(file_ref, *pos, None); + } else { + let file_ref = "voxygen.audio.sfx.abilities.flame_thrower"; + audio.play_sfx(file_ref, *pos, None); + } + }, + Outcome::Attack { + pos, + character_state, + loadout, + } => { + if let Some(item_config) = &loadout.active_item { + if let ItemKind::Tool(data) = item_config.item.kind() { + if character_state.is_attack() { + match ( + CharacterAbilityType::from(character_state), + data.kind.clone(), + ) { + ( + CharacterAbilityType::ComboMelee(StageSection::Swing, 1), + ToolKind::Sword, + ) => { + audio.play_sfx( + "voxygen.audio.sfx.abilities.swing_sword", + *pos, + None, + ); + }, + ( + CharacterAbilityType::ComboMelee(StageSection::Swing, 2), + ToolKind::Sword, + ) => { + audio.play_sfx( + "voxygen.audio.sfx.abilities.separated_second_swing", + *pos, + None, + ); + }, + ( + CharacterAbilityType::ComboMelee(StageSection::Swing, 3), + ToolKind::Sword, + ) => { + audio.play_sfx( + "voxygen.audio.sfx.abilities.separated_third_swing", + *pos, + None, + ); + }, + _ => {}, + } + } + } + } + }, } } From 3b47add55a4b0b0b3679ed98be3fdf0889ac6682 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Mon, 16 Nov 2020 15:32:23 -0800 Subject: [PATCH 35/37] Fully move sfx away from ECS event bus --- assets/voxygen/audio/sfx.ron | 66 +++++------ client/src/lib.rs | 14 +-- common/src/event.rs | 2 - common/src/outcome.rs | 8 +- common/src/state.rs | 25 ----- common/src/sys/melee.rs | 3 +- voxygen/src/audio/mod.rs | 68 +++++++++++- .../src/audio/sfx/event_mapper/block/mod.rs | 41 ++++--- .../audio/sfx/event_mapper/campfire/mod.rs | 33 +++--- .../src/audio/sfx/event_mapper/combat/mod.rs | 31 +++--- voxygen/src/audio/sfx/event_mapper/mod.rs | 17 ++- .../audio/sfx/event_mapper/movement/mod.rs | 26 +++-- voxygen/src/audio/sfx/mod.rs | 105 +----------------- voxygen/src/ecs/mod.rs | 3 +- voxygen/src/scene/mod.rs | 2 +- voxygen/src/session.rs | 15 ++- 16 files changed, 207 insertions(+), 252 deletions(-) diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 959d1913a1..53462bff26 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -181,24 +181,24 @@ ], threshold: 0.5, ), - //Attack(ComboMelee(Swing, 1), Sword): ( - // files: [ - // "voxygen.audio.sfx.abilities.swing_sword", - // ], - // threshold: 0.7, - //), - //Attack(ComboMelee(Swing, 2), Sword): ( - // files: [ - // "voxygen.audio.sfx.abilities.separated_second_swing", - // ], - // threshold: 0.7, - //), - //Attack(ComboMelee(Swing, 3), Sword): ( - // files: [ - // "voxygen.audio.sfx.abilities.separated_third_swing", - // ], - // threshold: 0.7, - //), + Attack(ComboMelee(Swing, 1), Sword): ( + files: [ + "voxygen.audio.sfx.abilities.swing_sword", + ], + threshold: 0.7, + ), + Attack(ComboMelee(Swing, 2), Sword): ( + files: [ + "voxygen.audio.sfx.abilities.separated_second_swing", + ], + threshold: 0.7, + ), + Attack(ComboMelee(Swing, 3), Sword): ( + files: [ + "voxygen.audio.sfx.abilities.separated_third_swing", + ], + threshold: 0.7, + ), Attack(DashMelee(Swing), Sword): ( files: [ "voxygen.audio.sfx.abilities.sword_dash", @@ -319,12 +319,12 @@ ], threshold: 0.5, ), - //Attack(BasicBeam, Staff): ( - // files: [ - // "voxygen.audio.sfx.abilities.flame_thrower", - // ], - // threshold: 0.2, - //), + Attack(BasicBeam, Staff): ( + files: [ + "voxygen.audio.sfx.abilities.flame_thrower", + ], + threshold: 0.2, + ), Attack(BasicRanged, Staff): ( files: [ // "voxygen.audio.sfx.abilities.staff_channeling", @@ -353,12 +353,12 @@ ], threshold: 0.5, ), - Attack(BasicRanged, Bow): ( - files: [ - // channeling sound. - ], - threshold: 0.8, - ), + //Attack(BasicRanged, Bow): ( + // files: [ + // // channeling sound. + // ], + // threshold: 0.8, + //), Inventory(CollectedTool(Bow)): ( files: [ "voxygen.audio.sfx.inventory.add_item", @@ -381,12 +381,6 @@ ], threshold: 0.5, ), - //Attack(BasicBeam, Sceptre): ( - // files: [ - // "voxygen.audio.sfx.abilities.staff_channeling", - // ], - // threshold: 0.6, - //), // // Dagger diff --git a/client/src/lib.rs b/client/src/lib.rs index f923961be4..4a672a6e87 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -858,15 +858,11 @@ impl Client { self.state.terrain().get_key_arc(chunk_pos).cloned() } - pub fn current(&self) -> Option where - C: Clone, - { - Some( - self.state - .read_storage::() - .get(self.entity) - .cloned()?, - ) + pub fn current(&self) -> Option + where + C: Clone, + { + Some(self.state.read_storage::().get(self.entity).cloned()?) } pub fn current_biome(&self) -> BiomeKind { diff --git a/common/src/event.rs b/common/src/event.rs index 3b07c7be38..fee8baf6a0 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -9,8 +9,6 @@ use std::{collections::VecDeque, ops::DerefMut}; use vek::*; pub enum LocalEvent { - /// An attack for use with particles and sfx - Attack(EcsEntity), /// Applies upward force to entity's `Vel` Jump(EcsEntity), /// Applies the `impulse` to `entity`'s `Vel` diff --git a/common/src/outcome.rs b/common/src/outcome.rs index 3fab916ada..97518b0a49 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -1,5 +1,5 @@ use crate::comp; -use comp::{item::Reagent, CharacterState, Loadout}; +use comp::item::Reagent; use serde::{Deserialize, Serialize}; use vek::*; @@ -22,11 +22,6 @@ pub enum Outcome { body: comp::Body, vel: Vec3, }, - Attack { - pos: Vec3, - character_state: CharacterState, - loadout: Loadout, - }, LevelUp { pos: Vec3, }, @@ -41,7 +36,6 @@ impl Outcome { match self { Outcome::Explosion { pos, .. } => Some(*pos), Outcome::ProjectileShot { pos, .. } => Some(*pos), - Outcome::Attack { pos, .. } => Some(*pos), Outcome::LevelUp { pos } => Some(*pos), Outcome::Beam { pos, .. } => Some(*pos), } diff --git a/common/src/state.rs b/common/src/state.rs index 4c4e64b5d0..aeb90bca02 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -2,7 +2,6 @@ use crate::{ comp, event::{EventBus, LocalEvent, ServerEvent}, metrics::{PhysicsMetrics, SysMetrics}, - outcome::Outcome, region::RegionMap, sync::WorldSyncExt, sys, @@ -188,9 +187,6 @@ impl State { ecs.insert(SysMetrics::default()); ecs.insert(PhysicsMetrics::default()); - // Register outcomes - ecs.insert(Vec::::new()); - ecs } @@ -392,28 +388,7 @@ impl State { for event in events { let mut velocities = self.ecs.write_storage::(); let mut controllers = self.ecs.write_storage::(); - let positions = self.ecs.read_storage::(); - let character_states = self.ecs.read_storage::(); - let loadouts = self.ecs.read_storage::(); match event { - LocalEvent::Attack(entity) => { - self.ecs - .write_resource::>() - .push(Outcome::Attack { - pos: positions - .get(entity) - .expect("Failed to fetch attacking entity") - .0, - character_state: character_states - .get(entity) - .expect("Failed to get the character state of the attacking entity") - .clone(), - loadout: loadouts - .get(entity) - .expect("Failed to get attacking entity's loadout") - .clone(), - }); - }, LocalEvent::Jump(entity) => { if let Some(vel) = velocities.get_mut(entity) { vel.0.z = HUMANOID_JUMP_ACCEL; diff --git a/common/src/sys/melee.rs b/common/src/sys/melee.rs index 60c120ab6e..19df271264 100644 --- a/common/src/sys/melee.rs +++ b/common/src/sys/melee.rs @@ -56,7 +56,7 @@ impl<'a> System<'a> for Sys { let start_time = std::time::Instant::now(); span!(_guard, "run", "melee::Sys::run"); let mut server_emitter = server_bus.emitter(); - let mut local_emitter = local_bus.emitter(); + let _local_emitter = local_bus.emitter(); // Attacks for (entity, uid, pos, ori, scale_maybe, attack) in ( &entities, @@ -72,7 +72,6 @@ impl<'a> System<'a> for Sys { continue; } attack.applied = true; - local_emitter.emit(LocalEvent::Attack(entity)); // Go through all other entities for (b, pos_b, scale_b_maybe, health_b, body_b, char_state_b_maybe) in ( diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 49da6c3689..20b78c4429 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -9,9 +9,10 @@ pub mod soundcache; use channel::{AmbientChannel, AmbientChannelTag, MusicChannel, MusicChannelTag, SfxChannel}; use fader::Fader; +use sfx::{SfxEvent, SfxTriggerItem}; use soundcache::SoundCache; use std::time::Duration; -//use tracing::warn; +use tracing::debug; use common::assets; use rodio::{source::Source, Decoder, OutputStream, OutputStreamHandle, StreamError}; @@ -162,6 +163,71 @@ impl AudioFrontend { self.music_channels.last_mut() } + /// Function to play sfx from external places. Useful for UI and + /// inventory events + pub fn emit_sfx_item(&mut self, trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>) { + if let Some((event, item)) = trigger_item { + let sfx_file = match item.files.len() { + 0 => { + debug!("Sfx event {:?} is missing audio file.", event); + "voxygen.audio.sfx.placeholder" + }, + 1 => item + .files + .last() + .expect("Failed to determine sound file for this trigger item."), + _ => { + // If more than one file is listed, choose one at random + let rand_step = rand::random::() % item.files.len(); + &item.files[rand_step] + }, + }; + + self.play_sfx(sfx_file, self.listener.pos, None); + } else { + debug!("Missing sfx trigger config for external sfx event.",); + } + } + + /// Play an sfx file given the position, SfxEvent, and whether it is + /// underwater or not + pub fn emit_sfx( + &mut self, + trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>, + position: Vec3, + volume: Option, + underwater: bool, + ) { + if let Some((event, item)) = trigger_item { + let sfx_file = match item.files.len() { + 0 => { + debug!("Sfx event {:?} is missing audio file.", event); + "voxygen.audio.sfx.placeholder" + }, + 1 => item + .files + .last() + .expect("Failed to determine sound file for this trigger item."), + _ => { + // If more than one file is listed, choose one at random + let rand_step = rand::random::() % item.files.len(); + &item.files[rand_step] + }, + }; + + if underwater { + self.play_underwater_sfx(sfx_file, position, volume); + } else { + self.play_sfx(sfx_file, position, volume); + } + } else { + debug!( + "Missing sfx trigger config for sfx event at position: {:?}", + position + ); + } + } + /// Play (once) an sfx file by file path at the give position and volume pub fn play_sfx(&mut self, sound: &str, pos: Vec3, vol: Option) { if self.audio_stream.is_some() { diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index b6d263208b..f64bbeb271 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -1,19 +1,22 @@ /// EventMapper::Block watches the sound emitting blocks within /// chunk range of the player and emits ambient sfx use crate::{ - audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, + audio::sfx::{SfxEvent, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, scene::{terrain::BlocksOfInterest, Camera, Terrain}, + AudioFrontend, }; use super::EventMapper; use client::Client; use common::{ - comp::Pos, event::EventBus, spiral::Spiral2d, state::State, terrain::TerrainChunk, - vol::RectRasterableVol, + comp::Pos, + spiral::Spiral2d, + state::State, + terrain::{BlockKind, TerrainChunk}, + vol::{ReadVol, RectRasterableVol}, }; use hashbrown::HashMap; use rand::{thread_rng, Rng}; -use specs::WorldExt; use std::time::Instant; use vek::*; @@ -39,6 +42,7 @@ pub struct BlockEventMapper { impl EventMapper for BlockEventMapper { fn maintain( &mut self, + audio: &mut AudioFrontend, state: &State, player_entity: specs::Entity, camera: &Camera, @@ -46,11 +50,6 @@ impl EventMapper for BlockEventMapper { terrain: &Terrain, client: &Client, ) { - let ecs = state.ecs(); - - let sfx_event_bus = ecs.read_resource::>(); - let mut sfx_emitter = sfx_event_bus.emitter(); - let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; @@ -175,21 +174,29 @@ impl EventMapper for BlockEventMapper { continue; } let block_pos: Vec3 = absolute_pos + block; - let state = self.history.entry(block_pos).or_default(); + let internal_state = self.history.entry(block_pos).or_default(); let block_pos = block_pos.map(|x| x as f32); - if Self::should_emit(state, triggers.get_key_value(&sounds.sfx)) { + if Self::should_emit(internal_state, triggers.get_key_value(&sounds.sfx)) { // If the camera is within SFX distance if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR { - sfx_emitter.emit(SfxEventItem::new( - sounds.sfx.clone(), - Some(block_pos), + let underwater = state + .terrain() + .get(cam_pos.map(|e| e.floor() as i32)) + .map(|b| b.kind() == BlockKind::Water) + .unwrap_or(false); + + let sfx_trigger_item = triggers.get_key_value(&sounds.sfx); + audio.emit_sfx( + sfx_trigger_item, + block_pos, Some(sounds.volume), - )); + underwater, + ); } - state.time = Instant::now(); - state.event = sounds.sfx.clone(); + internal_state.time = Instant::now(); + internal_state.event = sounds.sfx.clone(); } } }); diff --git a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs index d5a94cf9a9..712739390a 100644 --- a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs @@ -1,7 +1,8 @@ /// EventMapper::Campfire maps sfx to campfires use crate::{ - audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, + audio::sfx::{SfxEvent, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, scene::{Camera, Terrain}, + AudioFrontend, }; use super::EventMapper; @@ -9,9 +10,9 @@ use super::EventMapper; use client::Client; use common::{ comp::{object, Body, Pos}, - event::EventBus, state::State, - terrain::TerrainChunk, + terrain::{BlockKind, TerrainChunk}, + vol::ReadVol, }; use hashbrown::HashMap; use specs::{Entity as EcsEntity, Join, WorldExt}; @@ -39,6 +40,7 @@ pub struct CampfireEventMapper { impl EventMapper for CampfireEventMapper { fn maintain( &mut self, + audio: &mut AudioFrontend, state: &State, player_entity: specs::Entity, camera: &Camera, @@ -47,10 +49,6 @@ impl EventMapper for CampfireEventMapper { _client: &Client, ) { let ecs = state.ecs(); - - let sfx_event_bus = ecs.read_resource::>(); - let mut sfx_emitter = sfx_event_bus.emitter(); - let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; for (entity, body, pos) in ( @@ -62,24 +60,25 @@ impl EventMapper for CampfireEventMapper { .filter(|(_, _, e_pos)| (e_pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR) { if let Body::Object(object::Body::CampfireLit) = body { - let state = self.event_history.entry(entity).or_default(); + let internal_state = self.event_history.entry(entity).or_default(); let mapped_event = SfxEvent::Campfire; // Check for SFX config entry for this movement - if Self::should_emit(state, triggers.get_key_value(&mapped_event)) { - sfx_emitter.emit(SfxEventItem::new( - mapped_event.clone(), - Some(pos.0), - Some(0.25), - )); - - state.time = Instant::now(); + if Self::should_emit(internal_state, triggers.get_key_value(&mapped_event)) { + let underwater = state + .terrain() + .get(cam_pos.map(|e| e.floor() as i32)) + .map(|b| b.kind() == BlockKind::Water) + .unwrap_or(false); + let sfx_trigger_item = triggers.get_key_value(&mapped_event); + audio.emit_sfx(sfx_trigger_item, pos.0, None, underwater); + internal_state.time = Instant::now(); } // update state to determine the next event. We only record the time (above) if // it was dispatched - state.event = mapped_event; + internal_state.event = mapped_event; } } self.cleanup(player_entity); diff --git a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs index b90031d4e2..0b0720301e 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs @@ -1,8 +1,9 @@ /// EventMapper::Combat watches the combat states of surrounding entities' and /// emits sfx related to weapons and attacks/abilities use crate::{ - audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, + audio::sfx::{SfxEvent, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, scene::{Camera, Terrain}, + AudioFrontend, }; use super::EventMapper; @@ -10,9 +11,9 @@ use super::EventMapper; use client::Client; use common::{ comp::{item::ItemKind, CharacterAbilityType, CharacterState, Loadout, Pos}, - event::EventBus, state::State, - terrain::TerrainChunk, + terrain::{BlockKind, TerrainChunk}, + vol::ReadVol, }; use hashbrown::HashMap; use specs::{Entity as EcsEntity, Join, WorldExt}; @@ -42,6 +43,7 @@ pub struct CombatEventMapper { impl EventMapper for CombatEventMapper { fn maintain( &mut self, + audio: &mut AudioFrontend, state: &State, player_entity: specs::Entity, camera: &Camera, @@ -51,9 +53,6 @@ impl EventMapper for CombatEventMapper { ) { let ecs = state.ecs(); - let sfx_event_bus = ecs.read_resource::>(); - let mut sfx_emitter = sfx_event_bus.emitter(); - let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; @@ -67,21 +66,27 @@ impl EventMapper for CombatEventMapper { .filter(|(_, e_pos, ..)| (e_pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR) { if let Some(character) = character { - let state = self.event_history.entry(entity).or_default(); + let sfx_state = self.event_history.entry(entity).or_default(); - let mapped_event = Self::map_event(character, state, loadout); + let mapped_event = Self::map_event(character, sfx_state, loadout); // Check for SFX config entry for this movement - if Self::should_emit(state, triggers.get_key_value(&mapped_event)) { - sfx_emitter.emit(SfxEventItem::new(mapped_event.clone(), Some(pos.0), None)); + if Self::should_emit(sfx_state, triggers.get_key_value(&mapped_event)) { + let underwater = state + .terrain() + .get(cam_pos.map(|e| e.floor() as i32)) + .map(|b| b.kind() == BlockKind::Water) + .unwrap_or(false); - state.time = Instant::now(); + let sfx_trigger_item = triggers.get_key_value(&mapped_event); + audio.emit_sfx(sfx_trigger_item, pos.0, None, underwater); + sfx_state.time = Instant::now(); } // update state to determine the next event. We only record the time (above) if // it was dispatched - state.event = mapped_event; - state.weapon_drawn = Self::weapon_drawn(character); + sfx_state.event = mapped_event; + sfx_state.weapon_drawn = Self::weapon_drawn(character); } } diff --git a/voxygen/src/audio/sfx/event_mapper/mod.rs b/voxygen/src/audio/sfx/event_mapper/mod.rs index 12976a58b8..90c4c22ecc 100644 --- a/voxygen/src/audio/sfx/event_mapper/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/mod.rs @@ -12,11 +12,15 @@ use combat::CombatEventMapper; use movement::MovementEventMapper; use super::SfxTriggers; -use crate::scene::{Camera, Terrain}; +use crate::{ + scene::{Camera, Terrain}, + AudioFrontend, +}; trait EventMapper { fn maintain( &mut self, + audio: &mut AudioFrontend, state: &State, player_entity: specs::Entity, camera: &Camera, @@ -44,6 +48,7 @@ impl SfxEventMapper { pub fn maintain( &mut self, + audio: &mut AudioFrontend, state: &State, player_entity: specs::Entity, camera: &Camera, @@ -52,7 +57,15 @@ impl SfxEventMapper { client: &Client, ) { for mapper in &mut self.mappers { - mapper.maintain(state, player_entity, camera, triggers, terrain, client); + mapper.maintain( + audio, + state, + player_entity, + camera, + triggers, + terrain, + client, + ); } } } diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index df9d33366e..89ff544e9a 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -3,15 +3,16 @@ /// proportionate to the extity's size use super::EventMapper; use crate::{ - audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, + audio::sfx::{SfxEvent, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR}, scene::{Camera, Terrain}, + AudioFrontend, }; use client::Client; use common::{ comp::{Body, CharacterState, PhysicsState, Pos, Vel}, - event::EventBus, state::State, terrain::{BlockKind, TerrainChunk}, + vol::ReadVol, }; use hashbrown::HashMap; use specs::{Entity as EcsEntity, Join, WorldExt}; @@ -44,6 +45,7 @@ pub struct MovementEventMapper { impl EventMapper for MovementEventMapper { fn maintain( &mut self, + audio: &mut AudioFrontend, state: &State, player_entity: specs::Entity, camera: &Camera, @@ -53,9 +55,6 @@ impl EventMapper for MovementEventMapper { ) { let ecs = state.ecs(); - let sfx_event_bus = ecs.read_resource::>(); - let mut sfx_emitter = sfx_event_bus.emitter(); - let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; @@ -99,12 +98,19 @@ impl EventMapper for MovementEventMapper { // Check for SFX config entry for this movement if Self::should_emit(internal_state, triggers.get_key_value(&mapped_event)) { - sfx_emitter.emit(SfxEventItem::new( - mapped_event.clone(), - Some(pos.0), - Some(Self::get_volume_for_body_type(body)), - )); + let underwater = state + .terrain() + .get(cam_pos.map(|e| e.floor() as i32)) + .map(|b| b.kind() == BlockKind::Water) + .unwrap_or(false); + let sfx_trigger_item = triggers.get_key_value(&mapped_event); + audio.emit_sfx( + sfx_trigger_item, + pos.0, + Some(Self::get_volume_for_body_type(body)), + underwater, + ); internal_state.time = Instant::now(); } diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index c77cd7bb93..719e31578b 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -94,19 +94,15 @@ use common::{ item::{ItemKind, ToolKind}, object, Body, CharacterAbilityType, InventoryUpdateEvent, }, - event::EventBus, outcome::Outcome, state::State, - states::utils::StageSection, - terrain::{BlockKind, TerrainChunk}, - vol::ReadVol, + terrain::TerrainChunk, }; use event_mapper::SfxEventMapper; use hashbrown::HashMap; use rand::prelude::*; use serde::Deserialize; -use specs::WorldExt; -use tracing::{debug, warn}; +use tracing::warn; use vek::*; /// We watch the states of nearby entities in order to emit SFX at their @@ -241,7 +237,7 @@ impl SfxTriggers { } pub struct SfxMgr { - triggers: SfxTriggers, + pub triggers: SfxTriggers, event_mapper: SfxEventMapper, } @@ -269,25 +265,16 @@ impl SfxMgr { if !audio.sfx_enabled() { return; } - let ecs = state.ecs(); - // This checks to see if the camera is underwater. If it is, - // we pass all sfx through a low pass filter let focus_off = camera.get_focus_pos().map(f32::trunc); - let underwater = state - .terrain() - .get((camera.dependents().cam_pos + focus_off).map(|e| e.floor() as i32)) - .map(|b| b.kind()) - .unwrap_or(BlockKind::Air) - == BlockKind::Water; let cam_pos = camera.dependents().cam_pos + focus_off; // Sets the listener position to the camera position facing the // same direction as the camera audio.set_listener_pos(cam_pos, camera.dependents().cam_dir); - // TODO: replace; deprecated in favor of outcomes self.event_mapper.maintain( + audio, state, player_entity, camera, @@ -295,42 +282,6 @@ impl SfxMgr { terrain, client, ); - - // TODO: replace; deprecated in favor of outcomes - let events = ecs.read_resource::>().recv_all(); - - for event in events { - let position = match event.pos { - Some(pos) => pos, - _ => cam_pos, - }; - - if let Some(item) = self.triggers.get_trigger(&event.sfx) { - let sfx_file = match item.files.len() { - 0 => { - debug!("Sfx event {:?} is missing audio file.", event.sfx); - "voxygen.audio.sfx.placeholder" - }, - 1 => item - .files - .last() - .expect("Failed to determine sound file for this trigger item."), - _ => { - // If more than one file is listed, choose one at random - let rand_step = rand::random::() % item.files.len(); - &item.files[rand_step] - }, - }; - - if underwater { - audio.play_underwater_sfx(sfx_file, position, event.vol); - } else { - audio.play_sfx(sfx_file, position, event.vol); - } - } else { - debug!("Missing sfx trigger config for sfx event. {:?}", event.sfx); - } - } } pub fn handle_outcome(&mut self, outcome: &Outcome, audio: &mut AudioFrontend) { @@ -392,54 +343,6 @@ impl SfxMgr { audio.play_sfx(file_ref, *pos, None); } }, - Outcome::Attack { - pos, - character_state, - loadout, - } => { - if let Some(item_config) = &loadout.active_item { - if let ItemKind::Tool(data) = item_config.item.kind() { - if character_state.is_attack() { - match ( - CharacterAbilityType::from(character_state), - data.kind.clone(), - ) { - ( - CharacterAbilityType::ComboMelee(StageSection::Swing, 1), - ToolKind::Sword, - ) => { - audio.play_sfx( - "voxygen.audio.sfx.abilities.swing_sword", - *pos, - None, - ); - }, - ( - CharacterAbilityType::ComboMelee(StageSection::Swing, 2), - ToolKind::Sword, - ) => { - audio.play_sfx( - "voxygen.audio.sfx.abilities.separated_second_swing", - *pos, - None, - ); - }, - ( - CharacterAbilityType::ComboMelee(StageSection::Swing, 3), - ToolKind::Sword, - ) => { - audio.play_sfx( - "voxygen.audio.sfx.abilities.separated_third_swing", - *pos, - None, - ); - }, - _ => {}, - } - } - } - } - }, } } diff --git a/voxygen/src/ecs/mod.rs b/voxygen/src/ecs/mod.rs index 8e7b4cf08e..1bba6ffa02 100644 --- a/voxygen/src/ecs/mod.rs +++ b/voxygen/src/ecs/mod.rs @@ -2,7 +2,7 @@ pub mod comp; pub mod sys; use crate::audio::sfx::SfxEventItem; -use common::event::EventBus; +use common::{event::EventBus, outcome::Outcome}; use specs::{Entity, World, WorldExt}; #[derive(Copy, Clone, Debug)] @@ -27,6 +27,7 @@ pub fn init(world: &mut World) { world.register::(); world.register::(); world.insert(MyExpFloaterList::default()); + world.insert(Vec::::new()); // Voxygen event buses world.insert(EventBus::::default()); diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 23ec0bdaf0..63b7d25289 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -101,7 +101,7 @@ pub struct Scene { particle_mgr: ParticleMgr, figure_mgr: FigureMgr, - sfx_mgr: SfxMgr, + pub sfx_mgr: SfxMgr, music_mgr: MusicMgr, ambient_mgr: AmbientMgr, } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 260f057086..bd2df0c142 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -1,5 +1,5 @@ use crate::{ - audio::sfx::{SfxEvent, SfxEventItem}, + audio::sfx::SfxEvent, ecs::MyEntity, hud::{DebugInfo, Event as HudEvent, Hud, HudInfo, PressBehavior}, i18n::{i18n_asset_key, Localization}, @@ -17,7 +17,6 @@ use common::{ comp, comp::{ChatMsg, ChatType, InventoryUpdateEvent, Pos, Vel}, consts::{MAX_MOUNT_RANGE, MAX_PICKUP_RANGE}, - event::EventBus, msg::PresenceKind, outcome::Outcome, span, @@ -121,12 +120,12 @@ impl SessionState { self.hud.new_message(m); }, client::Event::InventoryUpdated(inv_event) => { - let sfx_event = SfxEvent::from(&inv_event); - client - .state() - .ecs() - .read_resource::>() - .emit_now(SfxEventItem::at_player_position(sfx_event)); + let sfx_trigger_item = self + .scene + .sfx_mgr + .triggers + .get_key_value(&SfxEvent::from(&inv_event)); + global_state.audio.emit_sfx_item(sfx_trigger_item); match inv_event { InventoryUpdateEvent::CollectFailed => { From 2d2f267907612b365f5a443e0a5f9e209e629f14 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Mon, 16 Nov 2020 16:38:48 -0800 Subject: [PATCH 36/37] Addressed comments and fixed pipeline --- assets/voxygen/audio/ambient.ron | 2 +- assets/voxygen/audio/ambient/wind.ogg | 4 +- assets/voxygen/audio/sfx.ron | 100 +++++++++--------- assets/voxygen/audio/sfx/ambient/fire.wav | 4 +- assets/voxygen/audio/soundtrack.ron | 12 +++ assets/voxygen/audio/soundtrack/oceania.ogg | 3 + voxygen/src/audio/ambient.rs | 74 +++++-------- voxygen/src/audio/music.rs | 2 +- .../src/audio/sfx/event_mapper/block/mod.rs | 12 ++- .../audio/sfx/event_mapper/campfire/mod.rs | 4 +- .../src/audio/sfx/event_mapper/combat/mod.rs | 4 +- .../audio/sfx/event_mapper/movement/mod.rs | 2 +- 12 files changed, 110 insertions(+), 113 deletions(-) create mode 100644 assets/voxygen/audio/soundtrack/oceania.ogg diff --git a/assets/voxygen/audio/ambient.ron b/assets/voxygen/audio/ambient.ron index e5f2a615fe..a33d46987d 100644 --- a/assets/voxygen/audio/ambient.ron +++ b/assets/voxygen/audio/ambient.ron @@ -2,7 +2,7 @@ tracks: [ ( path: "voxygen.audio.ambient.wind", - length: 4.5, + length: 14.5, tag: Wind, ), ] diff --git a/assets/voxygen/audio/ambient/wind.ogg b/assets/voxygen/audio/ambient/wind.ogg index 37cac9eb05..ce558e73b1 100644 --- a/assets/voxygen/audio/ambient/wind.ogg +++ b/assets/voxygen/audio/ambient/wind.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c28c1067d78474057c8a5b4608bb0a6026f90377074e287bb87fbd3e8fa39098 -size 94292 +oid sha256:4786e1bbda94b362a6866fc9235f56c4d5b809dd47e7d4700ccbe5c23f202613 +size 315989 diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 53462bff26..b4c6b24bb8 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -102,32 +102,32 @@ ], threshold: 0.12, ), - ExperienceGained: ( - files: [ - // "voxygen.audio.sfx.character.experience_gained_1", - // "voxygen.audio.sfx.character.experience_gained_2", - // "voxygen.audio.sfx.character.experience_gained_3", - ], - threshold: 0.5, - ), + //ExperienceGained: ( + // files: [ + // "voxygen.audio.sfx.character.experience_gained_1", + // "voxygen.audio.sfx.character.experience_gained_2", + // "voxygen.audio.sfx.character.experience_gained_3", + // ], + // threshold: 0.5, + //), LevelUp:( files: [ "voxygen.audio.sfx.character.level_up_sound_-_shorter_wind_up", ], threshold: 0.5, ), - Jump: ( - files: [ - // Event not implemented? - ], - threshold: 0.25, - ), - Fall: ( - files: [ - // Event not implemented? - ], - threshold: 0.25, - ), + //Jump: ( + // files: [ + // // Event not implemented? + // ], + // threshold: 0.25, + //), + //Fall: ( + // files: [ + // // Event not implemented? + // ], + // threshold: 0.25, + //), Roll: ( files: [ "voxygen.audio.sfx.character.dive_roll_1", @@ -135,18 +135,18 @@ ], threshold: 0.25, ), - Climb: ( - files: [ - // TODO: sync with animation - //"voxygen.audio.sfx.footsteps.stepgrass_1", - //"voxygen.audio.sfx.footsteps.stepgrass_2", - //"voxygen.audio.sfx.footsteps.stepgrass_3", - //"voxygen.audio.sfx.footsteps.stepgrass_4", - //"voxygen.audio.sfx.footsteps.stepgrass_5", - //"voxygen.audio.sfx.footsteps.stepgrass_6", - ], - threshold: 0.25, - ), + //Climb: ( + // files: [ + // TODO: sync with animation + // "voxygen.audio.sfx.footsteps.stepgrass_1", + // "voxygen.audio.sfx.footsteps.stepgrass_2", + // "voxygen.audio.sfx.footsteps.stepgrass_3", + // "voxygen.audio.sfx.footsteps.stepgrass_4", + // "voxygen.audio.sfx.footsteps.stepgrass_5", + // "voxygen.audio.sfx.footsteps.stepgrass_6", + // ], + // threshold: 0.25, + //), GliderOpen: ( files: [ "voxygen.audio.sfx.glider_open", @@ -325,12 +325,12 @@ ], threshold: 0.2, ), - Attack(BasicRanged, Staff): ( - files: [ - // "voxygen.audio.sfx.abilities.staff_channeling", - ], - threshold: 0.8, - ), + //Attack(BasicRanged, Staff): ( + // files: [ + // "voxygen.audio.sfx.abilities.staff_channeling", + // ], + // threshold: 0.8, + //), Inventory(CollectedTool(Staff)): ( files: [ "voxygen.audio.sfx.inventory.pickup_staff", @@ -577,17 +577,17 @@ ], threshold: 0.3, ), - Explosion: ( - files: [ - // in code - ], - threshold: 0.2, - ), - ProjectileShot: ( - files: [ - // in code - ], - threshold: 0.5, - ), + //Explosion: ( + // files: [ + // // in code + // ], + // threshold: 0.2, + //), + //ProjectileShot: ( + // files: [ + // // in code + // ], + // threshold: 0.5, + //), } ) diff --git a/assets/voxygen/audio/sfx/ambient/fire.wav b/assets/voxygen/audio/sfx/ambient/fire.wav index fc78392d20..bf72a7bdc5 100644 --- a/assets/voxygen/audio/sfx/ambient/fire.wav +++ b/assets/voxygen/audio/sfx/ambient/fire.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa0da468a1af98a51565f4430bfd5eb3a12db3bce2959c24b0d11b0e99c9c7b7 -size 372540 +oid sha256:937d4e08697d52a801b85fec37bb249eca17cb77d27f43575a941a38ff02b91d +size 324368 diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index 2cb39fe157..e45161a316 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -8,6 +8,18 @@ ( tracks: [ + ( + title: "Oceania", + path: "voxygen.audio.soundtrack.oceania", + length: 135.0, + timing: None, + biomes: [ + (Lake, 2), + (Ocean, 3), + ], + site: Some(Void), + artist: "Eden", + ), ( title: "A Solemn Quest", path: "voxygen.audio.soundtrack.a_solemn_quest", diff --git a/assets/voxygen/audio/soundtrack/oceania.ogg b/assets/voxygen/audio/soundtrack/oceania.ogg new file mode 100644 index 0000000000..944155f4df --- /dev/null +++ b/assets/voxygen/audio/soundtrack/oceania.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14d11b545dc71ecf168aa90f488a158020aa535141f08978b5e9e5049595b03e +size 7520524 diff --git a/voxygen/src/audio/ambient.rs b/voxygen/src/audio/ambient.rs index c56f833f4f..4a46a65fcf 100644 --- a/voxygen/src/audio/ambient.rs +++ b/voxygen/src/audio/ambient.rs @@ -4,10 +4,11 @@ use crate::{ scene::Camera, }; use client::Client; -use common::{assets, state::State, terrain::BlockKind, vol::ReadVol}; +use common::{assets, state::State, vol::ReadVol}; use serde::Deserialize; use std::time::Instant; use tracing::warn; +use vek::*; #[derive(Debug, Default, Deserialize)] struct AmbientCollection { @@ -20,6 +21,7 @@ pub struct AmbientItem { path: String, /// Length of the track in seconds length: f32, + /// Specifies which ambient channel to play on tag: AmbientChannelTag, } @@ -57,31 +59,24 @@ impl AmbientMgr { let focus_off = camera.get_focus_pos().map(f32::trunc); let cam_pos = camera.dependents().cam_pos + focus_off; - let cam_alt = cam_pos.z; - let terrain_alt = Self::get_current_terrain_alt(client); + let (terrain_alt, tree_density) = if let Some(chunk) = client.current_chunk() { + (chunk.meta().alt(), chunk.meta().tree_density()) + } else { + (0.0, 0.0) + }; // The following code is specifically for wind, as it is the only // non-positional ambient sound in the game. Others can be added // as seen fit. - let alt_multiplier = (cam_alt / 1200.0).abs(); + // Wind volume increases with altitude + let alt_multiplier = (cam_pos.z / 1200.0).abs(); - // Tree density factors into ambient volume. The more trees, - // the less ambient - let mut tree_multiplier = self.tree_multiplier; - let new_tree_multiplier = if (cam_alt - terrain_alt) < 150.0 { - 1.0 - Self::get_current_tree_density(client) - } else { - 1.0 - }; - - // Smooths tree_multiplier transitions between chunks - if tree_multiplier < new_tree_multiplier { - tree_multiplier += 0.001; - } else if tree_multiplier > new_tree_multiplier { - tree_multiplier -= 0.001; - } - self.tree_multiplier = tree_multiplier; + // Tree density factors into wind volume. The more trees, + // the lower wind volume. The trees make more of an impact + // the closer the camera is to the ground. + self.tree_multiplier = + ((1.0 - tree_density) + ((cam_pos.z - terrain_alt) / 150.0).powf(2.0)).min(1.0); let mut volume_multiplier = alt_multiplier * self.tree_multiplier; @@ -89,36 +84,30 @@ impl AmbientMgr { if state .terrain() .get((cam_pos).map(|e| e.floor() as i32)) - .map(|b| b.kind()) - .unwrap_or(BlockKind::Air) - == BlockKind::Water + .map(|b| b.is_liquid()) + .unwrap_or(false) { volume_multiplier *= 0.1; } - if cam_pos.z < Self::get_current_terrain_alt(client) - 10.0 { + if cam_pos.z < terrain_alt - 10.0 { volume_multiplier = 0.0; } - let target_volume = volume_multiplier.max(0.0).min(1.0); + let target_volume = volume_multiplier.clamped(0.0, 1.0); // Transitions the ambient sounds (more) smoothly self.volume = audio.get_ambient_volume(); - if self.volume < target_volume { - audio.set_ambient_volume(self.volume + 0.001); - } else if self.volume > target_volume { - audio.set_ambient_volume(self.volume - 0.001); - } + audio.set_ambient_volume(Lerp::lerp(self.volume, target_volume, 0.01)); if self.began_playing.elapsed().as_secs_f32() > self.next_track_change { - //let game_time = (state.get_time_of_day() as u64 % 86400) as u32; - //let current_period_of_day = Self::get_current_day_period(game_time); - + // Right now there is only wind non-positional sfx so it is always + // selected. Modify this variable assignment when adding other non- + // positional sfx let track = &self .soundtrack .tracks .iter() - .filter(|track| track.tag == AmbientChannelTag::Wind) - .next(); + .find(|track| track.tag == AmbientChannelTag::Wind); if let Some(track) = track { self.began_playing = Instant::now(); @@ -130,21 +119,6 @@ impl AmbientMgr { } } - fn get_current_terrain_alt(client: &Client) -> f32 { - if let Some(chunk) = client.current_chunk() { - chunk.meta().alt() - } else { - 0.0 - } - } - - fn get_current_tree_density(client: &Client) -> f32 { - match client.current_chunk() { - Some(current_chunk) => current_chunk.meta().tree_density(), - None => 0.0, - } - } - fn load_soundtrack_items() -> AmbientCollection { match assets::load_file("voxygen.audio.ambient", &["ron"]) { Ok(file) => match ron::de::from_reader(file) { diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 7d0e94b2c8..7c76f22a19 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -150,7 +150,7 @@ impl MusicMgr { let mut rng = thread_rng(); // Adds a bit of randomness between plays - let silence_between_tracks_seconds: f32 = rng.gen_range(15.0, 60.0); + let silence_between_tracks_seconds: f32 = rng.gen_range(45.0, 120.0); let game_time = (state.get_time_of_day() as u64 % 86400) as u32; let current_period_of_day = Self::get_current_day_period(game_time); diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index f64bbeb271..9c53f9f8d3 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -12,7 +12,7 @@ use common::{ comp::Pos, spiral::Spiral2d, state::State, - terrain::{BlockKind, TerrainChunk}, + terrain::TerrainChunk, vol::{ReadVol, RectRasterableVol}, }; use hashbrown::HashMap; @@ -184,7 +184,7 @@ impl EventMapper for BlockEventMapper { let underwater = state .terrain() .get(cam_pos.map(|e| e.floor() as i32)) - .map(|b| b.kind() == BlockKind::Water) + .map(|b| b.is_liquid()) .unwrap_or(false); let sfx_trigger_item = triggers.get_key_value(&sounds.sfx); @@ -212,6 +212,14 @@ impl BlockEventMapper { } } + /// Ensures that: + /// 1. An sfx.ron entry exists for an SFX event + /// 2. The sfx has not been played since it's timeout threshold has elapsed, + /// which prevents firing every tick + /// Note that with so many blocks to choose from and different blocks being + /// selected each time, this is not perfect, but does reduce the number of + /// plays from blocks that have already emitted sfx and are stored in the + /// BlockEventMapper history. fn should_emit( previous_state: &PreviousBlockState, sfx_trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>, diff --git a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs index 712739390a..26773bd387 100644 --- a/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/campfire/mod.rs @@ -11,7 +11,7 @@ use client::Client; use common::{ comp::{object, Body, Pos}, state::State, - terrain::{BlockKind, TerrainChunk}, + terrain::TerrainChunk, vol::ReadVol, }; use hashbrown::HashMap; @@ -69,7 +69,7 @@ impl EventMapper for CampfireEventMapper { let underwater = state .terrain() .get(cam_pos.map(|e| e.floor() as i32)) - .map(|b| b.kind() == BlockKind::Water) + .map(|b| b.is_liquid()) .unwrap_or(false); let sfx_trigger_item = triggers.get_key_value(&mapped_event); audio.emit_sfx(sfx_trigger_item, pos.0, None, underwater); diff --git a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs index 0b0720301e..87345fa4cf 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/mod.rs @@ -12,7 +12,7 @@ use client::Client; use common::{ comp::{item::ItemKind, CharacterAbilityType, CharacterState, Loadout, Pos}, state::State, - terrain::{BlockKind, TerrainChunk}, + terrain::TerrainChunk, vol::ReadVol, }; use hashbrown::HashMap; @@ -75,7 +75,7 @@ impl EventMapper for CombatEventMapper { let underwater = state .terrain() .get(cam_pos.map(|e| e.floor() as i32)) - .map(|b| b.kind() == BlockKind::Water) + .map(|b| b.is_liquid()) .unwrap_or(false); let sfx_trigger_item = triggers.get_key_value(&mapped_event); diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 89ff544e9a..5e795d5970 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -101,7 +101,7 @@ impl EventMapper for MovementEventMapper { let underwater = state .terrain() .get(cam_pos.map(|e| e.floor() as i32)) - .map(|b| b.kind() == BlockKind::Water) + .map(|b| b.is_liquid()) .unwrap_or(false); let sfx_trigger_item = triggers.get_key_value(&mapped_event); From 1ce3827e22fa4b4985265e8c492a2138717a8df7 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Wed, 18 Nov 2020 13:30:49 -0800 Subject: [PATCH 37/37] Address comment --- voxygen/src/audio/sfx/event_mapper/block/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/voxygen/src/audio/sfx/event_mapper/block/mod.rs b/voxygen/src/audio/sfx/event_mapper/block/mod.rs index 9c53f9f8d3..5dada9c97b 100644 --- a/voxygen/src/audio/sfx/event_mapper/block/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/block/mod.rs @@ -145,6 +145,7 @@ impl EventMapper for BlockEventMapper { for sounds in sounds.iter() { // If the timing condition is false, continue // or if the player is far enough underground, continue + // TODO Address bird hack properly. See TODO on line 171 if !(sounds.cond)(state) || player_pos.0.z < (terrain_alt - 30.0) || ((sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) @@ -167,6 +168,8 @@ impl EventMapper for BlockEventMapper { // Iterate through each individual block for block in blocks { + // TODO Address this hack properly, potentially by making a new + // block of interest type which picks fewer leaf blocks // Hack to reduce the number of bird sounds (too many leaf blocks) if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) && thread_rng().gen_bool(0.999)