veloren/voxygen/src/audio/mod.rs

251 lines
7.3 KiB
Rust
Raw Normal View History

2019-08-31 09:06:24 +00:00
pub mod channel;
2019-09-05 09:11:18 +00:00
pub mod fader;
pub mod soundcache;
2019-08-31 09:06:24 +00:00
use channel::{AudioType, Channel};
2019-09-05 09:11:18 +00:00
use fader::Fader;
use soundcache::SoundCache;
2019-08-31 08:30:23 +00:00
use common::assets;
2019-09-06 10:25:17 +00:00
use rodio::{Decoder, Device};
use vek::*;
2019-09-05 09:11:18 +00:00
const FALLOFF: f32 = 0.13;
pub struct AudioFrontend {
pub device: String,
pub device_list: Vec<String>,
audio_device: Option<Device>,
sound_cache: SoundCache,
channels: Vec<Channel>,
next_channel_id: usize,
sfx_volume: f32,
music_volume: f32,
2019-09-05 09:11:18 +00:00
listener_pos: Vec3<f32>,
listener_ori: Vec3<f32>,
2019-09-06 10:44:15 +00:00
listener_ear_left: Vec3<f32>,
listener_ear_right: Vec3<f32>,
}
impl AudioFrontend {
/// Construct with given device
2019-09-05 09:03:24 +00:00
pub fn new(device: String, channel_num: usize) -> Self {
let mut channels = Vec::with_capacity(channel_num);
let audio_device = get_device_raw(&device);
if let Some(audio_device) = &audio_device {
2019-09-06 10:25:17 +00:00
for _i in 0..channel_num {
2019-09-05 09:03:24 +00:00
channels.push(Channel::new(&audio_device));
}
}
Self {
device: device.clone(),
device_list: list_devices(),
2019-09-05 09:03:24 +00:00
audio_device,
sound_cache: SoundCache::new(),
2019-09-05 09:03:24 +00:00
channels: channels,
next_channel_id: 1,
sfx_volume: 1.0,
music_volume: 1.0,
listener_pos: Vec3::zero(),
listener_ori: Vec3::zero(),
2019-09-06 10:44:15 +00:00
listener_ear_left: Vec3::zero(),
listener_ear_right: Vec3::zero(),
}
}
/// Construct in `no-audio` mode for debugging
pub fn no_audio() -> Self {
Self {
device: "none".to_string(),
2019-09-07 09:46:21 +00:00
device_list: Vec::new(),
audio_device: None,
sound_cache: SoundCache::new(),
channels: Vec::new(),
2019-09-05 09:03:24 +00:00
next_channel_id: 1,
sfx_volume: 1.0,
music_volume: 1.0,
listener_pos: Vec3::zero(),
listener_ori: Vec3::zero(),
2019-09-06 10:44:15 +00:00
listener_ear_left: Vec3::zero(),
listener_ear_right: Vec3::zero(),
}
}
/// Maintain audio
2019-08-31 08:30:23 +00:00
pub fn maintain(&mut self, dt: f32) {
2019-09-06 10:25:17 +00:00
for channel in self.channels.iter_mut() {
2019-08-31 08:30:23 +00:00
channel.update(dt);
}
}
2019-09-05 09:03:24 +00:00
pub fn get_channel(&mut self) -> Option<&mut Channel> {
self.channels.iter_mut().find(|c| c.is_done())
}
/// Play specfied sound file.
///```ignore
///audio.play_sound("voxygen.audio.sfx.step");
///```
2019-09-06 10:36:42 +00:00
pub fn play_sound(&mut self, sound: &str, pos: Vec3<f32>) -> usize {
let id = self.next_channel_id;
self.next_channel_id += 1;
let sfx_volume = self.sfx_volume;
2019-09-08 15:47:52 +00:00
2019-09-06 10:25:17 +00:00
if let Some(_) = &self.audio_device {
2019-09-06 10:36:42 +00:00
let calc_pos = ((pos - self.listener_pos) * FALLOFF).into_array();
let sound = self.sound_cache.load_sound(sound);
2019-08-31 21:39:40 +00:00
2019-09-06 10:44:15 +00:00
let left_ear = self.listener_ear_left.into_array();
let right_ear = self.listener_ear_right.into_array();
2019-09-05 09:03:24 +00:00
if let Some(channel) = self.get_channel() {
channel.set_id(id);
channel.set_volume(sfx_volume);
2019-09-05 09:03:24 +00:00
channel.set_emitter_position(calc_pos);
channel.set_left_ear_position(left_ear);
channel.set_right_ear_position(right_ear);
channel.play(sound);
} else {
2019-09-06 10:36:42 +00:00
log::warn!("No available channels!");
2019-09-05 09:03:24 +00:00
}
2019-08-31 21:39:40 +00:00
}
id
}
2019-09-05 09:11:18 +00:00
pub fn set_listener_pos(&mut self, pos: &Vec3<f32>, ori: &Vec3<f32>) {
self.listener_pos = pos.clone();
self.listener_ori = ori.normalized();
let up = Vec3::new(0.0, 0.0, 1.0);
let pos_left = up.cross(self.listener_ori.clone()).normalized();
let pos_right = self.listener_ori.cross(up.clone()).normalized();
2019-09-06 10:44:15 +00:00
self.listener_ear_left = pos_left;
self.listener_ear_right = pos_right;
for channel in self.channels.iter_mut() {
if channel.get_audio_type() == AudioType::Sfx {
2019-09-06 10:36:42 +00:00
channel.set_emitter_position(
((channel.pos - self.listener_pos) * FALLOFF).into_array(),
);
channel.set_left_ear_position(pos_left.into_array());
channel.set_right_ear_position(pos_right.into_array());
}
}
}
2019-09-06 10:36:42 +00:00
pub fn play_music(&mut self, sound: &str) -> usize {
2019-08-31 21:39:40 +00:00
let id = self.next_channel_id;
self.next_channel_id += 1;
let music_volume = self.music_volume;
2019-09-06 10:25:17 +00:00
if let Some(_) = &self.audio_device {
2019-08-31 21:39:40 +00:00
let file = assets::load_file(&sound, &["ogg"]).unwrap();
2019-09-05 09:03:24 +00:00
let sound = Decoder::new(file).unwrap();
2019-09-05 09:03:24 +00:00
if let Some(channel) = self.get_channel() {
channel.set_id(id);
channel.set_volume(music_volume);
2019-09-05 09:03:24 +00:00
channel.play(sound);
}
} else {
log::warn!("No available channels!");
}
id
}
2019-08-31 08:30:23 +00:00
pub fn stop_channel(&mut self, channel_id: usize, fader: Fader) {
2019-08-31 09:06:24 +00:00
let index = self.channels.iter().position(|c| c.get_id() == channel_id);
2019-08-31 08:30:23 +00:00
if let Some(index) = index {
self.channels[index].stop(fader);
}
}
pub fn get_sfx_volume(&self) -> f32 {
self.sfx_volume
}
pub fn get_music_volume(&self) -> f32 {
self.music_volume
}
pub fn set_sfx_volume(&mut self, sfx_volume: f32) {
self.sfx_volume = sfx_volume;
2019-08-31 09:06:24 +00:00
for channel in self.channels.iter_mut() {
if channel.get_audio_type() == AudioType::Sfx {
channel.set_volume(sfx_volume);
}
}
}
pub fn set_music_volume(&mut self, music_volume: f32) {
self.music_volume = music_volume;
2019-08-31 09:06:24 +00:00
for channel in self.channels.iter_mut() {
if channel.get_audio_type() == AudioType::Music {
channel.set_volume(music_volume);
}
}
}
// TODO: figure out how badly this will break things when it is called
pub fn set_device(&mut self, name: String) {
self.device = name.clone();
2019-09-05 09:03:24 +00:00
self.audio_device = get_device_raw(&name);
}
}
pub fn select_random_music() -> String {
let soundtracks = load_soundtracks();
let index = rand::random::<usize>() % soundtracks.len();
soundtracks[index].clone()
}
/// Returns the default audio device.
/// Does not return rodio Device struct in case our audio backend changes.
pub fn get_default_device() -> String {
rodio::default_output_device()
.expect("No audio output devices detected.")
.name()
}
/// Load the audio file directory selected by genre.
pub fn load_soundtracks() -> Vec<String> {
let assets = assets::read_dir("voxygen.audio.soundtrack.regional").unwrap();
let soundtracks = assets
.filter_map(|entry| {
entry.ok().map(|f| {
let path = f.path();
path.to_string_lossy().into_owned()
})
})
.collect::<Vec<String>>();
soundtracks
}
/// Returns a vec of the audio devices available.
/// Does not return rodio Device struct in case our audio backend changes.
pub fn list_devices() -> Vec<String> {
list_devices_raw().iter().map(|x| x.name()).collect()
}
/// Returns vec of devices
fn list_devices_raw() -> Vec<Device> {
rodio::output_devices().collect()
}
2019-09-05 09:03:24 +00:00
fn get_device_raw(device: &str) -> Option<Device> {
rodio::output_devices().find(|d| d.name() == device)
}