Merge branch 'DaforLynx/thunder-fix' into 'master'

Lightning strikes are less audible; cave music restored; fixed audio permanently stopping on logout

See merge request veloren/veloren!3487
This commit is contained in:
Marcel 2022-07-21 08:27:35 +00:00
commit 7f94580b20
8 changed files with 89 additions and 76 deletions

View File

@ -2,22 +2,22 @@
tracks: [
(
path: "voxygen.audio.ambience.wind",
length: 14.17,
length: 14.2,
tag: Wind,
),
(
path: "voxygen.audio.ambience.rain",
length: 16.97,
length: 17.0,
tag: Rain,
),
(
path:"voxygen.audio.ambience.thunder",
length: 31.97,
length: 32.0,
tag: Thunder,
),
(
path:"voxygen.audio.ambience.leaves",
length: 25.97,
length: 26.0,
tag: Leaves,
),
]

Binary file not shown.

View File

@ -1496,20 +1496,22 @@ impl Client {
if let Some(position) = self.current::<comp::Pos>() {
player_alt = position.0.z;
}
let mut contains_cave = false;
//let mut contains_cave = false;
let mut terrain_alt = 0.0;
let mut contains_dungeon = false;
let mut contains_settlement = false;
if let Some(chunk) = self.current_chunk() {
terrain_alt = chunk.meta().alt();
contains_cave = chunk.meta().contains_cave();
//contains_cave = chunk.meta().contains_cave();
contains_dungeon = chunk.meta().contains_dungeon();
contains_settlement = chunk.meta().contains_settlement();
}
if player_alt < (terrain_alt - 25.0) && contains_cave {
SitesKind::Cave
} else if player_alt < (terrain_alt - 25.0) && contains_dungeon {
SitesKind::Dungeon
if player_alt < terrain_alt - 40.0 {
if contains_dungeon {
SitesKind::Dungeon
} else {
SitesKind::Cave
}
} else if contains_settlement {
SitesKind::Settlement
} else {

View File

@ -89,7 +89,11 @@ impl AmbientMgr {
channel.next_track_change = track.length;
// Play the file of the current tag at the current multiplier;
let current_multiplier = channel.multiplier;
audio.play_ambient(tag, &track.path, current_multiplier * ambience_volume);
audio.play_ambient(
tag,
&track.path,
Some(current_multiplier * ambience_volume),
);
}
};
@ -103,6 +107,15 @@ impl AmbientMgr {
}
impl AmbientChannelTag {
pub fn tag_max_volume(tag: AmbientChannelTag) -> f32 {
match tag {
AmbientChannelTag::Wind => 1.15,
AmbientChannelTag::Rain => 0.95,
AmbientChannelTag::Thunder => 1.33,
AmbientChannelTag::Leaves => 1.33,
}
}
// Gets appropriate volume for each tag
pub fn get_tag_volume(tag: AmbientChannelTag, client: &Client, camera: &Camera) -> f32 {
match tag {
@ -134,11 +147,10 @@ impl AmbientChannelTag {
/ 15.0_f32.powi(2))
.min(1.33);
((alt_multiplier
(alt_multiplier
* tree_multiplier
* (wind_speed_multiplier + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2)))
+ ((alt_multiplier * 0.15) * tree_multiplier))
.min(1.15)
+ (alt_multiplier * 0.15) * tree_multiplier
},
AmbientChannelTag::Rain => {
let focus_off = camera.get_focus_pos().map(f32::trunc);
@ -153,10 +165,10 @@ impl AmbientChannelTag {
let camera_multiplier =
1.0 - ((cam_pos.z - terrain_alt).abs() / 75.0).powi(2).min(1.0);
((client.weather_at_player().rain * 2.5) * camera_multiplier).min(0.95)
(client.weather_at_player().rain * 3.0) * camera_multiplier
},
AmbientChannelTag::Thunder => {
let rain_intensity = (client.weather_at_player().rain * 2.5).min(1.33);
let rain_intensity = client.weather_at_player().rain * 3.0;
if rain_intensity < 0.7 {
0.0
@ -179,8 +191,8 @@ impl AmbientChannelTag {
// the closer the camera is to the ground
let tree_multiplier = 1.0
- (((1.0 - tree_density)
+ ((cam_pos.z - terrain_alt + 20.0).abs() / 150.0).powi(2))
.min(1.0));
+ ((cam_pos.z - terrain_alt - 20.0).abs() / 150.0).powi(2))
.min(1.1));
// Take into account wind speed too, which amplifies tree noise
let wind_speed_multiplier = (client.weather_at_player().wind.magnitude_squared()
@ -188,7 +200,7 @@ impl AmbientChannelTag {
.min(1.0);
if tree_multiplier > 0.1 {
(tree_multiplier * (1.0 + wind_speed_multiplier)).min(1.33)
tree_multiplier * (1.0 + wind_speed_multiplier)
} else {
0.0
}
@ -225,7 +237,8 @@ fn get_target_volume(
}
// Is the camera underneath the terrain? Fade out the lower it goes beneath.
volume_multiplier * ((cam_pos.z - terrain_alt) / 30.0 + 1.0).clamped(0.0, 1.0)
(volume_multiplier * ((cam_pos.z - terrain_alt) / 40.0 + 1.0).clamped(0.0, 1.0))
.min(AmbientChannelTag::tag_max_volume(tag))
}
pub fn load_ambience_items() -> AssetHandle<AmbientCollection> {

View File

@ -282,6 +282,11 @@ impl SfxChannel {
}
}
/// An UiChannel uses a non-spatial audio sink, and is designed for short-lived
/// audio which is not spatially controlled, but does not need control over
/// playback or fading/transitions
///
/// See also: [`Rodio::Sink`](https://docs.rs/rodio/0.11.0/rodio/struct.Sink.html)
pub struct UiChannel {
sink: Sink,
}

View File

@ -21,6 +21,11 @@ use common::assets::{AssetExt, AssetHandle};
use rodio::{source::Source, OutputStream, OutputStreamHandle, StreamError};
use vek::*;
/// Prevents sounds that are too low in volume from playing. This may marginally
/// improve performance in certain situations since less audio channels will be
/// used on average.
const MIN_HEARABLE_VOLUME: f32 = 0.003;
#[derive(Default, Clone)]
pub struct Listener {
pos: Vec3<f32>,
@ -216,20 +221,14 @@ impl AudioFrontend {
self.music_channels.last_mut()
}
/// 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<f32>,
volume: Option<f32>,
underwater: bool,
) {
if let Some((event, item)) = trigger_item {
// Find sound based on given trigger_item
// Randomizes if multiple sounds are found
// Errors if no sounds are found
let sfx_file = match item.files.len() {
/// Find sound based on given trigger_item
/// Randomizes if multiple sounds are found
/// Errors if no sounds are found
fn get_sfx_file<'a>(
trigger_item: Option<(&'a SfxEvent, &'a SfxTriggerItem)>,
) -> Option<&'a str> {
trigger_item.map(|(event, item)| {
match item.files.len() {
0 => {
debug!("Sfx event {:?} is missing audio file.", event);
"voxygen.audio.sfx.placeholder"
@ -243,9 +242,22 @@ impl AudioFrontend {
let rand_step = rand::random::<usize>() % item.files.len();
&item.files[rand_step]
},
};
}
})
}
/// 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<f32>,
volume: Option<f32>,
underwater: bool,
) {
if let Some(sfx_file) = Self::get_sfx_file(trigger_item) {
// Play sound in empty channel at given position
if self.audio_stream.is_some() {
if self.audio_stream.is_some() && volume.map_or(true, |v| v > MIN_HEARABLE_VOLUME) {
let sound = load_ogg(sfx_file).amplify(volume.unwrap_or(1.0));
let listener = self.listener.clone();
@ -275,27 +287,9 @@ impl AudioFrontend {
trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>,
volume: Option<f32>,
) {
// Find sound based on given trigger_item
// Randomizes if multiple sounds are found
// Errors if no sounds are found
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::<usize>() % item.files.len();
&item.files[rand_step]
},
};
if let Some(sfx_file) = Self::get_sfx_file(trigger_item) {
// Play sound in empty channel
if self.audio_stream.is_some() {
if self.audio_stream.is_some() && volume.map_or(true, |v| v > MIN_HEARABLE_VOLUME) {
let sound = load_ogg(sfx_file).amplify(volume.unwrap_or(1.0));
if let Some(channel) = self.get_ui_channel() {
@ -308,10 +302,10 @@ impl AudioFrontend {
}
/// Plays a file at a given volume in the channel with a given tag
fn play_ambient(&mut self, channel_tag: AmbientChannelTag, sound: &str, volume: f32) {
fn play_ambient(&mut self, channel_tag: AmbientChannelTag, sound: &str, volume: Option<f32>) {
if self.audio_stream.is_some() {
if let Some(channel) = self.get_ambient_channel(channel_tag) {
channel.set_volume(volume);
channel.set_volume(volume.unwrap_or(1.0));
channel.play(load_ogg(sound));
}
}
@ -503,19 +497,18 @@ impl AudioFrontend {
}
}
pub fn stop_ambient_sounds(&mut self) {
for channel in self.ambient_channels.iter_mut() {
channel.stop()
}
}
pub fn stop_all_ambience(&mut self) { self.ambient_channels.retain(|x| Some(x).is_none()) }
// Sfx channels do not repopulate themselves yet
pub fn stop_all_sfx(&mut self) {
for channel in self.sfx_channels.iter_mut() {
channel.stop()
}
for channel in self.ui_channels.iter_mut() {
channel.stop()
}
if let Some(audio_stream) = &self.audio_stream {
for channel in &mut self.sfx_channels {
*channel = SfxChannel::new(audio_stream);
}
for channel in &mut self.ui_channels {
*channel = UiChannel::new(audio_stream);
}
};
}
// The following is for the disabled device switcher

View File

@ -435,13 +435,13 @@ impl SfxMgr {
);
},
Outcome::Lightning { pos } => {
let power = (1.0 - pos.distance(audio.listener.pos) / 6_000.0)
.clamped(0.0, 1.0)
.powf(0.75);
let power = (1.0 - pos.distance(audio.listener.pos) / 5_000.0)
.max(0.0)
.powi(7);
if power > 0.0 {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Lightning);
// TODO: Don't use UI sfx, add a way to control position falloff
audio.emit_ui_sfx(sfx_trigger_item, Some(power * 3.0));
audio.emit_ui_sfx(sfx_trigger_item, Some((power * 3.0).min(2.9)));
}
},
Outcome::GroundSlam { pos, .. } => {

View File

@ -1206,7 +1206,7 @@ impl PlayState for SessionState {
// Stop all sounds
// TODO: Abstract this behavior to all instances of PlayStateResult::Pop
// somehow
global_state.audio.stop_ambient_sounds();
global_state.audio.stop_all_ambience();
global_state.audio.stop_all_sfx();
return PlayStateResult::Pop;
},