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