1 use source::Spatial;
2 use std::f32;
3 use std::fmt::Debug;
4 use std::sync::{Arc, Mutex};
5 use std::time::Duration;
6 use Device;
7 use Sample;
8 use Sink;
9 use Source;
10 
11 pub struct SpatialSink {
12     sink: Sink,
13     positions: Arc<Mutex<SoundPositions>>,
14 }
15 
16 struct SoundPositions {
17     emitter_position: [f32; 3],
18     left_ear: [f32; 3],
19     right_ear: [f32; 3],
20 }
21 
22 impl SpatialSink {
23     /// Builds a new `SpatialSink`.
24     #[inline]
new( device: &Device, emitter_position: [f32; 3], left_ear: [f32; 3], right_ear: [f32; 3], ) -> SpatialSink25     pub fn new(
26         device: &Device, emitter_position: [f32; 3], left_ear: [f32; 3], right_ear: [f32; 3],
27     ) -> SpatialSink {
28         SpatialSink {
29             sink: Sink::new(device),
30             positions: Arc::new(Mutex::new(SoundPositions {
31                 emitter_position,
32                 left_ear,
33                 right_ear,
34             })),
35         }
36     }
37 
38     /// Sets the position of the sound emitter in 3 dimensional space.
set_emitter_position(&self, pos: [f32; 3])39     pub fn set_emitter_position(&self, pos: [f32; 3]) {
40         self.positions.lock().unwrap().emitter_position = pos;
41     }
42 
43     /// Sets the position of the left ear in 3 dimensional space.
set_left_ear_position(&self, pos: [f32; 3])44     pub fn set_left_ear_position(&self, pos: [f32; 3]) {
45         self.positions.lock().unwrap().left_ear = pos;
46     }
47 
48     /// Sets the position of the right ear in 3 dimensional space.
set_right_ear_position(&self, pos: [f32; 3])49     pub fn set_right_ear_position(&self, pos: [f32; 3]) {
50         self.positions.lock().unwrap().right_ear = pos;
51     }
52 
53     /// Appends a sound to the queue of sounds to play.
54     #[inline]
append<S>(&self, source: S) where S: Source + Send + 'static, S::Item: Sample + Send + Debug,55     pub fn append<S>(&self, source: S)
56     where
57         S: Source + Send + 'static,
58         S::Item: Sample + Send + Debug,
59     {
60         let positions = self.positions.clone();
61         let pos_lock = self.positions.lock().unwrap();
62         let source = Spatial::new(
63             source,
64             pos_lock.emitter_position,
65             pos_lock.left_ear,
66             pos_lock.right_ear,
67         ).periodic_access(Duration::from_millis(10), move |i| {
68             let pos = positions.lock().unwrap();
69             i.set_positions(pos.emitter_position, pos.left_ear, pos.right_ear);
70         });
71         self.sink.append(source);
72     }
73 
74     // Gets the volume of the sound.
75     ///
76     /// The value `1.0` is the "normal" volume (unfiltered input). Any value other than 1.0 will
77     /// multiply each sample by this value.
78     #[inline]
volume(&self) -> f3279     pub fn volume(&self) -> f32 {
80         self.sink.volume()
81     }
82 
83     /// Changes the volume of the sound.
84     ///
85     /// The value `1.0` is the "normal" volume (unfiltered input). Any value other than 1.0 will
86     /// multiply each sample by this value.
87     #[inline]
set_volume(&self, value: f32)88     pub fn set_volume(&self, value: f32) {
89         self.sink.set_volume(value);
90     }
91 
92     /// Resumes playback of a paused sound.
93     ///
94     /// No effect if not paused.
95     #[inline]
play(&self)96     pub fn play(&self) {
97         self.sink.play();
98     }
99 
100     /// Pauses playback of this sink.
101     ///
102     /// No effect if already paused.
103     ///
104     /// A paused sound can be resumed with `play()`.
pause(&self)105     pub fn pause(&self) {
106         self.sink.pause();
107     }
108 
109     /// Gets if a sound is paused
110     ///
111     /// Sounds can be paused and resumed using pause() and play(). This gets if a sound is paused.
is_paused(&self) -> bool112     pub fn is_paused(&self) -> bool {
113         self.sink.is_paused()
114     }
115 
116     /// Stops the sink by emptying the queue.
117     #[inline]
stop(&self)118     pub fn stop(&self) {
119         self.sink.stop()
120     }
121 
122     /// Destroys the sink without stopping the sounds that are still playing.
123     #[inline]
detach(self)124     pub fn detach(self) {
125         self.sink.detach();
126     }
127 
128     /// Sleeps the current thread until the sound ends.
129     #[inline]
sleep_until_end(&self)130     pub fn sleep_until_end(&self) {
131         self.sink.sleep_until_end();
132     }
133 
134     /// Returns true if this sink has no more sounds to play.
135     #[inline]
empty(&self) -> bool136     pub fn empty(&self) -> bool {
137         self.sink.empty()
138     }
139 }
140