Skip to content

Commit 274f78b

Browse files
committed
Create NodeCollection struct for holding the audio processors
No functional changes compared to the previous commit
1 parent 27552b0 commit 274f78b

File tree

4 files changed

+155
-117
lines changed

4 files changed

+155
-117
lines changed

src/render/graph.rs

Lines changed: 41 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::panic::{self, AssertUnwindSafe};
66
use crate::context::AudioNodeId;
77
use smallvec::{smallvec, SmallVec};
88

9-
use super::{Alloc, AudioParamValues, AudioProcessor, AudioRenderQuantum};
9+
use super::{Alloc, AudioParamValues, AudioProcessor, AudioRenderQuantum, NodeCollection};
1010
use crate::node::ChannelConfig;
1111
use crate::render::RenderScope;
1212

@@ -75,7 +75,7 @@ impl Node {
7575
/// The audio graph
7676
pub(crate) struct Graph {
7777
/// Processing Nodes
78-
nodes: Vec<Option<RefCell<Node>>>,
78+
nodes: NodeCollection,
7979
/// Allocator for audio buffers
8080
alloc: Alloc,
8181

@@ -94,7 +94,7 @@ pub(crate) struct Graph {
9494
impl Graph {
9595
pub fn new() -> Self {
9696
Graph {
97-
nodes: Vec::with_capacity(64),
97+
nodes: NodeCollection::new(),
9898
ordered: vec![],
9999
marked: vec![],
100100
marked_temp: vec![],
@@ -126,27 +126,23 @@ impl Graph {
126126
let outputs = vec![AudioRenderQuantum::from(self.alloc.silence()); number_of_outputs];
127127

128128
let index = index.0 as usize;
129-
if index >= self.nodes.len() {
130-
self.nodes.resize_with(index + 1, || None);
131-
}
132-
self.nodes[index] = Some(RefCell::new(Node {
133-
processor,
134-
inputs,
135-
outputs,
136-
channel_config,
137-
outgoing_edges: smallvec![],
138-
free_when_finished: false,
139-
has_inputs_connected: false,
140-
cycle_breaker: false,
141-
}));
129+
self.nodes.insert(
130+
index,
131+
RefCell::new(Node {
132+
processor,
133+
inputs,
134+
outputs,
135+
channel_config,
136+
outgoing_edges: smallvec![],
137+
free_when_finished: false,
138+
has_inputs_connected: false,
139+
cycle_breaker: false,
140+
}),
141+
);
142142
}
143143

144144
pub fn add_edge(&mut self, source: (AudioNodeId, usize), dest: (AudioNodeId, usize)) {
145-
self.nodes
146-
.get_mut(source.0 .0 as usize)
147-
.unwrap_or_else(|| panic!("cannot connect {:?} to {:?}", source, dest))
148-
.as_mut()
149-
.unwrap()
145+
self.nodes[source.0 .0 as usize]
150146
.get_mut()
151147
.outgoing_edges
152148
.push(OutgoingEdge {
@@ -159,11 +155,7 @@ impl Graph {
159155
}
160156

161157
pub fn remove_edge(&mut self, source: AudioNodeId, dest: AudioNodeId) {
162-
self.nodes
163-
.get_mut(source.0 as usize)
164-
.unwrap_or_else(|| panic!("cannot remove the edge from {:?} to {:?}", source, dest))
165-
.as_mut()
166-
.unwrap()
158+
self.nodes[source.0 as usize]
167159
.get_mut()
168160
.outgoing_edges
169161
.retain(|edge| edge.other_id != dest);
@@ -172,16 +164,12 @@ impl Graph {
172164
}
173165

174166
pub fn remove_edges_from(&mut self, source: AudioNodeId) {
175-
self.nodes
176-
.get_mut(source.0 as usize)
177-
.unwrap_or_else(|| panic!("cannot remove edges from {:?}", source))
178-
.as_mut()
179-
.unwrap()
167+
self.nodes[source.0 as usize]
180168
.get_mut()
181169
.outgoing_edges
182170
.clear();
183171

184-
self.nodes.iter_mut().flatten().for_each(|node| {
172+
self.nodes.values_mut().for_each(|node| {
185173
node.get_mut()
186174
.outgoing_edges
187175
.retain(|edge| edge.other_id != source);
@@ -194,27 +182,17 @@ impl Graph {
194182
// Issue #92, a race condition can occur for AudioParams. They may have already been
195183
// removed from the audio graph if the node they feed into was dropped.
196184
// Therefore, do not assume this node still exists:
197-
if let Some(node) = self.nodes.get_mut(index.0 as usize).unwrap().as_mut() {
185+
if let Some(node) = self.nodes.get_mut(index.0 as usize) {
198186
node.get_mut().free_when_finished = true;
199187
}
200188
}
201189

202190
pub fn mark_cycle_breaker(&mut self, index: AudioNodeId) {
203-
self.nodes
204-
.get_mut(index.0 as usize)
205-
.unwrap()
206-
.as_mut()
207-
.unwrap()
208-
.get_mut()
209-
.cycle_breaker = true;
191+
self.nodes[index.0 as usize].get_mut().cycle_breaker = true;
210192
}
211193

212194
pub fn route_message(&mut self, index: AudioNodeId, msg: &mut dyn Any) {
213-
self.nodes
214-
.get_mut(index.0 as usize)
215-
.unwrap()
216-
.as_mut()
217-
.unwrap()
195+
self.nodes[index.0 as usize]
218196
.get_mut()
219197
.processor
220198
.onmessage(msg);
@@ -237,15 +215,10 @@ impl Graph {
237215
// If this node is in the cycle detection list, it is part of a cycle!
238216
if let Some(pos) = marked_temp.iter().position(|&m| m == node_id) {
239217
// check if we can find some node that can break the cycle
240-
let cycle_breaker_node = marked_temp.iter().skip(pos).find(|node_id| {
241-
self.nodes
242-
.get(node_id.0 as usize)
243-
.unwrap()
244-
.as_ref()
245-
.unwrap()
246-
.borrow()
247-
.cycle_breaker
248-
});
218+
let cycle_breaker_node = marked_temp
219+
.iter()
220+
.skip(pos)
221+
.find(|node_id| self.nodes[node_id.0 as usize].borrow().cycle_breaker);
249222

250223
match cycle_breaker_node {
251224
Some(&node_id) => {
@@ -274,12 +247,7 @@ impl Graph {
274247
marked_temp.push(node_id);
275248

276249
// Visit outgoing nodes, and call `visit` on them recursively
277-
for edge in self
278-
.nodes
279-
.get(node_id.0 as usize)
280-
.unwrap()
281-
.as_ref()
282-
.unwrap()
250+
for edge in self.nodes[node_id.0 as usize]
283251
.borrow()
284252
.outgoing_edges
285253
.iter()
@@ -345,13 +313,7 @@ impl Graph {
345313
// since the audio graph could contain legs detached from the destination and those should
346314
// still be rendered.
347315
let mut cycle_breaker_applied = false;
348-
for node_id in self
349-
.nodes
350-
.iter()
351-
.enumerate()
352-
.filter(|(_, v)| v.is_some())
353-
.map(|(i, _)| AudioNodeId(i as u64))
354-
{
316+
for node_id in self.nodes.keys().map(|i| AudioNodeId(i as u64)) {
355317
cycle_breaker_applied = self.visit(
356318
node_id,
357319
&mut marked,
@@ -370,8 +332,7 @@ impl Graph {
370332
// clear the outgoing edges of the nodes that have been recognized as cycle breaker
371333
let nodes = &mut self.nodes;
372334
cycle_breakers.iter().for_each(|node_id| {
373-
let node = nodes.get_mut(node_id.0 as usize).unwrap().as_mut().unwrap();
374-
node.get_mut().outgoing_edges.clear();
335+
nodes[node_id.0 as usize].get_mut().outgoing_edges.clear();
375336
});
376337

377338
continue;
@@ -412,12 +373,7 @@ impl Graph {
412373
// process every node, in topological sorted order
413374
self.ordered.iter().for_each(|index| {
414375
// acquire a mutable borrow of the current processing node
415-
let mut node = nodes
416-
.get(index.0 as usize)
417-
.unwrap()
418-
.as_ref()
419-
.unwrap()
420-
.borrow_mut();
376+
let mut node = nodes[index.0 as usize].borrow_mut();
421377

422378
// make sure all input buffers have the correct number of channels, this might not be
423379
// the case if the node has no inputs connected or the channel count has just changed
@@ -428,7 +384,7 @@ impl Graph {
428384
.for_each(|i| i.mix(count, interpretation));
429385

430386
// let the current node process (catch any panics that may occur)
431-
let params = AudioParamValues::from(nodes.as_slice());
387+
let params = AudioParamValues::from(nodes);
432388
scope.node_id.set(*index);
433389
let (success, tail_time) = {
434390
// We are abusing AssertUnwindSafe here, we cannot guarantee it upholds.
@@ -452,12 +408,7 @@ impl Graph {
452408
// audio params are connected to the 'hidden' usize::MAX output, ignore them here
453409
.filter(|edge| edge.other_index != usize::MAX)
454410
.for_each(|edge| {
455-
let mut output_node = nodes
456-
.get(edge.other_id.0 as usize)
457-
.unwrap()
458-
.as_ref()
459-
.unwrap()
460-
.borrow_mut();
411+
let mut output_node = nodes[edge.other_id.0 as usize].borrow_mut();
461412
output_node.has_inputs_connected = true;
462413
let signal = &node.outputs[edge.self_index];
463414
let channel_config = &output_node.channel_config.clone();
@@ -483,44 +434,36 @@ impl Graph {
483434
// Check if we can decommission this node (end of life)
484435
if can_free {
485436
// Node is dropped, remove it from the node list
486-
nodes[index.0 as usize] = None;
437+
nodes.remove(index.0 as usize);
487438

488439
// And remove it from the ordering after we have processed all nodes
489440
nodes_dropped = true;
490441

491442
// Nodes are only dropped when they do not have incoming connections.
492443
// But they may have AudioParams feeding into them, these can de dropped too.
493-
for (id, node) in nodes.iter_mut().enumerate() {
494-
if node.is_none() {
495-
continue;
496-
}
444+
nodes.retain(|id, node| {
497445
// Check if this node was connected to the dropped node. In that case, it is
498446
// either an AudioParam (which can be dropped), or the AudioListener that feeds
499447
// into a PannerNode (which can be disconnected).
500448
let was_connected = {
501-
let outgoing_edges =
502-
&mut node.as_mut().unwrap().borrow_mut().outgoing_edges;
449+
let outgoing_edges = &mut node.borrow_mut().outgoing_edges;
503450
let prev_len = outgoing_edges.len();
504451
outgoing_edges.retain(|e| e.other_id != *index);
505452
outgoing_edges.len() != prev_len
506453
};
507454

455+
// retain when special or not connected to this dropped node
508456
let special = id < 2; // never drop Listener and Destination node
509-
510-
if special || !was_connected {
511-
// retain
512-
} else {
513-
*node = None;
514-
}
515-
}
457+
special || !was_connected
458+
})
516459
}
517460
});
518461

519462
// If there were any nodes decommissioned, remove from graph order
520463
if nodes_dropped {
521464
let mut i = 0;
522465
while i < self.ordered.len() {
523-
if nodes[self.ordered[i].0 as usize].is_none() {
466+
if nodes.get(self.ordered[i].0 as usize).is_none() {
524467
self.ordered.remove(i);
525468
} else {
526469
i += 1;
@@ -529,14 +472,7 @@ impl Graph {
529472
}
530473

531474
// Return the output buffer of destination node
532-
&self
533-
.nodes
534-
.get_mut(0)
535-
.unwrap()
536-
.as_mut()
537-
.unwrap()
538-
.get_mut()
539-
.outputs[0]
475+
&self.nodes[0].get_mut().outputs[0]
540476
}
541477
}
542478

src/render/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,8 @@ pub(crate) use thread::*;
1111
mod processor;
1212
pub use processor::*;
1313
mod quantum;
14+
15+
mod node_collection;
16+
pub(crate) use node_collection::NodeCollection;
17+
1418
pub use quantum::*;

0 commit comments

Comments
 (0)