mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Broken wind implementation
This commit is contained in:
parent
9b759efe41
commit
695cc7f5cb
BIN
assets/voxygen/audio/ambient/wind.ogg
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/ambient/wind.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
9
assets/voxygen/audio/wind.ron
Normal file
9
assets/voxygen/audio/wind.ron
Normal file
@ -0,0 +1,9 @@
|
||||
(
|
||||
tracks: [
|
||||
(
|
||||
path: "voxygen.audio.ambient.wind",
|
||||
length: 4.5,
|
||||
timing: Some(Day),
|
||||
),
|
||||
]
|
||||
)
|
@ -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> {}
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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
153
voxygen/src/audio/wind.rs
Normal 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()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user