From 0689630d987bc4818d56969cdcb39ec8471ea208 Mon Sep 17 00:00:00 2001 From: jiminycrick Date: Wed, 21 Oct 2020 15:10:32 -0700 Subject: [PATCH] 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);