From b2b14e7ab4888622638eadb57f798ef94b275bdb Mon Sep 17 00:00:00 2001 From: DaforLynx Date: Mon, 7 Nov 2022 22:39:25 +0000 Subject: [PATCH] Event music can use more than one event at a time. Added test for soundtracks. --- .../audio/calendar/christmas/soundtrack.ron | 13 ++ assets/voxygen/audio/sfx.ron | 4 +- common/src/calendar.rs | 3 +- voxygen/src/audio/music.rs | 162 ++++++++++++------ 4 files changed, 125 insertions(+), 57 deletions(-) create mode 100644 assets/voxygen/audio/calendar/christmas/soundtrack.ron diff --git a/assets/voxygen/audio/calendar/christmas/soundtrack.ron b/assets/voxygen/audio/calendar/christmas/soundtrack.ron new file mode 100644 index 0000000000..40a03d6f86 --- /dev/null +++ b/assets/voxygen/audio/calendar/christmas/soundtrack.ron @@ -0,0 +1,13 @@ +// Times: Some(Day or Night) or None [both] +// Weathers: Some(Clear, Cloudy, Rain, or Storm) or None [any weather] +// Biomes: Grassland, Forest, Desert, Snowland, Lake, Mountain, Ocean, Jungle, Savannah, Taiga +// planned biomes: Swamp +// Number after biome indicates weighting; higher numbers are less frequent +// Sites: Settlement(Default, Cliff, or Desert), Cave, Dungeon(Old or Gnarling), or Void [none] +// Music states: Activity(Explore or Combat) +// Combat music is looped. Needs three files: start, loop, and end. Start contains leadup to the loop. +// It's recommended to also have appropriate metadata for those who listen via the game files :) + +( + tracks: [] +) \ No newline at end of file diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 70197f4b5f..5a17cd3264 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -142,7 +142,7 @@ "voxygen.audio.sfx.footsteps.stepdirt_4", "voxygen.audio.sfx.footsteps.stepdirt_5", ], - threshold: 1.6, + threshold: 1.8, ), QuadRun(Earth): ( files: [ @@ -152,7 +152,7 @@ "voxygen.audio.sfx.footsteps.stepdirt_4", "voxygen.audio.sfx.footsteps.stepdirt_5", ], - threshold: 0.8, + threshold: 0.9, ), Run(Grass): ( files: [ diff --git a/common/src/calendar.rs b/common/src/calendar.rs index 6d1aa977f3..740af3a648 100644 --- a/common/src/calendar.rs +++ b/common/src/calendar.rs @@ -1,8 +1,9 @@ use chrono::{DateTime, Datelike, Local, TimeZone, Utc}; use chrono_tz::Tz; use serde::{Deserialize, Serialize}; +use strum::EnumIter; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, EnumIter)] #[repr(u16)] pub enum CalendarEvent { Christmas = 0, diff --git a/voxygen/src/audio/music.rs b/voxygen/src/audio/music.rs index b628fdcf71..469c19ed0c 100644 --- a/voxygen/src/audio/music.rs +++ b/voxygen/src/audio/music.rs @@ -56,7 +56,7 @@ use hashbrown::HashMap; use rand::{prelude::SliceRandom, thread_rng, Rng}; use serde::Deserialize; use std::time::Instant; -use tracing::{debug, trace, warn}; +use tracing::{debug, trace}; /// Collection of all the tracks #[derive(Debug, Deserialize)] @@ -151,7 +151,7 @@ enum PlayState { /// Provides methods to control music playback pub struct MusicMgr { /// Collection of all the tracks - soundtrack: AssetHandle>, + soundtrack: SoundtrackCollection, /// Instant at which the current track began playing began_playing: Instant, /// Time until the next track should be played @@ -310,7 +310,7 @@ impl MusicMgr { } if audio.music_enabled() - && !self.soundtrack.read().tracks.is_empty() + && !self.soundtrack.tracks.is_empty() && (self.began_playing.elapsed().as_secs_f32() > self.next_track_change || interrupt) { if interrupt { @@ -378,10 +378,10 @@ 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 soundtrack = self.soundtrack.read(); // First, filter out tracks not matching the timing, site, biome, and current // activity - let mut maybe_tracks = soundtrack + let mut maybe_tracks = self + .soundtrack .tracks .iter() .filter(|track| { @@ -487,24 +487,60 @@ impl MusicMgr { } } - fn load_soundtrack_items( - calendar: &Calendar, - ) -> AssetHandle> { - // Cannot fail: A default value is always provided - let mut soundtrack = SoundtrackCollection::load_expect("voxygen.audio.soundtrack"); + /// Loads default soundtrack if no events are active. Otherwise, attempts to + /// compile and load all active event soundtracks, falling back to default + /// if they are empty. + fn load_soundtrack_items(calendar: &Calendar) -> SoundtrackCollection { + let mut soundtrack = SoundtrackCollection::default(); + // Loads default soundtrack if no events are active if calendar.events().len() == 0 { - soundtrack + for track in SoundtrackCollection::load_expect("voxygen.audio.soundtrack") + .read() + .tracks + .clone() + { + soundtrack.tracks.push(track) + } } else { + // Compiles event-specific soundtracks if any are active for event in calendar.events() { match event { CalendarEvent::Halloween => { - soundtrack = SoundtrackCollection::load_expect( + for track in SoundtrackCollection::load_expect( "voxygen.audio.calendar.halloween.soundtrack", - ); + ) + .read() + .tracks + .clone() + { + soundtrack.tracks.push(track) + } + }, + CalendarEvent::Christmas => { + for track in SoundtrackCollection::load_expect( + "voxygen.audio.calendar.christmas.soundtrack", + ) + .read() + .tracks + .clone() + { + soundtrack.tracks.push(track) + } }, - _ => soundtrack = SoundtrackCollection::load_expect("voxygen.audio.soundtrack"), } } + } + // Fallback if events are active but give an empty tracklist + if soundtrack.tracks.is_empty() { + for track in SoundtrackCollection::load_expect("voxygen.audio.soundtrack") + .read() + .tracks + .clone() + { + soundtrack.tracks.push(track) + } + soundtrack + } else { soundtrack } } @@ -517,47 +553,65 @@ impl assets::Asset for SoundtrackCollection { impl assets::Compound for SoundtrackCollection { fn load(_: assets::AnyCache, id: &str) -> Result { - let inner = || -> Result<_, assets::Error> { - let manifest: AssetHandle> = - AssetExt::load(id)?; - let mut soundtracks = SoundtrackCollection::default(); - for item in manifest.read().tracks.iter().cloned() { - match item { - RawSoundtrackItem::Individual(track) => soundtracks.tracks.push(track), - RawSoundtrackItem::Segmented { - title, - timing, - weather, - biomes, - sites, - segments, - artist, - } => { - for (path, length, music_state, activity_override) in segments.into_iter() { - soundtracks.tracks.push(SoundtrackItem { - title: title.clone(), - path, - length, - timing: timing.clone(), - weather, - biomes: biomes.clone(), - sites: sites.clone(), - music_state, - activity_override, - artist: artist.clone(), - }); - } - }, - } + let manifest: AssetHandle> = AssetExt::load(id)?; + let mut soundtrack = SoundtrackCollection::default(); + for item in manifest.read().tracks.iter().cloned() { + match item { + RawSoundtrackItem::Individual(track) => soundtrack.tracks.push(track), + RawSoundtrackItem::Segmented { + title, + timing, + weather, + biomes, + sites, + segments, + artist, + } => { + for (path, length, music_state, activity_override) in segments.into_iter() { + soundtrack.tracks.push(SoundtrackItem { + title: title.clone(), + path, + length, + timing: timing.clone(), + weather, + biomes: biomes.clone(), + sites: sites.clone(), + music_state, + activity_override, + artist: artist.clone(), + }); + } + }, + } + } + Ok(soundtrack) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use strum::IntoEnumIterator; + + #[test] + fn test_load_soundtracks() { + let _: AssetHandle> = + SoundtrackCollection::load_expect("voxygen.audio.soundtrack"); + for event in CalendarEvent::iter() { + match event { + CalendarEvent::Halloween => { + let _: AssetHandle> = + SoundtrackCollection::load_expect( + "voxygen.audio.calendar.halloween.soundtrack", + ); + }, + CalendarEvent::Christmas => { + let _: AssetHandle> = + SoundtrackCollection::load_expect( + "voxygen.audio.calendar.christmas.soundtrack", + ); + }, } - Ok(soundtracks) - }; - match inner() { - Ok(soundtracks) => Ok(soundtracks), - Err(e) => { - warn!("Error loading soundtracks: {:?}", e); - Ok(SoundtrackCollection::default()) - }, } } }