Initial commit
This commit is contained in:
commit
3543552767
6 changed files with 703 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"workbench.colorCustomizations": {
|
||||||
|
"activityBar.background": "#56084C",
|
||||||
|
"titleBar.activeBackground": "#780B6B",
|
||||||
|
"titleBar.activeForeground": "#FFFBFE"
|
||||||
|
}
|
||||||
|
}
|
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "audio"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rg3d-sound = "0.26.0"
|
||||||
|
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||||
|
utilities = { git = "https://gavania.de/hodasemi/utilities.git" }
|
||||||
|
assetpath = { git = "https://gavania.de/hodasemi/vulkan_lib.git" }
|
5
src/lib.rs
Normal file
5
src/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mod shared;
|
||||||
|
mod sound;
|
||||||
|
|
||||||
|
pub use shared::*;
|
||||||
|
pub use sound::*;
|
165
src/shared.rs
Normal file
165
src/shared.rs
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use utilities::prelude::*;
|
||||||
|
|
||||||
|
use super::{Music, Sound};
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum SoundInterpretation {
|
||||||
|
Generic,
|
||||||
|
Spatial,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
// pub(crate) struct VolumeHandler {
|
||||||
|
pub struct VolumeHandler {
|
||||||
|
sound_volumes: HashMap<String, f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VolumeHandler {
|
||||||
|
pub(crate) fn new(volume_info: HashMap<String, f32>) -> Self {
|
||||||
|
VolumeHandler {
|
||||||
|
sound_volumes: volume_info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_volume(
|
||||||
|
&mut self,
|
||||||
|
sound_type: &str,
|
||||||
|
volume: f32,
|
||||||
|
audio_objects: &mut AudioObjects,
|
||||||
|
) -> Result<()> {
|
||||||
|
// check map if sound type is already present
|
||||||
|
let changed = match self.sound_volumes.get_mut(sound_type) {
|
||||||
|
Some(stype) => {
|
||||||
|
// set volume
|
||||||
|
if *stype != volume {
|
||||||
|
*stype = volume;
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// insert volume for requested sound type
|
||||||
|
self.sound_volumes.insert(sound_type.to_string(), volume);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if changed {
|
||||||
|
if sound_type == "music" {
|
||||||
|
audio_objects.apply_to_music(|music| music.set_volume(volume))?;
|
||||||
|
} else {
|
||||||
|
audio_objects.apply_to_sound(Some(sound_type), |sound| sound.set_volume(volume))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn volume(&self, sound_type: &str) -> f32 {
|
||||||
|
self.sound_volumes[sound_type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ClearQueueAudioObject: Send + Sync {
|
||||||
|
fn end_looping(&self) -> Result<()>;
|
||||||
|
fn is_playing(&self) -> Result<bool>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct AudioObjects {
|
||||||
|
// sound handling
|
||||||
|
sounds: HashMap<String, Vec<Arc<Sound>>>,
|
||||||
|
|
||||||
|
// music handling
|
||||||
|
music: Vec<Arc<Music>>,
|
||||||
|
|
||||||
|
clear_queue: Vec<Arc<dyn ClearQueueAudioObject>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AudioObjects {
|
||||||
|
pub fn add_sound(&mut self, sound: Arc<Sound>) {
|
||||||
|
match self.sounds.get_mut(sound.sound_type()) {
|
||||||
|
Some(sounds) => sounds.push(sound),
|
||||||
|
None => {
|
||||||
|
self.sounds
|
||||||
|
.insert(sound.sound_type().to_string(), vec![sound]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_music(&mut self, music: Arc<Music>) {
|
||||||
|
self.music.push(music);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_to_sound<F>(&self, sound_type: Option<&str>, f: F) -> Result<()>
|
||||||
|
where
|
||||||
|
F: Fn(&Arc<Sound>) -> Result<()>,
|
||||||
|
{
|
||||||
|
match sound_type {
|
||||||
|
Some(sound_type) => {
|
||||||
|
if let Some(sounds) = self.sounds.get(sound_type) {
|
||||||
|
for sound in sounds.iter() {
|
||||||
|
f(sound)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
for sounds in self.sounds.values() {
|
||||||
|
for sound in sounds.iter() {
|
||||||
|
f(sound)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_to_music<F>(&self, f: F) -> Result<()>
|
||||||
|
where
|
||||||
|
F: Fn(&Arc<Music>) -> Result<()>,
|
||||||
|
{
|
||||||
|
for music in self.music.iter() {
|
||||||
|
f(music)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.sounds.clear();
|
||||||
|
self.music.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_sound(&mut self, sound: &Arc<Sound>) -> Result<()> {
|
||||||
|
if let Some(sounds) = self.sounds.get_mut(sound.sound_type()) {
|
||||||
|
if let Some(old_sound) = erase_arc(sounds, sound) {
|
||||||
|
old_sound.end_looping()?;
|
||||||
|
self.clear_queue.push(old_sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_clear_queue(&mut self) -> Result<()> {
|
||||||
|
let mut new_queue = Vec::new();
|
||||||
|
|
||||||
|
for sound in self.clear_queue.iter() {
|
||||||
|
if sound.is_playing()? {
|
||||||
|
new_queue.push(sound.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.clear_queue = new_queue;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
512
src/sound.rs
Normal file
512
src/sound.rs
Normal file
|
@ -0,0 +1,512 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use super::{AudioObjects, ClearQueueAudioObject, SoundInterpretation, VolumeHandler};
|
||||||
|
|
||||||
|
use rg3d_sound::{
|
||||||
|
algebra::Vector3,
|
||||||
|
buffer::{DataSource, SoundBufferResource},
|
||||||
|
context::SoundContext,
|
||||||
|
engine::SoundEngine,
|
||||||
|
futures::executor::block_on,
|
||||||
|
pool::Handle,
|
||||||
|
source::{
|
||||||
|
generic::{GenericSource, GenericSourceBuilder},
|
||||||
|
spatial::{SpatialSource, SpatialSourceBuilder},
|
||||||
|
SoundSource, Status,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use assetpath::AssetPath;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn act_on_generic_source<T, F>(
|
||||||
|
ctx: &SoundContext,
|
||||||
|
handle: Handle<SoundSource>,
|
||||||
|
interpretation: SoundInterpretation,
|
||||||
|
f: F,
|
||||||
|
) -> Result<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut GenericSource) -> Result<T>,
|
||||||
|
{
|
||||||
|
let mut state = ctx.state();
|
||||||
|
let source = state.source_mut(handle);
|
||||||
|
|
||||||
|
let generic_source = match interpretation {
|
||||||
|
SoundInterpretation::Generic => match source {
|
||||||
|
SoundSource::Generic(generic_source) => generic_source,
|
||||||
|
SoundSource::Spatial(_) => {
|
||||||
|
return Err(anyhow::Error::msg(
|
||||||
|
"Audio Error: called generic on spatial source",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SoundInterpretation::Spatial => match source {
|
||||||
|
SoundSource::Spatial(spatial_source) => spatial_source.generic_mut(),
|
||||||
|
SoundSource::Generic(_) => {
|
||||||
|
return Err(anyhow::Error::msg(
|
||||||
|
"Audio Error: called spatial on generic source",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(f(generic_source)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn act_on_spatial_source<T, F>(
|
||||||
|
ctx: &SoundContext,
|
||||||
|
handle: Handle<SoundSource>,
|
||||||
|
interpretation: SoundInterpretation,
|
||||||
|
f: F,
|
||||||
|
) -> Result<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut SpatialSource) -> Result<T>,
|
||||||
|
{
|
||||||
|
let mut state = ctx.state();
|
||||||
|
let source = state.source_mut(handle);
|
||||||
|
|
||||||
|
let spatial_source = match interpretation {
|
||||||
|
SoundInterpretation::Generic => match source {
|
||||||
|
SoundSource::Generic(_) => {
|
||||||
|
return Err(anyhow::Error::msg(
|
||||||
|
"Audio Error: requested spatial source on generic",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SoundSource::Spatial(_) => {
|
||||||
|
return Err(anyhow::Error::msg(
|
||||||
|
"Audio Error: called generic on spatial source",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SoundInterpretation::Spatial => match source {
|
||||||
|
SoundSource::Spatial(spatial_source) => spatial_source,
|
||||||
|
SoundSource::Generic(_) => {
|
||||||
|
return Err(anyhow::Error::msg(
|
||||||
|
"Audio Error: called spatial on generic source",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(f(spatial_source)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! sound_ctor {
|
||||||
|
($struct_name:ident) => {
|
||||||
|
pub struct $struct_name {
|
||||||
|
handle: Handle<SoundSource>,
|
||||||
|
rg3d_context: SoundContext,
|
||||||
|
interpretation: SoundInterpretation,
|
||||||
|
sound_type: String,
|
||||||
|
path: AssetPath,
|
||||||
|
duration: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $struct_name {
|
||||||
|
fn new(
|
||||||
|
handle: Handle<SoundSource>,
|
||||||
|
rg3d_context: SoundContext,
|
||||||
|
interpretation: SoundInterpretation,
|
||||||
|
sound_type: String,
|
||||||
|
path: AssetPath,
|
||||||
|
) -> Result<Arc<Self>> {
|
||||||
|
let duration = act_on_generic_source(
|
||||||
|
&rg3d_context,
|
||||||
|
handle,
|
||||||
|
interpretation,
|
||||||
|
|generic_source| Ok(generic_source.playback_time()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Arc::new($struct_name {
|
||||||
|
handle,
|
||||||
|
rg3d_context,
|
||||||
|
interpretation,
|
||||||
|
sound_type,
|
||||||
|
path,
|
||||||
|
duration,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play(&self, enable_looping: Option<bool>) -> Result<()> {
|
||||||
|
act_on_generic_source(
|
||||||
|
&self.rg3d_context,
|
||||||
|
self.handle,
|
||||||
|
self.interpretation,
|
||||||
|
|generic_source| {
|
||||||
|
generic_source.stop()?;
|
||||||
|
generic_source.play();
|
||||||
|
if let Some(looping) = enable_looping {
|
||||||
|
generic_source.set_looping(looping);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pause(&self) -> Result<()> {
|
||||||
|
act_on_generic_source(
|
||||||
|
&self.rg3d_context,
|
||||||
|
self.handle,
|
||||||
|
self.interpretation,
|
||||||
|
|generic_source| {
|
||||||
|
generic_source.pause();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop_looping(&self) -> Result<()> {
|
||||||
|
act_on_generic_source(
|
||||||
|
&self.rg3d_context,
|
||||||
|
self.handle,
|
||||||
|
self.interpretation,
|
||||||
|
|generic_source| {
|
||||||
|
generic_source.set_looping(false);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&self) -> Result<()> {
|
||||||
|
act_on_generic_source(
|
||||||
|
&self.rg3d_context,
|
||||||
|
self.handle,
|
||||||
|
self.interpretation,
|
||||||
|
|generic_source| {
|
||||||
|
generic_source.stop()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_position(&self, position: impl Into<[f32; 3]>) -> Result<()> {
|
||||||
|
act_on_spatial_source(
|
||||||
|
&self.rg3d_context,
|
||||||
|
self.handle,
|
||||||
|
self.interpretation,
|
||||||
|
|spatial_source| {
|
||||||
|
let pos = position.into();
|
||||||
|
spatial_source.set_position(Vector3::new(pos[0], pos[1], pos[2]));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_volume(&self, volume: f32) -> Result<()> {
|
||||||
|
act_on_generic_source(
|
||||||
|
&self.rg3d_context,
|
||||||
|
self.handle,
|
||||||
|
self.interpretation,
|
||||||
|
|generic_source| {
|
||||||
|
generic_source.set_gain(volume);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_path(&self) -> &AssetPath {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sound_type(&self) -> &str {
|
||||||
|
&self.sound_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn duration(&self) -> Duration {
|
||||||
|
self.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_paused(&self) -> Result<bool> {
|
||||||
|
act_on_generic_source(
|
||||||
|
&self.rg3d_context,
|
||||||
|
self.handle,
|
||||||
|
self.interpretation,
|
||||||
|
|generic_source| Ok(generic_source.status() == Status::Paused),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClearQueueAudioObject for $struct_name {
|
||||||
|
fn end_looping(&self) -> Result<()> {
|
||||||
|
self.stop_looping()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_playing(&self) -> Result<bool> {
|
||||||
|
act_on_generic_source(
|
||||||
|
&self.rg3d_context,
|
||||||
|
self.handle,
|
||||||
|
self.interpretation,
|
||||||
|
|generic_source| Ok(generic_source.status() == Status::Playing),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
sound_ctor!(Music);
|
||||||
|
sound_ctor!(Sound);
|
||||||
|
|
||||||
|
enum SoundType {
|
||||||
|
Sound,
|
||||||
|
Music,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SoundHandler {
|
||||||
|
volume_handler: VolumeHandler,
|
||||||
|
|
||||||
|
rg3d_context: SoundContext,
|
||||||
|
_sound_engine: Arc<Mutex<SoundEngine>>,
|
||||||
|
|
||||||
|
data: HashMap<AssetPath, SoundBufferResource>,
|
||||||
|
|
||||||
|
audio_objects: AudioObjects,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoundHandler {
|
||||||
|
pub fn new(volume_info: HashMap<String, f32>) -> Result<Self> {
|
||||||
|
let sound_engine = SoundEngine::new();
|
||||||
|
let rg3d_context = SoundContext::new();
|
||||||
|
|
||||||
|
sound_engine
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.add_context(rg3d_context.clone());
|
||||||
|
|
||||||
|
let master_volume = match volume_info.get("master") {
|
||||||
|
Some(v) => *v,
|
||||||
|
None => 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
rg3d_context.state().set_master_gain(master_volume);
|
||||||
|
|
||||||
|
Ok(SoundHandler {
|
||||||
|
volume_handler: VolumeHandler::new(volume_info),
|
||||||
|
|
||||||
|
rg3d_context,
|
||||||
|
_sound_engine: sound_engine,
|
||||||
|
|
||||||
|
data: HashMap::new(),
|
||||||
|
|
||||||
|
audio_objects: AudioObjects::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_position(&self, position: impl Into<[f32; 3]>) -> Result<()> {
|
||||||
|
let pos = position.into();
|
||||||
|
|
||||||
|
self.rg3d_context
|
||||||
|
.state()
|
||||||
|
.listener_mut()
|
||||||
|
.set_position(Vector3::new(pos[0], pos[1], pos[2]));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_direction(
|
||||||
|
&self,
|
||||||
|
direction: impl Into<[f32; 3]>,
|
||||||
|
up: impl Into<[f32; 3]>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let dir = direction.into();
|
||||||
|
let up = up.into();
|
||||||
|
|
||||||
|
self.rg3d_context.state().listener_mut().set_orientation_rh(
|
||||||
|
Vector3::new(dir[0], dir[1], dir[2]),
|
||||||
|
Vector3::new(up[0], up[1], up[2]),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_sound(
|
||||||
|
&mut self,
|
||||||
|
path: AssetPath,
|
||||||
|
sound_type: &str,
|
||||||
|
interpretation: SoundInterpretation,
|
||||||
|
) -> Result<Arc<Sound>> {
|
||||||
|
let volume = self.volume_handler.volume(sound_type);
|
||||||
|
|
||||||
|
let handle = self.source_handle(&path, volume, interpretation, SoundType::Sound)?;
|
||||||
|
|
||||||
|
let sound = Sound::new(
|
||||||
|
handle,
|
||||||
|
self.rg3d_context.clone(),
|
||||||
|
interpretation,
|
||||||
|
sound_type.to_string(),
|
||||||
|
path,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.audio_objects.add_sound(sound.clone());
|
||||||
|
|
||||||
|
Ok(sound)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_music(
|
||||||
|
&mut self,
|
||||||
|
path: AssetPath,
|
||||||
|
interpretation: SoundInterpretation,
|
||||||
|
) -> Result<Arc<Music>> {
|
||||||
|
let volume = self.volume_handler.volume("music");
|
||||||
|
|
||||||
|
let handle = self.source_handle(&path, volume, interpretation, SoundType::Music)?;
|
||||||
|
|
||||||
|
let music = Music::new(
|
||||||
|
handle,
|
||||||
|
self.rg3d_context.clone(),
|
||||||
|
interpretation,
|
||||||
|
"music".to_string(),
|
||||||
|
path,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.audio_objects.add_music(music.clone());
|
||||||
|
|
||||||
|
Ok(music)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_volume(&mut self, sound_type: &str, volume: f32) -> Result<()> {
|
||||||
|
if sound_type == "master" {
|
||||||
|
self.rg3d_context.state().set_master_gain(volume);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
self.volume_handler
|
||||||
|
.set_volume(sound_type, volume, &mut self.audio_objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn volume(&self, sound_type: &str) -> Result<f32> {
|
||||||
|
if sound_type == "master" {
|
||||||
|
Ok(self.rg3d_context.state().master_gain())
|
||||||
|
} else {
|
||||||
|
Ok(self.volume_handler.volume(sound_type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pause(&mut self) -> Result<()> {
|
||||||
|
// check if sounds are playing
|
||||||
|
self.audio_objects.apply_to_sound(None, |sound| {
|
||||||
|
if sound.is_playing()? {
|
||||||
|
sound.pause()?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.audio_objects.apply_to_music(|music| {
|
||||||
|
if music.is_playing()? {
|
||||||
|
music.pause()?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resume(&self) -> Result<()> {
|
||||||
|
// check if sounds are paused
|
||||||
|
self.audio_objects.apply_to_sound(None, |sound| {
|
||||||
|
if sound.is_paused()? {
|
||||||
|
sound.play(None)?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.audio_objects.apply_to_music(|music| {
|
||||||
|
if music.is_paused()? {
|
||||||
|
music.play(None)?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_sound(&mut self, sound: &Arc<Sound>) -> Result<()> {
|
||||||
|
self.audio_objects.remove_sound(sound)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_handle(
|
||||||
|
&mut self,
|
||||||
|
path: &AssetPath,
|
||||||
|
volume: f32,
|
||||||
|
interpretation: SoundInterpretation,
|
||||||
|
sound_type: SoundType,
|
||||||
|
) -> Result<Handle<SoundSource>> {
|
||||||
|
let sound_buffer = match self.data.get(path) {
|
||||||
|
Some(buffer) => buffer.clone(),
|
||||||
|
None => {
|
||||||
|
let data_source =
|
||||||
|
block_on(DataSource::from_file(&path.full_path())).map_err(|_err| {
|
||||||
|
anyhow::Error::msg(format!(
|
||||||
|
"Audio Error: failed loading file {}",
|
||||||
|
path.full_path()
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let buffer = match sound_type {
|
||||||
|
SoundType::Sound => {
|
||||||
|
SoundBufferResource::new_generic(data_source).map_err(|_| {
|
||||||
|
anyhow::Error::msg("Audio Error: failed creating generic sound buffer")
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
SoundType::Music => {
|
||||||
|
SoundBufferResource::new_streaming(data_source).map_err(|_| {
|
||||||
|
anyhow::Error::msg(
|
||||||
|
"Audio Error: failed creating streaming sound buffer",
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.data.insert(path.clone(), buffer.clone());
|
||||||
|
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let generic_source_builder = GenericSourceBuilder::new()
|
||||||
|
.with_buffer(sound_buffer)
|
||||||
|
.with_status(Status::Stopped)
|
||||||
|
.with_gain(volume);
|
||||||
|
|
||||||
|
let source = match interpretation {
|
||||||
|
SoundInterpretation::Generic => generic_source_builder.build_source()?,
|
||||||
|
SoundInterpretation::Spatial => {
|
||||||
|
SpatialSourceBuilder::new(generic_source_builder.build()?).build_source()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle = self.rg3d_context.state().add_source(source);
|
||||||
|
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_clear_queue(&mut self) -> Result<()> {
|
||||||
|
self.audio_objects.check_clear_queue()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.audio_objects.clear();
|
||||||
|
self.data.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SoundHandler {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.clear();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue