1use std::{marker::PhantomData, thread::JoinHandle};
10
11use wreath::{Reader, RingReader, RingWriter, Writer, ring_buf};
12use xpans_xsr::SpatialSampleMap;
13
14use violet_core::{Connector, Source, spatial_input::SpatialInput};
15
16pub struct SpatialDecoderInfo<Scene, T>
21where
22 Scene: AsRef<SpatialSampleMap<usize, u16, T>>,
23{
24 scene: Scene,
25 source_count: usize,
26 duration: usize,
27 phantom_data: PhantomData<T>,
28}
29
30impl<Scene, T> SpatialDecoderInfo<Scene, T>
31where
32 T: Copy + Default,
33 Scene: AsRef<SpatialSampleMap<usize, u16, T>>,
34{
35 pub fn new(scene: Scene, source_count: usize, duration: usize) -> Self {
42 Self {
43 scene,
44 source_count,
45 duration,
46 phantom_data: PhantomData,
47 }
48 }
49 pub fn into_pair(
57 self,
58 write_capacity: usize,
59 ) -> (SpatialDecoder<T>, SpatialDecoderTask<Scene, T>) {
60 let (reader, writer) = ring_buf(1, write_capacity);
61 let decoder = SpatialDecoder {
62 reader,
63 source_count: self.source_count,
64 };
65 let task = SpatialDecoderTask { writer, info: self };
66 (decoder, task)
67 }
68}
69
70pub struct SpatialDecoderTask<Scene, T>
72where
73 Scene: AsRef<SpatialSampleMap<usize, u16, T>>,
74{
75 writer: RingWriter<Source<T>>,
76 info: SpatialDecoderInfo<Scene, T>,
77}
78
79impl<Scene, T> SpatialDecoderTask<Scene, T>
80where
81 T: Default + Copy,
82 Scene: AsRef<SpatialSampleMap<usize, u16, T>>,
83{
84 pub fn info(&self) -> &SpatialDecoderInfo<Scene, T> {
86 &self.info
87 }
88 pub fn run(self, cancelled: impl Fn() -> bool, paused: impl Fn() -> bool) {
95 spatial_decoder_process(
96 self.info.scene,
97 self.info.source_count,
98 self.info.duration,
99 self.writer,
100 cancelled,
101 paused,
102 );
103 }
104}
105
106impl<Scene, T> SpatialDecoderTask<Scene, T>
107where
108 T: Default + Copy + Send + 'static,
109 Scene: AsRef<SpatialSampleMap<usize, u16, T>> + Send + 'static,
110{
111 pub fn spawn_and_run(
113 self,
114 cancelled: impl Fn() -> bool + Send + 'static,
115 paused: impl Fn() -> bool + Send + 'static,
116 ) -> JoinHandle<()> {
117 std::thread::spawn(move || self.run(cancelled, paused))
118 }
119}
120
121pub struct SpatialDecoder<T> {
123 reader: RingReader<Source<T>>,
124 source_count: usize,
125}
126
127impl<T: Default + Copy> Connector for SpatialDecoder<T> {
128 fn advance(&mut self, frames: usize) {
129 self.reader
130 .advance_read_position_by(frames * self.source_count);
131 }
132
133 fn frames_available(&self) -> Option<usize> {
134 let reads_available = self.reader.real_reads_available() / self.source_count;
135 if (reads_available == 0) && self.reader.is_closed() {
136 return None;
137 }
138 Some(reads_available)
139 }
140}
141impl<T: Default + Copy> SpatialInput for SpatialDecoder<T> {
142 type Scalar = T;
143
144 fn source(&self, source: usize, frame: usize) -> Source<Self::Scalar> {
145 let frame = frame * self.source_count;
146 let index = frame + source;
147 self.reader.read_forward(index)
148 }
149
150 fn source_count(&self) -> usize {
151 self.source_count
152 }
153}
154
155fn spatial_decoder_process<Scene, T>(
161 spatial_scene: Scene,
162 source_count: usize,
163 duration: usize,
164 writer: RingWriter<Source<T>>,
165 cancelled: impl Fn() -> bool,
166 paused: impl Fn() -> bool,
167) where
168 T: Default + Copy,
169 Scene: AsRef<SpatialSampleMap<usize, u16, T>>,
170{
171 let mut frame = 0usize;
172 let mut sources = vec![Source::default(); source_count];
173 while frame < duration {
174 if cancelled() {
175 break;
176 }
177 if !writer.writes_are_available(source_count) || paused() {
178 continue;
179 }
180 if let Some(events) = spatial_scene.as_ref().get(&frame) {
181 for event in events {
182 apply_changes(&mut sources[event.id as usize], &event.changes);
183 }
184 }
185 for (i, source) in sources.iter().enumerate() {
186 writer.write_forward(i, *source);
187 }
188 writer.advance_write_position_by(source_count);
189 frame += 1;
190 }
191}
192
193fn apply_changes<T: Copy>(source: &mut Source<T>, changes: &xpans_xsr::Changes<T>) {
194 changes.pos_x.map(|v| source.pos_x = v);
195 changes.pos_y.map(|v| source.pos_y = v);
196 changes.pos_z.map(|v| source.pos_z = v);
197 changes.ext_x.map(|v| source.ext_x = v);
198 changes.ext_y.map(|v| source.ext_y = v);
199 changes.ext_z.map(|v| source.ext_z = v);
200}