rodio/source/
spatial.rs
1use std::time::Duration;
2
3use crate::source::ChannelVolume;
4use crate::{Sample, Source};
5
6use super::SeekError;
7
8#[derive(Clone)]
12pub struct Spatial<I>
13where
14 I: Source,
15 I::Item: Sample,
16{
17 input: ChannelVolume<I>,
18}
19
20fn dist_sq(a: [f32; 3], b: [f32; 3]) -> f32 {
21 a.iter()
22 .zip(b.iter())
23 .map(|(a, b)| (a - b) * (a - b))
24 .sum::<f32>()
25}
26
27impl<I> Spatial<I>
28where
29 I: Source,
30 I::Item: Sample,
31{
32 pub fn new(
34 input: I,
35 emitter_position: [f32; 3],
36 left_ear: [f32; 3],
37 right_ear: [f32; 3],
38 ) -> Spatial<I>
39 where
40 I: Source,
41 I::Item: Sample,
42 {
43 let mut ret = Spatial {
44 input: ChannelVolume::new(input, vec![0.0, 0.0]),
45 };
46 ret.set_positions(emitter_position, left_ear, right_ear);
47 ret
48 }
49
50 pub fn set_positions(
52 &mut self,
53 emitter_pos: [f32; 3],
54 left_ear: [f32; 3],
55 right_ear: [f32; 3],
56 ) {
57 debug_assert!(left_ear != right_ear);
58 let left_dist_sq = dist_sq(left_ear, emitter_pos);
59 let right_dist_sq = dist_sq(right_ear, emitter_pos);
60 let max_diff = dist_sq(left_ear, right_ear).sqrt();
61 let left_dist = left_dist_sq.sqrt();
62 let right_dist = right_dist_sq.sqrt();
63 let left_diff_modifier = (((left_dist - right_dist) / max_diff + 1.0) / 4.0 + 0.5).min(1.0);
64 let right_diff_modifier =
65 (((right_dist - left_dist) / max_diff + 1.0) / 4.0 + 0.5).min(1.0);
66 let left_dist_modifier = (1.0 / left_dist_sq).min(1.0);
67 let right_dist_modifier = (1.0 / right_dist_sq).min(1.0);
68 self.input
69 .set_volume(0, left_diff_modifier * left_dist_modifier);
70 self.input
71 .set_volume(1, right_diff_modifier * right_dist_modifier);
72 }
73}
74
75impl<I> Iterator for Spatial<I>
76where
77 I: Source,
78 I::Item: Sample,
79{
80 type Item = I::Item;
81
82 #[inline]
83 fn next(&mut self) -> Option<I::Item> {
84 self.input.next()
85 }
86
87 #[inline]
88 fn size_hint(&self) -> (usize, Option<usize>) {
89 self.input.size_hint()
90 }
91}
92
93impl<I> ExactSizeIterator for Spatial<I>
94where
95 I: Source + ExactSizeIterator,
96 I::Item: Sample,
97{
98}
99
100impl<I> Source for Spatial<I>
101where
102 I: Source,
103 I::Item: Sample,
104{
105 #[inline]
106 fn current_frame_len(&self) -> Option<usize> {
107 self.input.current_frame_len()
108 }
109
110 #[inline]
111 fn channels(&self) -> u16 {
112 self.input.channels()
113 }
114
115 #[inline]
116 fn sample_rate(&self) -> u32 {
117 self.input.sample_rate()
118 }
119
120 #[inline]
121 fn total_duration(&self) -> Option<Duration> {
122 self.input.total_duration()
123 }
124
125 #[inline]
126 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
127 self.input.try_seek(pos)
128 }
129}