Skip to content

Commit

Permalink
NodeCollection is now indexed by AudioNodeId, not usize
Browse files Browse the repository at this point in the history
  • Loading branch information
orottier committed Oct 29, 2023
1 parent 3e517c6 commit 402e21f
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 56 deletions.
2 changes: 1 addition & 1 deletion src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub(crate) struct AudioNodeId(pub u64);
///
/// Store these in your `AudioProcessor` to get access to `AudioParam` values.
#[derive(Debug)]
pub struct AudioParamId(pub(crate) u64);
pub struct AudioParamId(u64);

// bit contrived, but for type safety only the context mod can access the inner u64
impl From<&AudioParamId> for AudioNodeId {
Expand Down
49 changes: 19 additions & 30 deletions src/render/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ impl Graph {
let inputs = vec![AudioRenderQuantum::from(self.alloc.silence()); number_of_inputs];
let outputs = vec![AudioRenderQuantum::from(self.alloc.silence()); number_of_outputs];

let index = index.0 as usize;
self.nodes.insert(
index,
RefCell::new(Node {
Expand All @@ -148,7 +147,7 @@ impl Graph {
}

pub fn add_edge(&mut self, source: (AudioNodeId, usize), dest: (AudioNodeId, usize)) {
self.nodes[source.0 .0 as usize]
self.nodes[source.0]
.get_mut()
.outgoing_edges
.push(OutgoingEdge {
Expand All @@ -161,7 +160,7 @@ impl Graph {
}

pub fn remove_edge(&mut self, source: AudioNodeId, dest: AudioNodeId) {
self.nodes[source.0 as usize]
self.nodes[source]
.get_mut()
.outgoing_edges
.retain(|edge| edge.other_id != dest);
Expand All @@ -170,10 +169,7 @@ impl Graph {
}

pub fn remove_edges_from(&mut self, source: AudioNodeId) {
self.nodes[source.0 as usize]
.get_mut()
.outgoing_edges
.clear();
self.nodes[source].get_mut().outgoing_edges.clear();

self.nodes.values_mut().for_each(|node| {
node.get_mut()
Expand All @@ -188,20 +184,17 @@ impl Graph {
// Issue #92, a race condition can occur for AudioParams. They may have already been
// removed from the audio graph if the node they feed into was dropped.
// Therefore, do not assume this node still exists:
if let Some(node) = self.nodes.get_mut(index.0 as usize) {
if let Some(node) = self.nodes.get_mut(index) {
node.get_mut().free_when_finished = true;
}
}

pub fn mark_cycle_breaker(&mut self, index: AudioNodeId) {
self.nodes[index.0 as usize].get_mut().cycle_breaker = true;
self.nodes[index].get_mut().cycle_breaker = true;
}

pub fn route_message(&mut self, index: AudioNodeId, msg: &mut dyn Any) {
self.nodes[index.0 as usize]
.get_mut()
.processor
.onmessage(msg);
self.nodes[index].get_mut().processor.onmessage(msg);
}

/// Helper function for `order_nodes` - traverse node and outgoing edges
Expand All @@ -224,7 +217,7 @@ impl Graph {
let cycle_breaker_node = marked_temp
.iter()
.skip(pos)
.find(|node_id| self.nodes[node_id.0 as usize].borrow().cycle_breaker);
.find(|&&node_id| self.nodes[node_id].borrow().cycle_breaker);

match cycle_breaker_node {
Some(&node_id) => {
Expand Down Expand Up @@ -253,11 +246,7 @@ impl Graph {
marked_temp.push(node_id);

// Visit outgoing nodes, and call `visit` on them recursively
for edge in self.nodes[node_id.0 as usize]
.borrow()
.outgoing_edges
.iter()
{
for edge in self.nodes[node_id].borrow().outgoing_edges.iter() {
let cycle_breaker_applied = self.visit(
edge.other_id,
marked,
Expand Down Expand Up @@ -319,7 +308,7 @@ impl Graph {
// since the audio graph could contain legs detached from the destination and those should
// still be rendered.
let mut cycle_breaker_applied = false;
for node_id in self.nodes.keys().map(|i| AudioNodeId(i as u64)) {
for node_id in self.nodes.keys() {
cycle_breaker_applied = self.visit(
node_id,
&mut marked,
Expand All @@ -338,7 +327,7 @@ impl Graph {
// clear the outgoing edges of the nodes that have been recognized as cycle breaker
let nodes = &mut self.nodes;
cycle_breakers.iter().for_each(|node_id| {
nodes[node_id.0 as usize].get_mut().outgoing_edges.clear();
nodes[*node_id].get_mut().outgoing_edges.clear();
});

continue;
Expand Down Expand Up @@ -379,7 +368,7 @@ impl Graph {
// process every node, in topological sorted order
self.ordered.iter().for_each(|index| {
// acquire a mutable borrow of the current processing node
let mut node = nodes[index.0 as usize].borrow_mut();
let mut node = nodes[*index].borrow_mut();

// make sure all input buffers have the correct number of channels, this might not be
// the case if the node has no inputs connected or the channel count has just changed
Expand Down Expand Up @@ -414,7 +403,7 @@ impl Graph {
// audio params are connected to the 'hidden' usize::MAX output, ignore them here
.filter(|edge| edge.other_index != usize::MAX)
.for_each(|edge| {
let mut output_node = nodes[edge.other_id.0 as usize].borrow_mut();
let mut output_node = nodes[edge.other_id].borrow_mut();
output_node.has_inputs_connected = true;
let signal = &node.outputs[edge.self_index];
let channel_config = &output_node.channel_config.clone();
Expand All @@ -440,7 +429,7 @@ impl Graph {
// Check if we can decommission this node (end of life)
if can_free {
// Node is dropped, remove it from the node list
let mut node = nodes.remove(index.0 as usize).into_inner();
let mut node = nodes.remove(*index).into_inner();
self.reclaim_id_channel
.push(node.reclaim_id.take().unwrap());
drop(node);
Expand All @@ -467,7 +456,7 @@ impl Graph {
// - special node (destination = id 0, listener = id 1), or
// - not connected to this dropped node, or
// - if the control thread still has a handle to it.
let retain = id < 2 || !was_connected || !node.free_when_finished;
let retain = id.0 < 2 || !was_connected || !node.free_when_finished;

if !retain {
self.reclaim_id_channel
Expand All @@ -482,7 +471,7 @@ impl Graph {
if nodes_dropped {
let mut i = 0;
while i < self.ordered.len() {
if nodes.get(self.ordered[i].0 as usize).is_none() {
if nodes.get(self.ordered[i]).is_none() {
self.ordered.remove(i);
} else {
i += 1;
Expand All @@ -491,7 +480,7 @@ impl Graph {
}

// Return the output buffer of destination node
&self.nodes[0].get_mut().outputs[0]
&self.nodes[AudioNodeId(0)].get_mut().outputs[0]
}
}

Expand Down Expand Up @@ -681,7 +670,7 @@ mod tests {
// dropped and the AudioNodeId(3) should be reclaimed
add_node(&mut graph, 2, node.clone());
// Mark the node as 'detached from the control thread', so it is allowed to drop
graph.nodes[2].get_mut().free_when_finished = true;
graph.nodes[AudioNodeId(2)].get_mut().free_when_finished = true;

// Connect the regular node to the AudioDestinationNode
add_edge(&mut graph, 2, 0);
Expand Down Expand Up @@ -723,7 +712,7 @@ mod tests {
// dropped and the AudioNodeId(3) should be reclaimed
add_node(&mut graph, 2, node.clone());
// Mark the node as 'detached from the control thread', so it is allowed to drop
graph.nodes[2].get_mut().free_when_finished = true;
graph.nodes[AudioNodeId(2)].get_mut().free_when_finished = true;

// Connect the regular node to the AudioDestinationNode
add_edge(&mut graph, 2, 0);
Expand All @@ -732,7 +721,7 @@ mod tests {
let param = Box::new(TestNode { tail_time: true }); // audio params have tail time true
add_node(&mut graph, 3, param);
// Mark the node as 'detached from the control thread', so it is allowed to drop
graph.nodes[3].get_mut().free_when_finished = true;
graph.nodes[AudioNodeId(3)].get_mut().free_when_finished = true;

// Connect the audioparam to the regular node
add_audioparam(&mut graph, 3, 2);
Expand Down
49 changes: 25 additions & 24 deletions src/render/node_collection.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::context::AudioNodeId;
use crate::render::graph::Node;

use std::cell::RefCell;
use std::ops::{Index, IndexMut};

pub struct NodeCollection {
pub(crate) struct NodeCollection {
nodes: Vec<Option<RefCell<Node>>>,
}

Expand All @@ -26,26 +28,25 @@ impl NodeCollection {
}

#[inline(always)]
pub fn insert(&mut self, index: usize, value: RefCell<Node>) {
pub fn insert(&mut self, index: AudioNodeId, value: RefCell<Node>) {
let index = index.0 as usize;
self.ensure_capacity(index + 1);
self.nodes[index] = Some(value);
}

#[inline(always)]
pub fn remove(&mut self, index: usize) -> RefCell<Node> {
self.nodes
.get_mut(index)
.expect("Unexpected remove index for NodeCollection")
pub fn remove(&mut self, index: AudioNodeId) -> RefCell<Node> {
self.nodes[index.0 as usize]
.take()
.expect("Unable to remove non-existing Node in NodeCollection")
}

#[inline(always)]
pub fn keys(&self) -> impl Iterator<Item = usize> + '_ {
pub fn keys(&self) -> impl Iterator<Item = AudioNodeId> + '_ {
self.nodes
.iter()
.enumerate()
.filter_map(|(i, v)| v.as_ref().and(Some(i)))
.filter_map(|(i, v)| v.as_ref().and(Some(AudioNodeId(i as u64))))
}

#[inline(always)]
Expand All @@ -54,52 +55,52 @@ impl NodeCollection {
}

#[inline(always)]
pub fn get(&self, index: usize) -> Option<&RefCell<Node>> {
self.nodes[index].as_ref()
pub fn get(&self, index: AudioNodeId) -> Option<&RefCell<Node>> {
self.nodes[index.0 as usize].as_ref()
}

#[inline(always)]
pub fn get_mut(&mut self, index: usize) -> Option<&mut RefCell<Node>> {
self.nodes[index].as_mut()
pub fn get_mut(&mut self, index: AudioNodeId) -> Option<&mut RefCell<Node>> {
self.nodes[index.0 as usize].as_mut()
}

#[inline(always)]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(usize, &mut RefCell<Node>) -> bool,
F: FnMut(AudioNodeId, &mut RefCell<Node>) -> bool,
{
self.nodes.iter_mut().enumerate().for_each(|(i, opt)| {
if let Some(v) = opt.as_mut() {
if !f(i, v) {
if !f(AudioNodeId(i as u64), v) {
*opt = None;
}
}
})
}
}

impl Index<usize> for NodeCollection {
impl Index<AudioNodeId> for NodeCollection {
type Output = RefCell<Node>;

#[track_caller]
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
fn index(&self, index: AudioNodeId) -> &Self::Output {
self.nodes
.get(index)
.unwrap_or_else(|| panic!("Unexpected index {} for NodeCollection", index))
.get(index.0 as usize)
.unwrap_or_else(|| panic!("Unexpected index {} for NodeCollection", index.0))
.as_ref()
.unwrap_or_else(|| panic!("Index {} for dropped Node in NodeCollection", index))
.unwrap_or_else(|| panic!("Index {} for dropped Node in NodeCollection", index.0))
}
}

impl IndexMut<usize> for NodeCollection {
impl IndexMut<AudioNodeId> for NodeCollection {
#[track_caller]
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
fn index_mut(&mut self, index: AudioNodeId) -> &mut Self::Output {
self.nodes
.get_mut(index)
.unwrap_or_else(|| panic!("Unexpected index {} for NodeCollection", index))
.get_mut(index.0 as usize)
.unwrap_or_else(|| panic!("Unexpected index {} for NodeCollection", index.0))
.as_mut()
.unwrap_or_else(|| panic!("Index {} for dropped Node in NodeCollection", index))
.unwrap_or_else(|| panic!("Index {} for dropped Node in NodeCollection", index.0))
}
}
2 changes: 1 addition & 1 deletion src/render/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl<'a> AudioParamValues<'a> {
/// provide a slice of length equal to the render quantum size (default: 128)
#[allow(clippy::missing_panics_doc)]
pub fn get(&self, index: &AudioParamId) -> impl Deref<Target = [f32]> + '_ {
DerefAudioRenderQuantumChannel(self.nodes[index.0 as usize].borrow())
DerefAudioRenderQuantumChannel(self.nodes[index.into()].borrow())
}

pub(crate) fn listener_params(&self) -> [impl Deref<Target = [f32]> + '_; 9] {
Expand Down

0 comments on commit 402e21f

Please sign in to comment.