Broken wind implementation

This commit is contained in:
jiminycrick 2020-11-06 17:55:59 -08:00
parent 9b759efe41
commit 695cc7f5cb
8 changed files with 242 additions and 18 deletions

BIN
assets/voxygen/audio/ambient/wind.ogg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,9 @@
(
tracks: [
(
path: "voxygen.audio.ambient.wind",
length: 4.5,
timing: Some(Day),
),
]
)

View File

@ -11,8 +11,6 @@ pub struct Id<T>(u64, PhantomData<T>);
impl<T> Id<T> {
pub fn id(&self) -> u64 { self.0 }
pub fn phantomdata(&self) -> PhantomData<T> { self.1 }
}
impl<T> Copy for Id<T> {}

View File

@ -140,6 +140,30 @@ impl MusicChannel {
}
}
pub struct WindChannel {
sink: Sink,
}
impl WindChannel {
pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume); }
pub fn new(stream: &OutputStreamHandle) -> Self {
Self {
sink: Sink::try_new(stream).unwrap(),
}
}
pub fn play<S>(&mut self, source: S)
where
S: Source + Send + 'static,
S::Item: Sample,
S::Item: Send,
<S as std::iter::Iterator>::Item: std::fmt::Debug,
{
self.sink.append(source);
}
}
/// An SfxChannel uses a positional audio sink, and is designed for short-lived
/// audio which can be spatially controlled, but does not need control over
/// playback or fading/transitions

View File

@ -5,8 +5,9 @@ pub mod fader;
pub mod music;
pub mod sfx;
pub mod soundcache;
pub mod wind;
use channel::{MusicChannel, MusicChannelTag, SfxChannel};
use channel::{MusicChannel, MusicChannelTag, SfxChannel, WindChannel};
use fader::Fader;
use soundcache::SoundCache;
use std::time::Duration;
@ -39,6 +40,7 @@ pub struct AudioFrontend {
sound_cache: SoundCache,
music_channels: Vec<MusicChannel>,
wind_channels: Vec<WindChannel>,
sfx_channels: Vec<SfxChannel>,
sfx_volume: f32,
music_volume: f32,
@ -76,8 +78,10 @@ impl AudioFrontend {
//};
let mut sfx_channels = Vec::with_capacity(max_sfx_channels);
let mut wind_channels = Vec::new();
if let Some(audio_stream) = &audio_stream {
sfx_channels.resize_with(max_sfx_channels, || SfxChannel::new(audio_stream));
wind_channels.push(WindChannel::new(audio_stream));
};
Self {
@ -89,6 +93,7 @@ impl AudioFrontend {
sound_cache: SoundCache::default(),
music_channels: Vec::new(),
sfx_channels,
wind_channels,
sfx_volume: 1.0,
music_volume: 1.0,
listener: Listener::default(),
@ -106,6 +111,7 @@ impl AudioFrontend {
sound_cache: SoundCache::default(),
music_channels: Vec::new(),
sfx_channels: Vec::new(),
wind_channels: Vec::new(),
sfx_volume: 1.0,
music_volume: 1.0,
listener: Listener::default(),
@ -186,6 +192,37 @@ impl AudioFrontend {
}
}
fn play_wind(&mut self, sound: &str, volume_multiplier: f32) {
if self.audio_stream.is_some() {
if let Some(channel) = self.get_wind_channel(volume_multiplier) {
let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound");
let sound = Decoder::new(file).expect("Failed to decode sound");
channel.play(sound);
}
}
}
fn get_wind_channel(&mut self, volume_multiplier: f32) -> Option<&mut WindChannel> {
if self.audio_stream.is_some() {
if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) {
channel.set_volume(self.sfx_volume * volume_multiplier);
return Some(channel);
}
}
None
}
fn set_wind_volume(&mut self, volume_multiplier: f32) {
if self.audio_stream.is_some() {
if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) {
channel.set_volume(self.sfx_volume * volume_multiplier);
}
}
}
fn play_music(&mut self, sound: &str, channel_tag: MusicChannelTag) {
if let Some(channel) = self.get_music_channel(channel_tag) {
let file = assets::load_file(&sound, &["ogg"]).expect("Failed to load sound");

View File

@ -113,17 +113,17 @@ impl MusicMgr {
/// 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 let Some(current_chunk) = client.current_chunk() {
println!("biome: {:?}", current_chunk.meta().biome());
println!("chaos: {}", current_chunk.meta().chaos());
println!("alt: {}", current_chunk.meta().alt());
println!("temp: {}", current_chunk.meta().temp());
println!("tree_density: {}", current_chunk.meta().tree_density());
println!("humidity: {}", current_chunk.meta().humidity());
println!("cave_alt: {}", current_chunk.meta().cave_alt());
//if let Some(position) = client.current_position() {
// println!("player_pos: {:?}", position);
}
//if let Some(current_chunk) = client.current_chunk() {
//println!("biome: {:?}", current_chunk.meta().biome());
//println!("chaos: {}", current_chunk.meta().chaos());
//println!("alt: {}", current_chunk.meta().alt());
//println!("temp: {}", current_chunk.meta().temp());
//println!("tree_density: {}", current_chunk.meta().tree_density());
//println!("humidity: {}", current_chunk.meta().humidity());
//println!("cave_alt: {}", current_chunk.meta().cave_alt());
//if let Some(position) = client.current_position() {
// println!("player_pos: {:?}", position);
//}
//let player_position = match client.current_position() {
// Some(pos) => pos,
// None => Vec3::default(),

153
voxygen/src/audio/wind.rs Normal file
View File

@ -0,0 +1,153 @@
//! Handles ambient wind sounds
use crate::audio::AudioFrontend;
use client::Client;
use common::{
assets,
state::State,
terrain::{BiomeKind, SitesKind},
};
use rand::{prelude::SliceRandom, thread_rng, Rng};
use serde::Deserialize;
use std::time::Instant;
use tracing::warn;
const DAY_START_SECONDS: u32 = 28800; // 8:00
const DAY_END_SECONDS: u32 = 70200; // 19:30
#[derive(Debug, Default, Deserialize)]
struct WindCollection {
tracks: Vec<WindItem>,
}
/// Configuration for a single music track in the soundtrack
#[derive(Debug, Deserialize)]
pub struct WindItem {
path: String,
/// Length of the track in seconds
length: f32,
/// Whether this track should play during day or night
timing: Option<DayPeriod>,
}
/// Allows control over when a track should play based on in-game time of day
#[derive(Debug, Deserialize, PartialEq)]
enum DayPeriod {
/// 8:00 AM to 7:30 PM
Day,
/// 7:31 PM to 6:59 AM
Night,
}
/// Determines whether the sound is stopped, playing, or fading
#[derive(Debug, Deserialize, PartialEq)]
enum PlayState {
Playing,
Stopped,
FadingOut,
FadingIn,
}
pub struct WindMgr {
soundtrack: WindCollection,
began_playing: Instant,
next_track_change: f32,
}
impl WindMgr {
#[allow(clippy::new_without_default)] // TODO: Pending review in #587
pub fn new() -> Self {
Self {
soundtrack: Self::load_soundtrack_items(),
began_playing: Instant::now(),
next_track_change: 0.0,
}
}
/// 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.sfx_enabled() && !self.soundtrack.tracks.is_empty() {
let alt_multiplier = ((Self::get_current_alt(client) - 250.0) / 1500.0).min(0.0);
let tree_multiplier = 1.0 - Self::get_current_tree_density(client);
let volume_multiplier = alt_multiplier * tree_multiplier;
audio.set_wind_volume(volume_multiplier);
if self.began_playing.elapsed().as_secs_f32() > self.next_track_change {
println!("Got to wind maintain");
//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 track = &self.soundtrack.tracks[0];
self.began_playing = Instant::now();
self.next_track_change = track.length;
//let alt_multiplier = (Self::get_current_alt(client)
// - Self::get_current_terrain_alt(client))
// / 1500.0;
//let tree_multiplier = 1.0 - Self::get_current_tree_density(client);
//let volume_multiplier = alt_multiplier * tree_multiplier;
audio.play_wind(&track.path, volume_multiplier);
}
}
}
fn get_current_day_period(game_time: u32) -> DayPeriod {
if game_time > DAY_START_SECONDS && game_time < DAY_END_SECONDS {
DayPeriod::Day
} else {
DayPeriod::Night
}
}
fn get_current_alt(client: &Client) -> f32 {
match client.current_position() {
Some(pos) => pos.z,
None => 0.0,
}
}
fn get_current_terrain_alt(client: &Client) -> f32 {
if let Some(chunk) = client.current_chunk() {
chunk.meta().alt()
} else {
0.0
}
}
fn get_current_tree_density(client: &Client) -> f32 {
match client.current_chunk() {
Some(current_chunk) => current_chunk.meta().tree_density(),
None => 0.0,
}
}
fn load_soundtrack_items() -> WindCollection {
match assets::load_file("voxygen.audio.wind", &["ron"]) {
Ok(file) => match ron::de::from_reader(file) {
Ok(config) => config,
Err(error) => {
warn!(
"Error parsing music config file, music will not be available: {}",
format!("{:#?}", error)
);
WindCollection::default()
},
},
Err(error) => {
warn!(
"Error reading music config file, music will not be available: {}",
format!("{:#?}", error)
);
WindCollection::default()
},
}
}
}

View File

@ -14,7 +14,7 @@ pub use self::{
terrain::Terrain,
};
use crate::{
audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend},
audio::{music::MusicMgr, sfx::SfxMgr, wind::WindMgr, AudioFrontend},
render::{
create_clouds_mesh, create_pp_mesh, create_skybox_mesh, CloudsLocals, CloudsPipeline,
Consts, GlobalModel, Globals, Light, LodData, Model, PostProcessLocals,
@ -103,7 +103,7 @@ pub struct Scene {
figure_mgr: FigureMgr,
sfx_mgr: SfxMgr,
music_mgr: MusicMgr,
//ambient_mgr: AmbientMgr,
ambient_mgr: WindMgr,
}
pub struct SceneData<'a> {
@ -309,7 +309,7 @@ impl Scene {
figure_mgr: FigureMgr::new(renderer),
sfx_mgr: SfxMgr::new(),
music_mgr: MusicMgr::new(),
//ambient_mgr: AmbientMgr::new(),
ambient_mgr: WindMgr::new(),
}
}
@ -999,7 +999,7 @@ impl Scene {
&self.terrain,
);
self.music_mgr.maintain(audio, scene_data.state, client);
//self.ambient_mgr.maintain(audio, scene_data.state, client);
self.ambient_mgr.maintain(audio, scene_data.state, client);
}
/// Render the scene using the provided `Renderer`.