2019-08-31 09:06:24 +00:00
|
|
|
pub mod channel;
|
2019-09-05 09:11:18 +00:00
|
|
|
pub mod fader;
|
2019-11-23 08:26:39 +00:00
|
|
|
pub mod sfx;
|
2019-09-01 23:00:12 +00:00
|
|
|
pub mod soundcache;
|
2019-11-23 08:26:39 +00:00
|
|
|
|
2019-08-31 09:06:24 +00:00
|
|
|
use channel::{AudioType, Channel};
|
2019-09-05 09:11:18 +00:00
|
|
|
use fader::Fader;
|
2019-09-01 23:00:12 +00:00
|
|
|
use soundcache::SoundCache;
|
2019-08-31 08:30:23 +00:00
|
|
|
|
2019-08-31 06:37:09 +00:00
|
|
|
use common::assets;
|
2019-10-06 09:18:23 +00:00
|
|
|
use cpal::traits::DeviceTrait;
|
2019-09-06 10:25:17 +00:00
|
|
|
use rodio::{Decoder, Device};
|
2019-09-01 03:18:03 +00:00
|
|
|
use vek::*;
|
2019-08-31 06:37:09 +00:00
|
|
|
|
2019-09-05 09:11:18 +00:00
|
|
|
const FALLOFF: f32 = 0.13;
|
2019-05-11 20:39:46 +00:00
|
|
|
|
|
|
|
pub struct AudioFrontend {
|
2019-08-31 06:37:09 +00:00
|
|
|
pub device: String,
|
|
|
|
pub device_list: Vec<String>,
|
|
|
|
audio_device: Option<Device>,
|
2019-09-01 23:00:12 +00:00
|
|
|
sound_cache: SoundCache,
|
2019-08-31 06:37:09 +00:00
|
|
|
|
|
|
|
channels: Vec<Channel>,
|
|
|
|
next_channel_id: usize,
|
|
|
|
|
|
|
|
sfx_volume: f32,
|
|
|
|
music_volume: f32,
|
2019-09-01 21:40:54 +00:00
|
|
|
|
2019-09-05 09:11:18 +00:00
|
|
|
listener_pos: Vec3<f32>,
|
|
|
|
listener_ori: Vec3<f32>,
|
2019-09-01 21:40:54 +00:00
|
|
|
|
2019-09-06 10:44:15 +00:00
|
|
|
listener_ear_left: Vec3<f32>,
|
|
|
|
listener_ear_right: Vec3<f32>,
|
2019-05-11 20:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AudioFrontend {
|
2019-08-31 06:37:09 +00:00
|
|
|
/// 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));
|
|
|
|
}
|
|
|
|
}
|
2019-08-31 06:37:09 +00:00
|
|
|
Self {
|
|
|
|
device: device.clone(),
|
|
|
|
device_list: list_devices(),
|
2019-09-05 09:03:24 +00:00
|
|
|
audio_device,
|
2019-09-01 23:00:12 +00:00
|
|
|
sound_cache: SoundCache::new(),
|
2019-09-05 09:03:24 +00:00
|
|
|
channels: channels,
|
|
|
|
next_channel_id: 1,
|
2019-08-31 06:37:09 +00:00
|
|
|
sfx_volume: 1.0,
|
|
|
|
music_volume: 1.0,
|
2019-09-01 21:40:54 +00:00
|
|
|
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(),
|
2019-08-31 06:37:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Construct in `no-audio` mode for debugging
|
|
|
|
pub fn no_audio() -> Self {
|
2019-07-02 04:10:55 +00:00
|
|
|
Self {
|
2019-08-31 06:37:09 +00:00
|
|
|
device: "none".to_string(),
|
2019-09-07 09:46:21 +00:00
|
|
|
device_list: Vec::new(),
|
2019-08-31 06:37:09 +00:00
|
|
|
audio_device: None,
|
2019-09-01 23:00:12 +00:00
|
|
|
sound_cache: SoundCache::new(),
|
2019-08-31 06:37:09 +00:00
|
|
|
channels: Vec::new(),
|
2019-09-05 09:03:24 +00:00
|
|
|
next_channel_id: 1,
|
2019-08-31 06:37:09 +00:00
|
|
|
sfx_volume: 1.0,
|
|
|
|
music_volume: 1.0,
|
2019-09-01 21:40:54 +00:00
|
|
|
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(),
|
2019-06-28 17:05:20 +00:00
|
|
|
}
|
2019-05-18 19:28:12 +00:00
|
|
|
}
|
|
|
|
|
2019-08-31 06:37:09 +00:00
|
|
|
/// 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-08-31 06:37:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-10 14:02:51 +00:00
|
|
|
pub fn get_channel(&mut self, audio_type: AudioType) -> Option<&mut Channel> {
|
|
|
|
if let Some(channel) = self.channels.iter_mut().find(|c| c.is_done()) {
|
|
|
|
let id = self.next_channel_id;
|
|
|
|
self.next_channel_id += 1;
|
2019-09-05 09:03:24 +00:00
|
|
|
|
2019-12-10 14:02:51 +00:00
|
|
|
let volume = match audio_type {
|
|
|
|
AudioType::Music => self.music_volume,
|
|
|
|
_ => self.sfx_volume,
|
|
|
|
};
|
2019-08-31 06:37:09 +00:00
|
|
|
|
2019-12-10 14:02:51 +00:00
|
|
|
channel.set_id(id);
|
|
|
|
channel.set_audio_type(audio_type);
|
|
|
|
channel.set_volume(volume);
|
2019-09-08 15:47:52 +00:00
|
|
|
|
2019-12-10 14:02:51 +00:00
|
|
|
Some(channel)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Play specfied sound file.
|
|
|
|
pub fn play_sound(&mut self, sound: &str, pos: Vec3<f32>) -> Option<usize> {
|
|
|
|
if self.audio_device.is_some() {
|
2019-09-06 10:36:42 +00:00
|
|
|
let calc_pos = ((pos - self.listener_pos) * FALLOFF).into_array();
|
2019-08-31 06:37:09 +00:00
|
|
|
|
2019-09-01 23:00:12 +00:00
|
|
|
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
|
|
|
|
2019-12-10 14:02:51 +00:00
|
|
|
if let Some(channel) = self.get_channel(AudioType::Sfx) {
|
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);
|
2019-12-10 14:02:51 +00:00
|
|
|
|
|
|
|
return Some(channel.get_id());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn play_music(&mut self, sound: &str) -> Option<usize> {
|
|
|
|
if self.audio_device.is_some() {
|
|
|
|
if let Some(channel) = self.get_channel(AudioType::Music) {
|
|
|
|
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);
|
|
|
|
|
|
|
|
return Some(channel.get_id());
|
2019-09-05 09:03:24 +00:00
|
|
|
}
|
2019-08-31 21:39:40 +00:00
|
|
|
}
|
|
|
|
|
2019-12-10 14:02:51 +00:00
|
|
|
None
|
2019-08-31 21:39:40 +00:00
|
|
|
}
|
|
|
|
|
2019-09-05 09:11:18 +00:00
|
|
|
pub fn set_listener_pos(&mut self, pos: &Vec3<f32>, ori: &Vec3<f32>) {
|
2019-09-01 21:40:54 +00:00
|
|
|
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-01 03:18:03 +00:00
|
|
|
|
2019-09-06 10:44:15 +00:00
|
|
|
self.listener_ear_left = pos_left;
|
|
|
|
self.listener_ear_right = pos_right;
|
2019-09-01 03:18:03 +00:00
|
|
|
|
|
|
|
for channel in self.channels.iter_mut() {
|
2019-12-10 14:02:51 +00:00
|
|
|
if !channel.is_done() && channel.get_audio_type() == AudioType::Sfx {
|
|
|
|
// TODO: Update this to correctly determine the updated relative position of
|
|
|
|
// the SFX emitter when the player (listener) moves
|
|
|
|
// channel.set_emitter_position(
|
|
|
|
// ((channel.pos - self.listener_pos) * FALLOFF).into_array(),
|
|
|
|
// );
|
2019-09-01 03:18:03 +00:00
|
|
|
channel.set_left_ear_position(pos_left.into_array());
|
|
|
|
channel.set_right_ear_position(pos_right.into_array());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-31 06:37:09 +00:00
|
|
|
pub fn get_sfx_volume(&self) -> f32 {
|
|
|
|
self.sfx_volume
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_music_volume(&self) -> f32 {
|
|
|
|
self.music_volume
|
|
|
|
}
|
|
|
|
|
2019-09-24 16:25:24 +00:00
|
|
|
pub fn set_sfx_volume(&mut self, sfx_volume: f32) {
|
|
|
|
self.sfx_volume = sfx_volume;
|
2019-08-31 06:37:09 +00:00
|
|
|
|
2019-08-31 09:06:24 +00:00
|
|
|
for channel in self.channels.iter_mut() {
|
|
|
|
if channel.get_audio_type() == AudioType::Sfx {
|
2019-09-24 16:25:24 +00:00
|
|
|
channel.set_volume(sfx_volume);
|
2019-08-31 06:37:09 +00:00
|
|
|
}
|
2019-05-20 16:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-31 06:37:09 +00:00
|
|
|
|
2019-09-24 16:25:24 +00:00
|
|
|
pub fn set_music_volume(&mut self, music_volume: f32) {
|
|
|
|
self.music_volume = music_volume;
|
2019-08-31 06:37:09 +00:00
|
|
|
|
2019-08-31 09:06:24 +00:00
|
|
|
for channel in self.channels.iter_mut() {
|
|
|
|
if channel.get_audio_type() == AudioType::Music {
|
2019-09-24 16:25:24 +00:00
|
|
|
channel.set_volume(music_volume);
|
2019-08-31 06:37:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-01 03:18:03 +00:00
|
|
|
// TODO: figure out how badly this will break things when it is called
|
2019-08-31 06:37:09 +00:00
|
|
|
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);
|
2019-08-31 06:37:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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()
|
2019-10-06 09:18:23 +00:00
|
|
|
.expect("Unable to get device name")
|
2019-08-31 06:37:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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> {
|
2019-10-06 09:18:23 +00:00
|
|
|
list_devices_raw()
|
|
|
|
.iter()
|
|
|
|
.map(|x| x.name().expect("Unable to get device name"))
|
|
|
|
.collect()
|
2019-08-31 06:37:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns vec of devices
|
|
|
|
fn list_devices_raw() -> Vec<Device> {
|
2019-10-06 09:18:23 +00:00
|
|
|
rodio::output_devices()
|
|
|
|
.expect("Unable to get output devices")
|
|
|
|
.collect()
|
2019-08-31 06:37:09 +00:00
|
|
|
}
|
|
|
|
|
2019-09-05 09:03:24 +00:00
|
|
|
fn get_device_raw(device: &str) -> Option<Device> {
|
2019-10-06 09:18:23 +00:00
|
|
|
rodio::output_devices()
|
|
|
|
.expect("Unable to get output devices")
|
|
|
|
.find(|d| d.name().expect("Unable to get device name") == device)
|
2019-05-11 20:39:46 +00:00
|
|
|
}
|