From 7c34a9693460cdd5134dbf27889636c3ed321704 Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Thu, 8 Apr 2021 17:42:39 -0400 Subject: [PATCH] Make fade timings configurable, and stop combat music on death. --- .../audio/music_transition_manifest.ron | 8 ++++++ voxygen/src/audio/channel.rs | 2 +- voxygen/src/audio/mod.rs | 14 +++++++--- voxygen/src/audio/music.rs | 28 +++++++++++++------ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/assets/voxygen/audio/music_transition_manifest.ron b/assets/voxygen/audio/music_transition_manifest.ron index fc8c715146..a8edc54bd2 100644 --- a/assets/voxygen/audio/music_transition_manifest.ron +++ b/assets/voxygen/audio/music_transition_manifest.ron @@ -3,4 +3,12 @@ combat_health_factor: 1000, combat_nearby_high_thresh: 4, combat_nearby_low_thresh: 1, + fade_timings: { + (TitleMusic, Explore): (2.0, 12.0), + (TitleMusic, Combat): (2.0, 3.0), + (Explore, TitleMusic): (2.0, 12.0), + (Explore, Combat): (5.0, 3.0), + (Combat, Explore): (5.0, 3.0), + (Combat, TitleMusic): (2.0, 12.0), + }, ) diff --git a/voxygen/src/audio/channel.rs b/voxygen/src/audio/channel.rs index 0cbf0b2fac..dd29aa4b85 100644 --- a/voxygen/src/audio/channel.rs +++ b/voxygen/src/audio/channel.rs @@ -37,7 +37,7 @@ enum ChannelState { /// 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)] +#[derive(PartialEq, Clone, Copy, Hash, Eq, Deserialize)] pub enum MusicChannelTag { TitleMusic, Exploration, diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 0dad733c15..69ceeec48d 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -9,6 +9,7 @@ pub mod soundcache; use channel::{AmbientChannel, AmbientChannelTag, MusicChannel, MusicChannelTag, SfxChannel}; use fader::Fader; +use music::MUSIC_TRANSITION_MANIFEST; use sfx::{SfxEvent, SfxTriggerItem}; use soundcache::{OggSound, WavSound}; use std::time::Duration; @@ -152,14 +153,19 @@ impl AudioFrontend { let existing_channel = self.music_channels.last_mut()?; if existing_channel.get_tag() != next_channel_tag { + let mtm = MUSIC_TRANSITION_MANIFEST.read(); + let (fade_out, fade_in) = mtm + .fade_timings + .get(&(existing_channel.get_tag(), next_channel_tag)) + .unwrap_or(&(1.0, 1.0)); + let fade_out = Duration::from_millis((1000.0 * fade_out) as _); + let fade_in = Duration::from_millis((1000.0 * fade_in) as _); // Fade the existing channel out. It will be removed when the fade completes. - existing_channel - .set_fader(Fader::fade_out(Duration::from_secs(2), self.music_volume)); + existing_channel.set_fader(Fader::fade_out(fade_out, self.music_volume)); let mut next_music_channel = MusicChannel::new(&audio_stream); - next_music_channel - .set_fader(Fader::fade_in(Duration::from_secs(12), self.music_volume)); + next_music_channel.set_fader(Fader::fade_in(fade_in, self.music_volume)); self.music_channels.push(next_music_channel); } diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 2578b7f080..52e3a9ffcd 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -50,6 +50,7 @@ use common::{ terrain::{BiomeKind, SitesKind}, }; use common_sys::state::State; +use hashbrown::HashMap; use lazy_static::lazy_static; use rand::{prelude::SliceRandom, thread_rng, Rng}; use serde::Deserialize; @@ -156,7 +157,7 @@ pub struct MusicMgr { } #[derive(Deserialize)] -struct MusicTransitionManifest { +pub struct MusicTransitionManifest { /// Within what radius do enemies count towards combat music? combat_nearby_radius: f32, /// Each multiple of this factor that an enemy has health counts as an extra @@ -166,6 +167,8 @@ struct MusicTransitionManifest { combat_nearby_high_thresh: u32, /// How many nearby enemies trigger Low combat music combat_nearby_low_thresh: u32, + /// Fade in and fade out timings for transitions between channels + pub fade_timings: HashMap<(MusicChannelTag, MusicChannelTag), (f32, f32)>, } impl Default for MusicTransitionManifest { @@ -175,6 +178,7 @@ impl Default for MusicTransitionManifest { combat_health_factor: 1000, combat_nearby_high_thresh: 3, combat_nearby_low_thresh: 1, + fade_timings: HashMap::new(), } } } @@ -191,7 +195,7 @@ impl assets::Asset for MusicTransitionManifest { } lazy_static! { - static ref MUSIC_TRANSITION_MANIFEST: AssetHandle = + pub static ref MUSIC_TRANSITION_MANIFEST: AssetHandle = AssetExt::load_expect("voxygen.audio.music_transition_manifest"); } @@ -260,6 +264,13 @@ impl MusicMgr { ); } + // Override combat music with explore music if the player is dead + if let Some(health) = healths.get(player) { + if health.is_dead { + activity_state = Explore; + } + } + let activity = match self.last_activity { MusicActivity::State(prev) if prev != activity_state => { MusicActivity::Transition(prev, activity_state) @@ -311,7 +322,6 @@ impl MusicMgr { // too many constraints. Returning Err(()) signals that we couldn't find // an appropriate track for the current state, and hence the state // machine for the activity shouldn't be updated. - let mut res = Ok(*activity); let soundtrack = self.soundtrack.read(); // First, filter out tracks not matching the timing, site, and biome let mut maybe_tracks = soundtrack @@ -354,7 +364,7 @@ impl MusicMgr { if !filtered_tracks.is_empty() { maybe_tracks = filtered_tracks; } else { - res = Err(()); + return Err(()); } // Third, prevent playing the last track if possible (though don't return Err // here, since the combat music is intended to loop) @@ -396,9 +406,6 @@ impl MusicMgr { ); if let Ok(track) = new_maybe_track { - if let Some(state) = track.activity_override { - res = Ok(MusicActivity::State(state)); - } //println!("Now playing {:?}", track.title); self.last_track = String::from(&track.title); self.began_playing = Instant::now(); @@ -410,7 +417,12 @@ impl MusicMgr { MusicChannelTag::Combat }; audio.play_music(&track.path, tag); - res + + if let Some(state) = track.activity_override { + Ok(MusicActivity::State(state)) + } else { + Ok(*activity) + } } else { Err(()) }