rodio/src/spatial_sink.rs

166 lines
4.5 KiB
Rust
Raw Normal View History

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
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,
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.
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.
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.
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,
)
.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]
pub fn set_volume(&self, value: f32) {
2017-07-01 14:57:59 +00:00
self.sink.set_volume(value);
}
/// 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()
}
/// 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
}