From 545eda6eeac5fc35f21627977ad40a01a109997f Mon Sep 17 00:00:00 2001 From: Avi Weinstock Date: Sun, 11 Apr 2021 17:47:45 -0400 Subject: [PATCH] Address MR 2077 review comments. --- .../audio/music_transition_manifest.ron | 9 +- assets/voxygen/audio/soundtrack.ron | 66 +++++----- voxygen/src/audio/mod.rs | 16 ++- voxygen/src/audio/music.rs | 123 +++++++++--------- 4 files changed, 107 insertions(+), 107 deletions(-) diff --git a/assets/voxygen/audio/music_transition_manifest.ron b/assets/voxygen/audio/music_transition_manifest.ron index a8edc54bd2..ac1cfc8bcc 100644 --- a/assets/voxygen/audio/music_transition_manifest.ron +++ b/assets/voxygen/audio/music_transition_manifest.ron @@ -4,11 +4,12 @@ combat_nearby_high_thresh: 4, combat_nearby_low_thresh: 1, fade_timings: { - (TitleMusic, Explore): (2.0, 12.0), + (TitleMusic, Exploration): (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), + (Exploration, TitleMusic): (2.0, 12.0), + (Exploration, Combat): (5.0, 3.0), + (Combat, Exploration): (5.0, 3.0), (Combat, TitleMusic): (2.0, 12.0), }, + interrupt_delay: 5.0, ) diff --git a/assets/voxygen/audio/soundtrack.ron b/assets/voxygen/audio/soundtrack.ron index 0bd5e594dd..c7128aa303 100644 --- a/assets/voxygen/audio/soundtrack.ron +++ b/assets/voxygen/audio/soundtrack.ron @@ -13,7 +13,7 @@ timing: None, biomes: [], site: Some(Dungeon), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -25,7 +25,7 @@ (Mountain, 1) ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Ultimafounding; mixed by Robotnik", )), Individual(( @@ -37,7 +37,7 @@ (Desert, 1) ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic; mixed by Robotnik", )), Individual(( @@ -47,7 +47,7 @@ timing: None, biomes: [], site: Some(Dungeon), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -57,7 +57,7 @@ timing: None, biomes: [], site: Some(Cave), - activity: State(Explore), + music_state: Activity(Explore), artist: "Flashbang", )), Individual(( @@ -67,7 +67,7 @@ timing: None, biomes: [], site: Some(Dungeon), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -77,7 +77,7 @@ timing: None, biomes: [], site: Some(Dungeon), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -89,7 +89,7 @@ (Forest, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "DaforLynx", )), Individual(( @@ -101,7 +101,7 @@ (Jungle, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "badbbad", )), Individual(( @@ -113,7 +113,7 @@ (Mountain, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -126,7 +126,7 @@ (Lake, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -139,7 +139,7 @@ (Mountain, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "badbbad", )), Individual(( @@ -151,7 +151,7 @@ (Grassland, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -163,7 +163,7 @@ (Grassland, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Ultimafounding", )), Individual(( @@ -176,7 +176,7 @@ (Ocean, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "DaforLynx", )), Individual(( @@ -188,7 +188,7 @@ (Snowland, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "DaforLynx", )), Individual(( @@ -201,7 +201,7 @@ (Mountain, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Ap1evideogame", )), Individual(( @@ -214,7 +214,7 @@ (Ocean, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Eden", )), Individual(( @@ -227,7 +227,7 @@ (Mountain, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Eden", )), Individual(( @@ -240,7 +240,7 @@ (Jungle, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -253,7 +253,7 @@ (Forest, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -265,7 +265,7 @@ (Grassland, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -277,7 +277,7 @@ (Snowland, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -287,7 +287,7 @@ timing: None, biomes: [], site: Some(Cave), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -299,7 +299,7 @@ (Snowland, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -312,7 +312,7 @@ (Desert, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "Aeronic", )), Individual(( @@ -324,7 +324,7 @@ (Grassland, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "badbbad", )), Individual(( @@ -336,7 +336,7 @@ (Forest, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "badbbad", )), Individual(( @@ -348,7 +348,7 @@ (Mountain, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "badbbad", )), Individual(( @@ -358,7 +358,7 @@ timing: None, biomes: [], site: Some(Dungeon), - activity: State(Explore), + music_state: Activity(Explore), artist: "badbbad", )), Individual(( @@ -370,7 +370,7 @@ (Forest, 1), ], site: Some(Void), - activity: State(Explore), + music_state: Activity(Explore), artist: "badbbad", )), Segmented( @@ -381,10 +381,10 @@ site: Some(Dungeon), segments: [ ("voxygen.audio.soundtrack.barred_paths.barred_paths-hi-end", 6.0, Transition(Combat(High), Explore), None), - ("voxygen.audio.soundtrack.barred_paths.barred_paths-hi-loop", 54.0, State(Combat(High)), None), + ("voxygen.audio.soundtrack.barred_paths.barred_paths-hi-loop", 54.0, Activity(Combat(High)), None), ("voxygen.audio.soundtrack.barred_paths.barred_paths-hi-start", 55.0, Transition(Explore, Combat(High)), Some(Combat(High))), ("voxygen.audio.soundtrack.barred_paths.barred_paths-lo-end", 3.0, Transition(Combat(Low), Explore), None), - ("voxygen.audio.soundtrack.barred_paths.barred_paths-lo-loop", 7.0, State(Combat(Low)), None), + ("voxygen.audio.soundtrack.barred_paths.barred_paths-lo-loop", 7.0, Activity(Combat(Low)), None), ("voxygen.audio.soundtrack.barred_paths.barred_paths-lo-start", 10.0, Transition(Explore, Combat(Low)), None), ("voxygen.audio.soundtrack.barred_paths.barred_paths-trans-hi-lo", 10.0, Transition(Combat(High), Combat(Low)), None), ("voxygen.audio.soundtrack.barred_paths.barred_paths-trans-lo-hi", 7.0, Transition(Combat(Low), Combat(High)), None), diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 69ceeec48d..882d76cfc0 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -9,13 +9,13 @@ pub mod soundcache; use channel::{AmbientChannel, AmbientChannelTag, MusicChannel, MusicChannelTag, SfxChannel}; use fader::Fader; -use music::MUSIC_TRANSITION_MANIFEST; +use music::MusicTransitionManifest; use sfx::{SfxEvent, SfxTriggerItem}; use soundcache::{OggSound, WavSound}; use std::time::Duration; use tracing::{debug, error}; -use common::assets::AssetExt; +use common::assets::{AssetExt, AssetHandle}; use rodio::{source::Source, OutputStream, OutputStreamHandle, StreamError}; use vek::*; @@ -46,6 +46,8 @@ pub struct AudioFrontend { sfx_volume: f32, music_volume: f32, listener: Listener, + + mtm: AssetHandle, } impl AudioFrontend { @@ -91,6 +93,7 @@ impl AudioFrontend { sfx_volume: 1.0, music_volume: 1.0, listener: Listener::default(), + mtm: AssetExt::load_expect("voxygen.audio.music_transition_manifest"), } } @@ -109,6 +112,9 @@ impl AudioFrontend { sfx_volume: 1.0, music_volume: 1.0, listener: Listener::default(), + // This expect should be fine, since `::default_value` + // is specified + mtm: AssetExt::load_expect("voxygen.audio.music_transition_manifest"), } } @@ -153,13 +159,13 @@ 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 mtm = self.mtm.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 _); + let fade_out = Duration::from_secs_f32(*fade_out); + let fade_in = Duration::from_secs_f32(*fade_in); // Fade the existing channel out. It will be removed when the fade completes. existing_channel.set_fader(Fader::fade_out(fade_out, self.music_volume)); diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index 47564d85a4..cedb27e25a 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -51,7 +51,6 @@ use common::{ }; use common_sys::state::State; use hashbrown::HashMap; -use lazy_static::lazy_static; use rand::{prelude::SliceRandom, thread_rng, Rng}; use serde::Deserialize; use std::time::Instant; @@ -85,12 +84,12 @@ pub struct SoundtrackItem { site: Option, /// What the player is doing when the track is played (i.e. exploring, /// combat) - activity: MusicActivity, + music_state: MusicState, /// What activity to override the activity state with, if any (e.g. to make /// a long combat intro also act like the loop for the purposes of outro /// transitions) #[serde(default)] - activity_override: Option, + activity_override: Option, } #[derive(Clone, Debug, Deserialize)] @@ -101,7 +100,7 @@ enum RawSoundtrackItem { timing: Option, biomes: Vec<(BiomeKind, u8)>, site: Option, - segments: Vec<(String, f32, MusicActivity, Option)>, + segments: Vec<(String, f32, MusicState, Option)>, }, } @@ -112,15 +111,15 @@ enum CombatIntensity { } #[derive(Clone, Copy, Debug, Deserialize, PartialEq)] -enum MusicActivityState { +enum MusicActivity { Explore, Combat(CombatIntensity), } #[derive(Clone, Copy, Debug, Deserialize, PartialEq)] -enum MusicActivity { - State(MusicActivityState), - Transition(MusicActivityState, MusicActivityState), +enum MusicState { + Activity(MusicActivity), + Transition(MusicActivity, MusicActivity), } /// Allows control over when a track should play based on in-game time of day @@ -152,8 +151,10 @@ pub struct MusicMgr { /// The title of the last track played. Used to prevent a track /// being played twice in a row last_track: String, + /// Time of the last interrupt (to avoid rapid switching) + last_interrupt: Instant, /// The previous track's activity kind, for transitions - last_activity: MusicActivity, + last_activity: MusicState, } #[derive(Deserialize)] @@ -169,6 +170,8 @@ pub struct MusicTransitionManifest { combat_nearby_low_thresh: u32, /// Fade in and fade out timings for transitions between channels pub fade_timings: HashMap<(MusicChannelTag, MusicChannelTag), (f32, f32)>, + /// How many seconds between interrupt checks + pub interrupt_delay: f32, } impl Default for MusicTransitionManifest { @@ -179,6 +182,7 @@ impl Default for MusicTransitionManifest { combat_nearby_high_thresh: 3, combat_nearby_low_thresh: 1, fade_timings: HashMap::new(), + interrupt_delay: 5.0, } } } @@ -194,11 +198,6 @@ impl assets::Asset for MusicTransitionManifest { } } -lazy_static! { - pub static ref MUSIC_TRANSITION_MANIFEST: AssetHandle = - AssetExt::load_expect("voxygen.audio.music_transition_manifest"); -} - impl Default for MusicMgr { fn default() -> Self { Self { @@ -206,7 +205,8 @@ impl Default for MusicMgr { began_playing: Instant::now(), next_track_change: 0.0, last_track: String::from("None"), - last_activity: MusicActivity::State(MusicActivityState::Explore), + last_interrupt: Instant::now(), + last_activity: MusicState::Activity(MusicActivity::Explore), } } } @@ -227,15 +227,17 @@ impl MusicMgr { use common::comp::{group::ENEMY, Group, Health, Pos}; use specs::{Join, WorldExt}; - use MusicActivityState::*; - let mut activity_state = Explore; + + let mut activity_state = MusicActivity::Explore; + let player = client.entity(); let ecs = state.ecs(); let entities = ecs.entities(); let positions = ecs.read_component::(); let healths = ecs.read_component::(); let groups = ecs.read_component::(); - let mtm = MUSIC_TRANSITION_MANIFEST.read(); + let mtm = audio.mtm.read(); + if let Some(player_pos) = positions.get(player) { // TODO: `group::ENEMY` will eventually be moved server-side with an // alignment/faction rework, so this will need an alternative way to measure @@ -256,38 +258,45 @@ impl MusicMgr { .sum(); if num_nearby_entities >= mtm.combat_nearby_high_thresh { - activity_state = Combat(CombatIntensity::High); + activity_state = MusicActivity::Combat(CombatIntensity::High); } else if num_nearby_entities >= mtm.combat_nearby_low_thresh { - activity_state = Combat(CombatIntensity::Low); + activity_state = MusicActivity::Combat(CombatIntensity::Low); } } // 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; + activity_state = MusicActivity::Explore; } } - let activity = match self.last_activity { - MusicActivity::State(prev) if prev != activity_state => { - MusicActivity::Transition(prev, activity_state) + let music_state = match self.last_activity { + MusicState::Activity(prev) => { + if prev != activity_state { + MusicState::Transition(prev, activity_state) + } else { + MusicState::Activity(activity_state) + } }, - MusicActivity::Transition(_, next) => MusicActivity::State(next), - _ => MusicActivity::State(activity_state), + MusicState::Transition(_, next) => MusicState::Activity(next), }; - let interrupt = matches!(activity, MusicActivity::Transition(_, _)); + let interrupt = matches!(music_state, MusicState::Transition(_, _)) + && self.last_interrupt.elapsed().as_secs_f32() > mtm.interrupt_delay; if audio.music_enabled() && !self.soundtrack.read().tracks.is_empty() && (self.began_playing.elapsed().as_secs_f32() > self.next_track_change || interrupt) { + if interrupt { + self.last_interrupt = Instant::now(); + } debug!( "pre-play_random_track: {:?} {:?}", - self.last_activity, activity + self.last_activity, music_state ); - if let Ok(next_activity) = self.play_random_track(audio, state, client, &activity) { + if let Ok(next_activity) = self.play_random_track(audio, state, client, &music_state) { self.last_activity = next_activity; } } @@ -298,13 +307,13 @@ impl MusicMgr { audio: &mut AudioFrontend, state: &State, client: &Client, - activity: &MusicActivity, - ) -> Result { + music_state: &MusicState, + ) -> Result { let mut rng = thread_rng(); // Adds a bit of randomness between plays let silence_between_tracks_seconds: f32 = - if matches!(activity, MusicActivity::State(MusicActivityState::Explore)) { + if matches!(music_state, MusicState::Activity(MusicActivity::Explore)) { rng.gen_range(60.0..120.0) } else { 0.0 @@ -335,19 +344,9 @@ impl MusicMgr { } }) .filter(|track| { - let mut result = false; - if !track.biomes.is_empty() { - for biome in track.biomes.iter() { - if biome.0 == current_biome { - result = true; - } - } - } else { - result = true; - } - result + track.biomes.is_empty() || track.biomes.iter().any(|b| b.0 == current_biome) }) - .filter(|track| &track.activity == activity) + .filter(|track| &track.music_state == music_state) .collect::>(); if maybe_tracks.is_empty() { return Err(()); @@ -357,7 +356,7 @@ impl MusicMgr { let filtered_tracks: Vec<_> = maybe_tracks .iter() .filter(|track| !track.title.eq(&self.last_track)) - .cloned() + .copied() .collect(); if !filtered_tracks.is_empty() { maybe_tracks = filtered_tracks; @@ -366,24 +365,18 @@ impl MusicMgr { // 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.is_empty() { - for biome in track.biomes.iter() { - if biome.0 == current_biome { - chance = biome.1; - } - } - } 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 + // If no biome is listed, the song is still added to the + // rotation to allow for site specific songs to play + // in any biome + track + .biomes + .iter() + .find(|b| b.0 == current_biome) + .map_or(1, |b| b.1) }); debug!( "selecting new track for {:?}: {:?}", - activity, new_maybe_track + music_state, new_maybe_track ); if let Ok(track) = new_maybe_track { @@ -392,7 +385,7 @@ impl MusicMgr { self.began_playing = Instant::now(); self.next_track_change = track.length + silence_between_tracks_seconds; - let tag = if matches!(activity, MusicActivity::State(MusicActivityState::Explore)) { + let tag = if matches!(music_state, MusicState::Activity(MusicActivity::Explore)) { MusicChannelTag::Exploration } else { MusicChannelTag::Combat @@ -400,9 +393,9 @@ impl MusicMgr { audio.play_music(&track.path, tag); if let Some(state) = track.activity_override { - Ok(MusicActivity::State(state)) + Ok(MusicState::Activity(state)) } else { - Ok(*activity) + Ok(*music_state) } } else { Err(()) @@ -447,7 +440,7 @@ impl assets::Compound for SoundtrackCollection { site, segments, } => { - for (path, length, activity, activity_override) in segments.into_iter() { + for (path, length, music_state, activity_override) in segments.into_iter() { soundtracks.tracks.push(SoundtrackItem { title: title.clone(), path, @@ -455,7 +448,7 @@ impl assets::Compound for SoundtrackCollection { timing: timing.clone(), biomes: biomes.clone(), site, - activity, + music_state, activity_override, }); }