veloren/voxygen/src/audio/ambient.rs

145 lines
4.6 KiB
Rust
Raw Normal View History

2020-11-14 00:27:09 +00:00
//! Handles ambient non-positional sounds
use crate::{
audio::{channel::AmbientChannelTag, AudioFrontend},
scene::Camera,
};
2020-11-07 01:55:59 +00:00
use client::Client;
2020-12-13 01:09:57 +00:00
use common::{
assets::{self, AssetExt, AssetHandle},
vol::ReadVol,
};
2021-04-06 15:47:03 +00:00
use common_state::State;
2020-11-07 01:55:59 +00:00
use serde::Deserialize;
use std::time::Instant;
use tracing::warn;
2020-11-17 00:38:48 +00:00
use vek::*;
2020-11-07 01:55:59 +00:00
#[derive(Debug, Default, Deserialize)]
2020-11-14 00:27:09 +00:00
struct AmbientCollection {
tracks: Vec<AmbientItem>,
2020-11-07 01:55:59 +00:00
}
/// Configuration for a single music track in the soundtrack
#[derive(Debug, Deserialize)]
2020-11-14 00:27:09 +00:00
pub struct AmbientItem {
2020-11-07 01:55:59 +00:00
path: String,
/// Length of the track in seconds
length: f32,
2020-11-17 00:38:48 +00:00
/// Specifies which ambient channel to play on
2020-11-14 00:27:09 +00:00
tag: AmbientChannelTag,
2020-11-07 01:55:59 +00:00
}
2020-11-14 00:27:09 +00:00
pub struct AmbientMgr {
2020-12-12 22:14:24 +00:00
soundtrack: AssetHandle<AmbientCollection>,
2020-11-07 01:55:59 +00:00
began_playing: Instant,
next_track_change: f32,
2020-11-08 05:26:20 +00:00
volume: f32,
tree_multiplier: f32,
2020-11-07 01:55:59 +00:00
}
2020-11-14 00:27:09 +00:00
impl Default for AmbientMgr {
2020-11-12 03:55:40 +00:00
fn default() -> Self {
2020-11-07 01:55:59 +00:00
Self {
soundtrack: Self::load_soundtrack_items(),
began_playing: Instant::now(),
next_track_change: 0.0,
2020-11-08 05:26:20 +00:00
volume: 0.0,
tree_multiplier: 0.0,
2020-11-07 01:55:59 +00:00
}
}
2020-11-12 03:55:40 +00:00
}
2020-11-07 01:55:59 +00:00
2020-11-14 00:27:09 +00:00
impl AmbientMgr {
2020-11-07 01:55:59 +00:00
/// Checks whether the previous track has completed. If so, sends a
/// request to play the next (random) track
2020-11-07 10:02:29 +00:00
pub fn maintain(
&mut self,
audio: &mut AudioFrontend,
state: &State,
client: &Client,
camera: &Camera,
) {
2020-12-12 22:14:24 +00:00
if audio.sfx_enabled() && !self.soundtrack.read().tracks.is_empty() {
2020-11-12 03:55:40 +00:00
let focus_off = camera.get_focus_pos().map(f32::trunc);
let cam_pos = camera.dependents().cam_pos + focus_off;
2020-11-17 00:38:48 +00:00
let (terrain_alt, tree_density) = if let Some(chunk) = client.current_chunk() {
(chunk.meta().alt(), chunk.meta().tree_density())
} else {
(0.0, 0.0)
};
2020-11-08 05:26:20 +00:00
2020-11-14 00:27:09 +00:00
// The following code is specifically for wind, as it is the only
// non-positional ambient sound in the game. Others can be added
// as seen fit.
let target_volume = {
// Wind volume increases with altitude
let alt_multiplier = (cam_pos.z / 1200.0).abs();
// Tree density factors into wind volume. The more trees,
// the lower wind volume. The trees make more of an impact
// the closer the camera is to the ground.
self.tree_multiplier = ((1.0 - tree_density)
+ ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2))
.min(1.0);
let mut volume_multiplier = alt_multiplier * self.tree_multiplier;
// Checks if the camera is underwater to stop ambient sounds
if state
.terrain()
.get((cam_pos).map(|e| e.floor() as i32))
.map(|b| b.is_liquid())
.unwrap_or(false)
{
volume_multiplier *= 0.1;
}
if cam_pos.z < terrain_alt - 10.0 {
volume_multiplier = 0.0;
}
2020-11-07 01:55:59 +00:00
volume_multiplier.clamped(0.0, 1.0)
};
2020-11-08 05:26:20 +00:00
2020-11-14 00:27:09 +00:00
// Transitions the ambient sounds (more) smoothly
self.volume = audio.get_ambient_volume();
2020-11-17 00:38:48 +00:00
audio.set_ambient_volume(Lerp::lerp(self.volume, target_volume, 0.01));
2020-11-07 01:55:59 +00:00
if self.began_playing.elapsed().as_secs_f32() > self.next_track_change {
2020-11-17 00:38:48 +00:00
// Right now there is only wind non-positional sfx so it is always
// selected. Modify this variable assignment when adding other non-
// positional sfx
2020-12-12 22:14:24 +00:00
let soundtrack = self.soundtrack.read();
let track = &soundtrack
2020-11-14 00:27:09 +00:00
.tracks
.iter()
2020-11-17 00:38:48 +00:00
.find(|track| track.tag == AmbientChannelTag::Wind);
2020-11-14 00:27:09 +00:00
if let Some(track) = track {
self.began_playing = Instant::now();
self.next_track_change = track.length;
2020-11-07 01:55:59 +00:00
audio.play_ambient(AmbientChannelTag::Wind, &track.path, target_volume);
2020-11-14 00:27:09 +00:00
}
2020-11-07 01:55:59 +00:00
}
}
}
2020-12-12 22:14:24 +00:00
fn load_soundtrack_items() -> AssetHandle<AmbientCollection> {
2021-06-25 16:47:03 +00:00
AmbientCollection::load_or_insert_with("voxygen.audio.ambient", |error| {
warn!(
"Error reading ambience config file, ambience will not be available: {:#?}",
error
);
AmbientCollection::default()
})
2020-11-07 01:55:59 +00:00
}
}
2020-12-12 22:14:24 +00:00
impl assets::Asset for AmbientCollection {
type Loader = assets::RonLoader;
2020-12-13 01:09:57 +00:00
const EXTENSION: &'static str = "ron";
}