1use crate::*;
2use alloc::boxed::Box;
3use alloc::vec;
4use alloc::vec::Vec;
5
6pub struct Manager {
7 root: Node,
8 paths: Vec<Box<[u8]>>,
9 prev: Option<Frame>,
10 consumed: usize,
11}
12
13impl Manager {
14 #[must_use]
15 pub fn new() -> Self {
16 Self {
17 root: Node::new_root(),
18 paths: vec![Box::new([])],
19 prev: None,
20 consumed: 0,
21 }
22 }
23
24 pub fn get_node(&mut self, id: u32) -> Result<&mut Node, NodeError> {
30 let Some(path) = self.paths.get(id as usize) else {
31 return Err(NodeError::UnknownID(id));
32 };
33 Ok(self.root.get_node(path))
34 }
35
36 pub fn add_node(&mut self, parent_id: u32, b: Box<dyn Processor>) -> Result<u32, NodeError> {
44 const MAX_NODES: usize = 32;
45 if self.paths.len() >= MAX_NODES {
46 return Err(NodeError::TooManyNodes);
47 }
48 let Some(parent_path) = self.paths.get(parent_id as usize) else {
49 return Err(NodeError::UnknownID(parent_id));
50 };
51 let parent_node = self.root.get_node(parent_path);
52 let sub_id = parent_node.add(b)?;
53 #[expect(clippy::cast_possible_truncation)]
54 let id = self.paths.len() as u32;
55 let mut path = Vec::new();
56 path.extend_from_slice(parent_path);
57 path.push(sub_id);
58 self.paths.push(path.into_boxed_slice());
59 Ok(id)
60 }
61
62 pub fn clear(&mut self, id: u32) -> Result<(), NodeError> {
68 let Some(path) = self.paths.get(id as usize) else {
69 return Err(NodeError::UnknownID(id));
70 };
71 let node = self.root.get_node(path);
72 node.clear();
73 let mut paths = Vec::new();
74 for p in &self.paths {
75 if p.len() > path.len() && p.starts_with(path) {
76 continue;
77 }
78 paths.push(p.clone());
79 }
80 self.paths = paths;
81 Ok(())
82 }
83
84 pub fn write(&mut self, buf: &mut [i16]) {
86 let mut buf = self.write_prev(buf);
89
90 while buf.len() >= 16 {
91 let Some(frame) = self.root.next_frame() else {
92 break;
93 };
94 let written = fill_buf(buf, &frame, 0);
95 buf = &mut buf[written..];
96 }
97
98 if !buf.is_empty() {
102 if let Some(frame) = self.root.next_frame() {
103 self.prev = Some(frame);
104 self.consumed = 0;
105 buf = self.write_prev(buf);
106 debug_assert!(buf.is_empty());
107 } else {
108 buf.fill(0);
111 }
112 }
113 }
114
115 #[must_use]
116 fn write_prev<'a>(&mut self, buf: &'a mut [i16]) -> &'a mut [i16] {
117 debug_assert!(self.consumed < 16);
118 let Some(frame) = &mut self.prev else {
119 return buf;
120 };
121 let written = fill_buf(buf, frame, self.consumed);
122 let consumed = self.consumed + written;
123 if consumed >= 16 {
124 debug_assert_eq!(consumed, 16);
125 self.prev = None;
126 self.consumed = 0;
127 } else {
128 self.consumed = consumed;
129 }
130 &mut buf[written..]
131 }
132}
133
134fn fill_buf(buf: &mut [i16], frame: &Frame, skip: usize) -> usize {
136 let right = frame.right.unwrap_or(frame.left);
138 let mut left = frame.left.as_array().iter();
139 let mut right = right.as_array().iter();
140
141 let mut even = true;
143 for _ in 0..skip {
144 if even {
145 left.next()
146 } else {
147 right.next()
148 };
149 even = !even;
150 }
151
152 let mut written = 0;
153 #[expect(clippy::cast_possible_truncation)]
154 for tar in buf.iter_mut() {
155 let chan = if even { &mut left } else { &mut right };
156 let Some(s) = chan.next() else { break };
157 even = !even;
158 written += 1;
159 let s = s.clamp(-1., 1.);
160 *tar = (s * f32::from(i16::MAX)) as i16;
161 }
162 written
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn test_fill_buf_stereo() {
171 let frame = Frame::stereo(
172 Sample::new([
173 u2f(11),
174 u2f(13),
175 u2f(15),
176 u2f(17),
177 u2f(19),
178 u2f(21),
179 u2f(23),
180 u2f(25),
181 ]),
182 Sample::new([
183 u2f(12),
184 u2f(14),
185 u2f(16),
186 u2f(18),
187 u2f(20),
188 u2f(22),
189 u2f(24),
190 u2f(26),
191 ]),
192 );
193 let mut buf = [0i16; 20];
194 fill_buf(&mut buf[..], &frame, 0);
195 for (a, b) in buf[..15].iter().zip(&buf[1..]) {
196 assert!(a < b, "{a} < {b}");
197 }
198 assert!(buf[0] != 0);
199 assert_eq!(&buf[16..], &[0, 0, 0, 0]);
200 }
201
202 #[expect(clippy::cast_lossless)]
203 fn u2f(u: u16) -> f32 {
204 u as f32 / 100.
205 }
206}