@@ -4,7 +4,6 @@ use std::cell::RefCell;
4
4
use std:: panic:: { self , AssertUnwindSafe } ;
5
5
6
6
use crate :: context:: AudioNodeId ;
7
- use rustc_hash:: FxHashMap ;
8
7
use smallvec:: { smallvec, SmallVec } ;
9
8
10
9
use super :: { Alloc , AudioParamValues , AudioProcessor , AudioRenderQuantum } ;
@@ -76,7 +75,7 @@ impl Node {
76
75
/// The audio graph
77
76
pub ( crate ) struct Graph {
78
77
/// Processing Nodes
79
- nodes : FxHashMap < AudioNodeId , RefCell < Node > > ,
78
+ nodes : Vec < Option < RefCell < Node > > > ,
80
79
/// Allocator for audio buffers
81
80
alloc : Alloc ,
82
81
@@ -95,7 +94,7 @@ pub(crate) struct Graph {
95
94
impl Graph {
96
95
pub fn new ( ) -> Self {
97
96
Graph {
98
- nodes : FxHashMap :: default ( ) ,
97
+ nodes : Vec :: with_capacity ( 64 ) ,
99
98
ordered : vec ! [ ] ,
100
99
marked : vec ! [ ] ,
101
100
marked_temp : vec ! [ ] ,
@@ -126,25 +125,28 @@ impl Graph {
126
125
let inputs = vec ! [ AudioRenderQuantum :: from( self . alloc. silence( ) ) ; number_of_inputs] ;
127
126
let outputs = vec ! [ AudioRenderQuantum :: from( self . alloc. silence( ) ) ; number_of_outputs] ;
128
127
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
- ) ;
128
+ 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
+ } ) ) ;
142
142
}
143
143
144
144
pub fn add_edge ( & mut self , source : ( AudioNodeId , usize ) , dest : ( AudioNodeId , usize ) ) {
145
145
self . nodes
146
- . get_mut ( & source. 0 )
146
+ . get_mut ( source. 0 . 0 as usize )
147
147
. unwrap_or_else ( || panic ! ( "cannot connect {:?} to {:?}" , source, dest) )
148
+ . as_mut ( )
149
+ . unwrap ( )
148
150
. get_mut ( )
149
151
. outgoing_edges
150
152
. push ( OutgoingEdge {
@@ -158,8 +160,10 @@ impl Graph {
158
160
159
161
pub fn remove_edge ( & mut self , source : AudioNodeId , dest : AudioNodeId ) {
160
162
self . nodes
161
- . get_mut ( & source)
163
+ . get_mut ( source. 0 as usize )
162
164
. unwrap_or_else ( || panic ! ( "cannot remove the edge from {:?} to {:?}" , source, dest) )
165
+ . as_mut ( )
166
+ . unwrap ( )
163
167
. get_mut ( )
164
168
. outgoing_edges
165
169
. retain ( |edge| edge. other_id != dest) ;
@@ -169,13 +173,15 @@ impl Graph {
169
173
170
174
pub fn remove_edges_from ( & mut self , source : AudioNodeId ) {
171
175
self . nodes
172
- . get_mut ( & source)
176
+ . get_mut ( source. 0 as usize )
173
177
. unwrap_or_else ( || panic ! ( "cannot remove edges from {:?}" , source) )
178
+ . as_mut ( )
179
+ . unwrap ( )
174
180
. get_mut ( )
175
181
. outgoing_edges
176
182
. clear ( ) ;
177
183
178
- self . nodes . values_mut ( ) . for_each ( |node| {
184
+ self . nodes . iter_mut ( ) . flatten ( ) . for_each ( |node| {
179
185
node. get_mut ( )
180
186
. outgoing_edges
181
187
. retain ( |edge| edge. other_id != source) ;
@@ -188,18 +194,26 @@ impl Graph {
188
194
// Issue #92, a race condition can occur for AudioParams. They may have already been
189
195
// removed from the audio graph if the node they feed into was dropped.
190
196
// Therefore, do not assume this node still exists:
191
- if let Some ( node) = self . nodes . get_mut ( & index) {
197
+ if let Some ( node) = self . nodes . get_mut ( index. 0 as usize ) . unwrap ( ) . as_mut ( ) {
192
198
node. get_mut ( ) . free_when_finished = true ;
193
199
}
194
200
}
195
201
196
202
pub fn mark_cycle_breaker ( & mut self , index : AudioNodeId ) {
197
- self . nodes . get_mut ( & index) . unwrap ( ) . get_mut ( ) . cycle_breaker = true ;
203
+ self . nodes
204
+ . get_mut ( index. 0 as usize )
205
+ . unwrap ( )
206
+ . as_mut ( )
207
+ . unwrap ( )
208
+ . get_mut ( )
209
+ . cycle_breaker = true ;
198
210
}
199
211
200
212
pub fn route_message ( & mut self , index : AudioNodeId , msg : & mut dyn Any ) {
201
213
self . nodes
202
- . get_mut ( & index)
214
+ . get_mut ( index. 0 as usize )
215
+ . unwrap ( )
216
+ . as_mut ( )
203
217
. unwrap ( )
204
218
. get_mut ( )
205
219
. processor
@@ -223,10 +237,15 @@ impl Graph {
223
237
// If this node is in the cycle detection list, it is part of a cycle!
224
238
if let Some ( pos) = marked_temp. iter ( ) . position ( |& m| m == node_id) {
225
239
// check if we can find some node that can break the cycle
226
- let cycle_breaker_node = marked_temp
227
- . iter ( )
228
- . skip ( pos)
229
- . find ( |node_id| self . nodes . get ( node_id) . unwrap ( ) . borrow ( ) . cycle_breaker ) ;
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
+ } ) ;
230
249
231
250
match cycle_breaker_node {
232
251
Some ( & node_id) => {
@@ -257,7 +276,9 @@ impl Graph {
257
276
// Visit outgoing nodes, and call `visit` on them recursively
258
277
for edge in self
259
278
. nodes
260
- . get ( & node_id)
279
+ . get ( node_id. 0 as usize )
280
+ . unwrap ( )
281
+ . as_ref ( )
261
282
. unwrap ( )
262
283
. borrow ( )
263
284
. outgoing_edges
@@ -324,7 +345,13 @@ impl Graph {
324
345
// since the audio graph could contain legs detached from the destination and those should
325
346
// still be rendered.
326
347
let mut cycle_breaker_applied = false ;
327
- for & node_id in self . nodes . keys ( ) {
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
+ {
328
355
cycle_breaker_applied = self . visit (
329
356
node_id,
330
357
& mut marked,
@@ -343,7 +370,7 @@ impl Graph {
343
370
// clear the outgoing edges of the nodes that have been recognized as cycle breaker
344
371
let nodes = & mut self . nodes ;
345
372
cycle_breakers. iter ( ) . for_each ( |node_id| {
346
- let node = nodes. get_mut ( node_id) . unwrap ( ) ;
373
+ let node = nodes. get_mut ( node_id. 0 as usize ) . unwrap ( ) . as_mut ( ) . unwrap ( ) ;
347
374
node. get_mut ( ) . outgoing_edges . clear ( ) ;
348
375
} ) ;
349
376
@@ -385,7 +412,12 @@ impl Graph {
385
412
// process every node, in topological sorted order
386
413
self . ordered . iter ( ) . for_each ( |index| {
387
414
// acquire a mutable borrow of the current processing node
388
- let mut node = nodes. get ( index) . unwrap ( ) . borrow_mut ( ) ;
415
+ let mut node = nodes
416
+ . get ( index. 0 as usize )
417
+ . unwrap ( )
418
+ . as_ref ( )
419
+ . unwrap ( )
420
+ . borrow_mut ( ) ;
389
421
390
422
// make sure all input buffers have the correct number of channels, this might not be
391
423
// the case if the node has no inputs connected or the channel count has just changed
@@ -396,7 +428,7 @@ impl Graph {
396
428
. for_each ( |i| i. mix ( count, interpretation) ) ;
397
429
398
430
// let the current node process (catch any panics that may occur)
399
- let params = AudioParamValues :: from ( & * nodes) ;
431
+ let params = AudioParamValues :: from ( nodes. as_slice ( ) ) ;
400
432
scope. node_id . set ( * index) ;
401
433
let ( success, tail_time) = {
402
434
// We are abusing AssertUnwindSafe here, we cannot guarantee it upholds.
@@ -420,7 +452,12 @@ impl Graph {
420
452
// audio params are connected to the 'hidden' usize::MAX output, ignore them here
421
453
. filter ( |edge| edge. other_index != usize:: MAX )
422
454
. for_each ( |edge| {
423
- let mut output_node = nodes. get ( & edge. other_id ) . unwrap ( ) . borrow_mut ( ) ;
455
+ let mut output_node = nodes
456
+ . get ( edge. other_id . 0 as usize )
457
+ . unwrap ( )
458
+ . as_ref ( )
459
+ . unwrap ( )
460
+ . borrow_mut ( ) ;
424
461
output_node. has_inputs_connected = true ;
425
462
let signal = & node. outputs [ edge. self_index ] ;
426
463
let channel_config = & output_node. channel_config . clone ( ) ;
@@ -446,33 +483,44 @@ impl Graph {
446
483
// Check if we can decommission this node (end of life)
447
484
if can_free {
448
485
// Node is dropped, remove it from the node list
449
- nodes. remove ( index) ;
486
+ nodes[ index. 0 as usize ] = None ;
450
487
451
488
// And remove it from the ordering after we have processed all nodes
452
489
nodes_dropped = true ;
453
490
454
491
// Nodes are only dropped when they do not have incoming connections.
455
492
// But they may have AudioParams feeding into them, these can de dropped too.
456
- nodes. retain ( |id, n| {
493
+ for ( id, node) in nodes. iter_mut ( ) . enumerate ( ) {
494
+ if node. is_none ( ) {
495
+ continue ;
496
+ }
457
497
// Check if this node was connected to the dropped node. In that case, it is
458
498
// either an AudioParam (which can be dropped), or the AudioListener that feeds
459
499
// into a PannerNode (which can be disconnected).
460
- let outgoing_edges = & mut n. borrow_mut ( ) . outgoing_edges ;
461
- let prev_len = outgoing_edges. len ( ) ;
462
- outgoing_edges. retain ( |e| e. other_id != * index) ;
463
- let was_connected = outgoing_edges. len ( ) != prev_len;
464
-
465
- let special = id. 0 < 2 ; // never drop Listener and Destination node
466
- special || !was_connected
467
- } ) ;
500
+ let was_connected = {
501
+ let outgoing_edges =
502
+ & mut node. as_mut ( ) . unwrap ( ) . borrow_mut ( ) . outgoing_edges ;
503
+ let prev_len = outgoing_edges. len ( ) ;
504
+ outgoing_edges. retain ( |e| e. other_id != * index) ;
505
+ outgoing_edges. len ( ) != prev_len
506
+ } ;
507
+
508
+ 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
+ }
468
516
}
469
517
} ) ;
470
518
471
519
// If there were any nodes decommissioned, remove from graph order
472
520
if nodes_dropped {
473
521
let mut i = 0 ;
474
522
while i < self . ordered . len ( ) {
475
- if ! nodes. contains_key ( & self . ordered [ i] ) {
523
+ if nodes[ self . ordered [ i] . 0 as usize ] . is_none ( ) {
476
524
self . ordered . remove ( i) ;
477
525
} else {
478
526
i += 1 ;
@@ -483,7 +531,9 @@ impl Graph {
483
531
// Return the output buffer of destination node
484
532
& self
485
533
. nodes
486
- . get_mut ( & AudioNodeId ( 0 ) )
534
+ . get_mut ( 0 )
535
+ . unwrap ( )
536
+ . as_mut ( )
487
537
. unwrap ( )
488
538
. get_mut ( )
489
539
. outputs [ 0 ]
0 commit comments