1use std::cell::{RefCell, RefMut};
6use std::{cmp, fmt, hash};
7
8use malloc_size_of::MallocSizeOf as MallocSizeOfTrait;
9use malloc_size_of_derive::MallocSizeOf;
10use petgraph::Direction;
11use petgraph::graph::DefaultIx;
12use petgraph::stable_graph::{NodeIndex, StableGraph};
13use petgraph::visit::{DfsPostOrder, EdgeRef, Reversed};
14use smallvec::SmallVec;
15
16use crate::block::{Block, Chunk};
17use crate::destination_node::DestinationNode;
18use crate::listener::AudioListenerNode;
19use crate::node::{AudioNodeEngine, BlockInfo, ChannelCountMode, ChannelInterpretation};
20use crate::param::ParamType;
21
22#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Debug, MallocSizeOf)]
23pub struct NodeId(#[ignore_malloc_size_of = "External Type"] NodeIndex<DefaultIx>);
26
27impl NodeId {
28 pub fn input(self, port: u32) -> PortId<InputPort> {
29 PortId(self, PortIndex::Port(port))
30 }
31 pub fn param(self, param: ParamType) -> PortId<InputPort> {
32 PortId(self, PortIndex::Param(param))
33 }
34 pub fn output(self, port: u32) -> PortId<OutputPort> {
35 PortId(self, PortIndex::Port(port))
36 }
37 pub(crate) fn listener(self) -> PortId<InputPort> {
38 PortId(self, PortIndex::Listener(()))
39 }
40}
41
42#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Debug, MallocSizeOf)]
52pub enum PortIndex<Kind: PortKind> {
53 Port(u32),
54 Param(Kind::ParamId),
55 Listener(Kind::Listener),
58}
59
60impl<Kind: PortKind> PortId<Kind> {
61 pub fn node(&self) -> NodeId {
62 self.0
63 }
64}
65
66pub trait PortKind {
67 type ParamId: Copy
68 + Eq
69 + PartialEq
70 + Ord
71 + PartialOrd
72 + hash::Hash
73 + fmt::Debug
74 + MallocSizeOfTrait;
75 type Listener: Copy
76 + Eq
77 + PartialEq
78 + Ord
79 + PartialOrd
80 + hash::Hash
81 + fmt::Debug
82 + MallocSizeOfTrait;
83}
84
85#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Debug, MallocSizeOf)]
87pub struct PortId<Kind: PortKind>(NodeId, PortIndex<Kind>);
88
89#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, MallocSizeOf)]
90pub struct InputPort;
93#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, MallocSizeOf)]
94pub struct OutputPort;
97
98impl PortKind for InputPort {
99 type ParamId = ParamType;
100 type Listener = ();
101}
102
103#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq, Copy, Clone, MallocSizeOf)]
104pub enum Void {}
105
106impl PortKind for OutputPort {
107 type ParamId = Void;
112 type Listener = Void;
113}
114
115pub struct AudioGraph {
116 graph: StableGraph<Node, Edge>,
117 dest_id: NodeId,
118 dests: Vec<NodeId>,
119 listener_id: NodeId,
120}
121
122pub(crate) struct Node {
123 node: RefCell<Box<dyn AudioNodeEngine>>,
124}
125
126pub(crate) struct Edge {
134 connections: SmallVec<[Connection; 1]>,
135}
136
137impl Edge {
138 fn has_between(
140 &self,
141 output_idx: PortIndex<OutputPort>,
142 input_idx: PortIndex<InputPort>,
143 ) -> bool {
144 self.connections
145 .iter()
146 .any(|e| e.input_idx == input_idx && e.output_idx == output_idx)
147 }
148
149 fn remove_by_output(&mut self, output_idx: PortIndex<OutputPort>) {
150 self.connections.retain(|i| i.output_idx != output_idx)
151 }
152
153 fn remove_by_input(&mut self, input_idx: PortIndex<InputPort>) {
154 self.connections.retain(|i| i.input_idx != input_idx)
155 }
156
157 fn remove_by_pair(
158 &mut self,
159 output_idx: PortIndex<OutputPort>,
160 input_idx: PortIndex<InputPort>,
161 ) {
162 self.connections
163 .retain(|i| i.output_idx != output_idx || i.input_idx != input_idx)
164 }
165}
166
167struct Connection {
169 input_idx: PortIndex<InputPort>,
172 output_idx: PortIndex<OutputPort>,
175 cache: RefCell<Option<Block>>,
178}
179
180impl AudioGraph {
181 pub fn new(channel_count: u8) -> Self {
182 let mut graph = StableGraph::new();
183 let dest_id =
184 NodeId(graph.add_node(Node::new(Box::new(DestinationNode::new(channel_count)))));
185 let listener_id = NodeId(graph.add_node(Node::new(Box::new(AudioListenerNode::new()))));
186 AudioGraph {
187 graph,
188 dest_id,
189 dests: vec![dest_id],
190 listener_id,
191 }
192 }
193
194 pub(crate) fn add_node(&mut self, node: Box<dyn AudioNodeEngine>) -> NodeId {
196 NodeId(self.graph.add_node(Node::new(node)))
197 }
198
199 pub fn add_edge(&mut self, out: PortId<OutputPort>, inp: PortId<InputPort>) {
203 let edge = self
204 .graph
205 .edges(out.node().0)
206 .find(|e| e.target() == inp.node().0)
207 .map(|e| e.id());
208 if let Some(e) = edge {
209 let w = self
211 .graph
212 .edge_weight_mut(e)
213 .expect("This edge is known to exist");
214 if w.has_between(out.1, inp.1) {
215 return;
216 }
217 w.connections.push(Connection::new(inp.1, out.1))
218 } else {
219 self.graph
221 .add_edge(out.node().0, inp.node().0, Edge::new(inp.1, out.1));
222 }
223 }
224
225 pub fn disconnect_all_from(&mut self, node: NodeId) {
229 let edges = self.graph.edges(node.0).map(|e| e.id()).collect::<Vec<_>>();
230 for edge in edges {
231 self.graph.remove_edge(edge);
232 }
233 }
234
235 pub fn disconnect_output(&mut self, out: PortId<OutputPort>) {
239 let candidates: Vec<_> = self
240 .graph
241 .edges(out.node().0)
242 .map(|e| (e.id(), e.target()))
243 .collect();
244 for (edge, to) in candidates {
245 let mut e = self
246 .graph
247 .remove_edge(edge)
248 .expect("Edge index is known to exist");
249 e.remove_by_output(out.1);
250 if !e.connections.is_empty() {
251 self.graph.add_edge(out.node().0, to, e);
252 }
253 }
254 }
255
256 pub fn disconnect_between(&mut self, from: NodeId, to: NodeId) {
260 let edge = self
261 .graph
262 .edges(from.0)
263 .find(|e| e.target() == to.0)
264 .map(|e| e.id());
265 if let Some(i) = edge {
266 self.graph.remove_edge(i);
267 }
268 }
269
270 pub fn disconnect_output_between(&mut self, out: PortId<OutputPort>, to: NodeId) {
274 let edge = self
275 .graph
276 .edges(out.node().0)
277 .find(|e| e.target() == to.0)
278 .map(|e| e.id());
279 if let Some(edge) = edge {
280 let mut e = self
281 .graph
282 .remove_edge(edge)
283 .expect("Edge index is known to exist");
284 e.remove_by_output(out.1);
285 if !e.connections.is_empty() {
286 self.graph.add_edge(out.node().0, to.0, e);
287 }
288 }
289 }
290
291 pub fn disconnect_to(&mut self, node: NodeId, inp: PortId<InputPort>) {
297 let edge = self
298 .graph
299 .edges(node.0)
300 .find(|e| e.target() == inp.node().0)
301 .map(|e| e.id());
302 if let Some(edge) = edge {
303 let mut e = self
304 .graph
305 .remove_edge(edge)
306 .expect("Edge index is known to exist");
307 e.remove_by_input(inp.1);
308 if !e.connections.is_empty() {
309 self.graph.add_edge(node.0, inp.node().0, e);
310 }
311 }
312 }
313
314 pub fn disconnect_output_between_to(
319 &mut self,
320 out: PortId<OutputPort>,
321 inp: PortId<InputPort>,
322 ) {
323 let edge = self
324 .graph
325 .edges(out.node().0)
326 .find(|e| e.target() == inp.node().0)
327 .map(|e| e.id());
328 if let Some(edge) = edge {
329 let mut e = self
330 .graph
331 .remove_edge(edge)
332 .expect("Edge index is known to exist");
333 e.remove_by_pair(out.1, inp.1);
334 if !e.connections.is_empty() {
335 self.graph.add_edge(out.node().0, inp.node().0, e);
336 }
337 }
338 }
339
340 pub fn dest_id(&self) -> NodeId {
344 self.dest_id
345 }
346
347 pub fn add_extra_dest(&mut self, dest: NodeId) {
349 self.dests.push(dest);
350 }
351
352 pub fn listener_id(&self) -> NodeId {
360 self.listener_id
361 }
362
363 pub fn process(&mut self, info: &BlockInfo) -> Chunk {
365 let reversed = Reversed(&self.graph);
371
372 let mut blocks: SmallVec<[SmallVec<[Block; 1]>; 1]> = SmallVec::new();
373 let mut output_counts: SmallVec<[u32; 1]> = SmallVec::new();
374
375 let mut visit = DfsPostOrder::empty(reversed);
376
377 for dest in &self.dests {
378 visit.move_to(dest.0);
379
380 while let Some(ix) = visit.next(reversed) {
381 let mut curr = self.graph[ix].node.borrow_mut();
382
383 let mut chunk = Chunk::default();
384 chunk
385 .blocks
386 .resize(curr.input_count() as usize, Default::default());
387
388 blocks.clear();
393 blocks.resize(curr.input_count() as usize, Default::default());
394
395 let mode = curr.channel_count_mode();
396 let count = curr.channel_count();
397 let interpretation = curr.channel_interpretation();
398
399 for edge in self.graph.edges_directed(ix, Direction::Incoming) {
401 let edge = edge.weight();
402 for connection in &edge.connections {
403 let mut block = connection
404 .cache
405 .borrow_mut()
406 .take()
407 .expect("Cache should have been filled from traversal");
408
409 match connection.input_idx {
410 PortIndex::Port(idx) => {
411 blocks[idx as usize].push(block);
412 },
413 PortIndex::Param(param) => {
414 block.mix(1, ChannelInterpretation::Speakers);
417 curr.get_param(param).add_block(block)
418 },
419 PortIndex::Listener(_) => curr.set_listenerdata(block),
420 }
421 }
422 }
423
424 for (i, mut blocks) in blocks.drain(..).enumerate() {
425 if blocks.is_empty() {
426 if mode == ChannelCountMode::Explicit {
427 chunk.blocks[i].mix(count, interpretation);
429 }
430 } else if blocks.len() == 1 {
431 chunk.blocks[i] = blocks.pop().expect("`blocks` had length 1");
432 match mode {
433 ChannelCountMode::Explicit => {
434 chunk.blocks[i].mix(count, interpretation);
435 },
436 ChannelCountMode::ClampedMax => {
437 if chunk.blocks[i].chan_count() > count {
438 chunk.blocks[i].mix(count, interpretation);
439 }
440 },
441 ChannelCountMode::Max => (),
443 }
444 } else {
445 let mix_count = match mode {
446 ChannelCountMode::Explicit => count,
447 _ => {
448 let mut max = 0; for block in &blocks {
450 max = cmp::max(max, block.chan_count());
451 }
452 if mode == ChannelCountMode::ClampedMax {
453 max = cmp::min(max, count);
454 }
455 max
456 },
457 };
458 let block = blocks.into_iter().fold(Block::default(), |acc, mut block| {
459 block.mix(mix_count, interpretation);
460 acc.sum(block)
461 });
462 chunk.blocks[i] = block;
463 }
464 }
465
466 let mut out = curr.process(chunk, info);
468
469 assert_eq!(out.len(), curr.output_count() as usize);
470 if curr.output_count() == 0 {
471 continue;
472 }
473
474 output_counts.clear();
480 output_counts.resize(curr.output_count() as usize, 0);
481 for edge in self.graph.edges(ix) {
482 let edge = edge.weight();
483 for conn in &edge.connections {
484 if let PortIndex::Port(idx) = conn.output_idx {
485 output_counts[idx as usize] += 1;
486 } else {
487 unreachable!()
488 }
489 }
490 }
491
492 for edge in self.graph.edges(ix) {
495 let edge = edge.weight();
496 for conn in &edge.connections {
497 if let PortIndex::Port(idx) = conn.output_idx {
498 output_counts[idx as usize] -= 1;
499 let block = if output_counts[idx as usize] == 0 {
501 out[conn.output_idx].take()
502 } else {
503 out[conn.output_idx].clone()
504 };
505 *conn.cache.borrow_mut() = Some(block);
506 } else {
507 unreachable!()
508 }
509 }
510 }
511 }
512 }
513 self.graph[self.dest_id.0]
515 .node
516 .borrow_mut()
517 .destination_data()
518 .expect("Destination node should have data cached")
519 }
520
521 pub(crate) fn node_mut(&self, ix: NodeId) -> RefMut<'_, Box<dyn AudioNodeEngine>> {
523 self.graph[ix.0].node.borrow_mut()
524 }
525}
526
527impl Node {
528 pub fn new(node: Box<dyn AudioNodeEngine>) -> Self {
529 Node {
530 node: RefCell::new(node),
531 }
532 }
533}
534
535impl Edge {
536 pub fn new(input_idx: PortIndex<InputPort>, output_idx: PortIndex<OutputPort>) -> Self {
537 Edge {
538 connections: SmallVec::from_buf([Connection::new(input_idx, output_idx)]),
539 }
540 }
541}
542
543impl Connection {
544 pub fn new(input_idx: PortIndex<InputPort>, output_idx: PortIndex<OutputPort>) -> Self {
545 Connection {
546 input_idx,
547 output_idx,
548 cache: RefCell::new(None),
549 }
550 }
551}