1pub use euphony_macros::Node;
2
3#[doc(hidden)]
4#[cfg(feature = "reflect")]
5pub mod reflect;
6
7use euphony_graph as graph;
8
9pub type Error = String;
10
11pub type BoxProcessor = Box<dyn graph::Processor<Config>>;
12
13mod sink;
14pub use sink::{SampleType, Sink};
15
16#[inline]
17pub fn spawn<const I: usize, const B: usize, N: Node<I, B>>(node: N) -> BoxProcessor {
18 Box::new(StaticNode::new(node))
19}
20
21pub type Hash = [u8; 32];
22
23pub trait BufferMap: 'static + core::fmt::Debug + Send + Sync {
24 fn get(&self, id: u64, channel: u64) -> Buffer;
25}
26
27impl BufferMap for () {
28 fn get(&self, _id: u64, _channel: u64) -> Buffer {
29 Buffer {
30 samples: &[][..],
31 hash: &[0; 32],
32 }
33 }
34}
35
36pub type Sample = f64;
37pub const LEN: usize = 4000 / (core::mem::size_of::<Sample>() / 8);
38pub type Output = [Sample; LEN];
39
40type BufferKey = (u64, u64);
41
42#[derive(Debug)]
43pub struct Context {
44 pub buffers: Box<dyn BufferMap>,
45 pub partial: Option<usize>,
46}
47
48impl Default for Context {
49 fn default() -> Self {
50 Self {
51 buffers: Box::new(()),
52 partial: None,
53 }
54 }
55}
56
57#[derive(Clone, Copy, Debug, Default)]
58pub struct Config;
59
60impl graph::Config for Config {
61 type Context = Context;
62 type Output = Output;
63 type Value = Value;
64 type Parameter = Parameter;
65}
66
67type Parameter = u64;
68
69#[derive(Clone, Copy, Debug, PartialEq)]
70pub enum ParameterValue {
71 Constant(f64),
72 Node(u64),
73 Buffer(BufferKey),
74}
75
76pub enum Value {
77 Constant(f64),
78 Buffer(BufferKey),
79}
80
81pub struct Inputs<'a, const I: usize> {
82 inputs: graph::Inputs<'a, Config>,
83 keys: &'a [graph::Input<f64>; I],
84}
85
86impl<'a, const I: usize> Inputs<'a, I> {
87 #[inline]
88 pub fn get(&self, index: usize) -> Input {
89 debug_assert!(index < I);
90 match unsafe { *self.keys.get_unchecked(index) } {
91 graph::Input::Value(v) => Input::Constant(v),
92 graph::Input::Node(n) => Input::Buffer(&self.inputs[n]),
93 }
94 }
95}
96
97#[derive(Clone, Copy, Debug)]
98pub enum Input<'a> {
99 Constant(f64),
100 Buffer(&'a Output),
101}
102
103impl<'a> Input<'a> {
104 #[inline]
105 pub fn iter(&self) -> InputIter {
106 self.into_iter()
107 }
108}
109
110impl<'a> IntoIterator for Input<'a> {
111 type Item = Sample;
112 type IntoIter = InputIter<'a>;
113
114 fn into_iter(self) -> Self::IntoIter {
115 match self {
116 Self::Constant(v) => InputIter::Constant(v),
117 Self::Buffer(v) => InputIter::Buffer(v.iter()),
118 }
119 }
120}
121
122impl<'a> From<f64> for Input<'a> {
123 fn from(value: f64) -> Self {
124 Self::Constant(value)
125 }
126}
127
128impl<'a> From<&'a Output> for Input<'a> {
129 fn from(buffer: &'a Output) -> Self {
130 Self::Buffer(buffer)
131 }
132}
133
134pub enum InputIter<'a> {
135 Constant(f64),
136 Buffer(core::slice::Iter<'a, Sample>),
137}
138
139impl<'a> Iterator for InputIter<'a> {
140 type Item = Sample;
141
142 #[inline]
143 fn next(&mut self) -> Option<Self::Item> {
144 match self {
145 Self::Constant(v) => Some(*v),
146 Self::Buffer(v) => v.next().copied(),
147 }
148 }
149}
150
151pub struct Buffers<'a, const B: usize> {
152 buffers: &'a dyn BufferMap,
153 keys: &'a [BufferKey; B],
154}
155
156impl<'a, const B: usize> Buffers<'a, B> {
157 #[inline]
158 pub fn get(&self, index: usize) -> Buffer {
159 debug_assert!(index < B);
160 let (buffer, channel) = unsafe { *self.keys.get_unchecked(index) };
161
162 if buffer == u64::MAX {
164 return ().get(buffer, channel);
165 }
166
167 self.buffers.get(buffer, channel)
168 }
169}
170
171pub struct Buffer<'a> {
172 pub samples: &'a [Sample],
173 pub hash: &'a Hash,
174}
175
176impl<'a> From<&'a [Sample]> for Buffer<'a> {
177 fn from(samples: &'a [Sample]) -> Self {
178 Self {
179 samples,
180 hash: &[0; 32],
181 }
182 }
183}
184
185pub struct StaticNode<const I: usize, const B: usize, P: Node<I, B>> {
186 inputs: [graph::Input<f64>; I],
187 buffers: [BufferKey; B],
188 output: Output,
189 processor: P,
190}
191
192impl<const I: usize, const B: usize, P: Node<I, B>> StaticNode<I, B, P> {
193 #[inline]
194 pub fn new(processor: P) -> Self {
195 let defaults = P::DEFAULTS;
196
197 let mut inputs = [graph::Input::Value(0.0); I];
198
199 for (from, to) in defaults.iter().zip(inputs.iter_mut()) {
200 *to = graph::Input::Value(*from);
201 }
202
203 Self {
204 inputs,
205 buffers: [(u64::MAX, u64::MAX); B],
206 output: [0.0; LEN],
207 processor,
208 }
209 }
210}
211
212impl<const I: usize, const B: usize, P: Node<I, B>> graph::Processor<Config>
213 for StaticNode<I, B, P>
214{
215 #[inline(never)]
216 fn set(
217 &mut self,
218 param: Parameter,
219 value: graph::Input<Value>,
220 ) -> Result<graph::Input<Value>, u64> {
221 let value = match value {
222 graph::Input::Value(Value::Buffer(idx)) => {
223 let input = self.buffers.get_mut(param as usize).ok_or(param)?;
224 let prev = core::mem::replace(input, idx);
225 return Ok(graph::Input::Value(Value::Buffer(prev)));
226 }
227 graph::Input::Value(Value::Constant(v)) => {
228 self.processor.trigger(param, v);
229 graph::Input::Value(v)
230 }
231 graph::Input::Node(node) => {
232 if self.processor.trigger(param, 0.0) {
234 return Err(param);
235 }
236 graph::Input::Node(node)
237 }
238 };
239
240 let input = self.inputs.get_mut(param as usize).ok_or(param)?;
241 let prev = core::mem::replace(input, value);
242
243 Ok(match prev {
244 graph::Input::Value(v) => graph::Input::Value(Value::Constant(v)),
245 graph::Input::Node(n) => graph::Input::Node(n),
246 })
247 }
248
249 #[inline(never)]
250 fn remove(&mut self, node: graph::NodeKey) {
251 for input in self.inputs.iter_mut() {
252 if let graph::Input::Node(key) = input {
253 if *key == node {
254 *input = graph::Input::Value(0.0);
255 }
256 }
257 }
258 }
259
260 #[inline(never)]
261 fn output(&self) -> &Output {
262 &self.output
263 }
264
265 #[inline(never)]
266 fn output_mut(&mut self) -> &mut Output {
267 &mut self.output
268 }
269
270 #[inline(never)]
271 fn process(&mut self, inputs: graph::Inputs<Config>, context: &Context) {
272 let inputs = Inputs {
273 inputs,
274 keys: &self.inputs,
275 };
276
277 let buffers = Buffers {
278 buffers: context.buffers.as_ref(),
279 keys: &self.buffers,
280 };
281
282 if let Some(partial) = context.partial {
283 let output = unsafe {
284 debug_assert!(partial <= LEN);
285 self.output.get_unchecked_mut(..partial)
286 };
287 self.processor.process(inputs, buffers, output);
288 } else {
289 self.processor
290 .process_full(inputs, buffers, &mut self.output);
291 }
292 }
293}
294
295pub trait Node<const INPUTS: usize, const BUFFERS: usize>: 'static + Send {
296 const DEFAULTS: [f64; INPUTS] = [0.0; INPUTS];
297
298 #[inline]
299 fn trigger(&mut self, param: Parameter, value: f64) -> bool {
300 let _ = param;
302 let _ = value;
303 false
304 }
305
306 #[inline]
307 fn process_full(
308 &mut self,
309 inputs: Inputs<INPUTS>,
310 buffers: Buffers<BUFFERS>,
311 output: &mut Output,
312 ) {
313 self.process(inputs, buffers, output)
314 }
315
316 fn process(&mut self, inputs: Inputs<INPUTS>, buffers: Buffers<BUFFERS>, output: &mut [Sample]);
317}