2017-07-03 08:09:10 +00:00
|
|
|
use std::f32;
|
2017-07-01 14:57:59 +00:00
|
|
|
use std::fmt::Debug;
|
2017-07-03 08:09:10 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use std::time::Duration;
|
2017-07-01 14:57:59 +00:00
|
|
|
|
2021-03-06 17:46:52 +00:00
|
|
|
use crate::source::Spatial;
|
|
|
|
use crate::stream::{OutputStreamHandle, PlayError};
|
|
|
|
use crate::{Sample, Sink, Source};
|
|
|
|
|
2017-07-01 14:57:59 +00:00
|
|
|
pub struct SpatialSink {
|
|
|
|
sink: Sink,
|
|
|
|
positions: Arc<Mutex<SoundPositions>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SoundPositions {
|
|
|
|
emitter_position: [f32; 3],
|
|
|
|
left_ear: [f32; 3],
|
|
|
|
right_ear: [f32; 3],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SpatialSink {
|
|
|
|
/// Builds a new `SpatialSink`.
|
2020-02-25 10:09:17 +00:00
|
|
|
pub fn try_new(
|
|
|
|
stream: &OutputStreamHandle,
|
2020-01-31 00:15:41 +00:00
|
|
|
emitter_position: [f32; 3],
|
|
|
|
left_ear: [f32; 3],
|
|
|
|
right_ear: [f32; 3],
|
2020-02-25 10:09:17 +00:00
|
|
|
) -> Result<SpatialSink, PlayError> {
|
|
|
|
Ok(SpatialSink {
|
|
|
|
sink: Sink::try_new(stream)?,
|
2017-07-01 14:57:59 +00:00
|
|
|
positions: Arc::new(Mutex::new(SoundPositions {
|
2018-04-19 08:03:48 +00:00
|
|
|
emitter_position,
|
|
|
|
left_ear,
|
|
|
|
right_ear,
|
|
|
|
})),
|
2020-02-25 10:09:17 +00:00
|
|
|
})
|
2017-07-01 14:57:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the position of the sound emitter in 3 dimensional space.
|
2018-11-16 10:18:07 +00:00
|
|
|
pub fn set_emitter_position(&self, pos: [f32; 3]) {
|
2017-07-01 14:57:59 +00:00
|
|
|
self.positions.lock().unwrap().emitter_position = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the position of the left ear in 3 dimensional space.
|
2018-11-16 10:18:07 +00:00
|
|
|
pub fn set_left_ear_position(&self, pos: [f32; 3]) {
|
2017-07-01 14:57:59 +00:00
|
|
|
self.positions.lock().unwrap().left_ear = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the position of the right ear in 3 dimensional space.
|
2018-11-16 10:18:07 +00:00
|
|
|
pub fn set_right_ear_position(&self, pos: [f32; 3]) {
|
2017-07-01 14:57:59 +00:00
|
|
|
self.positions.lock().unwrap().right_ear = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Appends a sound to the queue of sounds to play.
|
|
|
|
#[inline]
|
|
|
|
pub fn append<S>(&self, source: S)
|
2018-04-19 08:03:48 +00:00
|
|
|
where
|
|
|
|
S: Source + Send + 'static,
|
|
|
|
S::Item: Sample + Send + Debug,
|
2017-07-01 14:57:59 +00:00
|
|
|
{
|
|
|
|
let positions = self.positions.clone();
|
|
|
|
let pos_lock = self.positions.lock().unwrap();
|
2018-04-19 08:03:48 +00:00
|
|
|
let source = Spatial::new(
|
|
|
|
source,
|
|
|
|
pos_lock.emitter_position,
|
|
|
|
pos_lock.left_ear,
|
|
|
|
pos_lock.right_ear,
|
2020-01-31 00:15:41 +00:00
|
|
|
)
|
|
|
|
.periodic_access(Duration::from_millis(10), move |i| {
|
2018-04-19 08:03:48 +00:00
|
|
|
let pos = positions.lock().unwrap();
|
|
|
|
i.set_positions(pos.emitter_position, pos.left_ear, pos.right_ear);
|
|
|
|
});
|
2017-07-01 14:57:59 +00:00
|
|
|
self.sink.append(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the volume of the sound.
|
|
|
|
///
|
|
|
|
/// The value `1.0` is the "normal" volume (unfiltered input). Any value other than 1.0 will
|
|
|
|
/// multiply each sample by this value.
|
|
|
|
#[inline]
|
|
|
|
pub fn volume(&self) -> f32 {
|
|
|
|
self.sink.volume()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Changes the volume of the sound.
|
|
|
|
///
|
|
|
|
/// The value `1.0` is the "normal" volume (unfiltered input). Any value other than 1.0 will
|
|
|
|
/// multiply each sample by this value.
|
|
|
|
#[inline]
|
2018-11-16 10:18:07 +00:00
|
|
|
pub fn set_volume(&self, value: f32) {
|
2017-07-01 14:57:59 +00:00
|
|
|
self.sink.set_volume(value);
|
|
|
|
}
|
|
|
|
|
2022-01-25 00:57:24 +00:00
|
|
|
/// Gets the speed of the sound.
|
|
|
|
///
|
|
|
|
/// The value `1.0` is the "normal" speed (unfiltered input). Any value other than `1.0` will
|
|
|
|
/// change the play speed of the sound.
|
|
|
|
#[inline]
|
|
|
|
pub fn speed(&self) -> f32 {
|
|
|
|
self.sink.speed()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Changes the speed of the sound.
|
|
|
|
///
|
|
|
|
/// The value `1.0` is the "normal" speed (unfiltered input). Any value other than `1.0` will
|
|
|
|
/// change the play speed of the sound.
|
|
|
|
#[inline]
|
|
|
|
pub fn set_speed(&self, value: f32) {
|
|
|
|
self.sink.set_speed(value)
|
|
|
|
}
|
|
|
|
|
2017-07-01 14:57:59 +00:00
|
|
|
/// Resumes playback of a paused sound.
|
|
|
|
///
|
|
|
|
/// No effect if not paused.
|
|
|
|
#[inline]
|
|
|
|
pub fn play(&self) {
|
|
|
|
self.sink.play();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Pauses playback of this sink.
|
|
|
|
///
|
|
|
|
/// No effect if already paused.
|
|
|
|
///
|
|
|
|
/// A paused sound can be resumed with `play()`.
|
|
|
|
pub fn pause(&self) {
|
|
|
|
self.sink.pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets if a sound is paused
|
|
|
|
///
|
|
|
|
/// Sounds can be paused and resumed using pause() and play(). This gets if a sound is paused.
|
|
|
|
pub fn is_paused(&self) -> bool {
|
|
|
|
self.sink.is_paused()
|
|
|
|
}
|
|
|
|
|
2018-09-23 03:10:35 +00:00
|
|
|
/// Stops the sink by emptying the queue.
|
|
|
|
#[inline]
|
|
|
|
pub fn stop(&self) {
|
|
|
|
self.sink.stop()
|
|
|
|
}
|
|
|
|
|
2017-07-01 14:57:59 +00:00
|
|
|
/// Destroys the sink without stopping the sounds that are still playing.
|
|
|
|
#[inline]
|
|
|
|
pub fn detach(self) {
|
|
|
|
self.sink.detach();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sleeps the current thread until the sound ends.
|
|
|
|
#[inline]
|
|
|
|
pub fn sleep_until_end(&self) {
|
|
|
|
self.sink.sleep_until_end();
|
|
|
|
}
|
2017-08-20 13:28:05 +00:00
|
|
|
|
|
|
|
/// Returns true if this sink has no more sounds to play.
|
|
|
|
#[inline]
|
|
|
|
pub fn empty(&self) -> bool {
|
|
|
|
self.sink.empty()
|
|
|
|
}
|
2022-01-22 22:16:38 +00:00
|
|
|
|
|
|
|
/// Returns the number of sounds currently in the queue.
|
|
|
|
#[inline]
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.sink.len()
|
|
|
|
}
|
2017-07-01 14:57:59 +00:00
|
|
|
}
|